libguile/Makefile.am (snarfcppopts): Remove CFLAGS
[bpt/guile.git] / libguile / array-handle.c
CommitLineData
9b977c83 1/* Copyright (C) 1995,1996,1997,1998,2000,2001,2002,2003,2004, 2005,
7070f12b 2 * 2006, 2009, 2011, 2013, 2014 Free Software Foundation, Inc.
c53c0893
AW
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3 of
7 * the License, or (at your option) any later version.
8 *
9 * This library 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 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
18 */
19
20
21\f
22
23#ifdef HAVE_CONFIG_H
24# include <config.h>
25#endif
26
27#include "libguile/_scm.h"
28#include "libguile/__scm.h"
29
30#include "libguile/array-handle.h"
c53c0893
AW
31
32
2a610be5 33SCM scm_i_array_element_types[SCM_ARRAY_ELEMENT_TYPE_LAST + 1];
c53c0893 34
c53c0893 35
cf64dca6 36/* Bytevectors as generalized vectors & arrays. */
c53c0893 37
cf64dca6
AW
38#define DEFINE_BYTEVECTOR_ACCESSORS(type, tag, infix) \
39 static SCM \
40 bytevector_##tag##_ref (SCM bv, size_t pos) \
41 { \
42 SCM idx = scm_from_size_t (pos * sizeof (type)); \
43 return scm_bytevector_##infix##_ref (bv, idx); \
44 } \
45 static void \
46 bytevector_##tag##_set (SCM bv, size_t pos, SCM val) \
47 { \
48 SCM idx = scm_from_size_t (pos * sizeof (type)); \
49 scm_bytevector_##infix##_set_x (bv, idx, val); \
50 }
c53c0893 51
cf64dca6
AW
52DEFINE_BYTEVECTOR_ACCESSORS (uint8_t, u8, u8);
53DEFINE_BYTEVECTOR_ACCESSORS (int8_t, s8, s8);
54DEFINE_BYTEVECTOR_ACCESSORS (uint16_t, u16, u16_native);
55DEFINE_BYTEVECTOR_ACCESSORS (int16_t, s16, s16_native);
56DEFINE_BYTEVECTOR_ACCESSORS (uint32_t, u32, u32_native);
57DEFINE_BYTEVECTOR_ACCESSORS (int32_t, s32, s32_native);
58DEFINE_BYTEVECTOR_ACCESSORS (uint64_t, u64, u64_native);
59DEFINE_BYTEVECTOR_ACCESSORS (int64_t, s64, s64_native);
60DEFINE_BYTEVECTOR_ACCESSORS (float, f32, ieee_single_native);
61DEFINE_BYTEVECTOR_ACCESSORS (double, f64, ieee_double_native);
62
63/* Since these functions are only called by Guile's C code, we can abort
64 instead of throwing if there is an error. */
65static SCM
66bytevector_c32_ref (SCM bv, size_t pos)
67{
68 char *c_bv;
69 float real, imag;
70
71 if (!SCM_BYTEVECTOR_P (bv))
72 abort ();
73 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
74 pos *= 2 * sizeof (float);
75 if (pos + 2 * sizeof (float) - 1 >= SCM_BYTEVECTOR_LENGTH (bv))
76 abort ();
77
78 memcpy (&real, &c_bv[pos], sizeof (float));
79 memcpy (&imag, &c_bv[pos + sizeof (float)], sizeof (float));
80 return scm_c_make_rectangular (real, imag);
81}
82
83static SCM
84bytevector_c64_ref (SCM bv, size_t pos)
c53c0893 85{
cf64dca6
AW
86 char *c_bv;
87 double real, imag;
88
89 if (!SCM_BYTEVECTOR_P (bv))
2a610be5 90 abort ();
cf64dca6
AW
91 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
92 pos *= 2 * sizeof (double);
93 if (pos + 2 * sizeof (double) - 1 >= SCM_BYTEVECTOR_LENGTH (bv))
94 abort ();
95
96 memcpy (&real, &c_bv[pos], sizeof (double));
97 memcpy (&imag, &c_bv[pos + sizeof (double)], sizeof (double));
98 return scm_c_make_rectangular (real, imag);
c53c0893
AW
99}
100
cf64dca6
AW
101static void
102bytevector_c32_set (SCM bv, size_t pos, SCM val)
c53c0893 103{
cf64dca6
AW
104 char *c_bv;
105 float real, imag;
106
107 if (!SCM_BYTEVECTOR_P (bv))
108 abort ();
109 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
110 pos *= 2 * sizeof (float);
111 if (pos + 2 * sizeof (float) - 1 >= SCM_BYTEVECTOR_LENGTH (bv))
112 abort ();
113
114 real = scm_c_real_part (val);
115 imag = scm_c_imag_part (val);
116 memcpy (&c_bv[pos], &real, sizeof (float));
117 memcpy (&c_bv[pos + sizeof (float)], &imag, sizeof (float));
118}
119
120static void
121bytevector_c64_set (SCM bv, size_t pos, SCM val)
122{
123 char *c_bv;
124 double real, imag;
125
126 if (!SCM_BYTEVECTOR_P (bv))
127 abort ();
128 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
129 pos *= 2 * sizeof (double);
130 if (pos + 2 * sizeof (double) - 1 >= SCM_BYTEVECTOR_LENGTH (bv))
131 abort ();
132
133 real = scm_c_real_part (val);
134 imag = scm_c_imag_part (val);
135 memcpy (&c_bv[pos], &real, sizeof (double));
136 memcpy (&c_bv[pos + sizeof (double)], &imag, sizeof (double));
137}
138
139static void
140initialize_vector_handle (scm_t_array_handle *h, size_t len,
141 scm_t_array_element_type element_type,
142 scm_t_vector_ref vref, scm_t_vector_set vset,
143 void *writable_elements)
144{
145 h->base = 0;
146 h->ndims = 1;
147 h->dims = &h->dim0;
148 h->dim0.lbnd = 0;
149 h->dim0.ubnd = (ssize_t) (len - 1U);
150 h->dim0.inc = 1;
151 h->element_type = element_type;
152 h->elements = h->writable_elements = writable_elements;
153 h->vector = h->array;
154 h->vref = vref;
155 h->vset = vset;
c53c0893
AW
156}
157
158void
159scm_array_get_handle (SCM array, scm_t_array_handle *h)
160{
cf64dca6 161 if (!SCM_HEAP_OBJECT_P (array))
2a610be5 162 scm_wrong_type_arg_msg (NULL, 0, array, "array");
cf64dca6 163
c53c0893 164 h->array = array;
cf64dca6
AW
165
166 switch (SCM_TYP7 (array))
167 {
168 case scm_tc7_string:
169 initialize_vector_handle (h, scm_c_string_length (array),
170 SCM_ARRAY_ELEMENT_TYPE_CHAR,
171 scm_c_string_ref, scm_c_string_set_x,
172 NULL);
173 break;
174 case scm_tc7_vector:
175 initialize_vector_handle (h, scm_c_vector_length (array),
176 SCM_ARRAY_ELEMENT_TYPE_SCM,
177 scm_c_vector_ref, scm_c_vector_set_x,
178 SCM_I_VECTOR_WELTS (array));
179 break;
180 case scm_tc7_bitvector:
181 initialize_vector_handle (h, scm_c_bitvector_length (array),
182 SCM_ARRAY_ELEMENT_TYPE_BIT,
183 scm_c_bitvector_ref, scm_c_bitvector_set_x,
184 scm_i_bitvector_bits (array));
185 break;
186 case scm_tc7_bytevector:
187 {
188 size_t byte_length, length, element_byte_size;
189 scm_t_array_element_type element_type;
190 scm_t_vector_ref vref;
191 scm_t_vector_set vset;
192
193 byte_length = scm_c_bytevector_length (array);
194 element_type = SCM_BYTEVECTOR_ELEMENT_TYPE (array);
195 element_byte_size = scm_i_array_element_type_sizes[element_type] / 8;
196 length = byte_length / element_byte_size;
197
198 switch (element_type)
199 {
200#define ACCESSOR_CASE(tag, TAG) \
201 case SCM_ARRAY_ELEMENT_TYPE_##TAG: \
202 vref = bytevector_##tag##_ref; \
203 vset = bytevector_##tag##_set; \
204 break
205
206 case SCM_ARRAY_ELEMENT_TYPE_VU8:
207 ACCESSOR_CASE(u8, U8);
208 ACCESSOR_CASE(s8, S8);
209 ACCESSOR_CASE(u16, U16);
210 ACCESSOR_CASE(s16, S16);
211 ACCESSOR_CASE(u32, U32);
212 ACCESSOR_CASE(s32, S32);
213 ACCESSOR_CASE(u64, U64);
214 ACCESSOR_CASE(s64, S64);
215 ACCESSOR_CASE(f32, F32);
216 ACCESSOR_CASE(f64, F64);
217 ACCESSOR_CASE(c32, C32);
218 ACCESSOR_CASE(c64, C64);
219
220 case SCM_ARRAY_ELEMENT_TYPE_SCM:
221 case SCM_ARRAY_ELEMENT_TYPE_BIT:
222 case SCM_ARRAY_ELEMENT_TYPE_CHAR:
223 default:
224 abort ();
225
226#undef ACCESSOR_CASE
227 }
228
229 initialize_vector_handle (h, length, element_type, vref, vset,
230 SCM_BYTEVECTOR_CONTENTS (array));
231 }
232 break;
233 case scm_tc7_array:
4e915304
AW
234 scm_array_get_handle (SCM_I_ARRAY_V (array), h);
235 h->array = array;
cf64dca6
AW
236 h->base = SCM_I_ARRAY_BASE (array);
237 h->ndims = SCM_I_ARRAY_NDIM (array);
238 h->dims = SCM_I_ARRAY_DIMS (array);
cf64dca6
AW
239 break;
240 default:
241 scm_wrong_type_arg_msg (NULL, 0, array, "array");
242 }
2a610be5
AW
243}
244
245ssize_t
246scm_array_handle_pos (scm_t_array_handle *h, SCM indices)
247{
248 scm_t_array_dim *s = scm_array_handle_dims (h);
249 ssize_t pos = 0, i;
250 size_t k = scm_array_handle_rank (h);
251
252 while (k > 0 && scm_is_pair (indices))
c53c0893 253 {
2a610be5
AW
254 i = scm_to_signed_integer (SCM_CAR (indices), s->lbnd, s->ubnd);
255 pos += (i - s->lbnd) * s->inc;
256 k--;
257 s++;
258 indices = SCM_CDR (indices);
c53c0893 259 }
2a610be5
AW
260 if (k > 0 || !scm_is_null (indices))
261 scm_misc_error (NULL, "wrong number of indices, expecting ~a",
262 scm_list_1 (scm_from_size_t (scm_array_handle_rank (h))));
263 return pos;
264}
265
336c9211
AW
266static void
267check_array_index_bounds (scm_t_array_dim *dim, ssize_t idx)
268{
269 if (idx < dim->lbnd || idx > dim->ubnd)
270 scm_error (scm_out_of_range_key, NULL, "Value out of range ~S to ~S: ~S",
271 scm_list_3 (scm_from_ssize_t (dim->lbnd),
272 scm_from_ssize_t (dim->ubnd),
273 scm_from_ssize_t (idx)),
274 scm_list_1 (scm_from_ssize_t (idx)));
275}
276
277ssize_t
278scm_array_handle_pos_1 (scm_t_array_handle *h, ssize_t idx0)
279{
280 scm_t_array_dim *dim = scm_array_handle_dims (h);
281
282 if (scm_array_handle_rank (h) != 1)
283 scm_misc_error (NULL, "wrong number of indices, expecting ~A",
284 scm_list_1 (scm_from_size_t (scm_array_handle_rank (h))));
285
286 check_array_index_bounds (&dim[0], idx0);
287
288 return (idx0 - dim[0].lbnd) * dim[0].inc;
289}
290
291ssize_t
292scm_array_handle_pos_2 (scm_t_array_handle *h, ssize_t idx0, ssize_t idx1)
293{
294 scm_t_array_dim *dim = scm_array_handle_dims (h);
295
296 if (scm_array_handle_rank (h) != 2)
297 scm_misc_error (NULL, "wrong number of indices, expecting ~A",
298 scm_list_1 (scm_from_size_t (scm_array_handle_rank (h))));
299
300 check_array_index_bounds (&dim[0], idx0);
301 check_array_index_bounds (&dim[1], idx1);
302
303 return ((idx0 - dim[0].lbnd) * dim[0].inc
304 + (idx1 - dim[1].lbnd) * dim[1].inc);
305}
306
2a610be5
AW
307SCM
308scm_array_handle_element_type (scm_t_array_handle *h)
309{
310 if (h->element_type < 0 || h->element_type > SCM_ARRAY_ELEMENT_TYPE_LAST)
311 abort (); /* guile programming error */
312 return scm_i_array_element_types[h->element_type];
c53c0893
AW
313}
314
315void
316scm_array_handle_release (scm_t_array_handle *h)
317{
318 /* Nothing to do here until arrays need to be reserved for real.
319 */
320}
321
c53c0893
AW
322const SCM *
323scm_array_handle_elements (scm_t_array_handle *h)
324{
2a610be5
AW
325 if (h->element_type != SCM_ARRAY_ELEMENT_TYPE_SCM)
326 scm_wrong_type_arg_msg (NULL, 0, h->array, "non-uniform array");
327 return ((const SCM*)h->elements) + h->base;
c53c0893
AW
328}
329
330SCM *
331scm_array_handle_writable_elements (scm_t_array_handle *h)
332{
2a610be5
AW
333 if (h->element_type != SCM_ARRAY_ELEMENT_TYPE_SCM)
334 scm_wrong_type_arg_msg (NULL, 0, h->array, "non-uniform array");
335 return ((SCM*)h->elements) + h->base;
c53c0893
AW
336}
337
c53c0893
AW
338void
339scm_init_array_handle (void)
340{
2a610be5 341#define DEFINE_ARRAY_TYPE(tag, TAG) \
25d50a05 342 scm_i_array_element_types[SCM_ARRAY_ELEMENT_TYPE_##TAG] = scm_from_utf8_symbol (#tag)
2a610be5
AW
343
344 scm_i_array_element_types[SCM_ARRAY_ELEMENT_TYPE_SCM] = SCM_BOOL_T;
345 DEFINE_ARRAY_TYPE (a, CHAR);
346 DEFINE_ARRAY_TYPE (b, BIT);
347 DEFINE_ARRAY_TYPE (vu8, VU8);
348 DEFINE_ARRAY_TYPE (u8, U8);
349 DEFINE_ARRAY_TYPE (s8, S8);
350 DEFINE_ARRAY_TYPE (u16, U16);
351 DEFINE_ARRAY_TYPE (s16, S16);
352 DEFINE_ARRAY_TYPE (u32, U32);
353 DEFINE_ARRAY_TYPE (s32, S32);
354 DEFINE_ARRAY_TYPE (u64, U64);
355 DEFINE_ARRAY_TYPE (s64, S64);
356 DEFINE_ARRAY_TYPE (f32, F32);
357 DEFINE_ARRAY_TYPE (f64, F64);
358 DEFINE_ARRAY_TYPE (c32, C32);
359 DEFINE_ARRAY_TYPE (c64, C64);
360
c53c0893
AW
361#include "libguile/array-handle.x"
362}
363
364/*
365 Local Variables:
366 c-file-style: "gnu"
367 End:
368*/