1 package Graph
::AdjacencyMap
;
6 use vars
qw(@ISA @EXPORT_OK %EXPORT_TAGS);
8 @EXPORT_OK = qw(_COUNT _MULTI _COUNTMULTI _GEN_ID
9 _HYPER _UNORD _UNIQ _REF _UNORDUNIQ _UNIONFIND _LIGHT
10 _n _f _a _i _s _p _g _u _ni _nc _na _nm);
12 (flags
=> [qw(_COUNT _MULTI _COUNTMULTI _GEN_ID
13 _HYPER _UNORD _UNIQ _REF _UNORDUNIQ _UNIONFIND _LIGHT)],
14 fields
=> [qw(_n _f _a _i _s _p _g _u _ni _nc _na _nm)]);
16 sub _COUNT
() { 0x00000001 }
17 sub _MULTI
() { 0x00000002 }
18 sub _COUNTMULTI
() { _COUNT
|_MULTI
}
19 sub _HYPER
() { 0x00000004 }
20 sub _UNORD
() { 0x00000008 }
21 sub _UNIQ
() { 0x00000010 }
22 sub _REF
() { 0x00000020 }
23 sub _UNORDUNIQ
() { _UNORD
|_UNIQ
}
24 sub _UNIONFIND
() { 0x00000040 }
25 sub _LIGHT
() { 0x00000080 }
29 sub _GEN_ID
() { \
$_GEN_ID }
31 sub _ni
() { 0 } # Node index.
32 sub _nc
() { 1 } # Node count.
33 sub _na
() { 2 } # Node attributes.
34 sub _nm
() { 3 } # Node map.
36 sub _n
() { 0 } # Next id.
37 sub _f
() { 1 } # Flags.
38 sub _a
() { 2 } # Arity.
39 sub _i
() { 3 } # Index to path.
40 sub _s
() { 4 } # Successors / Path to Index.
41 sub _p
() { 5 } # Predecessors.
42 sub _g
() { 6 } # Graph (AdjacencyMap::Light)
44 sub _V
() { 2 } # Graph::_V()
48 my $map = bless [ 0, @_ ], $class;
59 return defined $m->[ _i
] && keys %{ $m->[ _i
] };
63 my $d = Data
::Dumper
->new([$_[0]],[ref $_[0]]);
64 defined wantarray ?
$d->Dump : print $d->Dump;
69 my @p = $m->_get_id_path( $i );
70 $m->del_path( @p ) if @p;
74 my ($m, $n, $id) = @_;
78 $id = 0 if $id eq _GEN_ID
;
79 $$n = [ $i, 0, undef, { $id => { } } ];
80 } elsif (($f & _COUNT
)) {
89 my ($m, $n, $id) = @_;
94 while exists $$n->[ _nm
]->{ $$n->[ _nc
] };
97 $$n->[ _nm
]->{ $id } = { };
98 } elsif (($f & _COUNT
)) {
104 sub __get_path_node
{
108 @_ = sort @_ if ($f & _UNORD
);
109 if ($m->[ _a
] == 2 && @_ == 2 && !($f & (_HYPER
|_REF
|_UNIQ
))) { # Fast path.
110 return unless exists $m->[ _s
]->{ $_[0] };
111 $p = [ $m->[ _s
], $m->[ _s
]->{ $_[0] } ];
112 $k = [ $_[0], $_[1] ];
114 ($p, $k) = $m->__has_path( @_ );
116 return unless defined $p && defined $k;
117 my $l = defined $k->[-1] ?
$k->[-1] : "";
118 return ( exists $p->[-1]->{ $l }, $p->[-1]->{ $l }, $p, $k, $l );
121 sub set_path_by_multi_id
{
123 my ($p, $k) = $m->__set_path( @_ );
124 return unless defined $p && defined $k;
125 my $l = defined $k->[-1] ?
$k->[-1] : "";
126 return $m->__set_path_node( $p, $l, @_ );
132 return () unless ($f & _MULTI
);
133 my ($e, $n) = $m->__get_path_node( @_ );
134 return $e ?
keys %{ $n->[ _nm
] } : ();
137 sub _has_path_attrs
{
140 my $id = pop if ($f & _MULTI
);
141 @_ = sort @_ if ($f & _UNORD
);
144 my ($p, $k) = $m->__has_path( @_ );
145 return unless defined $p && defined $k;
146 my $l = defined $k->[-1] ?
$k->[-1] : "";
147 return keys %{ $p->[-1]->{ $l }->[ _nm
]->{ $id } } ?
1 : 0;
149 my ($e, $n) = $m->__get_path_node( @_ );
150 return undef unless $e;
151 return ref $n && $#$n == _na && keys %{ $n->[ _na ] } ? 1 : 0;
155 sub _set_path_attrs
{
159 my $id = pop if ($f & _MULTI
);
160 @_ = sort @_ if ($f & _UNORD
);
162 push @_, $id if ($f & _MULTI
);
163 my ($p, $k) = $m->__set_path( @_ );
164 return unless defined $p && defined $k;
165 my $l = defined $k->[-1] ?
$k->[-1] : "";
166 $m->__set_path_node( $p, $l, @_ ) unless exists $p->[-1]->{ $l };
168 $p->[-1]->{ $l }->[ _nm
]->{ $id } = $attr;
170 # Extend the node if it is a simple id node.
171 $p->[-1]->{ $l } = [ $p->[-1]->{ $l }, 1 ] unless ref $p->[-1]->{ $l };
172 $p->[-1]->{ $l }->[ _na
] = $attr;
180 my $id = pop if ($f & _MULTI
);
181 @_ = sort @_ if ($f & _UNORD
);
184 my ($p, $k) = $m->__has_path( @_ );
185 return unless defined $p && defined $k;
186 my $l = defined $k->[-1] ?
$k->[-1] : "";
187 exists $p->[-1]->{ $l }->[ _nm
]->{ $id }->{ $attr };
189 my ($e, $n) = $m->__get_path_node( @_ );
190 return undef unless $e;
191 return ref $n && $#$n == _na ? exists $n->[ _na ]->{ $attr } : undef;
200 my $id = pop if ($f & _MULTI
);
201 @_ = sort @_ if ($f & _UNORD
);
203 $m->__attr( \
@_ ); # _LIGHT maps need this to get upgraded when needed.
204 push @_, $id if ($f & _MULTI
);
205 @_ = sort @_ if ($f & _UNORD
);
206 if ($m->[ _a
] == 2 && @_ == 2 && !($f & (_REF
|_UNIQ
|_HYPER
|_UNIQ
))) {
207 $m->[ _s
]->{ $_[0] } ||= { };
208 $p = [ $m->[ _s
], $m->[ _s
]->{ $_[0] } ];
209 $k = [ $_[0], $_[1] ];
211 ($p, $k) = $m->__set_path( @_ );
213 return unless defined $p && defined $k;
214 my $l = defined $k->[-1] ?
$k->[-1] : "";
215 $m->__set_path_node( $p, $l, @_ ) unless exists $p->[-1]->{ $l };
217 $p->[-1]->{ $l }->[ _nm
]->{ $id }->{ $attr } = $val;
219 # Extend the node if it is a simple id node.
220 $p->[-1]->{ $l } = [ $p->[-1]->{ $l }, 1 ] unless ref $p->[-1]->{ $l };
221 $p->[-1]->{ $l }->[ _na
]->{ $attr } = $val;
226 sub _get_path_attrs
{
229 my $id = pop if ($f & _MULTI
);
230 @_ = sort @_ if ($f & _UNORD
);
233 my ($p, $k) = $m->__has_path( @_ );
234 return unless defined $p && defined $k;
235 my $l = defined $k->[-1] ?
$k->[-1] : "";
236 $p->[-1]->{ $l }->[ _nm
]->{ $id };
238 my ($e, $n) = $m->__get_path_node( @_ );
240 return $n->[ _na
] if ref $n && $#$n == _na;
249 my $id = pop if ($f & _MULTI
);
250 @_ = sort @_ if ($f & _UNORD
);
253 my ($p, $k) = $m->__has_path( @_ );
254 return unless defined $p && defined $k;
255 my $l = defined $k->[-1] ?
$k->[-1] : "";
256 return $p->[-1]->{ $l }->[ _nm
]->{ $id }->{ $attr };
258 my ($e, $n) = $m->__get_path_node( @_ );
259 return undef unless $e;
260 return ref $n && $#$n == _na ? $n->[ _na ]->{ $attr } : undef;
264 sub _get_path_attr_names
{
267 my $id = pop if ($f & _MULTI
);
268 @_ = sort @_ if ($f & _UNORD
);
271 my ($p, $k) = $m->__has_path( @_ );
272 return unless defined $p && defined $k;
273 my $l = defined $k->[-1] ?
$k->[-1] : "";
274 keys %{ $p->[-1]->{ $l }->[ _nm
]->{ $id } };
276 my ($e, $n) = $m->__get_path_node( @_ );
277 return undef unless $e;
278 return keys %{ $n->[ _na
] } if ref $n && $#$n == _na;
283 sub _get_path_attr_values
{
286 my $id = pop if ($f & _MULTI
);
287 @_ = sort @_ if ($f & _UNORD
);
290 my ($p, $k) = $m->__has_path( @_ );
291 return unless defined $p && defined $k;
292 my $l = defined $k->[-1] ?
$k->[-1] : "";
293 values %{ $p->[-1]->{ $l }->[ _nm
]->{ $id } };
295 my ($e, $n) = $m->__get_path_node( @_ );
296 return undef unless $e;
297 return values %{ $n->[ _na
] } if ref $n && $#$n == _na;
302 sub _del_path_attrs
{
305 my $id = pop if ($f & _MULTI
);
306 @_ = sort @_ if ($f & _UNORD
);
309 my ($p, $k) = $m->__has_path( @_ );
310 return unless defined $p && defined $k;
311 my $l = defined $k->[-1] ?
$k->[-1] : "";
312 delete $p->[-1]->{ $l }->[ _nm
]->{ $id };
313 unless (keys %{ $p->[-1]->{ $l }->[ _nm
] } ||
314 (defined $p->[-1]->{ $l }->[ _na
] &&
315 keys %{ $p->[-1]->{ $l }->[ _na
] })) {
316 delete $p->[-1]->{ $l };
319 my ($e, $n) = $m->__get_path_node( @_ );
320 return undef unless $e;
322 $e = _na
== $#$n && keys %{ $n->[ _na ] } ? 1 : 0;
335 my $id = pop if ($f & _MULTI
);
336 @_ = sort @_ if ($f & _UNORD
);
339 my ($p, $k) = $m->__has_path( @_ );
340 return unless defined $p && defined $k;
341 my $l = defined $k->[-1] ?
$k->[-1] : "";
342 delete $p->[-1]->{ $l }->[ _nm
]->{ $id }->{ $attr };
343 $m->_del_path_attrs( @_, $id )
344 unless keys %{ $p->[-1]->{ $l }->[ _nm
]->{ $id } };
346 my ($e, $n) = $m->__get_path_node( @_ );
347 return undef unless $e;
348 if (ref $n && $#$n == _na && exists $n->[ _na ]->{ $attr }) {
349 delete $n->[ _na
]->{ $attr };
357 sub _is_COUNT
{ $_[0]->[ _f
] & _COUNT
}
358 sub _is_MULTI
{ $_[0]->[ _f
] & _MULTI
}
359 sub _is_HYPER
{ $_[0]->[ _f
] & _HYPER
}
360 sub _is_UNORD
{ $_[0]->[ _f
] & _UNORD
}
361 sub _is_UNIQ
{ $_[0]->[ _f
] & _UNIQ
}
362 sub _is_REF
{ $_[0]->[ _f
] & _REF
}
376 push @u, $e if $u{$e}++ == 0;
381 # Alphabetic or numeric sort, does not matter as long as it unifies.
382 @
{$_[0]} = ($f & _UNORD
) ?
sort @a : @a;
389 map { my @v = @
{ $_->[ 1 ] };
391 map { $V->_get_id_path($_) } @v } $g->_edges_from( @_ );
399 map { my @v = @
{ $_->[ 1 ] };
401 map { $V->_get_id_path($_) } @v } $g->_edges_to( @_ );
403 return $g->_edges_to( @_ );
413 Graph::AdjacencyMap - create and a map of graph vertices or edges
421 B<This module is meant for internal use by the Graph module.>
423 =head2 Object Methods
429 Delete a Map path by ids.
431 =item del_path_by_multi_id($id)
433 Delete a Map path by a multi(vertex) id.
437 Return the multi ids.
441 Return true if the Map has the path by ids, false if not.
445 Return true if the Map has any paths, false if not.
447 =item has_path_by_multi_id($id)
449 Return true ifd the a Map has the path by a multi(vertex) id, false if not.
453 Return all the paths of the Map.
457 Set the path by @ids.
459 =item set_path_by_multi_id
461 Set the path in the Map by the multi id.
465 =head1 AUTHOR AND COPYRIGHT
467 Jarkko Hietaniemi F<jhi@iki.fi>
471 This module is licensed under the same terms as Perl itself.