annotate Tree/DAG_Node.pm @ 1:4f6952e0af48 default tip

CREST - add crest.loc.sample
author Jim Johnson <jj@umn.edu>
date Wed, 08 Feb 2012 16:08:01 -0600
parents acc8d8bfeb9a
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1 require 5;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2 package Tree::DAG_Node;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
3 use Carp ();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
4 use strict;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
5 use vars qw(@ISA $Debug $VERSION);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
6
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
7 $Debug = 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
8 $VERSION = '1.06';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
9
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
10 =head1 NAME
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
11
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
12 Tree::DAG_Node - (super)class for representing nodes in a tree
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
13
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
14 =head1 SYNOPSIS
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
15
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
16 Using as a base class:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
17
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
18 package Game::Tree::Node; # or whatever you're doing
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
19 use Tree::DAG_Node;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
20 @ISA = qw(Tree::DAG_Node);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
21 ...your own methods overriding/extending
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
22 the methods in Tree::DAG_Node...
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
23
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
24 Using as a class of its own:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
25
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
26 use Tree::DAG_Node;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
27 my $root = Tree::DAG_Node->new();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
28 $root->name("I'm the tops");
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
29 my $new_daughter = $root->new_daughter;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
30 $new_daughter->name("More");
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
31 ...
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
32
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
33 =head1 DESCRIPTION
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
34
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
35 This class encapsulates/makes/manipulates objects that represent nodes
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
36 in a tree structure. The tree structure is not an object itself, but
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
37 is emergent from the linkages you create between nodes. This class
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
38 provides the methods for making linkages that can be used to build up
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
39 a tree, while preventing you from ever making any kinds of linkages
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
40 which are not allowed in a tree (such as having a node be its own
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
41 mother or ancestor, or having a node have two mothers).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
42
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
43 This is what I mean by a "tree structure", a bit redundantly stated:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
44
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
45 * A tree is a special case of an acyclic directed graph.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
46
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
47 * A tree is a network of nodes where there's exactly one root
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
48 node (i.e., 'the top'), and the only primary relationship between nodes
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
49 is the mother-daugher relationship.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
50
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
51 * No node can be its own mother, or its mother's mother, etc.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
52
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
53 * Each node in the tree has exactly one "parent" (node in the "up"
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
54 direction) -- except the root, which is parentless.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
55
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
56 * Each node can have any number (0 to any finite number) of daughter
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
57 nodes. A given node's daughter nodes constitute an I<ordered> list.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
58 (However, you are free to consider this ordering irrelevant.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
59 Some applications do need daughters to be ordered, so I chose to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
60 consider this the general case.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
61
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
62 * A node can appear in only one tree, and only once in that tree.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
63 Notably (notable because it doesn't follow from the two above points),
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
64 a node cannot appear twice in its mother's daughter list.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
65
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
66 * In other words, there's an idea of up (toward the root) versus
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
67 down (away from the root), and left (i.e., toward the start (index 0)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
68 of a given node's daughter list) versus right (toward the end of a
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
69 given node's daughter list).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
70
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
71 Trees as described above have various applications, among them:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
72 representing syntactic constituency, in formal linguistics;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
73 representing contingencies in a game tree; representing abstract
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
74 syntax in the parsing of any computer language -- whether in
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
75 expression trees for programming languages, or constituency in the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
76 parse of a markup language document. (Some of these might not use the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
77 fact that daughters are ordered.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
78
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
79 (Note: B-Trees are a very special case of the above kinds of trees,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
80 and are best treated with their own class. Check CPAN for modules
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
81 encapsulating B-Trees; or if you actually want a database, and for
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
82 some reason ended up looking here, go look at L<AnyDBM_File>.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
83
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
84 Many base classes are not usable except as such -- but Tree::DAG_Node
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
85 can be used as a normal class. You can go ahead and say:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
86
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
87 use Tree::DAG_Node;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
88 my $root = Tree::DAG_Node->new();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
89 $root->name("I'm the tops");
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
90 $new_daughter = Tree::DAG_Node->new();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
91 $new_daughter->name("More");
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
92 $root->add_daughter($new_daughter);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
93
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
94 and so on, constructing and linking objects from Tree::DAG_Node and
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
95 making useful tree structures out of them.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
96
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
97 =head1 A NOTE TO THE READER
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
98
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
99 This class is big and provides lots of methods. If your problem is
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
100 simple (say, just representing a simple parse tree), this class might
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
101 seem like using an atomic sledgehammer to swat a fly. But the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
102 complexity of this module's bells and whistles shouldn't detract from
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
103 the efficiency of using this class for a simple purpose. In fact, I'd
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
104 be very surprised if any one user ever had use for more that even a
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
105 third of the methods in this class. And remember: an atomic
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
106 sledgehammer B<will> kill that fly.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
107
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
108 =head1 OBJECT CONTENTS
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
109
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
110 Implementationally, each node in a tree is an object, in the sense of
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
111 being an arbitrarily complex data structure that belongs to a class
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
112 (presumably Tree::DAG_Node, or ones derived from it) that provides
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
113 methods.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
114
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
115 The attributes of a node-object are:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
116
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
117 =over
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
118
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
119 =item mother -- this node's mother. undef if this is a root.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
120
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
121 =item daughters -- the (possibly empty) list of daughters of this node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
122
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
123 =item name -- the name for this node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
124
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
125 Need not be unique, or even printable. This is printed in some of the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
126 various dumper methods, but it's up to you if you don't put anything
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
127 meaningful or printable here.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
128
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
129 =item attributes -- whatever the user wants to use it for.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
130
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
131 Presumably a hashref to whatever other attributes the user wants to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
132 store without risk of colliding with the object's real attributes.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
133 (Example usage: attributes to an SGML tag -- you definitely wouldn't
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
134 want the existence of a "mother=foo" pair in such a tag to collide with
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
135 a node object's 'mother' attribute.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
136
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
137 Aside from (by default) initializing it to {}, and having the access
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
138 method called "attributes" (described a ways below), I don't do
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
139 anything with the "attributes" in this module. I basically intended
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
140 this so that users who don't want/need to bother deriving a class
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
141 from Tree::DAG_Node, could still attach whatever data they wanted in a
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
142 node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
143
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
144 =back
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
145
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
146 "mother" and "daughters" are attributes that relate to linkage -- they
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
147 are never written to directly, but are changed as appropriate by the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
148 "linkage methods", discussed below.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
149
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
150 The other two (and whatever others you may add in derived classes) are
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
151 simply accessed thru the same-named methods, discussed further below.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
152
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
153 =head2 ABOUT THE DOCUMENTED INTERFACE
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
154
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
155 Stick to the documented interface (and comments in the source --
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
156 especially ones saying "undocumented!" and/or "disfavored!" -- do not
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
157 count as documentation!), and don't rely on any behavior that's not in
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
158 the documented interface.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
159
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
160 Specifically, unless the documentation for a particular method says
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
161 "this method returns thus-and-such a value", then you should not rely on
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
162 it returning anything meaningful.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
163
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
164 A I<passing> acquintance with at least the broader details of the source
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
165 code for this class is assumed for anyone using this class as a base
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
166 class -- especially if you're overriding existing methods, and
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
167 B<definitely> if you're overriding linkage methods.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
168
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
169 =head1 MAIN CONSTRUCTOR, AND INITIALIZER
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
170
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
171 =over
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
172
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
173 =item the constructor CLASS->new() or CLASS->new({...options...})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
174
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
175 This creates a new node object, calls $object->_init({...options...})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
176 to provide it sane defaults (like: undef name, undef mother, no
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
177 daughters, 'attributes' setting of a new empty hashref), and returns
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
178 the object created. (If you just said "CLASS->new()" or "CLASS->new",
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
179 then it pretends you called "CLASS->new({})".)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
180
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
181 Currently no options for putting in {...options...} are part
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
182 of the documented interface, but the options is here in case
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
183 you want to add such behavior in a derived class.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
184
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
185 Read on if you plan on using Tree::DAG_New as a base class.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
186 (Otherwise feel free to skip to the description of _init.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
187
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
188 There are, in my mind, two ways to do object construction:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
189
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
190 Way 1: create an object, knowing that it'll have certain uninteresting
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
191 sane default values, and then call methods to change those values to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
192 what you want. Example:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
193
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
194 $node = Tree::DAG_Node->new;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
195 $node->name('Supahnode!');
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
196 $root->add_daughter($node);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
197 $node->add_daughters(@some_others)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
198
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
199 Way 2: be able to specify some/most/all the object's attributes in
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
200 the call to the constructor. Something like:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
201
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
202 $node = Tree::DAG_Node->new({
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
203 name => 'Supahnode!',
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
204 mother => $root,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
205 daughters => \@some_others
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
206 });
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
207
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
208 After some deliberation, I've decided that the second way is a Bad
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
209 Thing. First off, it is B<not> markedly more concise than the first
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
210 way. Second off, it often requires subtly different syntax (e.g.,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
211 \@some_others vs @some_others). It just complicates things for the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
212 programmer and the user, without making either appreciably happier.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
213
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
214 (This is not to say that options in general for a constructor are bad
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
215 -- C<random_network>, discussed far below, necessarily takes options.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
216 But note that those are not options for the default values of
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
217 attributes.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
218
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
219 Anyway, if you use Tree::DAG_Node as a superclass, and you add
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
220 attributes that need to be initialized, what you need to do is provide
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
221 an _init method that calls $this->SUPER::_init($options) to use its
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
222 superclass's _init method, and then initializes the new attributes:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
223
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
224 sub _init {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
225 my($this, $options) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
226 $this->SUPER::_init($options); # call my superclass's _init to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
227 # init all the attributes I'm inheriting
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
228
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
229 # Now init /my/ new attributes:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
230 $this->{'amigos'} = []; # for example
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
231 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
232
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
233 ...or, as I prefer when I'm being a neat freak:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
234
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
235 sub _init {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
236 my($this, $options) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
237 $this->SUPER::_init($options);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
238
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
239 $this->_init_amigos($options);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
240 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
241
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
242 sub _init_amigos {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
243 my $this = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
244 # Or my($this,$options) = @_[0,1]; if I'm using $options
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
245 $this->{'amigos'} = [];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
246 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
247
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
248
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
249 In other words, I like to have each attribute initialized thru a
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
250 method named _init_[attribute], which should expect the object as
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
251 $_[0] and the the options hashref (or {} if none was given) as $_[1].
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
252 If you insist on having your _init recognize options for setting
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
253 attributes, you might as well have them dealt with by the appropriate
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
254 _init_[attribute] method, like this:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
255
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
256 sub _init {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
257 my($this, $options) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
258 $this->SUPER::_init($options);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
259
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
260 $this->_init_amigos($options);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
261 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
262
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
263 sub _init_amigos {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
264 my($this,$options) = @_[0,1]; # I need options this time
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
265 $this->{'amigos'} = [];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
266 $this->amigos(@{$options->{'amigos'}}) if $options->{'amigos'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
267 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
268
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
269 All this bookkeeping looks silly with just one new attribute in a
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
270 class derived straight from Tree::DAG_Node, but if there's lots of new
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
271 attributes running around, and if you're deriving from a class derived
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
272 from a class derived from Tree::DAG_Node, then tidy
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
273 stratification/modularization like this can keep you sane.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
274
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
275 =item the constructor $obj->new() or $obj->new({...options...})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
276
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
277 Just another way to get at the C<new> method. This B<does not copy>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
278 $obj, but merely constructs a new object of the same class as it.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
279 Saves you the bother of going $class = ref $obj; $obj2 = $class->new;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
280
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
281 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
282
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
283 sub new { # constructor
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
284 # Presumably you won't EVER need to override this -- _init is what
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
285 # you'd override in order to set an object's default attribute values.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
286 my $class = shift;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
287 $class = ref($class) if ref($class); # tchristic style. why not?
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
288
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
289 my $o = ref($_[0]) eq 'HASH' ? $_[0] : {}; # o for options hashref
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
290 my $it = bless( {}, $class );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
291 print "Constructing $it in class $class\n" if $Debug;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
292 $it->_init( $o );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
293 return $it;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
294 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
295
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
296 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
297
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
298 =item the method $node->_init({...options...})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
299
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
300 Initialize the object's attribute values. See the discussion above.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
301 Presumably this should be called only by the guts of the C<new>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
302 constructor -- never by the end user.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
303
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
304 Currently there are no documented options for putting in
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
305 {...options...}, but (in case you want to disregard the above rant)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
306 the option exists for you to use {...options...} for something useful
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
307 in a derived class.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
308
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
309 Please see the source for more information.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
310
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
311 =item see also (below) the constructors "new_daughter" and "new_daughter_left"
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
312
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
313 =back
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
314
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
315 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
316
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
317 sub _init { # method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
318 my $this = shift;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
319 my $o = ref($_[0]) eq 'HASH' ? $_[0] : {};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
320
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
321 # Sane initialization.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
322 $this->_init_mother($o);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
323 $this->_init_daughters($o);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
324 $this->_init_name($o);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
325 $this->_init_attributes($o);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
326
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
327 return;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
328 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
329
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
330 sub _init_mother { # to be called by an _init
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
331 my($this, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
332
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
333 $this->{'mother'} = undef;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
334
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
335 # Undocumented and disfavored. Consider this just an example.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
336 ( $o->{'mother'} )->add_daughter($this)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
337 if defined($o->{'mother'}) && ref($o->{'mother'});
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
338 # DO NOT use this option (as implemented) with new_daughter or
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
339 # new_daughter_left!!!!!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
340 # BAD THINGS MAY HAPPEN!!!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
341 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
342
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
343 sub _init_daughters { # to be called by an _init
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
344 my($this, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
345
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
346 $this->{'daughters'} = [];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
347
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
348 # Undocumented and disfavored. Consider this just an example.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
349 $this->set_daughters( @{$o->{'daughters'}} )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
350 if ref($o->{'daughters'}) && (@{$o->{'daughters'}});
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
351 # DO NOT use this option (as implemented) with new_daughter or
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
352 # new_daughter_left!!!!!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
353 # BAD THINGS MAY HAPPEN!!!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
354 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
355
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
356 sub _init_name { # to be called by an _init
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
357 my($this, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
358
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
359 $this->{'name'} = undef;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
360
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
361 # Undocumented and disfavored. Consider this just an example.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
362 $this->name( $o->{'name'} ) if exists $o->{'name'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
363 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
364
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
365 sub _init_attributes { # to be called by an _init
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
366 my($this, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
367
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
368 $this->{'attributes'} = {};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
369
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
370 # Undocumented and disfavored. Consider this just an example.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
371 $this->attributes( $o->{'attributes'} ) if exists $o->{'attributes'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
372 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
373
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
374 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
375 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
376
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
377 =head1 LINKAGE-RELATED METHODS
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
378
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
379 =over
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
380
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
381 =item $node->daughters
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
382
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
383 This returns the (possibly empty) list of daughters for $node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
384
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
385 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
386
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
387 sub daughters { # read-only attrib-method: returns a list.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
388 my $this = shift;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
389
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
390 if(@_) { # undoc'd and disfavored to use as a write-method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
391 Carp::croak "Don't set daughters with doughters anymore\n";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
392 Carp::carp "my parameter must be a listref" unless ref($_[0]);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
393 $this->{'daughters'} = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
394 $this->_update_daughter_links;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
395 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
396 #return $this->{'daughters'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
397 return @{$this->{'daughters'} || []};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
398 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
399
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
400 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
401
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
402 =item $node->mother
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
403
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
404 This returns what node is $node's mother. This is undef if $node has
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
405 no mother -- i.e., if it is a root.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
406
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
407 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
408
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
409 sub mother { # read-only attrib-method: returns an object (the mother node)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
410 my $this = shift;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
411 Carp::croak "I'm a read-only method!" if @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
412 return $this->{'mother'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
413 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
414
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
415 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
416 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
417
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
418 =item $mother->add_daughters( LIST )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
419
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
420 This method adds the node objects in LIST to the (right) end of
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
421 $mother's C<daughter> list. Making a node N1 the daughter of another
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
422 node N2 also means that N1's C<mother> attribute is "automatically" set
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
423 to N2; it also means that N1 stops being anything else's daughter as
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
424 it becomes N2's daughter.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
425
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
426 If you try to make a node its own mother, a fatal error results. If
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
427 you try to take one of a a node N1's ancestors and make it also a
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
428 daughter of N1, a fatal error results. A fatal error results if
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
429 anything in LIST isn't a node object.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
430
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
431 If you try to make N1 a daughter of N2, but it's B<already> a daughter
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
432 of N2, then this is a no-operation -- it won't move such nodes to the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
433 end of the list or anything; it just skips doing anything with them.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
434
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
435 =item $node->add_daughter( LIST )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
436
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
437 An exact synonym for $node->add_daughters(LIST)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
438
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
439 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
440
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
441 sub add_daughters { # write-only method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
442 my($mother, @daughters) = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
443 return unless @daughters; # no-op
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
444 return
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
445 $mother->_add_daughters_wrapper(
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
446 sub { push @{$_[0]}, $_[1]; },
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
447 @daughters
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
448 );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
449 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
450
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
451 sub add_daughter { # alias
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
452 my($it,@them) = @_; $it->add_daughters(@them);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
453 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
454
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
455 =item $mother->add_daughters_left( LIST )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
456
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
457 This method is just like C<add_daughters>, except that it adds the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
458 node objects in LIST to the (left) beginning of $mother's daughter
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
459 list, instead of the (right) end of it.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
460
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
461 =item $node->add_daughter_left( LIST )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
462
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
463 An exact synonym for $node->add_daughters_left( LIST )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
464
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
465 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
466
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
467 sub add_daughters_left { # write-only method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
468 my($mother, @daughters) = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
469 return unless @daughters;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
470 return
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
471 $mother->_add_daughters_wrapper(
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
472 sub { unshift @{$_[0]}, $_[1]; },
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
473 @daughters
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
474 );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
475 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
476
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
477 sub add_daughter_left { # alias
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
478 my($it,@them) = @_; $it->add_daughters_left(@them);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
479 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
480
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
481 =item Note:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
482
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
483 The above link-making methods perform basically an C<unshift> or
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
484 C<push> on the mother node's daughter list. To get the full range of
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
485 list-handling functionality, copy the daughter list, and change it,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
486 and then call C<set_daughters> on the result:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
487
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
488 @them = $mother->daughters;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
489 @removed = splice(@them, 0,2, @new_nodes);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
490 $mother->set_daughters(@them);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
491
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
492 Or consider a structure like:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
493
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
494 $mother->set_daughters(
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
495 grep($_->name =~ /NP/ ,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
496 $mother->daughters
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
497 )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
498 );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
499
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
500 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
501
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
502
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
503 ###
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
504 ## Used by the adding methods
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
505 # (except maybe new_daughter, and new_daughter_left)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
506
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
507 sub _add_daughters_wrapper {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
508 my($mother, $callback, @daughters) = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
509 return unless @daughters;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
510
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
511 my %ancestors;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
512 @ancestors{ $mother->ancestors } = undef;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
513 # This could be made more efficient by not bothering to compile
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
514 # the ancestor list for $mother if all the nodes to add are
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
515 # daughterless.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
516 # But then you have to CHECK if they're daughterless.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
517 # If $mother is [big number] generations down, then it's worth checking.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
518
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
519 foreach my $daughter (@daughters) { # which may be ()
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
520 Carp::croak "daughter must be a node object!" unless UNIVERSAL::can($daughter, 'is_node');
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
521
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
522 printf "Mother : %s (%s)\n", $mother, ref $mother if $Debug;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
523 printf "Daughter: %s (%s)\n", $daughter, ref $daughter if $Debug;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
524 printf "Adding %s to %s\n",
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
525 ($daughter->name() || $daughter),
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
526 ($mother->name() || $mother) if $Debug > 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
527
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
528 Carp::croak "mother can't be its own daughter!" if $mother eq $daughter;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
529
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
530 $daughter->cyclicity_fault(
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
531 "$daughter (" . ($daughter->name || 'no_name') .
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
532 ") is an ancestor of $mother (" . ($mother->name || 'no_name') .
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
533 "), so can't became its daughter."
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
534 ) if exists $ancestors{$daughter};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
535
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
536 my $old_mother = $daughter->{'mother'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
537
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
538 next if defined($old_mother) && ref($old_mother) && $old_mother eq $mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
539 # noop if $daughter is already $mother's daughter
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
540
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
541 $old_mother->remove_daughters($daughter)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
542 if defined($old_mother) && ref($old_mother);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
543
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
544 &{$callback}($mother->{'daughters'}, $daughter);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
545 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
546 $mother->_update_daughter_links; # need only do this at the end
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
547
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
548 return;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
549 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
550
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
551 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
552 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
553
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
554 sub _update_daughter_links {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
555 # Eliminate any duplicates in my daughters list, and update
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
556 # all my daughters' links to myself.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
557 my $this = shift;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
558
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
559 my $them = $this->{'daughters'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
560
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
561 # Eliminate duplicate daughters.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
562 my %seen = ();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
563 @$them = grep { ref($_) && not($seen{$_}++) } @$them;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
564 # not that there should ever be duplicate daughters anyhoo.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
565
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
566 foreach my $one (@$them) { # linkage bookkeeping
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
567 Carp::croak "daughter <$one> isn't an object!" unless ref $one;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
568 $one->{'mother'} = $this;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
569 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
570 return;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
571 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
572
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
573 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
574
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
575 # Currently unused.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
576
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
577 sub _update_links { # update all descendant links for ancestorship below
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
578 # this point
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
579 # note: it's "descendant", not "descendent"
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
580 # see <http://www.lenzo.com/~sburke/stuff/english_ant_and_ent.html>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
581 my $this = shift;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
582 # $this->no_cyclicity;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
583 $this->walk_down({
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
584 'callback' => sub {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
585 my $this = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
586 $this->_update_daughter_links;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
587 return 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
588 },
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
589 });
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
590 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
591
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
592 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
593 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
594
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
595 =item the constructor $daughter = $mother->new_daughter, or
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
596
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
597 =item the constructor $daughter = $mother->new_daughter({...options...})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
598
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
599 This B<constructs> a B<new> node (of the same class as $mother), and
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
600 adds it to the (right) end of the daughter list of $mother. This is
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
601 essentially the same as going
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
602
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
603 $daughter = $mother->new;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
604 $mother->add_daughter($daughter);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
605
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
606 but is rather more efficient because (since $daughter is guaranteed new
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
607 and isn't linked to/from anything), it doesn't have to check that
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
608 $daughter isn't an ancestor of $mother, isn't already daughter to a
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
609 mother it needs to be unlinked from, isn't already in $mother's
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
610 daughter list, etc.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
611
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
612 As you'd expect for a constructor, it returns the node-object created.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
613
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
614 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
615
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
616 # Note that if you radically change 'mother'/'daughters' bookkeeping,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
617 # you may have to change this routine, since it's one of the places
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
618 # that directly writes to 'daughters' and 'mother'.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
619
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
620 sub new_daughter {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
621 my($mother, @options) = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
622 my $daughter = $mother->new(@options);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
623
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
624 push @{$mother->{'daughters'}}, $daughter;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
625 $daughter->{'mother'} = $mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
626
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
627 return $daughter;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
628 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
629
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
630 =item the constructor $mother->new_daughter_left, or
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
631
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
632 =item $mother->new_daughter_left({...options...})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
633
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
634 This is just like $mother->new_daughter, but adds the new daughter
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
635 to the left (start) of $mother's daughter list.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
636
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
637 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
638
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
639 # Note that if you radically change 'mother'/'daughters' bookkeeping,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
640 # you may have to change this routine, since it's one of the places
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
641 # that directly writes to 'daughters' and 'mother'.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
642
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
643 sub new_daughter_left {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
644 my($mother, @options) = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
645 my $daughter = $mother->new(@options);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
646
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
647 unshift @{$mother->{'daughters'}}, $daughter;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
648 $daughter->{'mother'} = $mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
649
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
650 return $daughter;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
651 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
652
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
653 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
654
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
655 =item $mother->remove_daughters( LIST )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
656
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
657 This removes the nodes listed in LIST from $mother's daughter list.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
658 This is a no-operation if LIST is empty. If there are things in LIST
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
659 that aren't a current daughter of $mother, they are ignored.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
660
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
661 Not to be confused with $mother->clear_daughters.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
662
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
663 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
664
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
665 sub remove_daughters { # write-only method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
666 my($mother, @daughters) = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
667 Carp::croak "mother must be an object!" unless ref $mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
668 return unless @daughters;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
669
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
670 my %to_delete;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
671 @daughters = grep {ref($_)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
672 and defined($_->{'mother'})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
673 and $mother eq $_->{'mother'}
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
674 } @daughters;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
675 return unless @daughters;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
676 @to_delete{ @daughters } = undef;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
677
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
678 # This could be done better and more efficiently, I guess.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
679 foreach my $daughter (@daughters) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
680 $daughter->{'mother'} = undef;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
681 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
682 my $them = $mother->{'daughters'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
683 @$them = grep { !exists($to_delete{$_}) } @$them;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
684
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
685 # $mother->_update_daughter_links; # unnecessary
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
686 return;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
687 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
688
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
689 =item $node->remove_daughter( LIST )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
690
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
691 An exact synonym for $node->remove_daughters( LIST )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
692
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
693 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
694
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
695 sub remove_daughter { # alias
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
696 my($it,@them) = @_; $it->remove_daughters(@them);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
697 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
698
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
699 =item $node->unlink_from_mother
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
700
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
701 This removes node from the daughter list of its mother. If it has no
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
702 mother, this is a no-operation.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
703
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
704 Returns the mother unlinked from (if any).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
705
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
706 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
707
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
708 sub unlink_from_mother {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
709 my $node = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
710 my $mother = $node->{'mother'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
711 $mother->remove_daughters($node) if defined($mother) && ref($mother);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
712 return $mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
713 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
714
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
715 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
716
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
717 =item $mother->clear_daughters
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
718
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
719 This unlinks all $mother's daughters.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
720 Returns the the list of what used to be $mother's daughters.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
721
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
722 Not to be confused with $mother->remove_daughters( LIST ).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
723
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
724 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
725
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
726 sub clear_daughters { # write-only method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
727 my($mother) = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
728 my @daughters = @{$mother->{'daughters'}};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
729
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
730 @{$mother->{'daughters'}} = ();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
731 foreach my $one (@daughters) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
732 next unless UNIVERSAL::can($one, 'is_node'); # sanity check
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
733 $one->{'mother'} = undef;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
734 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
735 # Another, simpler, way to do it:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
736 # $mother->remove_daughters($mother->daughters);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
737
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
738 return @daughters; # NEW
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
739 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
740 #--------------------------------------------------------------------------
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
741
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
742 =item $mother->set_daughters( LIST )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
743
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
744 This unlinks all $mother's daughters, and replaces them with the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
745 daughters in LIST.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
746
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
747 Currently implemented as just $mother->clear_daughters followed by
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
748 $mother->add_daughters( LIST ).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
749
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
750 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
751
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
752 sub set_daughters { # write-only method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
753 my($mother, @them) = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
754 $mother->clear_daughters;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
755 $mother->add_daughters(@them) if @them;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
756 # yup, it's that simple
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
757 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
758
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
759 #--------------------------------------------------------------------------
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
760
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
761 =item $node->replace_with( LIST )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
762
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
763 This replaces $node in its mother's daughter list, by unlinking $node
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
764 and replacing it with the items in LIST. This returns a list consisting
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
765 of $node followed by LIST, i.e., the nodes that replaced it.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
766
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
767 LIST can include $node itself (presumably at most once). LIST can
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
768 also be empty-list. However, if any items in LIST are sisters to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
769 $node, they are ignored, and are not in the copy of LIST passed as the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
770 return value.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
771
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
772 As you might expect for any linking operation, the items in LIST
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
773 cannot be $node's mother, or any ancestor to it; and items in LIST are,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
774 of course, unlinked from their mothers (if they have any) as they're
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
775 linked to $node's mother.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
776
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
777 (In the special (and bizarre) case where $node is root, this simply calls
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
778 $this->unlink_from_mother on all the items in LIST, making them roots of
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
779 their own trees.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
780
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
781 Note that the daughter-list of $node is not necessarily affected; nor
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
782 are the daughter-lists of the items in LIST. I mention this in case you
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
783 think replace_with switches one node for another, with respect to its
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
784 mother list B<and> its daughter list, leaving the rest of the tree
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
785 unchanged. If that's what you want, replacing $Old with $New, then you
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
786 want:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
787
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
788 $New->set_daughters($Old->clear_daughters);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
789 $Old->replace_with($New);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
790
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
791 (I can't say $node's and LIST-items' daughter lists are B<never>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
792 affected my replace_with -- they can be affected in this case:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
793
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
794 $N1 = ($node->daughters)[0]; # first daughter of $node
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
795 $N2 = ($N1->daughters)[0]; # first daughter of $N1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
796 $N3 = Tree::DAG_Node->random_network; # or whatever
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
797 $node->replace_with($N1, $N2, $N3);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
798
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
799 As a side affect of attaching $N1 and $N2 to $node's mother, they're
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
800 unlinked from their parents ($node, and $N1, replectively).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
801 But N3's daughter list is unaffected.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
802
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
803 In other words, this method does what it has to, as you'd expect it
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
804 to.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
805
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
806 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
807
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
808 sub replace_with { # write-only method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
809 my($this, @replacements) = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
810
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
811 if(not( defined($this->{'mother'}) && ref($this->{'mother'}) )) { # if root
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
812 foreach my $replacement (@replacements) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
813 $replacement->{'mother'}->remove_daughters($replacement)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
814 if $replacement->{'mother'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
815 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
816 # make 'em roots
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
817 } else { # I have a mother
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
818 my $mother = $this->{'mother'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
819
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
820 #@replacements = grep(($_ eq $this || $_->{'mother'} ne $mother),
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
821 # @replacements);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
822 @replacements = grep { $_ eq $this
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
823 || not(defined($_->{'mother'}) &&
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
824 ref($_->{'mother'}) &&
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
825 $_->{'mother'} eq $mother
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
826 )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
827 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
828 @replacements;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
829 # Eliminate sisters (but not self)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
830 # i.e., I want myself or things NOT with the same mother as myself.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
831
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
832 $mother->set_daughters( # old switcheroo
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
833 map($_ eq $this ? (@replacements) : $_ ,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
834 @{$mother->{'daughters'}}
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
835 )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
836 );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
837 # and set_daughters does all the checking and possible
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
838 # unlinking
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
839 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
840 return($this, @replacements);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
841 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
842
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
843 =item $node->replace_with_daughters
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
844
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
845 This replaces $node in its mother's daughter list, by unlinking $node
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
846 and replacing it with its daughters. In other words, $node becomes
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
847 motherless and daughterless as its daughters move up and take its place.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
848 This returns a list consisting of $node followed by the nodes that were
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
849 its daughters.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
850
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
851 In the special (and bizarre) case where $node is root, this simply
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
852 unlinks its daughters from it, making them roots of their own trees.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
853
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
854 Effectively the same as $node->replace_with($node->daughters), but more
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
855 efficient, since less checking has to be done. (And I also think
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
856 $node->replace_with_daughters is a more common operation in
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
857 tree-wrangling than $node->replace_with(LIST), so deserves a named
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
858 method of its own, but that's just me.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
859
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
860 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
861
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
862 # Note that if you radically change 'mother'/'daughters' bookkeeping,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
863 # you may have to change this routine, since it's one of the places
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
864 # that directly writes to 'daughters' and 'mother'.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
865
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
866 sub replace_with_daughters { # write-only method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
867 my($this) = $_[0]; # takes no params other than the self
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
868 my $mother = $this->{'mother'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
869 return($this, $this->clear_daughters)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
870 unless defined($mother) && ref($mother);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
871
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
872 my @daughters = $this->clear_daughters;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
873 my $sib_r = $mother->{'daughters'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
874 @$sib_r = map($_ eq $this ? (@daughters) : $_,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
875 @$sib_r # old switcheroo
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
876 );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
877 foreach my $daughter (@daughters) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
878 $daughter->{'mother'} = $mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
879 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
880 return($this, @daughters);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
881 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
882
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
883 #--------------------------------------------------------------------------
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
884
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
885 =item $node->add_left_sisters( LIST )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
886
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
887 This adds the elements in LIST (in that order) as immediate left sisters of
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
888 $node. In other words, given that B's mother's daughter-list is (A,B,C,D),
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
889 calling B->add_left_sisters(X,Y) makes B's mother's daughter-list
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
890 (A,X,Y,B,C,D).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
891
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
892 If LIST is empty, this is a no-op, and returns empty-list.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
893
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
894 This is basically implemented as a call to $node->replace_with(LIST,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
895 $node), and so all replace_with's limitations and caveats apply.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
896
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
897 The return value of $node->add_left_sisters( LIST ) is the elements of
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
898 LIST that got added, as returned by replace_with -- minus the copies
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
899 of $node you'd get from a straight call to $node->replace_with(LIST,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
900 $node).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
901
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
902 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
903
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
904 sub add_left_sisters { # write-only method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
905 my($this, @new) = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
906 return() unless @new;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
907
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
908 @new = $this->replace_with(@new, $this);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
909 shift @new; pop @new; # kill the copies of $this
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
910 return @new;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
911 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
912
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
913 =item $node->add_left_sister( LIST )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
914
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
915 An exact synonym for $node->add_left_sisters(LIST)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
916
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
917 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
918
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
919 sub add_left_sister { # alias
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
920 my($it,@them) = @_; $it->add_left_sisters(@them);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
921 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
922
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
923 =item $node->add_right_sisters( LIST )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
924
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
925 Just like add_left_sisters (which see), except that the the elements
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
926 in LIST (in that order) as immediate B<right> sisters of $node;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
927
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
928 In other words, given that B's mother's daughter-list is (A,B,C,D),
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
929 calling B->add_right_sisters(X,Y) makes B's mother's daughter-list
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
930 (A,B,X,Y,C,D).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
931
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
932 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
933
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
934 sub add_right_sisters { # write-only method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
935 my($this, @new) = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
936 return() unless @new;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
937 @new = $this->replace_with($this, @new);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
938 shift @new; shift @new; # kill the copies of $this
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
939 return @new;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
940 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
941
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
942 =item $node->add_right_sister( LIST )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
943
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
944 An exact synonym for $node->add_right_sisters(LIST)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
945
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
946 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
947
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
948 sub add_right_sister { # alias
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
949 my($it,@them) = @_; $it->add_right_sisters(@them);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
950 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
951
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
952 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
953
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
954 =back
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
955
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
956 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
957
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
958 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
959 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
960
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
961 =head1 OTHER ATTRIBUTE METHODS
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
962
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
963 =over
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
964
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
965 =item $node->name or $node->name(SCALAR)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
966
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
967 In the first form, returns the value of the node object's "name"
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
968 attribute. In the second form, sets it to the value of SCALAR.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
969
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
970 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
971
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
972 sub name { # read/write attribute-method. returns/expects a scalar
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
973 my $this = shift;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
974 $this->{'name'} = $_[0] if @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
975 return $this->{'name'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
976 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
977
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
978
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
979 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
980
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
981 =item $node->attributes or $node->attributes(SCALAR)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
982
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
983 In the first form, returns the value of the node object's "attributes"
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
984 attribute. In the second form, sets it to the value of SCALAR. I
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
985 intend this to be used to store a reference to a (presumably
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
986 anonymous) hash the user can use to store whatever attributes he
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
987 doesn't want to have to store as object attributes. In this case, you
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
988 needn't ever set the value of this. (_init has already initialized it
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
989 to {}.) Instead you can just do...
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
990
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
991 $node->attributes->{'foo'} = 'bar';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
992
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
993 ...to write foo => bar.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
994
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
995 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
996
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
997 sub attributes { # read/write attribute-method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
998 # expects a ref, presumably a hashref
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
999 my $this = shift;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1000 if(@_) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1001 Carp::carp "my parameter must be a reference" unless ref($_[0]);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1002 $this->{'attributes'} = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1003 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1004 return $this->{'attributes'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1005 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1006
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1007 =item $node->attribute or $node->attribute(SCALAR)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1008
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1009 An exact synonym for $node->attributes or $node->attributes(SCALAR)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1010
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1011 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1012
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1013 sub attribute { # alias
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1014 my($it,@them) = @_; $it->attributes(@them);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1015 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1016
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1017 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1018 # Secret Stuff.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1019
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1020 sub no_cyclicity { # croak iff I'm in a CYCLIC class.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1021 my($it) = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1022 # If, God forbid, I use this to make a cyclic class, then I'd
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1023 # expand the functionality of this routine to actually look for
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1024 # cyclicity. Or something like that. Maybe.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1025
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1026 $it->cyclicity_fault("You can't do that in a cyclic class!")
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1027 if $it->cyclicity_allowed;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1028 return;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1029 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1030
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1031 sub cyclicity_fault {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1032 my($it, $bitch) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1033 Carp::croak "Cyclicity fault: $bitch"; # never return
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1034 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1035
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1036 sub cyclicity_allowed {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1037 return 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1038 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1039
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1040 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1041 # More secret stuff. Currently unused.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1042
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1043 sub inaugurate_root { # no-op
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1044 my($it, $tree) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1045 # flag this node as being the root of the tree $tree.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1046 return;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1047 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1048
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1049 sub decommission_root { # no-op
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1050 # flag this node as no longer being the root of the tree $tree.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1051 return;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1052 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1053
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1054 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1055 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1056
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1057 =back
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1058
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1059 =head1 OTHER METHODS TO DO WITH RELATIONSHIPS
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1060
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1061 =over
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1062
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1063 =item $node->is_node
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1064
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1065 This always returns true. More pertinently, $object->can('is_node')
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1066 is true (regardless of what C<is_node> would do if called) for objects
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1067 belonging to this class or for any class derived from it.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1068
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1069 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1070
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1071 sub is_node { return 1; } # always true.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1072 # NEVER override this with anything that returns false in the belief
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1073 # that this'd signal "not a node class". The existence of this method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1074 # is what I test for, with the various "can()" uses in this class.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1075
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1076 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1077
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1078 =item $node->ancestors
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1079
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1080 Returns the list of this node's ancestors, starting with its mother,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1081 then grandmother, and ending at the root. It does this by simply
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1082 following the 'mother' attributes up as far as it can. So if $item IS
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1083 the root, this returns an empty list.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1084
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1085 Consider that scalar($node->ancestors) returns the ply of this node
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1086 within the tree -- 2 for a granddaughter of the root, etc., and 0 for
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1087 root itself.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1088
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1089 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1090
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1091 sub ancestors {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1092 my $this = shift;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1093 my $mama = $this->{'mother'}; # initial condition
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1094 return () unless ref($mama); # I must be root!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1095
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1096 # $this->no_cyclicity; # avoid infinite loops
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1097
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1098 # Could be defined recursively, as:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1099 # if(ref($mama = $this->{'mother'})){
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1100 # return($mama, $mama->ancestors);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1101 # } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1102 # return ();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1103 # }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1104 # But I didn't think of that until I coded the stuff below, which is
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1105 # faster.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1106
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1107 my @ancestors = ( $mama ); # start off with my mama
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1108 while(defined( $mama = $mama->{'mother'} ) && ref($mama)) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1109 # Walk up the tree
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1110 push(@ancestors, $mama);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1111 # This turns into an infinite loop if someone gets stupid
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1112 # and makes this tree cyclic! Don't do it!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1113 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1114 return @ancestors;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1115 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1116
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1117 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1118
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1119 =item $node->root
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1120
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1121 Returns the root of whatever tree $node is a member of. If $node is
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1122 the root, then the result is $node itself.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1123
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1124 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1125
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1126 sub root {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1127 my $it = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1128 my @ancestors = ($it, $it->ancestors);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1129 return $ancestors[-1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1130 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1131
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1132 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1133
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1134 =item $node->is_daughter_of($node2)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1135
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1136 Returns true iff $node is a daughter of $node2.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1137 Currently implemented as just a test of ($it->mother eq $node2).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1138
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1139 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1140
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1141 sub is_daughter_of {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1142 my($it,$mama) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1143 return $it->{'mother'} eq $mama;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1144 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1145
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1146 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1147
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1148 =item $node->self_and_descendants
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1149
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1150 Returns a list consisting of itself (as element 0) and all the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1151 descendants of $node. Returns just itself if $node is a
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1152 terminal_node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1153
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1154 (Note that it's spelled "descendants", not "descendents".)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1155
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1156 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1157
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1158 sub self_and_descendants {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1159 # read-only method: return a list of myself and any/all descendants
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1160 my $node = shift;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1161 my @List = ();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1162 # $node->no_cyclicity;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1163 $node->walk_down({ 'callback' => sub { push @List, $_[0]; return 1;}});
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1164 Carp::croak "Spork Error 919: \@List has no contents!?!?" unless @List;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1165 # impossible
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1166 return @List;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1167 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1168
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1169 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1170
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1171 =item $node->descendants
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1172
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1173 Returns a list consisting of all the descendants of $node. Returns
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1174 empty-list if $node is a terminal_node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1175
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1176 (Note that it's spelled "descendants", not "descendents".)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1177
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1178 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1179
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1180 sub descendants {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1181 # read-only method: return a list of my descendants
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1182 my $node = shift;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1183 my @list = $node->self_and_descendants;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1184 shift @list; # lose myself.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1185 return @list;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1186 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1187
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1188 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1189
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1190 =item $node->leaves_under
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1191
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1192 Returns a list (going left-to-right) of all the leaf nodes under
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1193 $node. ("Leaf nodes" are also called "terminal nodes" -- i.e., nodes
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1194 that have no daughters.) Returns $node in the degenerate case of
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1195 $node being a leaf itself.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1196
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1197 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1198
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1199 sub leaves_under {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1200 # read-only method: return a list of all leaves under myself.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1201 # Returns myself in the degenerate case of being a leaf myself.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1202 my $node = shift;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1203 my @List = ();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1204 # $node->no_cyclicity;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1205 $node->walk_down({ 'callback' =>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1206 sub {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1207 my $node = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1208 my @daughters = @{$node->{'daughters'}};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1209 push(@List, $node) unless @daughters;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1210 return 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1211 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1212 });
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1213 Carp::croak "Spork Error 861: \@List has no contents!?!?" unless @List;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1214 # impossible
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1215 return @List;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1216 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1217
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1218 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1219
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1220 =item $node->depth_under
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1221
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1222 Returns an integer representing the number of branches between this
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1223 $node and the most distant leaf under it. (In other words, this
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1224 returns the ply of subtree starting of $node. Consider
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1225 scalar($it->ancestors) if you want the ply of a node within the whole
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1226 tree.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1227
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1228 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1229
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1230 sub depth_under {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1231 my $node = shift;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1232 my $max_depth = 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1233 $node->walk_down({
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1234 '_depth' => 0,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1235 'callback' => sub {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1236 my $depth = $_[1]->{'_depth'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1237 $max_depth = $depth if $depth > $max_depth;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1238 return 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1239 },
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1240 });
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1241 return $max_depth;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1242 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1243
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1244 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1245
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1246 =item $node->generation
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1247
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1248 Returns a list of all nodes (going left-to-right) that are in $node's
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1249 generation -- i.e., that are the some number of nodes down from
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1250 the root. $root->generation is just $root.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1251
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1252 Of course, $node is always in its own generation.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1253
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1254 =item $node->generation_under(NODE2)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1255
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1256 Like $node->generation, but returns only the nodes in $node's generation
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1257 that are also descendants of NODE2 -- in other words,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1258
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1259 @us = $node->generation_under( $node->mother->mother );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1260
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1261 is all $node's first cousins (to borrow yet more kinship terminology) --
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1262 assuming $node does indeed have a grandmother. Actually "cousins" isn't
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1263 quite an apt word, because C<@us> ends up including $node's siblings and
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1264 $node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1265
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1266 Actually, C<generation_under> is just an alias to C<generation>, but I
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1267 figure that this:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1268
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1269 @us = $node->generation_under($way_upline);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1270
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1271 is a bit more readable than this:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1272
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1273 @us = $node->generation($way_upline);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1274
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1275 But it's up to you.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1276
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1277 $node->generation_under($node) returns just $node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1278
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1279 If you call $node->generation_under($node) but NODE2 is not $node or an
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1280 ancestor of $node, it behaves as if you called just $node->generation().
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1281
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1282 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1283
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1284 sub generation {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1285 my($node, $limit) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1286 # $node->no_cyclicity;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1287 return $node
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1288 if $node eq $limit || not(
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1289 defined($node->{'mother'}) &&
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1290 ref($node->{'mother'})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1291 ); # bailout
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1292
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1293 return map(@{$_->{'daughters'}}, $node->{'mother'}->generation($limit));
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1294 # recurse!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1295 # Yup, my generation is just all the daughters of my mom's generation.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1296 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1297
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1298 sub generation_under {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1299 my($node, @rest) = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1300 return $node->generation(@rest);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1301 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1302
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1303 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1304
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1305 =item $node->self_and_sisters
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1306
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1307 Returns a list of all nodes (going left-to-right) that have the same
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1308 mother as $node -- including $node itself. This is just like
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1309 $node->mother->daughters, except that that fails where $node is root,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1310 whereas $root->self_and_siblings, as a special case, returns $root.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1311
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1312 (Contrary to how you may interpret how this method is named, "self" is
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1313 not (necessarily) the first element of what's returned.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1314
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1315 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1316
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1317 sub self_and_sisters {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1318 my $node = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1319 my $mother = $node->{'mother'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1320 return $node unless defined($mother) && ref($mother); # special case
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1321 return @{$node->{'mother'}->{'daughters'}};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1322 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1323
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1324 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1325
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1326 =item $node->sisters
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1327
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1328 Returns a list of all nodes (going left-to-right) that have the same
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1329 mother as $node -- B<not including> $node itself. If $node is root,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1330 this returns empty-list.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1331
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1332 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1333
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1334 sub sisters {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1335 my $node = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1336 my $mother = $node->{'mother'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1337 return() unless $mother; # special case
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1338 return grep($_ ne $node,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1339 @{$node->{'mother'}->{'daughters'}}
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1340 );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1341 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1342
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1343 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1344
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1345 =item $node->left_sister
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1346
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1347 Returns the node that's the immediate left sister of $node. If $node
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1348 is the leftmost (or only) daughter of its mother (or has no mother),
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1349 then this returns undef.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1350
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1351 (See also $node->add_left_sisters(LIST).)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1352
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1353 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1354
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1355 sub left_sister {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1356 my $it = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1357 my $mother = $it->{'mother'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1358 return undef unless $mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1359 my @sisters = @{$mother->{'daughters'}};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1360
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1361 return undef if @sisters == 1; # I'm an only daughter
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1362
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1363 my $left = undef;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1364 foreach my $one (@sisters) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1365 return $left if $one eq $it;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1366 $left = $one;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1367 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1368 die "SPORK ERROR 9757: I'm not in my mother's daughter list!?!?";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1369 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1370
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1371
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1372 =item $node->left_sisters
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1373
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1374 Returns a list of nodes that're sisters to the left of $node. If
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1375 $node is the leftmost (or only) daughter of its mother (or has no
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1376 mother), then this returns an empty list.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1377
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1378 (See also $node->add_left_sisters(LIST).)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1379
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1380 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1381
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1382 sub left_sisters {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1383 my $it = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1384 my $mother = $it->{'mother'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1385 return() unless $mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1386 my @sisters = @{$mother->{'daughters'}};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1387 return() if @sisters == 1; # I'm an only daughter
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1388
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1389 my @out = ();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1390 foreach my $one (@sisters) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1391 return @out if $one eq $it;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1392 push @out, $one;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1393 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1394 die "SPORK ERROR 9767: I'm not in my mother's daughter list!?!?";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1395 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1396
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1397 =item $node->right_sister
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1398
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1399 Returns the node that's the immediate right sister of $node. If $node
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1400 is the rightmost (or only) daughter of its mother (or has no mother),
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1401 then this returns undef.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1402
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1403 (See also $node->add_right_sisters(LIST).)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1404
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1405 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1406
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1407 sub right_sister {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1408 my $it = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1409 my $mother = $it->{'mother'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1410 return undef unless $mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1411 my @sisters = @{$mother->{'daughters'}};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1412 return undef if @sisters == 1; # I'm an only daughter
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1413
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1414 my $seen = 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1415 foreach my $one (@sisters) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1416 return $one if $seen;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1417 $seen = 1 if $one eq $it;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1418 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1419 die "SPORK ERROR 9777: I'm not in my mother's daughter list!?!?"
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1420 unless $seen;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1421 return undef;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1422 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1423
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1424 =item $node->right_sisters
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1425
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1426 Returns a list of nodes that're sisters to the right of $node. If
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1427 $node is the rightmost (or only) daughter of its mother (or has no
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1428 mother), then this returns an empty list.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1429
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1430 (See also $node->add_right_sisters(LIST).)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1431
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1432 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1433
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1434 sub right_sisters {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1435 my $it = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1436 my $mother = $it->{'mother'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1437 return() unless $mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1438 my @sisters = @{$mother->{'daughters'}};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1439 return() if @sisters == 1; # I'm an only daughter
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1440
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1441 my @out;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1442 my $seen = 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1443 foreach my $one (@sisters) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1444 push @out, $one if $seen;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1445 $seen = 1 if $one eq $it;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1446 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1447 die "SPORK ERROR 9787: I'm not in my mother's daughter list!?!?"
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1448 unless $seen;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1449 return @out;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1450 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1451
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1452 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1453
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1454 =item $node->my_daughter_index
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1455
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1456 Returns what index this daughter is, in its mother's C<daughter> list.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1457 In other words, if $node is ($node->mother->daughters)[3], then
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1458 $node->my_daughter_index returns 3.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1459
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1460 As a special case, returns 0 if $node has no mother.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1461
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1462 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1463
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1464 sub my_daughter_index {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1465 # returns what number is my index in my mother's daughter list
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1466 # special case: 0 for root.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1467 my $node = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1468 my $ord = -1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1469 my $mother = $node->{'mother'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1470
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1471 return 0 unless $mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1472 my @sisters = @{$mother->{'daughters'}};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1473
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1474 die "SPORK ERROR 6512: My mother has no kids!!!" unless @sisters;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1475
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1476 Find_Self:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1477 for(my $i = 0; $i < @sisters; $i++) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1478 if($sisters[$i] eq $node) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1479 $ord = $i;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1480 last Find_Self;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1481 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1482 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1483 die "SPORK ERROR 2837: I'm not a daughter of my mother?!?!" if $ord == -1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1484 return $ord;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1485 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1486
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1487 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1488
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1489 =item $node->address or $anynode->address(ADDRESS)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1490
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1491 With the first syntax, returns the address of $node within its tree,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1492 based on its position within the tree. An address is formed by noting
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1493 the path between the root and $node, and concatenating the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1494 daughter-indices of the nodes this passes thru (starting with 0 for
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1495 the root, and ending with $node).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1496
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1497 For example, if to get from node ROOT to node $node, you pass thru
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1498 ROOT, A, B, and $node, then the address is determined as:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1499
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1500 * ROOT's my_daughter_index is 0.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1501
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1502 * A's my_daughter_index is, suppose, 2. (A is index 2 in ROOT's
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1503 daughter list.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1504
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1505 * B's my_daughter_index is, suppose, 0. (B is index 0 in A's
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1506 daughter list.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1507
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1508 * $node's my_daughter_index is, suppose, 4. ($node is index 4 in
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1509 B's daughter list.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1510
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1511 The address of the above-described $node is, therefore, "0:2:0:4".
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1512
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1513 (As a somewhat special case, the address of the root is always "0";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1514 and since addresses start from the root, all addresses start with a
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1515 "0".)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1516
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1517 The second syntax, where you provide an address, starts from the root
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1518 of the tree $anynode belongs to, and returns the node corresponding to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1519 that address. Returns undef if no node corresponds to that address.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1520 Note that this routine may be somewhat liberal in its interpretation
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1521 of what can constitute an address; i.e., it accepts "0.2.0.4", besides
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1522 "0:2:0:4".
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1523
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1524 Also note that the address of a node in a tree is meaningful only in
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1525 that tree as currently structured.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1526
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1527 (Consider how ($address1 cmp $address2) may be magically meaningful
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1528 to you, if you mant to figure out what nodes are to the right of what
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1529 other nodes.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1530
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1531 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1532
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1533 sub address {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1534 my($it, $address) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1535 if(defined($address) && length($address)) { # given the address, return the node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1536 # invalid addresses return undef
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1537 my $root = $it->root;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1538 my @parts = map {$_ + 0}
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1539 $address =~ m/(\d+)/g; # generous!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1540 Carp::croak "Address \"$address\" is an ill-formed address" unless @parts;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1541 Carp::croak "Address \"$address\" must start with '0'" unless shift(@parts) == 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1542
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1543 my $current_node = $root;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1544 while(@parts) { # no-op for root
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1545 my $ord = shift @parts;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1546 my @daughters = @{$current_node->{'daughters'}};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1547
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1548 if($#daughters < $ord) { # illegal address
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1549 print "* $address has an out-of-range index ($ord)!" if $Debug;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1550 return undef;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1551 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1552 $current_node = $daughters[$ord];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1553 unless(ref($current_node)) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1554 print "* $address points to or thru a non-node!" if $Debug;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1555 return undef;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1556 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1557 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1558 return $current_node;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1559
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1560 } else { # given the node, return the address
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1561 my @parts = ();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1562 my $current_node = $it;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1563 my $mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1564
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1565 while(defined( $mother = $current_node->{'mother'} ) && ref($mother)) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1566 unshift @parts, $current_node->my_daughter_index;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1567 $current_node = $mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1568 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1569 return join(':', 0, @parts);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1570 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1571 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1572
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1573 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1574
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1575 =item $node->common(LIST)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1576
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1577 Returns the lowest node in the tree that is ancestor-or-self to the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1578 nodes $node and LIST.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1579
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1580 If the nodes are far enough apart in the tree, the answer is just the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1581 root.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1582
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1583 If the nodes aren't all in the same tree, the answer is undef.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1584
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1585 As a degenerate case, if LIST is empty, returns $node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1586
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1587 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1588
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1589 sub common { # Return the lowest node common to all these nodes...
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1590 # Called as $it->common($other) or $it->common(@others)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1591 my @ones = @_; # all nodes I was given
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1592 my($first, @others) = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1593
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1594 return $first unless @others; # degenerate case
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1595
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1596 my %ones;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1597 @ones{ @ones } = undef;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1598
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1599 foreach my $node (@others) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1600 Carp::croak "TILT: node \"$node\" is not a node"
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1601 unless UNIVERSAL::can($node, 'is_node');
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1602 my %first_lineage;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1603 @first_lineage{$first, $first->ancestors} = undef;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1604 my $higher = undef; # the common of $first and $node
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1605 my @my_lineage = $node->ancestors;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1606
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1607 Find_Common:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1608 while(@my_lineage) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1609 if(exists $first_lineage{$my_lineage[0]}) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1610 $higher = $my_lineage[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1611 last Find_Common;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1612 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1613 shift @my_lineage;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1614 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1615 return undef unless $higher;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1616 $first = $higher;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1617 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1618 return $first;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1619 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1620
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1621
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1622 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1623
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1624 =item $node->common_ancestor(LIST)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1625
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1626 Returns the lowest node that is ancestor to all the nodes given (in
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1627 nodes $node and LIST). In other words, it answers the question: "What
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1628 node in the tree, as low as possible, is ancestor to the nodes given
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1629 ($node and LIST)?"
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1630
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1631 If the nodes are far enough apart, the answer is just the root --
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1632 except if any of the nodes are the root itself, in which case the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1633 answer is undef (since the root has no ancestor).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1634
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1635 If the nodes aren't all in the same tree, the answer is undef.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1636
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1637 As a degenerate case, if LIST is empty, returns $node's mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1638 that'll be undef if $node is root.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1639
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1640 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1641
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1642 sub common_ancestor {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1643 my @ones = @_; # all nodes I was given
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1644 my($first, @others) = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1645
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1646 return $first->{'mother'} unless @others;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1647 # which may be undef if $first is the root!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1648
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1649 my %ones;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1650 @ones{ @ones } = undef; # my arguments
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1651
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1652 my $common = $first->common(@others);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1653 if(exists($ones{$common})) { # if the common is one of my nodes...
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1654 return $common->{'mother'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1655 # and this might be undef, if $common is root!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1656 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1657 return $common;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1658 # which might be null if that's all common came up with
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1659 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1660 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1661
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1662 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1663 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1664
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1665 =back
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1666
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1667 =head1 YET MORE METHODS
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1668
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1669 =over
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1670
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1671 =item $node->walk_down({ callback => \&foo, callbackback => \&foo, ... })
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1672
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1673 Performs a depth-first traversal of the structure at and under $node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1674 What it does at each node depends on the value of the options hashref,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1675 which you must provide. There are three options, "callback" and
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1676 "callbackback" (at least one of which must be defined, as a sub
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1677 reference), and "_depth". This is what C<walk_down> does, in
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1678 pseudocode form:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1679
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1680 * Start at the $node given.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1681
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1682 * If there's a C<callback>, call it with $node as the first argument,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1683 and the options hashref as the second argument (which contains the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1684 potentially useful C<_depth>, remember). This function must return
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1685 true or false -- if false, it will block the next step:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1686
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1687 * If $node has any daughter nodes, increment C<_depth>, and call
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1688 $daughter->walk_down(options_hashref) for each daughter (in order, of
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1689 course), where options_hashref is the same hashref it was called with.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1690 When this returns, decrements C<_depth>.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1691
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1692 * If there's a C<callbackback>, call just it as with C<callback> (but
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1693 tossing out the return value). Note that C<callback> returning false
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1694 blocks traversal below $node, but doesn't block calling callbackback
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1695 for $node. (Incidentally, in the unlikely case that $node has stopped
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1696 being a node object, C<callbackback> won't get called.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1697
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1698 * Return.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1699
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1700 $node->walk_down is the way to recursively do things to a tree (if you
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1701 start at the root) or part of a tree; if what you're doing is best done
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1702 via pre-pre order traversal, use C<callback>; if what you're doing is
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1703 best done with post-order traversal, use C<callbackback>.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1704 C<walk_down> is even the basis for plenty of the methods in this
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1705 class. See the source code for examples both simple and horrific.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1706
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1707 Note that if you don't specify C<_depth>, it effectively defaults to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1708 0. You should set it to scalar($node->ancestors) if you want
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1709 C<_depth> to reflect the true depth-in-the-tree for the nodes called,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1710 instead of just the depth below $node. (If $node is the root, there's
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1711 difference, of course.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1712
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1713 And B<by the way>, it's a bad idea to modify the tree from the callback.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1714 Unpredictable things may happen. I instead suggest having your callback
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1715 add to a stack of things that need changing, and then, once C<walk_down>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1716 is all finished, changing those nodes from that stack.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1717
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1718 Note that the existence of C<walk_down> doesn't mean you can't write
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1719 you own special-use traversers.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1720
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1721 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1722
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1723 sub walk_down {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1724 my($this, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1725
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1726 # All the can()s are in case an object changes class while I'm
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1727 # looking at it.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1728
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1729 Carp::croak "I need options!" unless ref($o);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1730 Carp::croak "I need a callback or a callbackback" unless
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1731 ( ref($o->{'callback'}) || ref($o->{'callbackback'}) );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1732
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1733 # $this->no_cyclicity;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1734 my $callback = ref($o->{'callback'}) ? $o->{'callback'} : undef;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1735 my $callbackback = ref($o->{'callbackback'}) ? $o->{'callbackback'} : undef;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1736 my $callback_status = 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1737
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1738 print "Callback: $callback Callbackback: $callbackback\n" if $Debug;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1739
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1740 printf "* Entering %s\n", ($this->name || $this) if $Debug;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1741 $callback_status = &{ $callback }( $this, $o ) if $callback;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1742
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1743 if($callback_status) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1744 # Keep recursing unless callback returned false... and if there's
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1745 # anything to recurse into, of course.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1746 my @daughters = UNIVERSAL::can($this, 'is_node') ? @{$this->{'daughters'}} : ();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1747 if(@daughters) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1748 $o->{'_depth'} += 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1749 #print "Depth " , $o->{'_depth'}, "\n";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1750 foreach my $one (@daughters) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1751 $one->walk_down($o) if UNIVERSAL::can($one, 'is_node');
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1752 # and if it can do "is_node", it should provide a walk_down!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1753 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1754 $o->{'_depth'} -= 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1755 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1756 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1757 printf "* Recursing below %s pruned\n", ($this->name || $this) if $Debug;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1758 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1759
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1760 # Note that $callback_status doesn't block callbackback from being called
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1761 if($callbackback){
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1762 if(UNIVERSAL::can($this, 'is_node')) { # if it's still a node!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1763 print "* Calling callbackback\n" if $Debug;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1764 scalar( &{ $callbackback }( $this, $o ) );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1765 # scalar to give it the same context as callback
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1766 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1767 print "* Can't call callbackback -- $this isn't a node anymore\n"
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1768 if $Debug;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1769 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1770 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1771 if($Debug) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1772 if(UNIVERSAL::can($this, 'is_node')) { # if it's still a node!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1773 printf "* Leaving %s\n", ($this->name || $this)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1774 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1775 print "* Leaving [no longer a node]\n";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1776 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1777 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1778 return;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1779 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1780
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1781 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1782
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1783 =item @lines = $node->dump_names({ ...options... });
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1784
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1785 Dumps, as an indented list, the names of the nodes starting at $node,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1786 and continuing under it. Options are:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1787
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1788 * _depth -- A nonnegative number. Indicating the depth to consider
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1789 $node as being at (and so the generation under that is that plus one,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1790 etc.). Defaults to 0. You may choose to use set _depth =>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1791 scalar($node->ancestors).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1792
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1793 * tick -- a string to preface each entry with, between the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1794 indenting-spacing and the node's name. Defaults to empty-string. You
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1795 may prefer "*" or "-> " or someting.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1796
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1797 * indent -- the string used to indent with. Defaults to " " (two
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1798 spaces). Another sane value might be ". " (period, space). Setting it
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1799 to empty-string suppresses indenting.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1800
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1801 The dump is not printed, but is returned as a list, where each
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1802 item is a line, with a "\n" at the end.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1803
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1804 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1805
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1806 sub dump_names {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1807 my($it, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1808 $o = {} unless ref $o;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1809 my @out = ();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1810 $o->{'_depth'} ||= 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1811 $o->{'indent'} ||= ' ';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1812 $o->{'tick'} ||= '';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1813
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1814 $o->{'callback'} = sub {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1815 my($this, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1816 push(@out,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1817 join('',
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1818 $o->{'indent'} x $o->{'_depth'},
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1819 $o->{'tick'},
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1820 &Tree::DAG_Node::_dump_quote($this->name || $this),
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1821 "\n"
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1822 )
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1823 );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1824 return 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1825 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1826 ;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1827 $it->walk_down($o);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1828 return @out;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1829 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1830
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1831 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1832 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1833
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1834 =item the constructor CLASS->random_network({...options...})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1835
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1836 =item the method $node->random_network({...options...})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1837
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1838 In the first case, constructs a randomly arranged network under a new
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1839 node, and returns the root node of that tree. In the latter case,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1840 constructs the network under $node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1841
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1842 Currently, this is implemented a bit half-heartedly, and
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1843 half-wittedly. I basically needed to make up random-looking networks
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1844 to stress-test the various tree-dumper methods, and so wrote this. If
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1845 you actually want to rely on this for any application more
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1846 serious than that, I suggest examining the source code and seeing if
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1847 this does really what you need (say, in reliability of randomness);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1848 and feel totally free to suggest changes to me (especially in the form
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1849 of "I rewrote C<random_network>, here's the code...")
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1850
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1851 It takes four options:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1852
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1853 * max_node_count -- maximum number of nodes this tree will be allowed
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1854 to have (counting the root). Defaults to 25.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1855
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1856 * min_depth -- minimum depth for the tree. Defaults to 2. Leaves can
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1857 be generated only after this depth is reached, so the tree will be at
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1858 least this deep -- unless max_node_count is hit first.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1859
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1860 * max_depth -- maximum depth for the tree. Defaults to 3 plus
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1861 min_depth. The tree will not be deeper than this.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1862
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1863 * max_children -- maximum number of children any mother in the tree
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1864 can have. Defaults to 4.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1865
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1866 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1867
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1868 sub random_network { # constructor or method.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1869 my $class = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1870 my $o = ref($_[1]) ? $_[1] : {};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1871 my $am_cons = 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1872 my $root;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1873
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1874 if(ref($class)){ # I'm a method.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1875 $root = $_[0]; # build under the given node, from same class.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1876 $class = ref $class;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1877 $am_cons = 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1878 } else { # I'm a constructor
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1879 $root = $class->new; # build under a new node, with class named.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1880 $root->name("Root");
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1881 $am_cons = 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1882 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1883
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1884 my $min_depth = $o->{'min_depth'} || 2;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1885 my $max_depth = $o->{'max_depth'} || ($min_depth + 3);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1886 my $max_children = $o->{'max_children'} || 4;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1887 my $max_node_count = $o->{'max_node_count'} || 25;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1888
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1889 Carp::croak "max_children has to be positive" if int($max_children) < 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1890
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1891 my @mothers = ( $root );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1892 my @children = ( );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1893 my $node_count = 1; # the root
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1894
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1895 Gen:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1896 foreach my $depth (1 .. $max_depth) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1897 last if $node_count > $max_node_count;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1898 Mother:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1899 foreach my $mother (@mothers) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1900 last Gen if $node_count > $max_node_count;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1901 my $children_number;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1902 if($depth <= $min_depth) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1903 until( $children_number = int(rand(1 + $max_children)) ) {}
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1904 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1905 $children_number = int(rand($max_children));
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1906 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1907 Beget:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1908 foreach (1 .. $children_number) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1909 last Gen if $node_count > $max_node_count;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1910 my $node = $mother->new_daughter;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1911 $node->name("Node$node_count");
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1912 ++$node_count;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1913 push(@children, $node);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1914 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1915 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1916 @mothers = @children;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1917 @children = ();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1918 last unless @mothers;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1919 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1920
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1921 return $root;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1922 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1923
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1924 =item the constructor CLASS->lol_to_tree($lol);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1925
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1926 Converts something like bracket-notation for "Chomsky trees" (or
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1927 rather, the closest you can come with Perl
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1928 list-of-lists(-of-lists(-of-lists))) into a tree structure. Returns
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1929 the root of the tree converted.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1930
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1931 The conversion rules are that: 1) if the last (possibly the only) item
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1932 in a given list is a scalar, then that is used as the "name" attribute
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1933 for the node based on this list. 2) All other items in the list
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1934 represent daughter nodes of the current node -- recursively so, if
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1935 they are list references; otherwise, (non-terminal) scalars are
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1936 considered to denote nodes with that name. So ['Foo', 'Bar', 'N'] is
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1937 an alternate way to represent [['Foo'], ['Bar'], 'N'].
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1938
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1939 An example will illustrate:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1940
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1941 use Tree::DAG_Node;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1942 $lol =
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1943 [
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1944 [
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1945 [ [ 'Det:The' ],
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1946 [ [ 'dog' ], 'N'], 'NP'],
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1947 [ '/with rabies\\', 'PP'],
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1948 'NP'
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1949 ],
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1950 [ 'died', 'VP'],
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1951 'S'
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1952 ];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1953 $tree = Tree::DAG_Node->lol_to_tree($lol);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1954 $diagram = $tree->draw_ascii_tree;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1955 print map "$_\n", @$diagram;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1956
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1957 ...returns this tree:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1958
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1959 |
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1960 <S>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1961 |
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1962 /------------------\
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1963 | |
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1964 <NP> <VP>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1965 | |
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1966 /---------------\ <died>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1967 | |
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1968 <NP> <PP>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1969 | |
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1970 /-------\ </with rabies\>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1971 | |
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1972 <Det:The> <N>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1973 |
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1974 <dog>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1975
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1976 By the way (and this rather follows from the above rules), when
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1977 denoting a LoL tree consisting of just one node, this:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1978
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1979 $tree = Tree::DAG_Node->lol_to_tree( 'Lonely' );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1980
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1981 is okay, although it'd probably occur to you to denote it only as:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1982
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1983 $tree = Tree::DAG_Node->lol_to_tree( ['Lonely'] );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1984
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1985 which is of course fine, too.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1986
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1987 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1988
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1989 sub lol_to_tree {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1990 my($class, $lol, $seen_r) = @_[0,1,2];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1991 $seen_r = {} unless ref($seen_r) eq 'HASH';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1992 return if ref($lol) && $seen_r->{$lol}++; # catch circularity
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1993
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1994 $class = ref($class) || $class;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1995 my $node = $class->new();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1996
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1997 unless(ref($lol) eq 'ARRAY') { # It's a terminal node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1998 $node->name($lol) if defined $lol;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
1999 return $node;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2000 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2001 return $node unless @$lol; # It's a terminal node, oddly represented
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2002
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2003 # It's a non-terminal node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2004
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2005 my @options = @$lol;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2006 unless(ref($options[-1]) eq 'ARRAY') {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2007 # This is what separates this method from simple_lol_to_tree
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2008 $node->name(pop(@options));
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2009 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2010
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2011 foreach my $d (@options) { # Scan daughters (whether scalars or listrefs)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2012 $node->add_daughter( $class->lol_to_tree($d, $seen_r) ); # recurse!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2013 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2014
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2015 return $node;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2016 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2017
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2018 #--------------------------------------------------------------------------
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2019
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2020 =item $node->tree_to_lol_notation({...options...})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2021
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2022 Dumps a tree (starting at $node) as the sort of LoL-like bracket
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2023 notation you see in the above example code. Returns just one big
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2024 block of text. The only option is "multiline" -- if true, it dumps
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2025 the text as the sort of indented structure as seen above; if false
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2026 (and it defaults to false), dumps it all on one line (with no
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2027 indenting, of course).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2028
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2029 For example, starting with the tree from the above example,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2030 this:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2031
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2032 print $tree->tree_to_lol_notation, "\n";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2033
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2034 prints the following (which I've broken over two lines for sake of
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2035 printablitity of documentation):
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2036
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2037 [[[['Det:The'], [['dog'], 'N'], 'NP'], [["/with rabies\x5c"],
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2038 'PP'], 'NP'], [['died'], 'VP'], 'S'],
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2039
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2040 Doing this:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2041
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2042 print $tree->tree_to_lol_notation({ multiline => 1 });
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2043
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2044 prints the same content, just spread over many lines, and prettily
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2045 indented.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2046
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2047 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2048
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2049 #--------------------------------------------------------------------------
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2050
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2051 sub tree_to_lol_notation {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2052 my $root = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2053 my($it, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2054 $o = {} unless ref $o;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2055 my @out = ();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2056 $o->{'_depth'} ||= 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2057 $o->{'multiline'} = 0 unless exists($o->{'multiline'});
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2058
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2059 my $line_end;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2060 if($o->{'multiline'}) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2061 $o->{'indent'} ||= ' ';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2062 $line_end = "\n";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2063 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2064 $o->{'indent'} ||= '';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2065 $line_end = '';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2066 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2067
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2068 $o->{'callback'} = sub {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2069 my($this, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2070 push(@out,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2071 $o->{'indent'} x $o->{'_depth'},
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2072 "[$line_end",
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2073 );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2074 return 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2075 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2076 ;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2077 $o->{'callbackback'} = sub {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2078 my($this, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2079 my $name = $this->name;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2080 if(!defined($name)) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2081 $name = 'undef';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2082 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2083 $name = &Tree::DAG_Node::_dump_quote($name);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2084 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2085 push(@out,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2086 $o->{'indent'} x ($o->{'_depth'} + 1),
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2087 "$name$line_end",
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2088 $o->{'indent'} x $o->{'_depth'},
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2089 "], $line_end",
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2090 );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2091 return 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2092 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2093 ;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2094 $it->walk_down($o);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2095 return join('', @out);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2096 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2097
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2098 #--------------------------------------------------------------------------
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2099
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2100 =item $node->tree_to_lol
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2101
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2102 Returns that tree (starting at $node) represented as a LoL, like what
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2103 $lol, above, holds. (This is as opposed to C<tree_to_lol_notation>,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2104 which returns the viewable code like what gets evaluated and stored in
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2105 $lol, above.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2106
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2107 Lord only knows what you use this for -- maybe for feeding to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2108 Data::Dumper, in case C<tree_to_lol_notation> doesn't do just what you
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2109 want?
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2110
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2111 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2112
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2113 sub tree_to_lol {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2114 # I haven't /rigorously/ tested this.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2115 my($it, $o) = @_[0,1]; # $o is currently unused anyway
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2116 $o = {} unless ref $o;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2117
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2118 my $out = [];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2119 my @lol_stack = ($out);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2120 $o->{'callback'} = sub {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2121 my($this, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2122 my $new = [];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2123 push @{$lol_stack[-1]}, $new;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2124 push(@lol_stack, $new);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2125 return 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2126 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2127 ;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2128 $o->{'callbackback'} = sub {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2129 my($this, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2130 push @{$lol_stack[-1]}, $this->name;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2131 pop @lol_stack;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2132 return 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2133 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2134 ;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2135 $it->walk_down($o);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2136 die "totally bizarre error 12416" unless ref($out->[0]);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2137 $out = $out->[0]; # the real root
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2138 return $out;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2139 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2140
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2141 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2142
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2143 =item the constructor CLASS->simple_lol_to_tree($simple_lol);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2144
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2145 This is like lol_to_tree, except that rule 1 doesn't apply -- i.e.,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2146 all scalars (or really, anything not a listref) in the LoL-structure
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2147 end up as named terminal nodes, and only terminal nodes get names
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2148 (and, of course, that name comes from that scalar value). This method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2149 is useful for making things like expression trees, or at least
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2150 starting them off. Consider that this:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2151
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2152 $tree = Tree::DAG_Node->simple_lol_to_tree(
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2153 [ 'foo', ['bar', ['baz'], 'quux'], 'zaz', 'pati' ]
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2154 );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2155
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2156 converts from something like a Lispish or Iconish tree, if you pretend
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2157 the brackets are parentheses.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2158
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2159 Note that there is a (possibly surprising) degenerate case of what I'm
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2160 calling a "simple-LoL", and it's like this:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2161
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2162 $tree = Tree::DAG_Node->simple_lol_to_tree('Lonely');
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2163
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2164 This is the (only) way you can specify a tree consisting of only a
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2165 single node, which here gets the name 'Lonely'.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2166
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2167 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2168
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2169 sub simple_lol_to_tree {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2170 my($class, $lol, $seen_r) = @_[0,1,2];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2171 $class = ref($class) || $class;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2172 $seen_r = {} unless ref($seen_r) eq 'HASH';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2173 return if ref($lol) && $seen_r->{$lol}++; # catch circularity
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2174
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2175 my $node = $class->new();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2176
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2177 unless(ref($lol) eq 'ARRAY') { # It's a terminal node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2178 $node->name($lol) if defined $lol;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2179 return $node;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2180 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2181
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2182 # It's a non-terminal node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2183 foreach my $d (@$lol) { # scan daughters (whether scalars or listrefs)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2184 $node->add_daughter( $class->simple_lol_to_tree($d, $seen_r) ); # recurse!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2185 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2186
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2187 return $node;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2188 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2189
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2190 #--------------------------------------------------------------------------
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2191
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2192 =item $node->tree_to_simple_lol
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2193
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2194 Returns that tree (starting at $node) represented as a simple-LoL --
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2195 i.e., one where non-terminal nodes are represented as listrefs, and
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2196 terminal nodes are gotten from the contents of those nodes' "name'
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2197 attributes.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2198
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2199 Note that in the case of $node being terminal, what you get back is
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2200 the same as $node->name.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2201
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2202 Compare to tree_to_simple_lol_notation.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2203
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2204 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2205
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2206 sub tree_to_simple_lol {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2207 # I haven't /rigorously/ tested this.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2208 my $root = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2209
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2210 return $root->name unless scalar($root->daughters);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2211 # special case we have to nip in the bud
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2212
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2213 my($it, $o) = @_[0,1]; # $o is currently unused anyway
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2214 $o = {} unless ref $o;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2215
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2216 my $out = [];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2217 my @lol_stack = ($out);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2218 $o->{'callback'} = sub {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2219 my($this, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2220 my $new;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2221 $new = scalar($this->daughters) ? [] : $this->name;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2222 # Terminal nodes are scalars, the rest are listrefs we'll fill in
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2223 # as we recurse the tree below here.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2224 push @{$lol_stack[-1]}, $new;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2225 push(@lol_stack, $new);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2226 return 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2227 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2228 ;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2229 $o->{'callbackback'} = sub { pop @lol_stack; return 1; };
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2230 $it->walk_down($o);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2231 die "totally bizarre error 12416" unless ref($out->[0]);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2232 $out = $out->[0]; # the real root
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2233 return $out;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2234 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2235
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2236 #--------------------------------------------------------------------------
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2237
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2238 =item $node->tree_to_simple_lol_notation({...options...})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2239
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2240 A simple-LoL version of tree_to_lol_notation (which see); takes the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2241 same options.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2242
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2243 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2244
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2245 sub tree_to_simple_lol_notation {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2246 my($it, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2247 $o = {} unless ref $o;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2248 my @out = ();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2249 $o->{'_depth'} ||= 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2250 $o->{'multiline'} = 0 unless exists($o->{'multiline'});
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2251
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2252 my $line_end;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2253 if($o->{'multiline'}) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2254 $o->{'indent'} ||= ' ';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2255 $line_end = "\n";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2256 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2257 $o->{'indent'} ||= '';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2258 $line_end = '';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2259 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2260
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2261 $o->{'callback'} = sub {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2262 my($this, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2263 if(scalar($this->daughters)) { # Nonterminal
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2264 push(@out,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2265 $o->{'indent'} x $o->{'_depth'},
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2266 "[$line_end",
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2267 );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2268 } else { # Terminal
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2269 my $name = $this->name;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2270 push @out,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2271 $o->{'indent'} x $o->{'_depth'},
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2272 defined($name) ? &Tree::DAG_Node::_dump_quote($name) : 'undef',
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2273 ",$line_end";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2274 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2275 return 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2276 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2277 ;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2278 $o->{'callbackback'} = sub {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2279 my($this, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2280 push(@out,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2281 $o->{'indent'} x $o->{'_depth'},
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2282 "], $line_end",
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2283 ) if scalar($this->daughters);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2284 return 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2285 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2286 ;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2287
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2288 $it->walk_down($o);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2289 return join('', @out);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2290 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2291
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2292 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2293 # $list_r = $root_node->draw_ascii_tree({ h_compact => 1});
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2294 # print map("$_\n", @$list_r);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2295
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2296 =item $list_r = $node->draw_ascii_tree({ ... options ... })
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2297
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2298 Draws a nice ASCII-art representation of the tree structure
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2299 at-and-under $node, with $node at the top. Returns a reference to the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2300 list of lines (with no "\n"s or anything at the end of them) that make
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2301 up the picture.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2302
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2303 Example usage:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2304
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2305 print map("$_\n", @{$tree->draw_ascii_tree});
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2306
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2307 draw_ascii_tree takes parameters you set in the options hashref:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2308
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2309 * "no_name" -- if true, C<draw_ascii_tree> doesn't print the name of
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2310 the node; simply prints a "*". Defaults to 0 (i.e., print the node
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2311 name.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2312
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2313 * "h_spacing" -- number 0 or greater. Sets the number of spaces
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2314 inserted horizontally between nodes (and groups of nodes) in a tree.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2315 Defaults to 1.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2316
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2317 * "h_compact" -- number 0 or 1. Sets the extent to which
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2318 C<draw_ascii_tree> tries to save horizontal space. Defaults to 1. If
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2319 I think of a better scrunching algorithm, there'll be a "2" setting
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2320 for this.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2321
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2322 * "v_compact" -- number 0, 1, or 2. Sets the degree to which
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2323 C<draw_ascii_tree> tries to save vertical space. Defaults to 1.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2324
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2325 This occasionally returns trees that are a bit cock-eyed in parts; if
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2326 anyone can suggest a better drawing algorithm, I'd be appreciative.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2327
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2328 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2329
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2330 sub draw_ascii_tree {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2331 # Make a "box" for this node and its possible daughters, recursively.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2332
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2333 # The guts of this routine are horrific AND recursive!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2334
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2335 # Feel free to send me better code. I worked on this until it
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2336 # gave me a headache and it worked passably, and then I stopped.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2337
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2338 my $it = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2339 my $o = ref($_[1]) ? $_[1] : {};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2340 my(@box, @daughter_boxes, $width, @daughters);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2341 @daughters = @{$it->{'daughters'}};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2342
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2343 # $it->no_cyclicity;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2344
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2345 $o->{'no_name'} = 0 unless exists $o->{'no_name'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2346 $o->{'h_spacing'} = 1 unless exists $o->{'h_spacing'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2347 $o->{'h_compact'} = 1 unless exists $o->{'h_compact'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2348 $o->{'v_compact'} = 1 unless exists $o->{'v_compact'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2349
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2350 my $printable_name;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2351 if($o->{'no_name'}) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2352 $printable_name = '*';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2353 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2354 $printable_name = $it->name || $it;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2355 $printable_name =~ tr<\cm\cj\t >< >s;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2356 $printable_name = "<$printable_name>";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2357 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2358
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2359 if(!scalar(@daughters)) { # I am a leaf!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2360 # Now add the top parts, and return.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2361 @box = ("|", $printable_name);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2362 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2363 @daughter_boxes = map { &draw_ascii_tree($_, $o) } @daughters;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2364
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2365 my $max_height = 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2366 foreach my $box (@daughter_boxes) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2367 my $h = @$box;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2368 $max_height = $h if $h > $max_height;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2369 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2370
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2371 @box = ('') x $max_height; # establish the list
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2372
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2373 foreach my $one (@daughter_boxes) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2374 my $length = length($one->[0]);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2375 my $height = @$one;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2376
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2377 #now make all the same height.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2378 my $deficit = $max_height - $height;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2379 if($deficit > 0) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2380 push @$one, ( scalar( ' ' x $length ) ) x $deficit;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2381 $height = scalar(@$one);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2382 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2383
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2384
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2385 # Now tack 'em onto @box
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2386 ##########################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2387 # This used to be a sub of its own. Ho-hum.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2388
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2389 my($b1, $b2) = (\@box, $one);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2390 my($h1, $h2) = (scalar(@$b1), scalar(@$b2));
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2391
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2392 my(@diffs, $to_chop);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2393 if($o->{'h_compact'}) { # Try for h-scrunching.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2394 my @diffs;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2395 my $min_diff = length($b1->[0]); # just for starters
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2396 foreach my $line (0 .. ($h1 - 1)) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2397 my $size_l = 0; # length of terminal whitespace
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2398 my $size_r = 0; # length of initial whitespace
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2399 $size_l = length($1) if $b1->[$line] =~ /( +)$/s;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2400 $size_r = length($1) if $b2->[$line] =~ /^( +)/s;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2401 my $sum = $size_l + $size_r;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2402
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2403 $min_diff = $sum if $sum < $min_diff;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2404 push @diffs, [$sum, $size_l, $size_r];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2405 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2406 $to_chop = $min_diff - $o->{'h_spacing'};
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2407 $to_chop = 0 if $to_chop < 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2408 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2409
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2410 if(not( $o->{'h_compact'} and $to_chop )) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2411 # No H-scrunching needed/possible
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2412 foreach my $line (0 .. ($h1 - 1)) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2413 $b1->[ $line ] .= $b2->[ $line ] . (' ' x $o->{'h_spacing'});
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2414 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2415 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2416 # H-scrunching is called for.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2417 foreach my $line (0 .. ($h1 - 1)) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2418 my $r = $b2->[$line]; # will be the new line
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2419 my $remaining = $to_chop;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2420 if($remaining) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2421 my($l_chop, $r_chop) = @{$diffs[$line]}[1,2];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2422
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2423 if($l_chop) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2424 if($l_chop > $remaining) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2425 $l_chop = $remaining;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2426 $remaining = 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2427 } elsif($l_chop == $remaining) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2428 $remaining = 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2429 } else { # remaining > l_chop
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2430 $remaining -= $l_chop;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2431 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2432 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2433 if($r_chop) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2434 if($r_chop > $remaining) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2435 $r_chop = $remaining;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2436 $remaining = 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2437 } elsif($r_chop == $remaining) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2438 $remaining = 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2439 } else { # remaining > r_chop
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2440 $remaining -= $r_chop; # should never happen!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2441 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2442 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2443
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2444 substr($b1->[$line], -$l_chop) = '' if $l_chop;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2445 substr($r, 0, $r_chop) = '' if $r_chop;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2446 } # else no-op
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2447 $b1->[ $line ] .= $r . (' ' x $o->{'h_spacing'});
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2448 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2449 # End of H-scrunching ickyness
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2450 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2451 # End of ye big tack-on
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2452
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2453 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2454 # End of the foreach daughter_box loop
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2455
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2456 # remove any fencepost h_spacing
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2457 if($o->{'h_spacing'}) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2458 foreach my $line (@box) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2459 substr($line, -$o->{'h_spacing'}) = '' if length($line);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2460 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2461 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2462
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2463 # end of catenation
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2464 die "SPORK ERROR 958203: Freak!!!!!" unless @box;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2465
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2466 # Now tweak the pipes
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2467 my $new_pipes = $box[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2468 my $pipe_count = $new_pipes =~ tr<|><+>;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2469 if($pipe_count < 2) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2470 $new_pipes = "|";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2471 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2472 my($init_space, $end_space);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2473
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2474 # Thanks to Gilles Lamiral for pointing out the need to set to '',
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2475 # to avoid -w warnings about undeffiness.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2476
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2477 if( $new_pipes =~ s<^( +)><>s ) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2478 $init_space = $1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2479 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2480 $init_space = '';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2481 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2482
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2483 if( $new_pipes =~ s<( +)$><>s ) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2484 $end_space = $1
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2485 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2486 $end_space = '';
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2487 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2488
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2489 $new_pipes =~ tr< ><->;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2490 substr($new_pipes,0,1) = "/";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2491 substr($new_pipes,-1,1) = "\\";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2492
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2493 $new_pipes = $init_space . $new_pipes . $end_space;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2494 # substr($new_pipes, int((length($new_pipes)), 1)) / 2) = "^"; # feh
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2495 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2496
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2497 # Now tack on the formatting for this node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2498 if($o->{'v_compact'} == 2) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2499 if(@daughters == 1) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2500 unshift @box, "|", $printable_name;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2501 } else {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2502 unshift @box, "|", $printable_name, $new_pipes;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2503 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2504 } elsif ($o->{'v_compact'} == 1 and @daughters == 1) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2505 unshift @box, "|", $printable_name;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2506 } else { # general case
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2507 unshift @box, "|", $printable_name, $new_pipes;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2508 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2509 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2510
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2511 # Flush the edges:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2512 my $max_width = 0;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2513 foreach my $line (@box) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2514 my $w = length($line);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2515 $max_width = $w if $w > $max_width;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2516 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2517 foreach my $one (@box) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2518 my $space_to_add = $max_width - length($one);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2519 next unless $space_to_add;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2520 my $add_left = int($space_to_add / 2);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2521 my $add_right = $space_to_add - $add_left;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2522 $one = (' ' x $add_left) . $one . (' ' x $add_right);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2523 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2524
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2525 return \@box; # must not return a null list!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2526 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2527
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2528 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2529
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2530 =item $node->copy_tree or $node->copy_tree({...options...})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2531
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2532 This returns the root of a copy of the tree that $node is a member of.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2533 If you pass no options, copy_tree pretends you've passed {}.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2534
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2535 This method is currently implemented as just a call to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2536 $this->root->copy_at_and_under({...options...}), but magic may be
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2537 added in the future.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2538
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2539 Options you specify are passed down to calls to $node->copy.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2540
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2541 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2542
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2543 sub copy_tree {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2544 my($this, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2545 my $root = $this->root;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2546 $o = {} unless ref $o;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2547
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2548 my $new_root = $root->copy_at_and_under($o);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2549
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2550 return $new_root;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2551 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2552
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2553 =item $node->copy_at_and_under or $node->copy_at_and_under({...options...})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2554
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2555 This returns a copy of the subtree consisting of $node and everything
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2556 under it.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2557
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2558 If you pass no options, copy_at_and_under pretends you've passed {}.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2559
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2560 This works by recursively building up the new tree from the leaves,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2561 duplicating nodes using $orig_node->copy($options_ref) and then
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2562 linking them up into a new tree of the same shape.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2563
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2564 Options you specify are passed down to calls to $node->copy.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2565
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2566 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2567
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2568 sub copy_at_and_under {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2569 my($from, $o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2570 $o = {} unless ref $o;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2571 my @daughters = map($_->copy_at_and_under($o), @{$from->{'daughters'}});
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2572 my $to = $from->copy($o);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2573 $to->set_daughters(@daughters) if @daughters;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2574 return $to;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2575 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2576
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2577 =item the constructor $node->copy or $node->copy({...options...})
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2578
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2579 Returns a copy of $node, B<minus> its daughter or mother attributes
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2580 (which are set back to default values).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2581
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2582 If you pass no options, C<copy> pretends you've passed {}.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2583
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2584 Magic happens with the 'attributes' attribute: if it's a hashref (and
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2585 it usually is), the new node doesn't end up with the same hashref, but
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2586 with ref to a hash with the content duplicated from the original's
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2587 hashref. If 'attributes' is not a hashref, but instead an object that
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2588 belongs to a class that provides a method called "copy", then that
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2589 method is called, and the result saved in the clone's 'attribute'
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2590 attribute. Both of these kinds of magic are disabled if the options
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2591 you pass to C<copy> (maybe via C<copy_tree>, or C<copy_at_and_under>)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2592 includes (C<no_attribute_copy> => 1).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2593
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2594 The options hashref you pass to C<copy> (derictly or indirectly) gets
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2595 changed slightly after you call C<copy> -- it gets an entry called
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2596 "from_to" added to it. Chances are you would never know nor care, but
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2597 this is reserved for possible future use. See the source if you are
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2598 wildly curious.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2599
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2600 Note that if you are using $node->copy (whether directly or via
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2601 $node->copy_tree or $node->copy_at_or_under), and it's not properly
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2602 copying object attributes containing references, you probably
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2603 shouldn't fight it or try to fix it -- simply override copy_tree with:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2604
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2605 sub copy_tree {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2606 use Storable qw(dclone);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2607 my $this = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2608 return dclone($this->root);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2609 # d for "deep"
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2610 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2611
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2612 or
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2613
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2614 sub copy_tree {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2615 use Data::Dumper;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2616 my $this = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2617 $Data::Dumper::Purity = 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2618 return eval(Dumper($this->root));
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2619 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2620
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2621 Both of these avoid you having to reinvent the wheel.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2622
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2623 How to override copy_at_or_under with something that uses Storable
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2624 or Data::Dumper is left as an exercise to the reader.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2625
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2626 Consider that if in a derived class, you add attributes with really
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2627 bizarre contents (like a unique-for-all-time-ID), you may need to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2628 override C<copy>. Consider:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2629
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2630 sub copy {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2631 my($it, @etc) = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2632 $it->SUPER::copy(@etc);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2633 $it->{'UID'} = &get_new_UID;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2634 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2635
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2636 ...or the like. See the source of Tree::DAG_Node::copy for
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2637 inspiration.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2638
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2639 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2640
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2641 sub copy {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2642 my($from,$o) = @_[0,1];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2643 $o = {} unless ref $o;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2644
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2645 # Straight dupe, and bless into same class:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2646 my $to = bless { %$from }, ref($from);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2647
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2648 # Null out linkages.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2649 $to->_init_mother;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2650 $to->_init_daughters;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2651
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2652 # dupe the 'attributes' attribute:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2653 unless($o->{'no_attribute_copy'}) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2654 my $attrib_copy = ref($to->{'attributes'});
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2655 if($attrib_copy) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2656 if($attrib_copy eq 'HASH') {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2657 $to->{'attributes'} = { %{$to->{'attributes'}} };
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2658 # dupe the hashref
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2659 } elsif ($attrib_copy = UNIVERSAL::can($to->{'attributes'}, 'copy') ) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2660 # $attrib_copy now points to the copier method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2661 $to->{'attributes'} = &{$attrib_copy}($from);
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2662 } # otherwise I don't know how to copy it; leave as is
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2663 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2664 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2665 $o->{'from_to'}->{$from} = $to; # SECRET VOODOO
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2666 # ...autovivifies an anon hashref for 'from_to' if need be
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2667 # This is here in case I later want/need a table corresponding
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2668 # old nodes to new.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2669 return $to;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2670 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2671
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2672
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2673 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2674
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2675 =item $node->delete_tree
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2676
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2677 Destroys the entire tree that $node is a member of (starting at the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2678 root), by nulling out each node-object's attributes (including, most
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2679 importantly, its linkage attributes -- hopefully this is more than
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2680 sufficient to eliminate all circularity in the data structure), and
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2681 then moving it into the class DEADNODE.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2682
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2683 Use this when you're finished with the tree in question, and want to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2684 free up its memory. (If you don't do this, it'll get freed up anyway
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2685 when your program ends.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2686
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2687 If you try calling any methods on any of the node objects in the tree
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2688 you've destroyed, you'll get an error like:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2689
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2690 Can't locate object method "leaves_under"
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2691 via package "DEADNODE".
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2692
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2693 So if you see that, that's what you've done wrong. (Actually, the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2694 class DEADNODE does provide one method: a no-op method "delete_tree".
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2695 So if you want to delete a tree, but think you may have deleted it
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2696 already, it's safe to call $node->delete_tree on it (again).)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2697
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2698 The C<delete_tree> method is needed because Perl's garbage collector
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2699 would never (as currently implemented) see that it was time to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2700 de-allocate the memory the tree uses -- until either you call
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2701 $node->delete_tree, or until the program stops (at "global
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2702 destruction" time, when B<everything> is unallocated).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2703
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2704 Incidentally, there are better ways to do garbage-collecting on a
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2705 tree, ways which don't require the user to explicitly call a method
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2706 like C<delete_tree> -- they involve dummy classes, as explained at
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2707 C<http://mox.perl.com/misc/circle-destroy.pod>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2708
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2709 However, introducing a dummy class concept into Tree::DAG_Node would
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2710 be rather a distraction. If you want to do this with your derived
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2711 classes, via a DESTROY in a dummy class (or in a tree-metainformation
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2712 class, maybe), then feel free to.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2713
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2714 The only case where I can imagine C<delete_tree> failing to totally
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2715 void the tree, is if you use the hashref in the "attributes" attribute
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2716 to store (presumably among other things) references to other nodes'
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2717 "attributes" hashrefs -- which 1) is maybe a bit odd, and 2) is your
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2718 problem, because it's your hash structure that's circular, not the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2719 tree's. Anyway, consider:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2720
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2721 # null out all my "attributes" hashes
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2722 $anywhere->root->walk_down({
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2723 'callback' => sub {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2724 $hr = $_[0]->attributes; %$hr = (); return 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2725 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2726 });
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2727 # And then:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2728 $anywhere->delete_tree;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2729
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2730 (I suppose C<delete_tree> is a "destructor", or as close as you can
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2731 meaningfully come for a circularity-rich data structure in Perl.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2732
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2733 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2734
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2735 sub delete_tree {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2736 my $it = $_[0];
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2737 $it->root->walk_down({ # has to be callbackback, not callback
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2738 'callbackback' => sub {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2739 %{$_[0]} = ();
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2740 bless($_[0], 'DEADNODE'); # cause become dead! cause become dead!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2741 return 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2742 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2743 });
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2744 return;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2745 # Why DEADNODE? Because of the nice error message:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2746 # "Can't locate object method "leaves_under" via package "DEADNODE"."
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2747 # Moreover, DEADNODE doesn't provide is_node, so fails my can() tests.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2748 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2749
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2750 sub DEADNODE::delete_tree { return; }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2751 # in case you kill it AGAIN!!!!! AND AGAIN AND AGAIN!!!!!! OO-HAHAHAHA!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2752
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2753 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2754 # stolen from MIDI.pm
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2755
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2756 sub _dump_quote {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2757 my @stuff = @_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2758 return
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2759 join(", ",
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2760 map
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2761 { # the cleaner-upper function
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2762 if(!length($_)) { # empty string
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2763 "''";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2764 } elsif( m/^-?\d+(?:\.\d+)?$/s ) { # a number
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2765 $_;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2766 } elsif( # text with junk in it
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2767 s<([^\x20\x21\x23\x27-\x3F\x41-\x5B\x5D-\x7E])>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2768 <'\\x'.(unpack("H2",$1))>eg
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2769 ) {
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2770 "\"$_\"";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2771 } else { # text with no junk in it
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2772 s<'><\\'>g;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2773 "\'$_\'";
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2774 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2775 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2776 @stuff
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2777 );
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2778 }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2779
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2780 ###########################################################################
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2781
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2782 =back
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2783
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2784 =head2 When and How to Destroy
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2785
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2786 It should be clear to you that if you've built a big parse tree or
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2787 something, and then you're finished with it, you should call
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2788 $some_node->delete_tree on it if you want the memory back.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2789
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2790 But consider this case: you've got this tree:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2791
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2792 A
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2793 / | \
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2794 B C D
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2795 | | \
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2796 E X Y
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2797
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2798 Let's say you decide you don't want D or any of its descendants in the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2799 tree, so you call D->unlink_from_mother. This does NOT automagically
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2800 destroy the tree D-X-Y. Instead it merely splits the tree into two:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2801
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2802 A D
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2803 / \ / \
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2804 B C X Y
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2805 |
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2806 E
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2807
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2808 To destroy D and its little tree, you have to explicitly call
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2809 delete_tree on it.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2810
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2811 Note, however, that if you call C->unlink_from_mother, and if you don't
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2812 have a link to C anywhere, then it B<does> magically go away. This is
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2813 because nothing links to C -- whereas with the D-X-Y tree, D links to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2814 X and Y, and X and Y each link back to D. Note that calling
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2815 C->delete_tree is harmless -- after all, a tree of only one node is
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2816 still a tree.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2817
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2818 So, this is a surefire way of getting rid of all $node's children and
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2819 freeing up the memory associated with them and their descendants:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2820
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2821 foreach my $it ($node->clear_daughters) { $it->delete_tree }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2822
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2823 Just be sure not to do this:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2824
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2825 foreach my $it ($node->daughters) { $it->delete_tree }
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2826 $node->clear_daughters;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2827
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2828 That's bad; the first call to $_->delete_tree will climb to the root
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2829 of $node's tree, and nuke the whole tree, not just the bits under $node.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2830 You might as well have just called $node->delete_tree.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2831 (Moreavor, once $node is dead, you can't call clear_daughters on it,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2832 so you'll get an error there.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2833
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2834 =head1 BUG REPORTS
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2835
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2836 If you find a bug in this library, report it to me as soon as possible,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2837 at the address listed in the MAINTAINER section, below. Please try to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2838 be as specific as possible about how you got the bug to occur.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2839
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2840 =head1 HELP!
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2841
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2842 If you develop a given routine for dealing with trees in some way, and
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2843 use it a lot, then if you think it'd be of use to anyone else, do email
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2844 me about it; it might be helpful to others to include that routine, or
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2845 something based on it, in a later version of this module.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2846
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2847 It's occurred to me that you might like to (and might yourself develop
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2848 routines to) draw trees in something other than ASCII art. If you do so
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2849 -- say, for PostScript output, or for output interpretable by some
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2850 external plotting program -- I'd be most interested in the results.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2851
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2852 =head1 RAMBLINGS
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2853
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2854 This module uses "strict", but I never wrote it with -w warnings in
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2855 mind -- so if you use -w, do not be surprised if you see complaints
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2856 from the guts of DAG_Node. As long as there is no way to turn off -w
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2857 for a given module (instead of having to do it in every single
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2858 subroutine with a "local $^W"), I'm not going to change this. However,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2859 I do, at points, get bursts of ambition, and I try to fix code in
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2860 DAG_Node that generates warnings, I<as I come across them> -- which is
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2861 only occasionally. Feel free to email me any patches for any such
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2862 fixes you come up with, tho.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2863
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2864 Currently I don't assume (or enforce) anything about the class
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2865 membership of nodes being manipulated, other than by testing whether
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2866 each one provides a method C<is_node>, a la:
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2867
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2868 die "Not a node!!!" unless UNIVERSAL::can($node, "is_node");
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2869
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2870 So, as far as I'm concerned, a given tree's nodes are free to belong to
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2871 different classes, just so long as they provide/inherit C<is_node>, the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2872 few methods that this class relies on to navigate the tree, and have the
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2873 same internal object structure, or a superset of it. Presumably this
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2874 would be the case for any object belonging to a class derived from
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2875 C<Tree::DAG_Node>, or belonging to C<Tree::DAG_Node> itself.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2876
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2877 When routines in this class access a node's "mother" attribute, or its
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2878 "daughters" attribute, they (generally) do so directly (via
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2879 $node->{'mother'}, etc.), for sake of efficiency. But classes derived
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2880 from this class should probably do this instead thru a method (via
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2881 $node->mother, etc.), for sake of portability, abstraction, and general
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2882 goodness.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2883
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2884 However, no routines in this class (aside from, necessarily, C<_init>,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2885 C<_init_name>, and C<name>) access the "name" attribute directly;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2886 routines (like the various tree draw/dump methods) get the "name" value
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2887 thru a call to $obj->name(). So if you want the object's name to not be
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2888 a real attribute, but instead have it derived dynamically from some feature
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2889 of the object (say, based on some of its other attributes, or based on
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2890 its address), you can to override the C<name> method, without causing
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2891 problems. (Be sure to consider the case of $obj->name as a write
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2892 method, as it's used in C<lol_to_tree> and C<random_network>.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2893
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2894 =head1 SEE ALSO
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2895
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2896 L<HTML::Element>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2897
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2898 Wirth, Niklaus. 1976. I<Algorithms + Data Structures = Programs>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2899 Prentice-Hall, Englewood Cliffs, NJ.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2900
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2901 Knuth, Donald Ervin. 1997. I<Art of Computer Programming, Volume 1,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2902 Third Edition: Fundamental Algorithms>. Addison-Wesley, Reading, MA.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2903
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2904 Wirth's classic, currently and lamentably out of print, has a good
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2905 section on trees. I find it clearer than Knuth's (if not quite as
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2906 encyclopedic), probably because Wirth's example code is in a
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2907 block-structured high-level language (basically Pascal), instead
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2908 of in assembler (MIX).
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2909
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2910 Until some kind publisher brings out a new printing of Wirth's book,
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2911 try poking around used bookstores (or C<www.abebooks.com>) for a copy.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2912 I think it was also republished in the 1980s under the title
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2913 I<Algorithms and Data Structures>, and in a German edition called
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2914 I<Algorithmen und Datenstrukturen>. (That is, I'm sure books by Knuth
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2915 were published under those titles, but I'm I<assuming> that they're just
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2916 later printings/editions of I<Algorithms + Data Structures =
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2917 Programs>.)
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2918
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2919 =head1 MAINTAINER
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2920
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2921 David Hand, C<< <cogent@cpan.org> >>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2922
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2923 =head1 AUTHOR
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2924
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2925 Sean M. Burke, C<< <sburke@cpan.org> >>
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2926
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2927 =head1 COPYRIGHT, LICENSE, AND DISCLAIMER
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2928
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2929 Copyright 1998-2001, 2004, 2007 by Sean M. Burke and David Hand.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2930
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2931 This program is free software; you can redistribute it and/or modify it
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2932 under the same terms as Perl itself.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2933
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2934 This program is distributed in the hope that it will be useful, but
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2935 without any warranty; without even the implied warranty of
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2936 merchantability or fitness for a particular purpose.
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2937
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2938 =cut
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2939
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2940 1;
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2941
acc8d8bfeb9a Uploaded
jjohnson
parents:
diff changeset
2942 __END__