mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-09-22 10:43:39 -04:00
254 lines
6.4 KiB
Perl
254 lines
6.4 KiB
Perl
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__
|