summaryrefslogtreecommitdiff
path: root/perllib/Graph/AdjacencyMap/Heavy.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/Graph/AdjacencyMap/Heavy.pm')
-rw-r--r--perllib/Graph/AdjacencyMap/Heavy.pm253
1 files changed, 253 insertions, 0 deletions
diff --git a/perllib/Graph/AdjacencyMap/Heavy.pm b/perllib/Graph/AdjacencyMap/Heavy.pm
new file mode 100644
index 00000000..262bd4f5
--- /dev/null
+++ b/perllib/Graph/AdjacencyMap/Heavy.pm
@@ -0,0 +1,253 @@
+package Graph::AdjacencyMap::Heavy;
+
+# THIS IS INTERNAL IMPLEMENTATION ONLY, NOT TO BE USED DIRECTLY.
+# THE INTERFACE IS HARD TO USE AND GOING TO STAY THAT WAY AND
+# ALMOST GUARANTEED TO CHANGE OR GO AWAY IN FUTURE RELEASES.
+
+use strict;
+
+# $SIG{__DIE__ } = sub { use Carp; confess };
+# $SIG{__WARN__} = sub { use Carp; confess };
+
+use Graph::AdjacencyMap qw(:flags :fields);
+use base 'Graph::AdjacencyMap';
+
+require overload; # for de-overloading
+
+require Data::Dumper;
+
+sub __set_path {
+ my $m = shift;
+ my $f = $m->[ _f ];
+ my $id = pop if ($f & _MULTI);
+ if (@_ != $m->[ _a ] && !($f & _HYPER)) {
+ require Carp;
+ Carp::confess(sprintf "Graph::AdjacencyMap::Heavy: arguments %d expected %d",
+ scalar @_, $m->[ _a ]);
+ }
+ my $p;
+ $p = ($f & _HYPER) ?
+ (( $m->[ _s ] ||= [ ] )->[ @_ ] ||= { }) :
+ ( $m->[ _s ] ||= { });
+ my @p = $p;
+ my @k;
+ while (@_) {
+ my $k = shift;
+ my $q = ref $k && ($f & _REF) && overload::Method($k, '""') ? overload::StrVal($k) : $k;
+ if (@_) {
+ $p = $p->{ $q } ||= {};
+ return unless $p;
+ push @p, $p;
+ }
+ push @k, $q;
+ }
+ return (\@p, \@k);
+}
+
+sub __set_path_node {
+ my ($m, $p, $l) = splice @_, 0, 3;
+ my $f = $m->[ _f ] ;
+ my $id = pop if ($f & _MULTI);
+ unless (exists $p->[-1]->{ $l }) {
+ my $i = $m->_new_node( \$p->[-1]->{ $l }, $id );
+ $m->[ _i ]->{ defined $i ? $i : "" } = [ @_ ];
+ return defined $id ? ($id eq _GEN_ID ? $$id : $id) : $i;
+ } else {
+ return $m->_inc_node( \$p->[-1]->{ $l }, $id );
+ }
+}
+
+sub set_path {
+ my $m = shift;
+ my $f = $m->[ _f ];
+ if (@_ > 1 && ($f & _UNORDUNIQ)) {
+ if (($f & _UNORDUNIQ) == _UNORD && @_ == 2) { @_ = sort @_ }
+ else { $m->__arg(\@_) }
+ }
+ my ($p, $k) = $m->__set_path( @_ );
+ return unless defined $p && defined $k;
+ my $l = defined $k->[-1] ? $k->[-1] : "";
+ return $m->__set_path_node( $p, $l, @_ );
+}
+
+sub __has_path {
+ my $m = shift;
+ my $f = $m->[ _f ];
+ if (@_ != $m->[ _a ] && !($f & _HYPER)) {
+ require Carp;
+ Carp::confess(sprintf "Graph::AdjacencyMap::Heavy: arguments %d expected %d",
+ scalar @_, $m->[ _a ]);
+ }
+ if (@_ > 1 && ($f & _UNORDUNIQ)) {
+ if (($f & _UNORDUNIQ) == _UNORD && @_ == 2) { @_ = sort @_ }
+ else { $m->__arg(\@_) }
+ }
+ my $p = $m->[ _s ];
+ return unless defined $p;
+ $p = $p->[ @_ ] if ($f & _HYPER);
+ return unless defined $p;
+ my @p = $p;
+ my @k;
+ while (@_) {
+ my $k = shift;
+ my $q = ref $k && ($f & _REF) && overload::Method($k, '""') ? overload::StrVal($k) : $k;
+ if (@_) {
+ $p = $p->{ $q };
+ return unless defined $p;
+ push @p, $p;
+ }
+ push @k, $q;
+ }
+ return (\@p, \@k);
+}
+
+sub has_path {
+ my $m = shift;
+ my $f = $m->[ _f ];
+ if (@_ > 1 && ($f & _UNORDUNIQ)) {
+ if (($f & _UNORDUNIQ) == _UNORD && @_ == 2) { @_ = sort @_ }
+ else { $m->__arg(\@_) }
+ }
+ my ($p, $k) = $m->__has_path( @_ );
+ return unless defined $p && defined $k;
+ return exists $p->[-1]->{ defined $k->[-1] ? $k->[-1] : "" };
+}
+
+sub has_path_by_multi_id {
+ my $m = shift;
+ my $f = $m->[ _f ];
+ my $id = pop;
+ if (@_ > 1 && ($f & _UNORDUNIQ)) {
+ if (($f & _UNORDUNIQ) == _UNORD && @_ == 2) { @_ = sort @_ }
+ else { $m->__arg(\@_) }
+ }
+ my ($e, $n) = $m->__get_path_node( @_ );
+ return undef unless $e;
+ return exists $n->[ _nm ]->{ $id };
+}
+
+sub _get_path_node {
+ my $m = shift;
+ my $f = $m->[ _f ];
+ if ($m->[ _a ] == 2 && @_ == 2 && !($f & (_HYPER|_REF|_UNIQ))) { # Fast path.
+ @_ = sort @_ if ($f & _UNORD);
+ return unless exists $m->[ _s ]->{ $_[0] };
+ my $p = [ $m->[ _s ], $m->[ _s ]->{ $_[0] } ];
+ my $k = [ $_[0], $_[1] ];
+ my $l = $_[1];
+ return ( exists $p->[-1]->{ $l }, $p->[-1]->{ $l }, $p, $k, $l );
+ } else {
+ if (@_ > 1 && ($f & _UNORDUNIQ)) {
+ if (($f & _UNORDUNIQ) == _UNORD && @_ == 2) { @_ = sort @_ }
+ else { $m->__arg(\@_) }
+ }
+ $m->__get_path_node( @_ );
+ }
+}
+
+sub _get_path_id {
+ my $m = shift;
+ my $f = $m->[ _f ];
+ my ($e, $n);
+ if ($m->[ _a ] == 2 && @_ == 2 && !($f & (_HYPER|_REF|_UNIQ))) { # Fast path.
+ @_ = sort @_ if ($f & _UNORD);
+ return unless exists $m->[ _s ]->{ $_[0] };
+ my $p = $m->[ _s ]->{ $_[0] };
+ $e = exists $p->{ $_[1] };
+ $n = $p->{ $_[1] };
+ } else {
+ ($e, $n) = $m->_get_path_node( @_ );
+ }
+ return undef unless $e;
+ return ref $n ? $n->[ _ni ] : $n;
+}
+
+sub _get_path_count {
+ my $m = shift;
+ my $f = $m->[ _f ];
+ my ($e, $n) = $m->_get_path_node( @_ );
+ return undef unless $e && defined $n;
+ return
+ ($f & _COUNT) ? $n->[ _nc ] :
+ ($f & _MULTI) ? scalar keys %{ $n->[ _nm ] } : 1;
+}
+
+sub __attr {
+ my $m = shift;
+ if (@_) {
+ if (ref $_[0] && @{ $_[0] }) {
+ if (@{ $_[0] } != $m->[ _a ]) {
+ require Carp;
+ Carp::confess(sprintf
+ "Graph::AdjacencyMap::Heavy: arguments %d expected %d\n",
+ scalar @{ $_[0] }, $m->[ _a ]);
+ }
+ my $f = $m->[ _f ];
+ if (@{ $_[0] } > 1 && ($f & _UNORDUNIQ)) {
+ if (($f & _UNORDUNIQ) == _UNORD && @{ $_[0] } == 2) {
+ @{ $_[0] } = sort @{ $_[0] }
+ } else { $m->__arg(\@_) }
+ }
+ }
+ }
+}
+
+sub _get_id_path {
+ my ($m, $i) = @_;
+ my $p = defined $i ? $m->[ _i ]->{ $i } : undef;
+ return defined $p ? @$p : ( );
+}
+
+sub del_path {
+ my $m = shift;
+ my $f = $m->[ _f ];
+ if (@_ > 1 && ($f & _UNORDUNIQ)) {
+ if (($f & _UNORDUNIQ) == _UNORD && @_ == 2) { @_ = sort @_ }
+ else { $m->__arg(\@_) }
+ }
+ my ($e, $n, $p, $k, $l) = $m->__get_path_node( @_ );
+ return unless $e;
+ my $c = ($f & _COUNT) ? --$n->[ _nc ] : 0;
+ if ($c == 0) {
+ delete $m->[ _i ]->{ ref $n ? $n->[ _ni ] : $n };
+ delete $p->[-1]->{ $l };
+ while (@$p && @$k && keys %{ $p->[-1]->{ $k->[-1] } } == 0) {
+ delete $p->[-1]->{ $k->[-1] };
+ pop @$p;
+ pop @$k;
+ }
+ }
+ return 1;
+}
+
+sub del_path_by_multi_id {
+ my $m = shift;
+ my $f = $m->[ _f ];
+ my $id = pop;
+ if (@_ > 1 && ($f & _UNORDUNIQ)) {
+ if (($f & _UNORDUNIQ) == _UNORD && @_ == 2) { @_ = sort @_ }
+ else { $m->__arg(\@_) }
+ }
+ my ($e, $n, $p, $k, $l) = $m->__get_path_node( @_ );
+ return unless $e;
+ delete $n->[ _nm ]->{ $id };
+ unless (keys %{ $n->[ _nm ] }) {
+ delete $m->[ _i ]->{ $n->[ _ni ] };
+ delete $p->[-1]->{ $l };
+ while (@$p && @$k && keys %{ $p->[-1]->{ $k->[-1] } } == 0) {
+ delete $p->[-1]->{ $k->[-1] };
+ pop @$p;
+ pop @$k;
+ }
+ }
+ return 1;
+}
+
+sub paths {
+ my $m = shift;
+ return values %{ $m->[ _i ] } if defined $m->[ _i ];
+ wantarray ? ( ) : 0;
+}
+
+1;
+__END__