e7328e32b24ab50062ed73847403f028b505cbd1
[fw/altos] / src / scheme / ao_scheme_vector.c
1 /*
2  * Copyright © 2017 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  */
14
15 #include "ao_scheme.h"
16
17 #ifdef AO_SCHEME_FEATURE_VECTOR
18
19 static void vector_mark(void *addr)
20 {
21         struct ao_scheme_vector *vector = addr;
22         unsigned int    i;
23
24         for (i = 0; i < vector->length; i++) {
25                 ao_poly v = vector->vals[i];
26
27                 ao_scheme_poly_mark(v, 1);
28         }
29 }
30
31 static int vector_len_size(uint16_t length)
32 {
33         return sizeof (struct ao_scheme_vector) + length * sizeof (ao_poly);
34 }
35
36 static int vector_size(void *addr)
37 {
38         struct ao_scheme_vector *vector = addr;
39
40         return vector_len_size(vector->length);
41 }
42
43 static void vector_move(void *addr)
44 {
45         struct ao_scheme_vector *vector = addr;
46         unsigned int    i;
47
48         for (i = 0; i < vector->length; i++)
49                 (void) ao_scheme_poly_move(&vector->vals[i], 1);
50 }
51
52 const struct ao_scheme_type ao_scheme_vector_type = {
53         .mark = vector_mark,
54         .size = vector_size,
55         .move = vector_move,
56         .name = "vector",
57 };
58
59 struct ao_scheme_vector *
60 ao_scheme_vector_alloc(uint16_t length, ao_poly fill)
61 {
62         struct ao_scheme_vector *vector;
63         unsigned int i;
64
65         vector = ao_scheme_alloc(vector_len_size(length));
66         if (!vector)
67                 return NULL;
68         vector->type = AO_SCHEME_VECTOR;
69         vector->length = length;
70         for (i = 0; i < length; i++)
71                 vector->vals[i] = fill;
72         return vector;
73 }
74
75 struct vl {
76         struct ao_scheme_vector *vector;
77         struct vl *prev;
78 };
79
80 static struct vl *vl;
81 static unsigned int vd;
82
83 void
84 ao_scheme_vector_write(FILE *out, ao_poly v, bool write)
85 {
86         struct ao_scheme_vector *vector = ao_scheme_poly_vector(v);
87         unsigned int i;
88         int was_marked = 0;
89         struct vl *ve;
90
91         ++vd;
92         for (ve = vl; ve; ve = ve->prev)
93                 if (ve->vector == vector)
94                         abort();
95
96         ve = malloc(sizeof (struct vl));
97         ve->prev = vl;
98         ve->vector = vector;
99         vl = ve;
100
101         ao_scheme_print_start();
102         was_marked = ao_scheme_print_mark_addr(vector);
103         if (was_marked) {
104                 fputs("...", out);
105         } else {
106                 fputs("#(", out);
107                 for (i = 0; i < vector->length; i++) {
108                         if (i != 0)
109                                 putc(' ', out);
110                         ao_scheme_poly_write(out, vector->vals[i], write);
111                 }
112                 printf(")");
113         }
114         if (ao_scheme_print_stop() && !was_marked)
115                 ao_scheme_print_clear_addr(vector);
116         if (vl != ve)
117                 abort();
118         vl = ve->prev;
119         free(ve);
120         --vd;
121 }
122
123 struct ao_scheme_vector *
124 ao_scheme_list_to_vector(struct ao_scheme_cons *cons)
125 {
126         uint16_t                length;
127         uint16_t                i;
128         struct ao_scheme_vector *vector;
129
130         length = (uint16_t) ao_scheme_cons_length (cons);
131         if (ao_scheme_exception)
132                 return NULL;
133
134         ao_scheme_cons_stash(cons);
135         vector = ao_scheme_vector_alloc(length, AO_SCHEME_NIL);
136         cons = ao_scheme_cons_fetch();
137         if (!vector)
138                 return NULL;
139         i = 0;
140         while (cons) {
141                 vector->vals[i++] = cons->car;
142                 cons = ao_scheme_cons_cdr(cons);
143         }
144         return vector;
145 }
146
147 struct ao_scheme_cons *
148 ao_scheme_vector_to_list(struct ao_scheme_vector *vector, int start, int end)
149 {
150         int                     i;
151         uint16_t                length = vector->length;
152         struct ao_scheme_cons   *cons = NULL;
153
154         if (end == -1)
155                 end = length;
156         if (start < 0)
157                 start = 0;
158         if (end > length)
159                 end = length;
160         for (i = end; i-- > start;) {
161                 ao_scheme_vector_stash(vector);
162                 cons = ao_scheme_cons_cons(vector->vals[i], ao_scheme_cons_poly(cons));
163                 vector = ao_scheme_vector_fetch();
164                 if (!cons)
165                         return NULL;
166         }
167         return cons;
168 }
169
170 ao_poly
171 ao_scheme_do_vector(struct ao_scheme_cons *cons)
172 {
173         return ao_scheme_vector_poly(ao_scheme_list_to_vector(cons));
174 }
175
176 ao_poly
177 ao_scheme_do_make_vector(struct ao_scheme_cons *cons)
178 {
179         int32_t len;
180         ao_poly val;
181
182         if (!ao_scheme_parse_args(_ao_scheme_atom_make2dvector, cons,
183                                   AO_SCHEME_INT, &len,
184                                   AO_SCHEME_POLY|AO_SCHEME_ARG_OPTIONAL, _ao_scheme_bool_false, &val,
185                                   AO_SCHEME_ARG_END))
186                 return AO_SCHEME_NIL;
187         return ao_scheme_vector_poly(ao_scheme_vector_alloc(len, val));
188 }
189
190 static bool
191 ao_scheme_check_vector(ao_poly proc, struct ao_scheme_vector *vector, int32_t offset)
192 {
193         if (offset < 0 || vector->length <= offset) {
194                 (void) ao_scheme_error(AO_SCHEME_INVALID, "%v: vector index %d out of range (max %d)",
195                                        proc,
196                                        offset, vector->length);
197                 return false;
198         }
199         return true;
200 }
201
202 ao_poly
203 ao_scheme_do_vector_ref(struct ao_scheme_cons *cons)
204 {
205         struct ao_scheme_vector *vector;
206         int32_t                 offset;
207
208         if (!ao_scheme_parse_args(_ao_scheme_atom_vector2dref, cons,
209                                   AO_SCHEME_VECTOR, &vector,
210                                   AO_SCHEME_INT, &offset,
211                                   AO_SCHEME_ARG_END))
212                 return AO_SCHEME_NIL;
213         if (!ao_scheme_check_vector(_ao_scheme_atom_vector2dref, vector, offset))
214                 return AO_SCHEME_NIL;
215         return vector->vals[offset];
216 }
217
218 ao_poly
219 ao_scheme_do_vector_set(struct ao_scheme_cons *cons)
220 {
221         struct ao_scheme_vector *vector;
222         int32_t                 offset;
223         ao_poly                 val;
224
225         if (!ao_scheme_parse_args(_ao_scheme_atom_vector2dset21, cons,
226                                   AO_SCHEME_VECTOR, &vector,
227                                   AO_SCHEME_INT, &offset,
228                                   AO_SCHEME_POLY, &val,
229                                   AO_SCHEME_ARG_END))
230                 return AO_SCHEME_NIL;
231         if (!ao_scheme_check_vector(_ao_scheme_atom_vector2dset21, vector, offset))
232                 return AO_SCHEME_NIL;
233         vector->vals[offset] = val;
234         return val;
235 }
236
237 ao_poly
238 ao_scheme_do_list_to_vector(struct ao_scheme_cons *cons)
239 {
240         struct ao_scheme_cons   *pair;
241
242         if (!ao_scheme_parse_args(_ao_scheme_atom_list2d3evector, cons,
243                                   AO_SCHEME_CONS|AO_SCHEME_ARG_NIL_OK, &pair,
244                                   AO_SCHEME_ARG_END))
245                 return AO_SCHEME_NIL;
246         return ao_scheme_vector_poly(ao_scheme_list_to_vector(pair));
247 }
248
249 ao_poly
250 ao_scheme_do_vector_to_list(struct ao_scheme_cons *cons)
251 {
252         struct ao_scheme_vector *vector;
253         int32_t                 start, end;
254
255         if (!ao_scheme_parse_args(_ao_scheme_atom_vector2d3elist, cons,
256                                   AO_SCHEME_VECTOR, &vector,
257                                   AO_SCHEME_INT|AO_SCHEME_ARG_OPTIONAL, ao_scheme_int_poly(0), &start,
258                                   AO_SCHEME_INT|AO_SCHEME_ARG_OPTIONAL, ao_scheme_int_poly(-1), &end,
259                                   AO_SCHEME_ARG_END))
260                 return AO_SCHEME_NIL;
261         if (end == -1)
262                 end = vector->length;
263         return ao_scheme_cons_poly(ao_scheme_vector_to_list(vector, start, end));
264 }
265
266 ao_poly
267 ao_scheme_do_vector_length(struct ao_scheme_cons *cons)
268 {
269         struct ao_scheme_vector *vector;
270
271         if (!ao_scheme_parse_args(_ao_scheme_atom_vector2d3elist, cons,
272                                   AO_SCHEME_VECTOR, &vector,
273                                   AO_SCHEME_ARG_END))
274                 return AO_SCHEME_NIL;
275         return ao_scheme_integer_poly(vector->length);
276 }
277
278 ao_poly
279 ao_scheme_do_vectorp(struct ao_scheme_cons *cons)
280 {
281         return ao_scheme_do_typep(_ao_scheme_atom_vector3f, AO_SCHEME_VECTOR, cons);
282 }
283
284 #endif /* AO_SCHEME_FEATURE_VECTOR */