/* /$$$$$$ /$$ /$$ /$$$$$$$ /$$$$$$$$ /$$ /$$ /$$$$$ /$$$$$$ /$$ /$$ /$$$$$$$$ /$$$$$$$$ |_ $$_/| $$$ /$$$| $$__ $$| $$_____/| $$$ | $$ |__ $$|_ $$_/ | $$$ | $$| $$_____/|__ $$__/ | $$ | $$$$ /$$$$| $$ \ $$| $$ | $$$$| $$ | $$ | $$ | $$$$| $$| $$ | $$ | $$ | $$ $$/$$ $$| $$$$$$$ | $$$$$ | $$ $$ $$ | $$ | $$ | $$ $$ $$| $$$$$ | $$ | $$ | $$ $$$| $$| $$__ $$| $$__/ | $$ $$$$ /$$ | $$ | $$ | $$ $$$$| $$__/ | $$ | $$ | $$\ $ | $$| $$ \ $$| $$ | $$\ $$$| $$ | $$ | $$ | $$\ $$$| $$ | $$ /$$$$$$| $$ \/ | $$| $$$$$$$/| $$$$$$$$| $$ \ $$| $$$$$$/ /$$$$$$ /$$| $$ \ $$| $$$$$$$$ | $$ |______/|__/ |__/|_______/ |________/|__/ \__/ \______/ |______/|__/|__/ \__/|________/ |__/ � 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 #include #include #include #include #include #include #include #include #include #include // 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 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 constexpr BT_Type getTypeFromValue() { if constexpr (std::is_same_v || std::is_same_v) { return BT_Type::INTEGER; } else if constexpr (std::is_same_v) { return BT_Type::FLOAT; } else if constexpr (std::is_same_v) { return BT_Type::STRING; } else if constexpr (std::is_same_v> || std::is_same_v>) { return BT_Type::INTEGER_ARRAY; } else if constexpr (std::is_same_v>) { 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 encodeValue(const int32_t& value); std::vector encodeValue(const float& value); std::vector encodeValue(const std::string& value); std::vector encodeValue(const std::vector& value); std::vector encodeValue(const std::vector& value); // Template wrapper for encoding template std::vector 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 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 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& values); std::vector 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 freeListCache_; // Internal methods std::unordered_map getAddressTable(); void setAddressTable(const std::unordered_map& table); std::vector getFreeList(); void setFreeList(const std::vector& list); int64_t hashString(const std::string& str) const; void truncateFile(int64_t newSize); void antiFreeListScope(std::function 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 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& data); public: explicit BinaryTable(const std::string& path); ~BinaryTable(); void initialize(); // Memory management void liftFreeList(); void dropFreeList(); // Data operations template void set(const std::string& key, const T& value); template T get(const std::string& key); BT_Reference getReference(const std::string& key); template BT_UniformArray 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 friend class BT_UniformArray; int64_t getFileLength(); void setFilePosition(int64_t position); }; // Template specializations for decodeValue template<> int32_t BT_Reference::decodeValue(); template<> float BT_Reference::decodeValue(); template<> std::string BT_Reference::decodeValue(); template<> std::vector BT_Reference::decodeValue>(); template<> std::vector BT_Reference::decodeValue>(); template<> BT_UniformArray BT_Reference::decodeValue>(); template<> BT_UniformArray BT_Reference::decodeValue>(); // Template method implementations for BinaryTable template 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(valueBuffer.size())); writeBytes(valueAddress.address(), valueBuffer); addressTable[keyHash] = valueAddress; setAddressTable(addressTable); }); } template 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(); } template BT_UniformArray 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(this, it->second); } } // namespace bt