2 Copyright (C) 2001-2008, The Perl Foundation.
7 src/pmc/array.pmc - Array PMC
11 These are the vtable functions for the Array base class.
21 #include "parrot/parrot.h"
25 =item C<static PMC *undef(PARROT_INTERP)>
27 Returns a C<Undef> PMC.
33 static PMC *undef(PARROT_INTERP) {
34 return pmc_new(interp, enum_class_Undef);
39 =item C<static PMC *retval(PARROT_INTERP, void *ret)>
41 Processes C<*ret>, returning the appropriate PMC, or raising an
42 exception if necessary.
48 static PMC *retval(PARROT_INTERP, void *ret) {
52 real_exception(interp, NULL, E_IndexError,
53 "Array index out of bounds!");
55 /* XXX getting non existent value, exception or undef?
56 * current is for perlarray */
57 if (ret == (void *)-1)
58 value = undef(interp);
64 value = undef(interp);
73 *Parrot_Array_set_pmc_ptr(PARROT_INTERP, List *list, INTVAL key)>
75 Returns a pointer to the element at index C<key> of C<*list>. If
76 this element was previously empty, then this function also creates
77 and assigns an "undef" PMC to that element.
83 static PMC *Parrot_Array_set_pmc_ptr(PARROT_INTERP, List *list, INTVAL key) {
84 void * const ret = list_get(interp, list, key, enum_type_PMC);
88 real_exception(interp, NULL, E_IndexError,
89 "Array index out of bounds!");
91 /* assign into a sparse or not yet set value */
92 if (ret == (void *)-1 || *(PMC **)ret == 0) {
93 value = undef(interp);
94 list_assign(interp, list, key, value, enum_type_PMC);
103 pmclass Array need_ext provides array {
113 =item C<void class_init()>
115 Class initialization. Creates the required memory pools.
122 /* class_init_code; called for side effects */
123 Small_Object_Pool *List_chunks =
124 make_bufferlike_pool(INTERP, sizeof (List_chunk));
125 Small_Object_Pool *Lists =
126 make_bufferlike_pool(INTERP, sizeof (List));
128 /* XXX until there's a function to allocate a pool in an arena */
137 Initializes the PMC by calling the underlying C<list_new()> function.
144 list_pmc_new(INTERP, SELF);
145 PObj_custom_mark_SET(SELF);
150 =item C<void init_pmc(PMC *init)>
152 Calls C<list_new_init()> to initialize the underlying list.
154 C<*init> contains the initialization information specifying initial
155 size, number of dimensions, etc.
161 VTABLE void init_pmc(PMC *init) {
162 list_pmc_new_init(INTERP, SELF, init);
163 PObj_custom_mark_SET(SELF);
168 =item C<void assign_pmc(PMC *other)>
170 Copy the contents of other to self.
176 VTABLE void assign_pmc(PMC *other) {
177 const INTVAL size = VTABLE_elements(INTERP, other);
180 SELF.set_integer_native(size);
181 for (i = 0; i < size; i++) {
182 PMC * const elem = VTABLE_get_pmc_keyed_int(INTERP, other, i);
183 SELF.set_pmc_keyed_int(i, elem);
190 =item C<void set_pmc(PMC *other)>
192 Implemented as an alias to C<assign_pmc> since the behavior is the same.
198 VTABLE void set_pmc(PMC *other) {
199 SELF.assign_pmc(other);
206 Mark the array and its contents as live.
213 list_mark(INTERP, (List *)PMC_data(SELF));
218 =item C<PMC *clone()>
220 Return a clone of the array.
226 VTABLE PMC *clone() {
227 List *l = list_clone(INTERP, (List *)PMC_data(SELF));
228 PMC * const dest = pmc_new_noinit(INTERP, SELF->vtable->base_type);
230 PObj_custom_mark_SET(dest);
240 =item C<INTVAL get_integer()>
242 Returns the number of elements in the array.
248 VTABLE INTVAL get_integer() {
249 return SELF.elements();
254 =item C<INTVAL get_bool()>
256 Returns true if the array has one or more elements.
262 VTABLE INTVAL get_bool() {
263 const INTVAL size = SELF.elements();
264 return (INTVAL)(size != 0);
269 =item C<INTVAL elements()>
271 Returns the number of elements in the array.
277 VTABLE INTVAL elements() {
278 return ((List *) PMC_data(SELF))->length;
283 =item C<FLOATVAL get_number()>
285 Returns the number of elements in the array.
291 VTABLE FLOATVAL get_number() {
292 INTVAL e = SELF.elements();
298 =item C<STRING *get_string()>
300 Returns a string representation of the array.
306 VTABLE STRING *get_string() {
307 return Parrot_sprintf_c(INTERP, "array[%p]", SELF);
312 =item C<INTVAL get_integer_keyed_int(INTVAL key)>
314 Returns the integer value of the element at index C<key>.
320 VTABLE INTVAL get_integer_keyed_int(INTVAL key) {
321 PMC * const value = SELF.get_pmc_keyed_int(key);
323 return VTABLE_get_integer(INTERP, value);
328 =item C<INTVAL type_keyed_int(INTVAL key)>
334 VTABLE INTVAL type_keyed_int(INTVAL key) {
335 PMC * const value = SELF.get_pmc_keyed_int(key);
337 return VTABLE_type(INTERP, value);
342 =item C<INTVAL get_integer_keyed(PMC *key)>
344 Returns the integer value of the element at index C<key>.
350 VTABLE INTVAL get_integer_keyed(PMC *key) {
357 ix = key_integer(INTERP, key);
358 nextkey = key_next(INTERP, key);
361 return SELF.get_integer_keyed_int(ix);
363 box = SELF.get_pmc_keyed_int(ix);
368 return VTABLE_get_integer_keyed(INTERP, box, nextkey);
373 =item C<FLOATVAL get_number_keyed_int(INTVAL key)>
375 Returns the float value of the element at index C<key>.
381 VTABLE FLOATVAL get_number_keyed_int(INTVAL key) {
382 PMC * const value = SELF.get_pmc_keyed_int(key);
384 return VTABLE_get_number(INTERP, value);
390 =item C<FLOATVAL get_number_keyed(PMC *key)>
392 Returns the float value of the element at index C<key>.
398 VTABLE FLOATVAL get_number_keyed(PMC *key) {
405 ix = key_integer(INTERP, key);
406 nextkey = key_next(INTERP, key);
409 return SELF.get_number_keyed_int(ix);
411 box = SELF.get_pmc_keyed_int(ix);
416 return VTABLE_get_number_keyed(INTERP, box, nextkey);
421 =item C<STRING *get_string_keyed_int(INTVAL key)>
423 Returns the string value of the element at index C<key>.
429 VTABLE STRING *get_string_keyed_int(INTVAL key) {
430 PMC * const value = SELF.get_pmc_keyed_int(key);
432 return VTABLE_get_string(INTERP, value);
437 =item C<STRING *get_string_keyed(PMC *key)>
439 Returns the string value of the element at index C<key>.
445 VTABLE STRING *get_string_keyed(PMC *key) {
452 ix = key_integer(INTERP, key);
453 nextkey = key_next(INTERP, key);
456 return SELF.get_string_keyed_int(ix);
458 box = SELF.get_pmc_keyed_int(ix);
463 return VTABLE_get_string_keyed(INTERP, box, nextkey);
468 =item C<PMC *get_pmc_keyed_int(INTVAL key)>
470 Returns the PMC value of the element at index C<key>.
476 VTABLE PMC *get_pmc_keyed_int(INTVAL key) {
478 return retval(INTERP,
479 list_get(INTERP, (List *)PMC_data(SELF), key, enum_type_PMC));
484 =item C<PMC *get_pmc_keyed(PMC *key)>
486 Returns the PMC value of the element at index C<key>.
492 VTABLE PMC *get_pmc_keyed(PMC *key) {
499 ix = key_integer(INTERP, key);
500 nextkey = key_next(INTERP, key);
503 return SELF.get_pmc_keyed_int(ix);
505 box = SELF.get_pmc_keyed_int(ix);
510 return VTABLE_get_pmc_keyed(INTERP, box, nextkey);
515 =item C<void set_integer_native(INTVAL size)>
517 Sets the length of the array to C<size>.
523 VTABLE void set_integer_native(INTVAL size) {
524 list_set_length(INTERP, (List *)PMC_data(SELF), size);
528 =item C<void set_integer_same(PMC *value)>
530 Sets the length of the array to the number of elements in C<*value>.
536 VTABLE void set_integer_same(PMC *value) {
537 const INTVAL size = VTABLE_elements(INTERP, value);
538 list_set_length(INTERP, (List *)PMC_data(SELF), size);
543 =item C<void set_integer_keyed_int(INTVAL key, INTVAL value)>
545 Sets the integer value of the PMC at element C<key> to C<value>.
551 VTABLE void set_integer_keyed_int(INTVAL key, INTVAL value) {
553 Parrot_Array_set_pmc_ptr(INTERP, (List *)PMC_data(SELF), key);
555 VTABLE_set_integer_native(INTERP, ptr, value);
560 =item C<void set_integer_keyed(PMC *key, INTVAL value)>
562 Sets the integer value of the PMC at element C<key> to C<value>.
568 VTABLE void set_integer_keyed(PMC *key, INTVAL value) {
575 ix = key_integer(INTERP, key);
576 nextkey = key_next(INTERP, key);
579 SELF.set_integer_keyed_int(ix, value);
583 box = SELF.get_pmc_keyed_int(ix);
585 /* autovivify an Array */
587 box = pmc_new(INTERP, SELF.type());
589 VTABLE_set_integer_keyed(INTERP, box, nextkey, value);
594 =item C<void set_number_keyed_int(INTVAL key, FLOATVAL value)>
596 Sets the numeric value of the PMC at element C<key> to C<value>.
602 VTABLE void set_number_keyed_int(INTVAL key, FLOATVAL value) {
604 Parrot_Array_set_pmc_ptr(INTERP, (List *)PMC_data(SELF), key);
606 VTABLE_set_number_native(INTERP, ptr, value);
611 =item C<void set_number_keyed(PMC *key, FLOATVAL value)>
613 Sets the numeric value of the PMC at element C<key> to C<value>.
619 VTABLE void set_number_keyed(PMC *key, FLOATVAL value) {
626 ix = key_integer(INTERP, key);
627 nextkey = key_next(INTERP, key);
630 SELF.set_number_keyed_int(ix, value);
634 box = SELF.get_pmc_keyed_int(ix);
636 /* autovivify an Array */
638 box = pmc_new(INTERP, SELF.type());
640 VTABLE_set_number_keyed(INTERP, box, nextkey, value);
645 =item C<void set_string_keyed_int(INTVAL key, STRING *value)>
647 Sets the string value of the PMC at element C<key> to C<value>.
653 VTABLE void set_string_keyed_int(INTVAL key, STRING *value) {
655 Parrot_Array_set_pmc_ptr(INTERP, (List *)PMC_data(SELF), key);
657 VTABLE_set_string_native(INTERP, ptr, value);
662 =item C<void set_string_keyed(PMC *key, STRING *value)>
664 Sets the string value of the PMC at element C<key> to C<value>.
670 VTABLE void set_string_keyed(PMC *key, STRING *value) {
677 ix = key_integer(INTERP, key);
678 nextkey = key_next(INTERP, key);
681 VTABLE_set_string_keyed_int(INTERP, SELF, ix, value);
685 box = SELF.get_pmc_keyed_int(ix);
687 /* autovivify an Array */
689 box = pmc_new(INTERP, SELF.type());
691 VTABLE_set_string_keyed(INTERP, box, nextkey, value);
696 =item C<void set_pmc_keyed_int(INTVAL idx, PMC *src)>
698 Sets the PMC at element C<idx> to C<*src>.
704 VTABLE void set_pmc_keyed_int(INTVAL idx, PMC *src) {
705 const INTVAL length = ((List *)PMC_data(SELF))->length;
707 if (idx >= length || -idx > length)
708 real_exception(INTERP, NULL, E_IndexError,
709 "Array index out of bounds!");
711 list_assign(INTERP, (List *)PMC_data(SELF), idx,
712 (void *)src, enum_type_PMC);
717 =item C<void set_pmc_keyed(PMC *key, PMC *value)>
719 Sets the PMC at index C<key> to C<value>.
725 VTABLE void set_pmc_keyed(PMC *key, PMC *value) {
728 const INTVAL ix = key_integer(INTERP, key);
729 PMC * const nextkey = key_next(INTERP, key);
732 VTABLE_set_pmc_keyed_int(INTERP, SELF, ix, value);
736 box = SELF.get_pmc_keyed_int(ix);
738 /* autovivify an Array */
740 box = pmc_new(INTERP, SELF.type());
742 VTABLE_set_pmc_keyed(INTERP, box, nextkey, value);
747 =item C<void push_integer(INTVAL value)>
749 Extends the array by adding an element of value C<value> to the end of
756 VTABLE void push_integer(INTVAL value) {
757 const INTVAL nextix = SELF.elements();
758 SELF.set_integer_keyed_int(nextix, value);
763 =item C<void push_float(FLOATVAL value)>
765 Extends the array by adding an element of value C<value> to the end of
772 VTABLE void push_float(FLOATVAL value) {
773 const INTVAL nextix = SELF.elements();
774 SELF.set_number_keyed_int(nextix, value);
779 =item C<void push_string(STRING *value)>
781 Extends the array by adding an element of value C<*value> to the end of
788 VTABLE void push_string(STRING *value) {
789 const INTVAL nextix = SELF.elements();
790 SELF.set_string_keyed_int(nextix, value);
795 =item C<void push_pmc(PMC *value)>
797 Extends the array by adding an element of value C<*value> to the end of
804 void push_pmc(PMC *value) {
805 const INTVAL nextix = SELF.elements();
806 SELF.set_pmc_keyed_int(nextix, value);
811 =item C<void unshift_integer(INTVAL value)>
813 Extends the array by adding an element of value C<value> to the start
820 VTABLE void unshift_integer(INTVAL value) {
821 PMC * const val = undef(INTERP);
823 list_unshift(INTERP, (List *)PMC_data(SELF), val, enum_type_PMC);
824 VTABLE_set_integer_native(INTERP, val, value);
829 =item C<void unshift_float(FLOATVAL value)>
831 Extends the array by adding an element of value C<value> to the start
838 VTABLE void unshift_float(FLOATVAL value) {
839 PMC * const val = undef(INTERP);
841 list_unshift(INTERP, (List *)PMC_data(SELF), val, enum_type_PMC);
842 VTABLE_set_number_native(INTERP, val, value);
847 =item C<void unshift_string(STRING *value)>
849 Extends the array by adding an element of value C<*value> to the start
856 VTABLE void unshift_string(STRING *value) {
857 PMC * const val = undef(INTERP);
858 list_unshift(INTERP, (List *)PMC_data(SELF), val, enum_type_PMC);
859 VTABLE_set_string_native(INTERP, val, value);
864 =item C<void unshift_pmc(PMC *value)>
866 Extends the array by adding an element of value C<*value> to the start
873 void unshift_pmc(PMC *value) {
874 list_unshift(INTERP, (List *)PMC_data(SELF), value, enum_type_PMC);
879 =item C<INTVAL pop_integer()>
881 Removes and returns an integer from the end of the array.
887 VTABLE INTVAL pop_integer() {
888 PMC * const ptr = SELF.pop_pmc();
889 return VTABLE_get_integer(INTERP, ptr);
894 =item C<FLOATVAL pop_float()>
896 Removes and returns a float value from the end of the array.
902 VTABLE FLOATVAL pop_float() {
903 PMC * const ptr = SELF.pop_pmc();
904 return VTABLE_get_number(INTERP, ptr);
909 =item C<STRING *pop_string()>
911 Removes and returns a string from the end of the array.
917 VTABLE STRING *pop_string() {
918 PMC * const ptr = SELF.pop_pmc();
919 return VTABLE_get_string(INTERP, ptr);
924 =item C<PMC *pop_pmc()>
926 Removes and returns a PMC from the end of the array.
932 VTABLE PMC *pop_pmc() {
933 return retval(INTERP,
934 list_pop(INTERP, (List *)PMC_data(SELF), enum_type_PMC));
939 =item C<INTVAL shift_integer()>
941 Removes and returns an integer from the start of the array.
947 VTABLE INTVAL shift_integer() {
948 PMC * const ptr = SELF.shift_pmc();
949 return VTABLE_get_integer(INTERP, ptr);
954 =item C<FLOATVAL shift_float()>
956 Removes and returns a float from the start of the array.
962 VTABLE FLOATVAL shift_float() {
963 PMC * const ptr = SELF.shift_pmc();
964 return VTABLE_get_number(INTERP, ptr);
969 =item C<STRING *shift_string()>
971 Removes and returns a string from the start of the array.
977 VTABLE STRING *shift_string() {
978 PMC * const ptr = SELF.shift_pmc();
979 return VTABLE_get_string(INTERP, ptr);
984 =item C<PMC *shift_pmc()>
986 Removes and returns a PMC from the start of the array.
992 VTABLE PMC *shift_pmc() {
993 return retval(INTERP,
994 list_shift(INTERP, (List *)PMC_data(SELF), enum_type_PMC));
999 =item C<void splice(PMC *value, INTVAL offset, INTVAL count)>
1001 Replaces C<count> elements starting at C<offset> with the elements in
1004 If C<count> is 0 then the elements in C<value> will be inserted after
1011 void splice(PMC *value, INTVAL offset, INTVAL count) {
1012 if (SELF->vtable->base_type != value->vtable->base_type)
1013 real_exception(INTERP, NULL, E_TypeError,
1014 "Type mismatch in splice");
1016 list_splice(INTERP, (List *)PMC_data(SELF),
1017 (List *)PMC_data(value), offset, count);
1022 =item C<INTVAL defined_keyed_int(INTVAL key)>
1024 Returns TRUE is the element at C<key> is defined; otherwise returns false.
1030 VTABLE INTVAL defined_keyed_int(INTVAL key) {
1033 list_get(INTERP, (List *)PMC_data(pmc), key, enum_type_PMC);
1035 if (ret == 0 || ret == (void *) -1)
1038 value = *(PMC **)ret;
1043 return VTABLE_defined(INTERP, value);
1048 =item C<INTVAL defined_keyed(PMC *key)>
1050 Returns TRUE is the element at C<key> is defined; otherwise returns false.
1056 VTABLE INTVAL defined_keyed(PMC *key) {
1059 const INTVAL ix = key_integer(INTERP, key);
1060 PMC * const nextkey = key_next(INTERP, key);
1063 return SELF.defined_keyed_int(ix);
1065 box = SELF.get_pmc_keyed_int(ix);
1070 return VTABLE_defined_keyed(INTERP, box, nextkey);
1075 =item C<INTVAL exists_keyed_int(INTVAL key)>
1077 Returns TRUE is the element at C<key> exists; otherwise returns false.
1083 VTABLE INTVAL exists_keyed_int(INTVAL key) {
1084 void * ret = list_get(INTERP,
1085 (List *)PMC_data(pmc), key, enum_type_PMC);
1087 if (ret == 0 || ret == (void *)-1)
1090 return !PMC_IS_NULL(*(PMC **)ret);
1095 =item C<INTVAL exists_keyed(PMC *key)>
1097 Returns TRUE is the element at C<key> exists; otherwise returns false.
1103 VTABLE INTVAL exists_keyed(PMC *key) {
1106 const INTVAL ix = key_integer(INTERP, key);
1107 PMC * const nextkey = key_next(INTERP, key);
1110 return SELF.exists_keyed_int(ix);
1112 box = SELF.get_pmc_keyed_int(ix);
1117 return VTABLE_exists_keyed(INTERP, box, nextkey);
1122 =item C<void delete_keyed_int(INTVAL key)>
1124 Removes the element at C<key>.
1130 VTABLE void delete_keyed_int(INTVAL key) {
1131 list_splice(INTERP, (List *)PMC_data(pmc), NULL, key, 1);
1136 =item C<void delete_keyed(PMC *key)>
1138 Removes the element at C<*key>.
1144 VTABLE void delete_keyed(PMC *key) {
1145 const INTVAL ix = key_integer(INTERP, key);
1146 list_splice(INTERP, (List *)PMC_data(pmc), NULL, ix, 1);
1151 =item C<INTVAL is_equal(PMC *value)>
1153 The C<==> operation. Compares two array to hold equal elements.
1159 VTABLE INTVAL is_equal(PMC *value) {
1162 if (value->vtable->base_type != enum_class_Array)
1165 n = SELF.elements();
1167 if (VTABLE_elements(INTERP, value) != n)
1170 for (j = 0; j < n; ++j) {
1171 PMC * const item1 = SELF.get_pmc_keyed_int(j);
1172 PMC * const item2 = VTABLE_get_pmc_keyed_int(INTERP, value, j);
1175 if (!mmd_dispatch_i_pp(INTERP, item1, item2, MMD_EQ))
1184 =item C<PMC *slice(PMC *key, INTVAL f)>
1186 Return a new iterator for the slice PMC C<key> if f == 0.
1188 Return a new pythonic array slice if f == 1.
1190 =item C<PMC *get_iter()>
1192 Return a new iterator for SELF.
1198 VTABLE PMC *slice(PMC *key, INTVAL f) {
1200 PMC * const iter = pmc_new_init(INTERP, enum_class_Iterator, SELF);
1201 PMC_struct_val(iter) = key;
1205 real_exception(INTERP, NULL, E_TypeError, "Array: Unknown slice type");
1208 VTABLE PMC *get_iter() {
1209 PMC * const iter = pmc_new_init(INTERP, enum_class_Iterator, SELF);
1210 PMC * const key = pmc_new(INTERP, enum_class_Key);
1211 PMC_struct_val(iter) = key;
1212 PObj_get_FLAGS(key) |= KEY_integer_FLAG;
1213 PMC_int_val(key) = 0;
1215 if (!((List *)PMC_data(SELF))->length)
1216 PMC_int_val(key) = -1;
1223 =item C<void visit(visit_info *info)>
1225 This is used by freeze/thaw to visit the contents of the array.
1227 C<*info> is the visit info, (see F<include/parrot/pmc_freeze.h>).
1233 VTABLE void visit(visit_info *info) {
1234 list_visit(INTERP, (List *)PMC_data(SELF), info);
1240 =item C<void freeze(visit_info *info)>
1242 Used to archive the array.
1248 VTABLE void freeze(visit_info *info) {
1249 IMAGE_IO * const io = info->image_io;
1251 VTABLE_push_integer(INTERP, io, VTABLE_elements(INTERP, SELF));
1256 =item C<void thaw(visit_info *info)>
1258 Used to unarchive the array.
1264 VTABLE void thaw(visit_info *info) {
1265 IMAGE_IO * const io = info->image_io;
1268 if (info->extra_flags == EXTRA_IS_NULL) {
1269 SELF.set_integer_native(VTABLE_shift_integer(INTERP, io));
1275 =item C<PMC *share_ro()>
1277 Recursively make the array read-only and shared.
1282 VTABLE PMC *share_ro() {
1285 /* prevent infinite recursion */
1286 if (PObj_is_PMC_shared_TEST(SELF))
1287 real_exception(INTERP, NULL, INVALID_OPERATION, "share_ro on "
1288 "something that already is shared");
1290 _true = pmc_new(INTERP, enum_class_Integer);
1291 VTABLE_set_integer_native(INTERP, _true, 1);
1293 ret = pt_shared_fixup(INTERP, SELF);
1295 /* first set readonly */
1296 VTABLE_setprop(INTERP, ret, CONST_STRING(INTERP, "_ro"), _true);
1298 /* XXX do something that deals better with sparse lists */
1301 const INTVAL max = VTABLE_elements(INTERP, ret);
1303 for (i = 0; i < max; ++i) {
1305 (PMC *)list_get(INTERP, PMC_data_typed(ret, List *),
1308 if (!PMC_IS_NULL(value)) {
1309 /* XXX do we need to clone first? */
1310 PMC * const new_value = VTABLE_share_ro(INTERP, value);
1312 if (new_value != value)
1313 list_assign(INTERP, PMC_data_typed(ret, List *),
1314 i, new_value, enum_type_PMC);
1319 /* XXX FIXME workaround lack of metadata sharing */
1320 PMC_metadata(SELF) = NULL;
1332 F<src/list.c>, F<include/parrot/list.h>
1336 Create global immutable undef object.
1344 * c-file-style: "parrot"
1346 * vim: expandtab shiftwidth=4: