#include "lib.h" #include "rawlist.cc" TypeTree DB_TYPE; NameTree DB_NAME; //Pool DB_SCHEMA; Pool 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(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(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(addr.address); if(var.address != nullptr) { drop(var); } var.type = 0; var.address = nullptr; } break; case Type::Tag::Sequence: { auto& seq = *reinterpret_cast(addr.address); rawlist_clear(seq.data); } break; case Type::Tag::List: { Type::List& list = *reinterpret_cast(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(src.address); } // prepare destination for varying data if(type_key(dst.type) == Type::Tag::Varying) { auto& dest_ref = *reinterpret_cast(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(source.address); auto& dst_list = *reinterpret_cast(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(addr.address); return result; } extern "C" void varying_set(Reference addr, Reference source) { Reference& var = *reinterpret_cast(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(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(addr.address)) = value; } extern "C" Type::Boolean bool_get(Reference addr) { return *(reinterpret_cast(addr.address)); } // Natural // extern "C" void natural_set(Reference addr, Type::Natural value) { *(reinterpret_cast(addr.address)) = value; } extern "C" Type::Natural natural_get(Reference addr) { return *(reinterpret_cast(addr.address)); } // Integer // extern "C" void integer_set(Reference addr, Type::Integer value) { *(reinterpret_cast(addr.address)) = value; } extern "C" Type::Integer integer_get(Reference addr) { return *(reinterpret_cast(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(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(addr.address)[index] = value; } } // Sequence // extern "C" size_t sequence_length(Reference addr) { Type::Sequence& seq = *reinterpret_cast(addr.address); return seq.data.length; } extern "C" uint8_t sequence_get(Reference addr, size_t index) { Type::Sequence& seq = *reinterpret_cast(addr.address); if(index < seq.data.length) { return *reinterpret_cast(rawlist_cell(seq.data, 1, index)); } return 0; } extern "C" void sequence_clear(Reference addr) { Type::Sequence& seq = *reinterpret_cast(addr.address); rawlist_clear(seq.data); } extern "C" void sequence_set(Reference addr, size_t index, uint8_t value) { Type::Sequence& seq = *reinterpret_cast(addr.address); auto cell = reinterpret_cast(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(addr.address); auto cell = reinterpret_cast(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(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(reinterpret_cast(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(addr.address)).data.capacity; } extern "C" size_t list_length(Reference addr) { return (*reinterpret_cast(addr.address)).data.length; } Reference list_cell(Reference addr, size_t index) { Reference result {0}; Type::List& list = *reinterpret_cast(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(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(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(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(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(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(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(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(addr.address)); } }*/ /*extern "C" void list_shift(Reference addr) { if(type_key(addr.type) == Type::Tag::List) { //auto& list = (*reinterpret_cast(addr.address)); } }*/ extern "C" void list_remove(Reference addr, size_t index) { auto& list = (*reinterpret_cast(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(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(addr.address)); } }*/ // Schema // extern "C" size_t schema_length(Reference addr) { auto& object = (*reinterpret_cast(addr.address)); return object.data.length; } extern "C" size_t schema_add(Reference addr, size_t type_id) { auto& object = (*reinterpret_cast(addr.address)); void* cell = rawlist_insert(object.data, sizeof(size_t), object.data.length); *reinterpret_cast(cell) = type_id; return object.data.length - 1; } extern "C" void schema_remove(Reference addr, size_t index) { auto& object = (*reinterpret_cast(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(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(addr.address)); if(index < object.data.length) { size_t find_index = 0; for(; find_index < object.map.length; find_index++) { auto cell = reinterpret_cast(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(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(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(addr.address)); for(size_t i; i < object.map.length; i++) { auto cell = reinterpret_cast(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(addr.address)); for(size_t i = 0; i < object.map.length; i++) { auto cell = reinterpret_cast(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(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(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; }