Edit

kc3-lang/kc3/libc3/array.c

Branch :

  • libc3/array.c
  • /* c3
     * Copyright 2022,2023 kmx.io <contact@kmx.io>
     *
     * Permission is hereby granted to use this software granted the above
     * copyright notice and this permission paragraph are included in all
     * copies and substantial portions of this software.
     *
     * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
     * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
     * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
     * THIS SOFTWARE.
     */
    #include <assert.h>
    #include <stdlib.h>
    #include <string.h>
    #include <err.h>
    #include "array.h"
    #include "bool.h"
    #include "buf.h"
    #include "buf_inspect.h"
    #include "buf_parse.h"
    #include "call.h"
    #include "cfn.h"
    #include "character.h"
    #include "env.h"
    #include "f32.h"
    #include "f64.h"
    #include "fact.h"
    #include "fn.h"
    #include "ident.h"
    #include "integer.h"
    #include "list.h"
    #include "ptag.h"
    #include "quote.h"
    #include "s8.h"
    #include "s16.h"
    #include "s32.h"
    #include "s64.h"
    #include "str.h"
    #include "sw.h"
    #include "sym.h"
    #include "tag.h"
    #include "tuple.h"
    #include "type.h"
    #include "u8.h"
    #include "u16.h"
    #include "u32.h"
    #include "u64.h"
    #include "uw.h"
    #include "var.h"
    
    void array_clean (s_array *a)
    {
      u8 *data;
      u8 *data_tag;
      uw i;
      uw size;
      s_tag tag;
      assert(a);
      free(a->dimensions);
      if (a->data) {
        data = a->data;
        size = array_type_size(a->type);
        tag.type = array_type_to_tag_type(a->type);
        i = 0;
        while (i < a->count) {
          data_tag = tag_to_pointer(&tag, a->type);
          memcpy(data_tag, data, size);
          tag_clean(&tag);
          data += size;
          i++;
        }
        free(a->data);
      }
      if (a->tags) {
        i = 0;
        while (i < a->count) {
          tag_clean(a->tags + i);
          i++;
        }
        free(a->tags);
      }
    }
    
    void * array_data (const s_array *a, const uw *address)
    {
      uw i = 0;
      uw offset = 0;
      assert(a);
      assert(address);
      assert(a->data);
      while (i < a->dimension) {
        if (address[i] >= a->dimensions[i].count) {
          warnx("array_data: address overflow: %lu", i);
          return NULL;
        }
        offset += address[i] * a->dimensions[i].item_size;
        i++;
      }
      assert(offset < a->size);
      return (s8 *) a->data + offset;
    }
    
    s_tag * array_data_tag (s_tag *a, const s_tag *address, s_tag *dest)
    {
      void *a_data;
      f_init_copy init_copy;
      void *dest_data;
      assert(a->type == TAG_ARRAY);
      assert(address->type == TAG_ARRAY);
      if ((a_data = array_data(&a->data.array,
                               address->data.array.data))) {
        tag_init(dest);
        init_copy = array_type_to_init_copy(a->data.array.type);
        sym_to_tag_type(a->data.array.type, &dest->type);
        dest_data = tag_to_pointer(dest, a->data.array.type);
        if (init_copy(dest_data, a_data) != dest_data)
          return NULL;
        return dest;
      }
      return NULL;
    }
    
    s_array * array_init (s_array *a, const s_sym *type, uw dimension,
                          const uw *dimensions)
    {
      uw count = 1;
      uw i = 0;
      uw item_size;
      assert(a);
      assert(dimension);
      assert(dimensions);
      if (! dimension) {
        assert(! "array_init: zero dimension");
        errx(1, "array_init: zero dimension");
        return NULL;
      }
    #ifdef DEBUG
      while (i < dimension) {
        assert(dimensions[i]);
        i++;
      }
    #endif
      a->dimension = dimension;
      a->dimensions = calloc(dimension, sizeof(s_array_dimension));
      i = 0;
      while (i < dimension) {
        a->dimensions[i].count = dimensions[i];
        count *= dimensions[i];
        i++;
      }
      i--;
      a->type = type;
      item_size = array_type_size(type);
      a->dimensions[i].item_size = item_size;
      while (i > 0) {
        i--;
        a->dimensions[i].item_size = a->dimensions[i + 1].count *
          a->dimensions[i + 1].item_size;
      }
      a->size = a->dimensions[0].count * a->dimensions[0].item_size;
      a->count = count;
      a->data = NULL;
      a->tags = NULL;
      return a;
    }
    
    s_array * array_init_1 (s_array *array, s8 *p)
    {
      s_buf buf;
      sw r;
      s_array tmp;
      buf_init_1(&buf, p);
      if ((r = buf_parse_array(&buf, &tmp)) != (sw) strlen(p)) {
        warnx("array_init_1: buf_parse_array(%s) => %ld != %ld", p, r, strlen(p));
        if (r > 0)
          array_clean(&tmp);
        buf_clean(&buf);
        return NULL;
      }
      buf_clean(&buf);
      if (! env_eval_array(&g_c3_env, &tmp, array)) {
        warnx("array_init_1: env_eval_array");
        array_clean(&tmp);
        return NULL;
      }
      array_clean(&tmp);
      return array;
    }
    
    s_array * array_init_copy (s_array *a, const s_array *src)
    {
      f_init_copy init_copy;
      u8 *data_a;
      u8 *data_src;
      uw i = 0;
      uw item_size;
      s_array tmp;
      assert(a);
      assert(src);
      assert(src->dimension);
      assert(src->dimensions);
      (void) i;
      bzero(&tmp, sizeof(s_array));
      if (! src->dimension) {
        assert(! "array_init_copy: zero dimension");
        errx(1, "array_init_copy: zero dimension");
        return NULL;
      }
    #ifdef DEBUG
      while (i < src->dimension) {
        assert(src->dimensions[i].count);
        i++;
      }
    #endif
      tmp.dimension = src->dimension;
      if (! (tmp.dimensions = calloc(tmp.dimension,
                                     sizeof(s_array_dimension)))) {
        assert(! "array_init_copy: out of memory: dimensions");
        warnx("array_init_copy: out of memory: dimensions");
        return NULL;
      }
      memcpy(tmp.dimensions, src->dimensions,
             src->dimension * sizeof(s_array_dimension));
      tmp.count = src->count;
      tmp.size = src->size;
      tmp.type = src->type;
      if (src->data) {
        if (! (tmp.data = calloc(1, src->size)))
          errx(1, "array_init_copy: out of memory");
        init_copy = array_type_to_init_copy(src->type);
        data_a = tmp.data;
        data_src = src->data;
        i = 0;
        item_size = src->dimensions[src->dimension - 1].item_size;
        while (i < src->count) {
          if (init_copy(data_a, data_src) != data_a) {
            return NULL;
          }
          data_a += item_size;
          data_src += item_size;
          i++;
        }
      }
      else
        tmp.data = NULL;
      if (src->tags) {
        tmp.tags = calloc(src->count, sizeof(s_tag));
        i = 0;
        while (i < src->count) {
          tag_init_copy(tmp.tags + i, src->tags + i);
          i++;
        }
      }
      else
        tmp.tags = NULL;
      *a = tmp;
      return a;
    }
    
    s_str * array_inspect (const s_array *array, s_str *dest)
    {
      sw size;
      s_buf tmp;
      size = buf_inspect_array_size(array);
      if (size < 0) {
        assert(! "array_inspect: error");
        errx(1, "array_inspect: error");
        return NULL;
      }
      buf_init_alloc(&tmp, size);
      buf_inspect_array(&tmp, array);
      assert(tmp.wpos == tmp.size);
      if (tmp.wpos != tmp.size) {
        buf_clean(&tmp);
        errx(1, "array_inspect: buf_inspect_array");
        return NULL;
      }
      return buf_to_str(&tmp, dest);
    }
    
    uw array_type_size (const s_sym *type)
    {
      if (type == sym_1("Bool"))
        return sizeof(bool);
      if (type == sym_1("Call"))
        return sizeof(s_call);
      if (type == sym_1("Cfn"))
        return sizeof(s_cfn);
      if (type == sym_1("Character"))
        return sizeof(character);
      if (type == sym_1("F32"))
        return sizeof(f32);
      if (type == sym_1("F64"))
        return sizeof(f64);
      if (type == sym_1("Fact"))
        return sizeof(s_fact);
      if (type == sym_1("Fn"))
        return sizeof(s_fn);
      if (type == sym_1("Ident"))
        return sizeof(s_ident);
      if (type == sym_1("Integer"))
        return sizeof(s_integer);
      if (type == sym_1("Sw"))
        return sizeof(sw);
      if (type == sym_1("S64"))
        return sizeof(s64);
      if (type == sym_1("S32"))
        return sizeof(s32);
      if (type == sym_1("S16"))
        return sizeof(s16);
      if (type == sym_1("S8"))
        return sizeof(s8);
      if (type == sym_1("U8"))
        return sizeof(u8);
      if (type == sym_1("U16"))
        return sizeof(u16);
      if (type == sym_1("U32"))
        return sizeof(u32);
      if (type == sym_1("U64"))
        return sizeof(u64);
      if (type == sym_1("Uw"))
        return sizeof(uw);
      if (type == sym_1("List"))
        return sizeof(s_list *);
      if (type == sym_1("Ptag"))
        return sizeof(p_tag);
      if (type == sym_1("Quote"))
        return sizeof(s_quote);
      if (type == sym_1("Str"))
        return sizeof(s_str);
      if (type == sym_1("Sym"))
        return sizeof(s_sym *);
      if (type == sym_1("Tuple"))
        return sizeof(s_tuple);
      if (type == sym_1("Var"))
        return sizeof(s_tag);
      assert(! "array_type_size: unknown type");
      errx(1, "array_type_size: unknown type: %s", type->str.ptr.ps8);
      return 0;
    }
    
    f_buf_inspect array_type_to_buf_inspect (const s_sym *type)
    {
      if (type == sym_1("Bool"))
        return (f_buf_inspect) buf_inspect_bool;
      if (type == sym_1("Call"))
        return (f_buf_inspect) buf_inspect_call;
      if (type == sym_1("Cfn"))
        return (f_buf_inspect) buf_inspect_cfn;
      if (type == sym_1("Character"))
        return (f_buf_inspect) buf_inspect_character;
      if (type == sym_1("F32"))
        return (f_buf_inspect) buf_inspect_f32;
      if (type == sym_1("F64"))
        return (f_buf_inspect) buf_inspect_f64;
      if (type == sym_1("Fact"))
        return (f_buf_inspect) buf_inspect_fact;
      if (type == sym_1("Fn"))
        return (f_buf_inspect) buf_inspect_fn;
      if (type == sym_1("Ident"))
        return (f_buf_inspect) buf_inspect_ident;
      if (type == sym_1("Integer"))
        return (f_buf_inspect) buf_inspect_integer;
      if (type == sym_1("Sw"))
        return (f_buf_inspect) buf_inspect_sw;
      if (type == sym_1("S64"))
        return (f_buf_inspect) buf_inspect_s64;
      if (type == sym_1("S32"))
        return (f_buf_inspect) buf_inspect_s32;
      if (type == sym_1("S16"))
        return (f_buf_inspect) buf_inspect_s16;
      if (type == sym_1("S8"))
        return (f_buf_inspect) buf_inspect_s8;
      if (type == sym_1("U8"))
        return (f_buf_inspect) buf_inspect_u8;
      if (type == sym_1("U16"))
        return (f_buf_inspect) buf_inspect_u16;
      if (type == sym_1("U32"))
        return (f_buf_inspect) buf_inspect_u32;
      if (type == sym_1("U64"))
        return (f_buf_inspect) buf_inspect_u64;
      if (type == sym_1("Uw"))
        return (f_buf_inspect) buf_inspect_uw;
      if (type == sym_1("List"))
        return (f_buf_inspect) buf_inspect_list;
      if (type == sym_1("Ptag"))
        return (f_buf_inspect) buf_inspect_ptag;
      if (type == sym_1("Quote"))
        return (f_buf_inspect) buf_inspect_quote;
      if (type == sym_1("Str"))
        return (f_buf_inspect) buf_inspect_str;
      if (type == sym_1("Sym"))
        return (f_buf_inspect) buf_inspect_sym;
      if (type == sym_1("Tuple"))
        return (f_buf_inspect) buf_inspect_tuple;
      if (type == sym_1("Var"))
        return (f_buf_inspect) buf_inspect_var;
      assert(! "array_type_to_buf_inspect: unknown type");
      errx(1, "array_type_to_buf_inspect: unknown type");
      return NULL;
    }
    
    f_buf_inspect_size array_type_to_buf_inspect_size (const s_sym *type)
    {
      if (type == sym_1("Bool"))
        return (f_buf_inspect_size) buf_inspect_bool_size;
      if (type == sym_1("Call"))
        return (f_buf_inspect_size) buf_inspect_call_size;
      if (type == sym_1("Cfn"))
        return (f_buf_inspect_size) buf_inspect_cfn_size;
      if (type == sym_1("Character"))
        return (f_buf_inspect_size) buf_inspect_character_size;
      if (type == sym_1("F32"))
        return (f_buf_inspect_size) buf_inspect_f32_size;
      if (type == sym_1("F64"))
        return (f_buf_inspect_size) buf_inspect_f64_size;
      if (type == sym_1("Fact"))
        return (f_buf_inspect_size) buf_inspect_fact_size;
      if (type == sym_1("Fn"))
        return (f_buf_inspect_size) buf_inspect_fn_size;
      if (type == sym_1("Ident"))
        return (f_buf_inspect_size) buf_inspect_ident_size;
      if (type == sym_1("Integer"))
        return (f_buf_inspect_size) buf_inspect_integer_size;
      if (type == sym_1("Sw"))
        return (f_buf_inspect_size) buf_inspect_sw_size;
      if (type == sym_1("S64"))
        return (f_buf_inspect_size) buf_inspect_s64_size;
      if (type == sym_1("S32"))
        return (f_buf_inspect_size) buf_inspect_s32_size;
      if (type == sym_1("S16"))
        return (f_buf_inspect_size) buf_inspect_s16_size;
      if (type == sym_1("S8"))
        return (f_buf_inspect_size) buf_inspect_s8_size;
      if (type == sym_1("U8"))
        return (f_buf_inspect_size) buf_inspect_u8_size;
      if (type == sym_1("U16"))
        return (f_buf_inspect_size) buf_inspect_u16_size;
      if (type == sym_1("U32"))
        return (f_buf_inspect_size) buf_inspect_u32_size;
      if (type == sym_1("U64"))
        return (f_buf_inspect_size) buf_inspect_u64_size;
      if (type == sym_1("Uw"))
        return (f_buf_inspect_size) buf_inspect_uw_size;
      if (type == sym_1("List"))
        return (f_buf_inspect_size) buf_inspect_list_size;
      if (type == sym_1("Ptag"))
        return (f_buf_inspect_size) buf_inspect_ptag_size;
      if (type == sym_1("Quote"))
        return (f_buf_inspect_size) buf_inspect_quote_size;
      if (type == sym_1("Str"))
        return (f_buf_inspect_size) buf_inspect_str_size;
      if (type == sym_1("Sym"))
        return (f_buf_inspect_size) buf_inspect_sym_size;
      if (type == sym_1("Tuple"))
        return (f_buf_inspect_size) buf_inspect_tuple_size;
      if (type == sym_1("Var"))
        return (f_buf_inspect_size) buf_inspect_var_size;
      assert(! "array_type_to_buf_inspect: unknown type");
      errx(1, "array_type_to_buf_inspect: unknown type");
      return NULL;
    }
    
    f_init_copy array_type_to_init_copy (const s_sym *type)
    {
      if (type == sym_1("Bool"))
        return (f_init_copy) bool_init_copy;
      if (type == sym_1("Call"))
        return (f_init_copy) call_init_copy;
      if (type == sym_1("Cfn"))
        return (f_init_copy) cfn_init_copy;
      if (type == sym_1("Character"))
        return (f_init_copy) character_init_copy;
      if (type == sym_1("F32"))
        return (f_init_copy) f32_init_copy;
      if (type == sym_1("F64"))
        return (f_init_copy) f64_init_copy;
      if (type == sym_1("Fact"))
        return (f_init_copy) fact_init_copy;
      if (type == sym_1("Fn"))
        return (f_init_copy) fn_init_copy;
      if (type == sym_1("Ident"))
        return (f_init_copy) ident_init_copy;
      if (type == sym_1("Integer"))
        return (f_init_copy) integer_init_copy;
      if (type == sym_1("List"))
        return (f_init_copy) list_init_copy;
      if (type == sym_1("Sw"))
        return (f_init_copy) sw_init_copy;
      if (type == sym_1("S64"))
        return (f_init_copy) s64_init_copy;
      if (type == sym_1("S32"))
        return (f_init_copy) s32_init_copy;
      if (type == sym_1("S16"))
        return (f_init_copy) s16_init_copy;
      if (type == sym_1("S8"))
        return (f_init_copy) s8_init_copy;
      if (type == sym_1("U8"))
        return (f_init_copy) u8_init_copy;
      if (type == sym_1("U16"))
        return (f_init_copy) u16_init_copy;
      if (type == sym_1("U32"))
        return (f_init_copy) u32_init_copy;
      if (type == sym_1("U64"))
        return (f_init_copy) u64_init_copy;
      if (type == sym_1("Uw"))
        return (f_init_copy) uw_init_copy;
      if (type == sym_1("Ptag"))
        return (f_init_copy) ptag_init_copy;
      if (type == sym_1("Quote"))
        return (f_init_copy) quote_init_copy;
      if (type == sym_1("Str"))
        return (f_init_copy) str_init_copy;
      if (type == sym_1("Sym"))
        return (f_init_copy) sym_init_copy;
      if (type == sym_1("Tuple"))
        return (f_init_copy) tuple_init_copy;
      if (type == sym_1("Var"))
        return (f_init_copy) var_init_copy;
      assert(! "array_type_to_init_copy: unknown type");
      errx(1, "array_type_to_init_copy: unknown type");
      return NULL;
    }
    
    e_tag_type array_type_to_tag_type (const s_sym *type)
    {
      if (type == sym_1("Bool"))
        return TAG_BOOL;
      if (type == sym_1("Call"))
        return TAG_CALL;
      if (type == sym_1("Cfn"))
        return TAG_CFN;
      if (type == sym_1("Character"))
        return TAG_CHARACTER;
      if (type == sym_1("F32"))
        return TAG_F32;
      if (type == sym_1("F64"))
        return TAG_F64;
      if (type == sym_1("Fact"))
        return TAG_FACT;
      if (type == sym_1("Fn"))
        return TAG_FN;
      if (type == sym_1("Ident"))
        return TAG_IDENT;
      if (type == sym_1("Integer"))
        return TAG_INTEGER;
      if (type == sym_1("Sw"))
        return TAG_SW;
      if (type == sym_1("S64"))
        return TAG_S64;
      if (type == sym_1("S32"))
        return TAG_S32;
      if (type == sym_1("S16"))
        return TAG_S16;
      if (type == sym_1("S8"))
        return TAG_S8;
      if (type == sym_1("U8"))
        return TAG_U8;
      if (type == sym_1("U16"))
        return TAG_U16;
      if (type == sym_1("U32"))
        return TAG_U32;
      if (type == sym_1("U64"))
        return TAG_U64;
      if (type == sym_1("Uw"))
        return TAG_UW;
      if (type == sym_1("List"))
        return TAG_LIST;
      if (type == sym_1("Ptag"))
        return TAG_PTAG;
      if (type == sym_1("Quote"))
        return TAG_QUOTE;
      if (type == sym_1("Str"))
        return TAG_STR;
      if (type == sym_1("Sym"))
        return TAG_SYM;
      if (type == sym_1("Tuple"))
        return TAG_TUPLE;
      if (type == sym_1("Var"))
        return TAG_VAR;
      assert(! "array_type_to_tag_type: invalid type");
      errx(1, "array_type_to_tag_type: invalid type: %s", type->str.ptr.ps8);
      return TAG_VOID;
    }