Commit 1abf15e30ef0e5ffbbace962054c0964dc4bbcb6

Thomas de Grivel 2023-12-10T23:48:01

wip struct

diff --git a/libc3/struct.c b/libc3/struct.c
index 920dc23..8c38abb 100644
--- a/libc3/struct.c
+++ b/libc3/struct.c
@@ -13,6 +13,7 @@
 #include <assert.h>
 #include <err.h>
 #include <stdlib.h>
+#include <string.h>
 #include "env.h"
 #include "map.h"
 #include "struct.h"
@@ -41,6 +42,52 @@ void struct_clean (s_struct *s)
   struct_type_clean(&s->type);
 }
 
+s_struct * struct_init_copy (s_struct *s, const s_struct *src)
+{
+  f_clean clean;
+  f_init_copy init_copy;
+  uw i = 0;
+  uw size;
+  const s_sym *sym;
+  s_struct tmp;
+  assert(s);
+  assert(src);
+  if (! struct_type_init_copy(&tmp.type, &src->type))
+    return NULL;
+  tmp.free = true;
+  tmp.data = calloc(1, tmp.type.size);
+  while (i < tmp.type.map.count) {
+    if (tag_type(tmp.type.map.value + i, &sym)) {
+      init_copy = sym_to_init_copy(sym);
+      if (init_copy) {
+        if (! init_copy((s8 *) tmp.data + tmp.type.offset[i],
+                        (s8 *) src->data + tmp.type.offset[i]))
+          goto ko;
+      }
+      else {
+        size = tag_size(tmp.type.map.value + i);
+        memcpy((s8 *) tmp.data + tmp.type.offset[i],
+               (s8 *) src->data + tmp.type.offset[i],
+               size);
+      }
+    }
+    i++;
+  }
+  *s = tmp;
+  return s;
+ ko:
+  while (i > 0) {
+    i--;
+    tag_type(tmp.type.map.value + i, &sym);
+    clean = sym_to_clean(sym);
+    if (clean)
+      clean((s8 *) tmp.data + tmp.type.offset[i]);
+  }
+  free(tmp.data);
+  struct_type_clean(&tmp.type);
+  return NULL;
+}
+
 void struct_delete (s_struct *s)
 {
   assert(s);
diff --git a/libc3/struct_type.c b/libc3/struct_type.c
index 9dcd4fe..2d828ba 100644
--- a/libc3/struct_type.c
+++ b/libc3/struct_type.c
@@ -13,12 +13,15 @@
 #include <assert.h>
 #include <err.h>
 #include <stdlib.h>
+#include <string.h>
 #include "env.h"
 #include "list.h"
 #include "map.h"
 #include "struct.h"
 #include "struct_type.h"
 #include "sym.h"
+#include "tag.h"
+#include "tag_init.h"
 #include "tag_type.h"
 
 void struct_type_clean (s_struct_type *st)
@@ -39,6 +42,10 @@ s_struct_type * struct_type_init (s_struct_type *st, const s_sym *module,
                                   const s_list *spec)
 {
   uw count;
+  uw i;
+  uw offset;
+  const s_list *s;
+  uw size;
   assert(st);
   assert(module);
   assert(spec);
@@ -52,9 +59,52 @@ s_struct_type * struct_type_init (s_struct_type *st, const s_sym *module,
     map_clean(&st->map);
     return NULL;
   }
+  offset = 0;
+  i = 0;
+  s = spec;
+  while (s) {
+    if (s->tag.type != TAG_TUPLE || s->tag.data.tuple.count != 2) {
+      warn("struct_type_init: invalid spec");
+      map_clean(&st->map);
+      free(st->offset);
+      return NULL;
+    }
+    tag_init_copy(st->map.key + i,   s->tag.data.tuple.tag + 0);
+    tag_init_copy(st->map.value + i, s->tag.data.tuple.tag + 1);
+    size = tag_size(st->map.value + i);
+    offset = struct_type_padding(offset, size);
+    st->offset[i] = offset;
+    offset += size;
+    s = list_next(s);
+  }
+  st->size = offset;
   return st;
 }
 
+s_struct_type * struct_type_init_copy (s_struct_type *s,
+                                       const s_struct_type *src)
+{
+  s_struct_type tmp;
+  assert(s);
+  assert(src);
+  assert(src->module);
+  assert(src->map.count);
+  tmp.module = src->module;
+  if (! map_init_copy(&tmp.map, &src->map))
+    return NULL;
+  tmp.offset = calloc(tmp.map.count, sizeof(uw));
+  if (! tmp.offset) {
+    warn("struct_type_init_copy: offset array of size %lu",
+         tmp.map.count);
+    map_clean(&tmp.map);
+    return NULL;
+  }
+  memcpy(tmp.offset, src->offset, tmp.map.count * sizeof(uw));
+  tmp.size = src->size;
+  *s = tmp;
+  return s;
+}
+
 s_struct_type * struct_type_init_from_env (s_struct_type *st,
                                            const s_sym *module,
                                            s_env *env)
@@ -87,3 +137,17 @@ s_struct_type * struct_type_new (const s_sym *module,
   }
   return st;
 }
