|
@ -71,7 +71,7 @@ include_directories(SYSTEM
|
|||
${SDL2_INCLUDE_DIR}
|
||||
${PNG_INCLUDE_DIRS}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
lib/tree-2.81/src
|
||||
lib/tree-3.1/src
|
||||
)
|
||||
include_directories(
|
||||
src
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
a.out
|
||||
*~
|
||||
doxygen
|
|
@ -1,3 +1,22 @@
|
|||
2015-05-06 Kasper Peeters <kasper.peeters@phi-sci.com>
|
||||
|
||||
* Released 3.1
|
||||
|
||||
* Added asserts in 'subtree' in order to warn users about
|
||||
constructing empty subtrees.
|
||||
|
||||
2014-12-25 Kasper Peeters <kasper.peeters@phi-sci.com>
|
||||
|
||||
* Released 3.0
|
||||
|
||||
* Added move constructor and move_out, move_in, move_in_as_nth_child.
|
||||
|
||||
2013-09-02 Kasper Peeters <kasper.peeters@aei.mpg.de>
|
||||
|
||||
* Released 2.9
|
||||
|
||||
* Added 'pre_order_iterator::next_skip_children()'.
|
||||
|
||||
2011-08-23 Kasper Peeters <kasper.peeters@aei.mpg.de>
|
||||
|
||||
* Brown paper bag release 2.81.
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
RELEASE=2.8
|
||||
RELEASE=3.1
|
||||
HTML=${HOME}/public_html/
|
||||
|
||||
.PHONY: doc tarball
|
|
@ -76,7 +76,7 @@
|
|||
and all other things referred to on this page) is contained in the
|
||||
tarball</div>
|
||||
<div class="filename">
|
||||
<a href="tree-2.8.tar.gz">tree-2.8.tar.gz</a>
|
||||
<a href="tree-2.81.tar.gz">tree-2.81.tar.gz</a>
|
||||
</div>
|
||||
<div class="text">
|
||||
Feel free to copy the header <a href="tree.hh">tree.hh</a>
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 782 B After Width: | Height: | Size: 782 B |
Before Width: | Height: | Size: 881 B After Width: | Height: | Size: 881 B |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 888 KiB After Width: | Height: | Size: 888 KiB |
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 141 KiB |
|
@ -1,3 +1,4 @@
|
|||
*.o
|
||||
*.res
|
||||
test1
|
||||
test2
|
|
@ -1,10 +1,15 @@
|
|||
|
||||
%.o: %.cc
|
||||
g++ -c -I. $^
|
||||
all: test1 test2
|
||||
|
||||
%.o: %.cc
|
||||
g++ -g -c -Wall -O2 -std=c++11 -I. $^
|
||||
|
||||
test1: test1.o
|
||||
g++ -o test1 test1.o
|
||||
|
||||
test2: test2.o
|
||||
g++ -o test2 test2.o
|
||||
|
||||
run_tests: test1 test1.req
|
||||
./test1 > test1.res
|
||||
@diff test1.res test1.req
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
#include <iostream>
|
||||
#include "tree.hh"
|
||||
#include "tree_util.hh"
|
||||
|
111
lib/tree-3.1/src/test2.cc
Normal file
|
@ -0,0 +1,111 @@
|
|||
|
||||
#include <iostream>
|
||||
#include "tree.hh"
|
||||
#include "tree_util.hh"
|
||||
|
||||
tree<std::string> test_move_constructor()
|
||||
{
|
||||
tree<std::string> mtree;
|
||||
tree<std::string>::iterator it = mtree.set_head("top");
|
||||
mtree.append_child(it, "one");
|
||||
mtree.append_child(it, "two");
|
||||
mtree.append_child(it, "three");
|
||||
|
||||
tree<std::string> ctree(std::move(mtree));
|
||||
|
||||
std::cout << "ctree:" << std::endl;
|
||||
kptree::print_tree_bracketed(ctree);
|
||||
std::cout << "\nmtree:" << std::endl;
|
||||
kptree::print_tree_bracketed(mtree);
|
||||
|
||||
return ctree;
|
||||
}
|
||||
|
||||
tree<std::string> test_move_out()
|
||||
{
|
||||
tree<std::string> mtree;
|
||||
tree<std::string>::iterator it = mtree.set_head("top");
|
||||
mtree.append_child(it, "one");
|
||||
auto it2 = mtree.append_child(it, "two");
|
||||
mtree.append_child(it, "three");
|
||||
mtree.append_child(it2, "four");
|
||||
mtree.append_child(it2, "five");
|
||||
|
||||
auto ret = mtree.move_out(it2);
|
||||
ret.debug_verify_consistency();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void test_move_in(tree<std::string>& other)
|
||||
{
|
||||
tree<std::string> mtree;
|
||||
tree<std::string>::iterator it = mtree.set_head("top");
|
||||
mtree.append_child(it, "one");
|
||||
auto it3=mtree.append_child(it, "three");
|
||||
|
||||
mtree.move_in(it3, other);
|
||||
mtree.debug_verify_consistency();
|
||||
kptree::print_tree_bracketed(mtree);
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
void test_move_in_as_nth_child(int n)
|
||||
{
|
||||
tree<std::string> mtree, other;
|
||||
tree<std::string>::iterator it = mtree.set_head("top");
|
||||
mtree.append_child(it, "one");
|
||||
mtree.append_child(it, "three");
|
||||
|
||||
auto ot1 = other.set_head("hi");
|
||||
other.insert_after(ot1, "second");
|
||||
other.append_child(ot1, "1");
|
||||
other.append_child(ot1, "2");
|
||||
|
||||
mtree.move_in_as_nth_child(it, n, other);
|
||||
mtree.debug_verify_consistency();
|
||||
kptree::print_tree_bracketed(mtree);
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
void test_move_below(tree<std::string>& other)
|
||||
{
|
||||
tree<std::string> mtree;
|
||||
tree<std::string>::iterator it = mtree.set_head("top");
|
||||
mtree.append_child(it, "one");
|
||||
auto it3=mtree.append_child(it, "three");
|
||||
|
||||
mtree.move_in(it3, other);
|
||||
kptree::print_tree_bracketed(mtree);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// Move constructor.
|
||||
tree<std::string> res = test_move_constructor();
|
||||
std::cout << "res:" << std::endl;
|
||||
kptree::print_tree_bracketed(res);
|
||||
|
||||
// Move out.
|
||||
tree<std::string> res2 = test_move_out();
|
||||
std::cout << "\nres2:" << std::endl;
|
||||
kptree::print_tree_bracketed(res2);
|
||||
std::cout << std::endl;
|
||||
|
||||
// Move in.
|
||||
test_move_in(res2);
|
||||
std::cout << "\n";
|
||||
kptree::print_tree_bracketed(res2);
|
||||
std::cout << "\n";
|
||||
|
||||
// Move in as nth child.
|
||||
test_move_in_as_nth_child(0);
|
||||
test_move_in_as_nth_child(1);
|
||||
test_move_in_as_nth_child(2);
|
||||
try {
|
||||
test_move_in_as_nth_child(3);
|
||||
}
|
||||
catch(const std::range_error& ex) {
|
||||
std::cout << ex.what() << std::endl;
|
||||
}
|
||||
}
|
|
@ -365,14 +365,8 @@ int main(int argc, char **argv)
|
|||
++li;
|
||||
}
|
||||
|
||||
// tree<std::string> testfixed;
|
||||
// testfixed.insert(testfixed.begin(), "one");
|
||||
// testfixed.insert(testfixed.begin(), "two");
|
||||
// testfixed.insert(testfixed.begin(), "three");
|
||||
// tree<std::string>::fixed_depth_iterator fit=testfixed.begin();
|
||||
// while(testfixed.is_valid(fit)) {
|
||||
// std::cout << *fit << std::endl;
|
||||
// ++fit;
|
||||
// }
|
||||
// test_move_constructor();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,16 @@
|
|||
|
||||
// STL-like templated tree class.
|
||||
//
|
||||
// Copyright (C) 2001-2011 Kasper Peeters <kasper@phi-sci.com>
|
||||
// Copyright (C) 2001-2014 Kasper Peeters <kasper@phi-sci.com>
|
||||
// Distributed under the GNU General Public License version 3.
|
||||
//
|
||||
// When used together with the htmlcxx library to create
|
||||
// HTML::Node template instances, the GNU Lesser General Public
|
||||
// version 2 applies. Special permission to use tree.hh under
|
||||
// the LGPL for other projects can be requested from the author.
|
||||
// Special permission to use tree.hh under the conditions of a
|
||||
// different license can be requested from the author.
|
||||
|
||||
/** \mainpage tree.hh
|
||||
\author Kasper Peeters
|
||||
\version 2.81
|
||||
\date 23-Aug-2011
|
||||
\version 3.1
|
||||
\date 06-May-2015
|
||||
\see http://tree.phi-sci.com/
|
||||
\see http://tree.phi-sci.com/ChangeLog
|
||||
|
||||
|
@ -77,12 +75,14 @@ class tree {
|
|||
class sibling_iterator;
|
||||
class leaf_iterator;
|
||||
|
||||
tree();
|
||||
tree(const T&);
|
||||
tree(); // empty constructor
|
||||
tree(const T&); // constructor setting given element as head
|
||||
tree(const iterator_base&);
|
||||
tree(const tree<T, tree_node_allocator>&);
|
||||
tree(const tree<T, tree_node_allocator>&); // copy constructor
|
||||
tree(tree<T, tree_node_allocator>&&); // move constructor
|
||||
~tree();
|
||||
tree<T,tree_node_allocator>& operator=(const tree<T, tree_node_allocator>&);
|
||||
tree<T,tree_node_allocator>& operator=(const tree<T, tree_node_allocator>&); // copy assignment
|
||||
tree<T,tree_node_allocator>& operator=(tree<T, tree_node_allocator>&&); // move assignment
|
||||
|
||||
/// Base class for iterators, only pointers stored, no traversal logic.
|
||||
#ifdef __SGI_STL_PORT
|
||||
|
@ -134,6 +134,8 @@ class tree {
|
|||
pre_order_iterator operator--(int);
|
||||
pre_order_iterator& operator+=(unsigned int);
|
||||
pre_order_iterator& operator-=(unsigned int);
|
||||
|
||||
pre_order_iterator& next_skip_children();
|
||||
};
|
||||
|
||||
/// Depth-first iterator, first accessing the children, then the node itself.
|
||||
|
@ -275,9 +277,9 @@ class tree {
|
|||
/// Return iterator to the parent of a node.
|
||||
template<typename iter> static iter parent(iter);
|
||||
/// Return iterator to the previous sibling of a node.
|
||||
template<typename iter> iter previous_sibling(iter) const;
|
||||
template<typename iter> static iter previous_sibling(iter);
|
||||
/// Return iterator to the next sibling of a node.
|
||||
template<typename iter> iter next_sibling(iter) const;
|
||||
template<typename iter> static iter next_sibling(iter);
|
||||
/// Return iterator to the next node at a given depth.
|
||||
template<typename iter> iter next_at_same_depth(iter) const;
|
||||
|
||||
|
@ -308,6 +310,7 @@ class tree {
|
|||
/// Specialisation of previous member.
|
||||
sibling_iterator insert(sibling_iterator position, const T& x);
|
||||
/// Insert node (with children) pointed to by subtree as previous sibling of node pointed to by position.
|
||||
/// Does not change the subtree itself (use move_in or move_in_below for that).
|
||||
template<typename iter> iter insert_subtree(iter position, const iterator_base& subtree);
|
||||
/// Insert node as next sibling of node pointed to by position.
|
||||
template<typename iter> iter insert_after(iter position, const T& x);
|
||||
|
@ -340,6 +343,16 @@ class tree {
|
|||
/// Move 'source' node (plus its children) to become the node at 'target' (erasing the node at 'target').
|
||||
template<typename iter> iter move_ontop(iter target, iter source);
|
||||
|
||||
/// Extract the subtree starting at the indicated node, removing it from the original tree.
|
||||
tree move_out(iterator);
|
||||
/// Inverse of take_out: inserts the given tree as previous sibling of indicated node by a
|
||||
/// move operation, that is, the given tree becomes empty. Returns iterator to the top node.
|
||||
template<typename iter> iter move_in(iter, tree&);
|
||||
/// As above, but now make the tree a child of the indicated node.
|
||||
template<typename iter> iter move_in_below(iter, tree&);
|
||||
/// As above, but now make the tree the nth child of the indicated node (if possible).
|
||||
template<typename iter> iter move_in_as_nth_child(iter, size_t, tree&);
|
||||
|
||||
/// Merge with other tree, creating new branches and leaves only if they are not already present.
|
||||
void merge(sibling_iterator, sibling_iterator, sibling_iterator, sibling_iterator,
|
||||
bool duplicate_leaves=false);
|
||||
|
@ -486,6 +499,18 @@ tree<T, tree_node_allocator>::tree(const T& x)
|
|||
set_head(x);
|
||||
}
|
||||
|
||||
template <class T, class tree_node_allocator>
|
||||
tree<T, tree_node_allocator>::tree(tree<T, tree_node_allocator>&& x)
|
||||
{
|
||||
head_initialise_();
|
||||
head->next_sibling=x.head->next_sibling;
|
||||
feet->prev_sibling=x.head->prev_sibling;
|
||||
x.head->next_sibling->prev_sibling=head;
|
||||
x.feet->prev_sibling->next_sibling=feet;
|
||||
x.head->next_sibling=x.feet;
|
||||
x.feet->prev_sibling=x.head;
|
||||
}
|
||||
|
||||
template <class T, class tree_node_allocator>
|
||||
tree<T, tree_node_allocator>::tree(const iterator_base& other)
|
||||
{
|
||||
|
@ -533,6 +558,20 @@ tree<T,tree_node_allocator>& tree<T, tree_node_allocator>::operator=(const tree<
|
|||
return *this;
|
||||
}
|
||||
|
||||
template <class T, class tree_node_allocator>
|
||||
tree<T,tree_node_allocator>& tree<T, tree_node_allocator>::operator=(tree<T, tree_node_allocator>&& x)
|
||||
{
|
||||
if(this != &x) {
|
||||
head->next_sibling=x.head->next_sibling;
|
||||
feet->prev_sibling=x.head->prev_sibling;
|
||||
x.head->next_sibling->prev_sibling=head;
|
||||
x.feet->prev_sibling->next_sibling=feet;
|
||||
x.head->next_sibling=x.feet;
|
||||
x.feet->prev_sibling=x.head;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T, class tree_node_allocator>
|
||||
tree<T, tree_node_allocator>::tree(const tree<T, tree_node_allocator>& other)
|
||||
{
|
||||
|
@ -770,7 +809,7 @@ iter tree<T, tree_node_allocator>::parent(iter position)
|
|||
|
||||
template <class T, class tree_node_allocator>
|
||||
template <typename iter>
|
||||
iter tree<T, tree_node_allocator>::previous_sibling(iter position) const
|
||||
iter tree<T, tree_node_allocator>::previous_sibling(iter position)
|
||||
{
|
||||
assert(position.node!=0);
|
||||
iter ret(position);
|
||||
|
@ -780,7 +819,7 @@ iter tree<T, tree_node_allocator>::previous_sibling(iter position) const
|
|||
|
||||
template <class T, class tree_node_allocator>
|
||||
template <typename iter>
|
||||
iter tree<T, tree_node_allocator>::next_sibling(iter position) const
|
||||
iter tree<T, tree_node_allocator>::next_sibling(iter position)
|
||||
{
|
||||
assert(position.node!=0);
|
||||
iter ret(position);
|
||||
|
@ -1477,6 +1516,126 @@ template <typename iter> iter tree<T, tree_node_allocator>::move_ontop(iter targ
|
|||
return src;
|
||||
}
|
||||
|
||||
|
||||
template <class T, class tree_node_allocator>
|
||||
tree<T, tree_node_allocator> tree<T, tree_node_allocator>::move_out(iterator source)
|
||||
{
|
||||
tree ret;
|
||||
|
||||
// Move source node into the 'ret' tree.
|
||||
ret.head->next_sibling = source.node;
|
||||
ret.feet->prev_sibling = source.node;
|
||||
source.node->parent=0;
|
||||
|
||||
// Close the links in the current tree.
|
||||
if(source.node->prev_sibling!=0)
|
||||
source.node->prev_sibling->next_sibling = source.node->next_sibling;
|
||||
|
||||
if(source.node->next_sibling!=0)
|
||||
source.node->next_sibling->prev_sibling = source.node->prev_sibling;
|
||||
|
||||
// Fix source prev/next links.
|
||||
source.node->prev_sibling = ret.head;
|
||||
source.node->next_sibling = ret.feet;
|
||||
|
||||
return ret; // A good compiler will move this, not copy.
|
||||
}
|
||||
|
||||
template <class T, class tree_node_allocator>
|
||||
template<typename iter> iter tree<T, tree_node_allocator>::move_in(iter loc, tree& other)
|
||||
{
|
||||
if(other.head->next_sibling==other.feet) return loc; // other tree is empty
|
||||
|
||||
tree_node *other_first_head = other.head->next_sibling;
|
||||
tree_node *other_last_head = other.feet->prev_sibling;
|
||||
|
||||
sibling_iterator prev(loc);
|
||||
--prev;
|
||||
|
||||
prev.node->next_sibling = other_first_head;
|
||||
loc.node->prev_sibling = other_last_head;
|
||||
other_first_head->prev_sibling = prev.node;
|
||||
other_last_head->next_sibling = loc.node;
|
||||
|
||||
// Adjust parent pointers.
|
||||
tree_node *walk=other_first_head;
|
||||
while(true) {
|
||||
walk->parent=loc.node->parent;
|
||||
if(walk==other_last_head)
|
||||
break;
|
||||
walk=walk->next_sibling;
|
||||
}
|
||||
|
||||
// Close other tree.
|
||||
other.head->next_sibling=other.feet;
|
||||
other.feet->prev_sibling=other.head;
|
||||
|
||||
return other_first_head;
|
||||
}
|
||||
|
||||
template <class T, class tree_node_allocator>
|
||||
template<typename iter> iter tree<T, tree_node_allocator>::move_in_as_nth_child(iter loc, size_t n, tree& other)
|
||||
{
|
||||
if(other.head->next_sibling==other.feet) return loc; // other tree is empty
|
||||
|
||||
tree_node *other_first_head = other.head->next_sibling;
|
||||
tree_node *other_last_head = other.feet->prev_sibling;
|
||||
|
||||
if(n==0) {
|
||||
if(loc.node->first_child==0) {
|
||||
loc.node->first_child=other_first_head;
|
||||
loc.node->last_child=other_last_head;
|
||||
other_last_head->next_sibling=0;
|
||||
other_first_head->prev_sibling=0;
|
||||
}
|
||||
else {
|
||||
loc.node->first_child->prev_sibling=other_last_head;
|
||||
other_last_head->next_sibling=loc.node->first_child;
|
||||
loc.node->first_child=other_first_head;
|
||||
other_first_head->prev_sibling=0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
--n;
|
||||
tree_node *walk = loc.node->first_child;
|
||||
while(true) {
|
||||
if(walk==0)
|
||||
throw std::range_error("tree: move_in_as_nth_child position "
|
||||
+std::to_string(n+1)
|
||||
+" out of range; only "
|
||||
+std::to_string(number_of_children(loc))
|
||||
+" child nodes present");
|
||||
if(n==0)
|
||||
break;
|
||||
--n;
|
||||
walk = walk->next_sibling;
|
||||
}
|
||||
if(walk->next_sibling==0)
|
||||
loc.node->last_child=other_last_head;
|
||||
else
|
||||
walk->next_sibling->prev_sibling=other_last_head;
|
||||
other_last_head->next_sibling=walk->next_sibling;
|
||||
walk->next_sibling=other_first_head;
|
||||
other_first_head->prev_sibling=walk;
|
||||
}
|
||||
|
||||
// Adjust parent pointers.
|
||||
tree_node *walk=other_first_head;
|
||||
while(true) {
|
||||
walk->parent=loc.node;
|
||||
if(walk==other_last_head)
|
||||
break;
|
||||
walk=walk->next_sibling;
|
||||
}
|
||||
|
||||
// Close other tree.
|
||||
other.head->next_sibling=other.feet;
|
||||
other.feet->prev_sibling=other.head;
|
||||
|
||||
return other_first_head;
|
||||
}
|
||||
|
||||
|
||||
template <class T, class tree_node_allocator>
|
||||
void tree<T, tree_node_allocator>::merge(sibling_iterator to1, sibling_iterator to2,
|
||||
sibling_iterator from1, sibling_iterator from2,
|
||||
|
@ -1617,6 +1776,8 @@ bool tree<T, tree_node_allocator>::equal_subtree(const iter& one_, const iter& t
|
|||
template <class T, class tree_node_allocator>
|
||||
tree<T, tree_node_allocator> tree<T, tree_node_allocator>::subtree(sibling_iterator from, sibling_iterator to) const
|
||||
{
|
||||
assert(from!=to); // if from==to, the range is empty, hence no tree to return.
|
||||
|
||||
tree tmp;
|
||||
tmp.set_head(value_type());
|
||||
tmp.replace(tmp.begin(), tmp.end(), from, to);
|
||||
|
@ -1626,6 +1787,8 @@ tree<T, tree_node_allocator> tree<T, tree_node_allocator>::subtree(sibling_itera
|
|||
template <class T, class tree_node_allocator>
|
||||
void tree<T, tree_node_allocator>::subtree(tree& tmp, sibling_iterator from, sibling_iterator to) const
|
||||
{
|
||||
assert(from!=to); // if from==to, the range is empty, hence no tree to return.
|
||||
|
||||
tmp.set_head(value_type());
|
||||
tmp.replace(tmp.begin(), tmp.end(), from, to);
|
||||
}
|
||||
|
@ -2160,6 +2323,14 @@ typename tree<T, tree_node_allocator>::pre_order_iterator tree<T, tree_node_allo
|
|||
return copy;
|
||||
}
|
||||
|
||||
template <class T, class tree_node_allocator>
|
||||
typename tree<T, tree_node_allocator>::pre_order_iterator& tree<T, tree_node_allocator>::pre_order_iterator::next_skip_children()
|
||||
{
|
||||
(*this).skip_children();
|
||||
(*this)++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T, class tree_node_allocator>
|
||||
typename tree<T, tree_node_allocator>::pre_order_iterator tree<T, tree_node_allocator>::pre_order_iterator::operator--(int)
|
||||
{
|