tagged release 0.7.1
[parrot.git] / src / pmc / fixedpmcarray.pmc
blobd2d61c3a3948c53da5858ae79956809982f141d2
1 /*
2 Copyright (C) 2001-2008, The Perl 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 #include "parrot/parrot.h"
29 pmclass FixedPMCArray need_ext provides array {
33 =item C<METHOD sort(PMC *cmp_func)>
35 Sort this array, optionally using the provided cmp_func
37 =cut
41     METHOD sort(PMC *cmp_func :optional) {
42         const UINTVAL n = (UINTVAL) PMC_int_val(SELF);
44         if (n > 1)
45            Parrot_quicksort(interp, PMC_data_typed(SELF, void **), n, cmp_func);
46     }
50 =back
52 =head2 Methods
54 =over 4
56 =item C<void init()>
58 Initializes the array.
60 =cut
64     VTABLE void init() {
65         PMC_int_val(SELF) = 0;
66         PMC_data(SELF)    = NULL;
67         PObj_active_destroy_SET(SELF);
68         PObj_data_is_PMC_array_SET(SELF);
69     }
73 =item C<void destroy()>
75 Destroys the array.
77 =cut
81     VTABLE void destroy() {
82         if (PMC_data(SELF)) {
83             mem_sys_free(PMC_data(SELF));
84             PMC_data(SELF) = NULL;
85         }
86         PMC_int_val(SELF) = 0;
87     }
91 =item C<PMC *clone()>
93 Creates and returns a copy of the array.
95 =cut
99     VTABLE PMC *clone() {
100         PMC * const dest  = pmc_new(INTERP, SELF->vtable->base_type);
101         const INTVAL size = PMC_int_val(SELF);
103         if (size) {
104             PMC_int_val(dest) = size;
105             PMC_data(dest)    = mem_allocate_n_typed(size, PMC *);
106             mem_copy_n_typed(PMC_data(dest), PMC_data(SELF), size, PMC *);
107             PObj_data_is_PMC_array_SET(dest);
108         }
110         return dest;
111     }
115 =item C<INTVAL get_bool()>
117 Returns whether the array has any elements (meaning been initialized, for a
118 fixed sized array).
120 =cut
123     VTABLE INTVAL get_bool() {
124         const INTVAL size = SELF.elements();
125         return (INTVAL)(size != 0);
126     }
130 =item C<INTVAL elements()>
132 =cut
136     VTABLE INTVAL elements() {
137         return PMC_int_val(SELF);
138     }
142 =item C<INTVAL get_integer()>
144 Returns the number of elements in the array.
146 =cut
150     VTABLE INTVAL get_integer() {
151         return SELF.elements();
152     }
156 =item C<FLOATVAL get_number()>
158 Returns the number of elements in the array.
160 =cut
164     VTABLE FLOATVAL get_number() {
165         const INTVAL e = SELF.elements();
166         return (FLOATVAL)e;
167     }
171 =item C<STRING *get_string()>
173 Returns the number of elements in the array as a Parrot string. (??? -leo)
175 =item C<STRING *get_repr()>
177 Returns a string representation of the array contents.
178 RT#46673 implement freeze/thaw and use that instead.
180 =cut
184     VTABLE STRING *get_string() {
185         return string_from_int(INTERP, SELF.elements());
186     }
188     VTABLE STRING *get_repr() {
189         STRING *res    = CONST_STRING(INTERP, "(");
190         const INTVAL n = VTABLE_elements(INTERP, SELF);
191         INTVAL  i;
193         for (i = 0; i < n; ++i) {
194             PMC * const val = SELF.get_pmc_keyed_int(i);
196             res = string_append(INTERP, res, VTABLE_get_repr(INTERP, val));
197             if (n == 1)
198                 res = string_append(INTERP, res, CONST_STRING(INTERP, ","));
199             else if (i < n - 1)
200                 res = string_append(INTERP, res, CONST_STRING(INTERP, ", "));
201         }
203         res = string_append(INTERP, res, CONST_STRING(INTERP, ")"));
205         return res;
206     }
210 =item C<INTVAL get_integer_keyed_int(INTVAL key)>
212 Returns the integer value of the element at index C<key>.
214 =cut
218     VTABLE INTVAL get_integer_keyed_int(INTVAL key) {
219         PMC * const tempPMC = SELF.get_pmc_keyed_int(key);
220         if (PMC_IS_NULL(tempPMC))
221             return 0;
222         return VTABLE_get_integer(INTERP, tempPMC);
223     }
227 =item C<INTVAL get_integer_keyed(PMC *key)>
229 Returns the integer value of the element at index C<*key>.
231 =cut
235     VTABLE INTVAL get_integer_keyed(PMC *key) {
236         PMC * const tempPMC = SELF.get_pmc_keyed(key);
237         return VTABLE_get_integer(INTERP, tempPMC);
238     }
242 =item C<FLOATVAL get_number_keyed_int(INTVAL key)>
244 Returns the floating-point value of the element at index C<key>.
246 =cut
250     VTABLE FLOATVAL get_number_keyed_int(INTVAL key) {
251         PMC * const tempPMC = SELF.get_pmc_keyed_int(key);
252         return VTABLE_get_number(INTERP, tempPMC);
253     }
257 =item C<FLOATVAL get_number_keyed(PMC *key)>
259 Returns the floating-point value of the element at index C<*key>.
261 =cut
265     VTABLE FLOATVAL get_number_keyed(PMC *key) {
266         PMC * const tempPMC = SELF.get_pmc_keyed(key);
267         return VTABLE_get_number(INTERP, tempPMC);
268     }
272 =item C<STRING *get_string_keyed_int(INTVAL key)>
274 Returns the Parrot string value of the element at index C<key>.
276 =cut
280     VTABLE STRING *get_string_keyed_int(INTVAL key) {
281         PMC * const tempPMC = SELF.get_pmc_keyed_int(key);
283         if (PMC_IS_NULL(tempPMC))
284             return CONST_STRING(interp, "");
286         return VTABLE_get_string(INTERP, tempPMC);
287     }
291 =item C<STRING *get_string_keyed(PMC *key)>
293 Returns the Parrot string value of the element at index C<*key>.
295 =cut
299     VTABLE STRING *get_string_keyed(PMC *key) {
300         PMC * const tempPMC = SELF.get_pmc_keyed(key);
301         return VTABLE_get_string(INTERP, tempPMC);
302     }
306 =item C<PMC *get_pmc_keyed_int(INTVAL key)>
308 Returns the PMC value of the element at index C<key>.
310 =cut
314     VTABLE PMC *get_pmc_keyed_int(INTVAL key) {
315         PMC **data;
317         if (key < 0 || key >= PMC_int_val(SELF))
318             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
319                 _("FixedPMCArray: index out of bounds!"));
321         data = (PMC **)PMC_data(SELF);
322         return data[key];
323     }
327 =item C<PMC *get_pmc_keyed(PMC *key)>
329 Returns the PMC value of the element at index C<*key>.
331 =cut
335     VTABLE PMC *get_pmc_keyed(PMC *key) {
336         const INTVAL k        = key_integer(INTERP, key);
337         PMC   * const nextkey = key_next(INTERP, key);
338         PMC   *box;
340         if (!nextkey)
341             return SELF.get_pmc_keyed_int(k);
343         box = SELF.get_pmc_keyed_int(k);
345         if (box == NULL)
346             box = pmc_new(INTERP, enum_class_Undef);
348         return VTABLE_get_pmc_keyed(INTERP, box, nextkey);
349     }
353 =item C<void set_integer_native(INTVAL size)>
355 Sizes the array to C<size> elements. Can't be used to resize an
356 array.
358 =cut
362     VTABLE void set_integer_native(INTVAL size) {
363         int i;
364         PMC **data;
366         if (PMC_int_val(SELF) && size)
367             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
368                     _("FixedPMCArray: Can't resize!"));
369         if (!size)
370             return;
372         PMC_int_val(SELF) = size;
373         data              = mem_allocate_n_zeroed_typed(size, PMC *);
375         for (i = 0; i < size; i++)
376             data[i] = PMCNULL;
378         PMC_data(SELF) = data;
379     }
381     VTABLE void set_pmc(PMC *value) {
382         INTVAL size;
383         INTVAL is_set_same;
385         if (SELF == value)
386             return;
388         if (!VTABLE_does(interp, value, CONST_STRING(interp, "array")))
389             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
390                     _("Can't set self from this type"));
392         if (PMC_data(SELF))
393             mem_sys_free(PMC_data(SELF));
395         /* If the value is a FixedPMCArray or a ResizablePMCArray itself, we
396          * can just copy the data directly. Otherwise, must use interface. */
397         is_set_same    = value->vtable->base_type == enum_class_FixedPMCArray ||
398                          value->vtable->base_type == enum_class_ResizablePMCArray;
400         size           = PMC_int_val(SELF) = is_set_same ?
401                                                 PMC_int_val(value) :
402                                                 VTABLE_elements(INTERP, value);
403         PMC_data(SELF) = mem_allocate_n_zeroed_typed(size, PMC *);
405         if (is_set_same) {
406             mem_sys_memcopy(PMC_data(SELF), PMC_data(value), size * sizeof (PMC *));
407         }
408         else {
409             INTVAL i;
410             for (i = 0; i < size; i++)
411                 ((PMC**)PMC_data(SELF))[i] = VTABLE_get_pmc_keyed_int(INTERP, value, i);
412         }
414         PMC_int_val2(SELF) = size;
415         PObj_data_is_PMC_array_SET(SELF);
416     }
419 =item C<void set_integer_keyed_int(INTVAL key, INTVAL value)>
421 Sets the integer value of the element at index C<key> to C<value>.
423 =cut
427     VTABLE void set_integer_keyed_int(INTVAL key, INTVAL value) {
428         PMC * const val = pmc_new(INTERP, Parrot_get_ctx_HLL_type(INTERP,
429                     enum_class_Integer));
431         VTABLE_set_integer_native(INTERP, val, value);
432         SELF.set_pmc_keyed_int(key, val);
433     }
437 =item C<void set_integer_keyed(PMC *key, INTVAL value)>
439 Sets the integer value of the element at index C<key> to C<value>.
441 =cut
445     VTABLE void set_integer_keyed(PMC *key, INTVAL value) {
446         PMC * const val = pmc_new(INTERP, Parrot_get_ctx_HLL_type(INTERP,
447                     enum_class_Integer));
449         VTABLE_set_integer_native(INTERP, val, value);
451         /* Let set_pmc_keyed worry about multi keys */
452         SELF.set_pmc_keyed(key, val);
453     }
457 =item C<void set_number_keyed_int(INTVAL key, FLOATVAL value)>
459 Sets the floating-point value of the element at index C<key> to
460 C<value>.
462 =cut
466     VTABLE void set_number_keyed_int(INTVAL key, FLOATVAL value) {
467         PMC * const val = pmc_new(INTERP, Parrot_get_ctx_HLL_type(INTERP,
468                     enum_class_Float));
470         VTABLE_set_number_native(INTERP, val, value);
471         SELF.set_pmc_keyed_int(key, val);
472     }
476 =item C<void set_number_keyed(PMC *key, FLOATVAL value)>
478 Sets the floating-point value of the element at index C<key> to
479 C<value>.
481 =cut
485     VTABLE void set_number_keyed(PMC *key, FLOATVAL value) {
486         const INTVAL k        = key_integer(INTERP, key);
487         PMC   * const nextkey = key_next(INTERP, key);
489         if (nextkey == NULL) {
490             SELF.set_number_keyed_int(k, value);
491         }
492         else {
493             PMC *box = SELF.get_pmc_keyed_int(k);
495             /* RT#46675: autovivify an Array and insert it in SELF */
496             if (!box)
497                 box = pmc_new(INTERP, SELF.type());
499             VTABLE_set_number_keyed(INTERP, box, nextkey, value);
500         }
501     }
505 =item C<void set_string_keyed_int(INTVAL key, STRING *value)>
507 Sets the Parrot string value of the element at index C<key> to C<value>.
509 =cut
513     VTABLE void set_string_keyed_int(INTVAL key, STRING *value) {
514         PMC * const val = pmc_new(INTERP, Parrot_get_ctx_HLL_type(INTERP,
515                     enum_class_String));
517         VTABLE_set_string_native(INTERP, val, value);
518         SELF.set_pmc_keyed_int(key, val);
519     }
523 =item C<void set_string_keyed(PMC *key, STRING *value)>
525 Sets the string value of the element at index C<key> to
526 C<value>.
528 =cut
532     VTABLE void set_string_keyed(PMC *key, STRING *value) {
533         PMC * const val = pmc_new(INTERP, Parrot_get_ctx_HLL_type(INTERP,
534                     enum_class_String));
536         VTABLE_set_string_native(INTERP, val, value);
538         /* Let set_pmc_keyed worry about multi keys */
539         SELF.set_pmc_keyed(key, val);
540     }
544 =item C<void set_pmc_keyed_int(INTVAL key, PMC *src)>
546 Sets the PMC value of the element at index C<key> to C<*src>.
548 =cut
552     VTABLE void set_pmc_keyed_int(INTVAL key, PMC *src) {
553         PMC **data;
555         if (key < 0 || key >= PMC_int_val(SELF))
556             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
557                 _("FixedPMCArray: index out of bounds!"));
559         data      = (PMC**)PMC_data(SELF);
560         GC_WRITE_BARRIER(INTERP, SELF, data[key], src);
561         data[key] = src;
562     }
566 =item C<void set_pmc_keyed(PMC *key, PMC *value)>
568 Sets the PMC at index C<key> to C<value>.
570 =cut
574     VTABLE void set_pmc_keyed(PMC *key, PMC *value) {
575         const INTVAL k = key_integer(INTERP, key);
576         PMC   *nextkey = key_next(INTERP, key);
578         if (!nextkey) {
579             SELF.set_pmc_keyed_int(k, value);
580         }
581         else {
582             PMC *box = SELF.get_pmc_keyed_int(k);
584             /* RT#46675: autovivify an Array and insert it in SELF */
585             if (!box)
586                 box = pmc_new(INTERP, SELF.type());
588             VTABLE_set_pmc_keyed(INTERP, box, nextkey, value);
589         }
590     }
594 =item C<INTVAL is_equal(PMC *value)>
596 The C<==> operation. Compares two array to hold equal elements.
598 =cut
602     VTABLE INTVAL is_equal(PMC *value) {
603         INTVAL j, n;
605         if (value->vtable->base_type != enum_class_FixedPMCArray)
606             return 0;
608         n = SELF.elements();
610         if (VTABLE_elements(INTERP, value) != n)
611             return 0;
613         for (j = 0; j < n; ++j) {
614             PMC * const item1 = SELF.get_pmc_keyed_int(j);
615             PMC * const item2 = VTABLE_get_pmc_keyed_int(INTERP, value, j);
617             if (item1 == item2)
618                 continue;
620             if (item1->vtable->base_type == enum_class_Null
621             ||  item2->vtable->base_type == enum_class_Null)
622                 return 0;
624             if (!mmd_dispatch_i_pp(INTERP, item1, item2, MMD_EQ))
625                 return 0;
626         }
628         return 1;
629     }
633 =item C<PMC *slice(PMC *key, INTVAL f)>
635 Return a new iterator for the slice PMC C<key> if f == 0.
637 Return a new pythonic array slice if f == 1.
639 =item C<PMC *get_iter()>
641 Return a new iterator for SELF.
643 =cut
647     VTABLE PMC *slice(PMC *key, INTVAL f) {
648         if (f == 0) {
649             STRING     *name = CONST_STRING(interp, "set_key");
650             PMC * const iter = pmc_new_init(INTERP, enum_class_Iterator, SELF);
651             Parrot_PCCINVOKE(interp, iter, name, "P->", key);
652             return iter;
653         }
655         Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
656                 _("Array: Unknown slice type"));
657     }
659     VTABLE PMC *get_iter() {
660         STRING     *name     = CONST_STRING(interp, "set_key");
661         PMC * const iter     = pmc_new_init(INTERP, enum_class_Iterator, SELF);
662         PMC * const key      = pmc_new(INTERP, enum_class_Key);
664         Parrot_PCCINVOKE(interp, iter, name, "P->", key);
665         PObj_get_FLAGS(key) |= KEY_integer_FLAG;
666         PMC_int_val(key)     = 0;
668         if (PMC_int_val(SELF) == 0)
669             PMC_int_val(key) = -1;
671         return iter;
672     }
676 =item C<INTVAL exists_keyed_int(INTVAL key)>
678 =item C<INTVAL exists_keyed_int(PMC *key)>
680 Returns TRUE is the element at C<key> exists; otherwise returns false.
682 =cut
685     VTABLE INTVAL exists_keyed_int(INTVAL key) {
686         PMC **data;
687         if (key < 0 || key >= PMC_int_val(SELF))
688             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
689                 _("FixedPMCArray: index out of bounds!"));
691         data = (PMC**)PMC_data(SELF);
692         return !PMC_IS_NULL(data[key]);
693     }
695     VTABLE INTVAL exists_keyed(PMC *key) {
696         const INTVAL ix = key_integer(INTERP, key);
697         return SELF.exists_keyed_int(ix);
698     }
702 =item C<void splice(PMC *value, INTVAL offset, INTVAL count)>
704 Replaces C<count> elements starting at C<offset> with the elements in C<value>.
706 If C<count> is 0 then the elements in C<value> will be inserted after
707 C<offset>.
709 This throws an exception if any of the spliced in values are out of the range
710 of this array.
714     void splice(PMC *value, INTVAL offset, INTVAL count) {
715         if (count + offset > PMC_int_val(SELF))
716             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
717                 _("FixedPMCArray: index out of bounds!"));
719         for (count--; count >= 0; --count) {
720             VTABLE_set_pmc_keyed_int(INTERP, SELF, offset + count, value);
721         }
722     }
727 =item C<void visit(visit_info *info)>
729 This is used by freeze/thaw to visit the contents of the array.
731 C<*info> is the visit info, (see F<include/parrot/pmc_freeze.h>).
733 =item C<void freeze(visit_info *info)>
735 Used to archive the array.
737 =item C<void thaw(visit_info *info)>
739 Used to unarchive the array.
741 =cut
745     VTABLE void visit(visit_info *info) {
746         INTVAL  i;
747         const INTVAL n = VTABLE_elements(INTERP, SELF);
748         PMC   **pos    = (PMC **)PMC_data(SELF);
750         for (i = 0; i < n; ++i, ++pos) {
751             info->thaw_ptr = pos;
752             (info->visit_pmc_now)(INTERP, *pos, info);
753         }
755         SUPER(info);
756     }
758     VTABLE void freeze(visit_info *info) {
759         IMAGE_IO * const io = info->image_io;
760         SUPER(info);
761         VTABLE_push_integer(INTERP, io, VTABLE_elements(INTERP, SELF));
762     }
764     VTABLE void thaw(visit_info *info) {
765         IMAGE_IO * const io = info->image_io;
766         SUPER(info);
767         if (info->extra_flags == EXTRA_IS_NULL)
768             SELF.set_integer_native(VTABLE_shift_integer(INTERP, io));
769     }
773 =item C<INTVAL defined_keyed_int(INTVAL key)>
775 Returns TRUE is the element at C<key> is defined; otherwise returns false.
777 =cut
781     VTABLE INTVAL defined_keyed_int(INTVAL key) {
782         PMC * const val = SELF.get_pmc_keyed_int(key);
784         if (PMC_IS_NULL(val))
785             return 0;
787         return VTABLE_defined(INTERP, val);
788     }
794 =back
796 =head1 SEE ALSO
798 F<docs/pdds/pdd17_basic_types.pod>.
800 =cut
805  * Local variables:
806  *   c-file-style: "parrot"
807  * End:
808  * vim: expandtab shiftwidth=4:
809  */