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);