essence-os/util/designer/reflect.h

655 lines
18 KiB
C

// TODO Bitsets.
// TODO Versioning support for unions and enums.
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifndef RF_ASSERT
#include <assert.h>
#define RF_ASSERT assert
#endif
#ifndef RF_MEMZERO
#include <string.h>
#define RF_MEMZERO(pointer, byteCount) memset((pointer), 0, (byteCount))
#endif
#ifndef RF_MEMCPY
#include <string.h>
#define RF_MEMCPY(destination, source, byteCount) memcpy((destination), (source), (byteCount))
#endif
#ifndef RF_REALLOC
#include <stdlib.h>
#define RF_REALLOC(previous, byteCount) realloc((previous), (byteCount))
#endif
#define RF_SIZE_OF(containerType, field) sizeof(((containerType *) NULL)->field)
#define RF_FIELD(containerType, field, fieldRfType, ...) \
{ \
.item.type = &fieldRfType, \
.item.byteCount = RF_SIZE_OF(containerType, field), \
.cName = #field, \
.offset = offsetof(containerType, field), \
__VA_ARGS__ \
}
#define RF_OP_SAVE (-1) // Set access in RfState.
#define RF_OP_LOAD (-2) // Set access and allocate in RfState.
#define RF_OP_FREE (-3) // Set allocate in RfState.
#define RF_OP_ITERATE (-4) // Pass RfIterator; set index.
#define RF_OP_COUNT (-5) // Pass RfIterator; result saved in index.
// User-defined operations use positive integers.
typedef struct RfState {
bool error;
int16_t op;
uint32_t version, flags;
void *(*allocate)(struct RfState *state, void *previous, size_t byteCount);
void (*access)(struct RfState *state, void *buffer, size_t byteCount);
} RfState;
typedef struct RfItem {
struct RfType *type;
size_t byteCount;
void *options;
} RfItem;
typedef struct RfField {
RfItem item;
const char *cName;
ptrdiff_t offset;
uint32_t firstVersion, lastVersion;
uint32_t flagsInclude, flagsExclude;
} RfField;
typedef struct RfType {
void (*op)(RfState *state, RfItem *field, void *pointer);
const char *cName;
size_t fieldCount;
RfField *fields;
} RfType;
typedef struct RfIterator {
RfState s;
void *pointer;
RfItem item;
uint32_t index;
bool includeRemovedFields;
bool isRemoved;
} RfIterator;
typedef struct RfPath {
#define RF_PATH_TERMINATOR (0xFFFFFFFF)
uint32_t indices[1];
} RfPath;
typedef struct RfUnionHeader {
uint32_t tag;
} RfUnionHeader;
typedef struct RfArrayHeader {
size_t length, capacity;
// For compatability with stb_ds.h.
void *hashTable;
ptrdiff_t temporary;
} RfArrayHeader;
typedef struct RfData {
void *buffer;
size_t byteCount;
} RfData;
typedef struct RfGrowableBuffer {
RfState s;
RfData data;
// When writing - allocated space in data.
// When reading - position in data.
size_t position;
} RfGrowableBuffer;
extern RfType rfI8, rfI16, rfI32, rfI64,
rfU8, rfU16, rfU32, rfU64,
rfF32, rfF64,
rfChar, rfBool,
rfData, rfNone,
rfObject /* options - RfItem */,
rfArray /* options - RfItem */;
bool RfPathResolve(RfPath *path, RfItem *item, void **pointer); // Returns true if successful.
void RfBroadcast(RfState *state, RfItem *item, void *pointer, bool recurse);
void RfUnionSelect(RfState *state, RfItem *item, RfUnionHeader *header, uint32_t tag);
void RfReadGrowableBuffer(RfState /* RfGrowableBuffer */ *state, void *buffer, size_t byteCount);
void RfWriteGrowableBuffer(RfState /* RfGrowableBuffer */ *state, void *buffer, size_t byteCount);
void *RfRealloc(RfState *state, void *previous, size_t byteCount);
void RfStructOp(RfState *state, RfItem *item, void *pointer);
void RfUnionOp(RfState *state, RfItem *item, void *pointer);
void RfEnumOp(RfState *state, RfItem *item, void *pointer);
void RfBitSetOp(RfState *state, RfItem *item, void *pointer);
void RfEndianOp(RfState *state, RfItem *item, void *pointer);
void RfIntegerOp(RfState *state, RfItem *item, void *pointer);
void RfNoneOp(RfState *state, RfItem *item, void *pointer);
#ifdef REFLECT_IMPLEMENTATION
void RfIntegerSave(RfState *state, void *pointer, size_t inByteCount) {
uint8_t in[16];
RF_ASSERT(inByteCount < 16);
RF_MEMCPY(in, pointer, inByteCount);
bool negative = in[inByteCount - 1] & 0x80;
size_t inBitCount = 1;
for (int i = inByteCount - 1; i >= 0; i--) {
for (int j = 7; j >= 0; j--) {
if (((in[i] >> j) & 1) != negative) {
inBitCount = i * 8 + j + 2;
goto gotBitCount;
}
}
}
gotBitCount:;
size_t outByteCount = (inBitCount + 6) / 7;
uint8_t out[16];
RF_ASSERT(outByteCount < 16);
for (uintptr_t i = 0; i < outByteCount; i++) {
uint8_t b = 0;
for (uintptr_t j = 0; j < 7; j++) {
uintptr_t bitIndex = i * 7 + j;
bool inBit = negative;
if (bitIndex < 8 * inByteCount) inBit = in[bitIndex >> 3] & (1 << (bitIndex & 7));
if (inBit) b |= 1 << j;
}
out[i] = b;
}
out[outByteCount - 1] |= 0x80;
state->access(state, out, outByteCount);
}
void RfIntegerLoad(RfState *state, void *pointer, size_t byteCount) {
uint8_t out[16];
uintptr_t outIndex = 0;
RF_ASSERT(byteCount < 16);
RF_MEMZERO(out, byteCount);
while (!state->error) {
uint8_t b;
state->access(state, &b, 1);
for (uintptr_t i = 0; i < 7; i++) {
if (outIndex == byteCount * 8) break;
if (b & (1 << i)) out[outIndex >> 3] |= 1 << (outIndex & 7);
outIndex++;
}
if (b & 0x80) {
if (b & 0x40) {
for (uintptr_t i = outIndex; i < byteCount * 8; i++) {
out[i >> 3] |= 1 << (i & 7);
}
}
break;
}
}
if (!state->error && pointer) {
RF_MEMCPY(pointer, out, byteCount);
}
}
void RfStructOp(RfState *state, RfItem *item, void *pointer) {
RfType *type = item->type;
if (state->op == RF_OP_SAVE || state->op == RF_OP_LOAD || state->op == RF_OP_FREE) {
for (uintptr_t i = 0; i < type->fieldCount && !state->error; i++) {
RfField *field = type->fields + i;
if (state->flags & field->flagsExclude) continue;
if ((state->flags & field->flagsInclude) != field->flagsInclude) continue;
void *fieldPointer = pointer ? ((uint8_t *) pointer + field->offset) : NULL;
if (state->op == RF_OP_LOAD) {
if (state->version < field->firstVersion) {
// The field exists, but we're loading from a version where it did not exist.
// Ignore it.
continue;
} else if (field->lastVersion && state->version > field->lastVersion) {
// The field no longer exists, and we're from loading a version where it did not exist.
// Ignore it.
continue;
} else if (field->lastVersion) {
// The field no longer exists, but we're loading a version where it did.
// Skip over it.
fieldPointer = NULL;
} else {
// The field exists, and we're loading from a version where it exists.
}
} else {
if (field->lastVersion) {
continue;
}
}
field->item.type->op(state, &field->item, fieldPointer);
if (state->op == RF_OP_FREE) {
RF_MEMZERO(fieldPointer, field->item.byteCount);
}
}
} else if (state->op == RF_OP_COUNT) {
RfIterator *iterator = (RfIterator *) state;
uint32_t count = 0;
for (uintptr_t i = 0; i < type->fieldCount; i++) {
if (!type->fields[i].lastVersion) {
count++;
}
}
iterator->index = count;
} else if (state->op == RF_OP_ITERATE) {
RfIterator *iterator = (RfIterator *) state;
uint32_t count = 0;
for (uintptr_t i = 0; i < type->fieldCount; i++) {
iterator->isRemoved = type->fields[i].lastVersion;
if (!iterator->isRemoved || iterator->includeRemovedFields) {
if (iterator->index == count) {
iterator->pointer = (uint8_t *) pointer + type->fields[i].offset;
iterator->item = type->fields[i].item;
return;
}
count++;
}
}
state->error = true;
}
}
void RfUnionOp(RfState *state, RfItem *item, void *pointer) {
RfType *type = item->type;
RfUnionHeader *header = (RfUnionHeader *) pointer;
if (state->op == RF_OP_SAVE) {
state->access(state, &header->tag, sizeof(uint32_t));
if (header->tag) {
RfField *field = type->fields + header->tag - 1;
field->item.type->op(state, &field->item, (uint8_t *) pointer + field->offset);
}
} else if (state->op == RF_OP_LOAD) {
uint32_t tag = 0;
state->access(state, &tag, sizeof(uint32_t));
if (tag > type->fieldCount) {
tag = 0;
state->error = true;
} else if (tag) {
RfField *field = type->fields + tag - 1;
if (field->lastVersion) tag = 0;
field->item.type->op(state, &field->item, pointer && !field->lastVersion ? ((uint8_t *) pointer + field->offset) : NULL);
}
if (header) {
header->tag = tag;
}
} else if (state->op == RF_OP_FREE) {
if (header->tag) {
RfField *field = type->fields + header->tag - 1;
field->item.type->op(state, &field->item, (uint8_t *) pointer + field->offset);
}
header->tag = 0;
} else if (state->op == RF_OP_COUNT) {
RfIterator *iterator = (RfIterator *) state;
iterator->index = header->tag ? 1 : 0;
} else if (state->op == RF_OP_ITERATE) {
RfIterator *iterator = (RfIterator *) state;
if (!header->tag || iterator->index > 1) {
state->error = true;
} else {
RfField *field = type->fields + header->tag - 1;
iterator->pointer = (uint8_t *) pointer + field->offset;
iterator->item = field->item;
}
}
}
void RfUnionSelect(RfState *state, RfItem *item, RfUnionHeader *header, uint32_t tag) {
RF_ASSERT(header->tag < item->type->fieldCount && !item->type->fields[header->tag].lastVersion);
RF_ASSERT(tag < item->type->fieldCount && !item->type->fields[tag].lastVersion);
if (header->tag) {
RfField *field = item->type->fields + header->tag - 1;
field->item.type->op(state, &field->item, (uint8_t *) header + field->offset);
}
header->tag = tag + 1;
}
void RfEnumOp(RfState *state, RfItem *item, void *pointer) {
if (state->op == RF_OP_SAVE) {
RfIntegerSave(state, pointer, item->byteCount);
} else if (state->op == RF_OP_LOAD) {
RfIntegerLoad(state, pointer, item->byteCount);
if (pointer) {
uint32_t value = 0;
if (item->byteCount == 1) {
value = *(uint8_t *) pointer;
} else if (item->byteCount == 2) {
value = *(uint16_t *) pointer;
} else if (item->byteCount == 4) {
value = *(uint32_t *) pointer;
} else {
RF_ASSERT(false);
}
if (value >= item->type->fieldCount) {
state->error = true;
}
}
}
}
void RfEndianOp(RfState *state, RfItem *item, void *pointer) {
if (state->op == RF_OP_SAVE || state->op == RF_OP_LOAD) {
state->access(state, pointer, item->byteCount);
}
}
void RfBoolOp(RfState *state, RfItem *item, void *pointer) {
RfEndianOp(state, item, pointer);
if (state->op == RF_OP_LOAD) {
if (pointer && *(uint8_t *) pointer > 1) {
state->error = true;
}
}
}
void RfIntegerOp(RfState *state, RfItem *item, void *pointer) {
if (state->op == RF_OP_SAVE) {
RfIntegerSave(state, pointer, item->byteCount);
} else if (state->op == RF_OP_LOAD) {
RfIntegerLoad(state, pointer, item->byteCount);
}
}
void RfDataOp(RfState *state, RfItem *item, void *pointer) {
(void) item;
RfData *data = (RfData *) pointer;
if (state->op == RF_OP_SAVE) {
uint32_t byteCount = data->byteCount;
RfIntegerSave(state, &byteCount, sizeof(uint32_t));
state->access(state, data->buffer, data->byteCount);
} else if (state->op == RF_OP_LOAD) {
uint32_t byteCount = 0;
RfIntegerLoad(state, &byteCount, sizeof(uint32_t));
if (data) {
RF_ASSERT(!data->buffer);
data->buffer = state->allocate(state, NULL, byteCount);
if (!data->buffer) { state->error = true; return; }
data->byteCount = byteCount;
}
state->access(state, data ? data->buffer : NULL, data->byteCount);
} else if (state->op == RF_OP_FREE) {
state->allocate(state, data->buffer, 0);
data->buffer = NULL;
}
}
void RfObjectOp(RfState *state, RfItem *item, void *pointer) {
RfItem *objectItem = (RfItem *) item->options;
void **object = (void **) pointer;
if (state->op == RF_OP_SAVE) {
uint8_t present = *object != NULL;
state->access(state, &present, sizeof(uint8_t));
if (present) objectItem->type->op(state, objectItem, *object);
} else if (state->op == RF_OP_LOAD) {
uint8_t present = 0;
state->access(state, &present, sizeof(uint8_t));
if (object) {
RF_ASSERT(!(*object));
if (present) {
*object = state->allocate(state, NULL, objectItem->byteCount);
if (!(*object)) { state->error = true; return; }
RF_MEMZERO(*object, objectItem->byteCount);
objectItem->type->op(state, objectItem, *object);
}
} else if (present) {
objectItem->type->op(state, objectItem, NULL);
}
} else if (state->op == RF_OP_FREE) {
if (*object) {
objectItem->type->op(state, objectItem, *object);
state->allocate(state, *object, 0);
*object = NULL;
}
} else if (state->op == RF_OP_COUNT) {
RfIterator *iterator = (RfIterator *) state;
iterator->index = *object ? 1 : 0;
} else if (state->op == RF_OP_ITERATE) {
RfIterator *iterator = (RfIterator *) state;
if (!(*object) || iterator->index > 1) {
state->error = true;
} else {
iterator->pointer = *object;
iterator->item = *objectItem;
}
}
}
void RfNoneOp(RfState *state, RfItem *item, void *pointer) {
(void) state;
(void) item;
(void) pointer;
}
void RfArrayOp(RfState *state, RfItem *item, void *_pointer) {
RfArrayHeader **pointer = (RfArrayHeader **) _pointer;
RfItem *objectItem = (RfItem *) item->options;
if (state->op == RF_OP_SAVE) {
uint32_t length = 0;
if (*pointer) {
length = (*pointer)[-1].length;
}
RfIntegerSave(state, &length, sizeof(uint32_t));
for (uint32_t i = 0; i < length; i++) {
objectItem->type->op(state, objectItem, (uint8_t *) (*pointer) + i * objectItem->byteCount);
}
} else if (state->op == RF_OP_LOAD) {
RF_ASSERT(!pointer || !(*pointer));
uint32_t length = 0;
RfIntegerLoad(state, &length, sizeof(uint32_t));
if (length >= 0xFFFFFFFF / objectItem->byteCount) {
state->error = true;
return;
}
if (!length) {
return;
}
if (pointer) {
void *allocation = state->allocate(state, NULL, length * objectItem->byteCount + sizeof(RfArrayHeader));
if (!allocation) {
state->error = true;
return;
}
*pointer = (RfArrayHeader *) allocation + 1;
(*pointer)[-1].length = 0;
(*pointer)[-1].capacity = length;
(*pointer)[-1].hashTable = NULL;
(*pointer)[-1].temporary = 0;
}
for (uint32_t i = 0; i < length && !state->error; i++) {
if (pointer) {
uint32_t index = (*pointer)[-1].length;
(*pointer)[-1].length++;
uint8_t *p = (uint8_t *) (*pointer) + index * objectItem->byteCount;
RF_MEMZERO(p, objectItem->byteCount);
objectItem->type->op(state, objectItem, p);
} else {
objectItem->type->op(state, objectItem, NULL);
}
}
} else if (state->op == RF_OP_FREE) {
if (*pointer) {
state->allocate(state, (*pointer) - 1, 0);
(*pointer) = NULL;
}
} else if (state->op == RF_OP_COUNT) {
RfIterator *iterator = (RfIterator *) state;
iterator->index = *pointer ? (*pointer)[-1].length : 0;
} else if (state->op == RF_OP_ITERATE) {
RfIterator *iterator = (RfIterator *) state;
if (!(*pointer) || iterator->index > (*pointer)[-1].length) {
state->error = true;
} else {
iterator->pointer = (uint8_t *) (*pointer) + iterator->index * objectItem->byteCount;
iterator->item = *objectItem;
}
}
}
bool RfPathResolve(RfPath *path, RfItem *item, void **pointer) {
RfIterator iterator = { 0 };
iterator.s.op = RF_OP_ITERATE;
iterator.item = *item;
iterator.pointer = *pointer;
iterator.includeRemovedFields = true;
for (int i = 0; path->indices[i] != RF_PATH_TERMINATOR && !iterator.s.error; i++) {
iterator.index = path->indices[i];
RfItem _item = iterator.item;
_item.type->op(&iterator.s, &_item, iterator.pointer);
}
*item = iterator.item;
*pointer = iterator.pointer;
return !iterator.s.error;
}
void RfBroadcast(RfState *state, RfItem *item, void *pointer, bool recurse) {
RfIterator iterator = { 0 };
iterator.s.op = RF_OP_COUNT;
item->type->op(&iterator.s, item, pointer);
iterator.s.op = RF_OP_ITERATE;
uint32_t count = iterator.index;
for (uint32_t i = 0; i < count; i++) {
iterator.index = i;
item->type->op(&iterator.s, item, pointer);
if (iterator.s.error) return;
iterator.item.type->op(state, &iterator.item, iterator.pointer);
if (recurse) {
RfBroadcast(state, &iterator.item, iterator.pointer, true);
}
}
}
void RfWriteGrowableBuffer(RfState *state, void *source, size_t byteCount) {
if (state->error) return;
RfGrowableBuffer *destination = (RfGrowableBuffer *) state;
if (destination->data.byteCount + byteCount > destination->position) {
destination->position = destination->position * 2;
if (destination->data.byteCount + byteCount > destination->position) {
destination->position = destination->data.byteCount + byteCount + 64;
}
void *old = destination->data.buffer;
destination->data.buffer = state->allocate(state, destination->data.buffer, destination->position);
if (!destination->data.buffer) {
state->allocate(state, old, 0);
state->error = true;
return;
}
}
RF_MEMCPY((uint8_t *) destination->data.buffer + destination->data.byteCount, source, byteCount);
destination->data.byteCount += byteCount;
}
void RfReadGrowableBuffer(RfState *state, void *destination, size_t byteCount) {
if (state->error) return;
RfGrowableBuffer *source = (RfGrowableBuffer *) state;
if (source->position + byteCount > source->data.byteCount) {
state->error = true;
} else {
if (destination) {
RF_MEMCPY(destination, (uint8_t *) source->data.buffer + source->position, byteCount);
}
source->position += byteCount;
}
}
void *RfRealloc(RfState *state, void *previous, size_t byteCount) {
(void) state;
return RF_REALLOC(previous, byteCount);
}
RfType rfI8 = { .op = RfEndianOp, .cName = "I8" };
RfType rfI16 = { .op = RfIntegerOp, .cName = "I16" };
RfType rfI32 = { .op = RfIntegerOp, .cName = "I32" };
RfType rfI64 = { .op = RfIntegerOp, .cName = "I64" };
RfType rfU8 = { .op = RfEndianOp, .cName = "U8" };
RfType rfU16 = { .op = RfIntegerOp, .cName = "U16" };
RfType rfU32 = { .op = RfIntegerOp, .cName = "U32" };
RfType rfU64 = { .op = RfIntegerOp, .cName = "U64" };
RfType rfChar = { .op = RfEndianOp, .cName = "Char" };
RfType rfBool = { .op = RfBoolOp, .cName = "Bool" };
RfType rfF32 = { .op = RfEndianOp, .cName = "F32" };
RfType rfF64 = { .op = RfEndianOp, .cName = "F64" };
RfType rfData = { .op = RfDataOp, .cName = "Data" };
RfType rfObject = { .op = RfObjectOp, .cName = "Object" };
RfType rfArray = { .op = RfArrayOp, .cName = "Array" };
RfType rfNone = { .op = RfNoneOp, .cName = "None" };
#endif