File Coverage

blib/lib/Data/Hopen/OrderedPredecessorGraph.pm
Criterion Covered Total %
statement 33 33 100.0
branch 10 10 100.0
condition 4 4 100.0
subroutine 8 8 100.0
pod 4 4 100.0
total 59 59 100.0


line stmt bran cond sub pod time code
1             # Data::Hopen::OrderedPredecessorGraph - Graph that keeps predecessors in order
2             package Data::Hopen::OrderedPredecessorGraph;
3 9     9   4724 use strict;
  9         19  
  9         295  
4 9     9   57 use Data::Hopen::Base;
  9         17  
  9         56  
5              
6             our $VERSION = '0.000018';
7              
8 9     9   2140 use parent 'Graph';
  9         19  
  9         49  
9              
10             # Docs {{{1
11              
12             =head1 NAME
13              
14             Data::Hopen::OrderedPredecessorGraph - Graph that tracks the order in which edges are added
15              
16             =head1 SYNOPSIS
17              
18             Just like a L with two exceptions:
19              
20             =over
21              
22             =item *
23              
24             Every call to L (or other edge-adding routines) tracks the order in
25             an attribute on that edge; and
26              
27             =item *
28              
29             New routine L returns the predecessors sorted
30             in the order they were added.
31              
32             =back
33              
34             This is unlike L and L, which return
35             the predecessors in random order.
36              
37             =cut
38              
39             # }}}1
40              
41             # Internals
42              
43 9     9   907044 use constant _EDGE_ID => (__PACKAGE__ . '_edge_id'); # attribute name
  9         30  
  9         4402  
44             my $_edge_id = 0; # unique ID for each edge added.
45             # INTERNAL PRECONDITION: real edge IDs are > 0.
46              
47             =head1 FUNCTIONS
48              
49             =head2 add_edge
50              
51             Add an edge. Exactly as L except that it also creates the
52             new edge attribute to hold the order. Returns the graph.
53              
54             L is implemented using C, so we don't need to
55             override C.
56              
57             =cut
58              
59             sub add_edge {
60 66 100   66 1 33430 croak 'Need instance, from, to' unless @_ == 3;
61 65         174 my ($self, $from, $to) = @_;
62 65         270 $self->SUPER::add_edge($from, $to);
63 65         29905 $self->set_edge_attribute($from, $to, _EDGE_ID, ++$_edge_id);
64 65         34039 return $self;
65             } #todo()
66              
67             =head2 ordered_predecessors
68              
69             Return a list of the predecessors of the given vertex, in order that the edges
70             were added to that vertex. Exactly as L except for the
71             stable order.
72              
73             =cut
74              
75             sub ordered_predecessors {
76 101 100   101 1 35648 croak 'Need instance, vertex' unless @_ == 2;
77 100         242 my ($self, $to) = @_;
78 100 100       306 die 'Multiedged graphs are not yet supported' if $self->multiedged;
79             # TODO use get_multiedge_ids to get the edge IDs, then get the
80             # attributes for each edge, then sort.
81              
82 99         876 my @p = $self->predecessors($to);
83             return sort {
84 99   100     14248 ( $self->get_edge_attribute($a, $to, _EDGE_ID) // 0 )
  178   100     23003  
85             <=>
86             ( $self->get_edge_attribute($b, $to, _EDGE_ID) // 0 )
87             } @p;
88             } #ordered_predecessors()
89              
90             =head2 add_edge_by_id
91              
92             Add a multiedge. Exactly as L except that it also
93             creates the new edge attribute to hold the order. Returns the graph.
94             Can only be used on a multiedged graph.
95              
96             =cut
97              
98             sub add_edge_by_id {
99 2 100   2 1 3890 croak 'Need self, from, to, id' unless @_ == 4;
100 1         14 my ($self, $from, $to, $id) = @_;
101 1         13 $self->SUPER::add_edge_by_id($from, $to, $id);
102 1         262 $self->set_edge_attribute_by_id($from, $to, $id, _EDGE_ID, ++$_edge_id);
103 1         120 return $self;
104             } #add_edge_by_id()
105              
106             =head2 add_edge_get_id
107              
108             Add a multiedge. Exactly as L except that it also
109             creates the new edge attribute to hold the order. Returns the ID of the
110             new edge. Can only be used on a multiedged graph.
111              
112             =cut
113              
114             sub add_edge_get_id {
115 3 100   3 1 1507 croak 'Need self, from, to' unless @_ == 3;
116 2         7 my ($self, $from, $to) = @_;
117 2         11 my $id = $self->SUPER::add_edge_get_id($from, $to);
118 2         291 $self->set_edge_attribute_by_id($from, $to, $id, _EDGE_ID, ++$_edge_id);
119 2         234 return $id;
120             } #add_edge_get_id()
121              
122             1;
123             __END__