File Coverage

lib/AnyEvent/Tools/Pool.pm
Criterion Covered Total %
statement 73 77 94.8
branch 15 26 57.6
condition 2 6 33.3
subroutine 11 11 100.0
pod 0 4 0.0
total 101 124 81.4


line stmt bran cond sub pod time code
1 1     1   5 use utf8;
  1         1  
  1         8  
2 1     1   24 use strict;
  1         2  
  1         61  
3 1     1   5 use warnings;
  1         3  
  1         63  
4              
5             package AnyEvent::Tools::Pool;
6 1     1   15 use Carp;
  1         2  
  1         80  
7 1     1   5 use AnyEvent::Util;
  1         2  
  1         832  
8              
9             sub new
10             {
11 2     2 0 5 my $class = shift;
12              
13 2   33     27 my $self = bless {
14             pool => {},
15             no => 0,
16             queue => [],
17             free => [],
18             delete => [],
19              
20             } => ref($class) || $class;
21              
22 2         10 $self->push($_) for @_;
23              
24 2         7 return $self;
25             }
26              
27              
28             sub delete
29             {
30 1     1 0 202944 my ($self, $no, $cb) = @_;
31 1 50       14 croak "Can't find object: $no" unless exists $self->{pool}{$no};
32 1 50 33     21 croak "Callback must be CODEREF" if $cb and ref($cb) ne 'CODE';
33 1         4 push @{ $self->{delete} }, [ $no, $cb ];
  1         10  
34 1         9 $self->_check_pool;
35 1         3 return;
36             }
37              
38             sub push :method
39             {
40 5 50   5 0 17 croak 'usage: $pool->push($object)' unless @_ == 2;
41 5         9 my ($self, $object) = @_;
42 5         15 my $no = $self->{no}++;
43 5         7 push @{ $self->{free} }, $no;
  5         9  
44 5         15 $self->{pool}{$no} = $object;
45 5         11 $self->_check_pool;
46 5         17 return $no;
47             }
48              
49              
50             sub get
51             {
52 51 50   51 0 791 croak 'usage: $pool->get(sub { ($g, $o) = @_ .. })' unless @_ == 2;
53 51         66 my ($self, $cb) = @_;
54 51 50       103 croak 'Callback must be coderef', unless 'CODE' eq ref $cb;
55 51         52 push @{ $self->{queue} }, $cb;
  51         91  
56 51         96 $self->_check_pool;
57 51         133 return;
58             }
59              
60             sub _check_pool
61             {
62 109     109   277 my ($self) = @_;
63              
64 109 100       149 return unless @{ $self->{free} };
  109         418  
65              
66             # delete object
67 61 100       81 if (@{ $self->{delete} }) {
  61         207  
68 1         11 CHECK_CYCLE:
69 1         2 for (my $di = $#{ $self->{delete} }; $di >= 0; $di--) {
70 1         3 for (my $fi = $#{ $self->{free} }; $fi >= 0; $fi--) {
  1         7  
71 1 50       8 if ($self->{free}[$fi] == $self->{delete}[$di][0]) {
72 1         3 my ($no, $cb) = @{ $self->{delete}[$di] };
  1         5  
73 1         4 splice @{ $self->{free} }, $fi, 1;
  1         5  
74 1         2 splice @{ $self->{delete} }, $di, 1;
  1         4  
75 1         6 delete $self->{pool}{$no};
76 1 50       5 if ($cb) {
77 1         4 $cb->();
78 1 50       23 goto &_check_pool if $self;
79 0         0 return;
80             }
81 0         0 next CHECK_CYCLE;
82             }
83             }
84             }
85              
86 0 0       0 return unless @{ $self->{free} };
  0         0  
87             }
88              
89 60 100       84 return unless @{ $self->{queue} };
  60         189  
90              
91 51         75 my $ono = shift @{ $self->{free} };
  51         127  
92 51         122 my $cb = shift @{ $self->{queue} };
  51         230  
93              
94             my $guard = guard {
95 51 50   51   4216144 if ($self) { # can be destroyed
96 51         145 push @{ $self->{free} }, $ono;
  51         255  
97 51         229 $self->_check_pool;
98             }
99 51         470 };
100              
101 51         337 $cb->($guard, $self->{pool}{$ono});
102             }
103             1;