|
CX Framework
Cross-platform C utility framework
|
Macros | |
| #define | structInitMany(structname, s, n) _structInitMany(STRUCTBASE(s), &structInfoName(structname), n) |
| #define | structInit(structname, s) _structInitMany(STRUCTBASE(s), &structInfoName(structname), 1) |
| #define | structCreate(structname) ((structname*)_structAlloc(&structInfoName(structname))) |
| #define | structDestroyMembersMany(s, n) _structDestroyMembersMany(STRUCTBASE(s), n) |
| #define | structDestroyMembers(s) _structDestroyMembersMany(STRUCTBASE(s), 1) |
| #define | structDestroy(ps) _structDestroy(STRUCTHANDLE(ps)) |
Enumerations | |
| enum | StructMemberFlagsEnum { STRUCT_NoDestroy = 1 << 0 , STRUCT_NoCopy = 1 << 1 , STRUCT_NoSerialize = 1 << 2 , STRUCT_Ignore = STRUCT_NoDestroy | STRUCT_NoSerialize | STRUCT_NoCopy } |
Functions | |
| const StructInfo * | structSetFind (const StructSet *ss, strref name) |
The CX struct system provides plain-old-data (POD) C structures with runtime type introspection, automatic serialization, and lifecycle management. Unlike objects in the CX object system, structs are not reference counted, are not polymorphic, and carry no vtable overhead — they are simply annotated C structs with metadata automatically generated from .cxh definitions.
.cxh files alongside classes and interfacesStructInfo metadata, accessible at runtime for generic code[noserialize], or renamed on the wire with [serializeas]sarray, hashtable, ...)Structs are declared in .cxh files using the struct keyword:
The build system (via add_cxautogen() in CMakeLists.txt) generates:
mystructs.h - Public API (type definitions, function declarations)mystructs.c - Static StructInfo / StructMemberDesc tablesmystructs.auto.inc - Internal boilerplateNever edit generated .h files directly — modify the .cxh source instead.
[default value] gives a member a starting value other than zero: structInit() and structCreate() copy it in after the zero-fill, so cfg.port above comes out 8080 rather than 0. It also feeds serialization — see the Serialization section below.
Every generated struct type begins with a StructBase union as its first member:
This overlay means a Point* is castable to StructBase* for generic handling, and the structinfo pointer is always available at a known, zero offset.
Structs are not restricted to the heap:
| Function | Frees memory? | Description |
|---|---|---|
structInit(Type, ptr) | No | Set metadata pointer; zero-fill members |
structDestroyMembers(ptr) | No | Destroy members via stype dtors |
structDestroyMembersMany(ptr, n) | No | Same, for a flat array of n structs |
structDestroy(&ptr) | Yes | structDestroyMembers + xaFree; sets NULL |
Custom init and destroy hooks can be declared in the .cxh file (analogous to object system init()/destroy()):
A generated struct type works as a stype token exactly like any built-in type: pass the struct's name wherever a type argument is expected, including as a container element type.
Heap-allocated struct pointers use a second, separate token: structp. It takes no type parameter — every heap struct carries its own StructInfo* at offset 0, so structp reads the concrete type back from the pointer itself. This makes containers of structp values heterogeneous automatically, and whatever a slot holds, the container destroys it (via structDestroy) when the slot is overwritten or the container itself is destroyed.
htInsert() copies the struct in, like it does for any type — the pointer you passed is still yours to destroy. To move an existing heap struct into the container without a copy, steal it with htInsertC() instead:
A struct set is a named, sorted list of struct types — the declared vocabulary for a slot that may hold any one of them. Declare it with structset in a .cxh file and type a structp member by it:
structp[ShapeSet] behaves like bare structp at runtime — one heterogeneous pointer, dispatched through the pointee's own StructInfo*. Serialization is where the set matters: writing a struct that isn't in ShapeSet fails, and reading a Drawing resolves the concrete shape by name against ShapeSet with nothing to configure on the reader. Look a type up directly with structSetFind().
Structs serialize through the generic Serialization module, using the struct's generated schema (stExt(StructName)) and type (stType(StructName)) — there is no struct-specific serialization code, the same traverser and backends handle every stype-described value.
The same calls work unchanged against the binary or SSD-tree backend — see Serialization for the full read/write API, the available backends, and how object classes serialize.
A member declared [default value] is omitted from the document entirely when it still holds that value, and a document that omits it reads back as that value — SER_EmitDefaults writes it anyway. This is automatic once the member is annotated; there is nothing to opt into at the call site.
[noserialize] drops a member from the wire entirely. [serializeas X] keeps the member but changes the name it goes out under: the C identifier is unaffected, and X is the only spelling a document may use for it.
MyStruct — generated struct typeMyStruct_structinfo — the struct's StructInfo, including its member tablestType(MyStruct) — runtime stype descriptor; use directly as a type tokenstExt(MyStruct) — schema descriptor, for Serializationstructp — runtime stype for any heap-allocated struct pointer | #define structCreate | ( | structname | ) | ((structname*)_structAlloc(&structInfoName(structname))) |
struct* structCreate(structname);
Allocates and initializes a single struct instance of the given type on the heap.
Allocates memory for the struct, zero-fills it, and calls the type's custom init function (if any) to set up non-zero default values. The returned pointer must eventually be freed with structDestroy().
| structname | Name of the struct type (without the struct keyword) |
Example:
| #define structDestroy | ( | ps | ) | _structDestroy(STRUCTHANDLE(ps)) |
void structDestroy(struct** ps);
Destroys and frees a heap-allocated struct instance.
Calls the custom destructor (if any), releases all managed members (strings, containers, objects, etc.), frees the heap memory, and sets the pointer to NULL. The struct must have been allocated with structCreate().
| ps | Pointer to the struct pointer to destroy; set to NULL on return |
Example:
| #define structDestroyMembers | ( | s | ) | _structDestroyMembersMany(STRUCTBASE(s), 1) |
void structDestroyMembers(struct* s);
Destroys the members of a single struct instance without freeing the struct.
Calls the custom destructor (if any) and then releases all managed members (strings, containers, objects, etc.). The struct memory itself is not freed — use this for stack-allocated or embedded structs. For heap-allocated structs, use structDestroy() instead.
| s | Pointer to the struct instance whose members should be destroyed |
Example:
| #define structDestroyMembersMany | ( | s, | |
| n | |||
| ) | _structDestroyMembersMany(STRUCTBASE(s), n) |
void structDestroyMembersMany(struct* s, int n);
Destroys the members of n consecutive struct instances without freeing the structs.
Calls the custom destructor (if any) and then releases all managed members (strings, containers, objects, etc.) of each struct. The struct memory itself is not freed — use this for stack-allocated or embedded structs.
| s | Pointer to the first struct instance whose members should be destroyed |
| n | Number of consecutive struct instances to process |
Example:
| #define structInit | ( | structname, | |
| s | |||
| ) | _structInitMany(STRUCTBASE(s), &structInfoName(structname), 1) |
void structInit(structname, struct* s);
Initializes a single struct instance of the given type.
Zero-fills the struct and then calls the type's custom init function (if any) to set up non-zero default values. The struct memory must already be allocated — this function only initializes its contents.
| structname | Name of the struct type (without the struct keyword) |
| s | Pointer to the struct instance to initialize |
Example:
| #define structInitMany | ( | structname, | |
| s, | |||
| n | |||
| ) | _structInitMany(STRUCTBASE(s), &structInfoName(structname), n) |
void structInitMany(structname, struct* s, int n);
Initializes n consecutive struct instances of the given type.
Zero-fills each struct and then calls the type's custom init function (if any) to set up non-zero default values. The struct memory must already be allocated — this function only initializes its contents.
| structname | Name of the struct type (without the struct keyword) |
| s | Pointer to the first struct instance to initialize |
| n | Number of consecutive struct instances to initialize |
Example:
| const StructInfo * structSetFind | ( | const StructSet * | ss, |
| strref | name | ||
| ) |
Looks up a struct type by name in a StructSet using binary search.
| ss | The StructSet to search (must have entries sorted by name) |
| name | The struct type name to look up |