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   4866 use strict;
  9         23  
  9         286  
4 9     9   51 use Data::Hopen::Base;
  9         19  
  9         66  
5              
6             our $VERSION = '0.000019';
7              
8 9     9   2085 use parent 'Graph';
  9         23  
  9         53  
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   312420 use constant _EDGE_ID => (__PACKAGE__ . '_edge_id'); # attribute name
  9         29  
  9         4160  
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 49 100   49 1 18137 croak 'Need instance, from, to' unless @_ == 3;
61 48         131 my ($self, $from, $to) = @_;
62 48         233 $self->SUPER::add_edge($from, $to);
63 48         24455 $self->set_edge_attribute($from, $to, _EDGE_ID, ++$_edge_id);
64 48         38177 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 29615 croak 'Need instance, vertex' unless @_ == 2;
77 100         278 my ($self, $to) = @_;
78 100 100       673 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         688 my @p = $self->predecessors($to);
83             return sort {
84 99   100     22310 ( $self->get_edge_attribute($a, $to, _EDGE_ID) // 0 )
  137   100     15158  
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 2982 croak 'Need self, from, to, id' unless @_ == 4;
100 1         4 my ($self, $from, $to, $id) = @_;
101 1         11 $self->SUPER::add_edge_by_id($from, $to, $id);
102 1         295 $self->set_edge_attribute_by_id($from, $to, $id, _EDGE_ID, ++$_edge_id);
103 1         309 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 1080 croak 'Need self, from, to' unless @_ == 3;
116 2         5 my ($self, $from, $to) = @_;
117 2         12 my $id = $self->SUPER::add_edge_get_id($from, $to);
118 2         349 $self->set_edge_attribute_by_id($from, $to, $id, _EDGE_ID, ++$_edge_id);
119 2         408 return $id;
120             } #add_edge_get_id()
121              
122             1;
123             __END__