/
Simple.pm
executable file
·1331 lines (1014 loc) · 45.4 KB
/
Simple.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
class Tree::Simple {
## class constants
our $ROOT = "root";
#uid should be private however cannot init it a value within a new fcn
#will be private when submethod BUILD works
has $.uid is rw;
has $.node is rw;
has @.children is rw;
has $.height is rw = 1;
has $.width is rw = 1;
has $.parent is rw;
has $.depth is rw =-1;
## ----------------------------------------------------------------------------
## Tree::Simple
## ----------------------------------------------------------------------------
### constructor
multi method new(){
my $x =self.bless(*, node => '',parent => 'root');
#####
#should be in submethod BUILD
$x.uid = $x.WHERE;
###
return $x;
}
multi method new($node) {
my $x =self.bless(*, node => $node,parent => 'root');
#####
#should be in submethod BUILD
$x.uid = $x.WHERE;
###
return $x;
}
multi method new($node,'root'){
my $x= self.bless(*, node => $node,parent =>'root');
#####
#should be in submethod BUILD
$x.uid = $x.WHERE;
###
return $x;
}
#todo might be a rakudo bug where i cannot put the object type in the signatures without failing..
multi method new($node,$parent){
die 'Parent is not a Tree::Simple' if $parent !~~ Tree::Simple;
my $x = self.bless(*, node => $node,parent =>$parent,depth => $parent.getDepth() + 1);
#####
#should be in submethod BUILD
$x.uid = $x.WHERE;
$parent.addChild($x);
###
return $x;
}
#also should be private but cannot modify others setParent
method setParent($parent where { $parent eq $Tree::Simple::ROOT || $parent ~~ Tree::Simple}) {
$.parent = $parent;
if ($parent eq $ROOT) {
$.depth = -1;
}
else {
$.depth = $parent.getDepth() + 1;
}
}
method !detachParent() {
# return if $USE_WEAK_REFS;
self.parent = Mu;
}
method setHeight(Tree::Simple $child) {
my $child_height = $child.getHeight();
if self.height < $child_height +1 {
self.height = $child_height+1;
}
# and now bubble up to the parent (unless we are the root)
if ! self.isRoot() {
self.getParent().setHeight(self);
}
}
multi method setWidth(Tree::Simple $child_width) {
return if self.width > self.getChildCount();
my $width = $child_width.getWidth();
self.width += $width;
# and now bubble up to the parent (unless we are the root)
if !self.isRoot() {
self.getParent().setWidth($width);
}
}
multi method setWidth(Int $child_width) {
self.width += $child_width;
# and now bubble up to the parent (unless we are the root)
self.getParent().setWidth($child_width) unless self.isRoot();
}
## ----------------------------------------------------------------------------
## mutators
method setNodeValue($node_value) {
($node_value) || die "Insufficient Arguments : must supply a value for node";
self.node = $node_value;
}
method setUID($uid where { defined($uid) }) {
# ($uid) || die "Insufficient Arguments : Custom Unique ID's must be a true value";
self.uid = $uid;
}
## ----------------------------------------------
## child methods
#around type method like moose
method addChild(Tree::Simple $child) {
#provides the index
# splice @_, 1, 0, $_[0]->getChildCount;
my $index = self.getChildCount();
self.insertChildAt($index,$child);
return self;
}
method addChildren(*@children) {
my $index;
for @children -> $child {
$index = self.getChildCount();
self.insertChildAt($index,$child);
}
return self;
}
#adding alias for insertChildAt
#Tree::Simple.^add_method('insertChild', Tree::Simple.^can('insertChildAt'));
#Tree::Simple.^add_method('insertChildren', Tree::Simple.^can('insertChildAt'));
#todo hopefully one day it will return the two functions below
method insertChild($index,*@trees) {
self.insertChildAt($index,@trees);
}
method insertChildren($index,*@trees) {
self.insertChildAt($index,@trees);
}
#need to have an index and at least one child
method insertChildAt(Int $index where { $index >= 0 },*@trees where { @trees.elems() > 0 }) {
# check the bounds of our children
# against the index given
my $max = self.getChildCount();
if $index > $max {
die "Index Out of Bounds : got ($index) expected no more than (" ~ $max ~ ")";
}
for @trees -> $tree is rw {
# (blessed($tree) && $tree->isa("Tree::Simple"))
# || die "Insufficient Arguments : Child must be a Tree::Simple object";
$tree.setParent(self);
self.setHeight($tree);
self.setWidth($tree);
$tree.fixDepth() unless $tree.isLeaf();
}
# if index is zero, use this optimization
if $index == 0 {
unshift self.children , @trees;
# unshift @{$self->{_children}} => @trees;
}
# if index is equal to the number of children
# then use this optimization
elsif $index == $max {
push self.children , @trees;
# push @{$self->{_children}} => @trees;
}
# otherwise do some heavy lifting here
else {
splice self.children, $index,0, @trees;
# splice @{$self->{_children}}, $index, 0, @trees;
}
}
method removeChildAt($index) {
(self.getChildCount() != 0)
|| die "Illegal Operation : There are no children to remove";
# check the bounds of our children
# against the index given
($index < self.getChildCount())
|| die "Index Out of Bounds : got ($index) expected no more than (" ~ self.getChildCount() ~ ")";
my $removed_child;
# if index is zero, use this optimization
if $index == 0 {
$removed_child = shift self.children;
}
# if index is equal to the number of children
# then use this optimization
elsif $index == self.children.end {
$removed_child = pop self.children;
}
# otherwise do some heavy lifting here
else {
$removed_child = self.children[$index];
splice self.children, $index, 1;
}
# make sure we fix the height
self.fixHeight();
self.fixWidth();
# make sure that the removed child
# is no longer connected to the parent
# so we change its parent to ROOT
$removed_child.setParent($ROOT);
# and now we make sure that the depth
# of the removed child is aligned correctly
$removed_child.fixDepth() unless $removed_child.isLeaf();
# return ths removed child
# it is the responsibility
# of the user of this module
# to properly dispose of this
# child (and all its sub-children)
return $removed_child;
}
# maintain backwards compatability
# so any non-ref arguments will get
# sent to removeChildAt
#todo nyi what is ref in p6 idoms?
multi method removeChild(Int $child_index) {
return self.removeChildAt($child_index);
}
multi method removeChild($child_to_remove) {
# (blessed($child_to_remove) && $child_to_remove->isa("Tree::Simple"))
# || die "Insufficient Arguments : Only valid child type is a Tree::Simple object";
my $index = 0;
for self.getAllChildren() -> $child {
#todo need to double check it works as advertised
("$child" eq "$child_to_remove") && return self.removeChildAt($index);
$index++;
}
die "Child Not Found : cannot find object ($child_to_remove) in self";
}
method getIndex {
return -1 if $.parent eq $ROOT;
my $index = 0;
for self.parent.getAllChildren() -> $sibling {
#probably stringify the object to see if they are the same. Nice short circuit as well
("$sibling" eq self) && return $index;
$index++;
}
return $index;
}
# ## ----------------------------------------------
# ## Sibling methods
# # these addSibling and addSiblings functions
# # just pass along their arguments to the addChild
# # and addChildren method respectively, this
# # eliminates the need to overload these method
# # in things like the Keyable Tree object
method addSibling(Tree::Simple $child) {
(!self.isRoot())
|| die "Insufficient Arguments : cannot add a sibling to a ROOT tree";
self.parent.addChild($child);
}
method addSiblings(@siblings) {
(!self.isRoot())
|| die "Insufficient Arguments : cannot add siblings to a ROOT tree";
self.parent.addChildren(@siblings);
}
method insertSibling($index,$sibling) {
(!self.isRoot())
|| die "Insufficient Arguments : cannot insert sibling(s) to a ROOT tree";
self.parent.insertChildren($index,$sibling);
}
method insertSiblings($index,@args) {
(!self.isRoot())
|| die "Insufficient Arguments : cannot insert sibling(s) to a ROOT tree";
self.parent.insertChildren($index,@args);
}
# # I am not permitting the removal of siblings
# # as I think in general it is a bad idea
# ## ----------------------------------------------------------------------------
## accessors
#todo remove them and add the alias to the attributes
method getUID { $.uid; }
method getParent { $.parent; }
method getDepth { $.depth; }
method getNodeValue { $.node; }
method getWidth { $.width; }
method getHeight { $.height; }
method getChildCount {
#$#{$_[0]{_children}} + 1
return @.children.elems();
}
method getChild(Int $index) {
return self.children[$index];
}
method getAllChildren {
self.children;
}
method getSibling($index) {
(!self.isRoot())
|| die "Insufficient Arguments : cannot get siblings from a ROOT tree";
self.getParent().getChild($index);
}
method getAllSiblings {
(!self.isRoot())
|| die "Insufficient Arguments : cannot get siblings from a ROOT tree";
self.getParent().getAllChildren();
}
## ----------------------------------------------------------------------------
## informational
method isLeaf {
self.getChildCount() == 0;
}
method isRoot {
return (!defined($.parent) || $.parent eq $ROOT);
}
method size() {
my $size = 1;
for self.getAllChildren() -> $child {
$size += $child.size();
}
return $size;
}
## ----------------------------------------------------------------------------
# misc
# NOTE:
# Occasionally one wants to have the
# depth available for various reasons
# of convience. Sometimes that depth
# field is not always correct.
# If you create your tree in a top-down
# manner, this is usually not an issue
# since each time you either add a child
# or create a tree you are doing it with
# a single tree and not a hierarchy.
# If however you are creating your tree
# bottom-up, then you might find that
# when adding hierarchies of trees, your
# depth fields are all out of whack.
# This is where this method comes into play
# it will recurse down the tree and fix the
# depth fields appropriately.
# This method is called automatically when
# a subtree is added to a child array
method fixDepth {
# make sure the tree's depth
# is up to date all the way down
self.traverse(sub ($tree) {
return if $tree.isRoot();
$tree.depth = $tree.getParent().getDepth() + 1;
}
);
}
# NOTE:
# This method is used to fix any height
# discrepencies which might arise when
# you remove a sub-tree
method fixHeight {
# we must find the tallest sub-tree
# and use that to define the height
my $max_height = 0;
unless self.isLeaf() {
for self.getAllChildren() -> $child {
my $child_height = $child.getHeight();
$max_height = $child_height if $max_height < $child_height;
}
}
# if there is no change, then we
# need not bubble up through the
# parents
return if self.height == ($max_height + 1);
# otherwise ...
self.height = $max_height + 1;
# now we need to bubble up through the parents
# in order to rectify any issues with height
self.getParent().fixHeight() unless self.isRoot();
}
method fixWidth {
my $fixed_width = 0;
for self.getAllChildren() {
$fixed_width += $_.getWidth();
}
self.width = $fixed_width;
self.getParent().fixWidth() unless self.isRoot();
}
method traverse(Code $func,Code $post?) {
for self.getAllChildren() -> $child {
$func.($child);
$child.traverse($func, $post);
$post && $post.($child);
}
}
# this is an improved version of the
# old accept method, it now it more
# accepting of its arguments
method accept($visitor) {
#todo check to ensure that the $visitor has the 'visit' fcn
# die '$Visitor is not a valid Visitor object' if $visitor !~~ Tree::Simple::Visitor;
# my ($self, $visitor) = @_;
# # it must be a blessed reference and ...
# (blessed($visitor) &&
# # either a Tree::Simple::Visitor object, or ...
# ($visitor->isa("Tree::Simple::Visitor") ||
# # it must be an object which has a 'visit' method avaiable
# $visitor->can('visit')))
# || die "Insufficient Arguments : You must supply a valid Visitor object";
$visitor.visit(self);
}
## ----------------------------------------------------------------------------
## cloning
method clone() {
# first clone the value in the node
my $cloned_node = cloneNode(self.getNodeValue());
# create a new Tree::Simple object
# here with the cloned node, however
# we do not assign the parent node
# since it really does not make a lot
# of sense. To properly clone it would
# be to clone back up the tree as well,
# which IMO is not intuitive. So in essence
# when you clone a tree, you detach it from
# any parentage it might have
my $clone = self.new($cloned_node);
# however, because it is a recursive thing
# when you clone all the children, and then
# add them to the clone, you end up setting
# the parent of the children to be that of
# the clone (which is correct)
$clone.addChildren(
map { $_.clone() }, self.getAllChildren()
) unless self.isLeaf();
# return the clone
return $clone;
}
# this allows cloning of single nodes while
# retaining connections to a tree, this is sloppy
method cloneShallow() {
my $cloned_tree = self;
# bless($cloned_tree, ref($self));
# # just clone the node (if you can)
$cloned_tree.setNodeValue(cloneNode(self.getNodeValue()));
return $cloned_tree;
}
multi sub cloneNode(Str $node,%seen? = {} ) {
# store the clone in the cache and
%seen{$node} = $node;
return $node;
}
multi sub cloneNode($node where { $node ~~ Array}, %seen? ={}){
my $clone = [ map { cloneNode($_, %seen) }, @($node) ];
# store the clone in the cache and
%seen{$node} = $clone;
return $clone;
}
multi sub cloneNode($node where { $node ~~ Hash },%seen? ={}){
my $clone = {};
for keys $node -> $key {
$clone.{$key} = cloneNode($node.{$key}, %seen);
}
# store the clone in the cache and
%seen{$node} = $clone;
return $clone;
}
multi sub cloneNode(Tree::Simple $node, %seen? ={}) {
# store the clone in the cache and
my $clone = $node.clone();
%seen{$node} = $node;
return $clone;
}
# this is a helper function which
# recursively clones the node
multi sub cloneNode($node,%seen? = {}) {
# create a cache if we dont already
# have one to prevent circular refs
# from being copied more than once
# now here we go...
my $clone;
# if it is not a reference, then lets just return it
# return $node unless $node ~~ Tree::Simple;
# if it is in the cache, then return that
return %seen{$node} if %seen.exists($node);
# if it is an object, then ...
if $node ~~ Tree::Simple {
# see if we can clone it
if $node.can('clone') {
$clone = $node.clone();
}
# otherwise respect that it does
# not want to be cloned
else {
$clone = $node;
}
}
elsif $node ~~ Capture {
#todo fix this:need to deference...
$clone = \$node;
}
else {
$clone = $node;
}
# store the clone in the cache and
%seen{$node} = $clone;
# then return the clone
return $clone;
}
## ----------------------------------------------------------------------------
## Desctructor
method DESTROY() {
# if we are using weak refs
# we dont need to worry about
# destruction, it will just happen
#todo not sure what to do here... need to implement references
# return if $USE_WEAK_REFS;
# we want to detach all our children from
# ourselves, this will break most of the
# connections and allow for things to get
# reaped properly
unless (!(@.children) && @.children.elems()==0) {
for @.children -> $child {
defined $child && $child!detachParent();
}
}
# we do not need to remove or undef the _children
# of the _parent fields, this will cause some
# unwanted releasing of connections.
}
## ----------------------------------------------------------------------------
## end Tree::Simple
## ----------------------------------------------------------------------------
};
# __END__
# =head1 NAME
# Tree::Simple - A simple tree object
# =head1 SYNOPSIS
# use Tree::Simple;
# # make a tree root
# my $tree = Tree::Simple->new("0", Tree::Simple->ROOT);
# # explicity add a child to it
# $tree->addChild(Tree::Simple->new("1"));
# # specify the parent when creating
# # an instance and it adds the child implicity
# my $sub_tree = Tree::Simple->new("2", $tree);
# # chain method calls
# $tree->getChild(0)->addChild(Tree::Simple->new("1.1"));
# # add more than one child at a time
# $sub_tree->addChildren(
# Tree::Simple->new("2.1"),
# Tree::Simple->new("2.2")
# );
# # add siblings
# $sub_tree->addSibling(Tree::Simple->new("3"));
# # insert children a specified index
# $sub_tree->insertChild(1, Tree::Simple->new("2.1a"));
# # clean up circular references
# $tree->DESTROY();
# =head1 DESCRIPTION
# This module in an fully object-oriented implementation of a simple n-ary
# tree. It is built upon the concept of parent-child relationships, so
# therefore every B<Tree::Simple> object has both a parent and a set of
# children (who themselves may have children, and so on). Every B<Tree::Simple>
# object also has siblings, as they are just the children of their immediate
# parent.
# It is can be used to model hierarchal information such as a file-system,
# the organizational structure of a company, an object inheritance hierarchy,
# versioned files from a version control system or even an abstract syntax
# tree for use in a parser. It makes no assumptions as to your intended usage,
# but instead simply provides the structure and means of accessing and
# traversing said structure.
# This module uses exceptions and a minimal Design By Contract style. All method
# arguments are required unless specified in the documentation, if a required
# argument is not defined an exception will usually be thrown. Many arguments
# are also required to be of a specific type, for instance the C<$parent>
# argument to the constructor B<must> be a B<Tree::Simple> object or an object
# derived from B<Tree::Simple>, otherwise an exception is thrown. This may seems
# harsh to some, but this allows me to have the confidence that my code works as
# I intend, and for you to enjoy the same level of confidence when using this
# module. Note however that this module does not use any Exception or Error module,
# the exceptions are just strings thrown with C<die>.
# I consider this module to be production stable, it is based on a module which has
# been in use on a few production systems for approx. 2 years now with no issue.
# The only difference is that the code has been cleaned up a bit, comments added and
# the thorough tests written for its public release. I am confident it behaves as
# I would expect it to, and is (as far as I know) bug-free. I have not stress-tested
# it under extreme duress, but I don't so much intend for it to be used in that
# type of situation. If this module cannot keep up with your Tree needs, i suggest
# switching to one of the modules listed in the L<OTHER TREE MODULES> section below.
# =head1 CONSTANTS
# =over 4
# =item B<ROOT>
# This class constant serves as a placeholder for the root of our tree. If a tree
# does not have a parent, then it is considered a root.
# =back
# =head1 METHODS
# =head2 Constructor
# =over 4
# =item B<new ($node, $parent)>
# The constructor accepts two arguments a C<$node> value and an optional C<$parent>.
# The C<$node> value can be any scalar value (which includes references and objects).
# The optional C<$parent> value must be a B<Tree::Simple> object, or an object
# derived from B<Tree::Simple>. Setting this value implies that your new tree is a
# child of the parent tree, and therefore adds it to the parent's children. If the
# C<$parent> is not specified then its value defaults to ROOT.
# =back
# =head2 Mutator Methods
# =over 4
# =item B<setNodeValue ($node_value)>
# This sets the node value to the scalar C<$node_value>, an exception is thrown if
# C<$node_value> is not defined.
# =item B<setUID ($uid)>
# This allows you to set your own unique ID for this specific Tree::Simple object.
# A default value derived from the object's hex address is provided for you, so use
# of this method is entirely optional. It is the responsibility of the user to
# ensure the value's uniqueness, all that is tested by this method is that C<$uid>
# is a true value (evaluates to true in a boolean context). For even more information
# about the Tree::Simple UID see the C<getUID> method.
# =item B<addChild ($tree)>
# This method accepts only B<Tree::Simple> objects or objects derived from
# B<Tree::Simple>, an exception is thrown otherwise. This method will append
# the given C<$tree> to the end of it's children list, and set up the correct
# parent-child relationships. This method is set up to return its invocant so
# that method call chaining can be possible. Such as:
# my $tree = Tree::Simple->new("root")->addChild(Tree::Simple->new("child one"));
# Or the more complex:
# my $tree = Tree::Simple->new("root")->addChild(
# Tree::Simple->new("1.0")->addChild(
# Tree::Simple->new("1.0.1")
# )
# );
# =item B<addChildren (@trees)>
# This method accepts an array of B<Tree::Simple> objects, and adds them to
# it's children list. Like C<addChild> this method will return its invocant
# to allow for method call chaining.
# =item B<insertChild ($index, $tree)>
# This method accepts a numeric C<$index> and a B<Tree::Simple> object (C<$tree>),
# and inserts the C<$tree> into the children list at the specified C<$index>.
# This results in the shifting down of all children after the C<$index>. The
# C<$index> is checked to be sure it is the bounds of the child list, if it
# out of bounds an exception is thrown. The C<$tree> argument's type is
# verified to be a B<Tree::Simple> or B<Tree::Simple> derived object, if
# this condition fails, an exception is thrown.
# =item B<insertChildren ($index, @trees)>
# This method functions much as insertChild does, but instead of inserting a
# single B<Tree::Simple>, it inserts an array of B<Tree::Simple> objects. It
# too bounds checks the value of C<$index> and type checks the objects in
# C<@trees> just as C<insertChild> does.
# =item B<removeChild> ($child | $index)>
# Accepts two different arguemnts. If given a B<Tree::Simple> object (C<$child>),
# this method finds that specific C<$child> by comparing it with all the other
# children until it finds a match. At which point the C<$child> is removed. If
# no match is found, and exception is thrown. If a non-B<Tree::Simple> object
# is given as the C<$child> argument, an exception is thrown.
# This method also accepts a numeric C<$index> and removes the child found at
# that index from it's list of children. The C<$index> is bounds checked, if
# this condition fail, an exception is thrown.
# When a child is removed, it results in the shifting up of all children after
# it, and the removed child is returned. The removed child is properly
# disconnected from the tree and all its references to its old parent are
# removed. However, in order to properly clean up and circular references
# the removed child might have, it is advised to call it's C<DESTROY> method.
# See the L<CIRCULAR REFERENCES> section for more information.
# =item B<addSibling ($tree)>
# =item B<addSiblings (@trees)>
# =item B<insertSibling ($index, $tree)>
# =item B<insertSiblings ($index, @trees)>
# The C<addSibling>, C<addSiblings>, C<insertSibling> and C<insertSiblings>
# methods pass along their arguments to the C<addChild>, C<addChildren>,
# C<insertChild> and C<insertChildren> methods of their parent object
# respectively. This eliminates the need to overload these methods in subclasses
# which may have specialized versions of the *Child(ren) methods. The one
# exceptions is that if an attempt it made to add or insert siblings to the
# B<ROOT> of the tree then an exception is thrown.
# =back
# B<NOTE:>
# There is no C<removeSibling> method as I felt it was probably a bad idea.
# The same effect can be achieved by manual upwards traversal.
# =head2 Accessor Methods
# =over 4
# =item B<getNodeValue>
# This returns the value stored in the object's node field.
# =item B<getUID>
# This returns the unique ID associated with this particular tree. This can
# be custom set using the C<setUID> method, or you can just use the default.
# The default is the hex-address extracted from the stringified Tree::Simple
# object. This may not be a I<universally> unique identifier, but it should
# be adequate for at least the current instance of your perl interpreter. If
# you need a UUID, one can be generated with an outside module (there are
# many to choose from on CPAN) and the C<setUID> method (see above).
# =item B<getChild ($index)>
# This returns the child (a B<Tree::Simple> object) found at the specified
# C<$index>. Note that we do use standard zero-based array indexing.
# =item B<getAllChildren>
# This returns an array of all the children (all B<Tree::Simple> objects).
# It will return an array reference in scalar context.
# =item B<getSibling ($index)>
# =item B<getAllSiblings>
# Much like C<addSibling> and C<addSiblings>, these two methods simply call
# C<getChild> and C<getAllChildren> on the invocant's parent.
# =item B<getDepth>
# Returns a number representing the invocant's depth within the hierarchy of
# B<Tree::Simple> objects.
# B<NOTE:> A C<ROOT> tree has the depth of -1. This be because Tree::Simple
# assumes that a tree's root will usually not contain data, but just be an
# anchor for the data-containing branches. This may not be intuitive in all
# cases, so I mention it here.
# =item B<getParent>
# Returns the invocant's parent, which could be either B<ROOT> or a
# B<Tree::Simple> object.
# =item B<getHeight>
# Returns a number representing the length of the longest path from the current
# tree to the furthest leaf node.
# =item B<getWidth>
# Returns the a number representing the breadth of the current tree, basically
# it is a count of all the leaf nodes.
# =item B<getChildCount>
# Returns the number of children the invocant contains.
# =item B<getIndex>
# Returns the index of this tree within its parent's child list. Returns -1 if
# the tree is the root.
# =back
# =head2 Predicate Methods
# =over 4
# =item B<isLeaf>
# Returns true (1) if the invocant does not have any children, false (0) otherwise.
# =item B<isRoot>
# Returns true (1) if the invocant's "parent" field is B<ROOT>, returns false
# (0) otherwise.
# =back
# =head2 Recursive Methods
# =over 4
# =item B<traverse ($func, ?$postfunc)>
# This method accepts two arguments a mandatory C<$func> and an optional
# C<$postfunc>. If the argument C<$func> is not defined then an exception
# is thrown. If C<$func> or C<$postfunc> are not in fact CODE references
# then an exception is thrown. The function C<$func> is then applied
# recursively to all the children of the invocant. If given, the function
# C<$postfunc> will be applied to each child after the child's children
# have been traversed.
# Here is an example of a traversal function that will print out the
# hierarchy as a tabbed in list.
# $tree->traverse(sub {
# my ($_tree) = @_;
# print (("\t" x $_tree->getDepth()), $_tree->getNodeValue(), "\n");
# });
# Here is an example of a traversal function that will print out the
# hierarchy in an XML-style format.
# $tree->traverse(sub {
# my ($_tree) = @_;
# print ((' ' x $_tree->getDepth()),
# '<', $_tree->getNodeValue(),'>',"\n");
# },
# sub {
# my ($_tree) = @_;
# print ((' ' x $_tree->getDepth()),
# '</', $_tree->getNodeValue(),'>',"\n");
# });
# =item B<size>
# Returns the total number of nodes in the current tree and all its sub-trees.
# =item B<height>
# This method has also been B<deprecated> in favor of the C<getHeight> method above,
# it remains as an alias to C<getHeight> for backwards compatability.
# B<NOTE:> This is also no longer a recursive method which get's it's value on demand,
# but a value stored in the Tree::Simple object itself, hopefully making it much
# more efficient and usable.
# =back
# =head2 Visitor Methods
# =over 4
# =item B<accept ($visitor)>
# It accepts either a B<Tree::Simple::Visitor> object (which includes classes derived
# from B<Tree::Simple::Visitor>), or an object who has the C<visit> method available
# (tested with C<$visitor-E<gt>can('visit')>). If these qualifications are not met,
# and exception will be thrown. We then run the Visitor's C<visit> method giving the
# current tree as its argument.
# I have also created a number of Visitor objects and packaged them into the
# B<Tree::Simple::VisitorFactory>.
# =back
# =head2 Cloning Methods
# Cloning a tree can be an extremly expensive operation for large trees, so we provide
# two options for cloning, a deep clone and a shallow clone.
# When a Tree::Simple object is cloned, the node is deep-copied in the following manner.
# If we find a normal scalar value (non-reference), we simply copy it. If we find an
# object, we attempt to call C<clone> on it, otherwise we just copy the reference (since
# we assume the object does not want to be cloned). If we find a SCALAR, REF reference we
# copy the value contained within it. If we find a HASH or ARRAY reference we copy the
# reference and recursively copy all the elements within it (following these exact
# guidelines). We also do our best to assure that circular references are cloned
# only once and connections restored correctly. This cloning will not be able to copy
# CODE, RegExp and GLOB references, as they are pretty much impossible to clone. We
# also do not handle C<tied> objects, and they will simply be copied as plain
# references, and not re-C<tied>.
# =over 4
# =item B<clone>
# The clone method does a full deep-copy clone of the object, calling C<clone> recursively
# on all its children. This does not call C<clone> on the parent tree however. Doing
# this would result in a slowly degenerating spiral of recursive death, so it is not
# recommended and therefore not implemented. What happens is that the tree instance
# that C<clone> is actually called upon is detached from the tree, and becomes a root
# node, all if the cloned children are then attached as children of that tree. I personally
# think this is more intuitive then to have the cloning crawl back I<up> the tree is not
# what I think most people would expect.
# =item B<cloneShallow>
# This method is an alternate option to the plain C<clone> method. This method allows the
# cloning of single B<Tree::Simple> object while retaining connections to the rest of the
# tree/hierarchy.