DYT/Tool/3rdParty_x64/include/dcmtk/dcmsr/dsrtncsr.h
2024-11-22 23:19:31 +08:00

807 lines
22 KiB
C++

/*
*
* Copyright (C) 2000-2016, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
*
* OFFIS e.V.
* R&D Division Health
* Escherweg 2
* D-26121 Oldenburg, Germany
*
*
* Module: dcmsr
*
* Author: Joerg Riesmeier
*
* Purpose:
* classes: DSRTreeNodeCursor
*
*/
#ifndef DSRTNCSR_H
#define DSRTNCSR_H
#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
#include "dcmtk/dcmsr/dsrtypes.h"
#include "dcmtk/dcmsr/dsrposcn.h"
#include "dcmtk/dcmsr/dsrtnant.h"
#include "dcmtk/ofstd/ofstack.h"
/*-----------------------*
* forward declaration *
*-----------------------*/
class DSRTreeNode;
/*---------------------*
* class declaration *
*---------------------*/
/** Class implementing a tree node cursor.
** @tparam T template type used for the tree node pointers
* @tparam B boolean flag that indicates whether to treat certain tree nodes
* differently (depends on the particular implementation)
*/
template<typename T = DSRTreeNode, OFBool B = OFFalse>
class DSRTreeNodeCursor
{
public:
/** default constructor
*/
DSRTreeNodeCursor();
/** copy constructor
** @param cursor object to be copied
*/
DSRTreeNodeCursor(const DSRTreeNodeCursor<T, B> &cursor);
/** constructor.
* See comments on setCursor(T*) method.
** @param node pointer to tree node used to initialize the cursor
* @param position optional pointer to position counter that should be used to
* initialize the internal counter
*/
DSRTreeNodeCursor(T *node,
const DSRPositionCounter *position = NULL);
/** destructor
*/
virtual ~DSRTreeNodeCursor();
/** assignment operator
** @param cursor object to be copied
** @return reference to modified cursor (this object)
*/
DSRTreeNodeCursor<T, B> &operator=(const DSRTreeNodeCursor<T, B> &cursor);
/** assignment operator.
* See comments on setCursor(T*) method.
** @param node node to which the cursor should be set
** @return reference to modified cursor (this object)
*/
DSRTreeNodeCursor<T, B> &operator=(T *node);
/** clear all member variables.
* The cursor becomes invalid afterwards (same state as after default construction).
*/
virtual void clear();
/** check whether cursor currently points to a valid node
** @return OFTrue if valid, OFFalse otherwise
*/
virtual OFBool isValid() const;
/** count number of children of the current node.
* This method iterates over all children of the current node, either on all
* sub-levels or on the first child level only.
** @param searchIntoSub flag indicating whether to search into sub-trees
* ("deep search") or on the first child level only
** @return number of children of the current node, 0 if none
*/
size_t countChildNodes(const OFBool searchIntoSub = OFTrue) const;
/** check whether the current node has a parent
** @return OFTrue if the current node has a parent, OFFalse otherwise
*/
inline OFBool hasParentNode() const;
/** check whether the current node has any children
** @return OFTrue if the current node has any children, OFFalse otherwise
*/
inline OFBool hasChildNodes() const;
/** check whether the current node has a preceding sibling
** @return OFTrue if the current node has a preceding sibling, OFFalse otherwise
*/
inline OFBool hasPreviousNode() const;
/** check whether the current node has a following sibling
** @return OFTrue if the current node has a following sibling, OFFalse otherwise
*/
inline OFBool hasNextNode() const;
/** check whether the current node has any siblings
** @return OFTrue if the current node has any siblings, OFFalse otherwise
*/
inline OFBool hasSiblingNodes() const;
/** get pointer to current node
** @return pointer to current node (might be NULL)
*/
virtual T *getNode() const;
/** get pointer to parent node.
* Can be used to have a lookup to the parent node without changing the cursor.
** @return pointer to parent node (if any), NULL otherwise
*/
virtual const T *getParentNode() const;
/** get pointer to first child node.
* Can be used to have a lookup to the first child node without changing the cursor.
** @return pointer to first child node (if any), NULL otherwise
*/
virtual const T *getChildNode() const;
/** get pointer to previous node.
* Can be used to have a lookup to the previous node without changing the cursor.
** @return pointer to previous node (if any), NULL otherwise
*/
virtual const T *getPreviousNode() const;
/** get pointer to next node.
* Can be used to have a lookup to the next node without changing the cursor.
** @return pointer to next node (if any), NULL otherwise
*/
virtual const T *getNextNode() const;
/** goto first node on the same level (first sibling).
* Please note that the first node might be identical to the current node.
** @return ID of the first node if successful, 0 otherwise
*/
size_t gotoFirst();
/** goto last node on the same level (last sibling).
* Please note that the last node might be identical to the current node.
** @return ID of the last node if successful, 0 otherwise
*/
size_t gotoLast();
/** goto previous node on the same level (preceding sibling)
** @return ID of the previous node if successful, 0 otherwise
*/
size_t gotoPrevious();
/** goto next node on the same level (following sibling)
** @return ID of the next node if successful, 0 otherwise
*/
size_t gotoNext();
/** goto parent node (one level up)
** @return ID of the parent node if successful, 0 otherwise
*/
size_t goUp();
/** goto first child node (one level down)
** @return ID of the first child node if successful, 0 otherwise
*/
size_t goDown();
/** @copydoc goUp()
*/
inline size_t gotoParent();
/** @copydoc goDown()
*/
inline size_t gotoChild();
/** iterate over all nodes. Starts from current position!
** @param searchIntoSub flag indicating whether to search into sub-trees
* ("deep search") or on the current level only
** @return ID of the next node if successful, 0 otherwise
*/
size_t iterate(const OFBool searchIntoSub = OFTrue);
/** set cursor to specified node. Starts from current position!
** @param searchID ID of the node to set the cursor to
** @return ID of the new current node if successful, 0 otherwise
*/
size_t gotoNode(const size_t searchID);
/** set cursor to specified node. Starts from current position!
** @param position position string of the node to set the cursor to.
* (the format is e.g. "1.2.3" for the third child of the
* second child of the first node - see getPosition()).
* @param separator character used to separate the figures (default: '.')
** @return ID of the new current node if successful, 0 otherwise
*/
size_t gotoNode(const OFString &position,
const char separator = '.');
/** set cursor to specified node. Starts from current position!
** @param annotation annotation of the node to set the cursor to
** @return ID of the new current node if successful, 0 otherwise
*/
size_t gotoNode(const DSRTreeNodeAnnotation &annotation);
/** get current node ID.
* The node ID uniquely identifies a content item in the document tree. Most of
* the navigation methods above do return this ID too.
** @return ID of the current node if valid, 0 otherwise
*/
inline size_t getNodeID() const;
/** get current level.
* The level starts with 1 for the root node, then 2 for its child nodes, etc.
** @return number of the current level if valid, 0 otherwise
*/
inline size_t getLevel() const;
/** get reference to internal position counter.
* Please note that this method allows for manipulating the internal position
* counter, so handle with care!
** @return reference to internal position counter
*/
inline DSRPositionCounter &getPositionCounter();
/** get position string of the current node.
* Specifies the position of each node by means of a dot separated string of
* position counters. The first figure of this string specifies the position
* within the first level (e.g. "1"), the second one the position in the second
* level (e.g. "2"), the third one the position in the third level (e.g. "3"),
* etc. A position string of "1.2.3" would, therefore, point to the third child
* of the second child of the first node.
** @param position variable where the position string should be stored
* @param separator character used to separate the figures (default: '.')
** @return reference to the resulting position string (empty if invalid)
*/
inline const OFString &getPosition(OFString &position,
const char separator = '.') const;
protected:
/** clear the internal node cursor stack
*/
void clearNodeCursorStack();
/** get cursor
** @return reference to cursor (this object)
*/
inline const DSRTreeNodeCursor<T, B> &getCursor() const;
/** set cursor to specified object
** @param cursor object to set this cursor to
*/
inline void setCursor(const DSRTreeNodeCursor<T, B> &cursor);
/** set cursor to specified node.
* Clears the internal position counter and sets the position of the current level
* to 1 (if the passed 'node' is valid) or 0 (if the 'node' is invalid).
** @param node node to which the cursor should be set
** @return ID of the new current node if successful, 0 otherwise
*/
size_t setCursor(T *node);
/// pointer to current node
T *NodeCursor;
/// stack of node pointers. Used to store the cursor position of upper levels.
OFStack<T *> NodeCursorStack;
/// counter for the current position within the current level and on upper levels
DSRPositionCounter Position;
};
/*------------------*
* implementation *
*------------------*/
template<typename T, OFBool B>
DSRTreeNodeCursor<T, B>::DSRTreeNodeCursor()
: NodeCursor(NULL),
NodeCursorStack(),
Position()
{
}
template<typename T, OFBool B>
DSRTreeNodeCursor<T, B>::DSRTreeNodeCursor(const DSRTreeNodeCursor<T, B> &cursor)
: NodeCursor(cursor.NodeCursor),
NodeCursorStack(cursor.NodeCursorStack),
Position(cursor.Position)
{
}
template<typename T, OFBool B>
DSRTreeNodeCursor<T, B>::DSRTreeNodeCursor(T *node,
const DSRPositionCounter *position)
: NodeCursor(node),
NodeCursorStack(),
Position()
{
/* check whether a valid position counter is given */
if (position != NULL)
{
if (position->isValid())
Position = *position;
else
Position.initialize(NodeCursor != NULL, position->getFlags());
} else
Position.initialize(NodeCursor != NULL);
}
template<typename T, OFBool B>
DSRTreeNodeCursor<T, B>::~DSRTreeNodeCursor()
{
}
template<typename T, OFBool B>
DSRTreeNodeCursor<T, B> &DSRTreeNodeCursor<T, B>::operator=(const DSRTreeNodeCursor<T, B> &cursor)
{
setCursor(cursor);
return *this;
}
template<typename T, OFBool B>
DSRTreeNodeCursor<T, B> &DSRTreeNodeCursor<T, B>::operator=(T *node)
{
setCursor(node);
return *this;
}
template<typename T, OFBool B>
void DSRTreeNodeCursor<T, B>::clear()
{
NodeCursor = NULL;
clearNodeCursorStack();
Position.clear();
}
template<typename T, OFBool B>
OFBool DSRTreeNodeCursor<T, B>::isValid() const
{
return (NodeCursor != NULL);
}
template<typename T, OFBool B>
void DSRTreeNodeCursor<T, B>::clearNodeCursorStack()
{
while (!NodeCursorStack.empty())
NodeCursorStack.pop();
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::countChildNodes(const OFBool searchIntoSub) const
{
size_t count = 0;
if (NodeCursor != NULL)
{
/* do we have any children at all? */
DSRTreeNodeCursor<T, B> cursor(NodeCursor->getDown());
if (cursor.isValid())
{
/* iterate over all child nodes */
do {
++count;
} while (cursor.iterate(searchIntoSub));
}
}
return count;
}
template<typename T, OFBool B>
OFBool DSRTreeNodeCursor<T, B>::hasParentNode() const
{
return ((NodeCursor != NULL) && !NodeCursorStack.empty());
}
template<typename T, OFBool B>
OFBool DSRTreeNodeCursor<T, B>::hasChildNodes() const
{
return (getChildNode() != NULL);
}
template<typename T, OFBool B>
OFBool DSRTreeNodeCursor<T, B>::hasPreviousNode() const
{
return (getPreviousNode() != NULL);
}
template<typename T, OFBool B>
OFBool DSRTreeNodeCursor<T, B>::hasNextNode() const
{
return (getNextNode() != NULL);
}
template<typename T, OFBool B>
OFBool DSRTreeNodeCursor<T, B>::hasSiblingNodes() const
{
return (getPreviousNode() != NULL) || (getNextNode() != NULL);
}
template<typename T, OFBool B>
T *DSRTreeNodeCursor<T, B>::getNode() const
{
return NodeCursor;
}
template<typename T, OFBool B>
const T *DSRTreeNodeCursor<T, B>::getParentNode() const
{
T *node = NULL;
if (hasParentNode())
node = NodeCursorStack.top();
return node;
}
template<typename T, OFBool B>
const T *DSRTreeNodeCursor<T, B>::getChildNode() const
{
T *node = NULL;
if (NodeCursor != NULL)
node = NodeCursor->getDown();
return node;
}
template<typename T, OFBool B>
const T *DSRTreeNodeCursor<T, B>::getPreviousNode() const
{
T *node = NULL;
if (NodeCursor != NULL)
node = NodeCursor->getPrev();
return node;
}
template<typename T, OFBool B>
const T *DSRTreeNodeCursor<T, B>::getNextNode() const
{
T *node = NULL;
if (NodeCursor != NULL)
node = NodeCursor->getNext();
return node;
}
template<typename T, OFBool B>
const DSRTreeNodeCursor<T, B> &DSRTreeNodeCursor<T, B>::getCursor() const
{
return *this;
}
template<typename T, OFBool B>
void DSRTreeNodeCursor<T, B>::setCursor(const DSRTreeNodeCursor<T, B> &cursor)
{
NodeCursor = cursor.NodeCursor;
NodeCursorStack = cursor.NodeCursorStack;
Position = cursor.Position;
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::setCursor(T *node)
{
size_t nodeID = 0;
NodeCursor = node;
if (NodeCursor != NULL)
nodeID = NodeCursor->getIdent();
clearNodeCursorStack();
Position.initialize(NodeCursor != NULL);
return nodeID;
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::gotoFirst()
{
size_t nodeID = 0;
if (NodeCursor != NULL)
{
while (NodeCursor->getPrev() != NULL)
{
NodeCursor = NodeCursor->getPrev();
--Position;
}
nodeID = NodeCursor->getIdent();
}
return nodeID;
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::gotoLast()
{
size_t nodeID = 0;
if (NodeCursor != NULL)
{
while (NodeCursor->getNext() != NULL)
{
NodeCursor = NodeCursor->getNext();
++Position;
}
nodeID = NodeCursor->getIdent();
}
return nodeID;
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::gotoPrevious()
{
size_t nodeID = 0;
if (NodeCursor != NULL)
{
if (NodeCursor->getPrev() != NULL)
{
NodeCursor = NodeCursor->getPrev();
nodeID = NodeCursor->getIdent();
--Position;
}
}
return nodeID;
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::gotoNext()
{
size_t nodeID = 0;
if (NodeCursor != NULL)
{
if (NodeCursor->getNext() != NULL)
{
NodeCursor = NodeCursor->getNext();
nodeID = NodeCursor->getIdent();
++Position;
}
}
return nodeID;
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::goUp()
{
size_t nodeID = 0;
if (NodeCursor != NULL)
{
if (!NodeCursorStack.empty())
{
T *cursor = NodeCursorStack.top();
NodeCursorStack.pop();
if (cursor != NULL)
{
NodeCursor = cursor;
nodeID = NodeCursor->getIdent();
Position.goUp();
}
}
}
return nodeID;
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::goDown()
{
size_t nodeID = 0;
if (NodeCursor != NULL)
{
if (NodeCursor->getDown() != NULL)
{
NodeCursorStack.push(NodeCursor);
NodeCursor = NodeCursor->getDown();
nodeID = NodeCursor->getIdent();
Position.goDown();
}
}
return nodeID;
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::gotoParent()
{
return goUp();
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::gotoChild()
{
return goDown();
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::iterate(const OFBool searchIntoSub)
{
size_t nodeID = 0;
if (NodeCursor != NULL)
{
/* perform "deep search", if specified */
if (searchIntoSub && (NodeCursor->getDown() != NULL))
{
NodeCursorStack.push(NodeCursor);
NodeCursor = NodeCursor->getDown();
nodeID = NodeCursor->getIdent();
Position.goDown();
}
else if (NodeCursor->getNext() != NULL)
{
NodeCursor = NodeCursor->getNext();
nodeID = NodeCursor->getIdent();
++Position;
}
else if (searchIntoSub && !NodeCursorStack.empty())
{
do {
if (!NodeCursorStack.empty())
{
NodeCursor = NodeCursorStack.top();
NodeCursorStack.pop();
Position.goUp();
} else
NodeCursor = NULL;
} while ((NodeCursor != NULL) && (NodeCursor->getNext() == NULL));
if (NodeCursor != NULL)
{
if (NodeCursor->getNext() != NULL)
{
NodeCursor = NodeCursor->getNext();
nodeID = NodeCursor->getIdent();
++Position;
}
}
}
}
return nodeID;
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::gotoNode(const size_t searchID)
{
size_t nodeID = 0;
if (searchID > 0)
{
if (NodeCursor != NULL)
{
nodeID = NodeCursor->getIdent();
while ((nodeID > 0) && (nodeID != searchID))
nodeID = iterate();
}
}
return nodeID;
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::gotoNode(const OFString &position,
const char separator)
{
size_t nodeID = 0;
if (!position.empty())
{
if (NodeCursor != NULL)
{
nodeID = NodeCursor->getIdent();
size_t posStart = 0;
size_t posEnd = 0;
size_t goCount = 0;
do {
/* go down after first valid substring/segment */
if (posStart > 0)
nodeID = goDown();
/* current node still valid? */
if (nodeID > 0)
{
/* search for next separator */
posEnd = position.find(separator, posStart);
/* is last segment? */
if (posEnd == OFString_npos)
goCount = DSRTypes::stringToNumber(position.substr(posStart).c_str());
else {
goCount = DSRTypes::stringToNumber(position.substr(posStart, posEnd - posStart).c_str());
posStart = posEnd + 1;
}
/* is valid number? */
if (goCount > 0)
{
while ((nodeID > 0) && (goCount > 1))
{
nodeID = gotoNext();
goCount--;
}
} else
nodeID = 0;
}
} while ((nodeID > 0) && (posEnd != OFString_npos));
}
}
return nodeID;
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::gotoNode(const DSRTreeNodeAnnotation &annotation)
{
size_t nodeID = 0;
if (!annotation.isEmpty())
{
if (NodeCursor != NULL)
{
nodeID = NodeCursor->getIdent();
while ((nodeID > 0) && (NodeCursor->getAnnotation() != annotation))
nodeID = iterate();
}
}
return nodeID;
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::getNodeID() const
{
size_t nodeID = 0;
if (NodeCursor != NULL)
nodeID = NodeCursor->getIdent();
return nodeID;
}
template<typename T, OFBool B>
size_t DSRTreeNodeCursor<T, B>::getLevel() const
{
size_t level = 0;
if (NodeCursor != NULL)
level = NodeCursorStack.size() + 1;
return level;
}
template<typename T, OFBool B>
DSRPositionCounter &DSRTreeNodeCursor<T, B>::getPositionCounter()
{
return Position;
}
template<typename T, OFBool B>
const OFString &DSRTreeNodeCursor<T, B>::getPosition(OFString &position,
const char separator) const
{
return Position.getString(position, separator);
}
#endif