File Coverage

blib/lib/Array/Heap/PriorityQueue/Compare.pm
Criterion Covered Total %
statement 39 39 100.0
branch 2 4 50.0
condition 2 5 40.0
subroutine 14 14 100.0
pod 9 9 100.0
total 66 71 92.9


line stmt bran cond sub pod time code
1             package Array::Heap::PriorityQueue::Compare;
2 1     1   24258 use strict;
  1         2  
  1         36  
3 1     1   6 use warnings;
  1         2  
  1         37  
4 1     1   6 use Carp qw( croak );
  1         1  
  1         80  
5 1     1   6 use vars qw( $VERSION );
  1         2  
  1         71  
6             $VERSION = '1.10';
7 1     1   785 use Array::Heap ( );
  1         649  
  1         582  
8              
9             =head1 NAME
10              
11             Array::Heap::PriorityQueue::Compare - Priority queue with custom comparison
12              
13             =head1 SYNOPSIS
14              
15             use Array::Heap::PriorityQueue::Compare;
16             my $pq = Array::Heap::PriorityQueue::Compare->new(sub { $b cmp $a });
17             $pq->add('banana');
18             $pq->add('fish');
19             print $pq->get(), "\n"; # fish
20             print $pq->peek(), "\n"; # banana
21              
22             =head1 DESCRIPTION
23              
24             This module implements a priority queue, which is a data structure that can
25             efficiently locate the item with the lowest weight at any time. This is useful
26             for writing cost-minimizing and shortest-path algorithms.
27              
28             When creating a new queue, you supply a comparison function that is used to
29             order the items.
30              
31             This module is a wrapper around the *_heap_cmp methods provided by
32             L.
33              
34             =head1 FUNCTIONS
35              
36             =over 4
37              
38             =item Array::Heap::PriorityQueue::Compare->new(\&compare)
39              
40             =item Array::Heap::PriorityQueue::Compare->new(sub { ... })
41              
42             Create a new, empty priority queue. Requires a reference to a comparison
43             function. The example above sorts items in reverse alphabetical order.
44             If your items are hashes containing a weight key, use this:
45              
46             sub { $a->{weight} <=> $b->{weight} }
47              
48             If you are storing objects that have their own comparison function:
49              
50             sub { $a->cmp($b) }
51              
52             If the order of the objects changes after they are added to the queue,
53             you will need to call restore_order to repair the queue data structure.
54              
55             =cut
56              
57             my %funcs;
58              
59             sub new {
60 1     1 1 14 my ($class, $compare) = @_;
61 1 50       4 croak "Comparison function required" unless ref($compare) eq 'CODE';
62              
63             # This nonsense is necessary so that Array::Heap will put its $a and $b
64             # values in the caller's package instead of this module's package.
65 1   50     4 my $pkg = caller || 'main';
66 1 50 33     134 my $f = $funcs{$pkg} ||= eval "package $pkg;" . q{[
67             sub { &Array::Heap::push_heap_cmp },
68             sub { &Array::Heap::pop_heap_cmp },
69             sub { &Array::Heap::make_heap_cmp },
70             sub { my ($cmp, $heap) = @_; sort $cmp @$heap },
71             ]} or die "Compile failed: $@";
72             # If you're writing your own module that uses Array::Heap, and your
73             # comparison function is located in the current package, you don't
74             # need this trick. Just call the Array::Heap functions directly.
75              
76 1         8 return bless { cmp => $compare, heap => [ ], push => $f->[0],
77             pop => $f->[1], make => $f->[2], sort => $f->[3] } => $class;
78             }
79              
80             =item $pq->add($item)
81              
82             Add an item to the priority queue.
83              
84             =cut
85              
86             sub add {
87 1     1 1 3 my ($self, $item) = @_;
88 1         31 $self->{push}->($self->{cmp}, $self->{heap}, $item);
89             }
90              
91             =item $pq->peek()
92              
93             Return the first (lowest weight) item from the queue.
94             Does not modify the queue. Returns undef if the queue is empty.
95              
96             =cut
97              
98             sub peek {
99 1     1 1 426 my ($self) = @_;
100 1         5 return $self->{heap}[0];
101             }
102              
103             =item $pq->get()
104              
105             Removes the first item from the priority queue and returns it.
106             Returns undef if the queue is empty.
107              
108             If two items in the queue have equal weight, this module makes no guarantee
109             as to which one will be returned first. If this is a problem for you,
110             record the order that elements are added to the queue and use that to
111             break ties.
112              
113             my $pq = Array::Heap::PriorityQueue::Compare->new(sub {
114             $a->{weight} <=> $b->{weight} || $a->{order} <=> $b->{order} });
115             my $order = 0;
116             foreach my $item (@items) {
117             $item->{order} = ++$order;
118             $pq->add_unordered($item);
119             }
120             $pq->restore_order();
121              
122             =cut
123              
124             sub get {
125 1     1 1 3 my ($self) = @_;
126 1         31 return $self->{pop}->($self->{cmp}, $self->{heap});
127             }
128              
129             =item $pq->size()
130              
131             Returns the number of items in the priority queue.
132              
133             =cut
134              
135             sub size {
136 1     1 1 7 my ($self) = @_;
137 1         2 return scalar @{$self->{heap}};
  1         6  
138             }
139              
140             =item $pq->items()
141              
142             Returns all items in the heap, in an arbitrary order.
143              
144             =cut
145              
146             sub items {
147 1     1 1 2 my ($self) = @_;
148 1         0 return @{$self->{heap}};
  1         7  
149             }
150              
151             =item $pq->sorted_items()
152              
153             Returns all items in the heap, in weight order.
154              
155             =cut
156              
157             sub sorted_items {
158 1     1 1 2 my ($self) = @_;
159 1         32 return $self->{sort}->($self->{cmp}, $self->{heap});
160             }
161              
162             =item $pq->add_unordered($item)
163              
164             Add an item to the priority queue without updating the heap structure.
165             If you are adding a bunch of items at once, it may be more efficient to
166             use add_unordered, then call $pq->restore_order() once you are done.
167              
168             =cut
169              
170             sub add_unordered {
171 3     3 1 577 my ($self, $item) = @_;
172 3         4 push @{$self->{heap}}, $item;
  3         7  
173             }
174              
175             =item $pq->restore_order()
176              
177             Restore the heap structure after calling add_unordered. You need to do this
178             before calling any of the ordered methods (add, peek, or get).
179              
180             =cut
181              
182             sub restore_order {
183 1     1 1 4 my ($self) = @_;
184 1         31 $self->{make}->($self->{cmp}, $self->{heap});
185             }
186              
187             =back
188              
189             =head1 SEE ALSO
190              
191             L
192              
193             =head1 AUTHOR
194              
195             Bob Mathews
196              
197             =head1 REPOSITORY
198              
199             L
200              
201             =head1 COPYRIGHT
202              
203             This program is free software; you can redistribute
204             it and/or modify it under the same terms as Perl itself.
205              
206             The full text of the license can be found in the
207             LICENSE file included with this module.
208              
209             =cut
210              
211             1 # end Compare.pm