2 Copyright (C) 2001-2008, The Perl Foundation.
7 src/pmc/resizablepmcarray.pmc - resizable array for PMCs only
11 This class, ResizablePMCArray, implements an resizable array which stores PMCs.
12 It puts things into Integer, Float, or String PMCs as appropriate.
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.
37 VTABLE void set_integer_native(INTVAL size) {
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 */
46 PMC_int_val(SELF) = size;
47 PMC_int_val2(SELF) = 8;
51 PMC_int_val2(SELF) = size;
54 else if (size <= PMC_int_val2(SELF)) {
55 PMC_int_val(SELF) = size;
56 /* we could shrink here if necessary */
60 INTVAL i, cur, needed;
61 i = cur = PMC_int_val2(SELF);
63 cur = size < 2 * cur ? 2 * cur : size;
70 PMC_data(SELF) = mem_sys_realloc(PMC_data(SELF),
71 cur * sizeof (PMC *));
74 ((PMC **)PMC_data(SELF))[i] = PMCNULL;
76 PMC_int_val2(SELF) = cur;
77 PMC_int_val(SELF) = size;
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.
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);
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);
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;
122 VTABLE INTVAL shift_integer() {
123 INTVAL size = PMC_int_val(SELF);
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);
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;
143 VTABLE PMC *shift_pmc() {
144 INTVAL size = PMC_int_val(SELF);
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);
154 PMC_int_val(SELF) = --size;
156 mem_sys_memmove(item, item + 1, size * sizeof (PMC *));
157 item[size] = PMCNULL;
162 VTABLE STRING *shift_string() {
163 INTVAL size = PMC_int_val(SELF);
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);
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;
187 =item C<PMC *get_pmc_keyed_int(INTVAL key)>
189 Returns the PMC value of the element at index C<key>.
195 VTABLE PMC *get_pmc_keyed_int(INTVAL key) {
199 key += PMC_int_val(SELF);
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]))
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.
230 VTABLE void set_pmc_keyed_int(INTVAL key, PMC *src) {
234 key += PMC_int_val(SELF);
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);
248 VTABLE void set_pmc_keyed(PMC *key, PMC *src) {
252 VTABLE void delete_keyed(PMC *key) {
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];
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.
275 VTABLE INTVAL exists_keyed_int(INTVAL key) {
279 key += PMC_int_val(SELF);
281 if (key < 0 || key >= PMC_int_val(SELF))
284 data = (PMC **)PMC_data(SELF);
285 return !PMC_IS_NULL(data[key]);
288 VTABLE INTVAL exists_keyed(PMC *key) {
289 INTVAL ix = key_integer(INTERP, key);
290 return SELF.exists_keyed_int(ix);
295 =item C<INTVAL defined_keyed_int(INTVAL key)>
297 Returns TRUE is the element at C<key> is defined; otherwise returns false.
303 VTABLE INTVAL defined_keyed_int(INTVAL key) {
307 key += PMC_int_val(SELF);
309 if (key < 0 || key >= PMC_int_val(SELF))
312 val = SELF.get_pmc_keyed_int(key);
314 if (PMC_IS_NULL(val))
317 return VTABLE_defined(INTERP, val);
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
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);
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);
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;
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);
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()>
399 VTABLE FLOATVAL pop_float() {
400 INTVAL size = PMC_int_val(SELF);
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);
413 VTABLE INTVAL pop_integer() {
414 INTVAL size = PMC_int_val(SELF);
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);
427 VTABLE PMC *pop_pmc() {
428 INTVAL size = PMC_int_val(SELF);
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;
441 VTABLE STRING *pop_string() {
442 INTVAL size = PMC_int_val(SELF);
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);
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
472 VTABLE void unshift_float(FLOATVAL value) {
473 INTVAL size = PMC_int_val(SELF);
474 PMC *val = pmc_new(INTERP, enum_class_Float);
478 VTABLE_set_number_native(INTERP, val, value);
480 /* let set_integer_native() worry about memory allocation */
481 SELF.set_integer_native(size + 1);
484 data = (PMC **)PMC_data(SELF);
486 for (i = size; i; --i)
487 data[i] = data[i - 1];
494 VTABLE void unshift_integer(INTVAL value) {
495 INTVAL size = PMC_int_val(SELF);
496 PMC *val = pmc_new(INTERP, enum_class_Integer);
500 VTABLE_set_integer_native(INTERP, val, value);
502 /* let set_integer_native() worry about memory allocation */
503 SELF.set_integer_native(size + 1);
506 data = (PMC **)PMC_data(SELF);
508 for (i = size; i; --i)
509 data[i] = data[i - 1];
516 void unshift_pmc(PMC *value) {
517 INTVAL size = PMC_int_val(SELF);
521 /* let set_integer_native() worry about memory allocation */
522 SELF.set_integer_native(size + 1);
525 data = (PMC **)PMC_data(SELF);
527 for (i = size; i; --i)
528 data[i] = data[i - 1];
535 VTABLE void unshift_string(STRING *value) {
536 INTVAL size = PMC_int_val(SELF);
537 PMC *val = pmc_new(INTERP, enum_class_String);
541 VTABLE_set_string_native(INTERP, val, value);
543 /* let set_integer_native() worry about memory allocation */
544 SELF.set_integer_native(size + 1);
547 data = (PMC **)PMC_data(SELF);
549 for (i = size; i; --i)
550 data[i] = data[i - 1];
559 =item C<PMC *clone()>
561 Creates and returns a copy of the array.
567 VTABLE PMC *clone() {
570 /* copy trimmed extra space */
571 PMC_int_val2(copy) = PMC_int_val(SELF);
578 =item C<INTVAL is_equal(PMC *value)>
580 The C<==> operation. Compares two array to hold equal elements.
586 VTABLE INTVAL is_equal(PMC *value) {
589 if (value->vtable->base_type != enum_class_ResizablePMCArray)
594 if (VTABLE_elements(INTERP, value) != n)
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);
604 if (!mmd_dispatch_i_pp(INTERP, item1, item2, MMD_EQ))
613 =item METHOD append(PMC *other)
615 Append the other array to this array.
621 METHOD append(PMC *other) {
623 INTVAL n = VTABLE_elements(INTERP, SELF);
624 INTVAL m = VTABLE_elements(INTERP, other);
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];
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);
648 =item C<STRING *get_repr()>
650 Returns the Parrot string representation C<ResizablePMCArray>.
656 VTABLE STRING *get_repr() {
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));
666 res = string_append(INTERP, res, CONST_STRING(INTERP, ", "));
669 return string_append(INTERP, res, CONST_STRING(INTERP, " ]"));
674 =item C<void splice(PMC *value, INTVAL offset, INTVAL count)>
676 Replaces C<count> elements starting at C<offset> with the elements in
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.
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;
694 /* start from end? */
699 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
700 "illegal splice offset\n");
702 /* shrink the array */
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);
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));
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));
730 =item METHOD PMC* shift()
732 =item METHOD PMC* pop()
734 Method forms to remove and return a PMC from the beginning or
741 METHOD PMC* shift() {
742 PMC *value = VTABLE_shift_pmc(INTERP, SELF);
747 PMC *value = VTABLE_pop_pmc(INTERP, SELF);
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.
763 METHOD unshift(PMC* value) {
764 VTABLE_unshift_pmc(INTERP, SELF, value);
767 METHOD push(PMC* value) {
768 VTABLE_push_pmc(INTERP, SELF, value);
779 F<docs/pdds/pdd17_basic_types.pod>.
783 Initial version - Matt Fowles 2004-06-11
784 Changed allocator to double size - Matt Fowles 2004-06-15
792 * c-file-style: "parrot"
794 * vim: expandtab shiftwidth=4: