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
13extern "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
60static void *(*_lsd_calloc)(size_t nmemb, size_t size) = calloc;
61static void *(*_lsd_memcpy)(void *dest, const void *src, size_t n) = memcpy;
62static void *(*_lsd_memset)(void *s, int c, size_t n) = memset;
63static void (*_lsd_free)(void *ptr) = free;
64#endif
65
66#ifndef OVERRIDE_STRFUNCS
67static int(*_lsd_strcmp)(const char *s1, const char *s2) = strcmp;
68static char *(*_lsd_strdup)(const char *s) = strdup;
69static 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
76static 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
83static 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
90static int (*_lsd_calloc_aligned)(void **memptr, size_t nmemb, size_t size) =
91 _lsd_calloc_aligned_;
92
93static char *_lsd_proxy_strdup(char *str) ALLOW_UNUSED;
94static 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
130
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
185typedef 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
192typedef 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
196typedef 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
200typedef 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
205typedef 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
209typedef 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
220typedef 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
228typedef struct _lives_special_field {
230 //(and optionally offset_to_field)
231 uint64_t flags;
234 char name[LSD_NAMELEN];
235 size_t bytesize;
240
241typedef 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
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
303static int lsd_free(const lives_struct_def_t *) ALLOW_UNUSED;
304static int lsd_unref(const lives_struct_def_t *) ALLOW_UNUSED;
305static int lsd_ref(const lives_struct_def_t *) ALLOW_UNUSED;
306static 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)
311static 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.
315static void lives_struct_set_class_data(lives_struct_def_t *, void *class_data) ALLOW_UNUSED;
316static void *lives_struct_get_class_data(lives_struct_def_t *) ALLOW_UNUSED;
317
318static 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
325make_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,
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)
336static 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 *)
340static 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)
345static 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
349static void *lives_struct_copy(lives_struct_def_t *) ALLOW_UNUSED;
350
351// just calls lives_struct_unref
352static 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
356static int lives_struct_unref(lives_struct_def_t *) ALLOW_UNUSED;
357
358// increments refcount, returns new value. Returns 0 if paramter is NULL
359static int lives_struct_ref(lives_struct_def_t *) ALLOW_UNUSED;
360
361// returns current refcount, or 0 if NULL is passed
362static int lives_struct_get_refcount(lives_struct_def_t *) ALLOW_UNUSED;
363
364// set user data for an instance, reset for copies
365static void lives_struct_set_user_data(lives_struct_def_t *, void *data) ALLOW_UNUSED;
366static 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
370static int lives_struct_get_generation(lives_struct_def_t *) ALLOW_UNUSED;
371
372static uint64_t lives_struct_get_uid(lives_struct_def_t *) ALLOW_UNUSED;
373
374static const char *lives_struct_get_type(lives_struct_def_t *) ALLOW_UNUSED;
375
376static const char *lives_struct_get_last_field(lives_struct_def_t *) ALLOW_UNUSED;
377
378static uint64_t lives_struct_get_identifier(lives_struct_def_t *) ALLOW_UNUSED;
379
380static uint64_t lives_struct_get_end_id(lives_struct_def_t *) ALLOW_UNUSED;
381
382static 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
407error("LSD_RANDFUNC(ptr, size) must be defined");
408#endif
409#endif
410
411static void _lsd_init_copy(void *, void *, const char *, const char *, void *) ALLOW_UNUSED;
412static 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
439static void _lsd_init_cb(void *, const char *, const char *, void *) ALLOW_UNUSED;
440static 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
446static void _lsd_copy_cb(void *, void *, const char *, const char *, void *, void *) ALLOW_UNUSED;
447static 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
453static void _lsd_delete_cb(void *, const char *, const char *, void *) ALLOW_UNUSED;
454static 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
460static 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}
469static 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
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) {
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
502static 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
526static int _lsd_auto_delete(void *ptr, uint64_t flags, size_t bsize) {
528 if (!(flags & LIVES_FIELD_FLAG_IS_NULLT_ARRAY)) {
529 flags &= ~LIVES_FIELD_FLAG_FREE_ALL_ON_DELETE;
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 }
544 void *vptr = *((void **)ptr);
545 if (vptr) {
546 if ((flags & LIVES_FIELD_FLAG_ALLOC_AND_COPY) && !bsize
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
559static 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);
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;
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
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
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 {
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 {
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
779static void _lsd_struct_free(lives_struct_def_t *) ALLOW_UNUSED;
780static 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;
795 (*lsd->destroy_struct_callback)(thestruct, lsd->structtype, lsd->destroy_user_data);
796 spfields = lsd->special_fields;
797 }
798
799recurse_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
860static 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
887recurse_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
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
925recurse_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)
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)
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
981static 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
1000static void _lsd_lsd_free(lives_struct_def_t *lsd) {
1001 _lsd_struct_free(lsd);
1002}
1003
1005
1006static int lives_struct_get_generation(lives_struct_def_t *lsd) {
1007 return !lsd ? -1 : lsd->generation;
1008}
1009static uint64_t lives_struct_get_uid(lives_struct_def_t *lsd) {
1010 return !lsd ? 0 : lsd->unique_id;
1011}
1012static const char *lives_struct_get_type(lives_struct_def_t *lsd) {
1013 return !lsd ? NULL : lsd->structtype;
1014}
1015static const char *lives_struct_get_last_field(lives_struct_def_t *lsd) {
1016 return !lsd ? NULL : lsd->last_field;
1017}
1018static uint64_t lives_struct_get_identifier(lives_struct_def_t *lsd) {
1019 return !lsd ? 0ul : lsd->identifier;
1020}
1021static uint64_t lives_struct_get_end_id(lives_struct_def_t *lsd) {
1022 return !lsd ? 0ul : lsd->end_id;
1023}
1024static void *lives_struct_get_user_data(lives_struct_def_t *lsd) {
1025 return !lsd ? NULL : lsd->user_data;
1026}
1027static size_t lives_struct_get_size(lives_struct_def_t *lsd) {
1028 return !lsd ? 0 : lsd->structsize;
1029}
1030static void lives_struct_set_user_data(lives_struct_def_t *lsd, void *data) {
1031 if (lsd) lsd->user_data = data;
1032}
1033static void *lives_struct_get_class_data(lives_struct_def_t *lsd) {
1034 return !lsd ? NULL : lsd->class_data;
1035}
1036static void lives_struct_set_class_data(lives_struct_def_t *lsd, void *data) {
1037 if (lsd) lsd->class_data = data;
1038}
1039
1040static 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
1051static int lives_struct_ref(lives_struct_def_t *lsd) {
1052 return lsd ? ++((lives_struct_def_t *)lsd)->refcount : 0;
1053}
1054
1055static 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
1073static int lives_struct_get_refcount(lives_struct_def_t *lsd) {
1074 return lsd->refcount;
1075}
1076
1077static int lives_struct_free(lives_struct_def_t *lsd) {
1078 return lives_struct_unref(lsd);
1079}
1080
1081static 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
1086static 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
1096static 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
1104static 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
1132static int lsd_ref(const lives_struct_def_t *lsd) {
1133 return lives_struct_ref((lives_struct_def_t *)lsd);
1134}
1135static int lsd_unref(const lives_struct_def_t *lsd) {
1136 return lives_struct_unref((lives_struct_def_t *)lsd);
1137}
1138static int lsd_get_refcount(const lives_struct_def_t *lsd) {
1139 return lives_struct_get_refcount((lives_struct_def_t *)lsd);
1140}
1141static int lsd_free(const lives_struct_def_t *lsd) {
1142 return lsd_unref(lsd);
1143}
1144
1145static 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
1157static 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
#define baderr_print(...)
Definition: lsd.h:37
#define _MEM_ALIGNMENT_
Definition: lsd.h:87
#define LIVES_FIELD_FLAG_FREE_ALL_ON_DELETE
for (i = 0; struct->field[i], i++) free(struct->field[i];
Definition: lsd.h:127
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
#define SELF_STRUCT_TYPE
256 bytes
Definition: lsd.h:275
#define LIVES_FIELD_PTR_ARRAY
Definition: lsd.h:176
void(* lives_struct_new_cb)(void *strct, void *parent, const char *strct_type, void *new_user_data)
Definition: lsd.h:192
#define LSD_TEXTLEN
Definition: lsd.h:48
#define memerr_print(size, name, struct)
Definition: lsd.h:28
#define LIVES_STRUCT_ID
Definition: lsd.h:51
#define ALLOW_UNUSED
Definition: lsd.h:45
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
error("LSD_RANDFUNC(ptr, size) must be defined")
#define LIVES_FIELD_FLAG_ALLOC_AND_COPY
AUTONATION FLAGS.
Definition: lsd.h:108
#define LSD_NAMELEN
Definition: lsd.h:49
#define LIVES_FIELD_FLAG_IS_NULLT_ARRAY
Definition: lsd.h:141
struct _lives_struct_def lives_struct_def_t
Definition: lsd.h:185
#define LSD_MAX_ALLOC
Definition: lsd.h:50
#define LIVES_FIELD_FLAG_ZERO_ON_COPY
Definition: lsd.h:119
#define debug_print(...)
Definition: lsd.h:23
void(* lives_field_init_cb)(void *strct, const char *struct_type, const char *field_name, void *ptr_to_field)
Definition: lsd.h:205
void(* lives_struct_copied_cb)(void *strct, void *child, const char *strct_type, void *copied_user_data)
Definition: lsd.h:196
#define LIVES_FIELD_FLAG_IS_SUBSTRUCT
flags giving extra info about the field (affects copy and delete)
Definition: lsd.h:136
#define LIVES_FIELD_FLAG_FREE_ON_DELETE
< field wiill be freed in lives_struct_delete free(struct->field)
Definition: lsd.h:124
void(* lives_struct_destroy_cb)(void *strct, const char *strct_type, void *delete_user_data)
Definition: lsd.h:200
#define LSD_RANDFUNC(ptr, size)
Definition: machinestate.h:234
char name[LSD_NAMELEN]
Definition: lsd.h:234
lives_field_init_cb init_func
defines the elemnt size for
Definition: lsd.h:236
uint64_t flags
flags may be 0 to optionally provide info re. the field name, bytesize,
Definition: lsd.h:231
lives_field_copy_cb copy_func
will be called from lives_struct_copy
Definition: lsd.h:237
lives_field_delete_cb delete_func
called from lives_struct_free
Definition: lsd.h:238
size_t bytesize
optional unless flags == 0 or any of the functions below are defined.
Definition: lsd.h:235
off_t offset_to_field
must be set when creating the struct
Definition: lsd.h:233
112 bytes
Definition: lsd.h:241
void * copied_user_data
Definition: lsd.h:258
lives_struct_new_cb new_struct_callback
called from lives_struct_new
Definition: lsd.h:254
lives_special_field_t ** special_fields
user_data for delete_struct_callback
Definition: lsd.h:263
lives_special_field_t ** self_fields
may be NULL, else is pointer to NULL terminated array
Definition: lsd.h:264
uint64_t identifier
Definition: lsd.h:242
uint64_t end_id
user_data for instances of struct, reset on copy
Definition: lsd.h:268
void * top
ptr to the start of parent struct itself, typecast to a void *
Definition: lsd.h:248
void * class_data
fields in the struct_def_t struct itself
Definition: lsd.h:266
lives_struct_copied_cb copied_struct_callback
user_data for new_struct_callback
Definition: lsd.h:257
char structtype[LSD_TEXTLEN]
Definition: lsd.h:250
size_t structsize
type of the struct as string, e.g "lives_struct_def_t"
Definition: lsd.h:251
void * user_data
user_data, value maintained across clones
Definition: lsd.h:267
void * new_user_data
Definition: lsd.h:255
lives_struct_destroy_cb destroy_struct_callback
user_data for clone_struct_callback
Definition: lsd.h:260
char last_field[LSD_TEXTLEN]
name of last field of struct (informational only)
Definition: lsd.h:252
int32_t refcount
randomly generted id, unique to each instance
Definition: lsd.h:245
uint64_t unique_id
default: LIVES_STRUCT_ID
Definition: lsd.h:243
void * destroy_user_data
called from lives_struct_free if refcount is 0
Definition: lsd.h:261
uint32_t generation
initialized as 1 and incremented on each copy
Definition: lsd.h:246