| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Array::AsHash; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 4 |  |  | 4 |  | 97865 | use warnings; | 
|  | 4 |  |  |  |  | 10 |  | 
|  | 4 |  |  |  |  | 173 |  | 
| 4 | 4 |  |  | 4 |  | 29 | use strict; | 
|  | 4 |  |  |  |  | 10 |  | 
|  | 4 |  |  |  |  | 150 |  | 
| 5 | 4 |  |  | 4 |  | 3544 | use Clone (); | 
|  | 4 |  |  |  |  | 14128 |  | 
|  | 4 |  |  |  |  | 125 |  | 
| 6 | 4 |  |  | 4 |  | 49 | use Scalar::Util qw(refaddr); | 
|  | 4 |  |  |  |  | 11 |  | 
|  | 4 |  |  |  |  | 825 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | our $VERSION = '0.32'; | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | my ( $_bool, $_to_string ); | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | BEGIN { | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | # these are defined in a BEGIN block because otherwise, overloading | 
| 15 |  |  |  |  |  |  | # doesn't get them in time. | 
| 16 |  |  |  |  |  |  | $_bool = sub { | 
| 17 | 39 |  |  | 39 |  | 368 | my $self = CORE::shift; | 
| 18 | 39 |  |  |  |  | 211 | return $self->acount; | 
| 19 | 4 |  |  | 4 |  | 24 | }; | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | $_to_string = sub { | 
| 22 | 4 |  |  | 4 |  | 26 | no warnings 'once'; | 
|  | 4 |  |  |  |  | 8 |  | 
|  | 4 |  |  |  |  | 696 |  | 
| 23 | 3 |  |  | 3 |  | 3058 | require Data::Dumper; | 
| 24 | 3 |  |  |  |  | 7244 | local $Data::Dumper::Indent = 0; | 
| 25 | 3 |  |  |  |  | 7 | local $Data::Dumper::Terse  = 1; | 
| 26 | 3 |  |  |  |  | 6 | my $self   = CORE::shift; | 
| 27 | 3 |  |  |  |  | 5 | my $string = ''; | 
| 28 | 3 | 50 |  |  |  | 85 | return $string unless $self; | 
| 29 | 3 |  |  |  |  | 12 | while ( my ( $k, $v ) = $self->each ) { | 
| 30 |  |  |  |  |  |  |  | 
| 31 | 8 |  |  |  |  | 17 | foreach ( $k, $v ) { | 
| 32 | 16 | 100 |  |  |  | 38 | $_ = ref $_ ? Data::Dumper::Dumper($_) : $_; | 
| 33 |  |  |  |  |  |  | } | 
| 34 | 8 |  |  |  |  | 163 | $string .= "$k\n        $v\n"; | 
| 35 |  |  |  |  |  |  | } | 
| 36 | 3 |  |  |  |  | 23 | return $string; | 
| 37 | 4 |  |  |  |  | 114 | }; | 
| 38 |  |  |  |  |  |  | } | 
| 39 |  |  |  |  |  |  |  | 
| 40 | 4 |  |  | 4 |  | 7308 | use overload bool => $_bool, '""' => $_to_string, fallback => 1; | 
|  | 4 |  |  |  |  | 4724 |  | 
|  | 4 |  |  |  |  | 27 |  | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | my $_actual_key = sub { | 
| 43 |  |  |  |  |  |  | my ( $self, $key ) = @_; | 
| 44 |  |  |  |  |  |  | if ( ref $key ) { | 
| 45 |  |  |  |  |  |  | my $new_key = $self->{curr_key_of}{ refaddr $key}; | 
| 46 |  |  |  |  |  |  | return refaddr $key unless defined $new_key; | 
| 47 |  |  |  |  |  |  | $key = $new_key; | 
| 48 |  |  |  |  |  |  | } | 
| 49 |  |  |  |  |  |  | return $key; | 
| 50 |  |  |  |  |  |  | }; | 
| 51 |  |  |  |  |  |  |  | 
| 52 |  |  |  |  |  |  | # private because it doesn't match expectations.  The "index" of a | 
| 53 |  |  |  |  |  |  | # non-existent key is one greater than the current list | 
| 54 |  |  |  |  |  |  | my $_index = sub { | 
| 55 |  |  |  |  |  |  | my ( $self, $key ) = @_; | 
| 56 |  |  |  |  |  |  | my $index = | 
| 57 |  |  |  |  |  |  | $self->exists($key) | 
| 58 |  |  |  |  |  |  | ? $self->{index_of}{$key} | 
| 59 |  |  |  |  |  |  | : scalar @{ $self->{array_for} };    # automatically one greater | 
| 60 |  |  |  |  |  |  | return $index; | 
| 61 |  |  |  |  |  |  | }; | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | my $_croak = sub { | 
| 64 |  |  |  |  |  |  | my ( $proto, $message ) = @_; | 
| 65 |  |  |  |  |  |  | require Carp; | 
| 66 |  |  |  |  |  |  | Carp::croak($message); | 
| 67 |  |  |  |  |  |  | }; | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | my $_validate_kv_pairs = sub { | 
| 70 |  |  |  |  |  |  | my ( $self, $arg_for ) = @_; | 
| 71 |  |  |  |  |  |  | my $sub = $arg_for->{sub} || ( caller(1) )[3]; | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | if ( @{ $arg_for->{pairs} } % 2 ) { | 
| 74 |  |  |  |  |  |  | $self->$_croak("Arguments to $sub must be an even-sized list"); | 
| 75 |  |  |  |  |  |  | } | 
| 76 |  |  |  |  |  |  | }; | 
| 77 |  |  |  |  |  |  |  | 
| 78 |  |  |  |  |  |  | sub new { | 
| 79 | 35 |  |  | 35 | 1 | 17179 | my $class = shift; | 
| 80 | 35 |  |  |  |  | 120 | return $class->_initialize(@_); | 
| 81 |  |  |  |  |  |  | } | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | sub _initialize { | 
| 84 | 35 |  |  | 35 |  | 58 | my ( $class, $arg_ref ) = @_; | 
| 85 | 35 |  |  |  |  | 95 | my $self = bless {} => $class; | 
| 86 | 35 |  |  |  |  | 223 | $self->{array_for} = []; | 
| 87 | 35 | 100 |  |  |  | 123 | return $self unless $arg_ref; | 
| 88 | 25 |  | 100 |  |  | 78 | my $array = $arg_ref->{array} || []; | 
| 89 | 25 |  |  |  |  | 62 | $self->{is_strict} = $arg_ref->{strict}; | 
| 90 | 25 | 100 |  |  |  | 217 | $array = Clone::clone($array) if $arg_ref->{clone}; | 
| 91 |  |  |  |  |  |  |  | 
| 92 | 25 | 100 |  |  |  | 86 | unless ( 'ARRAY' eq ref $array ) { | 
| 93 | 1 |  |  |  |  | 5 | $class->$_croak('Argument to new() must be an array reference'); | 
| 94 |  |  |  |  |  |  | } | 
| 95 | 24 | 100 |  |  |  | 83 | if ( @$array % 2 ) { | 
| 96 | 1 |  |  |  |  | 4 | $class->$_croak('Uneven number of keys in array'); | 
| 97 |  |  |  |  |  |  | } | 
| 98 |  |  |  |  |  |  |  | 
| 99 | 23 |  |  |  |  | 44 | $self->{array_for} = $array; | 
| 100 | 23 |  |  |  |  | 86 | foreach ( my $i = 0; $i < @$array; $i += 2 ) { | 
| 101 | 56 |  |  |  |  | 79 | my $key = $array->[$i]; | 
| 102 | 56 |  |  |  |  | 156 | $self->{index_of}{$key} = $i; | 
| 103 | 56 | 100 |  |  |  | 192 | if ( ref $key ) { | 
| 104 | 4 |  |  |  |  | 964 | my $old_address = refaddr $arg_ref->{array}[$i]; | 
| 105 | 4 |  |  |  |  | 11 | my $curr_key    = "$key"; | 
| 106 | 4 |  |  |  |  | 29 | $self->{curr_key_of}{$old_address} = $curr_key; | 
| 107 |  |  |  |  |  |  | } | 
| 108 |  |  |  |  |  |  | } | 
| 109 | 23 |  |  |  |  | 81 | return $self; | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | sub get { | 
| 113 | 83 |  |  | 83 | 1 | 879 | my ( $self, @keys ) = @_; | 
| 114 | 83 |  |  |  |  | 90 | my @get; | 
| 115 | 83 |  |  |  |  | 136 | foreach my $key (@keys) { | 
| 116 | 86 |  |  |  |  | 185 | $key = $self->$_actual_key($key); | 
| 117 | 86 | 50 |  |  |  | 186 | next unless defined $key; | 
| 118 | 86 |  |  |  |  | 178 | my $exists = $self->exists($key); | 
| 119 | 86 | 100 | 100 |  |  | 264 | if ( $self->{is_strict} && !$exists ) { | 
| 120 | 1 |  |  |  |  | 4 | $self->$_croak("Cannot get non-existent key ($key)"); | 
| 121 |  |  |  |  |  |  | } | 
| 122 | 85 | 100 |  |  |  | 182 | if ($exists) { | 
|  |  | 100 |  |  |  |  |  | 
| 123 | 72 |  |  |  |  | 163 | CORE::push @get, $self->{array_for}[ $self->$_index($key) + 1 ]; | 
| 124 |  |  |  |  |  |  | } | 
| 125 |  |  |  |  |  |  | elsif ( @keys > 1 ) { | 
| 126 | 1 |  |  |  |  | 3 | CORE::push @get, undef; | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  | else { | 
| 129 | 12 |  |  |  |  | 63 | return; | 
| 130 |  |  |  |  |  |  | } | 
| 131 |  |  |  |  |  |  | } | 
| 132 |  |  |  |  |  |  | return wantarray ? @get | 
| 133 | 70 | 100 |  |  |  | 419 | : @keys > 1    ? \@get | 
|  |  | 100 |  |  |  |  |  | 
| 134 |  |  |  |  |  |  | : $get[0]; | 
| 135 |  |  |  |  |  |  | } | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | my $_insert = sub { | 
| 138 |  |  |  |  |  |  | my ( $self, $key, $label, $index ) = splice @_, 0, 4; | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | $self->$_validate_kv_pairs( | 
| 141 |  |  |  |  |  |  | { pairs => \@_, sub => "Array::AsHash::insert_$label" } ); | 
| 142 |  |  |  |  |  |  | $key = $self->$_actual_key($key); | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | unless ( $self->exists($key) ) { | 
| 145 |  |  |  |  |  |  | $self->$_croak("Cannot insert $label non-existent key ($key)"); | 
| 146 |  |  |  |  |  |  | } | 
| 147 |  |  |  |  |  |  | foreach ( my $i = 0; $i < @_; $i += 2 ) { | 
| 148 |  |  |  |  |  |  | my $new_key = $_[$i]; | 
| 149 |  |  |  |  |  |  | if ( $self->exists($new_key) ) { | 
| 150 |  |  |  |  |  |  | $self->$_croak("Cannot insert duplicate key ($new_key)"); | 
| 151 |  |  |  |  |  |  | } | 
| 152 |  |  |  |  |  |  | $self->{index_of}{$new_key} = $index + $i; | 
| 153 |  |  |  |  |  |  | } | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | my @tail = splice @{ $self->{array_for} }, $index; | 
| 156 |  |  |  |  |  |  | push @{ $self->{array_for} }, @_, @tail; | 
| 157 |  |  |  |  |  |  | my %seen = @_; | 
| 158 |  |  |  |  |  |  | foreach my $curr_key ( CORE::keys %{ $self->{index_of} } ) { | 
| 159 |  |  |  |  |  |  | if ( $self->{index_of}{$curr_key} >= $index | 
| 160 |  |  |  |  |  |  | && !exists $seen{$curr_key} ) | 
| 161 |  |  |  |  |  |  | { | 
| 162 |  |  |  |  |  |  | $self->{index_of}{$curr_key} += @_; | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  | } | 
| 165 |  |  |  |  |  |  | return $self; | 
| 166 |  |  |  |  |  |  | }; | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | sub strict { | 
| 169 | 4 |  |  | 4 | 1 | 1004 | my $self = shift; | 
| 170 | 4 | 100 |  |  |  | 15 | return $self->{is_strict} unless @_; | 
| 171 | 2 |  |  |  |  | 3 | $self->{is_strict} = !!shift; | 
| 172 | 2 |  |  |  |  | 6 | return $self; | 
| 173 |  |  |  |  |  |  | } | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | sub clone { | 
| 176 | 1 |  |  | 1 | 1 | 343 | my $self = CORE::shift; | 
| 177 | 1 |  |  |  |  | 5 | return ( ref $self )->new( | 
| 178 |  |  |  |  |  |  | {   array => scalar $self->get_array, | 
| 179 |  |  |  |  |  |  | clone => 1, | 
| 180 |  |  |  |  |  |  | } | 
| 181 |  |  |  |  |  |  | ); | 
| 182 |  |  |  |  |  |  | } | 
| 183 |  |  |  |  |  |  |  | 
| 184 |  |  |  |  |  |  | sub unshift { | 
| 185 | 3 |  |  | 3 | 1 | 537 | my ( $self, @kv_pairs ) = @_; | 
| 186 | 3 |  |  |  |  | 14 | $self->$_validate_kv_pairs( { pairs => \@kv_pairs } ); | 
| 187 | 3 |  |  |  |  | 7 | foreach my $curr_key ( CORE::keys %{ $self->{index_of} } ) { | 
|  | 3 |  |  |  |  | 13 |  | 
| 188 | 2 |  |  |  |  | 8 | $self->{index_of}{$curr_key} += @kv_pairs; | 
| 189 |  |  |  |  |  |  | } | 
| 190 | 3 |  |  |  |  | 15 | for ( my $i = 0; $i < @kv_pairs; $i += 2 ) { | 
| 191 | 5 |  |  |  |  | 12 | my ( $key, $value ) = @kv_pairs[ $i, $i + 1 ]; | 
| 192 | 5 | 50 |  |  |  | 19 | if ( $self->exists($key) ) { | 
| 193 | 0 |  |  |  |  | 0 | $self->$_croak("Cannot unshift an existing key ($key)"); | 
| 194 |  |  |  |  |  |  | } | 
| 195 | 5 |  |  |  |  | 21 | $self->{index_of}{$key} = $i; | 
| 196 |  |  |  |  |  |  | } | 
| 197 | 3 |  |  |  |  | 6 | unshift @{ $self->{array_for} }, @kv_pairs; | 
|  | 3 |  |  |  |  | 19 |  | 
| 198 |  |  |  |  |  |  | } | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | sub push { | 
| 201 | 6 |  |  | 6 | 1 | 562 | my ( $self, @kv_pairs ) = @_; | 
| 202 | 6 |  |  |  |  | 31 | $self->$_validate_kv_pairs( { pairs => \@kv_pairs } ); | 
| 203 | 6 |  |  |  |  | 23 | my @array = $self->get_array; | 
| 204 | 6 |  |  |  |  | 23 | for ( my $i = 0; $i < @kv_pairs; $i += 2 ) { | 
| 205 | 13 |  |  |  |  | 28 | my ( $key, $value ) = @kv_pairs[ $i, $i + 1 ]; | 
| 206 | 13 | 50 |  |  |  | 32 | if ( $self->exists($key) ) { | 
| 207 | 0 |  |  |  |  | 0 | $self->$_croak("Cannot push an existing key ($key)"); | 
| 208 |  |  |  |  |  |  | } | 
| 209 | 13 |  |  |  |  | 67 | $self->{index_of}{$key} = @array + $i; | 
| 210 |  |  |  |  |  |  | } | 
| 211 | 6 |  |  |  |  | 7 | CORE::push @{ $self->{array_for} }, @kv_pairs; | 
|  | 6 |  |  |  |  | 34 |  | 
| 212 |  |  |  |  |  |  | } | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | sub pop { | 
| 215 | 3 |  |  | 3 | 1 | 597 | my $self = shift; | 
| 216 | 3 | 100 |  |  |  | 11 | return unless $self; | 
| 217 | 2 |  |  |  |  | 4 | my ( $key, $value ) = splice @{ $self->{array_for} }, -2; | 
|  | 2 |  |  |  |  | 7 |  | 
| 218 | 2 |  |  |  |  | 5 | delete $self->{index_of}{$key}; | 
| 219 | 2 | 100 |  |  |  | 11 | return wantarray ? ( $key, $value ) : [ $key, $value ]; | 
| 220 |  |  |  |  |  |  | } | 
| 221 |  |  |  |  |  |  |  | 
| 222 |  |  |  |  |  |  | sub shift { | 
| 223 | 3 |  |  | 3 | 1 | 535 | my $self = CORE::shift; | 
| 224 | 3 | 100 |  |  |  | 8 | return unless $self; | 
| 225 | 2 |  |  |  |  | 4 | foreach my $curr_key ( CORE::keys %{ $self->{index_of} } ) { | 
|  | 2 |  |  |  |  | 8 |  | 
| 226 | 3 |  |  |  |  | 8 | $self->{index_of}{$curr_key} -= 2; | 
| 227 |  |  |  |  |  |  | } | 
| 228 | 2 |  |  |  |  | 5 | my ( $key, $value ) = splice @{ $self->{array_for} }, 0, 2; | 
|  | 2 |  |  |  |  | 6 |  | 
| 229 | 2 |  |  |  |  | 6 | delete $self->{index_of}{$key}; | 
| 230 | 2 | 100 |  |  |  | 10 | return wantarray ? ( $key, $value ) : [ $key, $value ]; | 
| 231 |  |  |  |  |  |  | } | 
| 232 |  |  |  |  |  |  |  | 
| 233 |  |  |  |  |  |  | sub hcount { | 
| 234 | 4 |  |  | 4 | 1 | 11 | my $self  = CORE::shift; | 
| 235 | 4 |  |  |  |  | 10 | my $count = $self->acount; | 
| 236 | 4 |  |  |  |  | 21 | return $count / 2; | 
| 237 |  |  |  |  |  |  | } | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | sub acount { | 
| 240 | 60 |  |  | 60 | 1 | 889 | my $self  = CORE::shift; | 
| 241 | 60 |  |  |  |  | 137 | my @array = $self->get_array; | 
| 242 | 60 |  |  |  |  | 283 | return scalar @array; | 
| 243 |  |  |  |  |  |  | } | 
| 244 |  |  |  |  |  |  |  | 
| 245 |  |  |  |  |  |  | sub hindex { | 
| 246 | 2 |  |  | 2 | 1 | 4 | my $self  = CORE::shift; | 
| 247 | 2 |  |  |  |  | 5 | my $index = $self->aindex(CORE::shift); | 
| 248 | 2 | 100 |  |  |  | 13 | return defined $index ? $index / 2 : (); | 
| 249 |  |  |  |  |  |  | } | 
| 250 |  |  |  |  |  |  |  | 
| 251 |  |  |  |  |  |  | sub aindex { | 
| 252 | 7 |  |  | 7 | 1 | 14 | my $self = CORE::shift; | 
| 253 | 7 |  |  |  |  | 17 | my $key  = $self->$_actual_key(CORE::shift); | 
| 254 | 7 | 100 |  |  |  | 35 | return unless $self->exists($key); | 
| 255 | 5 |  |  |  |  | 14 | return $self->$_index($key); | 
| 256 |  |  |  |  |  |  | } | 
| 257 |  |  |  |  |  |  |  | 
| 258 |  |  |  |  |  |  | sub keys { | 
| 259 | 21 |  |  | 21 | 1 | 705 | my $self  = CORE::shift; | 
| 260 | 21 |  |  |  |  | 55 | my @array = $self->get_array; | 
| 261 | 21 |  |  |  |  | 36 | my @keys; | 
| 262 | 21 |  |  |  |  | 69 | for ( my $i = 0; $i < @array; $i += 2 ) { | 
| 263 | 50 |  |  |  |  | 148 | CORE::push @keys, $array[$i]; | 
| 264 |  |  |  |  |  |  | } | 
| 265 | 21 | 100 |  |  |  | 151 | return wantarray ? @keys : \@keys; | 
| 266 |  |  |  |  |  |  | } | 
| 267 |  |  |  |  |  |  |  | 
| 268 |  |  |  |  |  |  | sub values { | 
| 269 | 19 |  |  | 19 | 1 | 2497 | my $self  = CORE::shift; | 
| 270 | 19 |  |  |  |  | 47 | my @array = $self->get_array; | 
| 271 | 19 |  |  |  |  | 33 | my @values; | 
| 272 | 19 |  |  |  |  | 68 | for ( my $i = 1; $i < @array; $i += 2 ) { | 
| 273 | 44 |  |  |  |  | 227 | CORE::push @values, $array[$i]; | 
| 274 |  |  |  |  |  |  | } | 
| 275 | 19 | 100 |  |  |  | 128 | return wantarray ? @values : \@values; | 
| 276 |  |  |  |  |  |  | } | 
| 277 |  |  |  |  |  |  |  | 
| 278 |  |  |  |  |  |  | sub first { | 
| 279 | 11 |  |  | 11 | 1 | 365 | my $self  = CORE::shift; | 
| 280 | 11 |  |  |  |  | 19 | my $index = $self->{current_index_for}; | 
| 281 | 11 |  | 100 |  |  | 113 | return defined $index && 2 == $index; | 
| 282 |  |  |  |  |  |  | } | 
| 283 |  |  |  |  |  |  |  | 
| 284 |  |  |  |  |  |  | sub last { | 
| 285 | 11 |  |  | 11 | 1 | 20 | my $self  = CORE::shift; | 
| 286 | 11 |  |  |  |  | 18 | my $index = $self->{current_index_for}; | 
| 287 | 11 |  | 100 |  |  | 57 | return defined $index && $self->acount == $index; | 
| 288 |  |  |  |  |  |  | } | 
| 289 |  |  |  |  |  |  |  | 
| 290 |  |  |  |  |  |  | sub each { | 
| 291 | 27 |  |  | 27 | 1 | 6335 | my $self = CORE::shift; | 
| 292 |  |  |  |  |  |  |  | 
| 293 |  |  |  |  |  |  | my $each = sub { | 
| 294 | 33 |  | 100 | 33 |  | 129 | my $index = $self->{current_index_for} || 0; | 
| 295 | 33 |  |  |  |  | 84 | my @array = $self->get_array; | 
| 296 | 33 | 100 |  |  |  | 95 | if ( $index >= @array ) { | 
| 297 | 6 |  |  |  |  | 23 | $self->reset_each; | 
| 298 | 6 |  |  |  |  | 40 | return; | 
| 299 |  |  |  |  |  |  | } | 
| 300 | 27 |  |  |  |  | 73 | my ( $key, $value ) = @array[ $index, $index + 1 ]; | 
| 301 | 4 |  |  | 4 |  | 8810 | no warnings 'uninitialized'; | 
|  | 4 |  |  |  |  | 10 |  | 
|  | 4 |  |  |  |  | 553 |  | 
| 302 | 27 |  |  |  |  | 49 | $self->{current_index_for} += 2; | 
| 303 | 27 |  |  |  |  | 180 | return ( $key, $value ); | 
| 304 | 27 |  |  |  |  | 116 | }; | 
| 305 |  |  |  |  |  |  |  | 
| 306 | 27 | 100 |  |  |  | 57 | if (wantarray) { | 
| 307 | 24 |  |  |  |  | 45 | return $each->(); | 
| 308 |  |  |  |  |  |  | } | 
| 309 |  |  |  |  |  |  | else { | 
| 310 | 3 |  |  |  |  | 1054 | require Array::AsHash::Iterator; | 
| 311 | 3 |  |  |  |  | 31 | return Array::AsHash::Iterator->new( | 
| 312 |  |  |  |  |  |  | {   parent   => $self, | 
| 313 |  |  |  |  |  |  | iterator => $each, | 
| 314 |  |  |  |  |  |  | } | 
| 315 |  |  |  |  |  |  | ); | 
| 316 |  |  |  |  |  |  | } | 
| 317 |  |  |  |  |  |  | } | 
| 318 |  |  |  |  |  |  | { | 
| 319 | 4 |  |  | 4 |  | 21 | no warnings 'once'; | 
|  | 4 |  |  |  |  | 8 |  | 
|  | 4 |  |  |  |  | 6141 |  | 
| 320 |  |  |  |  |  |  | *kv = \&each; | 
| 321 |  |  |  |  |  |  | } | 
| 322 |  |  |  |  |  |  |  | 
| 323 | 9 |  |  | 9 | 1 | 1356 | sub reset_each { CORE::shift->{current_index_for} = undef } | 
| 324 |  |  |  |  |  |  |  | 
| 325 |  |  |  |  |  |  | sub insert_before { | 
| 326 | 4 |  |  | 4 | 1 | 1974 | my $self  = CORE::shift; | 
| 327 | 4 |  |  |  |  | 8 | my $key   = CORE::shift; | 
| 328 | 4 |  |  |  |  | 11 | my $index = $self->$_index($key); | 
| 329 | 4 |  |  |  |  | 13 | $self->$_insert( $key, 'before', $index, @_ ); | 
| 330 |  |  |  |  |  |  | } | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | sub insert_after { | 
| 333 | 6 |  |  | 6 | 1 | 2358 | my $self  = CORE::shift; | 
| 334 | 6 |  |  |  |  | 10 | my $key   = CORE::shift; | 
| 335 | 6 |  |  |  |  | 15 | my $index = $self->$_index($key) + 2; | 
| 336 | 6 |  |  |  |  | 23 | $self->$_insert( $key, 'after', $index, @_ ); | 
| 337 |  |  |  |  |  |  | } | 
| 338 |  |  |  |  |  |  |  | 
| 339 |  |  |  |  |  |  | sub key_at { | 
| 340 | 7 |  |  | 7 | 1 | 469 | my $self = CORE::shift; | 
| 341 | 7 |  |  |  |  | 9 | my @keys; | 
| 342 | 7 |  |  |  |  | 16 | foreach my $index ( my @copy = @_ ) {    # prevent aliasing | 
| 343 | 9 |  |  |  |  | 12 | $index *= 2; | 
| 344 | 9 |  |  |  |  | 26 | CORE::push @keys => $self->{array_for}[$index]; | 
| 345 |  |  |  |  |  |  | } | 
| 346 |  |  |  |  |  |  | return wantarray ? @keys | 
| 347 | 7 | 50 |  |  |  | 46 | : 1 == @_      ? $keys[0] | 
|  |  | 100 |  |  |  |  |  | 
| 348 |  |  |  |  |  |  | : \@keys; | 
| 349 |  |  |  |  |  |  | } | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  | sub value_at { | 
| 352 | 8 |  |  | 8 | 1 | 19 | my $self = CORE::shift; | 
| 353 | 8 |  |  |  |  | 9 | my @values; | 
| 354 | 8 |  |  |  |  | 19 | foreach my $index ( my @copy = @_ ) {    # prevent aliasing | 
| 355 | 12 |  |  |  |  | 17 | $index = $index * 2 + 1; | 
| 356 | 12 |  |  |  |  | 30 | CORE::push @values => $self->{array_for}[$index]; | 
| 357 |  |  |  |  |  |  | } | 
| 358 |  |  |  |  |  |  | return wantarray ? @values | 
| 359 | 8 | 50 |  |  |  | 49 | : 1 == @_      ? $values[0] | 
|  |  | 100 |  |  |  |  |  | 
| 360 |  |  |  |  |  |  | : \@values; | 
| 361 |  |  |  |  |  |  | } | 
| 362 |  |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  | sub delete { | 
| 364 | 14 |  |  | 14 | 1 | 1112 | my $self     = CORE::shift; | 
| 365 | 14 |  |  |  |  | 22 | my $num_args = @_; | 
| 366 | 14 |  |  |  |  | 35 | my $key      = $self->$_actual_key(CORE::shift); | 
| 367 | 14 |  |  |  |  | 20 | my @value; | 
| 368 |  |  |  |  |  |  |  | 
| 369 | 14 | 100 |  |  |  | 32 | if ( $self->exists($key) ) { | 
|  |  | 100 |  |  |  |  |  | 
| 370 | 11 |  |  |  |  | 25 | my $index = $self->$_index($key); | 
| 371 | 11 |  |  |  |  | 29 | delete $self->{index_of}{$key}; | 
| 372 | 11 |  |  |  |  | 16 | my ( undef, $value ) = splice @{ $self->{array_for} }, $index, 2; | 
|  | 11 |  |  |  |  | 39 |  | 
| 373 | 11 |  |  |  |  | 23 | CORE::push @value, $value; | 
| 374 | 11 |  |  |  |  | 15 | foreach my $curr_key ( CORE::keys %{ $self->{index_of} } ) { | 
|  | 11 |  |  |  |  | 35 |  | 
| 375 | 17 | 100 |  |  |  | 52 | if ( $self->{index_of}{$curr_key} >= $index ) { | 
| 376 | 12 |  |  |  |  | 35 | $self->{index_of}{$curr_key} -= 2; | 
| 377 |  |  |  |  |  |  | } | 
| 378 |  |  |  |  |  |  | } | 
| 379 |  |  |  |  |  |  | } | 
| 380 |  |  |  |  |  |  | elsif ( $self->{is_strict} ) { | 
| 381 | 1 |  |  |  |  | 4 | $self->$_croak("Cannot delete non-existent key ($key)"); | 
| 382 |  |  |  |  |  |  | } | 
| 383 | 13 | 100 |  |  |  | 39 | if (@_) { | 
| 384 | 3 |  |  |  |  | 12 | CORE::push @value, $self->delete(@_); | 
| 385 |  |  |  |  |  |  | } | 
| 386 |  |  |  |  |  |  | return wantarray  ? @value | 
| 387 | 13 | 100 |  |  |  | 88 | : $num_args > 1 ? \@value | 
|  |  | 100 |  |  |  |  |  | 
| 388 |  |  |  |  |  |  | : $value[0]; | 
| 389 |  |  |  |  |  |  | } | 
| 390 |  |  |  |  |  |  |  | 
| 391 |  |  |  |  |  |  | sub clear { | 
| 392 | 1 |  |  | 1 | 1 | 6 | my $self = CORE::shift; | 
| 393 | 1 |  |  |  |  | 3 | for my $spec (qw) { | 
| 394 | 3 |  |  |  |  | 10 | $self->{$spec} = undef; | 
| 395 |  |  |  |  |  |  | } | 
| 396 | 1 |  |  |  |  | 3 | @{ $self->{array_for} } = (); | 
|  | 1 |  |  |  |  | 3 |  | 
| 397 | 1 |  |  |  |  | 5 | return $self; | 
| 398 |  |  |  |  |  |  | } | 
| 399 |  |  |  |  |  |  |  | 
| 400 |  |  |  |  |  |  | sub exists { | 
| 401 | 339 |  |  | 339 | 1 | 3672 | my ( $self, $key ) = @_; | 
| 402 | 339 |  |  |  |  | 516 | $key = $self->$_actual_key($key); | 
| 403 | 339 | 50 |  |  |  | 689 | return unless defined $key; | 
| 404 |  |  |  |  |  |  |  | 
| 405 | 339 |  |  |  |  | 1297 | return exists $self->{index_of}{$key}; | 
| 406 |  |  |  |  |  |  | } | 
| 407 |  |  |  |  |  |  |  | 
| 408 |  |  |  |  |  |  | sub rename { | 
| 409 | 3 |  |  | 3 | 1 | 772 | my ( $self, @pairs ) = @_; | 
| 410 | 3 |  |  |  |  | 13 | $self->$_validate_kv_pairs( { pairs => \@pairs } ); | 
| 411 |  |  |  |  |  |  |  | 
| 412 | 2 |  |  |  |  | 11 | foreach ( my $i = 0; $i < @pairs; $i += 2 ) { | 
| 413 | 3 |  |  |  |  | 7 | my ( $old, $new ) = @pairs[ $i, $i + 1 ]; | 
| 414 | 3 | 50 |  |  |  | 9 | unless ( $self->exists($old) ) { | 
| 415 | 0 |  |  |  |  | 0 | $self->$_croak("Cannot rename non-existent key ($old)"); | 
| 416 |  |  |  |  |  |  | } | 
| 417 | 3 | 50 |  |  |  | 9 | unless ( defined $new ) { | 
| 418 | 0 |  |  |  |  | 0 | $self->$_croak("Cannot rename ($old) to an undefined value"); | 
| 419 |  |  |  |  |  |  | } | 
| 420 | 3 | 50 |  |  |  | 7 | if ( $self->exists($new) ) { | 
| 421 | 0 |  |  |  |  | 0 | $self->$_croak( | 
| 422 |  |  |  |  |  |  | "Cannot rename ($old) to an key which already exists ($new)" | 
| 423 |  |  |  |  |  |  | ); | 
| 424 |  |  |  |  |  |  | } | 
| 425 | 3 |  |  |  |  | 8 | my $index = delete $self->{index_of}{$old}; | 
| 426 | 3 |  |  |  |  | 14 | $self->{index_of}{$new} = $index; | 
| 427 | 3 |  |  |  |  | 13 | $self->{array_for}[$index] = $new; | 
| 428 |  |  |  |  |  |  | } | 
| 429 | 2 |  |  |  |  | 10 | return $self; | 
| 430 |  |  |  |  |  |  | } | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  | sub get_pairs { | 
| 433 | 11 |  |  | 11 | 1 | 5873 | my ( $self, @keys ) = @_; | 
| 434 |  |  |  |  |  |  |  | 
| 435 | 11 |  |  |  |  | 14 | my @pairs; | 
| 436 | 11 |  |  |  |  | 20 | foreach my $key (@keys) { | 
| 437 | 20 | 100 |  |  |  | 38 | if ( $self->exists($key) ) { | 
|  |  | 100 |  |  |  |  |  | 
| 438 | 17 |  |  |  |  | 35 | CORE::push @pairs, $key, $self->get($key); | 
| 439 |  |  |  |  |  |  | } | 
| 440 |  |  |  |  |  |  | elsif ( $self->{is_strict} ) { | 
| 441 | 1 |  |  |  |  | 5 | $self->$_croak("Cannot get pair for non-existent key ($key)"); | 
| 442 |  |  |  |  |  |  | } | 
| 443 |  |  |  |  |  |  | } | 
| 444 | 10 | 100 |  |  |  | 46 | return wantarray ? @pairs : \@pairs; | 
| 445 |  |  |  |  |  |  | } | 
| 446 |  |  |  |  |  |  |  | 
| 447 |  |  |  |  |  |  | sub default { | 
| 448 | 3 |  |  | 3 | 1 | 330 | my ( $self, @pairs ) = @_; | 
| 449 | 3 |  |  |  |  | 12 | $self->$_validate_kv_pairs( { pairs => \@pairs } ); | 
| 450 |  |  |  |  |  |  |  | 
| 451 | 3 |  |  |  |  | 14 | for ( my $i = 0; $i < @pairs; $i += 2 ) { | 
| 452 | 5 |  |  |  |  | 8 | my ( $k, $v ) = @pairs[ $i, $i + 1 ]; | 
| 453 | 5 | 100 |  |  |  | 11 | next if $self->exists($k); | 
| 454 | 4 |  |  |  |  | 11 | $self->put( $k, $v ); | 
| 455 |  |  |  |  |  |  | } | 
| 456 | 3 |  |  |  |  | 8 | return $self; | 
| 457 |  |  |  |  |  |  | } | 
| 458 |  |  |  |  |  |  |  | 
| 459 |  |  |  |  |  |  | sub add { | 
| 460 | 2 |  |  | 2 | 1 | 825 | my ( $self, @pairs ) = @_; | 
| 461 | 2 |  |  |  |  | 9 | $self->$_validate_kv_pairs( { pairs => \@pairs } ); | 
| 462 |  |  |  |  |  |  |  | 
| 463 | 2 |  |  |  |  | 7 | for ( my $i = 0; $i < @pairs; $i += 2 ) { | 
| 464 | 2 |  |  |  |  | 4 | my ( $key, $value ) = @pairs[ $i, $i + 1 ]; | 
| 465 | 2 |  |  |  |  | 5 | $key = $self->$_actual_key($key); | 
| 466 | 2 | 100 |  |  |  | 3 | if ( $self->exists($key) ) { | 
| 467 | 1 |  |  |  |  | 5 | $self->$_croak("Cannot add existing key ($key)"); | 
| 468 |  |  |  |  |  |  | } | 
| 469 | 1 |  |  |  |  | 3 | my $index = $self->$_index($key); | 
| 470 | 1 |  |  |  |  | 3 | $self->{index_of}{$key}          = $index; | 
| 471 | 1 |  |  |  |  | 2 | $self->{array_for}[$index]       = $key; | 
| 472 | 1 |  |  |  |  | 4 | $self->{array_for}[ $index + 1 ] = $value; | 
| 473 |  |  |  |  |  |  | } | 
| 474 | 1 |  |  |  |  | 3 | return $self; | 
| 475 |  |  |  |  |  |  | } | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  | sub put { | 
| 478 | 18 |  |  | 18 | 1 | 2828 | my ( $self, @pairs ) = @_; | 
| 479 | 18 |  |  |  |  | 75 | $self->$_validate_kv_pairs( { pairs => \@pairs } ); | 
| 480 |  |  |  |  |  |  |  | 
| 481 | 18 |  |  |  |  | 69 | for ( my $i = 0; $i < @pairs; $i += 2 ) { | 
| 482 | 20 |  |  |  |  | 53 | my ( $key, $value ) = @pairs[ $i, $i + 1 ]; | 
| 483 | 20 |  |  |  |  | 42 | $key = $self->$_actual_key($key); | 
| 484 | 20 | 100 | 100 |  |  | 67 | if ( !$self->exists($key) && $self->{is_strict} ) { | 
| 485 | 2 |  |  |  |  | 6 | $self->$_croak("Cannot put a non-existent key ($key)"); | 
| 486 |  |  |  |  |  |  | } | 
| 487 | 18 |  |  |  |  | 47 | my $index = $self->$_index($key); | 
| 488 | 18 |  |  |  |  | 42 | $self->{index_of}{$key}          = $index; | 
| 489 | 18 |  |  |  |  | 37 | $self->{array_for}[$index]       = $key; | 
| 490 | 18 |  |  |  |  | 71 | $self->{array_for}[ $index + 1 ] = $value; | 
| 491 |  |  |  |  |  |  | } | 
| 492 | 16 |  |  |  |  | 59 | return $self; | 
| 493 |  |  |  |  |  |  | } | 
| 494 |  |  |  |  |  |  |  | 
| 495 |  |  |  |  |  |  | sub get_array { | 
| 496 | 150 |  |  | 150 | 1 | 194 | my $self = CORE::shift; | 
| 497 |  |  |  |  |  |  | return wantarray | 
| 498 | 150 | 100 |  |  |  | 329 | ? @{ $self->{array_for} } | 
|  | 143 |  |  |  |  | 637 |  | 
| 499 |  |  |  |  |  |  | : $self->{array_for}; | 
| 500 |  |  |  |  |  |  | } | 
| 501 |  |  |  |  |  |  |  | 
| 502 |  |  |  |  |  |  | 1; | 
| 503 |  |  |  |  |  |  | __END__ |