bazaar: a Tree<T> implementation

git-svn-id: svn://ultimatepp.org/upp/trunk@2606 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
kohait 2010-08-13 13:05:11 +00:00
parent 9a12c315e1
commit c761602615
13 changed files with 385 additions and 0 deletions

2
bazaar/Tree/Tree.cpp Normal file
View file

@ -0,0 +1,2 @@
#include "Tree.h"

107
bazaar/Tree/Tree.h Normal file
View file

@ -0,0 +1,107 @@
#ifndef _Tree_Tree_h
#define _Tree_Tree_h
#include <Core/Core.h>
using namespace Upp;
template <class T>
class Tree
: protected Array<T>
{
protected:
typedef Array<T> B;
T * parent;
T * root;
inline void Link(T & t) { t.root = root; t.parent = (T *)this; }
inline void Unlink(T & t) { t.root = NULL; t.parent = NULL; }
void Relink() { for(int i = 0; i < B::GetCount(); i++) { T & t = B::operator[](i); Link(t); t.Relink();} }
public:
T *GetPtr() { return (T *) this; }
const T *GetPtr() const { return (const T *) this; }
T *GetParent() { return parent; }
const T *GetParent() const { return parent; }
T *GetRoot() { return root; }
const T *GetRoot() const { return root; }
void SetAsRoot() { ASSERT(parent == NULL); root = (T *)this; Relink(); }
// Array interface
T& Add() { T & t = B::Add(); Link(t); return t; }
void Add(const T& x) { T & t = B::Add(DeepCopyNew(x)); Link(t); }// return t; }
void AddPick(pick_ T& x) { T & t = B::Add(new T(x)); Link(t); }// return t; }
T& Add(T *newt) { ASSERT(newt->parent == NULL); T & t = B::Add(newt); Link(t); return t; }
using B::operator[];
using B::GetCount;
using B::IsEmpty;
using B::Trim;
void SetCount(int n) { B::SetCount(n); for(int i = 0; i < B::GetCount(); i++) Link(B::operator[](i)); }
void SetCountR(int n) { B::SetCountR(n); for(int i = 0; i < B::GetCount(); i++) Link(B::operator[](i)); }
using B::Clear;
using B::Remove;
T& Insert(int i) { T & t = B::Insert(i); Link(t); return t; }
void InsertPick(int i, pick_ T& x) { Link(x); B::InsertPick(i, x); }
using B::GetIndex;
using B::Swap;
using B::Move;
T *Detach(int i) { T *t = B::Detach(i); Unlink(t); }
T& Set(int i, T *newt) { ASSERT(newt->parent == NULL); T & t = B::Set(i, newt); Link(t); return t; }
void Insert(int i, T *newt) { ASSERT(newt->parent == NULL); B::Insert(i, newt); Link(*newt); }
using B::Drop;
using B::Top;
T *PopDetach() { T * t = B::PopDetach(); Unlink(*t); return t; }
void Swap(Tree& b) { B::Swap(b); for(int i = 0; i < B::GetCount(); i++) Link(B::operator[](i)); for(int i = 0; i < b.GetCount(); i++) b.Link(b[i]); }
Tree& operator<<(const T& x) { Add(x); return *this; }
Tree& operator<<(T *newt) { Add(newt); return *this; }
Tree& operator|(pick_ T& x) { AddPick(x); return *this; }
// Array Interface end
Tree()
: parent(NULL)
, root(NULL)
{}
private:
Tree(const Tree&);
void operator=(const Tree&);
public:
#ifdef _DEBUG
void Dump() {
for(int i = 0; i < GetCount(); i++)
LOG((*this)[i]);
LOG("-------------------------------------");
}
#endif
};
//Tree Node helper class
template<class T>
class Node
: public Tree<Node<T> >
{
public:
typedef Node CLASSNAME;
T leaf;
};
template<class T, class B = EmptyClass>
class Leaf
: public Tree<Leaf<T, B> >
, public B
{};
#endif

