1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 03:40:34 +02:00
guile/libguile/array-handle.c
Andy Wingo cf64dca65c Remove array impl. registry; instead, hard-code array handle creation
* libguile/array-handle.h (scm_t_vector_ref, scm_t_vector_set): Rename
  from scm_t_array_ref, scm_t_array_set.  These were named
  scm_i_t_array_ref and scm_i_t_array_set in 1.8 and 2.0.  Change to
  take the vector directly, instead of the array handle.  In this way,
  generic array handles are layered on top of specific implementations
  of backing stores.

  Remove scm_t_array_implementation, introduced in 2.0 but never
  documented.  It was a failed attempt to layer the array implementation
  that actually introduced too many layers, as it prevented the "vref"
  and "vset" members of scm_t_array_handle (called "ref" and "set" in
  1.8, not present in 2.0) from specializing on array backing stores.

  (scm_i_register_array_implementation) (scm_i_array_implementation_for_obj):
  Remove these internal interfaces.

  (scm_t_array_handle): Adapt to scm_t_vector_ref / scm_t_vector_set
  change.

  (scm_array_handle_ref, scm_array_handle_set): Adapt to change in
  vref/vset prototype.

* libguile/array-handle.c (scm_array_get_handle): Inline all the
  necessary initializations here for all specific array types.

* libguile/array-map.c (rafill, racp, ramap, rafe, array_index_map_1):

* libguile/arrays.c: Remove array implementation code.

* libguile/bitvectors.h:
* libguile/bitvectors.c: Remove array implementation code.
  (scm_i_bitvector_bits): New internal interface.

* libguile/bytevectors.c: Remove array implementation code.

* libguile/srfi-4.h: Remove declarations for internal procedures that
  don't exist (!).

* libguile/strings.c: Remove array implementation code.

* libguile/vectors.c: Remove array implementation code.
2014-02-09 12:48:21 +01:00

