Removed final vestiges of misunderstandings
[dbsrgits/DBM-Deep.git] / lib / DBM / Deep / Array.pm
CommitLineData
6fe26b29 1package DBM::Deep::Array;
2
460b1067 3use 5.6.0;
4
6fe26b29 5use strict;
460b1067 6use warnings;
6fe26b29 7
c3aafc14 8our $VERSION = '0.99_03';
86867f3a 9
8fec41b9 10# This is to allow DBM::Deep::Array to handle negative indices on
11# its own. Otherwise, Perl would intercept the call to negative
12# indices for us. This was causing bugs for negative index handling.
460b1067 13our $NEGATIVE_INDICES = 1;
7910cf68 14
6fe26b29 15use base 'DBM::Deep';
16
e1b265cc 17use Scalar::Util ();
18
596e9574 19sub _get_self {
8db25060 20 eval { local $SIG{'__DIE__'}; tied( @{$_[0]} ) } || $_[0]
596e9574 21}
22
f9c33187 23sub _repr { shift;[ @_ ] }
24
25sub _import {
26 my $self = shift;
27 my ($struct) = @_;
28
29 eval {
30 local $SIG{'__DIE__'};
31 $self->push( @$struct );
32 }; if ($@) {
33 $self->_throw_error("Cannot import: type mismatch");
34 }
35
36 return 1;
37}
6fe26b29 38sub TIEARRAY {
6fe26b29 39 my $class = shift;
0ca7ea98 40 my $args = $class->_get_args( @_ );
504185fb 41
42 $args->{type} = $class->TYPE_ARRAY;
43
44 return $class->_init($args);
6fe26b29 45}
46
7f441181 47sub FETCH {
eea0d863 48 my $self = shift->_get_self;
49 my ($key) = @_;
7f441181 50
504185fb 51 $self->lock( $self->LOCK_SH );
9a187d8c 52
c3aafc14 53 my $orig_key;
7f441181 54 if ( $key =~ /^-?\d+$/ ) {
55 if ( $key < 0 ) {
56 $key += $self->FETCHSIZE;
9281d66b 57 unless ( $key >= 0 ) {
58 $self->unlock;
59 return;
60 }
7f441181 61 }
c3aafc14 62 $orig_key = $key;
63 }
64 else {
65 $orig_key = undef;
7f441181 66 }
67
cfd97a7f 68 my $rv = $self->SUPER::FETCH( $key, $orig_key );
9281d66b 69
70 $self->unlock;
71
72 return $rv;
7f441181 73}
74
cb79ec85 75sub STORE {
76 my $self = shift->_get_self;
77 my ($key, $value) = @_;
78
9281d66b 79 $self->lock( $self->LOCK_EX );
80
9ab67b8c 81 my $size;
c3aafc14 82 my $idx_is_numeric;
9ab67b8c 83 if ( $key =~ /^\-?\d+$/ ) {
c3aafc14 84 $idx_is_numeric = 1;
cb79ec85 85 if ( $key < 0 ) {
9ab67b8c 86 $size = $self->FETCHSIZE;
c3aafc14 87 if ( $key + $size < 0 ) {
88 die( "Modification of non-creatable array value attempted, subscript $key" );
baa27ab6 89 }
c3aafc14 90 $key += $size
cb79ec85 91 }
cb79ec85 92 }
93
c3aafc14 94 my $rv = $self->SUPER::STORE( $key, $value, ($key eq 'length' ? undef : $key) );
cb79ec85 95
c3aafc14 96 if ( $idx_is_numeric ) {
9ab67b8c 97 $size = $self->FETCHSIZE unless defined $size;
c3aafc14 98 if ( $key >= $size ) {
99 $self->STORESIZE( $key + 1 );
9ab67b8c 100 }
cb79ec85 101 }
102
9281d66b 103 $self->unlock;
104
cb79ec85 105 return $rv;
106}
107
baa27ab6 108sub EXISTS {
eea0d863 109 my $self = shift->_get_self;
110 my ($key) = @_;
baa27ab6 111
504185fb 112 $self->lock( $self->LOCK_SH );
9281d66b 113
9ab67b8c 114 if ( $key =~ /^\-?\d+$/ ) {
baa27ab6 115 if ( $key < 0 ) {
116 $key += $self->FETCHSIZE;
9281d66b 117 unless ( $key >= 0 ) {
118 $self->unlock;
119 return;
120 }
121 }
9281d66b 122 }
123
124 my $rv = $self->SUPER::EXISTS( $key );
125
126 $self->unlock;
127
128 return $rv;
129}
130
131sub DELETE {
eea0d863 132 my $self = shift->_get_self;
133 my ($key) = @_;
9281d66b 134
9281d66b 135 $self->lock( $self->LOCK_EX );
136
137 my $size = $self->FETCHSIZE;
138 if ( $key =~ /^-?\d+$/ ) {
139 if ( $key < 0 ) {
140 $key += $size;
141 unless ( $key >= 0 ) {
142 $self->unlock;
143 return;
144 }
baa27ab6 145 }
baa27ab6 146 }
147
c3aafc14 148 my $rv = $self->SUPER::DELETE( $key );
9281d66b 149
c3aafc14 150 if ($rv && $key == $size - 1) {
151 $self->STORESIZE( $key, ($key eq 'length' ? undef : $key) );
504185fb 152 }
9281d66b 153
154 $self->unlock;
155
156 return $rv;
baa27ab6 157}
158
6fe26b29 159sub FETCHSIZE {
9281d66b 160 my $self = shift->_get_self;
161
162 $self->lock( $self->LOCK_SH );
163
83371fe3 164 my $SAVE_FILTER = $self->_storage->{filter_fetch_value};
165 $self->_storage->{filter_fetch_value} = undef;
504185fb 166
167 my $packed_size = $self->FETCH('length');
168
83371fe3 169 $self->_storage->{filter_fetch_value} = $SAVE_FILTER;
504185fb 170
9281d66b 171 $self->unlock;
172
504185fb 173 if ($packed_size) {
72e315ac 174 return int(unpack($self->_engine->{long_pack}, $packed_size));
7f441181 175 }
cb79ec85 176
504185fb 177 return 0;
6fe26b29 178}
179
180sub STORESIZE {
eea0d863 181 my $self = shift->_get_self;
504185fb 182 my ($new_length) = @_;
183
9281d66b 184 $self->lock( $self->LOCK_EX );
185
83371fe3 186 my $SAVE_FILTER = $self->_storage->{filter_store_value};
187 $self->_storage->{filter_store_value} = undef;
504185fb 188
72e315ac 189 my $result = $self->STORE('length', pack($self->_engine->{long_pack}, $new_length), 'length');
504185fb 190
83371fe3 191 $self->_storage->{filter_store_value} = $SAVE_FILTER;
504185fb 192
9281d66b 193 $self->unlock;
194
504185fb 195 return $result;
6fe26b29 196}
197
198sub POP {
eea0d863 199 my $self = shift->_get_self;
9281d66b 200
201 $self->lock( $self->LOCK_EX );
202
504185fb 203 my $length = $self->FETCHSIZE();
204
205 if ($length) {
206 my $content = $self->FETCH( $length - 1 );
207 $self->DELETE( $length - 1 );
9281d66b 208
209 $self->unlock;
210
504185fb 211 return $content;
212 }
213 else {
9281d66b 214 $self->unlock;
504185fb 215 return;
216 }
6fe26b29 217}
218
219sub PUSH {
2ac02042 220 my $self = shift->_get_self;
504185fb 221
9281d66b 222 $self->lock( $self->LOCK_EX );
223
504185fb 224 my $length = $self->FETCHSIZE();
9281d66b 225
504185fb 226 while (my $content = shift @_) {
227 $self->STORE( $length, $content );
228 $length++;
229 }
8f6d6ed0 230
9281d66b 231 $self->unlock;
232
8f6d6ed0 233 return $length;
6fe26b29 234}
235
236sub SHIFT {
eea0d863 237 my $self = shift->_get_self;
9281d66b 238
239 $self->lock( $self->LOCK_EX );
240
504185fb 241 my $length = $self->FETCHSIZE();
242
243 if ($length) {
244 my $content = $self->FETCH( 0 );
245
246 for (my $i = 0; $i < $length - 1; $i++) {
247 $self->STORE( $i, $self->FETCH($i + 1) );
248 }
249 $self->DELETE( $length - 1 );
9281d66b 250
251 $self->unlock;
504185fb 252
253 return $content;
254 }
255 else {
9281d66b 256 $self->unlock;
504185fb 257 return;
258 }
6fe26b29 259}
260
261sub UNSHIFT {
2ac02042 262 my $self = shift->_get_self;
504185fb 263 my @new_elements = @_;
9281d66b 264
265 $self->lock( $self->LOCK_EX );
266
504185fb 267 my $length = $self->FETCHSIZE();
268 my $new_size = scalar @new_elements;
269
270 if ($length) {
271 for (my $i = $length - 1; $i >= 0; $i--) {
272 $self->STORE( $i + $new_size, $self->FETCH($i) );
273 }
274 }
275
276 for (my $i = 0; $i < $new_size; $i++) {
277 $self->STORE( $i, $new_elements[$i] );
278 }
8f6d6ed0 279
9281d66b 280 $self->unlock;
281
8f6d6ed0 282 return $length + $new_size;
6fe26b29 283}
284
285sub SPLICE {
2ac02042 286 my $self = shift->_get_self;
9281d66b 287
288 $self->lock( $self->LOCK_EX );
289
504185fb 290 my $length = $self->FETCHSIZE();
291
292 ##
293 # Calculate offset and length of splice
294 ##
295 my $offset = shift;
714618f0 296 $offset = 0 unless defined $offset;
504185fb 297 if ($offset < 0) { $offset += $length; }
298
299 my $splice_length;
300 if (scalar @_) { $splice_length = shift; }
301 else { $splice_length = $length - $offset; }
302 if ($splice_length < 0) { $splice_length += ($length - $offset); }
303
304 ##
305 # Setup array with new elements, and copy out old elements for return
306 ##
307 my @new_elements = @_;
308 my $new_size = scalar @new_elements;
309
df3c5701 310 my @old_elements = map {
311 $self->FETCH( $_ )
312 } $offset .. ($offset + $splice_length - 1);
504185fb 313
314 ##
315 # Adjust array length, and shift elements to accomodate new section.
316 ##
6fe26b29 317 if ( $new_size != $splice_length ) {
318 if ($new_size > $splice_length) {
319 for (my $i = $length - 1; $i >= $offset + $splice_length; $i--) {
320 $self->STORE( $i + ($new_size - $splice_length), $self->FETCH($i) );
321 }
322 }
323 else {
324 for (my $i = $offset + $splice_length; $i < $length; $i++) {
325 $self->STORE( $i + ($new_size - $splice_length), $self->FETCH($i) );
326 }
327 for (my $i = 0; $i < $splice_length - $new_size; $i++) {
328 $self->DELETE( $length - 1 );
329 $length--;
330 }
331 }
504185fb 332 }
333
334 ##
335 # Insert new elements into array
336 ##
337 for (my $i = $offset; $i < $offset + $new_size; $i++) {
338 $self->STORE( $i, shift @new_elements );
339 }
340
9281d66b 341 $self->unlock;
342
504185fb 343 ##
344 # Return deleted section, or last element in scalar context.
345 ##
346 return wantarray ? @old_elements : $old_elements[-1];
6fe26b29 347}
348
460b1067 349# We don't need to define it, yet.
350# It will be useful, though, when we split out HASH and ARRAY
685e40f1 351sub EXTEND {
504185fb 352 ##
353 # Perl will call EXTEND() when the array is likely to grow.
354 # We don't care, but include it because it gets called at times.
355 ##
685e40f1 356}
6fe26b29 357
f9c33187 358sub _copy_node {
898fd1fd 359 my $self = shift;
f9c33187 360 my ($db_temp) = @_;
361
362 my $length = $self->length();
363 for (my $index = 0; $index < $length; $index++) {
364 my $value = $self->get($index);
365 $self->_copy_value( \$db_temp->[$index], $value );
366 }
367
368 return 1;
369}
370
6fe26b29 371##
372# Public method aliases
373##
f9c33187 374sub length { (shift)->FETCHSIZE(@_) }
375sub pop { (shift)->POP(@_) }
376sub push { (shift)->PUSH(@_) }
377sub unshift { (shift)->UNSHIFT(@_) }
378sub splice { (shift)->SPLICE(@_) }
379
380# This must be last otherwise we have to qualify all other calls to shift
381# as calls to CORE::shift
f75b719e 382sub shift { (CORE::shift)->SHIFT(@_) }
6fe26b29 383
3841;
385__END__