Files
SweepStore/cpp/binary_table.h

305 lines
9.3 KiB
C++
Raw Blame History

/*
/$$$$$$ /$$ /$$ /$$$$$$$ /$$$$$$$$ /$$ /$$ /$$$$$ /$$$$$$ /$$ /$$ /$$$$$$$$ /$$$$$$$$
|_ $$_/| $$$ /$$$| $$__ $$| $$_____/| $$$ | $$ |__ $$|_ $$_/ | $$$ | $$| $$_____/|__ $$__/
| $$ | $$$$ /$$$$| $$ \ $$| $$ | $$$$| $$ | $$ | $$ | $$$$| $$| $$ | $$
| $$ | $$ $$/$$ $$| $$$$$$$ | $$$$$ | $$ $$ $$ | $$ | $$ | $$ $$ $$| $$$$$ | $$
| $$ | $$ $$$| $$| $$__ $$| $$__/ | $$ $$$$ /$$ | $$ | $$ | $$ $$$$| $$__/ | $$
| $$ | $$\ $ | $$| $$ \ $$| $$ | $$\ $$$| $$ | $$ | $$ | $$\ $$$| $$ | $$
/$$$$$$| $$ \/ | $$| $$$$$$$/| $$$$$$$$| $$ \ $$| $$$$$$/ /$$$$$$ /$$| $$ \ $$| $$$$$$$$ | $$
|______/|__/ |__/|_______/ |________/|__/ \__/ \______/ |______/|__/|__/ \__/|________/ |__/
<EFBFBD> 2025-26 by Benjamin Watt of IMBENJI.NET LIMITED - All rights reserved.
Use of this source code is governed by the Business Source License 1.1 that can be found in the LICENSE file.
This file is part of the SweepStore (formerly Binary Table) package for C++.
*/
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include <unordered_map>
#include <fstream>
#include <variant>
#include <memory>
#include <stdexcept>
#include <type_traits>
#include <functional>
#include <iostream>
// Debug control - comment out this line to disable all debug output
// #define ENABLE_DEBUG 1
#ifdef ENABLE_DEBUG
#define DEBUG_PRINT(x) std::cout << x
#define DEBUG_PRINTLN(x) std::cout << x << std::endl
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#endif
namespace bt {
// Forward declarations
class BinaryTable;
class BT_Reference;
template<typename T> class BT_UniformArray;
// Type enumeration matching Dart version
enum class BT_Type : uint8_t {
POINTER = 0,
ADDRESS_TABLE = 1,
INTEGER = 2,
FLOAT = 3,
STRING = 4,
INTEGER_ARRAY = 5,
FLOAT_ARRAY = 6
};
// Size mapping for types
constexpr int getTypeSize(BT_Type type) {
switch (type) {
case BT_Type::POINTER: return 8;
case BT_Type::ADDRESS_TABLE: return -1;
case BT_Type::INTEGER: return 4;
case BT_Type::FLOAT: return 4;
case BT_Type::STRING: return -1;
case BT_Type::INTEGER_ARRAY: return -1;
case BT_Type::FLOAT_ARRAY: return -1;
}
return -1;
}
// Check if type is array type
constexpr bool isArrayType(BT_Type type) {
return type == BT_Type::INTEGER_ARRAY || type == BT_Type::FLOAT_ARRAY;
}
// Type deduction helpers
template<typename T>
constexpr BT_Type getTypeFromValue() {
if constexpr (std::is_same_v<T, int32_t> || std::is_same_v<T, int>) {
return BT_Type::INTEGER;
} else if constexpr (std::is_same_v<T, float>) {
return BT_Type::FLOAT;
} else if constexpr (std::is_same_v<T, std::string>) {
return BT_Type::STRING;
} else if constexpr (std::is_same_v<T, std::vector<int32_t>> || std::is_same_v<T, std::vector<int>>) {
return BT_Type::INTEGER_ARRAY;
} else if constexpr (std::is_same_v<T, std::vector<float>>) {
return BT_Type::FLOAT_ARRAY;
} else {
static_assert(sizeof(T) == 0, "Unsupported type");
}
}
// Pointer class
class BT_Pointer {
private:
int64_t address_;
public:
explicit BT_Pointer(int64_t address = -1) : address_(address) {}
bool isNull() const { return address_ == -1; }
int64_t address() const { return address_; }
bool operator==(const BT_Pointer& other) const {
return address_ == other.address_;
}
bool operator!=(const BT_Pointer& other) const {
return !(*this == other);
}
};
// Null pointer constant
const BT_Pointer BT_Null{-1};
// Free list entry
struct BT_FreeListEntry {
BT_Pointer pointer;
int32_t size;
BT_FreeListEntry(BT_Pointer ptr, int32_t sz) : pointer(ptr), size(sz) {}
};
// Value encoding functions
std::vector<uint8_t> encodeValue(const int32_t& value);
std::vector<uint8_t> encodeValue(const float& value);
std::vector<uint8_t> encodeValue(const std::string& value);
std::vector<uint8_t> encodeValue(const std::vector<int32_t>& value);
std::vector<uint8_t> encodeValue(const std::vector<float>& value);
// Template wrapper for encoding
template<typename T>
std::vector<uint8_t> encodeValue(const T& value) {
return encodeValue(value);
}
// Reference class for handling stored values
class BT_Reference {
protected:
BinaryTable* table_;
BT_Pointer pointer_;
public:
BT_Reference(BinaryTable* table, BT_Pointer pointer);
template<typename T>
T decodeValue();
int32_t size() const;
BT_Type getType() const;
bool isNull() const { return pointer_.isNull(); }
BT_Pointer getPointer() const { return pointer_; }
};
// Uniform array class template
template<typename T>
class BT_UniformArray : public BT_Reference {
public:
BT_UniformArray(BinaryTable* table, BT_Pointer pointer) : BT_Reference(table, pointer) {}
int32_t length() const;
T operator[](int32_t index) const;
void set(int32_t index, const T& value);
void add(const T& value);
void addAll(const std::vector<T>& values);
std::vector<T> fetchSublist(int32_t start = 0, int32_t end = -1);
};
// Main BinaryTable class
class BinaryTable {
private:
FILE* file_;
std::string filePath_;
// Free list management
bool freeListLifted_;
std::vector<BT_FreeListEntry> freeListCache_;
// Internal methods
std::unordered_map<int64_t, BT_Pointer> getAddressTable();
void setAddressTable(const std::unordered_map<int64_t, BT_Pointer>& table);
std::vector<BT_FreeListEntry> getFreeList();
void setFreeList(const std::vector<BT_FreeListEntry>& list);
int64_t hashString(const std::string& str) const;
void truncateFile(int64_t newSize);
void antiFreeListScope(std::function<void()> fn);
void free(BT_Pointer pointer, int32_t size);
BT_Pointer alloc(int32_t size);
// File I/O helpers
int32_t readInt32(int64_t position);
float readFloat32(int64_t position);
int64_t readInt64(int64_t position);
uint8_t readByte(int64_t position);
std::vector<uint8_t> readBytes(int64_t position, int32_t count);
void writeInt32(int64_t position, int32_t value);
void writeFloat32(int64_t position, float value);
void writeInt64(int64_t position, int64_t value);
void writeByte(int64_t position, uint8_t value);
void writeBytes(int64_t position, const std::vector<uint8_t>& data);
public:
explicit BinaryTable(const std::string& path);
~BinaryTable();
void initialize();
// Memory management
void liftFreeList();
void dropFreeList();
// Data operations
template<typename T>
void set(const std::string& key, const T& value);
template<typename T>
T get(const std::string& key);
BT_Reference getReference(const std::string& key);
template<typename T>
BT_UniformArray<T> getArray(const std::string& key);
void remove(const std::string& key);
void truncate();
// Debug methods
void debugAddressTable(const std::string& context = "");
// File access for reference classes
friend class BT_Reference;
template<typename T> friend class BT_UniformArray;
int64_t getFileLength();
void setFilePosition(int64_t position);
};
// Template specializations for decodeValue
template<> int32_t BT_Reference::decodeValue<int32_t>();
template<> float BT_Reference::decodeValue<float>();
template<> std::string BT_Reference::decodeValue<std::string>();
template<> std::vector<int32_t> BT_Reference::decodeValue<std::vector<int32_t>>();
template<> std::vector<float> BT_Reference::decodeValue<std::vector<float>>();
template<> BT_UniformArray<int32_t> BT_Reference::decodeValue<BT_UniformArray<int32_t>>();
template<> BT_UniformArray<float> BT_Reference::decodeValue<BT_UniformArray<float>>();
// Template method implementations for BinaryTable
template<typename T>
void BinaryTable::set(const std::string& key, const T& value) {
antiFreeListScope([&]() {
auto addressTable = getAddressTable();
int64_t keyHash = hashString(key);
if (addressTable.find(keyHash) != addressTable.end()) {
throw std::runtime_error("Key already exists");
}
auto valueBuffer = encodeValue(value);
BT_Pointer valueAddress = alloc(static_cast<int32_t>(valueBuffer.size()));
writeBytes(valueAddress.address(), valueBuffer);
addressTable[keyHash] = valueAddress;
setAddressTable(addressTable);
});
}
template<typename T>
T BinaryTable::get(const std::string& key) {
auto addressTable = getAddressTable();
int64_t keyHash = hashString(key);
auto it = addressTable.find(keyHash);
if (it == addressTable.end()) {
throw std::runtime_error("Key does not exist");
}
BT_Reference valueRef(this, it->second);
return valueRef.decodeValue<T>();
}
template<typename T>
BT_UniformArray<T> BinaryTable::getArray(const std::string& key) {
auto addressTable = getAddressTable();
int64_t keyHash = hashString(key);
auto it = addressTable.find(keyHash);
if (it == addressTable.end()) {
throw std::runtime_error("Key does not exist");
}
return BT_UniformArray<T>(this, it->second);
}
} // namespace bt