Commit b25494f155a92cca1f0f462f8c4b49febd08e242

Thomas de Grivel 2023-09-20T15:09:54

fix arrays

diff --git a/libc3/array.c b/libc3/array.c
index 4a204e6..e12d7f6 100644
--- a/libc3/array.c
+++ b/libc3/array.c
@@ -71,7 +71,8 @@ s_array * array_copy (const s_array *src, s_array *dest)
   dest->size = src->size;
   dest->type = src->type;
   if (src->data) {
-    dest->data = calloc(1, src->size);
+    if (! (dest->data = calloc(1, src->size)))
+      errx(1, "array_copy: out of memory");
     memcpy(dest->data, src->data, dest->size);
   }
   else
@@ -190,6 +191,27 @@ s_array * array_init_1 (s_array *array, s8 *p)
   return array;
 }
 
+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"))
diff --git a/libc3/array.h b/libc3/array.h
index cf33a98..c91970b 100644
--- a/libc3/array.h
+++ b/libc3/array.h
@@ -20,6 +20,7 @@ s_array *          array_copy (const s_array *src, s_array *dest);
 s_array *          array_init (s_array *a, const s_sym *type,
                                uw dimension, const uw *dimensions);
 s_array *          array_init_1 (s_array *a, s8 *p);
+s_str *            array_inspect (const s_array *array, s_str *dest);
 void *             array_data (const s_array *a, const uw *address);
 s_tag *            array_data_tag (s_tag *a, const s_tag *address,
                                    s_tag *dest);
diff --git a/libc3/buf_inspect.c b/libc3/buf_inspect.c
index 3b0c24f..cff786a 100644
--- a/libc3/buf_inspect.c
+++ b/libc3/buf_inspect.c
@@ -28,12 +28,15 @@
 
 sw buf_inspect_array_data (s_buf *buf, const s_array *array);
 sw buf_inspect_array_data_rec (s_buf *buf, const s_array *array,
+                               const u8 **data, f_buf_inspect inspect,
                                const s_tag **tag, uw *address,
                                uw dimension);
 sw buf_inspect_array_data_size (const s_array *array);
 sw buf_inspect_array_data_size_rec (const s_array *array,
-                                    const s_tag **tag, uw *address,
-                                    uw dimension);
+                                    const u8 **data,
+                                    f_buf_inspect_size inspect_size,
+                                    const s_tag **tag,
+                                    uw *address, uw dimension);
 sw buf_inspect_tag_type (s_buf *buf, e_tag_type type);
 
 sw buf_inspect_array (s_buf *buf, const s_array *array)
