This repository has been archived on 2025-03-27. You can view files and clone it, but cannot push or open issues or pull requests.

723 lines
20 KiB
C++

#include "lib.h"
#include "rawlist.cc"
TypeTree DB_TYPE;
NameTree DB_NAME;
//Pool<Type::Schema> DB_SCHEMA;
Pool<Reference> DB_DATA;
extern "C" size_t type_outer(size_t type_id, size_t key)
{
return DB_TYPE.outer(type_id, key);
}
extern "C" size_t type_inner(size_t type_id)
{
return DB_TYPE.inner(type_id);
}
extern "C" size_t type_key(size_t type_id)
{
return DB_TYPE.key(type_id);
}
extern "C" size_t type_size(size_t type_id)
{
if(DB_TYPE.has(type_id)) {
size_t type = DB_TYPE.key(type_id);
switch(type) {
case Type::Tag::Null: return 0;
case Type::Tag::Varying: return sizeof(Reference);
case Type::Tag::Boolean: return sizeof(Type::Boolean);
case Type::Tag::Natural: return sizeof(Type::Natural);
case Type::Tag::Integer: return sizeof(Type::Integer);
case Type::Tag::Block: return DB_TYPE.key(DB_TYPE.inner(type_id));
case Type::Tag::Sequence: return sizeof(Type::Sequence);
case Type::Tag::Array: {
size_t length = DB_TYPE.inner(type_id);
size_t inner = DB_TYPE.inner(length);
return static_cast<size_t>(DB_TYPE.key(length)) * type_size(inner);
};
case Type::Tag::List: return sizeof(Type::List);
case Type::Tag::Record: {
//if(DB_SCHEMA.has(type_key(type_inner(type_id)))) {
// return DB_SCHEMA.get().size;
//}
return 0;
}
case Type::Tag::Schema: return sizeof(Type::Schema);
default: return 0;
}
}
return 0;
}
extern "C" size_t name_indexof(const uint8_t* bytes, size_t length)
{
std::string str(reinterpret_cast<const char*>(bytes), length);
return DB_NAME.indexof(str);
}
extern "C" Str name_keyof(size_t index)
{
Str result {0};
std::string str = DB_NAME.keyof(index);
if(str.length() > 0) {
result.bytes = new uint8_t[str.length()];
}
for(size_t i = 0; i < str.length(); ++i) {
result.bytes[i] = str[i];
}
result.length = str.length();
return result;
}
std::string name_keyof_internal(size_t index)
{
return DB_NAME.keyof(index);
}
extern "C" void name_release(Str data)
{
if(data.bytes != nullptr) {
delete[] data.bytes;
}
}
void* allocate(size_t type_id, size_t count)
{
void* mem = nullptr;
size_t size = type_size(type_id) * count;
if(size > 0) {
mem = malloc(size);
if(mem != nullptr) {
memset(mem, 0, size);
}
return mem;
}
return nullptr;
}
extern "C" Reference acquire(size_t type_id)
{
Reference addr {0};
addr.address = allocate(type_id, 1);
if(addr.address != nullptr) {
addr.type = type_id;
}
return addr;
}
void drop(Reference addr)
{
if(addr.address != nullptr) {
switch(type_key(addr.type)) {
case Type::Tag::Boolean:
case Type::Tag::Natural:
case Type::Tag::Integer:
case Type::Tag::Block:
break;
case Type::Tag::Varying: {
auto& var = *reinterpret_cast<Reference*>(addr.address);
if(var.address != nullptr) {
drop(var);
}
var.type = 0;
var.address = nullptr;
} break;
case Type::Tag::Sequence: {
auto& seq = *reinterpret_cast<Type::Sequence*>(addr.address);
rawlist_clear(seq.data);
} break;
case Type::Tag::List: {
Type::List& list = *reinterpret_cast<Type::List*>(addr.address);
for(size_t i = 0; i < list.data.length; ++i) {
drop(list_cell(addr, i));
}
rawlist_clear(list.data);
} break;
}
memset(addr.address, 0, type_size(addr.type));
}
}
extern "C" void release(Reference addr)
{
if(addr.address != nullptr) {
drop(addr);
free(addr.address);
}
}
bool copy(Reference src, Reference dst)
{
Reference source = src;
Reference destination = dst;
// dereference varying data
if(type_key(src.type) == Type::Tag::Varying) {
source = *reinterpret_cast<Reference*>(src.address);
}
// prepare destination for varying data
if(type_key(dst.type) == Type::Tag::Varying) {
auto& dest_ref = *reinterpret_cast<Reference*>(dst.address);
// determine if memory can be reused, otherwise free and reallocate
if(source.type != dest_ref.type) {
if(dest_ref.address != nullptr) {
free(dest_ref.address);
dest_ref.type = Type::Tag::Null;
dest_ref.address = nullptr;
}
dest_ref = acquire(source.type);
}
}
// copy data into destination
if(source.type == destination.type) {
switch(type_key(destination.type)) {
case Type::Tag::Null: { } break;
case Type::Tag::Boolean:
case Type::Tag::Natural:
case Type::Tag::Integer:
case Type::Tag::Block:
{
memcpy(destination.address, source.address, type_size(source.type));
} break;
case Type::Tag::List: {
auto& src_list = *reinterpret_cast<Type::List*>(source.address);
auto& dst_list = *reinterpret_cast<Type::List*>(destination.address);
rawlist_reserve(dst_list.data, type_size(type_inner(source.type)), src_list.data.capacity);
dst_list.data.length = src_list.data.length;
//dst_list.data = allocate(type_inner(source.type), src_list.capacity);
for(size_t i = 0; i < src_list.data.length; ++i) {
copy(list_at(source, i), list_at(destination, i));
}
} break;
}
return true;
}
return false;
}
// Varying //
extern "C" Reference varying_get(Reference addr)
{
Reference result {0};
result = *reinterpret_cast<Reference*>(addr.address);
return result;
}
extern "C" void varying_set(Reference addr, Reference source)
{
Reference& var = *reinterpret_cast<Reference*>(addr.address);
if(var.address != nullptr) {
drop(var);
}
if(var.type != source.type || var.address == nullptr) {
if(var.address != nullptr) {
free(var.address);
}
var.type = source.type;
var.address = allocate(source.type, 1);
}
copy(source, var);
}
extern "C" void varying_clear(Reference addr)
{
Reference& var = *reinterpret_cast<Reference*>(addr.address);
if(var.address != nullptr) {
drop(var);
free(var.address);
var.type = 0;
var.address = nullptr;
}
}
// Boolean //
extern "C" void bool_set(Reference addr, Type::Boolean value)
{
*(reinterpret_cast<Type::Boolean*>(addr.address)) = value;
}
extern "C" Type::Boolean bool_get(Reference addr)
{
return *(reinterpret_cast<Type::Boolean*>(addr.address));
}
// Natural //
extern "C" void natural_set(Reference addr, Type::Natural value)
{
*(reinterpret_cast<Type::Natural*>(addr.address)) = value;
}
extern "C" Type::Natural natural_get(Reference addr)
{
return *(reinterpret_cast<Type::Natural*>(addr.address));
}
// Integer //
extern "C" void integer_set(Reference addr, Type::Integer value)
{
*(reinterpret_cast<Type::Integer*>(addr.address)) = value;
}
extern "C" Type::Integer integer_get(Reference addr)
{
return *(reinterpret_cast<Type::Integer*>(addr.address));
}
// Block //
extern "C" size_t block_length(Reference addr)
{
return type_key(type_inner(addr.type));
}
extern "C" uint8_t block_get(Reference addr, size_t index)
{
size_t length = type_key(type_inner(addr.type));
if(index < length) {
return reinterpret_cast<uint8_t*>(addr.address)[index];
}
return 0;
}
extern "C" void block_set(Reference addr, size_t index, uint8_t value)
{
size_t length = type_key(type_inner(addr.type));
if(index < length) {
reinterpret_cast<uint8_t*>(addr.address)[index] = value;
}
}
// Sequence //
extern "C" size_t sequence_length(Reference addr)
{
Type::Sequence& seq = *reinterpret_cast<Type::Sequence*>(addr.address);
return seq.data.length;
}
extern "C" uint8_t sequence_get(Reference addr, size_t index)
{
Type::Sequence& seq = *reinterpret_cast<Type::Sequence*>(addr.address);
if(index < seq.data.length) {
return *reinterpret_cast<uint8_t*>(rawlist_cell(seq.data, 1, index));
}
return 0;
}
extern "C" void sequence_clear(Reference addr)
{
Type::Sequence& seq = *reinterpret_cast<Type::Sequence*>(addr.address);
rawlist_clear(seq.data);
}
extern "C" void sequence_set(Reference addr, size_t index, uint8_t value)
{
Type::Sequence& seq = *reinterpret_cast<Type::Sequence*>(addr.address);
auto cell = reinterpret_cast<uint8_t*>(rawlist_cell(seq.data, 1, index));
if(cell != nullptr) {
*cell = value;
}
}
extern "C" void sequence_insert(Reference addr, size_t index, uint8_t value)
{
Type::Sequence& seq = *reinterpret_cast<Type::Sequence*>(addr.address);
auto cell = reinterpret_cast<uint8_t*>(rawlist_insert(seq.data, 1, index));
if(cell != nullptr) {
*cell = value;
}
}
extern "C" void sequence_reserve(Reference addr, size_t capacity)
{
Type::Sequence& seq = *reinterpret_cast<Type::Sequence*>(addr.address);
rawlist_reserve(seq.data, 1, capacity);
}
// Array //
extern "C" size_t array_length(Reference addr)
{
return type_key(type_inner(addr.type));
}
Reference array_cell(Reference addr, size_t index)
{
Reference result {0};
size_t length_n = type_inner(addr.type);
size_t length = type_key(length_n);
size_t type = type_inner(length_n);
size_t offset = type_size(type);
// validate for overflow
if(addr.address != nullptr && offset > 0 && index < length) {
result.type = type;
result.address = reinterpret_cast<void*>(reinterpret_cast<size_t>(addr.address) + (offset * index));
}
return result;
}
extern "C" Reference array_at(Reference addr, size_t index)
{
Reference result {0};
Reference cell = array_cell(addr, index);
if(cell.address != nullptr) {
if(type_key(cell.type) == Type::Tag::Varying) {
result = varying_get(cell);
}
else {
result = cell;
}
}
return result;
}
extern "C" void array_update(Reference addr, size_t index, Reference source)
{
Reference cell = array_cell(addr, index);
if(type_key(cell.type) == Type::Tag::Varying) {
varying_set(cell, source);
}
else {
copy(source, cell);
}
}
// List //
extern "C" size_t list_capacity(Reference addr)
{
return (*reinterpret_cast<Type::List*>(addr.address)).data.capacity;
}
extern "C" size_t list_length(Reference addr)
{
return (*reinterpret_cast<Type::List*>(addr.address)).data.length;
}
Reference list_cell(Reference addr, size_t index)
{
Reference result {0};
Type::List& list = *reinterpret_cast<Type::List*>(addr.address);
size_t inner = type_inner(addr.type);
size_t offset = type_size(inner);
// validate for overflow
if(list.data.data != nullptr && offset > 0 && index < list.data.capacity) {
result.type = inner;
result.address = rawlist_cell(list.data, offset, index);
}
return result;
}
extern "C" Reference list_at(Reference addr, size_t index)
{
Reference result {0};
Reference cell = list_cell(addr, index);
if(cell.address != nullptr) {
if(type_key(cell.type) == Type::Tag::Varying) {
result = *reinterpret_cast<Reference*>(cell.address);
} else {
result = cell;
}
}
return result;
}
/*extern "C" Reference list_first(Reference addr)
{
Reference result {0};
if(type_key(addr.type) == Type::Tag::List) {
auto& list = (*reinterpret_cast<Type::List*>(addr.address));
if(list.length > 0) {
result = list_at(addr, 0);
}
}
return result;
}*/
/*extern "C" Reference list_last(Reference addr)
{
Reference result {0};
if(type_key(addr.type) == Type::Tag::List) {
auto& list = (*reinterpret_cast<Type::List*>(addr.address));
if(list.length > 0) {
result = list_at(addr, list.length - 1);
}
}
return result;
}*/
extern "C" void list_clear(Reference addr)
{
drop(addr);
}
/*extern "C" void list_prepend(Reference addr, Reference source)
{
if(type_key(addr.type) == Type::Tag::List) {
size_t inner = type_inner(addr.type);
//size_t offset = type_size(inner);
// validate list can store value
if(type_key(inner) == Type::Tag::Varying || source.type == inner) {
auto& list = (*reinterpret_cast<Type::List*>(addr.address));
if(list.length == list.capacity) {
list_reserve(addr, list.capacity * 2);
}
// copy source to cell
list.length++;
}
}
}*/
/*extern "C" void list_append(Reference addr, Reference source)
{
if(type_key(addr.type) == Type::Tag::List) {
Type::List& list = *reinterpret_cast<Type::List*>(addr.address);
size_t inner = type_inner(addr.type);
//size_t offset = type_size(inner);
// validate list can store value
if(type_key(inner) == Type::Tag::Varying || source.type == inner) {
if(list.length == list.capacity) {
list_reserve(addr, list.capacity * 2);
}
// copy source to cell
list.length++;
}
}
}*/
extern "C" void list_insert(Reference addr, size_t index, Reference source)
{
auto& list = (*reinterpret_cast<Type::List*>(addr.address));
size_t inner = type_inner(addr.type);
size_t offset = type_size(inner);
if(index > list.data.length) { index = list.data.length; }
void* cell = rawlist_insert(list.data, offset, index);
if(type_key(inner) == Type::Tag::Varying) {
varying_set(list_cell(addr, index), source);
}
else {
copy(source, list_cell(addr, index));
}
}
extern "C" void list_update(Reference addr, size_t index, Reference source)
{
auto& list = (*reinterpret_cast<Type::List*>(addr.address));
if(index < list.data.length) {
size_t inner = type_inner(addr.type);
size_t offset = type_size(inner);
if(type_key(inner) == Type::Tag::Varying) {
varying_set(list_cell(addr, index), source);
}
else {
copy(source, list_cell(addr, index));
}
}
}
/*extern "C" void list_truncate(Reference addr, size_t maximum)
{
if(type_key(addr.type) == Type::Tag::List) {
//auto& list = (*reinterpret_cast<Type::List*>(addr.address));
}
}*/
/*extern "C" void list_shift(Reference addr)
{
if(type_key(addr.type) == Type::Tag::List) {
//auto& list = (*reinterpret_cast<Type::List*>(addr.address));
}
}*/
extern "C" void list_remove(Reference addr, size_t index)
{
auto& list = (*reinterpret_cast<Type::List*>(addr.address));
size_t inner = type_inner(addr.type);
size_t offset = type_size(inner);
drop(list_at(addr, index));
rawlist_remove(list.data, offset, index);
}
extern "C" void list_reserve(Reference addr, size_t capacity)
{
auto& list = (*reinterpret_cast<Type::List*>(addr.address));
size_t inner = type_inner(addr.type);
size_t offset = type_size(inner);
rawlist_reserve(list.data, offset, capacity);
}
/*extern "C" void list_resize(Reference addr, size_t length)
{
if(type_key(addr.type) == Type::Tag::List) {
//auto& list = (*reinterpret_cast<Type::List*>(addr.address));
}
}*/
// Schema //
extern "C" size_t schema_length(Reference addr)
{
auto& object = (*reinterpret_cast<Type::Schema*>(addr.address));
return object.data.length;
}
extern "C" size_t schema_add(Reference addr, size_t type_id)
{
auto& object = (*reinterpret_cast<Type::Schema*>(addr.address));
void* cell = rawlist_insert(object.data, sizeof(size_t), object.data.length);
*reinterpret_cast<size_t*>(cell) = type_id;
return object.data.length - 1;
}
extern "C" void schema_remove(Reference addr, size_t index)
{
auto& object = (*reinterpret_cast<Type::Schema*>(addr.address));
if(index < object.data.length) {
}
}
extern "C" void schema_reorder(Reference addr, size_t index_from, size_t index_to)
{
auto& object = (*reinterpret_cast<Type::Schema*>(addr.address));
if(index_from < object.data.length && index_to <= object.data.length) {
if(index_from > index_to) {
}
else {
}
}
}
extern "C" void schema_map(Reference addr, size_t key, size_t index)
{
auto& object = (*reinterpret_cast<Type::Schema*>(addr.address));
if(index < object.data.length) {
size_t find_index = 0;
for(; find_index < object.map.length; find_index++) {
auto cell = reinterpret_cast<Type::Schema::Mapping*>(rawlist_cell(object.map, sizeof(Type::Schema::Mapping), find_index));
if(cell != nullptr) {
if(cell->key == key) { break; }
}
}
// if key is not found, add new mapping
if(find_index == object.map.length) {
auto cell = reinterpret_cast<Type::Schema::Mapping*>(rawlist_insert(object.map, sizeof(Type::Schema::Mapping), object.map.length));
cell->key = key;
cell->index = index;
}
// otherwise, update existing key
else {
auto cell = reinterpret_cast<Type::Schema::Mapping*>(rawlist_cell(object.map, sizeof(Type::Schema::Mapping), find_index));
cell->index = index;
}
}
}
extern "C" void schema_unmap(Reference addr, size_t key)
{
auto& object = (*reinterpret_cast<Type::Schema*>(addr.address));
for(size_t i; i < object.map.length; i++) {
auto cell = reinterpret_cast<Type::Schema::Mapping*>(rawlist_cell(object.map, sizeof(Type::Schema::Mapping), i));
if(cell != nullptr) {
if(cell->key == key) {
rawlist_remove(object.map, sizeof(Type::Schema::Mapping), i);
return;
}
}
}
}
extern "C" size_t schema_index(Reference addr, size_t key)
{
auto& object = (*reinterpret_cast<Type::Schema*>(addr.address));
for(size_t i = 0; i < object.map.length; i++) {
auto cell = reinterpret_cast<Type::Schema::Mapping*>(rawlist_cell(object.map, sizeof(Type::Schema::Mapping), i));
if(cell != nullptr) {
if(cell->key == key) {
return cell->index;
}
}
}
return object.data.length;
}
extern "C" size_t schema_bind(Reference addr, size_t id)
{
Type::SchemaBinding binding {0};
auto& object = (*reinterpret_cast<Type::Schema*>(addr.address));
// prepare binding
binding.schema = object;
binding.binding = id;
for(size_t i = 0; i < object.data.length; ++i) {
size_t type_id = *reinterpret_cast<size_t*>(rawlist_cell(object.data, sizeof(size_t), i));
size_t size = type_size(type_id);
size_t alignment = size;
binding.alignment = std::max(alignment, binding.alignment);
size_t position = ((binding.size + (alignment - 1)) & ~(alignment - 1));
binding.size = size + position;
}
binding.size = ((binding.size + (binding.alignment - 1)) & ~(binding.alignment - 1));
// add binding to pool
//DB_SCHEMA.add(id, binding);
return id;
}