mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-21 06:45:39 -06:00
bazaar: a Tree<T> implementation
git-svn-id: svn://ultimatepp.org/upp/trunk@2606 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
9a12c315e1
commit
c761602615
13 changed files with 385 additions and 0 deletions
2
bazaar/Tree/Tree.cpp
Normal file
2
bazaar/Tree/Tree.cpp
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#include "Tree.h"
|
||||
|
||||
107
bazaar/Tree/Tree.h
Normal file
107
bazaar/Tree/Tree.h
Normal 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
11
bazaar/Tree/Tree.upp
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
uses
|
||||
Core;
|
||||
|
||||
file
|
||||
Tree.h,
|
||||
Tree.cpp,
|
||||
src.tpp;
|
||||
|
||||
mainconfig
|
||||
"" = "";
|
||||
|
||||
4
bazaar/Tree/init
Normal file
4
bazaar/Tree/init
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#ifndef _Tree_icpp_init_stub
|
||||
#define _Tree_icpp_init_stub
|
||||
#include "Core/init"
|
||||
#endif
|
||||
14
bazaar/Tree/src.tpp/Leaf$en-us.tpp
Normal file
14
bazaar/Tree/src.tpp/Leaf$en-us.tpp
Normal 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; ]
|
||||
13
bazaar/Tree/src.tpp/Node$en-us.tpp
Normal file
13
bazaar/Tree/src.tpp/Node$en-us.tpp
Normal 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;%% ]
|
||||
47
bazaar/Tree/src.tpp/Tree$en-us.tpp
Normal file
47
bazaar/Tree/src.tpp/Tree$en-us.tpp
Normal 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; ]
|
||||
88
bazaar/Tree/src.tpp/about$en-us.tpp
Normal file
88
bazaar/Tree/src.tpp/about$en-us.tpp
Normal 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 ]
|
||||
33
bazaar/TreeTest/TreeTest.h
Normal file
33
bazaar/TreeTest/TreeTest.h
Normal 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
|
||||
|
||||
5
bazaar/TreeTest/TreeTest.lay
Normal file
5
bazaar/TreeTest/TreeTest.lay
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
LAYOUT(Layout, 200, 100)
|
||||
|
||||
END_LAYOUT
|
||||
|
||||
12
bazaar/TreeTest/TreeTest.upp
Normal file
12
bazaar/TreeTest/TreeTest.upp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
uses
|
||||
CtrlLib,
|
||||
Tree;
|
||||
|
||||
file
|
||||
TreeTest.h,
|
||||
main.cpp,
|
||||
TreeTest.lay;
|
||||
|
||||
mainconfig
|
||||
"" = "GUI";
|
||||
|
||||
5
bazaar/TreeTest/init
Normal file
5
bazaar/TreeTest/init
Normal 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
44
bazaar/TreeTest/main.cpp
Normal 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();
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue