v4k-git-backup/engine/split/v4k_obj.h

311 lines
12 KiB
C
Raw Normal View History

2023-10-21 09:18:13 +00:00
// C objects framework
// - rlyeh, public domain.
//
2023-10-21 09:18:13 +00:00
// ## object limitations
// - 8-byte overhead per object
// - XX-byte overhead per object-entity
// - 32 components max per object-entity
// - 256 classes max per game
// - 256 references max per object
// - 1024K bytes max per object
// - 8 generations + 64K IDs per running instance (19-bit IDs)
// - support for pragma pack(1) structs not enabled by default.
2023-10-21 09:18:13 +00:00
/* /!\ if you plan to use pragma pack(1) on any struct, you need #define OBJ_MIN_PRAGMAPACK_BITS 0 at the expense of max class size /!\ */
#ifndef OBJ_MIN_PRAGMAPACK_BITS
2023-10-23 13:25:03 +00:00
//#define OBJ_MIN_PRAGMAPACK_BITS 3 // allows pragma packs >= 8. objsizew becomes 8<<3, so 2048 bytes max per class (default)
#define OBJ_MIN_PRAGMAPACK_BITS 2 // allows pragma packs >= 4. objsizew becomes 8<<2, so 1024 bytes max per class
//#define OBJ_MIN_PRAGMAPACK_BITS 1 // allows pragma packs >= 2. objsizew becomes 8<<1, so 512 bytes max per class
//#define OBJ_MIN_PRAGMAPACK_BITS 0 // allows pragma packs >= 1. objsizew becomes 8<<0, so 256 bytes max per class
2023-10-21 09:18:13 +00:00
#endif
2023-10-21 09:18:13 +00:00
#define OBJHEADER \
2023-10-28 12:16:41 +00:00
struct { \
ifdef(debug, const char *objname;) \
2023-10-21 09:18:13 +00:00
union { \
uintptr_t objheader; \
struct { \
uintptr_t objtype:8; \
2023-10-23 13:25:03 +00:00
uintptr_t objsizew:8; \
2023-10-21 09:18:13 +00:00
uintptr_t objrefs:8; \
2023-10-23 13:25:03 +00:00
uintptr_t objheap:1; \
2023-10-21 09:18:13 +00:00
uintptr_t objcomps:1; /* << can be removed? check payload ptr instead? */ \
2023-10-23 13:25:03 +00:00
uintptr_t objunused:64-8-8-8-1-1-ID_INDEX_BITS-ID_COUNT_BITS; /*19*/ \
2023-10-21 09:18:13 +00:00
uintptr_t objid:ID_INDEX_BITS+ID_COUNT_BITS; /*16+3*/ \
}; \
2023-10-28 12:16:41 +00:00
}; \
array(struct obj*) objchildren; \
2023-10-21 09:18:13 +00:00
};
2023-10-21 09:18:13 +00:00
#define OBJ \
2023-10-28 12:16:41 +00:00
OBJHEADER
2023-10-21 09:18:13 +00:00
// ----------------------------------------------------------------------------
// syntax sugars
2023-10-21 09:18:13 +00:00
#ifdef OBJTYPE
#undef OBJTYPE
#endif
2023-10-21 09:18:13 +00:00
#define OBJTYPE(T) \
OBJTYPE_##T
2023-10-21 09:18:13 +00:00
#define OBJTYPEDEF(NAME,N) \
enum { OBJTYPE(NAME) = N }; \
STATIC_ASSERT( N <= 255 ); \
2023-10-23 13:25:03 +00:00
STATIC_ASSERT( sizeof(NAME) == ((sizeof(NAME)>>OBJ_MIN_PRAGMAPACK_BITS)<<OBJ_MIN_PRAGMAPACK_BITS) ); // (sizeof(NAME) & ((1<<OBJ_MIN_PRAGMAPACK_BITS)-1)) == 0 );
2023-10-21 09:18:13 +00:00
// ----------------------------------------------------------------------------
// objects
2023-10-21 09:18:13 +00:00
#define TYPEDEF_STRUCT(NAME,N,...) \
typedef struct NAME { OBJ \
__VA_ARGS__ \
char payload[0]; \
} NAME; OBJTYPEDEF(NAME,N);
2023-10-21 09:18:13 +00:00
// TYPEDEF_STRUCT(obj,0);
typedef struct obj { OBJ } obj;
2023-10-21 09:18:13 +00:00
// ----------------------------------------------------------------------------
// entities
2023-10-21 09:18:13 +00:00
#define OBJCOMPONENTS_MAX 32
#define OBJCOMPONENTS_ALL_ENABLED 0xAAAAAAAAAAAAAAAAULL
#define OBJCOMPONENTS_ALL_FLAGGED 0x5555555555555555ULL
#define COMPONENTS_ONLY(x) ((x) & ~OBJCOMPONENTS_ALL_FLAGGED)
#define ENTITY \
struct { OBJHEADER union { struct { uintptr_t objenabled:OBJCOMPONENTS_MAX, objflagged:OBJCOMPONENTS_MAX; }; uintptr_t cflags; }; void *c[OBJCOMPONENTS_MAX]; };
#define TYPEDEF_ENTITY(NAME,N,...) \
typedef struct NAME { ENTITY \
__VA_ARGS__ \
char payload[0]; \
} NAME; OBJTYPEDEF(NAME,N);
// OBJTYPEDEF(entity,1)
typedef struct entity { ENTITY } entity;
2023-10-28 12:16:41 +00:00
#define entity_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, 0, __VA_ARGS__)
#define entity_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, 0, __VA_ARGS__)
2023-10-21 09:18:13 +00:00
// ----------------------------------------------------------------------------
// heap/stack ctor/dtor
static __thread obj *objtmp;
2023-10-23 13:25:03 +00:00
#define OBJ_CTOR_HDR(PTR,HEAP,SIZEOF_OBJ,OBJ_TYPE) ( \
2023-10-21 09:18:13 +00:00
(PTR)->objheader = HEAP ? id_make(PTR) : 0, /*should assign to .objid instead. however, id_make() returns shifted bits already*/ \
(PTR)->objtype = (OBJ_TYPE), \
(PTR)->objheap = (HEAP), \
(PTR)->objsizew = (SIZEOF_OBJ>>OBJ_MIN_PRAGMAPACK_BITS))
2023-10-23 13:25:03 +00:00
#define OBJ_CTOR_PTR(PTR,HEAP,SIZEOF_OBJ,OBJ_TYPE) ( \
OBJ_CTOR_HDR(PTR,HEAP,SIZEOF_OBJ,OBJ_TYPE), \
2023-10-21 09:18:13 +00:00
obj_ctor(PTR))
#define OBJ_CTOR(TYPE, NAME, HEAP, PAYLOAD_SIZE, ...) (TYPE*)( \
objtmp = (HEAP ? MALLOC(sizeof(TYPE)+(PAYLOAD_SIZE)) : ALLOCA(sizeof(TYPE)+(PAYLOAD_SIZE))), \
2023-10-28 12:16:41 +00:00
*(TYPE*)objtmp = ((TYPE){ {0,}, __VA_ARGS__}), \
2023-10-21 09:18:13 +00:00
((PAYLOAD_SIZE) ? memset((char*)objtmp + sizeof(TYPE), 0, (PAYLOAD_SIZE)) : objtmp), \
( OBJTYPES[ OBJTYPE(TYPE) ] = #TYPE ), \
2023-10-23 13:25:03 +00:00
OBJ_CTOR_PTR(objtmp, HEAP,sizeof(TYPE),OBJTYPE(TYPE)), \
2023-10-21 09:18:13 +00:00
ifdef(debug, (obj_printf)(objtmp, va("%s", callstack(+16))), 0), \
2023-10-23 13:25:03 +00:00
obj_setname(objtmp, NAME))
2023-10-21 09:18:13 +00:00
2023-10-28 12:16:41 +00:00
#define obj(TYPE, ...) *OBJ_CTOR(TYPE, #TYPE, 0, 0, __VA_ARGS__)
#define obj_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, 0, __VA_ARGS__)
#define obj_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, 0, __VA_ARGS__)
2023-10-21 09:18:13 +00:00
void* obj_malloc(unsigned sz);
void* obj_free(void *o);
// ----------------------------------------------------------------------------
// obj generics. can be extended.
#define obj_ctor(o,...) obj_method(ctor, o, ##__VA_ARGS__)
#define obj_dtor(o,...) obj_method(dtor, o, ##__VA_ARGS__)
#define obj_save(o,...) obj_method(save, o, ##__VA_ARGS__)
#define obj_load(o,...) obj_method(load, o, ##__VA_ARGS__)
#define obj_test(o,...) obj_method(test, o, ##__VA_ARGS__)
#define obj_init(o,...) obj_method(init, o, ##__VA_ARGS__)
#define obj_quit(o,...) obj_method(quit, o, ##__VA_ARGS__)
#define obj_tick(o,...) obj_method(tick, o, ##__VA_ARGS__)
#define obj_draw(o,...) obj_method(draw, o, ##__VA_ARGS__)
#define obj_lerp(o,...) obj_method(lerp, o, ##__VA_ARGS__)
#define obj_edit(o,...) obj_method(edit, o, ##__VA_ARGS__)
// --- syntax sugars
#define obj_extend(T,func) (obj_##func[OBJTYPE(T)] = (void*)T##_##func)
#define obj_method(method,o,...) (obj_##method[((obj*)(o))->objtype](o,##__VA_ARGS__)) // (obj_##method[((obj*)(o))->objtype]((o), ##__VA_ARGS__))
#define obj_vtable(func,RC,...) RC macro(obj_##func)(){ __VA_ARGS__ }; RC (*obj_##func[256])() = { REPEAT256(macro(obj_##func)) };
#define obj_vtable_null(func,RC) RC (*obj_##func[256])() = { 0 }; // null virtual table. will crash unless obj_extend'ed
#define REPEAT16(f) f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f
#define REPEAT64(f) REPEAT16(f),REPEAT16(f),REPEAT16(f),REPEAT16(f)
#define REPEAT256(f) REPEAT64(f),REPEAT64(f),REPEAT64(f),REPEAT64(f)
// --- declare vtables
API extern void (*obj_ctor[256])(); ///-
API extern void (*obj_dtor[256])(); ///-
API extern char* (*obj_save[256])(); ///-
API extern bool (*obj_load[256])(); ///-
API extern int (*obj_test[256])(); ///-
API extern int (*obj_init[256])(); ///-
API extern int (*obj_quit[256])(); ///-
API extern int (*obj_tick[256])(); ///-
API extern int (*obj_draw[256])(); ///-
API extern int (*obj_lerp[256])(); ///-
API extern int (*obj_edit[256])(); ///-
// ----------------------------------------------------------------------------
// core
API uintptr_t obj_header(const void *o);
API uintptr_t obj_id(const void *o);
API const char* obj_type(const void *o);
2023-10-23 13:25:03 +00:00
API unsigned obj_typeid(const void *o);
2023-10-21 09:18:13 +00:00
API int obj_sizeof(const void *o);
API int obj_size(const void *o); // size of all members together in struct. may include padding bytes.
API char* obj_data(void *o); // pointer to the first member in struct
API const char* obj_datac(const void *o); // const pointer to the first struct member
API void* obj_payload(const void *o); // pointer right after last member in struct
API void* obj_zero(void *o); // reset all object members
// ----------------------------------------------------------------------------
// refcounting
API void* obj_ref(void *oo);
API void* obj_unref(void *oo);
// ----------------------------------------------------------------------------
// scene tree
2023-10-27 07:42:40 +00:00
#define each_objchild(p,T,o) /*non-recursive*/ \
2023-10-21 09:18:13 +00:00
(array(obj*)* children = obj_children(p); children; children = 0) \
for(int _i = 1, _end = array_count(*children); _i < _end; ++_i) \
2023-10-27 07:42:40 +00:00
for(T o = (T)((*children)[_i]); o && (obj_parent(o) == p); o = 0)
2023-10-21 09:18:13 +00:00
API obj* obj_detach(void *c);
API obj* obj_attach(void *o, void *c);
API obj* obj_root(const void *o);
API obj* obj_parent(const void *o);
2023-10-23 13:25:03 +00:00
API array(obj*)*obj_children(const void *o); // child[0]: parent, child[1]: 1st child, child[2]: 2nd child...
API array(obj*)*obj_siblings(const void *o); // child[0]: grandpa, child[1]: sibling1, child[2]: sibling2...
2023-10-21 09:18:13 +00:00
API int obj_dumptree(const void *o);
// ----------------------------------------------------------------------------
// metadata
2023-10-23 13:25:03 +00:00
API void* obj_setmeta(void *o, const char *key, const char *value);
API const char* obj_meta(const void *o, const char *key);
API void* obj_setname(void *o, const char *name);
API const char* obj_name(const void *o);
2023-10-21 09:18:13 +00:00
// ----------------------------------------------------------------------------
// stl
API void* obj_swap(void *dst, void *src);
API void* obj_copy_fast(void *dst, const void *src);
API void* obj_copy(void *dst, const void *src);
API int obj_comp_fast(const void *a, const void *b);
API int obj_comp(const void *a, const void *b);
API int obj_lesser(const void *a, const void *b);
API int obj_greater(const void *a, const void *b);
API int obj_equal(const void *a, const void *b);
API uint64_t obj_hash(const void *o);
// ----------------------------------------------------------------------------
// debug
API bool obj_hexdump(const void *oo);
API int obj_print(const void *o);
API int obj_printf(const void *o, const char *text);
API int obj_console(const void *o); // obj_output() ?
#define obj_printf(o, ...) obj_printf(o, va(__VA_ARGS__))
// ----------------------------------------------------------------------------
// serialization
API char* obj_saveini(const void *o);
API obj* obj_mergeini(void *o, const char *ini);
API obj* obj_loadini(void *o, const char *ini);
API char* obj_savejson(const void *o);
API obj* obj_mergejson(void *o, const char *json);
API obj* obj_loadjson(void *o, const char *json);
API char* obj_savebin(const void *o);
API obj* obj_mergebin(void *o, const char *sav);
API obj* obj_loadbin(void *o, const char *sav);
API char* obj_savempack(const void *o); // @todo
API obj* obj_mergempack(void *o, const char *sav); // @todo
API obj* obj_loadmpack(void *o, const char *sav); // @todo
API int obj_push(const void *o);
API int obj_pop(void *o);
// ----------------------------------------------------------------------------
// components
2023-10-28 12:16:41 +00:00
API bool obj_addcomponent(entity *e, unsigned c, void *ptr);
API bool obj_hascomponent(entity *e, unsigned c);
API void* obj_getcomponent(entity *e, unsigned c);
API bool obj_delcomponent(entity *e, unsigned c);
API bool obj_usecomponent(entity *e, unsigned c);
API bool obj_offcomponent(entity *e, unsigned c);
2023-10-21 09:18:13 +00:00
API char* entity_save(entity *self);
// ----------------------------------------------------------------------------
// reflection
#define each_objmember(oo,TYPE,NAME,PTR) \
2023-10-23 13:25:03 +00:00
(array(reflect_t) *found_ = members_find(obj_type(oo)); found_; found_ = 0) \
2023-10-21 09:18:13 +00:00
for(int it_ = 0, end_ = array_count(*found_); it_ != end_; ++it_ ) \
for(reflect_t *R = &(*found_)[it_]; R; R = 0 ) \
for(const char *NAME = R->name, *TYPE = R->type; NAME || TYPE; ) \
for(void *PTR = ((char*)oo) + R->sz ; NAME || TYPE ; NAME = TYPE = 0 )
API void* obj_clone(const void *src);
API void* obj_merge(void *dst, const void *src); // @testme
2023-10-28 12:16:41 +00:00
API void* obj_mutate(void *dst, const void *src);
2023-10-21 09:18:13 +00:00
API void* obj_make(const char *str);
// built-ins
typedef enum OBJTYPE_BUILTINS {
OBJTYPE_obj = 0,
OBJTYPE_entity = 1,
OBJTYPE_vec2 = 2,
OBJTYPE_vec3 = 3,
OBJTYPE_vec4 = 4,
OBJTYPE_quat = 5,
OBJTYPE_mat33 = 6,
OBJTYPE_mat34 = 7,
OBJTYPE_mat44 = 8,
OBJTYPE_vec2i = 9,
OBJTYPE_vec3i = 10,
} OBJTYPE_BUILTINS;