[t][TT#1509] Prevent core dumps by preventing negative length array creation. Tests...
[parrot.git] / src / pmc / fixedpmcarray.pmc
blob451f9927e6f6d4a00f43750dbc4bba180b4250a3
1 /*
2 Copyright (C) 2001-2010, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/pmc/fixedpmcarray.pmc - fixed size array for PMCs only
9 =head1 DESCRIPTION
11 This class, FixedPMCArray, implements an array of fixed size which stores PMCs.
12 It puts things into Integer, Float, or String PMCs as appropriate
14 =head2 Note
16 The flag C<PObj_private0_FLAG> is used in the C<NameSpace> PMC and should
17 never be set for user arrays.
19 =head2 Functions
21 =over 4
23 =cut
27 #define PMC_size(x)  ((Parrot_FixedPMCArray_attributes *)PMC_data(x))->size
28 #define PMC_array(x) ((Parrot_FixedPMCArray_attributes *)PMC_data(x))->pmc_array
30 pmclass FixedPMCArray auto_attrs provides array {
31     ATTR INTVAL   size;      /* number of elements in the array */
32     ATTR PMC    **pmc_array; /* pointer to PMC array */
36 =item C<METHOD sort(PMC *cmp_func)>
38 Sort this array, optionally using the provided cmp_func
40 =cut
44     METHOD sort(PMC *cmp_func :optional) {
45         const INTVAL n = SELF.elements();
47         if (n > 1) {
48             /* XXX Workaround for TT #218 */
49             if (PObj_is_object_TEST(SELF)) {
50                 PMC *parent = SELF.get_attr_str(CONST_STRING(interp, "proxy"));
51                 Parrot_pcc_invoke_method_from_c_args(interp, parent, CONST_STRING(interp, "sort"), "P->", cmp_func);
52             }
53             else
54                 Parrot_quicksort(interp, (void **)PMC_array(SELF), n, cmp_func);
55         }
56         RETURN(PMC *SELF);
57     }
61 =back
63 =head2 Methods
65 =over 4
67 =item C<void init()>
69 Initializes the array.
71 =cut
75     VTABLE void init() {
76         PObj_custom_mark_destroy_SETALL(SELF);
77     }
81 =item C<void init_int(INTVAL size)>
83 Initializes the array.
85 =cut
89     VTABLE void init_int(INTVAL size) {
90         PMC **data;
91         int i;
93         if (size < 0)
94             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
95                     _("FixedPMCArray: Cannot set array size to a negative number (%d)"),size);
97         SET_ATTR_size(INTERP, SELF, size);
98         data           = mem_gc_allocate_n_typed(INTERP, size, PMC *);
100         for (i = 0; i < size; i++)
101             data[i] = PMCNULL;
103         PObj_custom_destroy_SET(SELF);
104     }
108 =item C<void destroy()>
110 Destroys the array.
112 =cut
116     VTABLE void destroy() {
117         if (PMC_array(SELF))
118             mem_gc_free(INTERP, PMC_array(SELF));
119     }
123 =item C<PMC *clone()>
125 Creates and returns a copy of the array.
127 =cut
131     VTABLE PMC *clone() {
132         PMC * const dest  = Parrot_pmc_new(INTERP, SELF->vtable->base_type);
133         const INTVAL size = PMC_size(SELF);
135         if (size) {
136             PMC_size(dest)  = size;
137             PMC_array(dest) = mem_gc_allocate_n_zeroed_typed(INTERP, size, PMC *);
138             mem_copy_n_typed(PMC_array(dest), PMC_array(SELF), size, PMC *);
139             PObj_custom_mark_destroy_SETALL(dest);
140         }
142         return dest;
143     }
147 =item C<INTVAL get_bool()>
149 Returns whether the array has any elements (meaning been initialized, for a
150 fixed sized array).
152 =cut
155     VTABLE INTVAL get_bool() {
156         const INTVAL size = SELF.elements();
157         return (INTVAL)(size != 0);
158     }
162 =item C<INTVAL elements()>
164 =cut
168     VTABLE INTVAL elements() {
169         return PMC_size(SELF);
170     }
174 =item C<INTVAL get_integer()>
176 Returns the number of elements in the array.
178 =cut
182     VTABLE INTVAL get_integer() {
183         return SELF.elements();
184     }
188 =item C<FLOATVAL get_number()>
190 Returns the number of elements in the array.
192 =cut
196     VTABLE FLOATVAL get_number() {
197         const INTVAL e = SELF.elements();
198         return (FLOATVAL)e;
199     }
203 =item C<STRING *get_string()>
205 Returns the number of elements in the array as a Parrot string. (??? -leo)
207 =item C<STRING *get_repr()>
209 Returns a string representation of the array contents.
210 TT #1229: implement freeze/thaw and use that instead.
212 =cut
216     VTABLE STRING *get_string() {
217         return Parrot_str_from_int(INTERP, SELF.elements());
218     }
220     VTABLE STRING *get_repr() {
221         STRING *res    = CONST_STRING(INTERP, "(");
222         const INTVAL n = VTABLE_elements(INTERP, SELF);
223         INTVAL  i;
225         for (i = 0; i < n; ++i) {
226             PMC * const val = SELF.get_pmc_keyed_int(i);
227             if (i > 0)
228                 res = Parrot_str_append(INTERP, res, CONST_STRING(INTERP, ", "));
230             res = Parrot_str_append(INTERP, res, VTABLE_get_repr(INTERP, val));
231         }
233         res = Parrot_str_append(INTERP, res, CONST_STRING(INTERP, ")"));
235         return res;
236     }
240 =item C<INTVAL get_integer_keyed_int(INTVAL key)>
242 Returns the integer value of the element at index C<key>.
244 =cut
248     VTABLE INTVAL get_integer_keyed_int(INTVAL key) {
249         PMC * const tempPMC = SELF.get_pmc_keyed_int(key);
250         if (PMC_IS_NULL(tempPMC))
251             return 0;
252         return VTABLE_get_integer(INTERP, tempPMC);
253     }
257 =item C<INTVAL get_integer_keyed(PMC *key)>
259 Returns the integer value of the element at index C<*key>.
261 =cut
265     VTABLE INTVAL get_integer_keyed(PMC *key) {
266         PMC * const tempPMC = SELF.get_pmc_keyed(key);
267         return VTABLE_get_integer(INTERP, tempPMC);
268     }
272 =item C<FLOATVAL get_number_keyed_int(INTVAL key)>
274 Returns the floating-point value of the element at index C<key>.
276 =cut
280     VTABLE FLOATVAL get_number_keyed_int(INTVAL key) {
281         PMC * const tempPMC = SELF.get_pmc_keyed_int(key);
282         return VTABLE_get_number(INTERP, tempPMC);
283     }
287 =item C<FLOATVAL get_number_keyed(PMC *key)>
289 Returns the floating-point value of the element at index C<*key>.
291 =cut
295     VTABLE FLOATVAL get_number_keyed(PMC *key) {
296         PMC * const tempPMC = SELF.get_pmc_keyed(key);
297         return VTABLE_get_number(INTERP, tempPMC);
298     }
302 =item C<STRING *get_string_keyed_int(INTVAL key)>
304 Returns the Parrot string value of the element at index C<key>.
306 =cut
310     VTABLE STRING *get_string_keyed_int(INTVAL key) {
311         PMC * const retval = SELF.get_pmc_keyed_int(key);
313         if (PMC_IS_NULL(retval))
314             return string_from_literal(interp, "");
316         return VTABLE_get_string(INTERP, retval);
317     }
321 =item C<STRING *get_string_keyed(PMC *key)>
323 Returns the Parrot string value of the element at index C<*key>.
325 =cut
329     VTABLE STRING *get_string_keyed(PMC *key) {
330         PMC * const tempPMC = SELF.get_pmc_keyed(key);
331         return VTABLE_get_string(INTERP, tempPMC);
332     }
336 =item C<PMC *get_pmc_keyed_int(INTVAL key)>
338 Returns the PMC value of the element at index C<key>.
340 =cut
344     VTABLE PMC *get_pmc_keyed_int(INTVAL key) {
345         PMC **data;
347         if (key < 0 || key >= PMC_size(SELF))
348             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
349                 _("FixedPMCArray: index out of bounds!"));
351         data = PMC_array(SELF);
352         return data[key];
353     }
357 =item C<PMC *get_pmc_keyed(PMC *key)>
359 Returns the PMC value of the element at index C<*key>.
361 =cut
365     VTABLE PMC *get_pmc_keyed(PMC *key) {
366         const INTVAL k        = VTABLE_get_integer(INTERP, key);
367         PMC   * const nextkey = key_next(INTERP, key);
368         PMC   *box;
370         if (!nextkey)
371             return SELF.get_pmc_keyed_int(k);
373         box = SELF.get_pmc_keyed_int(k);
375         if (box == NULL)
376             box = Parrot_pmc_new(INTERP, enum_class_Undef);
378         return VTABLE_get_pmc_keyed(INTERP, box, nextkey);
379     }
383 =item C<void set_integer_native(INTVAL size)>
385 Sizes the array to C<size> elements. Can't be used to resize an
386 array.
388 =cut
392     VTABLE void set_integer_native(INTVAL size) {
393         int i;
394         PMC **data;
396         if (PMC_size(SELF) && size)
397             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
398                     _("FixedPMCArray: Can't resize!"));
399         if (!size)
400             return;
402         if (size < 0)
403             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
404                     _("FixedPMCArray: Cannot set array size to a negative number"));
406         PMC_size(SELF) = size;
407         data           = mem_gc_allocate_n_zeroed_typed(INTERP, size, PMC *);
409         for (i = 0; i < size; i++)
410             data[i] = PMCNULL;
412         PMC_array(SELF) = data;
413     }
415     VTABLE void set_pmc(PMC *value) {
416         INTVAL size;
417         INTVAL i;
419         if (SELF == value)
420             return;
422         if (!VTABLE_does(interp, value, CONST_STRING(interp, "array")))
423             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
424                     _("Can't set self from this type"));
426         if (PMC_array(SELF))
427             mem_gc_free(INTERP, PMC_array(SELF));
429         size            = PMC_size(SELF) = VTABLE_elements(INTERP, value);
430         PMC_array(SELF) = mem_gc_allocate_n_zeroed_typed(INTERP, size, PMC *);
432         for (i = 0; i < size; i++)
433             (PMC_array(SELF))[i] = VTABLE_get_pmc_keyed_int(INTERP, value, i);
435         PObj_custom_mark_destroy_SETALL(SELF);
436     }
439 =item C<void set_integer_keyed_int(INTVAL key, INTVAL value)>
441 Sets the integer value of the element at index C<key> to C<value>.
443 =cut
447     VTABLE void set_integer_keyed_int(INTVAL key, INTVAL value) {
448         PMC * const val = Parrot_pmc_new(INTERP, Parrot_get_ctx_HLL_type(INTERP,
449                     enum_class_Integer));
451         VTABLE_set_integer_native(INTERP, val, value);
452         SELF.set_pmc_keyed_int(key, val);
453     }
457 =item C<void set_integer_keyed(PMC *key, INTVAL value)>
459 Sets the integer value of the element at index C<key> to C<value>.
461 =cut
465     VTABLE void set_integer_keyed(PMC *key, INTVAL value) {
466         PMC * const val = Parrot_pmc_new(INTERP, Parrot_get_ctx_HLL_type(INTERP,
467                     enum_class_Integer));
469         VTABLE_set_integer_native(INTERP, val, value);
471         /* Let set_pmc_keyed worry about multi keys */
472         SELF.set_pmc_keyed(key, val);
473     }
477 =item C<void set_number_keyed_int(INTVAL key, FLOATVAL value)>
479 Sets the floating-point value of the element at index C<key> to
480 C<value>.
482 =cut
486     VTABLE void set_number_keyed_int(INTVAL key, FLOATVAL value) {
487         PMC * const val = Parrot_pmc_new(INTERP, Parrot_get_ctx_HLL_type(INTERP,
488                     enum_class_Float));
490         VTABLE_set_number_native(INTERP, val, value);
491         SELF.set_pmc_keyed_int(key, val);
492     }
496 =item C<void set_number_keyed(PMC *key, FLOATVAL value)>
498 Sets the floating-point value of the element at index C<key> to
499 C<value>.
501 =cut
505     VTABLE void set_number_keyed(PMC *key, FLOATVAL value) {
506         const INTVAL k        = VTABLE_get_integer(INTERP, key);
507         PMC   * const nextkey = key_next(INTERP, key);
509         if (nextkey == NULL) {
510             SELF.set_number_keyed_int(k, value);
511         }
512         else {
513             PMC *box = SELF.get_pmc_keyed_int(k);
515             /* TT #1295: autovivify an Array and insert it in SELF */
516             if (!box)
517                 box = Parrot_pmc_new(INTERP, SELF.type());
519             VTABLE_set_number_keyed(INTERP, box, nextkey, value);
520         }
521     }
525 =item C<void set_string_keyed_int(INTVAL key, STRING *value)>
527 Sets the Parrot string value of the element at index C<key> to C<value>.
529 =cut
533     VTABLE void set_string_keyed_int(INTVAL key, STRING *value) {
534         PMC * const val = Parrot_pmc_new(INTERP, Parrot_get_ctx_HLL_type(INTERP,
535                     enum_class_String));
537         VTABLE_set_string_native(INTERP, val, value);
538         SELF.set_pmc_keyed_int(key, val);
539     }
543 =item C<void set_string_keyed(PMC *key, STRING *value)>
545 Sets the string value of the element at index C<key> to
546 C<value>.
548 =cut
552     VTABLE void set_string_keyed(PMC *key, STRING *value) {
553         PMC * const val = Parrot_pmc_new(INTERP, Parrot_get_ctx_HLL_type(INTERP,
554                     enum_class_String));
556         VTABLE_set_string_native(INTERP, val, value);
558         /* Let set_pmc_keyed worry about multi keys */
559         SELF.set_pmc_keyed(key, val);
560     }
564 =item C<void set_pmc_keyed_int(INTVAL key, PMC *src)>
566 Sets the PMC value of the element at index C<key> to C<*src>.
568 =cut
572     VTABLE void set_pmc_keyed_int(INTVAL key, PMC *src) {
573         PMC **data;
575         if (key < 0 || key >= PMC_size(SELF))
576             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
577                 _("FixedPMCArray: index out of bounds!"));
579         data      = PMC_array(SELF);
580         data[key] = src;
581     }
585 =item C<void set_pmc_keyed(PMC *key, PMC *value)>
587 Sets the PMC at index C<key> to C<value>.
589 =cut
593     VTABLE void set_pmc_keyed(PMC *key, PMC *value) {
594         const INTVAL k = VTABLE_get_integer(INTERP, key);
595         PMC   *nextkey = key_next(INTERP, key);
597         if (!nextkey) {
598             SELF.set_pmc_keyed_int(k, value);
599         }
600         else {
601             PMC *box = SELF.get_pmc_keyed_int(k);
603             /* TT #1295: autovivify an Array and insert it in SELF */
604             if (!box)
605                 box = Parrot_pmc_new(INTERP, SELF.type());
607             VTABLE_set_pmc_keyed(INTERP, box, nextkey, value);
608         }
609     }
613 =item C<INTVAL is_equal(PMC *value)>
615 The C<==> operation. Compares two array to hold equal elements.
617 =cut
621     VTABLE INTVAL is_equal(PMC *value) {
622         INTVAL j, n;
624         if (value->vtable->base_type != SELF->vtable->base_type)
625             return 0;
627         n = SELF.elements();
629         if (VTABLE_elements(INTERP, value) != n)
630             return 0;
632         for (j = 0; j < n; ++j) {
633             PMC * const item1 = SELF.get_pmc_keyed_int(j);
634             PMC * const item2 = VTABLE_get_pmc_keyed_int(INTERP, value, j);
636             if (item1 == item2)
637                 continue;
639             if (item1->vtable->base_type == enum_class_Null
640             ||  item2->vtable->base_type == enum_class_Null)
641                 return 0;
643             if (!VTABLE_is_equal(interp, item1, item2))
644                 return 0;
645         }
647         return 1;
648     }
653 =item C<PMC *get_iter()>
655 Return a new iterator for SELF.
657 =cut
661     VTABLE PMC *get_iter() {
662         return Parrot_pmc_new_init(INTERP, enum_class_ArrayIterator, SELF);
663     }
667 =item C<INTVAL exists_keyed_int(INTVAL key)>
669 =item C<INTVAL exists_keyed_int(PMC *key)>
671 Returns TRUE is the element at C<key> exists; otherwise returns false.
673 =cut
676     VTABLE INTVAL exists_keyed_int(INTVAL key) {
677         PMC **data;
678         if (key < 0 || key >= PMC_size(SELF))
679             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
680                 _("FixedPMCArray: index out of bounds!"));
682         data = PMC_array(SELF);
683         return !PMC_IS_NULL(data[key]);
684     }
686     VTABLE INTVAL exists_keyed(PMC *key) {
687         const INTVAL ix = VTABLE_get_integer(INTERP, key);
688         return SELF.exists_keyed_int(ix);
689     }
693 =item C<void splice(PMC *value, INTVAL offset, INTVAL count)>
695 Replaces C<count> elements starting at C<offset> with the elements in C<value>.
697 If C<count> is 0 then the elements in C<value> will be inserted after
698 C<offset>.
700 This throws an exception if any of the spliced in values are out of the range
701 of this array.
703 =cut
707     VTABLE void splice(PMC *value, INTVAL offset, INTVAL count) {
708         if (count + offset > PMC_size(SELF))
709             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
710                 _("FixedPMCArray: index out of bounds!"));
712         for (count--; count >= 0; --count) {
713             VTABLE_set_pmc_keyed_int(INTERP, SELF, offset + count, value);
714         }
715     }
720 =item C<void visit(PMC *info)>
722 This is used by freeze/thaw to visit the contents of the array.
724 C<*info> is the visit info, (see F<include/parrot/pmc_freeze.h>).
726 =item C<void freeze(PMC *info)>
728 Used to archive the array.
730 =item C<void thaw(PMC *info)>
732 Used to unarchive the array.
734 =cut
738     VTABLE void visit(PMC *info) {
739         INTVAL  i;
740         const INTVAL n = VTABLE_elements(INTERP, SELF);
741         PMC   **pos    = PMC_array(SELF);
743         for (i = 0; i < n; ++i, ++pos) {
744             VISIT_PMC(INTERP, info, *pos);
745         }
747         SUPER(info);
748     }
750     VTABLE void freeze(PMC *info) {
751         SUPER(info);
752         VTABLE_push_integer(INTERP, info, VTABLE_elements(INTERP, SELF));
753     }
755     VTABLE void thaw(PMC *info) {
756         SUPER(info);
757         SELF.set_integer_native(VTABLE_shift_integer(INTERP, info));
758     }
762 =item C<INTVAL defined_keyed_int(INTVAL key)>
764 Returns TRUE is the element at C<key> is defined; otherwise returns false.
766 =cut
770     VTABLE INTVAL defined_keyed_int(INTVAL key) {
771         PMC * const val = SELF.get_pmc_keyed_int(key);
773         if (PMC_IS_NULL(val))
774             return 0;
776         return VTABLE_defined(INTERP, val);
777     }
781 =item C<void mark(void)>
783 Mark the array.
785 =cut
789     VTABLE void mark() {
790         PMC ** const data = PMC_array(SELF);
791         INTVAL i;
793         if (!data)
794             return;
796         for (i = PMC_size(SELF) - 1; i >= 0; --i)
797             Parrot_gc_mark_PMC_alive(interp, data[i]);
798     }
806 =back
808 =head1 SEE ALSO
810 F<docs/pdds/pdd17_basic_types.pod>.
812 =cut
817  * Local variables:
818  *   c-file-style: "parrot"
819  * End:
820  * vim: expandtab shiftwidth=4:
821  */