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   4768 use strict;
  9         63  
  9         297  
4 9     9   53 use Data::Hopen::Base;
  9         19  
  9         61  
5              
6             our $VERSION = '0.000017';
7              
8 9     9   2105 use parent 'Graph';
  9         22  
  9         58  
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   953331 use constant _EDGE_ID => (__PACKAGE__ . '_edge_id'); # attribute name
  9         26  
  9         4030  
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 32692 croak 'Need instance, from, to' unless @_ == 3;
61 65         169 my ($self, $from, $to) = @_;
62 65         331 $self->SUPER::add_edge($from, $to);
63 65         30172 $self->set_edge_attribute($from, $to, _EDGE_ID, ++$_edge_id);
64 65         34911 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 30309 croak 'Need instance, vertex' unless @_ == 2;
77 100         238 my ($self, $to) = @_;
78 100 100       366 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         869 my @p = $self->predecessors($to);
83             return sort {
84 99   100     14912 ( $self->get_edge_attribute($a, $to, _EDGE_ID) // 0 )
  171   100     21671  
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 3325 croak 'Need self, from, to, id' unless @_ == 4;
100 1         6 my ($self, $from, $to, $id) = @_;
101 1         13 $self->SUPER::add_edge_by_id($from, $to, $id);
102 1         222 $self->set_edge_attribute_by_id($from, $to, $id, _EDGE_ID, ++$_edge_id);
103 1         108 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 1277 croak 'Need self, from, to' unless @_ == 3;
116 2         7 my ($self, $from, $to) = @_;
117 2         10 my $id = $self->SUPER::add_edge_get_id($from, $to);
118 2         292 $self->set_edge_attribute_by_id($from, $to, $id, _EDGE_ID, ++$_edge_id);
119 2         192 return $id;
120             } #add_edge_get_id()
121              
122             1;
123             __END__