+
+uw struct_type_padding (uw offset, uw size)
+{
+  unsigned int align = 1;
+  if (size == 2)
+    align = 2;
+  else if (size == 4)
+    align = 4;
+  else if (size == 8)
+    align = 8;
+  else if (size == 16)
+    align = 16;
+  return (offset + align - 1) / align * align;
+}
diff --git a/libc3/struct_type.h b/libc3/struct_type.h
index 81a84af..c7332cb 100644
--- a/libc3/struct_type.h
+++ b/libc3/struct_type.h
@@ -29,6 +29,8 @@
 void            struct_type_clean (s_struct_type *s);
 s_struct_type * struct_type_init (s_struct_type *s, const s_sym *module,
                                   const s_list *spec);
+s_struct_type * struct_type_init_copy (s_struct_type *s,
+                                       const s_struct_type *src);
 s_struct_type * struct_type_init_from_env (s_struct_type *st,
                                            const s_sym *module,
                                            s_env *env);
@@ -38,4 +40,7 @@ void            struct_type_delete (s_struct_type *s);
 s_struct_type * struct_type_new (const s_sym *module,
                                  const s_list *spec);
 
+/* Utility functions. */
+uw struct_type_padding (uw offset, uw size);
+
 #endif /* LIBC3_STRUCT_TYPE_H */
diff --git a/libc3/tag.c b/libc3/tag.c
index dc4ea3b..8cdf8c9 100644
--- a/libc3/tag.c
+++ b/libc3/tag.c
@@ -1083,6 +1083,14 @@ s_tag * tag_paren (const s_tag *tag, s_tag *dest)
   return tag_init_copy(dest, tag);
 }
 
+sw tag_size (const s_tag *tag)
+{
+  const s_sym *type;
+  assert(tag);
+  type = tag_type_to_sym(tag->type);
+  return sym_type_size(type);
+}
+
 /*
 s_tag * tag_s8 (s_tag *tag, s8 x)
 {
diff --git a/libc3/window/sdl2/demo/earth.c b/libc3/window/sdl2/demo/earth.c
index e396487..7b87b2d 100644
--- a/libc3/window/sdl2/demo/earth.c
+++ b/libc3/window/sdl2/demo/earth.c
@@ -104,6 +104,8 @@ bool earth_render (s_sequence *seq, s_window_sdl2 *window,
     sphere_radius = 5.0;
     glScalef(sphere_radius, sphere_radius, sphere_radius);
     glEnable(GL_TEXTURE_2D);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                    GL_LINEAR_MIPMAP_LINEAR);
     sdl2_sprite_bind(&g_sprite_earth, 0);
     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
     gl_sphere_render(sphere);