LiVES  3.2.0
lsd.h
Go to the documentation of this file.
1 // LiVES - decoder plugin header
2 // (c) G. Finch 2008 - 2020 <salsaman+lives@gmail.com>
3 // released under the GNU GPL 3 or later
4 // see file COPYING or www.gnu.org for details
5 
6 // lsd.h :: implemntation of LiVES Struct Definition (LSD)
7 // functions for auto copy and auto free of structs
8 
9 #ifndef __STRUCTDEFS_H__
10 #define __STRUCTDEFS_H__
11 
12 #ifdef __cplusplus
13 extern "C"
14 {
15 #endif
16 
17 //#define DEBUG
18 
19 #ifdef DEBUG
20 #include <stdio.h>
21 #define debug_print(...) fprintf(stderr, __VA_ARGS__)
22 #else
23 #define debug_print(...)
24 #endif
25 
26 #ifndef SILENT_ENOMEM
27 #include <stdio.h>
28 #define memerr_print(size, name, struct) fprintf(stderr, "WARNING: memory failure allocating " \
29  "%lu bytes for field %s in struct %s", \
30  size, name, struct)
31 #else
32 #define memerr_print(a, b, c)
33 #endif
34 
35 #ifndef SILENT_FAILURES
36 #include <stdio.h>
37 #define baderr_print(...) fprintf(stderr, __VA_ARGS__)
38 #else
39 #define baderr_print(...)
40 #endif
41 
42 #if defined __GNUC__
43 #define ALLOW_UNUSED __attribute__((unused))
44 #else
45 #define ALLOW_UNUSED
46 #endif
47 
48 #define LSD_TEXTLEN 64
49 #define LSD_NAMELEN 16
50 #define LSD_MAX_ALLOC 65535
51 #define LIVES_STRUCT_ID 0x4C7C56332D2D3035
52 
53 #include <inttypes.h>
54 #include <string.h>
55 #include <stdlib.h>
56 #include <unistd.h>
57 #include <errno.h>
58 
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;
64 #endif
65 
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;
70 #endif
71 
72 #ifdef USE_POSIX_MEMALIGN
73 #ifndef _MEM_ALIGNMENT_
74 #define _MEM_ALIGNMENT_ 64 // or whatever power of 2
75 #endif
76 static int _lsd_calloc_aligned_(void **memptr, size_t nmemb, size_t size) {
77  int ret = posix_memalign(memptr, _MEM_ALIGNMENT_, nmemb * size);
78  if (!ret && *memptr)(*_lsd_memset)(*memptr, 0, nmemb * size);
79  return ret;
80 }
81 #else
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;
85 }
86 #endif
87 #define _MEM_ALIGNMENT_ 0 // irrelevant
88 #endif
89 
90 static int (*_lsd_calloc_aligned)(void **memptr, size_t nmemb, size_t size) =
91  _lsd_calloc_aligned_;
92 
93 static char *_lsd_proxy_strdup(char *str) ALLOW_UNUSED;
94 static char *_lsd_proxy_strdup(char *str) {
95  char *ret;
96  int i = 0;
97  while (str[i++]);
98  (*_lsd_calloc_aligned)((void **)&ret, 1, i);
99  (*_lsd_memcpy)(ret, str, i);
100  return ret;
101 }
102 
104 
108 #define LIVES_FIELD_FLAG_ALLOC_AND_COPY (1l << 0)
109 
119 #define LIVES_FIELD_FLAG_ZERO_ON_COPY (1l << 1)
120 
121 // delete flags
124 #define LIVES_FIELD_FLAG_FREE_ON_DELETE (1l << 16)
125 
127 #define LIVES_FIELD_FLAG_FREE_ALL_ON_DELETE (1l << 17)
128 
129 
136 #define LIVES_FIELD_FLAG_IS_SUBSTRUCT (1l << 32)
137 
141 #define LIVES_FIELD_FLAG_IS_NULLT_ARRAY (1l << 33)
142 
143 // combinations:
144 // Z : bytesize == 0 :: set any * to NULL
145 // Z : bytesize > 0 :: memset(bytesize, 0)
146 
147 // A&C : bytesize == 0 :: strdup
148 // A&C : bytesize > 0 :: malloc(bytesize), memcpy(bytesize)
149 // FREE_ON_DELETE recommended (LIVES_FIELD_IS_CHARPTR, LIVES_FIELD_IS_BLOB)
150 
151 // A&C | Z : bytesize == 0 :: strdup("") (LIVES_FIELD_TO_EMPTY_STRING)
152 // A&C | Z : bytesize > 0 :: malloc(bytesize), memset(bytesize, 0)
153 // FREE_ON_DELETE recommended
154 
155 // NULLT : bytesize == 0 :: copy string array (strings still point to original strings)
156 // NULLT : bytesize > 0 :: copy array of elements of size bytesize
157 // FREE_ON_DELETE recommended (LIVES_FIELD_IS_ARRAY)
158 // setting FREE_ALL_ON_DELETE may be dangerous, as it would free the original values !
159 
160 // NULLT + Z : interpreted as NULLT + ACC + Z,
161 // otherwise it would imply copying by reference, then ovewriting memory with 0
162 
163 // NULLT + A&C : bytesize == 0 :: strdup, multiple strings
164 // NULLT + A&C : bytesize > 0 :: copy array of pointers to elements of size bytesize
165 // FREE_ON_DELETE | FREE_ALL_ON_DELETE recommended (LIVES_FIELD_IS_
166 
167 // NULLT + A&C + Z : bytesize == 0 :: creates an equivalent number of empty strings
168 // NULLT + A&C + Z : bytesize > 0 :: malloc(bytesize), memset(bytesize, 0), multiple elements
169 // FREE_ON_DELETE | FREE_ALL_ON_DELETE recommended
170 
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
173 
174 #define LIVES_FIELD_ARRAY (LIVES_FIELD_FLAG_IS_NULLT_ARRAY | LIVES_FIELD_FLAG_FREE_ON_DELETE)
175 
176 #define LIVES_FIELD_PTR_ARRAY (LIVES_FIELD_ARRAY | LIVES_FIELD_FLAG_ALLOC_AND_COPY \
177  | LIVES_FIELD_FLAG_FREE_ALL_ON_DELETE)
178 
179 // with a bytesize of zero this will cause a string to be set to "" on copy
180 // without the ALLOC_AND_COPY, the string would be set to NULL
181 #define LIVES_FIELD_TO_EMPTY_STRING (LIVES_FIELD_FLAG_ALLOC_AND_COPY | LIVES_FIELD_FLAG_ZERO_ON_COPY)
182 
183 // forward decl
184 
185 typedef struct _lives_struct_def lives_struct_def_t;
186 
187 // CALLBACK FUNCTION TYPEDEFS
188 
189 // struct callbacks
190 
191 // this is called from lives_struct_new after all fields have been initialised via init_cbunc
192 typedef void (*lives_struct_new_cb)(void *strct, void *parent, const char *strct_type,
193  void *new_user_data);
194 
195 // this is called from lives_struct_copy after a copy is made
196 typedef void (*lives_struct_copied_cb)(void *strct, void *child, const char *strct_type,
197  void *copied_user_data);
198 
199 // this is called from lives_struct_free before any fields are freed or delete_func called
200 typedef void (*lives_struct_destroy_cb)(void *strct, const char *strct_type, void *delete_user_data);
201 
202 // field callbacks
203 
204 //called from lives_struct_new
205 typedef void (*lives_field_init_cb)(void *strct, const char *struct_type,
206  const char *field_name, void *ptr_to_field);
207 
208 // this is called from lives_struct_copy after all automatic updates are performed
209 typedef void (*lives_field_copy_cb)(void *dst_struct, void *src_struct, const char *strct_type,
210  const char *field_name, void *ptr_to_dst_field,
211  void *ptr_to_src_field);
212 // e,g, using field names:
213 // strct_type *d = (strct_type *)dst_struct;
214 // strct_type *s = (strct_type *)src_struct;
218 
219 //called from lives_struct_free before any fields are finalised
220 typedef void (*lives_field_delete_cb)(void *strct, const char *struct_type,
221  const char *field_name, void *ptr_to_field);
222 // e,g
223 // strct_type *mystruct = (strct_type *)strct;
224 // free(mystryct->(field_name));
225 
226 // STRUCTS
227 
228 typedef struct _lives_special_field {
230  //(and optionally offset_to_field)
231  uint64_t flags;
234  char name[LSD_NAMELEN];
235  size_t bytesize;
240 
241 typedef struct _lives_struct_def {
242  uint64_t identifier;
243  uint64_t unique_id;
244 
245  int32_t refcount;
246  uint32_t generation;
247 
248  void *top;
249 
250  char structtype[LSD_TEXTLEN];
251  size_t structsize;
252  char last_field[LSD_TEXTLEN];
253 
256 
259 
262 
265 
266  void *class_data;
267  void *user_data;
268  uint64_t end_id;
270 
271 // it is also possible to create a static struct_def, in which case the following is true
272 // unique_id is 0, top is NULL, refcount is 0, generation is 0,
273 // a static version may be copied to struct_def for a struct, this is like a normal copy
274 
275 #define SELF_STRUCT_TYPE "lives_struct_def_t"
276 
278 
279 
299 
302 
303 static int lsd_free(const lives_struct_def_t *) ALLOW_UNUSED;
304 static int lsd_unref(const lives_struct_def_t *) ALLOW_UNUSED;
305 static int lsd_ref(const lives_struct_def_t *) ALLOW_UNUSED;
306 static int lsd_get_refcount(const lives_struct_def_t *) ALLOW_UNUSED;
307 
308 // returns 1 if both struct defs have same identifier, end_id, structtype,
309 // structsize, last_field, class_data (i.e one is copy / instance of another)
310 // (lives_struct_get_generation can provide more information)
311 static int lsd_same_family(const lives_struct_def_t *lsd1, lives_struct_def_t *lsd2) ALLOW_UNUSED;
312 
313 // sets class data which will be copied to all instances from template
314 // and from instance to copies.
315 static void lives_struct_set_class_data(lives_struct_def_t *, void *class_data) ALLOW_UNUSED;
316 static void *lives_struct_get_class_data(lives_struct_def_t *) ALLOW_UNUSED;
317 
318 static const lives_struct_def_t *lsd_create(const char *struct_type,
319  size_t struct_size, const char *last_field,
320  int nspecial) ALLOW_UNUSED;
321 
322 // function to define special fields, array elements returned from make_structdef
323 // should be assigned via this function
324 static lives_special_field_t *
325 make_special_field(uint64_t flags, void *sample_struct, void *ptr_to_field,
326  const char *field_name, size_t data_size,
327  lives_field_init_cb init_func, lives_field_copy_cb copy_func,
328  lives_field_delete_cb delete_func) ALLOW_UNUSED;
329 
330 // Finishes the initialisation of the lsd template (passed as the first parameter)
331 // a sample instance of the struct should be created (using malloc / calloc, etc)
332 // and passed as the second parameter. The sample should be freed afterwards using normal free.
333 // All subsequent instances must be created with lives_struct_create or lives_struct_copy.
334 // The function returns 0 on success, EINVAL if a paramter is invalid.
335 // this version should be used when sruct has a field with type (lives_struct_def_t)
336 static int lives_struct_init(const lives_struct_def_t *, void *thestruct,
338 
339 // as above - this version should be used when lsd is of type (lives_struct_def_t *)
340 static int lives_struct_init_p(const lives_struct_def_t *, void *thestruct,
342 
344 // or it can be lsd from inside another struct (cast to const)
345 static void *lives_struct_create(const lives_struct_def_t *) ALLOW_UNUSED;
346 
347 // allocates and returns a copy of struct, calls copy_funcs, fills in lives_struct_def for copy
348 // lsd must be within a struct, not a static template
349 static void *lives_struct_copy(lives_struct_def_t *) ALLOW_UNUSED;
350 
351 // just calls lives_struct_unref
352 static int lives_struct_free(lives_struct_def_t *) ALLOW_UNUSED;
353 
354 // decrements refcount, then if <=0 frees struct. Returns refcount (so value <=0 means struct freed)
355 // returns -1 if parameter is NULL
356 static int lives_struct_unref(lives_struct_def_t *) ALLOW_UNUSED;
357 
358 // increments refcount, returns new value. Returns 0 if paramter is NULL
359 static int lives_struct_ref(lives_struct_def_t *) ALLOW_UNUSED;
360 
361 // returns current refcount, or 0 if NULL is passed
362 static int lives_struct_get_refcount(lives_struct_def_t *) ALLOW_UNUSED;
363 
364 // set user data for an instance, reset for copies
365 static void lives_struct_set_user_data(lives_struct_def_t *, void *data) ALLOW_UNUSED;
366 static void *lives_struct_get_user_data(lives_struct_def_t *) ALLOW_UNUSED;
367 
368 // returns generation number, 0 for a template, 1 for instance created via lives_struct_new,
369 // 2 for copy of instance, 3 for copy of copy, etc
370 static int lives_struct_get_generation(lives_struct_def_t *) ALLOW_UNUSED;
371 
372 static uint64_t lives_struct_get_uid(lives_struct_def_t *) ALLOW_UNUSED;
373 
374 static const char *lives_struct_get_type(lives_struct_def_t *) ALLOW_UNUSED;
375 
376 static const char *lives_struct_get_last_field(lives_struct_def_t *) ALLOW_UNUSED;
377 
378 static uint64_t lives_struct_get_identifier(lives_struct_def_t *) ALLOW_UNUSED;
379 
380 static uint64_t lives_struct_get_end_id(lives_struct_def_t *) ALLOW_UNUSED;
381 
382 static size_t lives_struct_get_size(lives_struct_def_t *) ALLOW_UNUSED;
383 
384 /*
385  // set init_callback for a struct or instance, passed on to copies
386  // called after instance is made via lives_struct_new or lives_struct_copy
387  // parent struct is NULL for lives_struct_new
388  static void lives_struct_set_new_callback(lives_struct_def_t *, void *new_user_data) ALLOW_UNUSED; // TODO
389 
390  // set copied callback for a struct or instance, passed on to copies
391  // called when copy is made of an instance
392  static void lives_struct_set_copied_callback(lives_struct_def_t *, void *copied_user_data) ALLOW_UNUSED; // TODO
393 
394  // set destroy callback for a struct or instance, passed on to copies
395  // called when instance is about to be destroyed
396  static void lives_struct_set_destroy_callback(lives_struct_def_t *, void *destroy_user_data) ALLOW_UNUSED; // TODO
397 */
398 
399 
401 
402 #ifndef LSD_RANDFUNC
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))
406 #else
407 error("LSD_RANDFUNC(ptr, size) must be defined");
408 #endif
409 #endif
410 
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) {
414  if (!dst) {
416  if (!strcmp(field_name, "identifier")) {
417  *(uint64_t *)ptr_to_field = LIVES_STRUCT_ID;
418  return;
419  }
420  if (!strcmp(field_name, "end_id")) {
421  *(uint64_t *)ptr_to_field =
422  (LIVES_STRUCT_ID ^ 0xFFFFFFFFFFFFFFFF);
423  return;
424  }
425  }
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")) {
430  LSD_RANDFUNC(ptr_to_field, 8);
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)++;
435  }
436 }
437 
438 // builtin init_cb
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);
443 }
444 
445 // builtin copy cb
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);
450 }
451 
452 // builtin delete_cb
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) {
456  // nothing
457 }
458 
459 // other internal funcs
460 static int _lsd_generation_check_lt(lives_struct_def_t *lsd, int gen, int show_error) {
462  if (lsd) {
463  if (lsd->generation < gen) return 1;
464  if (show_error)
465  baderr_print("Function was called with an lsd-in-struct, but we wanted static lsd\n");
466  }
467  return 0;
468 }
469 static int _lsd_generation_check_gt(lives_struct_def_t *lsd, int gen, int show_error) {
471  if (lsd) {
472  if (lsd->generation > gen) return 1;
473  if (show_error)
474  baderr_print("Function was called with a static lsd, but we wanted lsd-in-struct\n");
475  }
476  return 0;
477 }
478 
479 static lives_special_field_t *
480 _lsd_make_special_field(uint64_t flags, void *top, void *ptr_to_field,
481  const char *name, size_t data_size,
482  lives_field_init_cb init_func,
483  lives_field_copy_cb copy_func,
484  lives_field_delete_cb delete_func) {
485  lives_special_field_t *specf;
486 
487  if ((*_lsd_calloc_aligned)((void **)&specf, 1, sizeof(lives_special_field_t))) {
488  memerr_print(sizeof(lives_special_field_t), name, "?????");
489  return NULL;
490  }
491  specf->flags = flags;
492  specf->offset_to_field = (off_t)((char *)ptr_to_field - (char *)top);
493  if (name)
494  snprintf(specf->name, LSD_NAMELEN, "%s", name);
495  specf->bytesize = data_size;
496  specf->init_func = init_func;
497  specf->copy_func = copy_func;
498  specf->delete_func = delete_func;
499  return specf;
500 }
501 
502 static void *_lsd_get_field(char *top, int is_self_field,
503  lives_special_field_t **spfields, int i) {
504  // fo init / copy top is new_struct or parent, for delete, top is lsd->top
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);
508  if (is_self_field) {
509  top += spfields[0]->offset_to_field;
510  debug_print("lsd field is at offset %lu, %p\n",
511  spfields[0]->offset_to_field, top);
512  if (spfields[0]->bytesize) {
513  if (!i) return top;
514  top = *((char **)top);
515  debug_print("\nlsd is a pointer, real top is %p\n",
516  top);
517  }
518  }
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);
521  return top + spfields[i]->offset_to_field;
522 }
523 
524 // auto (flagbit) handlers
525 
526 static int _lsd_auto_delete(void *ptr, uint64_t flags, size_t bsize) {
528  if (!(flags & LIVES_FIELD_FLAG_IS_NULLT_ARRAY)) {
531  }
532  }
534  void **vptr = *((void ** *)ptr);
535  if (vptr) {
536  if ((flags & LIVES_FIELD_FLAG_ALLOC_AND_COPY) && !bsize) {
537  for (int j = 0; vptr[j]; j++) if (vptr[j])(*_lsd_string_free)(vptr[j]);
538  } else {
539  for (int j = 0; vptr[j]; j++) if (vptr[j])(*_lsd_free)(vptr[j]);
540  }
541  }
542  }
543  if (flags & LIVES_FIELD_FLAG_FREE_ON_DELETE) {
544  void *vptr = *((void **)ptr);
545  if (vptr) {
546  if ((flags & LIVES_FIELD_FLAG_ALLOC_AND_COPY) && !bsize
547  && !(flags & LIVES_FIELD_FLAG_FREE_ALL_ON_DELETE)) {
548  //g_print("flags !!! %lu %lu\n", flags, sizee);
549  (*_lsd_string_free)(vptr);
550  } else {
551  //g_print("flags %lu %lu\n", flags, sizee);
552  (*_lsd_free)(vptr);
553  }
554  }
555  }
556  return 0;
557 }
558 
559 static void _lsd_auto_copy(void *dst_field, void *src_field, lives_special_field_t *spcf,
560  lives_struct_def_t *lsd) {
561  size_t bsize = spcf->bytesize;
562  int j;
563  if (!(spcf->flags & LIVES_FIELD_FLAG_IS_NULLT_ARRAY)) {
565  if (bsize) {
566  if (bsize > LSD_MAX_ALLOC) {
567  debug_print("error: memory request too large (%lu > %lu)\n", bsize, LSD_MAX_ALLOC);
568  return;
569  } else {
570  debug_print("allocating %lu bytes...", bsize);
571  if (spcf->flags & LIVES_FIELD_FLAG_ZERO_ON_COPY) {
572  if (!(*_lsd_calloc_aligned)((void **)dst_field, 1, bsize)) {
573  debug_print("and set to zero.\n");
574  } else {
575  memerr_print(bsize, spcf->name, lsd->structtype);
576  }
577  return;
578  } else {
579  if (src_field != lsd && !(*((void **)src_field))) {
580  debug_print("value is NULL, not copying\n");
581  } else {
582  if (!(*_lsd_calloc_aligned)((void **)dst_field, 1, bsize)) {
583  (*_lsd_memcpy)(*(void **)dst_field, src_field, bsize);
584  debug_print("and copying from src to dest.\n");
585  } else {
586  memerr_print(bsize, spcf->name, lsd->structtype);
587  return;
588  }
589  // *INDENT-OFF*
590  }}}
591  // *INDENT-ON*
592  } else {
593  // strings
594  char **cptr = (char **)dst_field;
595  if (spcf->flags & LIVES_FIELD_FLAG_ZERO_ON_COPY) {
596  // set the string to an empty string
597  // without ALLOC_AND_COPY we set it to NULL instead
598  *cptr = (*_lsd_strdup)("");
599  debug_print("string was set to \"\"\n");
600  } else {
601  if ((*((char **)src_field))) {
602  *cptr = (*_lsd_strdup)(*((char **)src_field));
603  debug_print("did a strdup from src to dest\n");
604 #ifdef SHOW_TEXT
605  debug_print("%s\n", *cptr);
606 #endif
607  } else {
608  debug_print("value is NULL, not copying\n");
609  }
610  }
611  }
612  if (!(spcf->flags & LIVES_FIELD_FLAG_FREE_ON_DELETE)) {
613  debug_print("WARNING: FREE_ON_DELETE not set\n");
614  }
616  debug_print("WARNING: FREE_ALL_ON_DELETE is set\n");
617  }
618  return;
619  }
620  // non-alloc
621  if (spcf->flags & LIVES_FIELD_FLAG_ZERO_ON_COPY) {
622  if (bsize) {
623  (*_lsd_memset)(dst_field, 0, bsize);
624  debug_print("zeroed %lu bytes\n", bsize);
625  } else {
626  *((char **)dst_field) = NULL;
627  debug_print("set string to NULL\n");
628  }
629  }
630  if ((spcf->flags & LIVES_FIELD_FLAG_ZERO_ON_COPY) && !bsize) {
631  if (!(spcf->flags & LIVES_FIELD_FLAG_FREE_ON_DELETE)) {
632  debug_print("WARNING: FREE_ON_DELETE not set\n");
633  }
634  } else {
636  debug_print("WARNING: FREE_ON_DELETE is set\n");
637  }
638  }
640  debug_print("WARNING: FREE_ALL_ON_DELETE is set\n");
641  }
642  return;
643  }
645  int count = 0;
646  debug_print("handling array...");
647  // copy / create n elements or strings
648  if (!bsize) {
649  // copy N strings or create empty strings, source field is char **
650  char **cptr = (*(char ** *)src_field), **dptr;
651  if (cptr) {
652  while (cptr[count]) count++;
653  if ((*_lsd_calloc_aligned)((void **)&dptr, count + 1, sizeof(char *))) {
654  memerr_print(bsize, spcf->name, lsd->structtype);
655  return;
656  }
657  for (j = 0; j < count; j++) {
658  // flags tells us what to with each element
659  if (spcf->flags & LIVES_FIELD_FLAG_ZERO_ON_COPY) {
660  dptr[j] = (*_lsd_strdup)("");
661  } else {
663  dptr[j] = (*_lsd_strdup)(cptr[j]);
664  } else dptr[j] = cptr[j];
665  }
666  }
667  dptr[j] = NULL;
668  (*(char ** *)dst_field) = dptr;
669  }
670 
671  if (!cptr) {
672  debug_print("value is NULL, not copying\n");
673  } else {
674  if (spcf->flags & LIVES_FIELD_FLAG_ZERO_ON_COPY) {
675  debug_print("created %d empty strings (+ terminating NULL)\n", count);
676  } else {
678  debug_print("duplicated %d strings (+ terminating NULL)\n", count);
679  } else {
680  debug_print("copy-by-ref %d strings (+ terminating NULL)\n", count);
681  }
682  }
683  }
684  if (!(spcf->flags & LIVES_FIELD_FLAG_FREE_ON_DELETE)) {
685  debug_print("WARNING: FREE_ON_DELETE not set\n");
686  }
687  if (!(spcf->flags & LIVES_FIELD_FLAG_ALLOC_AND_COPY) &&
690  debug_print("WARNING: FREE_ALL_ON_DELETE is set\n");
691  }
692  } else {
694  debug_print("WARNING: FREE_ALL_ON_DELETE not set\n");
695  }
696  }
697  return;
698  } else {
702  void **vptr = (*(void ** *)src_field), **dptr;
703  if (vptr) {
704  count = 0;
705  while (vptr[count]) count++;
706  if ((*_lsd_calloc_aligned)((void **)&dptr, count + 1, sizeof(void *))) {
707  memerr_print((count + 1) * sizeof(void *), spcf->name, lsd->structtype);
708  return;
709  }
710  for (j = 0; j < count; j++) {
711  // flags tells us what to with each element
712  if ((*_lsd_calloc_aligned)((void **)&dptr[j], 1, bsize)) {
713  memerr_print(bsize, spcf->name, lsd->structtype);
714  return;
715  } else {
716  if (!(spcf->flags & LIVES_FIELD_FLAG_ZERO_ON_COPY)) {
717  (*_lsd_memcpy)(dptr[j], vptr[j], bsize);
718  }
719  }
720  }
721  dptr[j] = NULL;
722  (*(void **)dst_field) = dptr;
723  }
724  if (!vptr) {
725  debug_print("value is NULL, not copying\n");
726  } else {
727  if (spcf->flags & LIVES_FIELD_FLAG_ZERO_ON_COPY) {
728  debug_print("created %d pointers to empty elements of size %lu "
729  "(+ terminating NULL)\n", count, bsize);
730  } else {
731  debug_print("duplicated %d pointers to elements of size %lu "
732  "(+ terminating NULL)\n",
733  count, bsize);
734  }
735  }
736  if (!(spcf->flags & LIVES_FIELD_FLAG_FREE_ON_DELETE)) {
737  debug_print("WARNING: FREE_ON_DELETE not set\n");
738  }
740  debug_print("WARNING: FREE_ALL_ON_DELETE not set\n");
741  }
742  } else {
743  // simple array of bsize elements
744  // copy up to and including an element with all 0's
745  void *oldarea = *((void **)src_field), *newarea;
746  char *ptr = oldarea;
747  if (ptr) {
748  for (count = 0;; count++) {
749  for (j = 0; j < bsize; j++) if (ptr[j]) break;
750  if (j == bsize) break;
751  ptr += bsize;
752  }
753  count++;
754  if ((*_lsd_calloc_aligned)((void **)&newarea, count, bsize)) {
755  memerr_print(bsize, spcf->name, lsd->structtype);
756  return;
757  } else {
758  (*_lsd_memcpy)(newarea, src_field, count * bsize);
759  *((char **)dst_field) = (char *)newarea;
760  }
761  }
762  if (!ptr) {
763  debug_print("value is NULL, not copying\n");
764  } else {
765  debug_print("- copied %d values of size %ld (including final 0's)\n",
766  count, bsize);
767  }
768  if (!(spcf->flags & LIVES_FIELD_FLAG_FREE_ON_DELETE)) {
769  debug_print("WARNING: FREE_ON_DELETE not set\n");
770  }
772  debug_print("WARNING: FREE_ALL_ON_DELETE is set\n");
773  }
774  // *INDENT-OFF*
775  }}}
776  // *INDENT-ON*
777 }
778 
779 static void _lsd_struct_free(lives_struct_def_t *) ALLOW_UNUSED;
780 static void _lsd_struct_free(lives_struct_def_t *lsd) {
781  lives_special_field_t **spfields, *self_spcf = NULL;
782  uint64_t lsd_flags = 0;
783  size_t lsd_size = 0;
784  void *src_field, *self_fields = NULL;
785  void *thestruct = NULL;
786 
787  if (!lsd) return;
788 
789  if (_lsd_generation_check_lt(lsd, 1, 0)) {
790  thestruct = lsd;
791  spfields = lsd->self_fields;
792  } else {
793  thestruct = lsd->top;
794  if (lsd->destroy_struct_callback)
795  (*lsd->destroy_struct_callback)(thestruct, lsd->structtype, lsd->destroy_user_data);
796  spfields = lsd->special_fields;
797  }
798 
799 recurse_free:
800  if (spfields) {
801  for (int i = 0; spfields[i]; i++) {
802  lives_special_field_t *spcf = spfields[i];
803  src_field = _lsd_get_field(thestruct, thestruct == lsd, spfields, i);
804  if (thestruct == lsd) {
805  if (!i) {
806  lsd_size = spcf->bytesize;
807  lsd_flags = spcf->flags;
808  }
809  if (spcf->delete_func)
810  (*spcf->delete_func)(lsd->top, SELF_STRUCT_TYPE,
811  spcf->name, src_field);
812  } else {
813  if (spcf->delete_func)
814  (*spcf->delete_func)(lsd->top, lsd->structtype,
815  spcf->name, src_field);
816  }
817  }
818 
819  for (int i = 0; spfields[i]; i++) {
820  lives_special_field_t *spcf = spfields[i];
821  uint64_t flags = spcf->flags;
822  src_field = _lsd_get_field(thestruct, spfields == lsd->self_fields, spfields, i);
823  if (src_field == &lsd->self_fields) {
825  self_fields = src_field;
826  self_spcf = spcf;
827  continue;
828  }
829 
830  if (!flags) continue;
831  if (flags & LIVES_FIELD_FLAG_IS_SUBSTRUCT) {
834  continue;
835  }
836  _lsd_auto_delete(src_field, flags, spcf->bytesize);
837  }
838  }
839 
840  // after freeing the struct fields we free the lives_struct_def_t itself
841  // this is done using the values contained in selfdata
842  if (spfields == lsd->special_fields) {
843  spfields = lsd->self_fields;
844  goto recurse_free;
845  }
846 
847  if (self_fields) {
848  _lsd_auto_delete(self_fields, self_spcf->flags, 1);
849  }
850 
851  if (lsd_flags) {
852  src_field = (void *)lsd;
853  _lsd_auto_delete(src_field, lsd_flags, lsd_size);
854  }
855 
856  if (thestruct)(*_lsd_free)(thestruct);
857  else (*_lsd_free)(lsd);
858 }
859 
860 static void *_lsd_struct_copy(lives_struct_def_t *lsd, void *new_struct) {
861  lives_special_field_t **spfields;
862  lives_struct_def_t *dst_lsd;
863  void *parent = NULL;
864  char *dst_field, *src_field;
865 
866  spfields = lsd->self_fields;
867 
868  if (!new_struct) {
869  // copy
870  if ((*_lsd_calloc_aligned)((void **)&new_struct, 1, lsd->structsize)) {
871  memerr_print(lsd->structsize, "ALL FIELDS", lsd->structtype);
872  return NULL;
873  }
874  debug_print("copying struct of type: %s, %p -> %p, with size %lu\n", lsd->structtype,
875  parent, new_struct,
876  lsd->structsize);
877  parent = lsd->top;
878  (*_lsd_memcpy)(new_struct, parent, lsd->structsize);
879  } else {
880  debug_print("initing struct %p of type: %s\n", new_struct, lsd->structtype);
881  }
882 
883  // copy self_fields first:
884 
885  debug_print("copying lives_struct_def_t fields first\n");
886 
887 recurse_copy:
888 
889  if (spfields) {
890  for (int i = 0; spfields[i]; i++) {
891  lives_special_field_t *spcf = spfields[i];
892 
893  if (!spcf->flags) continue;
894  if (i > 1) debug_print("field done\n\n");
895 
896  dst_field = _lsd_get_field(new_struct, spfields == lsd->self_fields, spfields, i);
897 
898  debug_print("handling field %s with flags 0X%016lX\n",
899  spcf->name, spcf->flags);
900 
901  if (spcf->flags & LIVES_FIELD_FLAG_IS_SUBSTRUCT) {
902  // otherwise we descend into the substruct and locate its lives_struct_def *
903  // TODO...
904  debug_print("field is another substruct {TODO}\n");
905  continue;
906  }
907 
908  if (!parent) {
909  off_t offset = spfields[0]->offset_to_field;
910  size_t bytesize = spfields[0]->bytesize;
914  spfields[0]->offset_to_field = 0;
915  spfields[0]->bytesize = 0;
916  src_field = _lsd_get_field((char *)lsd, spfields == lsd->self_fields, spfields, i);
917  spfields[0]->offset_to_field = offset;
918  spfields[0]->bytesize = bytesize;
919  } else src_field = _lsd_get_field(parent, spfields == lsd->self_fields, spfields, i);
920  _lsd_auto_copy(dst_field, src_field, spcf, lsd);
921  }
922 
923  debug_print("all fields in struct copied\n\n");
924 
925 recurse_callbacks:
927  if (spfields) {
928  for (int i = 0; spfields[i]; i++) {
929  lives_special_field_t *spcf = spfields[i];
930  dst_field = _lsd_get_field(new_struct, spfields == lsd->self_fields, spfields, i);
931 
932  if (parent) {
933  if (spcf->copy_func) {
934  debug_print("calling copy_func for %s\n", spcf->name);
935  src_field = (char *)lsd->top + spcf->offset_to_field;
936  (*spcf->copy_func)(new_struct, lsd->top, (spfields == lsd->special_fields)
937  ? lsd->structtype : SELF_STRUCT_TYPE,
938  spcf->name, dst_field, src_field);
939  }
940  } else {
941  if (spcf->init_func) {
942  debug_print("calling init_func for %s\n", spcf->name);
943  (*spcf->init_func)(new_struct, (spfields == lsd->special_fields)
944  ? lsd->structtype : SELF_STRUCT_TYPE,
945  spcf->name, dst_field);
946  // *INDENT-OFF*
947  }}}}}
948  // *INDENT-ON*
949 
950  if (spfields != lsd->special_fields) {
951  // after copying structdef, we copy the normal fields
952  spfields = lsd->special_fields;
953  if (!parent) {
954  debug_print("initing normal fields\n");
955  if (spfields) goto recurse_callbacks;
956  } else {
957  debug_print("copying normal fields\n");
958  if (spfields) goto recurse_copy;
959  }
960  }
961 
962  if (parent)
963  debug_print("struct copy done\n\n");
964  else
965  debug_print("struct init done\n\n");
966 
967  debug_print("triggering any struct callbacks\n\n");
968 
969  if (parent) {
970  if (lsd->copied_struct_callback)
971  (*lsd->copied_struct_callback)(parent, new_struct, lsd->structtype, lsd->copied_user_data);
972  }
973 
974  dst_lsd = _lsd_get_field(new_struct, 1, lsd->self_fields, 0);
975  if (dst_lsd->new_struct_callback)
976  (*dst_lsd->new_struct_callback)(new_struct, parent, lsd->structtype, dst_lsd->new_user_data);
977 
978  return new_struct;
979 }
980 
981 static int _lsd_struct_init(const lives_struct_def_t *lsd, void *thestruct,
982  lives_struct_def_t **lsd_in_structp, int is_ptr) {
983  lives_struct_def_t *lsd_in_struct;
984  if (!lsd || !thestruct || !lsd_in_structp) return EINVAL;
985  if (!is_ptr && !(lsd_in_struct = (lives_struct_def_t *)*lsd_in_structp))
986  return EINVAL;
987  if (!_lsd_generation_check_lt((lives_struct_def_t *)lsd, 1, 0)) return EINVAL;
988  else {
989  lives_special_field_t **spfields = lsd->self_fields;
990  if (is_ptr)
991  spfields[0] = _lsd_make_special_field(LIVES_FIELD_FLAG_ALLOC_AND_COPY, thestruct,
992  lsd_in_structp, "lsd",
993  sizeof(lives_struct_def_t), NULL, NULL, NULL);
994  else
995  spfields[0] = _lsd_make_special_field(0, thestruct, lsd_in_struct, "lsd", 0, NULL, NULL, NULL);
996  }
997  return 0;
998 }
999 
1000 static void _lsd_lsd_free(lives_struct_def_t *lsd) {
1001  _lsd_struct_free(lsd);
1002 }
1003 
1005 
1006 static int lives_struct_get_generation(lives_struct_def_t *lsd) {
1007  return !lsd ? -1 : lsd->generation;
1008 }
1009 static uint64_t lives_struct_get_uid(lives_struct_def_t *lsd) {
1010  return !lsd ? 0 : lsd->unique_id;
1011 }
1012 static const char *lives_struct_get_type(lives_struct_def_t *lsd) {
1013  return !lsd ? NULL : lsd->structtype;
1014 }
1015 static const char *lives_struct_get_last_field(lives_struct_def_t *lsd) {
1016  return !lsd ? NULL : lsd->last_field;
1017 }
1018 static uint64_t lives_struct_get_identifier(lives_struct_def_t *lsd) {
1019  return !lsd ? 0ul : lsd->identifier;
1020 }
1021 static uint64_t lives_struct_get_end_id(lives_struct_def_t *lsd) {
1022  return !lsd ? 0ul : lsd->end_id;
1023 }
1024 static void *lives_struct_get_user_data(lives_struct_def_t *lsd) {
1025  return !lsd ? NULL : lsd->user_data;
1026 }
1027 static size_t lives_struct_get_size(lives_struct_def_t *lsd) {
1028  return !lsd ? 0 : lsd->structsize;
1029 }
1030 static void lives_struct_set_user_data(lives_struct_def_t *lsd, void *data) {
1031  if (lsd) lsd->user_data = data;
1032 }
1033 static void *lives_struct_get_class_data(lives_struct_def_t *lsd) {
1034  return !lsd ? NULL : lsd->class_data;
1035 }
1036 static void lives_struct_set_class_data(lives_struct_def_t *lsd, void *data) {
1037  if (lsd) lsd->class_data = data;
1038 }
1039 
1040 static lives_special_field_t *make_special_field(uint64_t flags, void *thestruct,
1041  void *ptr_to_field,
1042  const char *name,
1043  size_t data_size,
1044  lives_field_init_cb init_func,
1045  lives_field_copy_cb copy_func,
1046  lives_field_delete_cb delete_func) {
1047  return _lsd_make_special_field(flags, thestruct, ptr_to_field, name, data_size,
1048  init_func, copy_func, delete_func);
1049 }
1050 
1051 static int lives_struct_ref(lives_struct_def_t *lsd) {
1052  return lsd ? ++((lives_struct_def_t *)lsd)->refcount : 0;
1053 }
1054 
1055 static int lives_struct_unref(lives_struct_def_t *lsd) {
1056  if (lsd) {
1057  if (!lsd->top) {
1058  baderr_print("Unable to free struct of type %s, lives_struct_init must be called first\n",
1059  lsd->structtype);
1060  return -1;;
1061  }
1062  int rc = --(((lives_struct_def_t *)lsd)->refcount);
1063  if (rc <= 0) {
1064  if (_lsd_generation_check_lt((lives_struct_def_t *)lsd, 1, 0))
1065  _lsd_lsd_free((lives_struct_def_t *)lsd);
1066  else _lsd_struct_free((lives_struct_def_t *)lsd);
1067  return rc;
1068  }
1069  }
1070  return 0;
1071 }
1072 
1073 static int lives_struct_get_refcount(lives_struct_def_t *lsd) {
1074  return lsd->refcount;
1075 }
1076 
1077 static int lives_struct_free(lives_struct_def_t *lsd) {
1078  return lives_struct_unref(lsd);
1079 }
1080 
1081 static void *lives_struct_copy(lives_struct_def_t *lsd) {
1082  if (!_lsd_generation_check_gt(lsd, 0, 1)) return NULL;
1083  return _lsd_struct_copy(lsd, NULL);
1084 }
1085 
1086 static int lives_struct_init_p(const lives_struct_def_t *lsd, void *thestruct,
1087  lives_struct_def_t **lsd_in_struct) {
1089  // copy and free lsd, and additionally, special_field offsets are measured from the
1090  // dereferenced field rather than the field itself
1091  // internally this is signalled by setting the bytesize for lsd->special_fields[0].bytesize
1092  // to sizeof(lives_struct_def_t *) instead of 0...
1093  return _lsd_struct_init(lsd, thestruct, lsd_in_struct, 1);
1094 }
1095 
1096 static int lives_struct_init(const lives_struct_def_t *lsd, void *thestruct,
1097  lives_struct_def_t *lsd_in_struct) {
1098  // in other cases a bytesize of zero indicates a string, but in this case it is not relevant
1099  // since flags is also zero. In the unforseen case that flags ever needs setting, then care
1100  // needs to be taken in callbacks to use memcpy rather than strdup, etc.
1101  return _lsd_struct_init(lsd, thestruct, &lsd_in_struct, 0);
1102 }
1103 
1104 static void *lives_struct_create(const lives_struct_def_t *lsd) {
1105  void *thestruct, *lsd_in_struct;
1106  lives_special_field_t **spfields;
1107  off_t offset;
1108 
1109  if (!lsd) return NULL;
1110  spfields = lsd->self_fields;
1111  if (!spfields) return NULL;
1112  if (!spfields[0]) {
1113  baderr_print("Unable to create struct of type %s, lives_struct_init "
1114  "or lives_struct_init_p must be called first\n",
1115  lsd->structtype);
1116  return NULL;
1117  }
1118  offset = spfields[0]->offset_to_field;
1119  if ((*_lsd_calloc_aligned)((void **)&thestruct, 1, lsd->structsize)) {
1120  memerr_print(lsd->structsize, "ALL", lsd->structtype);
1121  return NULL;
1122  }
1123 
1124  if (!(spfields[0]->bytesize)) {
1125  lsd_in_struct = (void *)((char *)thestruct + offset);
1126  (*_lsd_memcpy)(lsd_in_struct, lsd, sizeof(lives_struct_def_t));
1127  }
1128  _lsd_struct_copy((lives_struct_def_t *)lsd, thestruct);
1129  return thestruct;
1130 }
1131 
1132 static int lsd_ref(const lives_struct_def_t *lsd) {
1133  return lives_struct_ref((lives_struct_def_t *)lsd);
1134 }
1135 static int lsd_unref(const lives_struct_def_t *lsd) {
1136  return lives_struct_unref((lives_struct_def_t *)lsd);
1137 }
1138 static int lsd_get_refcount(const lives_struct_def_t *lsd) {
1139  return lives_struct_get_refcount((lives_struct_def_t *)lsd);
1140 }
1141 static int lsd_free(const lives_struct_def_t *lsd) {
1142  return lsd_unref(lsd);
1143 }
1144 
1145 static int lsd_same_family(const lives_struct_def_t *lsd1, lives_struct_def_t *lsd2) {
1146  // must have same identifier, end_id, structtype, structsize, last_field, class_data
1147  if (lsd1->structsize == lsd2->structsize
1148  && lsd1->identifier == lsd2->identifier
1149  && lsd1->end_id == lsd2->end_id
1150  && (!(*_lsd_strcmp)(lsd1->structtype, lsd2->structtype))
1151  && (!(*_lsd_strcmp)(lsd1->class_data, lsd2->class_data))
1152  && (!(*_lsd_strcmp)(lsd1->last_field, lsd2->last_field))) return 1;
1153  return 0;
1154 }
1155 
1156 
1157 static const lives_struct_def_t *lsd_create(const char *struct_type, size_t struct_size,
1158  const char *last_field, int nspecial) {
1159  lives_special_field_t **xspecf;
1160  lives_struct_def_t *lsd;
1161 
1162  if ((*_lsd_calloc_aligned)((void **)&lsd, 1, sizeof(lives_struct_def_t))) {
1163  memerr_print(sizeof(lives_struct_def_t), "LSD template", lsd->structtype);
1164  return NULL;
1165  }
1166 
1167  if (struct_type)
1168  snprintf(lsd->structtype, LSD_TEXTLEN, "%s", struct_type);
1169 
1170  lsd->structsize = struct_size;
1171  lsd->refcount = 1;
1172 
1173  if (last_field)
1174  snprintf(lsd->last_field, LSD_TEXTLEN, "%s", last_field);
1175 
1176  if (nspecial > 0) {
1177  if ((*_lsd_calloc_aligned)((void **)&lsd->special_fields, nspecial + 1,
1178  sizeof(lives_special_field_t *))) {
1179  memerr_print((nspecial + 1) * sizeof(lives_special_field_t *), "lsd.special_fields",
1181  return NULL;
1182  }
1183  lsd->special_fields[nspecial] = NULL;
1184  }
1185 
1186  if ((*_lsd_calloc_aligned)((void **) & (lsd->self_fields), 11, sizeof(lives_special_field_t *))) {
1187  memerr_print(8 * sizeof(lives_special_field_t *), "lsd.self_fields", SELF_STRUCT_TYPE);
1188  return NULL;
1189  }
1190  xspecf = lsd->self_fields;
1191 
1192  // xspecf[0] ("lsd") stays as NULL for now, this tells us that the struct has not been inited yet.
1193 
1194  // set on init
1195  xspecf[1] = _lsd_make_special_field(0, lsd, &lsd->identifier, "identifier", 0, _lsd_init_cb,
1196  NULL, NULL);
1197  // set a new random value on init / copy
1198  xspecf[2] = _lsd_make_special_field(0, lsd, &lsd->unique_id, "unique_id", 0,
1199  _lsd_init_cb, _lsd_copy_cb, NULL);
1200  // et to 1 on init / copy
1201  xspecf[3] = _lsd_make_special_field(0, lsd, &lsd->refcount, "refcount", 0,
1202  _lsd_init_cb, _lsd_copy_cb, NULL);
1203  // set to 1 on init, increment on copy
1204  xspecf[4] = _lsd_make_special_field(0, lsd, &lsd->generation, "generation", 0,
1205  _lsd_init_cb, _lsd_copy_cb, NULL);
1206  // point to struct on init / copy
1207  xspecf[5] = _lsd_make_special_field(0, lsd, &lsd->top, "top", 0, _lsd_init_cb, _lsd_copy_cb, NULL);
1208 
1209  // values will be alloced and copied to a copy struct,
1210  xspecf[6] = _lsd_make_special_field(LIVES_FIELD_PTR_ARRAY, lsd,
1211  &lsd->special_fields, "special_fields",
1212  sizeof(lives_special_field_t), NULL, NULL, NULL);
1213  // NULL terminated array - array allocated / freed elements copied
1214  xspecf[7] = _lsd_make_special_field(LIVES_FIELD_PTR_ARRAY, lsd,
1215  &lsd->self_fields, "self_fields",
1216  sizeof(lives_special_field_t),
1217  NULL, NULL, NULL);
1218  // value will be set to zero after copying
1219  xspecf[8] = _lsd_make_special_field(LIVES_FIELD_FLAG_ZERO_ON_COPY, lsd,
1220  &lsd->user_data, "user_data", 8, NULL, NULL, NULL);
1221  // set to val
1222  xspecf[9] = _lsd_make_special_field(0, lsd, &lsd->end_id, "end_id", 0, _lsd_init_cb,
1223  NULL, NULL);
1224 
1225  xspecf[10] = NULL;
1226 
1227  return lsd;
1228 }
1229 
1231 
1232 #ifdef DEBUG
1233 #undef DEBUG
1234 #endif
1235 
1236 #ifdef __cplusplus
1237 }
1238 #endif /* __cplusplus */
1239 
1240 #endif
lives_struct_def_t::identifier
uint64_t identifier
Definition: lsd.h:242
lives_struct_def_t
112 bytes
Definition: lsd.h:241
LIVES_STRUCT_ID
#define LIVES_STRUCT_ID
Definition: lsd.h:51
lives_struct_def_t::copied_struct_callback
lives_struct_copied_cb copied_struct_callback
user_data for new_struct_callback
Definition: lsd.h:257
lives_special_field_t::name
char name[LSD_NAMELEN]
Definition: lsd.h:234
lives_struct_def_t::user_data
void * user_data
user_data, value maintained across clones
Definition: lsd.h:267
lives_special_field_t::offset_to_field
off_t offset_to_field
must be set when creating the struct
Definition: lsd.h:233
LSD_NAMELEN
#define LSD_NAMELEN
Definition: lsd.h:49
lives_struct_def_t::class_data
void * class_data
fields in the struct_def_t struct itself
Definition: lsd.h:266
lives_struct_def_t::unique_id
uint64_t unique_id
default: LIVES_STRUCT_ID
Definition: lsd.h:243
lives_struct_def_t::top
void * top
ptr to the start of parent struct itself, typecast to a void *
Definition: lsd.h:248
lives_struct_def_t::new_struct_callback
lives_struct_new_cb new_struct_callback
called from lives_struct_new
Definition: lsd.h:254
lives_field_delete_cb
void(* lives_field_delete_cb)(void *strct, const char *struct_type, const char *field_name, void *ptr_to_field)
d->*field_name = s->(field_name) + 10; or using anonymous fields: *(int *)dst_field = *(int *)src_fie...
Definition: lsd.h:220
LIVES_FIELD_PTR_ARRAY
#define LIVES_FIELD_PTR_ARRAY
Definition: lsd.h:176
ALLOW_UNUSED
#define ALLOW_UNUSED
Definition: lsd.h:45
LSD_RANDFUNC
#define LSD_RANDFUNC(ptr, size)
Definition: machinestate.h:234
LIVES_FIELD_FLAG_IS_SUBSTRUCT
#define LIVES_FIELD_FLAG_IS_SUBSTRUCT
flags giving extra info about the field (affects copy and delete)
Definition: lsd.h:136
LIVES_FIELD_FLAG_ALLOC_AND_COPY
#define LIVES_FIELD_FLAG_ALLOC_AND_COPY
AUTONATION FLAGS.
Definition: lsd.h:108
LIVES_FIELD_FLAG_ZERO_ON_COPY
#define LIVES_FIELD_FLAG_ZERO_ON_COPY
Definition: lsd.h:119
lives_struct_def_t::new_user_data
void * new_user_data
Definition: lsd.h:255
lives_struct_def_t::destroy_user_data
void * destroy_user_data
called from lives_struct_free if refcount is 0
Definition: lsd.h:261
lives_special_field_t
Definition: lsd.h:228
memerr_print
#define memerr_print(size, name, struct)
Definition: lsd.h:28
LSD_MAX_ALLOC
#define LSD_MAX_ALLOC
Definition: lsd.h:50
lives_struct_def_t::self_fields
lives_special_field_t ** self_fields
may be NULL, else is pointer to NULL terminated array
Definition: lsd.h:264
baderr_print
#define baderr_print(...)
Definition: lsd.h:37
lives_special_field_t::copy_func
lives_field_copy_cb copy_func
will be called from lives_struct_copy
Definition: lsd.h:237
lives_struct_destroy_cb
void(* lives_struct_destroy_cb)(void *strct, const char *strct_type, void *delete_user_data)
Definition: lsd.h:200
lives_struct_new_cb
void(* lives_struct_new_cb)(void *strct, void *parent, const char *strct_type, void *new_user_data)
Definition: lsd.h:192
lives_special_field_t::delete_func
lives_field_delete_cb delete_func
called from lives_struct_free
Definition: lsd.h:238
lives_field_copy_cb
void(* lives_field_copy_cb)(void *dst_struct, void *src_struct, const char *strct_type, const char *field_name, void *ptr_to_dst_field, void *ptr_to_src_field)
Definition: lsd.h:209
lives_struct_def_t::structsize
size_t structsize
type of the struct as string, e.g "lives_struct_def_t"
Definition: lsd.h:251
LIVES_FIELD_FLAG_FREE_ON_DELETE
#define LIVES_FIELD_FLAG_FREE_ON_DELETE
< field wiill be freed in lives_struct_delete free(struct->field)
Definition: lsd.h:124
lives_struct_def_t::last_field
char last_field[LSD_TEXTLEN]
name of last field of struct (informational only)
Definition: lsd.h:252
lives_struct_def_t::end_id
uint64_t end_id
user_data for instances of struct, reset on copy
Definition: lsd.h:268
error
error("LSD_RANDFUNC(ptr, size) must be defined")
lives_struct_def_t::generation
uint32_t generation
initialized as 1 and incremented on each copy
Definition: lsd.h:246
lives_special_field_t::init_func
lives_field_init_cb init_func
defines the elemnt size for
Definition: lsd.h:236
SELF_STRUCT_TYPE
#define SELF_STRUCT_TYPE
256 bytes
Definition: lsd.h:275
lives_struct_def_t
struct _lives_struct_def lives_struct_def_t
Definition: lsd.h:185
_MEM_ALIGNMENT_
#define _MEM_ALIGNMENT_
Definition: lsd.h:87
lives_struct_def_t::structtype
char structtype[LSD_TEXTLEN]
Definition: lsd.h:250
debug_print
#define debug_print(...)
Definition: lsd.h:23
lives_field_init_cb
void(* lives_field_init_cb)(void *strct, const char *struct_type, const char *field_name, void *ptr_to_field)
Definition: lsd.h:205
lives_special_field_t::flags
uint64_t flags
flags may be 0 to optionally provide info re. the field name, bytesize,
Definition: lsd.h:231
lives_struct_def_t::special_fields
lives_special_field_t ** special_fields
user_data for delete_struct_callback
Definition: lsd.h:263
lives_struct_def_t::copied_user_data
void * copied_user_data
Definition: lsd.h:258
LSD_TEXTLEN
#define LSD_TEXTLEN
Definition: lsd.h:48
lives_special_field_t::bytesize
size_t bytesize
optional unless flags == 0 or any of the functions below are defined.
Definition: lsd.h:235
LIVES_FIELD_FLAG_FREE_ALL_ON_DELETE
#define LIVES_FIELD_FLAG_FREE_ALL_ON_DELETE
for (i = 0; struct->field[i], i++) free(struct->field[i];
Definition: lsd.h:127
lives_struct_def_t::refcount
int32_t refcount
randomly generted id, unique to each instance
Definition: lsd.h:245
LIVES_FIELD_FLAG_IS_NULLT_ARRAY
#define LIVES_FIELD_FLAG_IS_NULLT_ARRAY
Definition: lsd.h:141
lives_struct_copied_cb
void(* lives_struct_copied_cb)(void *strct, void *child, const char *strct_type, void *copied_user_data)
Definition: lsd.h:196
lives_struct_def_t::destroy_struct_callback
lives_struct_destroy_cb destroy_struct_callback
user_data for clone_struct_callback
Definition: lsd.h:260