Marked two tests as passing that were TODO
[dbsrgits/DBM-Deep.git] / lib / DBM / Deep / Array.pm
CommitLineData
6fe26b29 1package DBM::Deep::Array;
2
3use strict;
4
5use base 'DBM::Deep';
6
e1b265cc 7use Scalar::Util ();
8
596e9574 9sub _get_self {
10 eval { tied( @{$_[0]} ) } || $_[0]
11}
12
6fe26b29 13sub TIEARRAY {
14##
15# Tied array constructor method, called by Perl's tie() function.
16##
17 my $class = shift;
18 my $args;
217fef02 19 if (scalar(@_) > 1) {
20 if ( @_ % 2 ) {
21 $class->_throw_error( "Odd number of parameters to TIEARRAY" );
22 }
23 $args = {@_};
24 }
e1b265cc 25 elsif ( my $type = Scalar::Util::reftype($_[0]) ) {
26 if ( $type ne 'HASH' ) {
27 $class->_throw_error( "Not a hashref in TIEARRAY" );
28 }
29 $args = $_[0];
30 }
31 else {
32 $args = { file => shift };
33 }
6fe26b29 34
35 $args->{type} = $class->TYPE_ARRAY;
36
37 return $class->_init($args);
38}
39
40##
41# The following methods are for arrays only
42##
43
44sub FETCHSIZE {
45 ##
46 # Return the length of the array
47 ##
2ac02042 48 my $self = $_[0]->_get_self;
6fe26b29 49
50 my $SAVE_FILTER = $self->root->{filter_fetch_value};
51 $self->root->{filter_fetch_value} = undef;
52
53 my $packed_size = $self->FETCH('length');
54
55 $self->root->{filter_fetch_value} = $SAVE_FILTER;
56
57 if ($packed_size) { return int(unpack($DBM::Deep::LONG_PACK, $packed_size)); }
58 else { return 0; }
59}
60
61sub STORESIZE {
62 ##
63 # Set the length of the array
64 ##
2ac02042 65 my $self = $_[0]->_get_self;
6fe26b29 66 my $new_length = $_[1];
67
68 my $SAVE_FILTER = $self->root->{filter_store_value};
69 $self->root->{filter_store_value} = undef;
70
71 my $result = $self->STORE('length', pack($DBM::Deep::LONG_PACK, $new_length));
72
73 $self->root->{filter_store_value} = $SAVE_FILTER;
74
75 return $result;
76}
77
78sub POP {
79 ##
80 # Remove and return the last element on the array
81 ##
2ac02042 82 my $self = $_[0]->_get_self;
6fe26b29 83 my $length = $self->FETCHSIZE();
84
85 if ($length) {
86 my $content = $self->FETCH( $length - 1 );
87 $self->DELETE( $length - 1 );
88 return $content;
89 }
90 else {
91 return;
92 }
93}
94
95sub PUSH {
96 ##
97 # Add new element(s) to the end of the array
98 ##
2ac02042 99 my $self = shift->_get_self;
6fe26b29 100 my $length = $self->FETCHSIZE();
101
102 while (my $content = shift @_) {
103 $self->STORE( $length, $content );
104 $length++;
105 }
8f6d6ed0 106
107 return $length;
6fe26b29 108}
109
110sub SHIFT {
111 ##
112 # Remove and return first element on the array.
113 # Shift over remaining elements to take up space.
114 ##
2ac02042 115 my $self = $_[0]->_get_self;
6fe26b29 116 my $length = $self->FETCHSIZE();
117
118 if ($length) {
119 my $content = $self->FETCH( 0 );
120
121 ##
122 # Shift elements over and remove last one.
123 ##
124 for (my $i = 0; $i < $length - 1; $i++) {
125 $self->STORE( $i, $self->FETCH($i + 1) );
126 }
127 $self->DELETE( $length - 1 );
128
129 return $content;
130 }
131 else {
132 return;
133 }
134}
135
136sub UNSHIFT {
137 ##
138 # Insert new element(s) at beginning of array.
139 # Shift over other elements to make space.
140 ##
2ac02042 141 my $self = shift->_get_self;
6fe26b29 142 my @new_elements = @_;
143 my $length = $self->FETCHSIZE();
144 my $new_size = scalar @new_elements;
145
146 if ($length) {
147 for (my $i = $length - 1; $i >= 0; $i--) {
148 $self->STORE( $i + $new_size, $self->FETCH($i) );
149 }
150 }
151
152 for (my $i = 0; $i < $new_size; $i++) {
153 $self->STORE( $i, $new_elements[$i] );
154 }
8f6d6ed0 155
156 return $length + $new_size;
6fe26b29 157}
158
159sub SPLICE {
160 ##
161 # Splices section of array with optional new section.
162 # Returns deleted section, or last element deleted in scalar context.
163 ##
2ac02042 164 my $self = shift->_get_self;
6fe26b29 165 my $length = $self->FETCHSIZE();
166
167 ##
168 # Calculate offset and length of splice
169 ##
170 my $offset = shift || 0;
171 if ($offset < 0) { $offset += $length; }
172
173 my $splice_length;
174 if (scalar @_) { $splice_length = shift; }
175 else { $splice_length = $length - $offset; }
176 if ($splice_length < 0) { $splice_length += ($length - $offset); }
177
178 ##
179 # Setup array with new elements, and copy out old elements for return
180 ##
181 my @new_elements = @_;
182 my $new_size = scalar @new_elements;
183
184 my @old_elements = ();
185 for (my $i = $offset; $i < $offset + $splice_length; $i++) {
186 push @old_elements, $self->FETCH( $i );
187 }
188
189 ##
190 # Adjust array length, and shift elements to accomodate new section.
191 ##
192 if ( $new_size != $splice_length ) {
193 if ($new_size > $splice_length) {
194 for (my $i = $length - 1; $i >= $offset + $splice_length; $i--) {
195 $self->STORE( $i + ($new_size - $splice_length), $self->FETCH($i) );
196 }
197 }
198 else {
199 for (my $i = $offset + $splice_length; $i < $length; $i++) {
200 $self->STORE( $i + ($new_size - $splice_length), $self->FETCH($i) );
201 }
202 for (my $i = 0; $i < $splice_length - $new_size; $i++) {
203 $self->DELETE( $length - 1 );
204 $length--;
205 }
206 }
207 }
208
209 ##
210 # Insert new elements into array
211 ##
212 for (my $i = $offset; $i < $offset + $new_size; $i++) {
213 $self->STORE( $i, shift @new_elements );
214 }
215
216 ##
217 # Return deleted section, or last element in scalar context.
218 ##
219 return wantarray ? @old_elements : $old_elements[-1];
220}
221
222#XXX We don't need to define it.
223#XXX It will be useful, though, when we split out HASH and ARRAY
224#sub EXTEND {
225 ##
226 # Perl will call EXTEND() when the array is likely to grow.
227 # We don't care, but include it for compatibility.
228 ##
229#}
230
231##
232# Public method aliases
233##
234*length = *FETCHSIZE;
235*pop = *POP;
236*push = *PUSH;
237*shift = *SHIFT;
238*unshift = *UNSHIFT;
239*splice = *SPLICE;
240
2411;
242__END__