altos/scheme: Add ports. Split scheme code up.
[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, j;
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("#(\n", out);
107                 for (i = 0; i < vector->length; i++) {
108                         printf("%3d: ", i);
109                         for (j = 0; j < vd; j++)
110                                 printf(".");
111                         ao_scheme_poly_write(out, vector->vals[i], write);
112                         printf("\n");
113                 }
114                 printf("     ");
115                 for (j = 0; j < vd; j++)
116                         printf(".");
117                 printf(")");
118         }
119         if (ao_scheme_print_stop() && !was_marked)
120                 ao_scheme_print_clear_addr(vector);
121         if (vl != ve)
122                 abort();
123         vl = ve->prev;
124         free(ve);
125         --vd;
126 }
127
128 struct ao_scheme_vector *
129 ao_scheme_list_to_vector(struct ao_scheme_cons *cons)
130 {
131         uint16_t                length;
132         uint16_t                i;
133         struct ao_scheme_vector *vector;
134
135         length = (uint16_t) ao_scheme_cons_length (cons);
136         if (ao_scheme_exception)
137                 return NULL;
138
139         ao_scheme_cons_stash(cons);
140         vector = ao_scheme_vector_alloc(length, AO_SCHEME_NIL);
141         cons = ao_scheme_cons_fetch();
142         if (!vector)
143                 return NULL;
144         i = 0;
145         while (cons) {
146                 vector->vals[i++] = cons->car;
147                 cons = ao_scheme_cons_cdr(cons);
148         }
149         return vector;
150 }
151
152 struct ao_scheme_cons *
153 ao_scheme_vector_to_list(struct ao_scheme_vector *vector, int start, int end)
154 {
155         int                     i;
156         uint16_t                length = vector->length;
157         struct ao_scheme_cons   *cons = NULL;
158
159         if (end == -1)
160                 end = length;
161         if (start < 0)
162                 start = 0;
163         if (end > length)
164                 end = length;
165         for (i = end; i-- > start;) {
166                 ao_scheme_vector_stash(vector);
167                 cons = ao_scheme_cons_cons(vector->vals[i], ao_scheme_cons_poly(cons));
168                 vector = ao_scheme_vector_fetch();
169                 if (!cons)
170                         return NULL;
171         }
172         return cons;
173 }
174
175 ao_poly
176 ao_scheme_do_vector(struct ao_scheme_cons *cons)
177 {
178         return ao_scheme_vector_poly(ao_scheme_list_to_vector(cons));
179 }
180
181 ao_poly
182 ao_scheme_do_make_vector(struct ao_scheme_cons *cons)
183 {
184         int32_t len;
185         ao_poly val;
186
187         if (!ao_scheme_parse_args(_ao_scheme_atom_make2dvector, cons,
188                                   AO_SCHEME_INT, &len,
189                                   AO_SCHEME_POLY|AO_SCHEME_ARG_OPTIONAL, _ao_scheme_bool_false, &val,
190                                   AO_SCHEME_ARG_END))
191                 return AO_SCHEME_NIL;
192         return ao_scheme_vector_poly(ao_scheme_vector_alloc(len, val));
193 }
194
195 static bool
196 ao_scheme_check_vector(ao_poly proc, struct ao_scheme_vector *vector, int32_t offset)
197 {
198         if (offset < 0 || vector->length <= offset) {
199                 (void) ao_scheme_error(AO_SCHEME_INVALID, "%v: vector index %d out of range (max %d)",
200                                        proc,
201                                        offset, vector->length);
202                 return false;
203         }
204         return true;
205 }
206
207 ao_poly
208 ao_scheme_do_vector_ref(struct ao_scheme_cons *cons)
209 {
210         struct ao_scheme_vector *vector;
211         int32_t                 offset;
212
213         if (!ao_scheme_parse_args(_ao_scheme_atom_vector2dref, cons,
214                                   AO_SCHEME_VECTOR, &vector,
215                                   AO_SCHEME_INT, &offset,
216                                   AO_SCHEME_ARG_END))
217                 return AO_SCHEME_NIL;
218         if (!ao_scheme_check_vector(_ao_scheme_atom_vector2dref, vector, offset))
219                 return AO_SCHEME_NIL;
220         return vector->vals[offset];
221 }
222
223 ao_poly
224 ao_scheme_do_vector_set(struct ao_scheme_cons *cons)
225 {
226         struct ao_scheme_vector *vector;
227         int32_t                 offset;
228         ao_poly                 val;
229
230         if (!ao_scheme_parse_args(_ao_scheme_atom_vector2dset21, cons,
231                                   AO_SCHEME_VECTOR, &vector,
232                                   AO_SCHEME_INT, &offset,
233                                   AO_SCHEME_POLY, &val,
234                                   AO_SCHEME_ARG_END))
235                 return AO_SCHEME_NIL;
236         if (!ao_scheme_check_vector(_ao_scheme_atom_vector2dset21, vector, offset))
237                 return AO_SCHEME_NIL;
238         vector->vals[offset] = val;
239         return val;
240 }
241
242 ao_poly
243 ao_scheme_do_list_to_vector(struct ao_scheme_cons *cons)
244 {
245         struct ao_scheme_cons   *pair;
246
247         if (!ao_scheme_parse_args(_ao_scheme_atom_list2d3evector, cons,
248                                   AO_SCHEME_CONS|AO_SCHEME_ARG_NIL_OK, &pair,
249                                   AO_SCHEME_ARG_END))
250                 return AO_SCHEME_NIL;
251         return ao_scheme_vector_poly(ao_scheme_list_to_vector(pair));
252 }
253
254 ao_poly
255 ao_scheme_do_vector_to_list(struct ao_scheme_cons *cons)
256 {
257         struct ao_scheme_vector *vector;
258         int32_t                 start, end;
259
260         if (!ao_scheme_parse_args(_ao_scheme_atom_vector2d3elist, cons,
261                                   AO_SCHEME_VECTOR, &vector,
262                                   AO_SCHEME_INT|AO_SCHEME_ARG_OPTIONAL, ao_scheme_int_poly(0), &start,
263                                   AO_SCHEME_INT|AO_SCHEME_ARG_OPTIONAL, ao_scheme_int_poly(-1), &end,
264                                   AO_SCHEME_ARG_END))
265                 return AO_SCHEME_NIL;
266         if (end == -1)
267                 end = vector->length;
268         return ao_scheme_cons_poly(ao_scheme_vector_to_list(vector, start, end));
269 }
270
271 ao_poly
272 ao_scheme_do_vector_length(struct ao_scheme_cons *cons)
273 {
274         struct ao_scheme_vector *vector;
275
276         if (!ao_scheme_parse_args(_ao_scheme_atom_vector2d3elist, cons,
277                                   AO_SCHEME_VECTOR, &vector,
278                                   AO_SCHEME_ARG_END))
279                 return AO_SCHEME_NIL;
280         return ao_scheme_integer_poly(vector->length);
281 }
282
283 ao_poly
284 ao_scheme_do_vectorp(struct ao_scheme_cons *cons)
285 {
286         return ao_scheme_do_typep(_ao_scheme_atom_vector3f, AO_SCHEME_VECTOR, cons);
287 }
288
289 #endif /* AO_SCHEME_FEATURE_VECTOR */