11
bazaar/Tree/Tree.upp Normal file
View file

@ -0,0 +1,11 @@
uses
Core;
file
Tree.h,
Tree.cpp,
src.tpp;
mainconfig
"" = "";

4
bazaar/Tree/init Normal file
View file

@ -0,0 +1,4 @@
#ifndef _Tree_icpp_init_stub
#define _Tree_icpp_init_stub
#include "Core/init"
#endif

View file

@ -0,0 +1,14 @@
topic "template <class T, class B = EmptyClass>";
[ $$0,0#00000000000000000000000000000000:Default]
[i448;a25;kKO9; $$1,0#37138531426314131252341829483380:structitem]
[l288;2 $$2,0#27521748481378242620020725143825:desc]
[0 $$3,0#96390100711032703541132217272105:end]
[{_}
[s1;:noref: [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 T], [@(0.0.255) class]_[*@3 B]_`=_Em
ptyClass>&]
[s1;:Leaf`:`:class: [@(0.0.255) class]_[* Leaf]_:_[@(0.0.255) public]_[*@3 Tree]<[* Leaf]<[*@4 T],
[*@3 B]>_>_, [@(0.0.255) public]_[*@3 B]&]
[s2;%% another Node implementation, showing how to chain inheritance
with Tree, this one is usefull if te leaf itself is the tree&]
[s3; &]
[s0; ]

View file

@ -0,0 +1,13 @@
topic "template <class T>";
[ $$0,0#00000000000000000000000000000000:Default]
[i448;a25;kKO9; $$1,0#37138531426314131252341829483380:structitem]
[l288;2 $$2,0#27521748481378242620020725143825:desc]
[0 $$3,0#96390100711032703541132217272105:end]
[{_}
[s1;:noref: [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 T]>&]
[s1;:Node`:`:class: [@(0.0.255) class]_[* Node]_:_[@(0.0.255) public]_[*@3 Tree]<[* Node]<[*@4 T]>
_>_&]
[s2;%% an example implementation of a Tree Node, usefull for almost
all cases, since leaf type T can be specified what ever type.&]
[s3; &]
[s0;%% ]

View file

@ -0,0 +1,47 @@
topic "template <class T>";
[ $$0,0#00000000000000000000000000000000:Default]
[i448;a25;kKO9; $$1,0#37138531426314131252341829483380:structitem]
[l288;2 $$2,0#27521748481378242620020725143825:desc]
[0 $$3,0#96390100711032703541132217272105:end]
[H6;0 $$4,0#05600065144404261032431302351956:begin]
[i448;a25;kKO9;2 $$5,0#37138531426314131252341829483370:codeitem]
[{_}
[s1;:noref: [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 T]>&]
[s1;:Tree`:`:class: [@(0.0.255) class]_[* Tree]_:_[@(0.0.255) protected]_[*@3 Array]<[*@4 T]>_&]
[s2;%% a template class that can be used in the same manner as Link<T>,
to see how to use it, check out the manual&]
[s3; &]
[s4; &]
[s5;:Tree`:`:GetPtr`(`): [*@4 T]_`*[* GetPtr]()&]
[s2;%% returns a pointer to self. caution on using it on Tree<T>
elements only, which are not T themselves.&]
[s3; &]
[s4; &]
[s5;:Tree`:`:GetParent`(`): [*@4 T]_`*[* GetParent]()&]
[s2;%% GetParent reference if any&]
[s3; &]
[s4; &]
[s5;:Tree`:`:GetRoot`(`): [*@4 T]_`*[* GetRoot]()&]
[s2;%% GetRoot reference, if NULL, element is root itself&]
[s3; &]
[s4; &]
[s5;:Tree`:`:SetAsRoot`(`): [@(0.0.255) void]_[* SetAsRoot]()&]
[s2;%% a VERY important function. To be called for the root element
to set up the root reference which is forwarded to each child
later. call only once on root element only.&]
[s3; &]
[s4; &]
[s5;:Tree`:`:Link`(T`&`): [@(0.0.255) void]_[* Link]([*@4 T]_`&_[*@3 t])&]
[s2;%% provides a shallow linking of [%-*@3 t].only, this means that
it does `*NOT`* change pertenance of object, but simply links
the root and parent reference.&]
[s3;%% &]
[s4; &]
[s5;:Tree`:`:Unlink`(T`&`): [@(0.0.255) void]_[* Unlink]([*@4 T]_`&_[*@3 t])&]
[s2;%% does the opposite of Link to object [%-*@3 t].&]
[s3;%% &]
[s4; &]
[s5;:Tree`:`:Relink`(`): [@(0.0.255) void]_[* Relink]()&]
[s2;%% `'repairs`' linkage of a tree recursively&]
[s3; &]
[s0; ]

View file

@ -0,0 +1,88 @@
topic "Tree<T>";
[ $$0,0#00000000000000000000000000000000:Default]
[{_}%EN-US
[s0; [+150 Tree<T>]&]
[s0; &]
[s0; A Tree is a very effective way of bringing in some level of
logical organisation in a bunch of data which the NTL containers
can`'t provide inherently. They make access to a variety of `*[* equal
/ similar]`* data easy but it is all lineary organised. Every
item is equaly important. It is hard and errorprone to say `'The
first ten elements are special, the others are reserved`'. In
some cases one can use linked lists (U`+`+ Link<T>) to reflect
such things, defining maybe sth like `'everything after LinkOwner<T>
is free, everything before is used. But what if grouped hierarchy
comes into play? Handling with sorts of paths etc. Here, a Tree
can help provide means not merly to store elements, but bring
in a model based hierarchy.&]
[s0; &]
[s0; One could use constructs like this:&]
[s0; &]
[s0;i160; [C2 struct MyTree]&]
[s0;i160; [C2 `{]&]
[s0;i160; [C2 -|Array<MyTree> tree;]&]
[s0;i160; [C2 `};]&]
[s0;i160; &]
[s0; but one might end up needing Parent references, or even Root
references. and who is going to take care of them when moving
the elements around?&]
[s0; &]
[s0; Here comes a solution, which is not the only one in this world,
but serves 95 % of cases.&]
[s0; &]
[s0; The Tree<T> is actually a partially hidden Array of the same
type elements, This making usage of well known and tested NTL
containers. It has a parent pointer and a root pointer. some
methods from Array are free to access, some are overblended.
the protected inheritance ensures that the overblended base methods
are inaccessible in any case. some methods are not critical though
and can be exposed (using using), in some, the correct parent
ref is to be ensured. this thing can be thought in Vector and
the Map flavours as well, making handling more difficult though.
Array was chosen because of its Attach/Detach ability, which
comes in really handy when dealing with Trees (attaching detaching
or moving trees somewhere)&]
[s0; &]
[s0; Maybe in near future, one might provide an extended templated
version where to specify which container to use...&]
[s0; &]
[s0; Example of usage:&]
[s0; &]
[s0; HINT: using One<T> as T instead of T directly gives you the ability
of handling true leafs, which are attachable / detachable independantly
from the tree structure. This a tree can remain intact, while
you detach the leafs..&]
[s0; &]
[s0;i160; [C2 class Element]&]
[s0;i160; [C2 `{]&]
[s0;i160; [C2 public:]&]
[s0;i160; [C2 -|String name;]&]
[s0;i160; [C2 -|Value value;]&]
[s0;i160; [C2 `};]&]
[s0;i160;C2 &]
[s0;i160; [C2 Node<One<Element> > root;]&]
[s0;i160; [C2 Node<Element> roota;]&]
[s0;i160;C2 &]
[s0;i160; [C2 //Tree<One<Element> >]&]
[s0;i128;C2 &]
[s0;i128; [C2 root.SetAsRoot();]&]
[s0;i128; [C2 root.leaf.Create();]&]
[s0;i128; [C2 root.leaf`->name `= `"/`";]&]
[s0;i128; [C2 root.SetCount(3);]&]
[s0;i128; [C2 Node<One<Element> > `& child `= root`[2`];]&]
[s0;i128; [C2 child.leaf.Create();]&]
[s0;i128; [C2 child.leaf`->name `= `"Hallo`";]&]
[s0;i128; [C2 String `& s `= child.GetParent()`->leaf`->name;]&]
[s0;i128; [C2 s `= `"root`";]&]
[s0;i128; [C2 String `& ss `= root.leaf`->name;]&]
[s0;i128;C2 &]
[s0;i128; [C2 //Node<Element>]&]
[s0;i128; [C2 roota.SetAsRoot();]&]
[s0;i128; [C2 roota.leaf.name `= `"/`";]&]
[s0;i128; [C2 roota.SetCount(3);]&]
[s0;i128; [C2 Node<Element> `& childa `= roota`[2`];]&]
[s0;i128; [C2 childa.leaf.name `= `"Hallo`";]&]
[s0;i128; [C2 String `& sa `= childa.GetParent()`->leaf.name;]&]
[s0;i128; [C2 sa `= `"root`";]&]
[s0;i128; [C2 String `& ssa `= roota.leaf.name;]&]
[s0;i128;C2 ]

View file

@ -0,0 +1,33 @@
#ifndef _TreeTest_TreeTest_h
#define _TreeTest_TreeTest_h
#include <CtrlLib/CtrlLib.h>
using namespace Upp;
#define LAYOUTFILE <TreeTest/TreeTest.lay>
#include <CtrlCore/lay.h>
#include <Tree/Tree.h>
class Element
{
public:
typedef Element CLASSNAME;
String name;
Value value;
};
///
class TreeTest : public WithLayout<TopWindow> {
public:
typedef TreeTest CLASSNAME;
TreeTest();
Node<One<Element> > root;
Node<Element> roota;
};
#endif

View file

@ -0,0 +1,5 @@
LAYOUT(Layout, 200, 100)
END_LAYOUT

View file

@ -0,0 +1,12 @@
uses
CtrlLib,
Tree;
file
TreeTest.h,
main.cpp,
TreeTest.lay;
mainconfig
"" = "GUI";

5
bazaar/TreeTest/init Normal file
View file

@ -0,0 +1,5 @@
#ifndef _TreeTest_icpp_init_stub
#define _TreeTest_icpp_init_stub
#include "CtrlLib/init"
#include "Tree/init"
#endif

44
bazaar/TreeTest/main.cpp Normal file
View file

@ -0,0 +1,44 @@
#include "TreeTest.h"
TreeTest::TreeTest()
{
CtrlLayout(*this, "Window title");
//Tree<One<Element> >
root.SetAsRoot();
root.leaf.Create<Element>();
root.leaf->name = "/";
root.SetCount(3);
Node<One<Element> > & child = root[2];
ASSERT(child.GetParent() == &root);
ASSERT(child.GetRoot() == &root);
child.leaf.Create<Element>();
child.leaf->name = "Hallo";
String & s = child.GetParent()->leaf->name;
s = "root";
String & ss = root.leaf->name;
ASSERT(ss.IsEqual(s));
//Node<Element>
roota.SetAsRoot();
roota.leaf.name = "/";
roota.SetCount(3);
Node<Element> & childa = roota[2];
childa.leaf.name = "Hallo";
ASSERT(childa.GetParent() == &roota);
ASSERT(childa.GetRoot() == &roota);
String & sa = childa.GetParent()->leaf.name;
sa = "root";
String & ssa = roota.leaf.name;
ASSERT(ssa.IsEqual(sa));
int x = 123;
}
GUI_APP_MAIN
{
TreeTest().Run();
}