1/*
2Copyright (C) 2001-2014, Parrot Foundation.
3
4=head1 NAME
5
6src/pmc/resizablefloatarray.pmc - ResizableFloatArray PMC
7
8=head1 DESCRIPTION
9
10This class, C<ResizableFloatArray>, implements an array of resizable size,
11which stores FLOATVALs. It uses Float PMCs to do all necessary conversions.
12
13=head2 Functions
14
15=over 4
16
17=cut
18
19*/
20
21/* HEADERIZER HFILE: none */
22/* HEADERIZER BEGIN: static */
23/* HEADERIZER END: static */
24
25pmclass ResizableFloatArray extends FixedFloatArray auto_attrs provides array {
26    ATTR INTVAL resize_threshold; /* max size before array needs resizing */
27
28/*
29
30=item C<FLOATVAL get_number_keyed_int(INTVAL key)>
31
32Returns the floating-point value of the element at index C<key>.
33
34=cut
35
36*/
37
38    VTABLE FLOATVAL get_number_keyed_int(INTVAL key) :no_wb {
39        FLOATVAL *float_array;
40        INTVAL    size;
41        GET_ATTR_size(INTERP, SELF, size);
42
43        if (key < 0)
44            key += size;
45        if (key < 0)
46                Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
47                        "index out of bounds");
48        if (key >= size)
49            return 0.0;
50
51        GET_ATTR_float_array(INTERP, SELF, float_array);
52        return float_array[key];
53    }
54
55/*
56
57=item C<void set_number_keyed_int(INTVAL key, FLOATVAL value)>
58
59Sets the floating-point value of the element at index C<key> to
60C<value>.
61
62=cut
63
64*/
65
66    VTABLE void set_number_keyed_int(INTVAL key, FLOATVAL value) {
67        FLOATVAL *float_array;
68        INTVAL    size;
69        GET_ATTR_size(INTERP, SELF, size);
70
71        if (key < 0)
72            key += size;
73        if (key < 0)
74            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
75                    "index out of bounds");
76
77        if (key >= size)
78            SELF.set_integer_native(key + 1);
79
80        GET_ATTR_float_array(INTERP, SELF, float_array);
81        float_array[key] = value;
82    }
83
84/*
85
86=item C<void set_integer_native(INTVAL size)>
87
88Resizes the array to C<size> elements.
89
90When growing, if the new size stays smaller than twice the old size,
91grow to twice the old size; otherwise, grow to the new size.
92
93When shrinking, if the new size is smaller than half the old size,
94shrink to one and half times the new size (which is less than or
95equal to three quarters of the old size).
96
97=cut
98
99*/
100
101    VTABLE void set_integer_native(INTVAL size) {
102        FLOATVAL *float_array;
103        INTVAL    resize_threshold;
104
105        if (size < 0)
106            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
107                    "illegal argument");
108
109        GET_ATTR_float_array(INTERP, SELF, float_array);
110        GET_ATTR_resize_threshold(INTERP, SELF, resize_threshold);
111        if (!float_array) {
112            /* empty - used fixed routine */
113            if (size < 8) {
114                SUPER(8);
115                SET_ATTR_size(INTERP, SELF, size);
116                SET_ATTR_resize_threshold(INTERP, SELF, 8);
117            }
118            else {
119                SUPER(size);
120                SET_ATTR_resize_threshold(INTERP, SELF, size);
121            }
122        }
123        else if (size <= resize_threshold){
124            /* we could shrink here if necessary */
125            SET_ATTR_size(INTERP, SELF, size);
126            return;
127        }
128        else {
129            INTVAL cur = resize_threshold;
130            if (cur < 8192)
131                cur = size < 2 * cur ? 2 * cur : size;
132            else {
133                const INTVAL needed = size - cur;
134                cur          += needed + 4096;
135                cur          &= ~0xfff;
136            }
137            SET_ATTR_float_array(INTERP, SELF,
138                    mem_gc_realloc_n_typed(INTERP, float_array, cur, FLOATVAL));
139            SET_ATTR_size(INTERP, SELF, size);
140            SET_ATTR_resize_threshold(INTERP, SELF, cur);
141        }
142    }
143
144/*
145
146=item C<PMC *clone()>
147
148Creates and returns a copy of the array.
149
150=cut
151
152*/
153
154    VTABLE PMC *clone() :no_wb {
155        INTVAL size;
156        PMC * const copy = SUPER();
157
158        /* copy trimmed extra space */
159        GET_ATTR_size(INTERP, SELF, size);
160        SET_ATTR_resize_threshold(INTERP, copy, size);
161
162        return copy;
163    }
164
165/*
166
167=item C<void push_float(FLOATVAL value)>
168
169Adds C<value> to the end of the array.
170
171=cut
172
173*/
174
175    VTABLE void push_float(FLOATVAL value) :manual_wb {
176        const INTVAL nextix = SELF.elements();
177        SELF.set_number_keyed_int(nextix, value);
178    }
179
180/*
181
182=item C<FLOATVAL pop_float()>
183
184Removes and returns the last element in the array.
185
186=cut
187
188*/
189
190    VTABLE FLOATVAL pop_float() :manual_wb {
191        FLOATVAL value;
192        INTVAL size;
193        GET_ATTR_size(INTERP, SELF, size);
194
195        if (size == 0)
196            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
197                    "Can't pop from an empty array");
198
199        value = SELF.get_number_keyed_int(size-1);
200        SELF.set_integer_native(size - 1);
201        return value;
202    }
203/*
204
205=item C<INTVAL shift_float()>
206
207Removes and returns an item from the start of the array.
208
209=cut
210
211*/
212
213    VTABLE FLOATVAL shift_float() {
214        FLOATVAL value, *float_array;
215        INTVAL size;
216
217        GET_ATTR_size(INTERP, SELF, size);
218
219        if (size == 0)
220            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
221                    "Can't shift from an empty array");
222
223        GET_ATTR_float_array(INTERP, SELF, float_array);
224        value             = float_array[0];
225        SET_ATTR_size(INTERP, SELF, --size);
226
227        memmove(float_array, float_array + 1, size * sizeof (FLOATVAL));
228        return value;
229    }
230
231/*
232
233=item C<void unshift_float(FLOATVAL value)>
234
235Add and integer to the start of the array.
236
237=cut
238
239*/
240
241    VTABLE void unshift_float(FLOATVAL value) {
242        INTVAL    size;
243        FLOATVAL *float_array;
244
245        GET_ATTR_size(INTERP, SELF, size);
246        SELF.set_integer_native(size + 1);
247        GET_ATTR_float_array(INTERP, SELF, float_array);
248        memmove(float_array + 1, float_array, size * sizeof (FLOATVAL));
249        float_array[0] = value;
250    }
251
252}
253
254/*
255
256=back
257
258=head1 SEE ALSO
259
260F<docs/pdds/pdd17_basic_types.pod>.
261
262=cut
263
264*/
265
266/*
267 * Local variables:
268 *   c-file-style: "parrot"
269 * End:
270 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
271 */
272