1/*
2Copyright (C) 2001-2014, Parrot Foundation.
3
4=head1 NAME
5
6src/pmc/fixedbooleanarray.pmc - FixedBooleanArray PMC
7
8=head1 DESCRIPTION
9
10Fixed size array for booleans only.
11
12The C<FixedBooleanArray> PMC implements an array of fixed size, which
13stores booleans.  It uses the C<Boolean> PMC for all conversions.  The
14C<FixedBooleanArray> PMC is extended by the C<ResizableBooleanArray>
15PMC.
16
17=head2 Functions
18
19=over 4
20
21=item C<static UINTVAL get_size_in_bytes(UINTVAL size)>
22
23Auxiliar function to avoid repeating the size evaluation.
24
25=cut
26
27*/
28
29#define BITS_PER_CHAR 8
30
31/* HEADERIZER HFILE: none */
32/* HEADERIZER BEGIN: static */
33/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
34
35PARROT_INLINE
36PARROT_CONST_FUNCTION
37static UINTVAL get_size_in_bytes(UINTVAL size);
38
39#define ASSERT_ARGS_get_size_in_bytes __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
40/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
41/* HEADERIZER END: static */
42
43PARROT_INLINE
44PARROT_CONST_FUNCTION
45static UINTVAL
46get_size_in_bytes(UINTVAL size)
47{
48    ASSERT_ARGS(get_size_in_bytes)
49
50    return (size + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
51}
52
53
54pmclass FixedBooleanArray auto_attrs provides array {
55    ATTR UINTVAL         size;             /* # of bits this fba holds */
56    ATTR UINTVAL         resize_threshold; /* max capacity before resizing */
57    ATTR unsigned char * bit_array;        /* where the bits go */
58
59/*
60
61=back
62
63=head2 Vtable functions
64
65=over 4
66
67=item C<void init()>
68
69Initializes the array.
70
71=cut
72
73*/
74
75    VTABLE void init() {
76        PObj_custom_destroy_SET(SELF);
77    }
78
79/*
80
81=item C<void init_int(INTVAL size)>
82
83Initializes the array.
84
85=cut
86
87*/
88
89    VTABLE void init_int(INTVAL size) {
90        const size_t size_in_bytes = get_size_in_bytes(size);
91
92        if (size < 0)
93            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
94                    "illegal argument");
95
96        SET_ATTR_size(INTERP, SELF, size);
97        SET_ATTR_resize_threshold(INTERP, SELF, size_in_bytes * BITS_PER_CHAR);
98        SET_ATTR_bit_array(INTERP, SELF, mem_gc_allocate_n_zeroed_typed(INTERP, size_in_bytes,
99                                                                        unsigned char));
100        PObj_custom_destroy_SET(SELF);
101    }
102
103
104/*
105
106=item C<void destroy()>
107
108Destroys the array.
109
110=cut
111
112*/
113
114    VTABLE void destroy() :no_wb {
115        unsigned char *bit_array;
116        GET_ATTR_bit_array(INTERP, SELF, bit_array);
117        if (bit_array)
118            mem_gc_free(INTERP, bit_array);
119    }
120
121/*
122
123=item C<PMC *clone()>
124
125Creates and returns a copy of the array.
126
127=cut
128
129*/
130
131    VTABLE PMC *clone() :no_wb {
132        unsigned char * my_bit_array;
133        UINTVAL         resize_threshold, size;
134        PMC *   const   dest   = Parrot_pmc_new(INTERP, SELF->vtable->base_type);
135
136        GET_ATTR_bit_array(INTERP, SELF, my_bit_array);
137        GET_ATTR_size(INTERP, SELF, size);
138        GET_ATTR_resize_threshold(INTERP, SELF, resize_threshold);
139
140        if (my_bit_array) {
141            unsigned char * clone_bit_array;
142            const size_t size_in_bytes = get_size_in_bytes(resize_threshold);
143
144            SET_ATTR_size(INTERP, dest, size);
145            SET_ATTR_resize_threshold(INTERP, dest, resize_threshold);
146
147            clone_bit_array = mem_gc_allocate_n_typed(INTERP, size_in_bytes, unsigned char);
148            memcpy(clone_bit_array, my_bit_array, size_in_bytes);
149
150            SET_ATTR_bit_array(INTERP, dest, clone_bit_array);
151        }
152
153        PObj_custom_destroy_SET(dest);
154        return dest;
155    }
156
157/*
158
159=item C<INTVAL get_bool()>
160
161Returns whether the array has any elements (meaning been initialized, for a
162fixed sized array).
163
164=cut
165
166*/
167    VTABLE INTVAL get_bool() :no_wb {
168        return SELF.elements() ? 1 : 0;
169    }
170
171/*
172
173=item C<INTVAL elements()>
174
175=cut
176
177*/
178
179    VTABLE INTVAL elements() :no_wb {
180        UINTVAL size;
181        GET_ATTR_size(INTERP, SELF, size);
182        return size;
183    }
184
185/*
186
187=item C<INTVAL get_integer()>
188
189Returns the number of elements in the array.
190
191=cut
192
193*/
194
195    VTABLE INTVAL get_integer() :no_wb {
196        return SELF.elements();
197    }
198
199/*
200
201=item C<INTVAL get_integer_keyed_int(INTVAL key)>
202
203Returns the integer value of the element at index C<key>.
204
205=cut
206
207*/
208
209    VTABLE INTVAL get_integer_keyed_int(INTVAL key) :no_wb {
210        UINTVAL               size;
211        const unsigned char * bit_array;
212        GET_ATTR_bit_array(INTERP, SELF, bit_array);
213        GET_ATTR_size(INTERP, SELF, size);
214
215        if (key < 0)
216            key += size;
217        if (key < 0 || (UINTVAL)key >= size)
218            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
219                    "index out of bounds");
220
221        return (bit_array[key / BITS_PER_CHAR] & (1 << (key % BITS_PER_CHAR))) ? 1 : 0;
222    }
223
224/*
225
226=item C<INTVAL get_integer_keyed(PMC *key)>
227
228Returns the integer value of the element at index C<*key>.
229
230=cut
231
232*/
233
234    VTABLE INTVAL get_integer_keyed(PMC *key) :no_wb {
235        /* simple int keys only */
236        const INTVAL k = VTABLE_get_integer(INTERP, key);
237        return SELF.get_integer_keyed_int(k);
238    }
239
240
241/*
242
243=item C<FLOATVAL get_number_keyed_int(INTVAL key)>
244
245Returns the floating-point value of the element at index C<key>.
246
247=cut
248
249*/
250
251    VTABLE FLOATVAL get_number_keyed_int(INTVAL key) :no_wb {
252        const INTVAL i = SELF.get_integer_keyed_int(key);
253        return (FLOATVAL)i;
254    }
255
256/*
257
258=item C<FLOATVAL get_number_keyed(PMC *key)>
259
260Returns the floating-point value of the element at index C<*key>.
261
262=cut
263
264*/
265
266    VTABLE FLOATVAL get_number_keyed(PMC *key) :no_wb {
267        const INTVAL k = VTABLE_get_integer(INTERP, key);
268        return SELF.get_number_keyed_int(k);
269    }
270
271/*
272
273=item C<STRING *get_string()>
274
275Returns the Parrot string representation of the array.
276
277=cut
278
279*/
280
281    VTABLE STRING *get_string() :no_wb {
282        STRING *str   = STRINGNULL;
283        UINTVAL i;
284        const UINTVAL elems = SELF.elements();
285
286        const STRING * const zero = CONST_STRING(INTERP, "0");
287        const STRING * const one  = CONST_STRING(INTERP, "1");
288
289        for (i = 0; i < elems; ++i) {
290            str = Parrot_str_concat(INTERP, str,
291                SELF.get_integer_keyed_int((INTVAL)i) ? one : zero);
292        }
293
294        return str;
295
296    }
297
298/*
299
300=item C<STRING *get_string_keyed_int(INTVAL key)>
301
302Returns the Parrot string value of the element at index C<key>.
303
304=cut
305
306*/
307
308    VTABLE STRING *get_string_keyed_int(INTVAL key) :no_wb {
309        PMC * const val = SELF.get_pmc_keyed_int(key);
310        return VTABLE_get_string(INTERP, val);
311    }
312
313/*
314
315=item C<STRING *get_string_keyed(PMC *key)>
316
317Returns the Parrot string value of the element at index C<*key>.
318
319=cut
320
321*/
322
323    VTABLE STRING *get_string_keyed(PMC *key) :no_wb {
324        const INTVAL k = VTABLE_get_integer(INTERP, key);
325        return SELF.get_string_keyed_int(k);
326    }
327
328
329/*
330
331=item C<PMC *get_pmc_keyed_int(INTVAL key)>
332
333Returns the PMC value of the element at index C<key>.
334
335=cut
336
337*/
338
339    VTABLE PMC *get_pmc_keyed_int(INTVAL key) :no_wb {
340        return Parrot_pmc_new_init_int(INTERP, enum_class_Boolean,
341                SELF.get_integer_keyed_int(key));
342    }
343
344/*
345
346=item C<PMC *get_pmc_keyed(PMC *key)>
347
348Returns the PMC value of the element at index C<*key>.
349
350=cut
351
352*/
353
354    VTABLE PMC *get_pmc_keyed(PMC *key) :no_wb {
355        const INTVAL k = VTABLE_get_integer(INTERP, key);
356        return SELF.get_pmc_keyed_int(k);
357    }
358
359/*
360
361=item C<void set_integer_native(INTVAL size)>
362
363Resizes the array to C<size> elements.
364
365=cut
366
367*/
368
369    VTABLE void set_integer_native(INTVAL size) {
370        const size_t size_in_bytes = get_size_in_bytes(size);
371        UINTVAL old_size;
372        unsigned char *bit_array;
373
374        GET_ATTR_size(INTERP, SELF, old_size);
375        if (old_size || size < 1)
376            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
377                    "Can't resize");
378
379        SET_ATTR_size(INTERP, SELF, size);
380        SET_ATTR_resize_threshold(INTERP, SELF, size_in_bytes * BITS_PER_CHAR);
381        bit_array = mem_gc_allocate_n_typed(INTERP, size_in_bytes, unsigned char);
382        memset(bit_array, 0, size_in_bytes);
383        SET_ATTR_bit_array(INTERP, SELF, bit_array);
384    }
385
386/*
387
388=item C<void set_integer_keyed_int(INTVAL key, INTVAL value)>
389
390Sets the integer value of the element at index C<key> to C<value>.
391
392=cut
393
394*/
395
396    VTABLE void set_integer_keyed_int(INTVAL key, INTVAL value) {
397        UINTVAL size;
398        unsigned char * bit_array;
399        GET_ATTR_bit_array(INTERP, SELF, bit_array);
400        GET_ATTR_size(INTERP, SELF, size);
401
402        if (key < 0)
403            key += size;
404        if (key < 0 || (UINTVAL)key >= size)
405            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
406                "index out of bounds");
407
408        if (value)
409            bit_array[key/BITS_PER_CHAR] |=  (1 << (key % BITS_PER_CHAR));
410        else
411            bit_array[key/BITS_PER_CHAR] &= ~(1 << (key % BITS_PER_CHAR));
412    }
413
414/*
415
416=item C<void set_integer_keyed(PMC *key, INTVAL value)>
417
418Sets the integer value of the element at index C<key> to C<value>.
419
420=cut
421
422*/
423
424    VTABLE void set_integer_keyed(PMC *key, INTVAL value) :manual_wb {
425        const INTVAL k = VTABLE_get_integer(INTERP, key);
426        SELF.set_integer_keyed_int(k, value);
427    }
428
429/*
430
431=item C<void set_number_keyed_int(INTVAL key, FLOATVAL value)>
432
433Sets the floating-point value of the element at index C<key> to
434C<value>.
435
436=cut
437
438*/
439
440    VTABLE void set_number_keyed_int(INTVAL key, FLOATVAL value) :manual_wb {
441        SELF.set_integer_keyed_int(key, !FLOAT_IS_ZERO(value));
442    }
443
444/*
445
446=item C<void set_number_keyed(PMC *key, FLOATVAL value)>
447
448Sets the floating-point value of the element at index C<key> to
449C<value>.
450
451=cut
452
453*/
454
455    VTABLE void set_number_keyed(PMC *key, FLOATVAL value) :manual_wb {
456        const INTVAL k = VTABLE_get_integer(INTERP, key);
457        SELF.set_number_keyed_int(k, value);
458    }
459
460/*
461
462=item C<void set_string_keyed_int(INTVAL key, STRING *value)>
463
464Sets the Parrot string value of the element at index C<key> to C<value>.
465
466=cut
467
468*/
469
470    VTABLE void set_string_keyed_int(INTVAL key, STRING *value) :manual_wb {
471        INTVAL tempInt;
472        PMC * const tempPMC = Parrot_pmc_new(INTERP, enum_class_Boolean);
473
474        VTABLE_set_string_native(INTERP, tempPMC, value);
475        tempInt = VTABLE_get_integer(INTERP, tempPMC);
476
477        SELF.set_integer_keyed_int(key, tempInt);
478    }
479
480/*
481
482=item C<void set_string_keyed(PMC *key, STRING *value)>
483
484Sets the string value of the element at index C<key> to
485C<value>.
486
487=cut
488
489*/
490
491    VTABLE void set_string_keyed(PMC *key, STRING *value) :manual_wb {
492        const INTVAL k = VTABLE_get_integer(INTERP, key);
493        SELF.set_string_keyed_int(k, value);
494    }
495
496/*
497
498=item C<void set_pmc_keyed_int(INTVAL key, PMC *src)>
499
500Sets the PMC value of the element at index C<key> to C<*src>.
501
502=cut
503
504*/
505
506    VTABLE void set_pmc_keyed_int(INTVAL key, PMC *src) :manual_wb {
507        const INTVAL tempInt = VTABLE_get_integer(INTERP, src);
508        SELF.set_integer_keyed_int(key, tempInt);
509    }
510
511/*
512
513=item C<void set_pmc_keyed(PMC *key, PMC *value)>
514
515Sets the string value of the element at index C<key> to
516C<value>.
517
518=cut
519
520*/
521
522    VTABLE void set_pmc_keyed(PMC *key, PMC *value) :manual_wb {
523        const INTVAL k = VTABLE_get_integer(INTERP, key);
524        SELF.set_pmc_keyed_int(k, value);
525    }
526
527/*
528
529=item C<PMC *get_iter()>
530
531Return a new iterator for SELF.
532
533=cut
534
535*/
536
537    VTABLE PMC *get_iter() :no_wb {
538        return Parrot_pmc_new_init(INTERP, enum_class_ArrayIterator, SELF);
539    }
540
541
542
543/*
544
545=back
546
547=head2 Freeze/thaw Interface
548
549=over 4
550
551=item C<void freeze(PMC *info)>
552
553Used to archive the string.
554
555=cut
556
557*/
558    VTABLE void freeze(PMC *info) :no_wb {
559        UINTVAL          size, resize_threshold;
560        unsigned char  * bit_array;
561        STRING   *       s;
562        GET_ATTR_size(INTERP, SELF, size);
563        GET_ATTR_resize_threshold(INTERP, SELF, resize_threshold);
564        GET_ATTR_bit_array(INTERP, SELF, bit_array);
565
566        s = Parrot_str_new_init(INTERP, (char*)bit_array,
567                (resize_threshold / BITS_PER_CHAR),
568                Parrot_binary_encoding_ptr, 0);
569
570        VTABLE_push_integer(INTERP, info, size);
571        VTABLE_push_string(INTERP, info, s);
572    }
573
574/*
575
576=item C<void thaw(PMC *info)>
577
578Used to unarchive the string.
579
580=cut
581
582*/
583    VTABLE void thaw(PMC *info) {
584        SUPER(info);
585
586        {
587            const INTVAL    size          = VTABLE_shift_integer(INTERP, info);
588            STRING * const  s             = VTABLE_shift_string(INTERP, info);
589            const size_t    size_in_bytes = get_size_in_bytes(size);
590            unsigned char  *bit_array;
591
592            SELF.set_integer_native(size);
593
594            if (s->bufused < size_in_bytes)
595                Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_BAD_BUFFER_SIZE,
596                    "FixedBooleanArray: invalid buffer size during thaw");
597
598            GET_ATTR_bit_array(INTERP, SELF, bit_array);
599            memcpy(bit_array, s->strstart, size_in_bytes);
600        }
601    }
602
603/*
604
605=back
606
607=head2 Methods
608
609=over 4
610
611=item C<METHOD fill(INTVAL fill)>
612
613Sets all of the entries to true if fill is a true value, otherwise
614sets them all to false.
615
616=cut
617
618*/
619
620    METHOD fill(INTVAL fill) {
621        UINTVAL         size;
622        unsigned char * bit_array;
623        size_t          size_in_bytes;
624
625        GET_ATTR_bit_array(INTERP, SELF, bit_array);
626        GET_ATTR_size(INTERP, SELF, size);
627        size_in_bytes  = get_size_in_bytes(size);
628
629        if (size_in_bytes)
630            memset(bit_array, fill ? 0xff : 0, size_in_bytes);
631    }
632}
633
634/*
635
636=back
637
638=head1 SEE ALSO
639
640F<docs/pdds/pdd17_basic_types.pod>.
641
642=cut
643
644*/
645
646/*
647 * Local variables:
648 *   c-file-style: "parrot"
649 * End:
650 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
651 */
652