#ifndef PARSE_TREE_HH #define PARSE_TREE_HH /** * Parse_tree and subtree classes * (c) Maarten Keijzer 1999 * These classes may be used for educational and * other non-commercial purposes only. Even if I * wanted to, I am not at liberty to place this file * under the GNU Lesser Public Library License, as this * would limit my and my institution's freedom to use * this file in closed-source software. * This material is provided "as is", with absolutely no warranty expressed * or implied. Any use is at your own risk. * * Permission to use or copy this software for non-commercial purpose is hereby granted * without fee, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. * Usage information. class Node (your node in the tree) must have the following implemented: ****** Arity ****** int arity(void) const Note: the default constructor of a Node should provide a Node with arity 0! ****** Evaluation ****** A parse_tree is evaluated through one of it's apply() members: 1) parse_tree::apply(void) is the simplest evaluation, it will call RetVal Node::operator()(subtree::const_iterator) 2) parse_tree::apply(It values) will call: RetVal Node::operator()(subtree<... , It values) where It is whatever type you desire (most of the time this will be a vector containing the values of your variables); 3) parse_tree::apply(It values, It2 moreValues) will call: RetVal Node::operator()(subtree<... , It values, It2 moreValues) although I do not see the immediate use of this, however... 4) parse_tree::apply(It values, It2 args, It3 adfs) that calls: RetVal Node::operator()(subtree<... , It values, It2 args, It3 adfs) can be useful for implementing adfs. In general it is a good idea to leave the specifics of the arguments open so that different ways of evaluation remain possible. Implement the simplest eval as: template RetVal operator()(It begin) const ****** Internal Structure ****** A parse_tree has two template arguments: the Node and the ReturnValue produced by evaluating the node. The structure of the tree is defined through a subtree class that has the same two template arguments. The nodes are stored in a tree like : node4 / \ node3 node2 / \ node1 node0 where nodes 2 and 4 have arity 2 and nodes 0,1 and 3 arity 0 (terminals) The nodes are subtrees, containing the structure of the tree, together with its size and depth. They contain a Node, the user defined template argument. To access these nodes from a subtree, use operator-> or operator*. The numbers behind the nodes define a reverse-polish or postfix traversel through the tree. The parse_tree defines iterators on the tree such that tree.begin() points at the subtree at node0 and tree.back() returns the subtree at node4, the complete tree Likewise operator[] is defined on the tree, such that: tree[0] will return the subtree at node0, while tree[2] will return the subtree at node2 Assigments of subtrees is protected so that the code: tree[2] = tree[0]; will not crash and result in a tree structured as: node4 / \ node3 node0 Note that the rank numbers no longer specify their place in the tree: tree[0] still points at node0, but tree[1] now points to node3 and tree[2] points at the root node4 Embedded iterators are implemented to iterate over nodes rather than subtrees. So an easy way to copy your tree to a vector is: vector vec(tree.size()); copy(tree.ebegin(), tree.eend(), vec.begin()); You can also copy it to an ostream_iterator with this technique, given that your Node implements an appropriate operator<<. Reinitializing a tree with the vector is also simple: tree.clear(); copy(vec.begin(), vec.end(), back_inserter(tree)); Note that the back_inserter must be used as there is no resize member in the parse_tree. back_inserter will use the push_back member from the parse_tree */ #include #include // for swap #ifdef _MSC_VER #pragma warning(disable : 4786) // disable this nagging warning about the limitations of the mirkosoft debugger #endif namespace gp_parse_tree { #include "node_pool.h" template inline void do_the_swap(T& a, T& b) { T tmp = a; a = b; b = tmp; } template class parse_tree { public : class subtree { // a bit nasty way to use a pool allocator (which would otherwise use slooow new and delete) #if (defined(__GNUC__) || defined(_MSC_VER)) && !defined(_MT) Node_alloc node_allocator; Tree_alloc tree_allocator; #else Standard_Node_alloc node_allocator; Standard_alloc tree_allocator; #endif public : typedef subtree* iterator; typedef const subtree* const_iterator; //typedef std::vector::const_reverse_iterator const_reverse_iterator; /* Constructors, assignments */ subtree(void) : content(node_allocator.allocate()), args(0), parent(0), _cumulative_size(0), _depth(0), _size(1) {} subtree(const subtree& s) : content(node_allocator.allocate()), args(0), parent(0), _cumulative_size(0), _depth(0), _size(1) { copy(s); } subtree(const T& t) : content(node_allocator.allocate()), args(0), parent(0), _cumulative_size(0), _depth(0), _size(1) { copy(t); } template subtree(It b, It e) : content(node_allocator.allocate()), args(0), parent(0), _cumulative_size(0), _depth(0), _size(1) { // initialize in prefix way for efficiency reasons init(b, --e); } virtual ~subtree(void) { tree_allocator.deallocate(args, arity()); node_allocator.deallocate(content); } subtree& operator=(const subtree& s) { if (s.get_root() == get_root()) { // from the same tree, maybe a child. Don't take any chances subtree anotherS = s; return copy(anotherS); } return copy(s); } subtree& operator=(const T& t) { return copy(t); } /* Access to the nodes */ T& operator*(void) { return *content; } const T& operator*(void) const { return *content; } T* operator->(void) { return content; } const T* operator->(void) const { return content; } /* Equality, inequality check, Node needs to implement operator== */ bool operator==(const subtree& other) const { if (! (*content == *other.content)) return false; for (int i = 0; i < arity(); i++) { if (!(args[i] == other.args[i])) return false; } return true; } bool operator !=(const subtree& other) const { return !operator==(other); } /* Arity */ int arity(void) const { return content->arity(); } /* Evaluation with an increasing amount of user defined arguments */ template RetVal apply(RetVal v) const { return (*content)(v, begin()); } template RetVal apply(RetVal v, It values) const { return (*content)(v, begin(), values); } template RetVal apply(RetVal v, It values, It2 moreValues) const { return (*content)(v, begin(), values, moreValues); } template RetVal apply(RetVal v, It values, It2 moreValues, It3 evenMoreValues) const { return (*content)(v, begin(), values, moreValues, evenMoreValues); } /* Iterators */ iterator begin(void) { return args; } const_iterator begin(void) const { return args; } iterator end(void) { return args + arity(); } const_iterator end(void) const { return args + arity(); } subtree& operator[](int i) { return *(begin() + i); } const subtree& operator[](int i) const { return *(begin() + i); } /* Some statistics */ size_t size(void) const { return _size; } size_t cumulative_size(void) const { return _cumulative_size; } size_t depth(void) const { return _depth; } const subtree& select_cumulative(size_t which) const { return imp_select_cumulative(which); } subtree& select_cumulative(size_t which) { return const_cast(imp_select_cumulative(which)); } subtree& get_node(size_t which) { return const_cast(imp_get_node(which));} const subtree& get_node(size_t which) const { return imp_get_node(which); } subtree* get_parent(void) { return parent; } const subtree* get_parent(void) const { return parent; } void clear(void) { tree_allocator.deallocate(args, arity()); args = 0; *content = T(); parent = 0; _cumulative_size = 0; _depth = 0; _size = 0; } void swap(subtree& y) { do_the_swap(content, y.content); do_the_swap(args, y.args); do_the_swap(parent, y.parent); do_the_swap(_cumulative_size, y._cumulative_size); do_the_swap(_depth, y._depth); do_the_swap(_size, y._size); updateAfterInsert(); } friend void swap(subtree& x, subtree& y) { x.swap(y); } protected : virtual void updateAfterInsert(void) { _depth = 0; _size = 1; _cumulative_size = 0; for (iterator it = begin(); it != end(); ++it) { _size += it->size(); _cumulative_size += it->_cumulative_size; _depth = it->_depth > _depth? it->_depth: _depth; } _cumulative_size += _size; _depth++; if (parent) parent->updateAfterInsert(); } private : const subtree& imp_select_cumulative(size_t which) const { if (which >= (_cumulative_size - size())) return *this; // else for (int i = arity() - 1; i >= 0; --i) { if (which < args[i]._cumulative_size) return args[i].imp_select_cumulative(which); which -= args[i]._cumulative_size; } return *this; // error! } const subtree& imp_get_node(size_t which) const { if (which == size() - 1) return *this; for (int i = arity() - 1; i >= 0; --i) { unsigned c_size = args[i].size(); if (which < c_size) return args[i].imp_get_node(which); which -= c_size; } return *this; // error! } const subtree* get_root(void) const { if (parent == 0) return this; // else return parent->get_root(); } subtree& copy(const subtree& s) { int oldArity = arity(); disown(); int ar = s.arity(); if (ar != oldArity) { tree_allocator.deallocate(args, oldArity); args = tree_allocator.allocate(ar); //if (ar > 0) // args = new subtree [ar]; //else // args = 0; } switch(ar) { case 3 : args[2].copy(s.args[2]); // no break! case 2 : args[1].copy(s.args[1]); case 1 : args[0].copy(s.args[0]); break; case 0 : break; default : { for (int i = 0; i < ar; ++i) { args[i].copy(s.args[i]); } } } *content = *s.content; adopt(); updateAfterInsert(); return *this; } subtree& copy(const T& t) { int oldArity = arity(); if (content != &t) *content = t; else oldArity = -1; int ar = arity(); if (ar != oldArity) { if (oldArity != -1) tree_allocator.deallocate(args, oldArity); args = tree_allocator.allocate(ar); //if (ar > 0) // args = new subtree [ar]; //else // args = 0; } adopt(); updateAfterInsert(); return *this; } void disown(void) { switch(arity()) { case 3 : args[2].parent = 0; // no break! case 2 : args[1].parent = 0; case 1 : args[0].parent = 0; break; case 0 : break; default : { for (iterator it = begin(); it != end(); ++it) { it->parent = 0; } } } } void adopt(void) { switch(arity()) { case 3 : args[2].parent = this; // no break! case 2 : args[1].parent = this; case 1 : args[0].parent = this; break; case 0 : break; default : { for (iterator it = begin(); it != end(); ++it) { it->parent = this; } } } } template void init(It b, It& last) { *this = *last; #ifndef NDEBUG if (last == b && arity() > 0) { throw "subtree::init()"; } #endif for (int i = 0; i < arity(); ++i) { args[i].parent = 0; args[i].init(b, --last); args[i].parent = this; } updateAfterInsert(); } T* content; subtree* args; subtree* parent; size_t _cumulative_size; size_t _depth; size_t _size; }; // Continuing with parse_tree typedef T value_type; /* Constructors and Assignments */ parse_tree(void) : _root(), pushed() {} parse_tree(const parse_tree& org) : _root(org._root), pushed(org.pushed) { } parse_tree(const subtree& sub) : _root(sub), pushed() { } template parse_tree(It b, It e) : _root(b, e), pushed() {} virtual ~parse_tree(void) {} parse_tree& operator=(const parse_tree& org) { return copy(org); } parse_tree& operator=(const subtree& sub) { return copy(sub); } /* Equality and inequality */ bool operator==(const parse_tree& other) const { return _root == other._root; } bool operator !=(const parse_tree& other) const { return !operator==(other); } /* Simple tree statistics */ size_t size(void) const { return _root.size(); } size_t depth(void) const { return _root.depth(); } void clear(void) { _root.clear(); pushed.resize(0); } /* Evaluation (application), with an increasing number of user defined arguments */ template RetVal apply(RetVal v) const { return _root.apply(v); } template RetVal apply(RetVal v, It varValues) const { return _root.apply(v, varValues); } template RetVal apply(RetVal v, It varValues, It2 moreValues) const { return _root.apply(v, varValues, moreValues); } template RetVal apply(RetVal v, It varValues, It2 moreValues, It3 evenMoreValues) const { return _root.apply(v, varValues, moreValues, evenMoreValues); } /* Customized Swap */ void swap(parse_tree& other) { do_the_swap(pushed, other.pushed); _root.swap(other._root); } /* Definitions of the iterators */ class base_iterator { public : base_iterator() {} base_iterator(subtree* n) { node = n; } base_iterator& operator=(const base_iterator& org) { node = org.node; return *this; } bool operator==(const base_iterator& org) const { return node == org.node; } bool operator!=(const base_iterator& org) const { return !operator==(org); } base_iterator operator+(size_t n) const { base_iterator tmp = *this; for(;n != 0; --n) { ++tmp; } return tmp; } base_iterator& operator++(void) { subtree* parent = node->get_parent(); if (parent == 0) { node = 0; return *this; } // else subtree::iterator it; for (it = parent->begin(); it != parent->end(); ++it) { if (node == &(*it)) break; } if (it == parent->begin()) node = parent; else { node = &(--it)->get_node(0); } return *this; } base_iterator operator++(int) { base_iterator tmp = *this; operator++(); return tmp; } protected : subtree* node; }; class iterator : public base_iterator { public : typedef std::forward_iterator_tag iterator_category; typedef subtree value_type; typedef size_t distance_type; typedef size_t difference_type; typedef subtree* pointer; typedef subtree& reference; iterator() : base_iterator() {} iterator(subtree* n): base_iterator(n) {} iterator& operator=(const iterator& org) { base_iterator::operator=(org); return *this; } subtree& operator*(void) { return *node; } subtree* operator->(void) { return node; } }; class embedded_iterator : public base_iterator { public : typedef std::forward_iterator_tag iterator_category; typedef T value_type; typedef size_t distance_type; typedef size_t difference_type; typedef T* pointer; typedef T& reference; embedded_iterator() : base_iterator() {} embedded_iterator(subtree* n): base_iterator(n) {} embedded_iterator& operator=(const embedded_iterator& org) { base_iterator::operator=(org); return *this; } T& operator*(void) { return **node; } T* operator->(void) { return &**node; } }; class base_const_iterator { public : base_const_iterator() {} base_const_iterator(const subtree* n) { node = n; } base_const_iterator& operator=(const base_const_iterator& org) { node = org.node; return *this; } bool operator==(const base_const_iterator& org) const { return node == org.node; } bool operator!=(const base_const_iterator& org) const { return !operator==(org); } base_const_iterator& operator++(void) { const subtree* parent = node->get_parent(); if (parent == 0) { node = 0; return *this; } // else subtree::const_iterator it; for (it = parent->begin(); it != parent->end(); ++it) { if (node == &(*it)) break; } if (it == parent->begin()) node = parent; else node = &(--it)->get_node(0); return *this; } base_const_iterator operator++(int) { base_const_iterator tmp = *this; operator++(); return tmp; } protected : const subtree* node; }; class const_iterator : public base_const_iterator { public : typedef std::forward_iterator_tag iterator_category; typedef const subtree value_type; typedef size_t distance_type; typedef size_t difference_type; typedef const subtree* pointer; typedef const subtree& reference; const_iterator() : base_const_iterator() {} const_iterator(const subtree* n): base_const_iterator(n) {} const_iterator& operator=(const const_iterator& org) { base_const_iterator::operator=(org); return *this; } const subtree& operator*(void) { return *node; } const subtree* operator->(void) { return node; } }; class embedded_const_iterator : public base_const_iterator { public : typedef std::forward_iterator_tag iterator_category; typedef const T value_type; typedef size_t distance_type; typedef size_t difference_type; typedef const T* pointer; typedef const T& reference; embedded_const_iterator() : base_const_iterator() {} embedded_const_iterator(const subtree* n): base_const_iterator(n) {} embedded_const_iterator& operator=(const embedded_const_iterator& org) { base_const_iterator::operator=(org); return *this; } embedded_const_iterator operator+(size_t n) const { embedded_const_iterator tmp = *this; for(;n != 0; --n) { ++tmp; } return tmp; } const T& operator*(void) const { return **node; } const T* operator->(void) const { return node->operator->(); } }; /* Iterator access */ iterator begin(void) { return iterator(&operator[](0)); } const_iterator begin(void) const { return const_iterator(&operator[](0)); } iterator end(void) { return iterator(0); } const_iterator end(void) const { return const_iterator(0);} embedded_iterator ebegin(void) { return embedded_iterator(&operator[](0)); } embedded_const_iterator ebegin(void) const { return embedded_const_iterator(&operator[](0)); } embedded_iterator eend(void) { return embedded_iterator(0); } embedded_const_iterator eend(void) const { return embedded_const_iterator(0);} bool empty(void) const { return size() == 0; } bool valid(void) const { return pushed.empty(); } /* push_back */ void push_back(const parse_tree& tree) { if (!empty()) pushed.push_back(_root); _root = tree.back(); } void push_back(const T& t) { if (!empty()) pushed.push_back(_root); _root = t; for (subtree::iterator it = _root.begin(); it != _root.end(); it++) { *it = pushed.back(); pushed.pop_back(); } } /* Access to subtrees */ subtree& back(void) { return _root; } const subtree& back(void) const { return _root; } subtree& root(void) { return _root; } const subtree& root(void) const { return _root; } subtree& front(void) { return _root[0]; } const subtree& front(void) const { return _root[0]; } subtree& operator[](size_t i) { return const_cast(_root.get_node(i)); } const subtree& operator[](size_t i) const { return _root.get_node(i); } subtree& get_cumulative(size_t i) { return const_cast(_root.get_cumulative(i)); } const subtree& get_cumulative(size_t i) const { return get_cumulative(i); } private : parse_tree& copy(const parse_tree& org) { _root = org._root; pushed = org.pushed; return *this; } parse_tree& copy(const subtree& sub) { _root = sub; pushed.resize(0); return *this; } subtree _root; std::vector pushed; }; // end class parse_tree } // end namespace gp_parse_tree namespace std { // for use with stlport on MSVC template inline std::forward_iterator_tag iterator_category(gp_parse_tree::parse_tree::embedded_iterator) { return std::forward_iterator_tag(); } template inline ptrdiff_t* distance_type(gp_parse_tree::parse_tree::embedded_iterator) { return 0; } template inline std::forward_iterator_tag iterator_category(gp_parse_tree::parse_tree::iterator) { return std::forward_iterator_tag(); } template inline ptrdiff_t* distance_type(gp_parse_tree::parse_tree::iterator) { return 0; } // Put customized swaps also in std... template inline void swap(gp_parse_tree::parse_tree& a, gp_parse_tree::parse_tree& b) { a.swap(b); } template inline void iter_swap(vector >::iterator a, vector > b) { a->swap(*b); } } // namespace std #endif