1 # This file is part of the DEPS/graph-includes package
3 # (c) 2005,2006 Yann Dirson <ydirson@altern.org>
4 # Distributed under version 2 of the GNU GPL.
6 package graphincludes
::graph
;
10 use Hash
::Util
qw(lock_keys);
19 $self->{_NODES
} = undef;
20 $self->{_EDGES
} = undef;
21 $self->{_REVEDGES
} = undef;
23 $self->{_DROPCOUNT
} = 0;
24 $self->{_DROPPEDEDGES
} = {};
25 $self->{_DROPPEDREVEDGES
} = {};
27 bless ($self, $class);
36 my $class = ref $self;
37 my %nodes = %{$self->{_NODES
}};
44 _DROPPEDREVEDGES
=> {},
47 bless ($copy, $class);
49 if (defined $args{deep_copy_edges
}) {
50 foreach my $src ($self->get_edge_origins) {
51 foreach my $dst ($self->get_dep_names_from($src)) {
52 $copy->record_edge($src,$dst);
56 # FIXME: copy mode probably too shallow to make any sense ?
57 my (%edges,%revedges);
58 %edges = %{$self->{_EDGES
}};
59 %revedges = %{$self->{_REVEDGES
}};
60 $copy->{_EDGES
} = \
%edges;
61 $copy->{_REVEDGES
} = \
%revedges;
71 # store nodes as a hash indexed by label
72 my %nodes = map { ($_->{LABEL
} => $_) } @_;
74 $self->{_NODES
} = \
%nodes;
76 sub set_nodes_from_names
{
80 $self->set_nodes(map { new DEPS
::Node
($_); } @
$files);
87 croak
"node name must not be an object or reference" if ref $name;
89 $self->{_NODES
}{$name} = new DEPS
::Node
($name)
90 unless defined $self->{_NODES
}{$name};
92 return $self->{_NODES
}{$name};
101 printf STDERR
"Non-object: %s\n", $node->dump;
102 croak
"Trying to add a non-object as node";
104 if (defined $self->{_NODES
}{$node->{LABEL
}}) {
105 printf STDERR
"Already have %s\n", $self->{_NODES
}{$node->{LABEL
}}->dump;
106 printf STDERR
"Want to add %s\n", $node->dump;
107 croak
"Cannot add another node labelled $node->{LABEL}";
110 $self->{_NODES
}{$node->{LABEL
}} = $node;
116 values %{$self->{_NODES
}};
119 sub get_node_from_name
{
123 $self->{_NODES
}{$name};
129 defined get_node_from_name
($name);
134 my ($src, $dst) = @_;
136 # if (defined $self->{IGNOREDDEPS}{$src}{$dst}) {
137 # print STDERR "ignoring $src -> $dst\n" if $graphincludes::params::debug;
138 # $self->{IGNOREDEDGES}{$src}{$dst} =
139 # $self->{IGNOREDDEPS}{$src}{$dst};
143 croak
"edge src name must not be an object or reference" if ref $src;
144 croak
"edge dst name must not be an object or reference" if ref $dst;
146 unless (defined $self->{_EDGES
}{$src}{$dst}) {
148 my $srcnode = $self->{_NODES
}{$src}
149 or croak
"Source node not found '$src'";
150 my $dstnode = $self->{_NODES
}{$dst}
151 or croak
"Destination node not found '$dst' (source was '$src')";
153 my $edge = new DEPS
::Edge
($srcnode, $dstnode);
155 $self->{_EDGES
}{$src}{$dst} = $self->{_REVEDGES
}{$dst}{$src} = $edge;
158 return $self->{_EDGES
}{$src}{$dst};
167 printf STDERR
"Non-object: %s\n", $edge;
168 croak
"Trying to add a non-object as edge";
170 if ($self->has_edge($edge->{SRC
}{LABEL
},$edge->{DST
}{LABEL
})) {
171 printf STDERR
"Already have %s\n", $self->get_edge($edge->{SRC
}{LABEL
},$edge->{DST
}{LABEL
})->dump;
172 printf STDERR
"Want to add %s\n", $edge->dump;
173 croak
"Request to add duplicate edge";
177 $self->{_EDGES
}{$edge->{SRC
}{LABEL
}}{$edge->{DST
}{LABEL
}} =
178 $self->{_REVEDGES
}{$edge->{DST
}{LABEL
}}{$edge->{SRC
}{LABEL
}} = $edge;
185 # FIXME: not 100% correct - that could be an empty hash
186 defined $self->{_EDGES
}{$src};
192 defined $self->{_REVEDGES
}{$dst};
197 my ($src, $dst) = @_;
198 return $self->{_EDGES
}{$src}{$dst};
202 my ($src, $dst) = @_;
203 croak
"has_edge: uninitialized src" unless defined $src;
204 croak
"has_edge: uninitialized dst" unless defined $dst;
205 defined $self->{_EDGES
}{$src}{$dst};
209 my ($from, $to, @seen) = @_; # @seen is a private parameter
210 return ($from) if $from eq $to;
211 return () if grep { $_ eq $from } @seen;
212 return ($from, $to) if $self->has_edge($from,$to); # superfluous ?
213 foreach my $child ($self->get_dep_names_from($from)) {
214 if (my @path = $self->has_path($child, $to, (@seen, $from))) {
215 return ($from, @path);
218 return (); # no child (left) to look at
223 my ($src, $dst) = @_;
225 $self->{_DROPPEDEDGES
}{$src}{$dst} = $self->{_EDGES
}{$src}{$dst};
226 $self->{_DROPPEDREVEDGES
}{$dst}{$src} = $self->{_REVEDGES
}{$dst}{$src};
227 delete $self->{_EDGES
}{$src}{$dst};
228 delete $self->{_REVEDGES
}{$dst}{$src};
231 sub get_edge_origins
{
233 keys %{$self->{_EDGES
}};
238 values %{$self->{_EDGES
}{$origin}};
240 sub get_dep_names_from
{
243 keys %{$self->{_EDGES
}{$origin}};
246 sub get_edge_weight
{
249 return $self->get_edge($src,$dst)->weight();
252 sub is_reduction_of
{
256 print STDERR
"Verifying validity of transitive reduction "
257 if $graphincludes::params
::verbose
;
260 foreach my $node ($complete->get_edge_origins) {
261 print STDERR
'.' if $graphincludes::params
::verbose
;
262 foreach my $child ($complete->get_dep_names_from($node)) {
263 if (!$self->has_path($node, $child)) {
264 print STDERR
"ERROR: missing edge from $node to $child\n"
265 if $graphincludes::params
::debug
;
270 printf STDERR
" %s.\n", ($ok ?
"ok" : "FAILED")
271 if $graphincludes::params
::verbose
;