mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-09-22 10:43:39 -04:00
248 lines
5.7 KiB
Perl
248 lines
5.7 KiB
Perl
package Graph::AdjacencyMap::Light;
|
|
|
|
# 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;
|
|
|
|
use Graph::AdjacencyMap qw(:flags :fields);
|
|
use base 'Graph::AdjacencyMap';
|
|
|
|
use Scalar::Util qw(weaken);
|
|
|
|
use Graph::AdjacencyMap::Heavy;
|
|
use Graph::AdjacencyMap::Vertex;
|
|
|
|
sub _V () { 2 } # Graph::_V
|
|
sub _E () { 3 } # Graph::_E
|
|
sub _F () { 0 } # Graph::_F
|
|
|
|
sub _new {
|
|
my ($class, $graph, $flags, $arity) = @_;
|
|
my $m = bless [ ], $class;
|
|
$m->[ _n ] = 0;
|
|
$m->[ _f ] = $flags | _LIGHT;
|
|
$m->[ _a ] = $arity;
|
|
$m->[ _i ] = { };
|
|
$m->[ _s ] = { };
|
|
$m->[ _p ] = { };
|
|
$m->[ _g ] = $graph;
|
|
weaken $m->[ _g ]; # So that DESTROY finds us earlier.
|
|
return $m;
|
|
}
|
|
|
|
sub set_path {
|
|
my $m = shift;
|
|
my ($n, $f, $a, $i, $s, $p) = @$m;
|
|
if ($a == 2) {
|
|
@_ = sort @_ if ($f & _UNORD);
|
|
}
|
|
my $e0 = shift;
|
|
if ($a == 2) {
|
|
my $e1 = shift;
|
|
unless (exists $s->{ $e0 } && exists $s->{ $e0 }->{ $e1 }) {
|
|
$n = $m->[ _n ]++;
|
|
$i->{ $n } = [ $e0, $e1 ];
|
|
$s->{ $e0 }->{ $e1 } = $n;
|
|
$p->{ $e1 }->{ $e0 } = $n;
|
|
}
|
|
} else {
|
|
unless (exists $s->{ $e0 }) {
|
|
$n = $m->[ _n ]++;
|
|
$s->{ $e0 } = $n;
|
|
$i->{ $n } = $e0;
|
|
}
|
|
}
|
|
}
|
|
|
|
sub has_path {
|
|
my $m = shift;
|
|
my ($n, $f, $a, $i, $s) = @$m;
|
|
return 0 unless $a == @_;
|
|
my $e;
|
|
if ($a == 2) {
|
|
@_ = sort @_ if ($f & _UNORD);
|
|
$e = shift;
|
|
return 0 unless exists $s->{ $e };
|
|
$s = $s->{ $e };
|
|
}
|
|
$e = shift;
|
|
exists $s->{ $e };
|
|
}
|
|
|
|
sub _get_path_id {
|
|
my $m = shift;
|
|
my ($n, $f, $a, $i, $s) = @$m;
|
|
return undef unless $a == @_;
|
|
my $e;
|
|
if ($a == 2) {
|
|
@_ = sort @_ if ($f & _UNORD);
|
|
$e = shift;
|
|
return undef unless exists $s->{ $e };
|
|
$s = $s->{ $e };
|
|
}
|
|
$e = shift;
|
|
$s->{ $e };
|
|
}
|
|
|
|
sub _get_path_count {
|
|
my $m = shift;
|
|
my ($n, $f, $a, $i, $s) = @$m;
|
|
my $e;
|
|
if (@_ == 2) {
|
|
@_ = sort @_ if ($f & _UNORD);
|
|
$e = shift;
|
|
return undef unless exists $s->{ $e };
|
|
$s = $s->{ $e };
|
|
}
|
|
$e = shift;
|
|
return exists $s->{ $e } ? 1 : 0;
|
|
}
|
|
|
|
sub has_paths {
|
|
my $m = shift;
|
|
my ($n, $f, $a, $i, $s) = @$m;
|
|
keys %$s;
|
|
}
|
|
|
|
sub paths {
|
|
my $m = shift;
|
|
my ($n, $f, $a, $i) = @$m;
|
|
if (defined $i) {
|
|
my ($k, $v) = each %$i;
|
|
if (ref $v) {
|
|
return values %{ $i };
|
|
} else {
|
|
return map { [ $_ ] } values %{ $i };
|
|
}
|
|
} else {
|
|
return ( );
|
|
}
|
|
}
|
|
|
|
sub _get_id_path {
|
|
my $m = shift;
|
|
my ($n, $f, $a, $i) = @$m;
|
|
my $p = $i->{ $_[ 0 ] };
|
|
defined $p ? ( ref $p eq 'ARRAY' ? @$p : $p ) : ( );
|
|
}
|
|
|
|
sub del_path {
|
|
my $m = shift;
|
|
my ($n, $f, $a, $i, $s, $p) = @$m;
|
|
if (@_ == 2) {
|
|
@_ = sort @_ if ($f & _UNORD);
|
|
my $e0 = shift;
|
|
return 0 unless exists $s->{ $e0 };
|
|
my $e1 = shift;
|
|
if (defined($n = $s->{ $e0 }->{ $e1 })) {
|
|
delete $i->{ $n };
|
|
delete $s->{ $e0 }->{ $e1 };
|
|
delete $p->{ $e1 }->{ $e0 };
|
|
delete $s->{ $e0 } unless keys %{ $s->{ $e0 } };
|
|
delete $p->{ $e1 } unless keys %{ $p->{ $e1 } };
|
|
return 1;
|
|
}
|
|
} else {
|
|
my $e = shift;
|
|
if (defined($n = $s->{ $e })) {
|
|
delete $i->{ $n };
|
|
delete $s->{ $e };
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
sub __successors {
|
|
my $E = shift;
|
|
return wantarray ? () : 0 unless defined $E->[ _s ];
|
|
my $g = shift;
|
|
my $V = $g->[ _V ];
|
|
return wantarray ? () : 0 unless defined $V && defined $V->[ _s ];
|
|
# my $i = $V->_get_path_id( $_[0] );
|
|
my $i =
|
|
($V->[ _f ] & _LIGHT) ?
|
|
$V->[ _s ]->{ $_[0] } :
|
|
$V->_get_path_id( $_[0] );
|
|
return wantarray ? () : 0 unless defined $i && defined $E->[ _s ]->{ $i };
|
|
return keys %{ $E->[ _s ]->{ $i } };
|
|
}
|
|
|
|
sub _successors {
|
|
my $E = shift;
|
|
my $g = shift;
|
|
my @s = $E->__successors($g, @_);
|
|
if (($E->[ _f ] & _UNORD)) {
|
|
push @s, $E->__predecessors($g, @_);
|
|
my %s; @s{ @s } = ();
|
|
@s = keys %s;
|
|
}
|
|
my $V = $g->[ _V ];
|
|
return wantarray ? map { $V->[ _i ]->{ $_ } } @s : @s;
|
|
}
|
|
|
|
sub __predecessors {
|
|
my $E = shift;
|
|
return wantarray ? () : 0 unless defined $E->[ _p ];
|
|
my $g = shift;
|
|
my $V = $g->[ _V ];
|
|
return wantarray ? () : 0 unless defined $V && defined $V->[ _s ];
|
|
# my $i = $V->_get_path_id( $_[0] );
|
|
my $i =
|
|
($V->[ _f ] & _LIGHT) ?
|
|
$V->[ _s ]->{ $_[0] } :
|
|
$V->_get_path_id( $_[0] );
|
|
return wantarray ? () : 0 unless defined $i && defined $E->[ _p ]->{ $i };
|
|
return keys %{ $E->[ _p ]->{ $i } };
|
|
}
|
|
|
|
sub _predecessors {
|
|
my $E = shift;
|
|
my $g = shift;
|
|
my @p = $E->__predecessors($g, @_);
|
|
if ($E->[ _f ] & _UNORD) {
|
|
push @p, $E->__successors($g, @_);
|
|
my %p; @p{ @p } = ();
|
|
@p = keys %p;
|
|
}
|
|
my $V = $g->[ _V ];
|
|
return wantarray ? map { $V->[ _i ]->{ $_ } } @p : @p;
|
|
}
|
|
|
|
sub __attr {
|
|
# Major magic takes place here: we rebless the appropriate 'light'
|
|
# map into a more complex map and then redispatch the method.
|
|
my $m = $_[0];
|
|
my ($n, $f, $a, $i, $s, $p, $g) = @$m;
|
|
my ($k, $v) = each %$i;
|
|
my @V = @{ $g->[ _V ] };
|
|
my @E = $g->edges; # TODO: Both these (ZZZ) lines are mysteriously needed!
|
|
# ZZZ: an example of failing tests is t/52_edge_attributes.t.
|
|
if (ref $v eq 'ARRAY') { # Edges, then.
|
|
# print "Reedging.\n";
|
|
@E = $g->edges; # TODO: Both these (ZZZ) lines are mysteriously needed!
|
|
$g->[ _E ] = $m = Graph::AdjacencyMap::Heavy->_new($f, 2);
|
|
$g->add_edges( @E );
|
|
} else {
|
|
# print "Revertexing.\n";
|
|
$m = Graph::AdjacencyMap::Vertex->_new(($f & ~_LIGHT), 1);
|
|
$m->[ _n ] = $V[ _n ];
|
|
$m->[ _i ] = $V[ _i ];
|
|
$m->[ _s ] = $V[ _s ];
|
|
$m->[ _p ] = $V[ _p ];
|
|
$g->[ _V ] = $m;
|
|
}
|
|
$_[0] = $m;
|
|
goto &{ ref($m) . "::__attr" }; # Redispatch.
|
|
}
|
|
|
|
sub _is_COUNT () { 0 }
|
|
sub _is_MULTI () { 0 }
|
|
sub _is_HYPER () { 0 }
|
|
sub _is_UNIQ () { 0 }
|
|
sub _is_REF () { 0 }
|
|
|
|
1;
|