File Coverage

blib/lib/Heap/Priority.pm
Criterion Covered Total %
statement 103 104 99.0
branch 39 42 92.8
condition 2 4 50.0
subroutine 18 19 94.7
pod 15 16 93.7
total 177 185 95.6


line stmt bran cond sub pod time code
1             package Heap::Priority;
2 1     1   5563 use Carp;
  1         2  
  1         49  
3 1     1   4 use strict;
  1         1  
  1         32  
4 1     1   5 use vars '$VERSION';
  1         7  
  1         1075  
5             $VERSION = 0.01;
6              
7             sub new {
8 1     1 1 78 my $class = shift;
9 1         7 my $defaults = { '.priorities' => [],
10             '.fifo' => 1,
11             '.highest_first' => 1,
12             '.raise_error' => 0,
13             '.error_message' => '' };
14 1         5 return bless $defaults, $class;
15             }
16              
17 1     1 1 40 sub fifo { $_[0]->{'.fifo'} = 1 }
18 1     1 1 36 sub lifo { $_[0]->{'.fifo'} = 0 }
19 1     1 1 34 sub highest_first { $_[0]->{'.highest_first'} = 1 }
20 1     1 1 34 sub lowest_first { $_[0]->{'.highest_first'} = 0 }
21 0   0 0 1 0 sub raise_error { $_[0]->{'.raise_error'} = shift || 0 }
22              
23             sub add {
24 33     33 1 283 my ($self, $item, $priority) = @_;
25 33   100     96 $priority ||= 0;
26 33 100       59 unless (defined $item) {
27 1         4 $self->error("Need to supply an item to add to heap!\n");
28 1         2 return undef;
29             }
30 32         30 push @{$self->{'.items'}->{$item}}, $priority;
  32         110  
31             # we need to re-sort priorities if new priority level supplied with item
32 32 100       77 $self->{'.priorities'} = [ sort { $a <=> $b } ( @{$self->{'.priorities'}}, $priority ) ]
  4         15  
  5         17  
33             unless exists $self->{'.heap'}->{$priority};
34 32         34 push @{$self->{'.heap'}->{$priority}}, $item;
  32         110  
35             }
36              
37             sub pop {
38 4     4 1 97 my $self = shift;
39 4         5 my @priorities = @{$self->{'.priorities'}};
  4         11  
40 4 100       10 return undef unless @priorities;
41 3 50       15 my $priority = $self->{'.highest_first'} ? pop @priorities :
42             shift @priorities;
43 2         5 my $item = $self->{'.fifo'} ? shift @{$self->{'.heap'}->{$priority}}:
  1         3  
44 3 100       8 pop @{$self->{'.heap'}->{$priority}};
45 3         9 $self->delete_item($item, $priority, 1);
46 3         10 return $item;
47             }
48              
49             sub delete_priority_level {
50 6     6 1 46 my ($self, $priority) = @_;
51 6 100       15 if (exists $self->{'.heap'}->{$priority}) {
52 5         6 my @items = @{$self->{'.heap'}->{$priority}};
  5         16  
53 5         25 delete $self->{'.items'}->{$_} for @items;
54 5         11 delete $self->{'.heap'}->{$priority};
55 5         5 $self->{'.priorities'} = [ grep { $_ ne $priority } @{$self->{'.priorities'}} ];
  9         30  
  5         9  
56             } else {
57 1         5 $self->error("Priority level $priority does not exist in heap!\n");
58             }
59             }
60              
61             sub delete_item {
62 10     10 1 125 my ($self, $item, $priority, $_off_heap) = @_;
63 10 100       28 unless (exists $self->{'.items'}->{$item}) {
64 1         5 $self->error("Item $item does not exist in heap!\n");
65 1         2 return undef;
66             }
67 9 100       17 if (defined $priority) {
68             # remove item from from appropriate priority level of .heap
69 5 100       11 @{$self->{'.heap'}->{$priority}} = grep{$_ ne $item}@{$self->{'.heap'}->{$priority}}
  2         22  
  44         68  
  2         6  
70             unless $_off_heap;
71             # remove item priority level from .items
72 5         9 @{$self->{'.items'}->{$item}} = grep {$_ ne $priority} @{$self->{'.items'}->{$item}};
  5         43  
  8         20  
  5         11  
73             # remove item if it no longer exists on any priority levels
74 5 100       7 delete $self->{'.items'}->{$item} unless @{$self->{'.items'}->{$item}};
  5         19  
75             # remove priority level if it is now empty as a result or deleting item
76 5 100       6 $self->delete_priority_level($priority) unless @{$self->{'.heap'}->{$priority}};
  5         20  
77             } else {
78 4         6 for my $priority (@{$self->{'.items'}->{$item}}) {
  4         12  
79             # remove item from from appropriate priority level of .heap
80 6         7 @{$self->{'.heap'}->{$priority}} = grep{$_ ne $item}@{$self->{'.heap'}->{$priority}};
  6         33  
  72         107  
  6         14  
81             # remove priority level if empty
82 6 100       10 $self->delete_priority_level($priority) unless @{$self->{'.heap'}->{$priority}};
  6         49  
83             }
84             # bye bye item, you are gone
85 4         16 delete $self->{'.items'}->{$item};
86             }
87             }
88              
89             sub modify_priority {
90 2     2 1 40 my ($self, $item, $priority) = @_;
91 2 100       8 unless (exists $self->{'.items'}->{$item}) {
92 1         4 $self->error("Item $item does not exist in heap!\n");
93 1         2 return undef;
94             }
95 1         3 $self->delete_item($item);
96 1         3 $self->add($item, $priority);
97             }
98              
99             sub get_priority_levels {
100 20     20 1 156 my $self = shift;
101 20         21 my @levels = @{$self->{'.priorities'}};
  20         56  
102 20 100       48 @levels = reverse @levels if $self->{'.highest_first'};
103 20 100       69 return wantarray ? @levels : scalar @levels;
104             }
105              
106             sub get_level {
107 22     22 1 117 my ($self, $priority) = @_;
108 22 100       50 unless (exists $self->{'.heap'}->{$priority}) {
109 1         4 $self->error("Priority level $priority does not exist on heap!\n");
110 1         2 return undef;
111             }
112 21         22 my @items = @{$self->{'.heap'}->{$priority}};
  21         113  
113 21 100       48 @items = reverse @items unless $self->{'.fifo'};
114 21 100       168 return wantarray ? @items : scalar @items;
115             }
116              
117             sub get_heap {
118 14     14 1 134 my $self = shift;
119 14         22 my @heap = ();
120 14         24 my @levels = $self->get_priority_levels();
121 14         34 push @heap, $self->get_level($_) for @levels;
122 14 100       154 return wantarray ? @heap : scalar @heap;
123             }
124              
125             sub error {
126 5     5 0 8 my ($self, $error) = @_;
127 5         9 $self->{'.error_message'} .= $error;
128 5 50       11 croak $self->{'.error_message'} if $self->{'.raise_error'} == 2;
129 5 50       16 carp $self->{'.error_message'} if $self->{'.raise_error'} == 1;
130             }
131              
132 5     5 1 26 sub err_str { return $_[0]->{'.error_message'} }
133              
134             1;
135             __END__