378 lines
12 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Copyright (C) 1995,1996,1997,1998,2000,2001,2002,2003,2004, 2005,
* 2006, 2009, 2011, 2013, 2014 Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "libguile/_scm.h"
#include "libguile/__scm.h"
#include "libguile/array-handle.h"
SCM scm_i_array_element_types[SCM_ARRAY_ELEMENT_TYPE_LAST + 1];
/* Bytevectors as generalized vectors & arrays. */
#define DEFINE_BYTEVECTOR_ACCESSORS(type, tag, infix) \
static SCM \
bytevector_##tag##_ref (SCM bv, size_t pos) \
{ \
SCM idx = scm_from_size_t (pos * sizeof (type)); \
return scm_bytevector_##infix##_ref (bv, idx); \
} \
static void \
bytevector_##tag##_set (SCM bv, size_t pos, SCM val) \
{ \
SCM idx = scm_from_size_t (pos * sizeof (type)); \
scm_bytevector_##infix##_set_x (bv, idx, val); \
}
DEFINE_BYTEVECTOR_ACCESSORS (uint8_t, u8, u8);
DEFINE_BYTEVECTOR_ACCESSORS (int8_t, s8, s8);
DEFINE_BYTEVECTOR_ACCESSORS (uint16_t, u16, u16_native);
DEFINE_BYTEVECTOR_ACCESSORS (int16_t, s16, s16_native);
DEFINE_BYTEVECTOR_ACCESSORS (uint32_t, u32, u32_native);
DEFINE_BYTEVECTOR_ACCESSORS (int32_t, s32, s32_native);
DEFINE_BYTEVECTOR_ACCESSORS (uint64_t, u64, u64_native);
DEFINE_BYTEVECTOR_ACCESSORS (int64_t, s64, s64_native);
DEFINE_BYTEVECTOR_ACCESSORS (float, f32, ieee_single_native);
DEFINE_BYTEVECTOR_ACCESSORS (double, f64, ieee_double_native);
/* Since these functions are only called by Guile's C code, we can abort
instead of throwing if there is an error. */
static SCM
bytevector_c32_ref (SCM bv, size_t pos)
{
char *c_bv;
float real, imag;
if (!SCM_BYTEVECTOR_P (bv))
abort ();
c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
pos *= 2 * sizeof (float);
if (pos + 2 * sizeof (float) - 1 >= SCM_BYTEVECTOR_LENGTH (bv))
abort ();
memcpy (&real, &c_bv[pos], sizeof (float));
memcpy (&imag, &c_bv[pos + sizeof (float)], sizeof (float));
return scm_c_make_rectangular (real, imag);
}
static SCM
bytevector_c64_ref (SCM bv, size_t pos)
{
char *c_bv;
double real, imag;
if (!SCM_BYTEVECTOR_P (bv))
abort ();
c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
pos *= 2 * sizeof (double);
if (pos + 2 * sizeof (double) - 1 >= SCM_BYTEVECTOR_LENGTH (bv))
abort ();
memcpy (&real, &c_bv[pos], sizeof (double));
memcpy (&imag, &c_bv[pos + sizeof (double)], sizeof (double));
return scm_c_make_rectangular (real, imag);
}
static void
bytevector_c32_set (SCM bv, size_t pos, SCM val)
{
char *c_bv;
float real, imag;
if (!SCM_BYTEVECTOR_P (bv))
abort ();
c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
pos *= 2 * sizeof (float);
if (pos + 2 * sizeof (float) - 1 >= SCM_BYTEVECTOR_LENGTH (bv))
abort ();
real = scm_c_real_part (val);
imag = scm_c_imag_part (val);
memcpy (&c_bv[pos], &real, sizeof (float));
memcpy (&c_bv[pos + sizeof (float)], &imag, sizeof (float));
}
static void
bytevector_c64_set (SCM bv, size_t pos, SCM val)
{
char *c_bv;
double real, imag;
if (!SCM_BYTEVECTOR_P (bv))
abort ();
c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
pos *= 2 * sizeof (double);
if (pos + 2 * sizeof (double) - 1 >= SCM_BYTEVECTOR_LENGTH (bv))
abort ();
real = scm_c_real_part (val);
imag = scm_c_imag_part (val);
memcpy (&c_bv[pos], &real, sizeof (double));
memcpy (&c_bv[pos + sizeof (double)], &imag, sizeof (double));
}
static void
initialize_vector_handle (scm_t_array_handle *h, size_t len,
scm_t_array_element_type element_type,
scm_t_vector_ref vref, scm_t_vector_set vset,
void *writable_elements)
{
h->base = 0;
h->ndims = 1;
h->dims = &h->dim0;
h->dim0.lbnd = 0;
h->dim0.ubnd = (ssize_t) (len - 1U);
h->dim0.inc = 1;
h->element_type = element_type;
h->elements = h->writable_elements = writable_elements;
h->vector = h->array;
h->vref = vref;
h->vset = vset;
}
void
scm_array_get_handle (SCM array, scm_t_array_handle *h)
{
if (!SCM_HEAP_OBJECT_P (array))
scm_wrong_type_arg_msg (NULL, 0, array, "array");
h->array = array;
switch (SCM_TYP7 (array))
{
case scm_tc7_string:
initialize_vector_handle (h, scm_c_string_length (array),
SCM_ARRAY_ELEMENT_TYPE_CHAR,
scm_c_string_ref, scm_c_string_set_x,
NULL);
break;
case scm_tc7_vector:
initialize_vector_handle (h, scm_c_vector_length (array),
SCM_ARRAY_ELEMENT_TYPE_SCM,
scm_c_vector_ref, scm_c_vector_set_x,
SCM_I_VECTOR_WELTS (array));
break;
case scm_tc7_bitvector:
initialize_vector_handle (h, scm_c_bitvector_length (array),
SCM_ARRAY_ELEMENT_TYPE_BIT,
scm_c_bitvector_ref, scm_c_bitvector_set_x,
scm_i_bitvector_bits (array));
break;
case scm_tc7_bytevector:
{
size_t byte_length, length, element_byte_size;
scm_t_array_element_type element_type;
scm_t_vector_ref vref;
scm_t_vector_set vset;
byte_length = scm_c_bytevector_length (array);
element_type = SCM_BYTEVECTOR_ELEMENT_TYPE (array);
element_byte_size = scm_i_array_element_type_sizes[element_type] / 8;
length = byte_length / element_byte_size;
switch (element_type)
{
#define ACCESSOR_CASE(tag, TAG) \
case SCM_ARRAY_ELEMENT_TYPE_##TAG: \
vref = bytevector_##tag##_ref; \
vset = bytevector_##tag##_set; \
break
case SCM_ARRAY_ELEMENT_TYPE_VU8:
ACCESSOR_CASE(u8, U8);
ACCESSOR_CASE(s8, S8);
ACCESSOR_CASE(u16, U16);
ACCESSOR_CASE(s16, S16);
ACCESSOR_CASE(u32, U32);
ACCESSOR_CASE(s32, S32);
ACCESSOR_CASE(u64, U64);
ACCESSOR_CASE(s64, S64);
ACCESSOR_CASE(f32, F32);
ACCESSOR_CASE(f64, F64);
ACCESSOR_CASE(c32, C32);
ACCESSOR_CASE(c64, C64);
case SCM_ARRAY_ELEMENT_TYPE_SCM:
case SCM_ARRAY_ELEMENT_TYPE_BIT:
case SCM_ARRAY_ELEMENT_TYPE_CHAR:
default:
abort ();
#undef ACCESSOR_CASE
}
initialize_vector_handle (h, length, element_type, vref, vset,
SCM_BYTEVECTOR_CONTENTS (array));
}
break;
case scm_tc7_array:
h->base = SCM_I_ARRAY_BASE (array);
h->ndims = SCM_I_ARRAY_NDIM (array);
h->dims = SCM_I_ARRAY_DIMS (array);
{
scm_t_array_handle vh;
scm_array_get_handle (SCM_I_ARRAY_V (array), &vh);
h->element_type = vh.element_type;
h->elements = vh.elements;
h->writable_elements = vh.writable_elements;
h->vector = vh.vector;
h->vref = vh.vref;
h->vset = vh.vset;
scm_array_handle_release (&vh);
}
break;
default:
scm_wrong_type_arg_msg (NULL, 0, array, "array");
}
}
ssize_t
scm_array_handle_pos (scm_t_array_handle *h, SCM indices)
{
scm_t_array_dim *s = scm_array_handle_dims (h);
ssize_t pos = 0, i;
size_t k = scm_array_handle_rank (h);
while (k > 0 && scm_is_pair (indices))
{
i = scm_to_signed_integer (SCM_CAR (indices), s->lbnd, s->ubnd);
pos += (i - s->lbnd) * s->inc;
k--;
s++;
indices = SCM_CDR (indices);
}
if (k > 0 || !scm_is_null (indices))
scm_misc_error (NULL, "wrong number of indices, expecting ~a",
scm_list_1 (scm_from_size_t (scm_array_handle_rank (h))));
return pos;
}
static void
check_array_index_bounds (scm_t_array_dim *dim, ssize_t idx)
{
if (idx < dim->lbnd || idx > dim->ubnd)
scm_error (scm_out_of_range_key, NULL, "Value out of range ~S to ~S: ~S",
scm_list_3 (scm_from_ssize_t (dim->lbnd),
scm_from_ssize_t (dim->ubnd),
scm_from_ssize_t (idx)),
scm_list_1 (scm_from_ssize_t (idx)));
}
ssize_t
scm_array_handle_pos_1 (scm_t_array_handle *h, ssize_t idx0)
{
scm_t_array_dim *dim = scm_array_handle_dims (h);
if (scm_array_handle_rank (h) != 1)
scm_misc_error (NULL, "wrong number of indices, expecting ~A",
scm_list_1 (scm_from_size_t (scm_array_handle_rank (h))));
check_array_index_bounds (&dim[0], idx0);
return (idx0 - dim[0].lbnd) * dim[0].inc;
}
ssize_t
scm_array_handle_pos_2 (scm_t_array_handle *h, ssize_t idx0, ssize_t idx1)
{
scm_t_array_dim *dim = scm_array_handle_dims (h);
if (scm_array_handle_rank (h) != 2)
scm_misc_error (NULL, "wrong number of indices, expecting ~A",
scm_list_1 (scm_from_size_t (scm_array_handle_rank (h))));
check_array_index_bounds (&dim[0], idx0);
check_array_index_bounds (&dim[1], idx1);
return ((idx0 - dim[0].lbnd) * dim[0].inc
+ (idx1 - dim[1].lbnd) * dim[1].inc);
}
SCM
scm_array_handle_element_type (scm_t_array_handle *h)
{
if (h->element_type < 0 || h->element_type > SCM_ARRAY_ELEMENT_TYPE_LAST)
abort (); /* guile programming error */
return scm_i_array_element_types[h->element_type];
}
void
scm_array_handle_release (scm_t_array_handle *h)
{
/* Nothing to do here until arrays need to be reserved for real.
*/
}
const SCM *
scm_array_handle_elements (scm_t_array_handle *h)
{
if (h->element_type != SCM_ARRAY_ELEMENT_TYPE_SCM)
scm_wrong_type_arg_msg (NULL, 0, h->array, "non-uniform array");
return ((const SCM*)h->elements) + h->base;
}
SCM *
scm_array_handle_writable_elements (scm_t_array_handle *h)
{
if (h->element_type != SCM_ARRAY_ELEMENT_TYPE_SCM)
scm_wrong_type_arg_msg (NULL, 0, h->array, "non-uniform array");
return ((SCM*)h->elements) + h->base;
}
void
scm_init_array_handle (void)
{
#define DEFINE_ARRAY_TYPE(tag, TAG) \
scm_i_array_element_types[SCM_ARRAY_ELEMENT_TYPE_##TAG] = scm_from_utf8_symbol (#tag)
scm_i_array_element_types[SCM_ARRAY_ELEMENT_TYPE_SCM] = SCM_BOOL_T;
DEFINE_ARRAY_TYPE (a, CHAR);
DEFINE_ARRAY_TYPE (b, BIT);
DEFINE_ARRAY_TYPE (vu8, VU8);
DEFINE_ARRAY_TYPE (u8, U8);
DEFINE_ARRAY_TYPE (s8, S8);
DEFINE_ARRAY_TYPE (u16, U16);
DEFINE_ARRAY_TYPE (s16, S16);
DEFINE_ARRAY_TYPE (u32, U32);
DEFINE_ARRAY_TYPE (s32, S32);
DEFINE_ARRAY_TYPE (u64, U64);
DEFINE_ARRAY_TYPE (s64, S64);
DEFINE_ARRAY_TYPE (f32, F32);
DEFINE_ARRAY_TYPE (f64, F64);
DEFINE_ARRAY_TYPE (c32, C32);
DEFINE_ARRAY_TYPE (c64, C64);
#include "libguile/array-handle.x"
}
/*
Local Variables:
c-file-style: "gnu"
End:
*/