// Read the documentation to learn more about C++ code generator // versioning. // %X% %Q% %Z% %W% #ifndef XSMODEXPTREE_H #define XSMODEXPTREE_H 1 #include #include #include #include template class XSModExpTree; class ExpTreeNodeType { public: ExpTreeNodeType():pos(-999), parentPos(-1), children() {} int pos; int parentPos; IntegerArray children; }; // It would really be cleaner to combine the ValCont and Ret // Type template parameters into a single Traits class. // However, SunWS6.0 seemed to have bizarre and // unsystematic compile-time errors when RetType was // enclosed in a traits class and used as the return type // of a function (which is really its sole purpose). template class XSModExpTree_Iterator { public: XSModExpTree_Iterator(const XSModExpTree_Iterator< T,ValCont,RetType > &right); ~XSModExpTree_Iterator(); XSModExpTree_Iterator< T,ValCont,RetType > & operator=(const XSModExpTree_Iterator< T,ValCont,RetType > &right); XSModExpTree_Iterator& operator ++ (); const XSModExpTree_Iterator operator ++ (int ); bool operator == (const XSModExpTree_Iterator& right) const; bool operator != (const XSModExpTree_Iterator& right) const; RetType& operator * (); RetType* operator -> (); void childNodes (IntegerArray& children) const; XSModExpTree_Iterator& postOrderNext (); // Additional Public Declarations protected: // Additional Protected Declarations private: XSModExpTree_Iterator (const ExpTreeNodeType* nodePointer, const std::vector& nodeArray, ValCont& valueArray, const XSModExpTree* theContainer); int nextPreOrder (int nodePos) const; // Additional Private Declarations private: //## implementation // Data Members for Class Attributes const ExpTreeNodeType* m_nodePointer; const std::vector& m_nodeArray; ValCont& m_valueArray; const XSModExpTree* m_theContainer; // Additional Implementation Declarations template friend class XSModExpTree; }; // This is a specialized tree class for containing the // relations between XSPEC Expressions and their nested // sub-Expressions (or the same relations among Component // Group objects). This does not offer the level of // functionality of STL containers (by a long shot). // // Important: This performs NO internal ordering. It // ASSUMES client will enter values in a POST_ORDER fashion // and supply appropriate relational information . The // tree iterators will then perform a PRE-ORDER traversal, // but with the begin node defined as the root's first // child rather than the root itself (due to the nature of // the way Expressions and ComponentGroups are used in // XSPEC). // // As with STL, the end iterator does not point to a valid // element. Also like STL, this DOES NOT call delete on // values during cleanup if T is a pointer. The client // will need to do this by retrieving the values array. template class XSModExpTree { public: typedef XSModExpTree_Iterator,T > iterator; typedef XSModExpTree_Iterator, const T > const_iterator; XSModExpTree(); XSModExpTree(const XSModExpTree< T > &right); ~XSModExpTree(); XSModExpTree< T > & operator=(const XSModExpTree< T > &right); typename XSModExpTree::iterator begin (); typename XSModExpTree::iterator end (); void clear (); // This REQUIRES that insertion is done in post-order // fashion, meaning that all nodes specified in the // children array have already been inserted. void insert (T entry, const IntegerArray& children); typename XSModExpTree::const_iterator begin () const; typename XSModExpTree::const_iterator end () const; std::vector& values (); size_t size () const; int position (const typename XSModExpTree::iterator& it) const; int position (const typename XSModExpTree::const_iterator& it) const; typename XSModExpTree::iterator postBegin (); typename XSModExpTree::const_iterator postBegin () const; void insertRoot (const IntegerArray& rootChildren); const IntegerArray& getRoot () const; const std::vector& values () const; public: // Additional Public Declarations protected: // Additional Protected Declarations private: void swap (XSModExpTree& right); // Additional Private Declarations private: //## implementation // Data Members for Class Attributes std::vector m_nodes; std::vector m_values; // Additional Implementation Declarations }; // Parameterized Class XSModExpTree_Iterator template inline bool XSModExpTree_Iterator::operator == (const XSModExpTree_Iterator& right) const { return m_nodePointer == right.m_nodePointer; } template inline bool XSModExpTree_Iterator::operator != (const XSModExpTree_Iterator& right) const { return m_nodePointer != right.m_nodePointer; } template inline RetType& XSModExpTree_Iterator::operator * () { if (!m_nodePointer) throw RedAlert("Attempting to dereference non-existing XSModExpTree node."); return m_valueArray[m_nodePointer->pos]; } template inline RetType* XSModExpTree_Iterator::operator -> () { if (!m_nodePointer) throw RedAlert("Attempting to dereference non-existing XSModExpTree node."); return &m_valueArray[m_nodePointer->pos]; } template inline void XSModExpTree_Iterator::childNodes (IntegerArray& children) const { children = m_nodePointer->children; } // Parameterized Class XSModExpTree template inline std::vector& XSModExpTree::values () { return m_values; } template inline size_t XSModExpTree::size () const { return m_values.size(); } template inline int XSModExpTree::position (const typename XSModExpTree::iterator& it) const { int nodePos = it.m_nodePointer->pos; if (nodePos < 0 || nodePos >= (int)m_values.size()) throw RedAlert("Invalid node pointer accessed in ExpTree position function."); return nodePos; } template inline int XSModExpTree::position (const typename XSModExpTree::const_iterator& it) const { int nodePos = it.m_nodePointer->pos; if (nodePos < 0 || nodePos >= (int)m_values.size()) throw RedAlert("Invalid node pointer accessed in ExpTree position function."); return nodePos; } template inline const std::vector& XSModExpTree::values () const { return m_values; } // Parameterized Class XSModExpTree_Iterator template XSModExpTree_Iterator::XSModExpTree_Iterator(const XSModExpTree_Iterator &right) :m_nodePointer(right.m_nodePointer), // shallow copies, non-owning m_nodeArray(right.m_nodeArray), m_valueArray(right.m_valueArray), m_theContainer(right.m_theContainer) { } template XSModExpTree_Iterator::XSModExpTree_Iterator (const ExpTreeNodeType* nodePointer, const std::vector& nodeArray, ValCont& valueArray, const XSModExpTree* theContainer) :m_nodePointer(nodePointer), m_nodeArray(nodeArray), m_valueArray(valueArray), m_theContainer(theContainer) { } template XSModExpTree_Iterator::~XSModExpTree_Iterator() { } template XSModExpTree_Iterator & XSModExpTree_Iterator::operator=(const XSModExpTree_Iterator &right) { if (m_theContainer != right.m_theContainer) throw RedAlert("Invalid attempt to assign iterator of one XSModExpTree to another."); m_nodePointer = right.m_nodePointer; return *this; } template XSModExpTree_Iterator& XSModExpTree_Iterator::operator ++ () { // Pre-increment. If m_nodePointer = 0, assume we are at the end and // do nothing. if (m_nodePointer) { // Let's not assume anywhere that &a[n] == &a[0]+n since this // wasn't truly in the '98 standard. int nextPos = nextPreOrder(m_nodePointer->pos); if (nextPos == (int)m_nodeArray.size()-1) { // This is the root node, which we'll use for the end. m_nodePointer = 0; } else m_nodePointer = &m_nodeArray[nextPos]; } return *this; } template const XSModExpTree_Iterator XSModExpTree_Iterator::operator ++ (int ) { XSModExpTree_Iterator oldNode(*this); ++(*this); return oldNode; } template int XSModExpTree_Iterator::nextPreOrder (int nodePos) const { // This is a recursive function. const ExpTreeNodeType& testNode = m_nodeArray[nodePos]; int nChildren = (int)testNode.children.size(); int currPos = m_nodePointer->pos; int nextPos = 0; if (nChildren) { if (currPos == testNode.pos) // Simple case, just grab the node's first child. nextPos = testNode.children[0]; else { // It has been kicked back up here from a child. Therefore // find whose subtree this is coming from, indicated by first // child with pos >= currPos (ASSUMING insertions were post-order). int currSubTree = -1; for (int i=0; i= currPos) { currSubTree = i; break; } } if (currSubTree == -1) { throw RedAlert("ModExpTree structural relation error."); } else if (currSubTree == nChildren-1) { // Pass back up to parent, or if we're at root, simply return // the root node position. if (testNode.parentPos >= 0) nextPos = nextPreOrder(testNode.parentPos); else nextPos = m_nodeArray.size() - 1; } else { // Start on next subtree nextPos = testNode.children[currSubTree+1]; } } } else { // Pass back up to parent. Don't need to check if this is root // node, since root will always have at least 1 child and can't // get in here. nextPos = nextPreOrder(testNode.parentPos); } return nextPos; } template XSModExpTree_Iterator& XSModExpTree_Iterator::postOrderNext () { if (m_nodePointer) { int currPos = m_nodePointer->pos; if (currPos >= (int)m_nodeArray.size() - 2) { // Next is the root node, which we'll use for the end. m_nodePointer = 0; } else m_nodePointer = &m_nodeArray[currPos+1]; } return *this; } // Additional Declarations // Parameterized Class XSModExpTree template XSModExpTree::XSModExpTree() { } template XSModExpTree::XSModExpTree(const XSModExpTree &right) : m_nodes(right.m_nodes), m_values(right.m_values) { } template XSModExpTree::~XSModExpTree() { } template XSModExpTree & XSModExpTree::operator=(const XSModExpTree &right) { if (this != &right) { XSModExpTree tmp(right); swap(tmp); } return *this; } template typename XSModExpTree::iterator XSModExpTree::begin () { // Not true pre-order since begin is not defined as the root, // but the root's first child. The root will be treated as // the end. ExpTreeNodeType* beginNode = 0; if (m_nodes.size() > 1) { // We have a root, and root has a child. const ExpTreeNodeType& root = m_nodes[m_nodes.size()-1]; beginNode = &m_nodes[root.children[0]]; } return iterator(beginNode, m_nodes, m_values, this); } template typename XSModExpTree::iterator XSModExpTree::end () { ExpTreeNodeType* endNode = 0; return iterator(endNode, m_nodes, m_values, this); } template void XSModExpTree::clear () { m_values.clear(); m_nodes.clear(); } template void XSModExpTree::insert (T entry, const IntegerArray& children) { m_values.push_back(entry); ExpTreeNodeType newNode; newNode.pos = static_cast(m_values.size()-1); // parentPos will be set when this node's parent is // inserted into the tree. newNode.parentPos = -1; newNode.children = children; m_nodes.push_back(newNode); for (size_t i=0; i typename XSModExpTree::const_iterator XSModExpTree::begin () const { const ExpTreeNodeType* beginNode = 0; if (m_nodes.size() > 1) { // We have a root, and root has a child. const ExpTreeNodeType& root = m_nodes[m_nodes.size()-1]; beginNode = &m_nodes[root.children[0]]; } return const_iterator(beginNode, m_nodes, m_values, this); } template typename XSModExpTree::const_iterator XSModExpTree::end () const { const ExpTreeNodeType* endNode = 0; return const_iterator(endNode, m_nodes, m_values, this); } template void XSModExpTree::swap (XSModExpTree& right) { std::swap(m_nodes, right.m_nodes); std::swap(m_values, right.m_values); } template typename XSModExpTree::iterator XSModExpTree::postBegin () { ExpTreeNodeType* beginNode = 0; if (m_nodes.size() > 1) { // We have a root, and root has a child. beginNode = &m_nodes[0]; } return iterator(beginNode, m_nodes, m_values, this); } template typename XSModExpTree::const_iterator XSModExpTree::postBegin () const { const ExpTreeNodeType* beginNode = 0; if (m_nodes.size() > 1) { // We have a root, and root has a child. beginNode = &m_nodes[0]; } return const_iterator(beginNode, m_nodes, m_values, this); } template void XSModExpTree::insertRoot (const IntegerArray& rootChildren) { // Root must be inserted AFTER all other nodes. This will // always make m_nodes.size() == m_values.size()+1 in a well // constructed tree. if (m_nodes.size() && m_nodes.size() == m_values.size()) { ExpTreeNodeType newNode; newNode.pos = static_cast(m_nodes.size()); // parentPos will be set when this node's parent is // inserted into the tree. newNode.parentPos = -1; newNode.children = rootChildren; m_nodes.push_back(newNode); for (size_t i=0; i const IntegerArray& XSModExpTree::getRoot () const { if (!m_nodes.size()) { throw RedAlert("Attempting to get root node of empty ModExpTree."); } return m_nodes[m_nodes.size()-1].children; } // Additional Declarations #endif