tagged release 0.6.4
[parrot.git] / src / pmc / sarray.pmc
blobdfab2fd6d553ca9bd85ddcf16ef237df08f045ca
1 /*
2 Copyright (C) 2001-2008, The Perl Foundation.
3 $Id$
5 =head1 NAME
7 src/pmc/sarray.pmc - Simple Array or Subroutine Parameter Array
9 =head1 DESCRIPTION
11 Simple Array or Subroutine Parameter Array PMC.
12 SArray data are kept in an malloced array of C<HashEntry>s:
14 =over 4
16 =item 0 C<start_idx>
18 First index, for C<shift>.
20 =item 1 C<end_idx>
22 Last index, for C<push>.
24 =item 2...
26 Data.
28 =back
30 SArrays are fixed size, implying that the first operation on it must be
31 setting its size, and that only the most important vtable methods are
32 implemented.
34 Currently SArrays are used for:
36 =over 4
38 =item Global data per interpreter
40 =item Implementing lists, see F<src/list.c>.
42 =item Base class of the Exception PMC, see F<src/exception.pmc>
44 =back
46 =head2 Functions
48 =over 4
50 =cut
54 #include "parrot/parrot.h"
58 =item C<static PARROT_INLINE INTVAL
59 ret_int(PARROT_INTERP, const HashEntry *e)>
61 Processes C<*e>, returning the appropriate integer, or raising an
62 exception if necessary.
64 =cut
68 static PARROT_INLINE INTVAL
69 ret_int(PARROT_INTERP, const HashEntry *e)
71     switch (e->type) {
72         case enum_hash_int:
73             return UVal_int(e->val);
74         case enum_hash_pmc:
75             return VTABLE_get_integer(interp, UVal_pmc(e->val));
76         default:
77             break;
78     }
80     real_exception(interp, NULL, E_IndexError, "SArray: Entry not an integer!");
85 =item C<static PARROT_INLINE FLOATVAL
86 ret_num(PARROT_INTERP, const HashEntry *e)>
88 Processes C<*e>, returning the appropriate floating-point number, or
89 raising an exception if necessary.
91 =cut
95 static PARROT_INLINE FLOATVAL
96 ret_num(PARROT_INTERP, const HashEntry *e)
98     switch (e->type) {
99         case enum_hash_num:
100             return UVal_num(e->val);
101         case enum_hash_pmc:
102             return VTABLE_get_number(interp, UVal_pmc(e->val));
103         default:
104             break;
105     }
107     real_exception(interp, NULL, E_IndexError, "SArray: Entry not a number!");
112 =item C<static PARROT_INLINE STRING *
113 ret_string(PARROT_INTERP, HashEntry *e)>
115 Processes C<*e>, returning the appropriate Parrot string, or raising an
116 exception if necessary.
118 =cut
122 static PARROT_INLINE STRING*
123 ret_string(PARROT_INTERP, const HashEntry *e)
125     switch (e->type) {
126         case enum_hash_string:
127             return UVal_str(e->val);
128         case enum_hash_pmc:
129             return VTABLE_get_string(interp, UVal_pmc(e->val));
130         default:
131             break;
132     }
134     real_exception(interp, NULL, E_IndexError, "SArray: Entry not a string!");
139 =item C<static PARROT_INLINE PMC *
140 ret_pmc(PARROT_INTERP, const HashEntry *e)>
142 Processes C<*e>, returning the appropriate PMC, or raising an exception
143 if necessary.
145 =cut
149 static PARROT_INLINE PMC*
150 ret_pmc(PARROT_INTERP, const HashEntry *e)
152     PMC *ret;
153     switch (e->type) {
154         case enum_hash_int:
155             ret = pmc_new(interp, enum_class_Undef);
156             VTABLE_set_integer_native(interp, ret, UVal_int(e->val));
157             return ret;
158         case enum_hash_num:
159             ret = pmc_new(interp, enum_class_Undef);
160             VTABLE_set_number_native(interp, ret, UVal_num(e->val));
161             return ret;
162         case enum_hash_string:
163             ret = pmc_new(interp, enum_class_Undef);
164             VTABLE_set_string_native(interp, ret, UVal_str(e->val));
165             return ret;
166         case enum_hash_pmc:
167             return UVal_pmc(e->val);
168         default:
169             real_exception(interp, NULL, E_IndexError, "SArray: Unknown entry!");
170     }
175 =item C<static PARROT_INLINE HashEntry *
176 shift_entry(PARROT_INTERP, PMC *self)>
178 Removes and returns the first element from the array.
180 =cut
184 static PARROT_INLINE HashEntry *
185 shift_entry(PARROT_INTERP, PMC *self)
187     HashEntry   * const e    = (HashEntry *) PMC_data(self);
188     INTVAL       start_index = UVal_int(e[0].val);
189     const INTVAL end_index   = UVal_int(e[1].val);
190     HashEntry   *ret;
192     if (start_index >= end_index)
193         real_exception(interp, NULL, OUT_OF_BOUNDS,
194             "SArray index out of bounds!");
196     ret = (HashEntry *) PMC_data(self) + (2 + start_index++);
198     /* Update the starting index */
199     UVal_int(e[0].val) = start_index;
200     return ret;
205 =item C<static PARROT_INLINE HashEntry *
206 get_entry(PARROT_INTERP, PMC *self, INTVAL key)>
208 Returns the element for index C<key>.
210 =cut
214 static PARROT_INLINE HashEntry*
215 get_entry(PARROT_INTERP, PMC *self, INTVAL key)
217     HashEntry   *e           = (HashEntry *)PMC_data(self);
218     const INTVAL start_index = UVal_int(e[0].val);
219     const INTVAL end_index   = UVal_int(e[1].val);
221     if (key < 0)
222         key += end_index;
224     key += start_index;   /* lower bound if already shifted */
226     if (key < start_index || key >= end_index)
227         real_exception(interp, NULL, OUT_OF_BOUNDS,
228             "SArray index out of bounds!");
230     return (HashEntry *)PMC_data(self) + (2 + key);
233 pmclass SArray need_ext provides array {
237 =back
239 =head2 Methods
241 =over 4
243 =item C<void init()>
245 Initializes the array.
247 =cut
251     VTABLE void init() {
252         PMC_int_val(SELF) = 0;
253         PMC_data(SELF)    = NULL;
254     }
259 =item C<void mark()>
261 Marks the array as live.
263 =cut
267     VTABLE void mark() {
268         HashEntry *e;
269         int        i, start, end;
271         if (!PMC_data(SELF))
272             return;
274         e     = (HashEntry *)PMC_data(SELF);
275         start = UVal_int(e[0].val);
276         end   = UVal_int(e[1].val);
277         e     = (HashEntry *)PMC_data(SELF) + (2 + start);
279         for (i = start; i < end; i++, e++) {
280             switch (e->type) {
281                 case enum_hash_string:
282                     if (UVal_str(e->val))
283                         pobject_lives(INTERP, (PObj *)UVal_str(e->val));
284                     break;
285                 case enum_hash_pmc:
286                     if (UVal_pmc(e->val))
287                         pobject_lives(INTERP, (PObj *)UVal_pmc(e->val));
288                     break;
289                 default:
290                     break;
291             }
292         }
293     }
297 =item C<void destroy()>
299 Destroys the array.
301 =cut
305     VTABLE void destroy() {
306         if (PMC_data(SELF))
307             mem_sys_free(PMC_data(SELF));
308         PMC_data(SELF) = NULL;
309     }
313 =item C<PMC *clone()>
315 Creates and returns a copy of the array.
317 =cut
321     VTABLE PMC *clone() {
322         HashEntry *e, *d;
323         int i, start, end;
324         INTVAL size;
325         PMC * const dest = pmc_new(INTERP, SELF->vtable->base_type);
327         if (!PMC_data(SELF))
328             return dest;
330         size              = PMC_int_val(SELF);
331         PMC_int_val(dest) = size;
332         PMC_data(dest)    = mem_allocate_n_zeroed_typed(2 + size, HashEntry);
334         e     = (HashEntry *)PMC_data(SELF);
335         d     = (HashEntry *)PMC_data(dest);
336         start = UVal_int(e[0].val);
337         end   = UVal_int(e[1].val);
339         UVal_int(d[0].val) = start;
340         UVal_int(d[1].val) = end;
342         e = (HashEntry *)PMC_data(SELF) + (2 + start);
343         d = (HashEntry *)PMC_data(dest) + (2 + start);
345         for (i = start; i < end; i++, e++, d++) {
346             d->type = e->type;
347             switch (e->type) {
348                 case enum_hash_int:
349                     UVal_int(d->val) = UVal_int(e->val);
350                     break;
351                 case enum_hash_num:
352                     UVal_num(d->val) = UVal_num(e->val);
353                     break;
354                 case enum_hash_string:
355                     UVal_str(d->val) =
356                         string_copy(INTERP, UVal_str(e->val));
357                     break;
358                 case enum_hash_pmc:
359                     UVal_pmc(d->val) =
360                         VTABLE_clone(INTERP, UVal_pmc(e->val));
361                     break;
362                 default:
363                     break;
364             }
365         }
367         PObj_custom_mark_destroy_SETALL(dest);
368         return dest;
369     }
373 =item C<INTVAL get_bool()>
375 Returns whether the array has any elements.
377 =cut
381     VTABLE INTVAL get_bool() {
382         INTVAL size = SELF.elements();
383         return (INTVAL)(size != 0);
384     }
388 =item C<INTVAL elements()>
390 =cut
394     VTABLE INTVAL elements() {
395         HashEntry *e;
397         if (!PMC_data(SELF))
398             return 0;
400         e = (HashEntry *)PMC_data(SELF);
401         return UVal_int(e[1].val) - UVal_int(e[0].val);
402     }
406 =item C<INTVAL get_integer()>
408 Returns the number of elements in the array.
410 =cut
414     VTABLE INTVAL get_integer() {
415         return SELF.elements();
416     }
420 =item C<INTVAL type_keyed_int(INTVAL key)>
422 Returns the type of the element at index C<key>.
424 =cut
428     VTABLE INTVAL type_keyed_int(INTVAL key) {
429         HashEntry *e = get_entry(INTERP, SELF, key);
430         return e->type;
431     }
435 =item C<INTVAL get_integer_keyed_int(INTVAL key)>
437 Returns the integer value of the element at index C<key>.
439 =cut
443     VTABLE INTVAL get_integer_keyed_int(INTVAL key) {
444         HashEntry *e = get_entry(INTERP, SELF, key);
445         return ret_int(INTERP, e);
446     }
450 =item C<INTVAL get_integer_keyed(PMC *key)>
452 Returns the integer value of the element at index C<*key>.
454 =cut
458     VTABLE INTVAL get_integer_keyed(PMC *key) {
459         /* simple int keys only */
460         INTVAL k = key_integer(INTERP, key);
461         return SELF.get_integer_keyed_int(k);
462     }
466 =item C<INTVAL shift_integer()>
468 Removes the first element from the array and returns its integer value.
470 =cut
474     VTABLE INTVAL shift_integer() {
475         HashEntry *ret = shift_entry(INTERP, SELF);
476         return ret_int(INTERP, ret);
477     }
481 =item C<FLOATVAL get_number_keyed_int(INTVAL key)>
483 Returns the floating-point value of the element at index C<key>.
485 =cut
489     VTABLE FLOATVAL get_number_keyed_int(INTVAL key) {
490         HashEntry *e = get_entry(INTERP, SELF, key);
491         return ret_num(INTERP, e);
492     }
496 =item C<FLOATVAL get_number_keyed(PMC *key)>
498 Returns the floating-point value of the element at index C<*key>.
500 =cut
504     VTABLE FLOATVAL get_number_keyed(PMC *key) {
505         INTVAL k = key_integer(INTERP, key);
506         return SELF.get_number_keyed_int(k);
507     }
511 =item C<FLOATVAL shift_float()>
513 Removes the first element from the array and returns its floating-point
514 value.
516 =cut
520     VTABLE FLOATVAL shift_float() {
521         HashEntry *ret = shift_entry(INTERP, SELF);
522         return ret_num(INTERP, ret);
523     }
527 =item C<STRING *get_string_keyed_int(INTVAL key)>
529 Returns the Parrot string value of the element at index C<key>.
531 =cut
535     VTABLE STRING *get_string_keyed_int(INTVAL key) {
536         HashEntry *e = get_entry(INTERP, SELF, key);
537         return ret_string(INTERP, e);
538     }
542 =item C<STRING *get_string_keyed(PMC *key)>
544 Returns the Parrot string value of the element at index C<*key>.
546 =cut
550     VTABLE STRING *get_string_keyed(PMC *key) {
551         INTVAL k = key_integer(INTERP, key);
552         return SELF.get_string_keyed_int(k);
553     }
557 =item C<STRING *shift_string()>
559 Removes the first element from the array and returns its Parrot string
560 value.
562 =cut
566     VTABLE STRING *shift_string() {
567         HashEntry *ret = shift_entry(INTERP, SELF);
568         return ret_string(INTERP, ret);
569     }
573 =item C<PMC *get_pmc_keyed_int(INTVAL key)>
575 Returns the PMC value of the element at index C<key>.
577 =cut
581     VTABLE PMC *get_pmc_keyed_int(INTVAL key) {
582         HashEntry *e = get_entry(INTERP, SELF, key);
583         return ret_pmc(INTERP, e);
584     }
588 =item C<PMC *get_pmc_keyed(PMC *key)>
590 Returns the PMC value of the element at index C<*key>.
592 =cut
596     VTABLE PMC *get_pmc_keyed(PMC *key) {
597         INTVAL k = key_integer(INTERP, key);
598         return SELF.get_pmc_keyed_int(k);
599     }
603 =item C<PMC *shift_pmc()>
605 Removes the first element from the array and returns its PMC value.
607 =cut
611     VTABLE PMC *shift_pmc() {
612         HashEntry *ret = shift_entry(INTERP, SELF);
613         return ret_pmc(INTERP, ret);
614     }
618 =item C<void set_integer_native(INTVAL size)>
620 Resizes the array to C<size> elements.
622 =cut
626     VTABLE void set_integer_native(INTVAL size) {
627         if (PMC_int_val(SELF))
628             real_exception(interp, NULL, E_IndexError, "SArray: Can't resize!");
630         PMC_int_val(SELF) = size;
632         /* Probably ought to actually copy this... */
634         if (PMC_data(SELF))
635           mem_sys_free(PMC_data(SELF));
637         PMC_data(SELF) = mem_allocate_n_zeroed_typed(2 + size, HashEntry);
638         PObj_custom_mark_destroy_SETALL(SELF);
639     }
643 =item C<void set_integer_keyed_int(INTVAL key, INTVAL value)>
645 Sets the integer value of the element at index C<key> to C<value>.
647 =cut
651     VTABLE void set_integer_keyed_int(INTVAL key, INTVAL value) {
652         HashEntry *e;
654         if (key < 0 || key >= PMC_int_val(SELF))
655             real_exception(interp, NULL, E_IndexError, "SArray index out of bounds!");
657         e                = (HashEntry *)PMC_data(SELF) + (2 + key);
658         e->type          = enum_hash_int;
659         UVal_int(e->val) = value;
660         e                = (HashEntry *)PMC_data(SELF) + 1;
662         if (key >= UVal_int(e->val))
663             UVal_int(e->val) = key + 1;
664     }
668 =item C<void push_integer(INTVAL value)>
670 Adds an element with integer value C<value> to the end of the array.
672 =cut
676     VTABLE void push_integer(INTVAL value) {
677         HashEntry *e;
678         INTVAL     nextix;
680         if (!PMC_data(SELF))
681             real_exception(interp, NULL, E_IndexError, "SArray index out of bounds!");
683         e      = (HashEntry *)PMC_data(SELF) + 1;
684         nextix = UVal_int(e->val);
686         SELF.set_integer_keyed_int(nextix, value);
687     }
691 =item C<void set_number_keyed_int(INTVAL key, FLOATVAL value)>
693 Sets the floating-point value of the element at index C<key> to
694 C<value>.
696 =cut
700     VTABLE void set_number_keyed_int(INTVAL key, FLOATVAL value) {
701         HashEntry *e;
703         if (key < 0 || key >= PMC_int_val(SELF))
704             real_exception(interp, NULL, E_IndexError, "SArray index out of bounds!");
706         e                = (HashEntry *)PMC_data(SELF) + (2 + key);
707         e->type          = enum_hash_num;
708         UVal_num(e->val) = value;
709         e                = (HashEntry *)PMC_data(SELF) + 1;
711         if (key >= UVal_int(e->val))
712             UVal_int(e->val) = key + 1;
713     }
717 =item C<void push_float(FLOATVAL value)>
719 Adds an element with floating-point value C<value> to the end of the array.
721 =cut
725     VTABLE void push_float(FLOATVAL value) {
726         HashEntry *e;
727         INTVAL     nextix;
729         if (!PMC_data(SELF))
730             real_exception(interp, NULL, E_IndexError, "SArray index out of bounds!");
732         e      = (HashEntry *) PMC_data(SELF) + 1;
733         nextix = UVal_int(e->val);
735         SELF.set_number_keyed_int(nextix, value);
736     }
740 =item C<void set_string_keyed_int(INTVAL key, STRING *value)>
742 Sets the Parrot string value of the element at index C<key> to C<value>.
744 =cut
748     VTABLE void set_string_keyed_int(INTVAL key, STRING *value) {
749         HashEntry *e;
751         if (key < 0 || key >= PMC_int_val(SELF))
752             real_exception(interp, NULL, E_IndexError, "SArray index out of bounds!");
754         e                = (HashEntry *)PMC_data(SELF) + (2 + key);
755         e->type          = enum_hash_string;
756         UVal_str(e->val) = value;
757         e                = (HashEntry *)PMC_data(SELF) + 1;
759         if (key >= UVal_int(e->val))
760             UVal_int(e->val) = key + 1;
761     }
765 =item C<void push_string(STRING *value)>
767 Adds an element with Parrot string value C<*value> to the end of the
768 array.
770 =cut
774     VTABLE void push_string(STRING *value) {
775         HashEntry *e;
776         INTVAL     nextix;
778         if (!PMC_data(SELF))
779             real_exception(interp, NULL, E_IndexError,
780                     "SArray index out of bounds!");
782         e      = (HashEntry *)PMC_data(SELF) + 1;
783         nextix = UVal_int(e->val);
785         SELF.set_string_keyed_int(nextix, value);
786     }
790 =item C<void set_pmc_keyed_int(INTVAL key, PMC *src)>
792 Sets the PMC value of the element at index C<key> to C<*src>.
794 =cut
798     VTABLE void set_pmc_keyed_int(INTVAL key, PMC *src) {
799         HashEntry *e;
801         if (key < 0 || key >= PMC_int_val(SELF))
802             real_exception(interp, NULL, E_IndexError, "SArray index out of bounds!");
804         e       = (HashEntry *) PMC_data(SELF) + (2 + key);
805         e->type = enum_hash_pmc;
807         GC_WRITE_BARRIER(INTERP, SELF, UVal_pmc(e->val), src);
808         UVal_pmc(e->val) = src;
809         e                = (HashEntry *) PMC_data(SELF) + 1;
811         if (key >= UVal_int(e->val))
812             UVal_int(e->val) = key + 1;
813     }
817 =item C<void push_pmc(PMC *value)>
819 Adds an element with PMC value C<*value> to the end of the array.
821 =cut
825     void push_pmc(PMC *value) {
826         HashEntry *e;
827         INTVAL     nextix;
829         if (!PMC_data(SELF))
830             real_exception(interp, NULL, E_IndexError,
831                     "SArray index out of bounds!");
833         e      = (HashEntry *)PMC_data(SELF) + 1;
834         nextix = UVal_int(e->val);
836         SELF.set_pmc_keyed_int(nextix, value);
837     }
842 =back
844 =head1 SEE ALSO
846 F<docs/pdds/pdd03_calling_conventions.pod>.
848 =head1 HISTORY
850 Initial version 2003.07.04 by leo
852 2003.11.06 boemmels renamed HASH_ENTRY to HashEntry
854 =cut
859  * Local variables:
860  *   c-file-style: "parrot"
861  * End:
862  * vim: expandtab shiftwidth=4:
863  */