tagged release 0.7.1
[parrot.git] / src / pmc / resizablepmcarray.pmc
blob3204d1834240d956be6b7c64e70d2a29b4bd69d2
1 /*
2 Copyright (C) 2001-2008, The Perl Foundation.
3 $Id$
5 =head1 NAME
7 src/pmc/resizablepmcarray.pmc - resizable array for PMCs only
9 =head1 DESCRIPTION
11 This class, ResizablePMCArray, implements an resizable array which stores PMCs.
12 It puts things into Integer, Float, or String PMCs as appropriate.
14 =head2 Functions
16 =over 4
18 =cut
22 #include "parrot/parrot.h"
25 pmclass ResizablePMCArray extends FixedPMCArray need_ext provides array {
29 =item C<void set_integer_native(INTVAL size)>
31 Resizes the array to C<size> elements.
33 =cut
37     VTABLE void set_integer_native(INTVAL size) {
38         if (size < 0)
39             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
40                     "ResizablePMCArray: Can't resize!");
42         if (!PMC_data(SELF)) {
43             /* empty - used fixed routine */
44             if (size < 8) {
45                 SUPER(8);
46                 PMC_int_val(SELF)  = size;
47                 PMC_int_val2(SELF) = 8;
48             }
49             else {
50                 SUPER(size);
51                 PMC_int_val2(SELF) = size;
52             }
53         }
54         else if (size <= PMC_int_val2(SELF)) {
55             PMC_int_val(SELF) = size;
56             /* we could shrink here if necessary */
57             return;
58         }
59         else {
60             INTVAL i, cur, needed;
61             i = cur = PMC_int_val2(SELF);
62             if (cur < 8192)
63                 cur = size < 2 * cur ? 2 * cur : size;
64             else {
65                 needed = size - cur;
66                 cur   += needed + 4096;
67                 cur   &= ~0xfff;
68             }
70             PMC_data(SELF) = mem_sys_realloc(PMC_data(SELF),
71                     cur * sizeof (PMC *));
73             for (; i < cur; i++)
74                 ((PMC **)PMC_data(SELF))[i] = PMCNULL;
76             PMC_int_val2(SELF) = cur;
77             PMC_int_val(SELF)  = size;
78         }
79     }
83 =item C<FLOATVAL shift_float()>
85 =item C<INTVAL shift_integer()>
87 =item C<PMC *shift_pmc()>
89 =item C<STRING *shift_string()>
91 Removes and returns an item from the start of the array.
93 =cut
95 TODO: This always moves the array memory, which is not very performant
96 TODO: Check whether there is already an element that can be shifted
100     VTABLE FLOATVAL shift_float() {
101         INTVAL    size = PMC_int_val(SELF);
102         PMC      *data;
103         PMC     **item;
104         FLOATVAL  value;
106         if (0 == size)
107             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
108                     "ResizablePMCArray: Can't shift from an empty array!");
110         item              = (PMC  **)PMC_data(SELF);
111         data              = item[0];
112         value             = VTABLE_get_number(INTERP, data);
113         PMC_int_val(SELF) = --size;
115         mem_sys_memmove(item, item + 1, size * sizeof (PMC *));
117         item[size]        = PMCNULL;
119         return value;
120     }
122     VTABLE INTVAL shift_integer() {
123         INTVAL    size = PMC_int_val(SELF);
124         PMC      *data;
125         PMC     **item;
126         INTVAL    value;
128         if (0 == size)
129             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
130                     "ResizablePMCArray: Can't shift from an empty array!");
132         item              = (PMC **)PMC_data(SELF);
133         data              = item[0];
134         value             = VTABLE_get_integer(INTERP, data);
135         PMC_int_val(SELF) = --size;
137         mem_sys_memmove(item, item + 1, size * sizeof (PMC*));
138         item[size]        = PMCNULL;
140         return value;
141     }
143     VTABLE PMC *shift_pmc() {
144         INTVAL  size = PMC_int_val(SELF);
145         PMC    *data;
146         PMC   **item;
148         if (0 == size)
149             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
150                     "ResizablePMCArray: Can't shift from an empty array!");
152         item              = (PMC **)PMC_data(SELF);
153         data              = item[0];
154         PMC_int_val(SELF) = --size;
156         mem_sys_memmove(item, item + 1, size * sizeof (PMC *));
157         item[size]        = PMCNULL;
159         return data;
160     }
162     VTABLE STRING *shift_string() {
163         INTVAL   size = PMC_int_val(SELF);
164         PMC     *data;
165         PMC    **item;
166         STRING  *value;
168         if (0 == size)
169             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
170                     "ResizablePMCArray: Can't shift from an empty array!");
172         item              = (PMC **)PMC_data(SELF);
173         data              = item[0];
174         value             = VTABLE_get_string(INTERP, data);
175         PMC_int_val(SELF) = --size;
177         mem_sys_memmove(item, item + 1, size * sizeof (PMC *));
179         item[size]        = PMCNULL;
181         return value;
182     }
187 =item C<PMC *get_pmc_keyed_int(INTVAL key)>
189 Returns the PMC value of the element at index C<key>.
191 =cut
195     VTABLE PMC *get_pmc_keyed_int(INTVAL key) {
196         PMC **data;
198         if (key < 0)
199             key += PMC_int_val(SELF);
201         if (key < 0)
202             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
203                 "ResizablePMCArray: index out of bounds!");
205         if (key >= PMC_int_val(SELF))
206             SELF.set_integer_native(key+1);
208         data = PMC_data_typed(SELF, PMC **);
210         if (PMC_IS_NULL(data[key]))
211             return PMCNULL;
213         return data[key];
214     }
218 =item C<void set_pmc_keyed_int(INTVAL key, PMC *src)>
220 Sets the PMC value of the element at index C<key> to C<*src>.
222 =item C<void set_pmc_keyed(PMC *key, PMC *src)>
224 If key is a slice, do a splice as set that item.
226 =cut
230     VTABLE void set_pmc_keyed_int(INTVAL key, PMC *src) {
231         PMC **data;
233         if (key < 0)
234             key += PMC_int_val(SELF);
236         if (key < 0)
237             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
238                 "ResizablePMCArray: index out of bounds!");
240         if (key >= PMC_int_val(SELF))
241             SELF.set_integer_native(key+1);
243         data      = (PMC **)PMC_data(SELF);
244         GC_WRITE_BARRIER(INTERP, SELF, data[key], src);
245         data[key] = src;
246     }
248     VTABLE void set_pmc_keyed(PMC *key, PMC *src) {
249         SUPER(key, src);
250     }
252     VTABLE void delete_keyed(PMC *key) {
253         INTVAL  i;
254         INTVAL  idx  = key_integer(INTERP, key);
255         INTVAL  n    = PMC_int_val(SELF);
256         PMC   **data = PMC_data_typed(SELF, PMC **);
258         for (i = idx; i < n - 1; ++i)
259             data[i] = data[i + 1];
261         PMC_int_val(SELF)--;
262     }
266 =item C<INTVAL exists_keyed_int(INTVAL key)>
268 =item C<INTVAL exists_keyed_int(PMC *key)>
270 Returns TRUE is the element at C<key> exists; otherwise returns false.
272 =cut
275     VTABLE INTVAL exists_keyed_int(INTVAL key) {
276         PMC **data;
278         if (key < 0)
279             key += PMC_int_val(SELF);
281         if (key < 0 || key >= PMC_int_val(SELF))
282             return 0;
284         data = (PMC **)PMC_data(SELF);
285         return !PMC_IS_NULL(data[key]);
286     }
288     VTABLE INTVAL exists_keyed(PMC *key) {
289         INTVAL ix = key_integer(INTERP, key);
290         return SELF.exists_keyed_int(ix);
291     }
295 =item C<INTVAL defined_keyed_int(INTVAL key)>
297 Returns TRUE is the element at C<key> is defined; otherwise returns false.
299 =cut
303     VTABLE INTVAL defined_keyed_int(INTVAL key) {
304         PMC *val;
306         if (key < 0)
307             key += PMC_int_val(SELF);
309         if (key < 0 || key >= PMC_int_val(SELF))
310             return 0;
312         val = SELF.get_pmc_keyed_int(key);
314         if (PMC_IS_NULL(val))
315             return 0;
317         return VTABLE_defined(INTERP, val);
318     }
322 =item C<void push_float(FLOATVAL value)>
324 =item C<void push_integer(INTVAL value)>
326 =item C<void push_pmc(PMC *value)>
328 =item C<void push_string(STRING *value)>
330 Extends the array by adding an element of value C<*value> to the end of
331 the array.
333 =cut
337     VTABLE void push_float(FLOATVAL value) {
338         INTVAL size = PMC_int_val(SELF);
339         PMC   *val  = pmc_new(INTERP, enum_class_Float);
341         VTABLE_set_number_native(INTERP, val, value);
343         /* let set_pmc_keyed_int() worry about memory allocation */
344         SELF.set_pmc_keyed_int(size, val);
346         return;
347     }
349     VTABLE void push_integer(INTVAL value) {
350         INTVAL size = PMC_int_val(SELF);
351         PMC   *val  = pmc_new(INTERP, enum_class_Integer);
353         VTABLE_set_integer_native(INTERP, val, value);
355         /* let set_pmc_keyed_int() worry about memory allocation */
356         SELF.set_pmc_keyed_int(size, val);
358         return;
359     }
361     void push_pmc(PMC *value) {
362         INTVAL size = PMC_int_val(SELF);
364         /* let set_integer_native() worry about memory allocation */
365         SELF.set_integer_native(size + 1);
366         ((PMC **)PMC_data(SELF))[size] = value;
368         return;
369     }
371     VTABLE void push_string(STRING *value) {
372         INTVAL size = PMC_int_val(SELF);
373         PMC   *val  = pmc_new(INTERP, enum_class_String);
375         VTABLE_assign_string_native(INTERP, val, value);
377         /* let set_pmc_keyed_int() worry about memory allocation */
378         SELF.set_pmc_keyed_int(size, val);
380         return;
381     }
385 Removes and returns the last element in the array.
387 =item C<INTVAL pop_float()>
389 =item C<INTVAL pop_integer()>
391 =item C<PMC *pop_pmc()>
393 =item C<STRING *pop_string()>
395 =cut
399     VTABLE FLOATVAL pop_float() {
400         INTVAL   size = PMC_int_val(SELF);
401         PMC     *data;
403         if (0 == size)
404             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
405                     "ResizablePMCArray: Can't pop from an empty array!");
407         data              = ((PMC **)PMC_data(SELF))[--size];
408         PMC_int_val(SELF) = size;
410         return VTABLE_get_number(INTERP, data);
411     }
413     VTABLE INTVAL pop_integer() {
414         INTVAL  size = PMC_int_val(SELF);
415         PMC    *data;
417         if (0 == size)
418             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
419                     "ResizablePMCArray: Can't pop from an empty array!");
421         data              = ((PMC **)PMC_data(SELF))[--size];
422         PMC_int_val(SELF) = size;
424         return VTABLE_get_integer(INTERP, data);
425     }
427     VTABLE PMC *pop_pmc() {
428         INTVAL size = PMC_int_val(SELF);
429         PMC   *data;
431         if (0 == size)
432             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
433                     "ResizablePMCArray: Can't pop from an empty array!");
435         data              = ((PMC **)PMC_data(SELF))[--size];
436         PMC_int_val(SELF) = size;
438         return data;
439     }
441     VTABLE STRING *pop_string() {
442         INTVAL  size = PMC_int_val(SELF);
443         PMC    *data;
445         if (0 == size)
446             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
447                     "ResizablePMCArray: Can't pop from an empty array!");
449         data              = ((PMC **)PMC_data(SELF))[--size];
450         PMC_int_val(SELF) = size;
452         return VTABLE_get_string(INTERP, data);
453     }
457 =item C<void unshift_float(FLOATVAL value)>
459 =item C<void unshift_integer(INTVAL value)>
461 =item C<void unshift_pmc(PMC *value)>
463 =item C<void unshift_string(STRING *value)>
465 Extends the array by adding an element of value C<*value> to the begin of
466 the array.
468 =cut
472     VTABLE void unshift_float(FLOATVAL value) {
473         INTVAL  size = PMC_int_val(SELF);
474         PMC    *val  = pmc_new(INTERP, enum_class_Float);
475         PMC   **data;
476         INTVAL  i;
478         VTABLE_set_number_native(INTERP, val, value);
480         /* let set_integer_native() worry about memory allocation */
481         SELF.set_integer_native(size + 1);
483         /* make room */
484         data = (PMC **)PMC_data(SELF);
486         for (i = size; i; --i)
487             data[i] = data[i - 1];
489         data[0] = val;
491         return;
492     }
494     VTABLE void unshift_integer(INTVAL value) {
495         INTVAL  size = PMC_int_val(SELF);
496         PMC    *val  = pmc_new(INTERP, enum_class_Integer);
497         PMC    **data;
498         INTVAL   i;
500         VTABLE_set_integer_native(INTERP, val, value);
502         /* let set_integer_native() worry about memory allocation */
503         SELF.set_integer_native(size + 1);
505         /* make room */
506         data = (PMC **)PMC_data(SELF);
508         for (i = size; i; --i)
509             data[i] = data[i - 1];
511         data[0] = val;
513         return;
514     }
516     void unshift_pmc(PMC *value) {
517         INTVAL  size = PMC_int_val(SELF);
518         PMC   **data;
519         INTVAL  i;
521         /* let set_integer_native() worry about memory allocation */
522         SELF.set_integer_native(size + 1);
524         /* make room */
525         data = (PMC **)PMC_data(SELF);
527         for (i = size; i; --i)
528             data[i] = data[i - 1];
530         data[0] = value;
532         return;
533     }
535     VTABLE void unshift_string(STRING *value) {
536         INTVAL  size = PMC_int_val(SELF);
537         PMC    *val  = pmc_new(INTERP, enum_class_String);
538         PMC   **data;
539         INTVAL  i;
541         VTABLE_set_string_native(INTERP, val, value);
543         /* let set_integer_native() worry about memory allocation */
544         SELF.set_integer_native(size + 1);
546         /* make room */
547         data = (PMC **)PMC_data(SELF);
549         for (i = size; i; --i)
550             data[i] = data[i - 1];
552         data[0] = val;
554         return;
555     }
559 =item C<PMC *clone()>
561 Creates and returns a copy of the array.
563 =cut
567     VTABLE PMC *clone() {
568         PMC *copy = SUPER();
570         /* copy trimmed extra space */
571         PMC_int_val2(copy) = PMC_int_val(SELF);
573         return copy;
574     }
578 =item C<INTVAL is_equal(PMC *value)>
580 The C<==> operation. Compares two array to hold equal elements.
582 =cut
586     VTABLE INTVAL is_equal(PMC *value) {
587         INTVAL j, n;
589         if (value->vtable->base_type != enum_class_ResizablePMCArray)
590             return 0;
592         n = SELF.elements();
594         if (VTABLE_elements(INTERP, value) != n)
595             return 0;
597         for (j = 0; j < n; ++j) {
598             PMC *item1 = SELF.get_pmc_keyed_int(j);
599             PMC *item2 = VTABLE_get_pmc_keyed_int(INTERP, value, j);
601             if (item1 == item2)
602                 continue;
604             if (!mmd_dispatch_i_pp(INTERP, item1, item2, MMD_EQ))
605                 return 0;
606         }
608         return 1;
609     }
613 =item METHOD append(PMC *other)
615 Append the other array to this array.
617 =cut
621     METHOD append(PMC *other) {
622         INTVAL i;
623         INTVAL n = VTABLE_elements(INTERP, SELF);
624         INTVAL m = VTABLE_elements(INTERP, other);
626         if (!m)
627             RETURN(void);
629         /* pre-size it */
630         VTABLE_set_integer_native(INTERP, SELF, n + m);
631         if (other->vtable->base_type == SELF->vtable->base_type ||
632                 other->vtable->base_type == enum_class_FixedPMCArray) {
633             PMC **other_data = PMC_data_typed(other, PMC **);
634             PMC **this_data  = PMC_data_typed(SELF, PMC **);
636             for (i = 0; i < m; ++i)
637                 this_data[n + i] = other_data[i];
638         }
639         else {
640             PMC **this_data = PMC_data_typed(SELF, PMC **);
642             for (i = 0; i < m; ++i)
643                 this_data[n + i] = VTABLE_get_pmc_keyed_int(INTERP, other, i);
644         }
645     }
648 =item C<STRING *get_repr()>
650 Returns the Parrot string representation C<ResizablePMCArray>.
652 =cut
656     VTABLE STRING *get_repr() {
657         INTVAL  j;
658         INTVAL  n   = VTABLE_elements(INTERP, SELF);
659         STRING *res = CONST_STRING(INTERP, "[ ");
661         for (j = 0; j < n; ++j) {
662             PMC *val = SELF.get_pmc_keyed_int(j);
663             res      = string_append(INTERP, res, VTABLE_get_repr(INTERP, val));
665             if (j < n - 1)
666                 res = string_append(INTERP, res, CONST_STRING(INTERP, ", "));
667         }
669         return string_append(INTERP, res, CONST_STRING(INTERP, " ]"));
670     }
674 =item C<void splice(PMC *value, INTVAL offset, INTVAL count)>
676 Replaces C<count> elements starting at C<offset> with the elements in
677 C<value>.
679 Note that the C<value> PMC can be of any of the various array types.
681 Note that this implementation can be *VERY *inefficient as it manipulates
682 everything via the VTABLE api.
684 =cut
688     void splice(PMC *value, INTVAL offset, INTVAL count) {
689         const INTVAL length = VTABLE_elements(INTERP, SELF);
690         const INTVAL elems  = VTABLE_elements(INTERP, value);
691         INTVAL       shift  = elems - count;
692         INTVAL       i;
694         /* start from end? */
695         if (offset < 0)
696             offset += length;
698         if (offset < 0)
699             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
700                 "illegal splice offset\n");
702         /* shrink the array */
703         if (shift < 0) {
704             /* start at offset so we don't overwrite values we'll need */
705             for (i = offset + count; i < length; i++)
706                 VTABLE_set_pmc_keyed_int(INTERP, SELF, i + shift,
707                     VTABLE_get_pmc_keyed_int(INTERP, SELF, i));
709             SELF.set_integer_native(length + shift);
710         }
711         /* grow the array */
712         else if (shift > 0) {
713             SELF.set_integer_native(length + shift);
715             /* move the existing values */
716             /* start at length-1 so we don't overwrite values we'll need */
717             for (i = length - 1; i >= offset; i--)
718                 VTABLE_set_pmc_keyed_int(INTERP, SELF, i + shift,
719                     VTABLE_get_pmc_keyed_int(INTERP, SELF, i));
720         }
722         /* copy the new values */
723         for (i = 0; i < elems; i++)
724             VTABLE_set_pmc_keyed_int(INTERP, SELF, i + offset,
725                 VTABLE_get_pmc_keyed_int(INTERP, value, i));
726     }
730 =item METHOD PMC* shift()
732 =item METHOD PMC* pop()
734 Method forms to remove and return a PMC from the beginning or
735 end of the array.
737 =cut
741     METHOD PMC* shift() {
742         PMC *value = VTABLE_shift_pmc(INTERP, SELF);
743         RETURN(PMC *value);
744     }
746     METHOD PMC* pop() {
747         PMC *value = VTABLE_pop_pmc(INTERP, SELF);
748         RETURN(PMC *value);
749     }
753 =item METHOD unshift(PMC* value)
755 =item METHOD push(PMC* value)
757 Method forms to add a PMC to the beginning or end of the array.
759 =cut
763     METHOD unshift(PMC* value) {
764         VTABLE_unshift_pmc(INTERP, SELF, value);
765     }
767     METHOD push(PMC* value) {
768         VTABLE_push_pmc(INTERP, SELF, value);
769     }
775 =back
777 =head1 SEE ALSO
779 F<docs/pdds/pdd17_basic_types.pod>.
781 =head1 HISTORY
783 Initial version                  - Matt Fowles 2004-06-11
784 Changed allocator to double size - Matt Fowles 2004-06-15
786 =cut
791  * Local variables:
792  *   c-file-style: "parrot"
793  * End:
794  * vim: expandtab shiftwidth=4:
795  */