@@ -61,19 +64,30 @@ sw buf_inspect_array (s_buf *buf, const s_array *array)
 sw buf_inspect_array_data (s_buf *buf, const s_array *array)
 {
   uw *address;
-  s_tag *tag;
+  u8 *data = NULL;
+  f_buf_inspect inspect = NULL;
+  s_tag *tag = NULL;
+  e_tag_type tag_type;
   sw r;
   assert(buf);
   assert(array);
   address = calloc(array->dimension, sizeof(uw));
-  tag = array->tags;
-  r = buf_inspect_array_data_rec(buf, array, (const s_tag **) &tag,
+  if (array->data) {
+    data = array->data;
+    tag_type = array_type_to_tag_type(array->type);
+    inspect = tag_type_to_buf_inspect(tag_type);
+  }
+  else 
+    tag = array->tags;
+  r = buf_inspect_array_data_rec(buf, array, (const u8 **) &data,
+                                 inspect, (const s_tag **) &tag,
                                  address, 0);
   free(address);
   return r;
 }
 
 sw buf_inspect_array_data_rec (s_buf *buf, const s_array *array,
+                               const u8 **data, f_buf_inspect inspect,
                                const s_tag **tag, uw *address,
                                uw dimension)
 {
@@ -85,13 +99,22 @@ sw buf_inspect_array_data_rec (s_buf *buf, const s_array *array,
   address[dimension] = 0;
   while (1) {
     if (dimension == array->dimension - 1) {
-      if ((r = buf_inspect_tag(buf, *tag)) <= 0)
-        goto clean;
-      result += r;
-      (*tag)++;
+      if (*data) {
+        if ((r = inspect(buf, *data)) <= 0)
+          goto clean;
+        result += r;
+        *data += array->dimensions[dimension].item_size;
+      }
+      else if (*tag) {
+        if ((r = buf_inspect_tag(buf, *tag)) <= 0)
+          goto clean;
+        result += r;
+        (*tag)++;
+      }
     }
     else {
-      if ((r = buf_inspect_array_data_rec(buf, array, tag, address,
+      if ((r = buf_inspect_array_data_rec(buf, array, data, inspect,
+                                          tag, address,
                                           dimension + 1)) <= 0)
         goto clean;
       result += r;
@@ -114,20 +137,33 @@ sw buf_inspect_array_data_rec (s_buf *buf, const s_array *array,
 sw buf_inspect_array_data_size (const s_array *array)
 {
   uw *address;
-  s_tag *tag;
+  u8 *data = NULL;
+  f_buf_inspect_size inspect_size = NULL;
+  s_tag *tag = NULL;
+  e_tag_type tag_type;
   sw r;
   assert(array);
   address = calloc(array->dimension, sizeof(uw));
-  tag = array->tags;
-  r = buf_inspect_array_data_size_rec(array, (const s_tag **) &tag,
+  if (array->data) {
+    data = array->data;
+    tag_type = array_type_to_tag_type(array->type);
+    inspect_size = tag_type_to_buf_inspect_size(tag_type);
+  }
+  else 
+    tag = array->tags;
+  r = buf_inspect_array_data_size_rec(array, (const u8 **) &data,
+                                      inspect_size,
+                                      (const s_tag **) &tag,
                                       address, 0);
   free(address);
   return r;
 }
 
 sw buf_inspect_array_data_size_rec (const s_array *array,
-                                    const s_tag **tag, uw *address,
-                                    uw dimension)
+                                    const u8 **data,
+                                    f_buf_inspect_size inspect_size,
+                                    const s_tag **tag,
+                                    uw *address, uw dimension)
 {
   sw r;
   sw result = 0;
@@ -136,13 +172,23 @@ sw buf_inspect_array_data_size_rec (const s_array *array,
   address[dimension] = 0;
   while (1) {
     if (dimension == array->dimension - 1) {
-      if ((r = buf_inspect_tag_size(*tag)) <= 0)
-        goto clean;
-      result += r;
-      (*tag)++;
+      if (*data) {
+        if ((r = inspect_size(*data)) <= 0)
+          goto clean;
+        result += r;
+        *data += array->dimensions[dimension].item_size;
+      }
+      else if (*tag) {
+        if ((r = buf_inspect_tag_size(*tag)) <= 0)
+          goto clean;
+        result += r;
+        (*tag)++;
+      }
     }
     else {
-      if ((r = buf_inspect_array_data_size_rec(array, tag, address,
+      if ((r = buf_inspect_array_data_size_rec(array, data,
+                                               inspect_size,
+                                               tag, address,
                                                dimension + 1)) <= 0)
         goto clean;
       result += r;
diff --git a/test/array_test.c b/test/array_test.c
index adf727b..b7c224d 100644
--- a/test/array_test.c
+++ b/test/array_test.c
@@ -12,6 +12,7 @@
  */
 #include <string.h>
 #include "../libc3/array.h"
+#include "../libc3/str.h"
 #include "../libc3/sym.h"
 #include "test.h"
 
@@ -29,16 +30,30 @@
     array_clean(&a);                                                   \
   } while(0)
 
+#define ARRAY_TEST_INSPECT(test, expected)                             \
+  do {                                                                 \
+    s_str str;                                                         \
+    s_array tmp;                                                       \
+    test_context("array_inspect(" # test ") -> " # expected);          \
+    TEST_EQ(array_init_1(&tmp, (test)), &tmp);                         \
+    TEST_EQ(array_inspect(&tmp, &str), &str);                          \
+    TEST_STRNCMP(str.ptr.p, (expected), str.size);                     \
+    array_clean(&tmp);                                                 \
+    str_clean(&str);						       \
+  } while(0)
+
 void array_test ();
 TEST_CASE_PROTOTYPE(array_data);
 TEST_CASE_PROTOTYPE(array_init_clean);
 TEST_CASE_PROTOTYPE(array_init_1_clean);
+TEST_CASE_PROTOTYPE(array_inspect);
 
 void array_test ()
 {
   TEST_CASE_RUN(array_init_clean);
   TEST_CASE_RUN(array_init_1_clean);
   TEST_CASE_RUN(array_data);
+  TEST_CASE_RUN(array_inspect);
 }
 
 TEST_CASE(array_data)
@@ -49,6 +64,11 @@ TEST_CASE(array_data)
   TEST_EQ(* (u8 *) array_data(&a, (uw []) {1}), 2);
   TEST_EQ(* (u8 *) array_data(&a, (uw []) {2}), 3);
   array_clean(&a);
+  TEST_EQ(array_init_1(&a, "(U8) {1 + 1, 2 + 2, 3 + 3}"), &a);
+  TEST_EQ(* (u8 *) array_data(&a, (uw []) {0}), 2);
+  TEST_EQ(* (u8 *) array_data(&a, (uw []) {1}), 4);
+  TEST_EQ(* (u8 *) array_data(&a, (uw []) {2}), 6);
+  array_clean(&a);
 }
 TEST_CASE_END(array_data)
 
@@ -77,3 +97,24 @@ TEST_CASE(array_init_1_clean)
   ARRAY_TEST_INIT_1_CLEAN("(U8) {{{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}}");
 }
 TEST_CASE_END(array_init_1_clean)
+
+TEST_CASE(array_inspect)
+{
+  ARRAY_TEST_INSPECT("(U8) {0}",
+                     "(U8) {0}");
+  ARRAY_TEST_INSPECT("(U8) {0, 0}",
+                     "(U8) {0, 0}");
+  ARRAY_TEST_INSPECT("(U8) {0, 0, 0}",
+                     "(U8) {0, 0, 0}");
+  ARRAY_TEST_INSPECT("(U8) {{0}, {0}}",
+                     "(U8) {{0}, {0}}");
+  ARRAY_TEST_INSPECT("(U8) {{0, 0}, {0, 0}}",
+                     "(U8) {{0, 0}, {0, 0}}");
+  ARRAY_TEST_INSPECT("(U8) {{0, 0}, {0, 0}, {0, 0}}",
+                     "(U8) {{0, 0}, {0, 0}, {0, 0}}");
+  ARRAY_TEST_INSPECT("(U8) {{{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}}",
+                     "(U8) {{{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}}");
+  ARRAY_TEST_INSPECT("(U8) {1, 2, 3}", "(U8) {1, 2, 3}");
+  ARRAY_TEST_INSPECT("(U8) {1 + 1, 2 + 2, 3 + 3}", "(U8) {2, 4, 6}");
+}
+TEST_CASE_END(array_inspect)