This repository has been archived on 2026-03-28. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
eodev/eo/gp/parse_tree.h

915 lines
No EOL
24 KiB
C++

#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<Node, RetVal>::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 <class It>
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<Node> 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 <vector>
#include <utility> // 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 <class T>
inline void do_the_swap(T& a, T& b)
{
T tmp = a;
a = b;
b = tmp;
}
template <class T> 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<T> node_allocator;
Tree_alloc<subtree> tree_allocator;
#else
Standard_Node_alloc<T> node_allocator;
Standard_alloc<subtree> tree_allocator;
#endif
public :
typedef subtree* iterator;
typedef const subtree* const_iterator;
//typedef std::vector<subtree >::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 <class It>
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 <class RetVal>
RetVal apply(RetVal v) const { return (*content)(v, begin()); }
template <class RetVal, class It>
RetVal apply(RetVal v, It values) const { return (*content)(v, begin(), values); }
template <class RetVal, class It, class It2>
RetVal apply(RetVal v, It values, It2 moreValues) const
{ return (*content)(v, begin(), values, moreValues); }
template <class RetVal, class It, class It2, class It3>
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<subtree&>(imp_select_cumulative(which)); }
subtree& get_node(size_t which)
{ return const_cast<subtree&>(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 <class It>
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 <class It>
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 <class RetVal>
RetVal apply(RetVal v) const
{ return _root.apply(v); }
template <class RetVal, class It>
RetVal apply(RetVal v, It varValues) const
{ return _root.apply(v, varValues); }
template <class RetVal, class It, class It2>
RetVal apply(RetVal v, It varValues, It2 moreValues) const
{ return _root.apply(v, varValues, moreValues); }
template <class RetVal, class It, class It2, class It3>
RetVal apply(RetVal v, It varValues, It2 moreValues, It3 evenMoreValues) const
{ return _root.apply(v, varValues, moreValues, evenMoreValues); }
/* Customized Swap */
void swap(parse_tree<T>& 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<T>& 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<subtree&>(_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<subtree&>(_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<subtree > pushed;
}; // end class parse_tree
} // end namespace gp_parse_tree
namespace std
{ // for use with stlport on MSVC
template <class T> inline
std::forward_iterator_tag iterator_category(gp_parse_tree::parse_tree<T>::embedded_iterator)
{
return std::forward_iterator_tag();
}
template <class T> inline
ptrdiff_t* distance_type(gp_parse_tree::parse_tree<T>::embedded_iterator)
{
return 0;
}
template <class T> inline
std::forward_iterator_tag iterator_category(gp_parse_tree::parse_tree<T>::iterator)
{
return std::forward_iterator_tag();
}
template <class T> inline
ptrdiff_t* distance_type(gp_parse_tree::parse_tree<T>::iterator)
{
return 0;
}
// Put customized swaps also in std...
template<class T> inline
void swap(gp_parse_tree::parse_tree<T>& a, gp_parse_tree::parse_tree<T>& b)
{
a.swap(b);
}
template<class T> inline
void iter_swap(vector<gp_parse_tree::parse_tree<T> >::iterator a, vector<gp_parse_tree::parse_tree<T> > b)
{
a->swap(*b);
}
} // namespace std
#endif