9 #ifndef __STRUCTDEFS_H__
10 #define __STRUCTDEFS_H__
21 #define debug_print(...) fprintf(stderr, __VA_ARGS__)
23 #define debug_print(...)
28 #define memerr_print(size, name, struct) fprintf(stderr, "WARNING: memory failure allocating " \
29 "%lu bytes for field %s in struct %s", \
32 #define memerr_print(a, b, c)
35 #ifndef SILENT_FAILURES
37 #define baderr_print(...) fprintf(stderr, __VA_ARGS__)
39 #define baderr_print(...)
43 #define ALLOW_UNUSED __attribute__((unused))
48 #define LSD_TEXTLEN 64
49 #define LSD_NAMELEN 16
50 #define LSD_MAX_ALLOC 65535
51 #define LIVES_STRUCT_ID 0x4C7C56332D2D3035
59 #ifndef OVERRIDE_MEMFUNCS
60 static void *(*_lsd_calloc)(
size_t nmemb,
size_t size) = calloc;
61 static void *(*_lsd_memcpy)(
void *dest,
const void *src,
size_t n) = memcpy;
62 static void *(*_lsd_memset)(
void *s,
int c,
size_t n) = memset;
63 static void (*_lsd_free)(
void *ptr) = free;
66 #ifndef OVERRIDE_STRFUNCS
67 static int(*_lsd_strcmp)(
const char *s1,
const char *s2) = strcmp;
68 static char *(*_lsd_strdup)(
const char *s) = strdup;
69 static void (*_lsd_string_free)(
void *ptr) = free;
72 #ifdef USE_POSIX_MEMALIGN
73 #ifndef _MEM_ALIGNMENT_
74 #define _MEM_ALIGNMENT_ 64 // or whatever power of 2
76 static int _lsd_calloc_aligned_(
void **memptr,
size_t nmemb,
size_t size) {
78 if (!ret && *memptr)(*_lsd_memset)(*memptr, 0, nmemb * size);
82 #ifndef OVERRIDE_CALLOC_ALIGNED
83 static int _lsd_calloc_aligned_(
void **memptr,
size_t nmemb,
size_t size) {
84 return !memptr ? 0 : (!(*memptr = (*_lsd_calloc)(nmemb, size))) ? ENOMEM : 0;
87 #define _MEM_ALIGNMENT_ 0 // irrelevant
90 static int (*_lsd_calloc_aligned)(
void **memptr,
size_t nmemb,
size_t size) =
94 static char *_lsd_proxy_strdup(
char *str) {
98 (*_lsd_calloc_aligned)((
void **)&ret, 1, i);
99 (*_lsd_memcpy)(ret, str, i);
108 #define LIVES_FIELD_FLAG_ALLOC_AND_COPY (1l << 0)
119 #define LIVES_FIELD_FLAG_ZERO_ON_COPY (1l << 1)
124 #define LIVES_FIELD_FLAG_FREE_ON_DELETE (1l << 16)
127 #define LIVES_FIELD_FLAG_FREE_ALL_ON_DELETE (1l << 17)
136 #define LIVES_FIELD_FLAG_IS_SUBSTRUCT (1l << 32)
141 #define LIVES_FIELD_FLAG_IS_NULLT_ARRAY (1l << 33)
171 #define LIVES_FIELD_CHARPTR (LIVES_FIELD_FLAG_ALLOC_AND_COPY | LIVES_FIELD_FLAG_FREE_ON_DELETE)
172 #define LIVES_FIELD_BLOB LIVES_FIELD_CHARPTR // with bytesize > 0
174 #define LIVES_FIELD_ARRAY (LIVES_FIELD_FLAG_IS_NULLT_ARRAY | LIVES_FIELD_FLAG_FREE_ON_DELETE)
176 #define LIVES_FIELD_PTR_ARRAY (LIVES_FIELD_ARRAY | LIVES_FIELD_FLAG_ALLOC_AND_COPY \
177 | LIVES_FIELD_FLAG_FREE_ALL_ON_DELETE)
181 #define LIVES_FIELD_TO_EMPTY_STRING (LIVES_FIELD_FLAG_ALLOC_AND_COPY | LIVES_FIELD_FLAG_ZERO_ON_COPY)
193 void *new_user_data);
197 void *copied_user_data);
206 const char *field_name,
void *ptr_to_field);
210 const char *field_name,
void *ptr_to_dst_field,
211 void *ptr_to_src_field);
221 const char *field_name,
void *ptr_to_field);
228 typedef struct _lives_special_field {
241 typedef struct _lives_struct_def {
275 #define SELF_STRUCT_TYPE "lives_struct_def_t"
319 size_t struct_size,
const char *last_field,
325 make_special_field(uint64_t flags,
void *sample_struct,
void *ptr_to_field,
326 const char *field_name,
size_t data_size,
403 #ifdef HAVE_GETENTROPY
404 #define _LSD_IGN_RET(a) ((void)((a) + 1))
405 #define LSD_RANDFUNC(ptr, size) _LSD_IGN_RET(getentropy(ptr, size))
407 error(
"LSD_RANDFUNC(ptr, size) must be defined");
411 static void _lsd_init_copy(
void *,
void *,
const char *,
const char *,
void *)
ALLOW_UNUSED;
412 static void _lsd_init_copy(
void *dst,
void *strct,
const char *strct_type,
const char *field_name,
413 void *ptr_to_field) {
416 if (!strcmp(field_name,
"identifier")) {
420 if (!strcmp(field_name,
"end_id")) {
421 *(uint64_t *)ptr_to_field =
426 if (!strcmp(field_name,
"top")) {
427 if (dst) *(
void **)ptr_to_field = dst;
428 else *(
void **)ptr_to_field = strct;
429 }
else if (!strcmp(field_name,
"unique_id")) {
431 }
else if (!strcmp(field_name,
"refcount")) {
432 *((
int *)ptr_to_field) = 1;
433 }
else if (!strcmp(field_name,
"generation")) {
434 (*(
int *)ptr_to_field)++;
439 static void _lsd_init_cb(
void *,
const char *,
const char *,
void *)
ALLOW_UNUSED;
440 static void _lsd_init_cb(
void *strct,
const char *strct_type,
const char *field_name,
441 void *ptr_to_field) {
442 _lsd_init_copy(NULL, strct, strct_type, field_name, ptr_to_field);
446 static void _lsd_copy_cb(
void *,
void *,
const char *,
const char *,
void *,
void *)
ALLOW_UNUSED;
447 static void _lsd_copy_cb(
void *dst,
void *src,
const char *strct_type,
const char *field_name,
448 void *dst_fld_ptr,
void *src_fld_ptr) {
449 _lsd_init_copy(dst, src, strct_type, field_name, dst_fld_ptr);
453 static void _lsd_delete_cb(
void *,
const char *,
const char *,
void *)
ALLOW_UNUSED;
454 static void _lsd_delete_cb(
void *strct,
const char *strct_type,
const char *field_name,
455 void *ptr_to_field) {
460 static int _lsd_generation_check_lt(
lives_struct_def_t *lsd,
int gen,
int show_error) {
465 baderr_print(
"Function was called with an lsd-in-struct, but we wanted static lsd\n");
469 static int _lsd_generation_check_gt(
lives_struct_def_t *lsd,
int gen,
int show_error) {
474 baderr_print(
"Function was called with a static lsd, but we wanted lsd-in-struct\n");
480 _lsd_make_special_field(uint64_t flags,
void *top,
void *ptr_to_field,
481 const char *name,
size_t data_size,
491 specf->flags = flags;
492 specf->offset_to_field = (off_t)((
char *)ptr_to_field - (
char *)top);
495 specf->bytesize = data_size;
496 specf->init_func = init_func;
497 specf->copy_func = copy_func;
498 specf->delete_func = delete_func;
502 static void *_lsd_get_field(
char *top,
int is_self_field,
505 debug_print(
"calculating offset: for %s number %d, %s, top is %p, ",
506 is_self_field ?
"self_field" :
"special_field", i,
507 spfields[i]->name, top);
511 spfields[0]->offset_to_field, top);
512 if (spfields[0]->bytesize) {
514 top = *((
char **)top);
515 debug_print(
"\nlsd is a pointer, real top is %p\n",
519 debug_print(
"adding field offset of %lu, final ptr is %p\n",
520 spfields[i]->offset_to_field, top + spfields[i]->offset_to_field);
526 static int _lsd_auto_delete(
void *ptr, uint64_t flags,
size_t bsize) {
534 void **vptr = *((
void ** *)ptr);
537 for (
int j = 0; vptr[j]; j++)
if (vptr[j])(*_lsd_string_free)(vptr[j]);
539 for (
int j = 0; vptr[j]; j++)
if (vptr[j])(*_lsd_free)(vptr[j]);
544 void *vptr = *((
void **)ptr);
549 (*_lsd_string_free)(vptr);
572 if (!(*_lsd_calloc_aligned)((
void **)dst_field, 1, bsize)) {
579 if (src_field != lsd && !(*((
void **)src_field))) {
582 if (!(*_lsd_calloc_aligned)((
void **)dst_field, 1, bsize)) {
583 (*_lsd_memcpy)(*(
void **)dst_field, src_field, bsize);
594 char **cptr = (
char **)dst_field;
598 *cptr = (*_lsd_strdup)(
"");
601 if ((*((
char **)src_field))) {
602 *cptr = (*_lsd_strdup)(*((
char **)src_field));
616 debug_print(
"WARNING: FREE_ALL_ON_DELETE is set\n");
623 (*_lsd_memset)(dst_field, 0, bsize);
626 *((
char **)dst_field) = NULL;
640 debug_print(
"WARNING: FREE_ALL_ON_DELETE is set\n");
650 char **cptr = (*(
char ** *)src_field), **dptr;
652 while (cptr[count]) count++;
653 if ((*_lsd_calloc_aligned)((
void **)&dptr, count + 1,
sizeof(
char *))) {
657 for (j = 0; j < count; j++) {
660 dptr[j] = (*_lsd_strdup)(
"");
663 dptr[j] = (*_lsd_strdup)(cptr[j]);
664 }
else dptr[j] = cptr[j];
668 (*(
char ** *)dst_field) = dptr;
675 debug_print(
"created %d empty strings (+ terminating NULL)\n", count);
678 debug_print(
"duplicated %d strings (+ terminating NULL)\n", count);
680 debug_print(
"copy-by-ref %d strings (+ terminating NULL)\n", count);
690 debug_print(
"WARNING: FREE_ALL_ON_DELETE is set\n");
694 debug_print(
"WARNING: FREE_ALL_ON_DELETE not set\n");
702 void **vptr = (*(
void ** *)src_field), **dptr;
705 while (vptr[count]) count++;
706 if ((*_lsd_calloc_aligned)((
void **)&dptr, count + 1,
sizeof(
void *))) {
710 for (j = 0; j < count; j++) {
712 if ((*_lsd_calloc_aligned)((
void **)&dptr[j], 1, bsize)) {
717 (*_lsd_memcpy)(dptr[j], vptr[j], bsize);
722 (*(
void **)dst_field) = dptr;
728 debug_print(
"created %d pointers to empty elements of size %lu "
729 "(+ terminating NULL)\n", count, bsize);
731 debug_print(
"duplicated %d pointers to elements of size %lu "
732 "(+ terminating NULL)\n",
740 debug_print(
"WARNING: FREE_ALL_ON_DELETE not set\n");
745 void *oldarea = *((
void **)src_field), *newarea;
748 for (count = 0;; count++) {
749 for (j = 0; j < bsize; j++)
if (ptr[j])
break;
750 if (j == bsize)
break;
754 if ((*_lsd_calloc_aligned)((
void **)&newarea, count, bsize)) {
758 (*_lsd_memcpy)(newarea, src_field, count * bsize);
759 *((
char **)dst_field) = (
char *)newarea;
765 debug_print(
"- copied %d values of size %ld (including final 0's)\n",
772 debug_print(
"WARNING: FREE_ALL_ON_DELETE is set\n");
782 uint64_t lsd_flags = 0;
784 void *src_field, *self_fields = NULL;
785 void *thestruct = NULL;
789 if (_lsd_generation_check_lt(lsd, 1, 0)) {
793 thestruct = lsd->
top;
801 for (
int i = 0; spfields[i]; i++) {
803 src_field = _lsd_get_field(thestruct, thestruct == lsd, spfields, i);
804 if (thestruct == lsd) {
807 lsd_flags = spcf->
flags;
811 spcf->
name, src_field);
815 spcf->
name, src_field);
819 for (
int i = 0; spfields[i]; i++) {
821 uint64_t flags = spcf->
flags;
822 src_field = _lsd_get_field(thestruct, spfields == lsd->
self_fields, spfields, i);
825 self_fields = src_field;
830 if (!flags)
continue;
836 _lsd_auto_delete(src_field, flags, spcf->
bytesize);
848 _lsd_auto_delete(self_fields, self_spcf->
flags, 1);
852 src_field = (
void *)lsd;
853 _lsd_auto_delete(src_field, lsd_flags, lsd_size);
856 if (thestruct)(*_lsd_free)(thestruct);
857 else (*_lsd_free)(lsd);
864 char *dst_field, *src_field;
870 if ((*_lsd_calloc_aligned)((
void **)&new_struct, 1, lsd->
structsize)) {
878 (*_lsd_memcpy)(new_struct, parent, lsd->
structsize);
885 debug_print(
"copying lives_struct_def_t fields first\n");
890 for (
int i = 0; spfields[i]; i++) {
893 if (!spcf->
flags)
continue;
896 dst_field = _lsd_get_field(new_struct, spfields == lsd->
self_fields, spfields, i);
898 debug_print(
"handling field %s with flags 0X%016lX\n",
904 debug_print(
"field is another substruct {TODO}\n");
910 size_t bytesize = spfields[0]->
bytesize;
916 src_field = _lsd_get_field((
char *)lsd, spfields == lsd->self_fields, spfields, i);
919 }
else src_field = _lsd_get_field(parent, spfields == lsd->
self_fields, spfields, i);
920 _lsd_auto_copy(dst_field, src_field, spcf, lsd);
928 for (
int i = 0; spfields[i]; i++) {
930 dst_field = _lsd_get_field(new_struct, spfields == lsd->
self_fields, spfields, i);
938 spcf->
name, dst_field, src_field);
945 spcf->
name, dst_field);
955 if (spfields)
goto recurse_callbacks;
958 if (spfields)
goto recurse_copy;
967 debug_print(
"triggering any struct callbacks\n\n");
974 dst_lsd = _lsd_get_field(new_struct, 1, lsd->
self_fields, 0);
984 if (!lsd || !thestruct || !lsd_in_structp)
return EINVAL;
992 lsd_in_structp,
"lsd",
995 spfields[0] = _lsd_make_special_field(0, thestruct, lsd_in_struct,
"lsd", 0, NULL, NULL, NULL);
1001 _lsd_struct_free(lsd);
1022 return !lsd ? 0ul : lsd->
end_id;
1047 return _lsd_make_special_field(flags, thestruct, ptr_to_field, name, data_size,
1048 init_func, copy_func, delete_func);
1058 baderr_print(
"Unable to free struct of type %s, lives_struct_init must be called first\n",
1078 return lives_struct_unref(lsd);
1082 if (!_lsd_generation_check_gt(lsd, 0, 1))
return NULL;
1083 return _lsd_struct_copy(lsd, NULL);
1093 return _lsd_struct_init(lsd, thestruct, lsd_in_struct, 1);
1101 return _lsd_struct_init(lsd, thestruct, &lsd_in_struct, 0);
1105 void *thestruct, *lsd_in_struct;
1109 if (!lsd)
return NULL;
1111 if (!spfields)
return NULL;
1113 baderr_print(
"Unable to create struct of type %s, lives_struct_init "
1114 "or lives_struct_init_p must be called first\n",
1119 if ((*_lsd_calloc_aligned)((
void **)&thestruct, 1, lsd->
structsize)) {
1124 if (!(spfields[0]->bytesize)) {
1125 lsd_in_struct = (
void *)((
char *)thestruct + offset);
1142 return lsd_unref(lsd);
1157 static const lives_struct_def_t *lsd_create(
const char *struct_type,
size_t struct_size,
1158 const char *last_field,
int nspecial) {
1168 snprintf(lsd->structtype,
LSD_TEXTLEN,
"%s", struct_type);
1170 lsd->structsize = struct_size;
1174 snprintf(lsd->last_field,
LSD_TEXTLEN,
"%s", last_field);
1177 if ((*_lsd_calloc_aligned)((
void **)&lsd->special_fields, nspecial + 1,
1183 lsd->special_fields[nspecial] = NULL;
1190 xspecf = lsd->self_fields;
1195 xspecf[1] = _lsd_make_special_field(0, lsd, &lsd->identifier,
"identifier", 0, _lsd_init_cb,
1198 xspecf[2] = _lsd_make_special_field(0, lsd, &lsd->unique_id,
"unique_id", 0,
1199 _lsd_init_cb, _lsd_copy_cb, NULL);
1201 xspecf[3] = _lsd_make_special_field(0, lsd, &lsd->refcount,
"refcount", 0,
1202 _lsd_init_cb, _lsd_copy_cb, NULL);
1204 xspecf[4] = _lsd_make_special_field(0, lsd, &lsd->generation,
"generation", 0,
1205 _lsd_init_cb, _lsd_copy_cb, NULL);
1207 xspecf[5] = _lsd_make_special_field(0, lsd, &lsd->top,
"top", 0, _lsd_init_cb, _lsd_copy_cb, NULL);
1211 &lsd->special_fields,
"special_fields",
1215 &lsd->self_fields,
"self_fields",
1220 &lsd->user_data,
"user_data", 8, NULL, NULL, NULL);
1222 xspecf[9] = _lsd_make_special_field(0, lsd, &lsd->end_id,
"end_id", 0, _lsd_init_cb,