Add fetchSublist method to BinaryTable for improved data retrieval

This commit is contained in:
ImBenji
2025-09-18 15:08:57 +01:00
parent 3ae088f518
commit cf983c8d96
2 changed files with 75 additions and 2 deletions

View File

@@ -11,6 +11,7 @@
#include <algorithm> #include <algorithm>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <shared_mutex>
// --- BT_Type Enum --- // --- BT_Type Enum ---
enum class BT_Type : int { enum class BT_Type : int {
@@ -127,10 +128,11 @@ struct BT_FreeListEntry {
class BT_File { class BT_File {
public: public:
std::fstream file; std::fstream file;
mutable std::shared_mutex _rwlock;
BT_File(const std::string& path) { BT_File(const std::string& path) {
std::unique_lock lock(_rwlock);
file.open(path, std::ios::in | std::ios::out | std::ios::binary); file.open(path, std::ios::in | std::ios::out | std::ios::binary);
if (!file.is_open()) { if (!file.is_open()) {
// Try to create the file if it doesn't exist
file.open(path, std::ios::out | std::ios::binary); file.open(path, std::ios::out | std::ios::binary);
file.close(); file.close();
file.open(path, std::ios::in | std::ios::out | std::ios::binary); file.open(path, std::ios::in | std::ios::out | std::ios::binary);
@@ -138,10 +140,12 @@ public:
if (!file.is_open()) throw std::runtime_error("Failed to open file"); if (!file.is_open()) throw std::runtime_error("Failed to open file");
} }
void setPosition(int64_t pos) { void setPosition(int64_t pos) {
std::unique_lock lock(_rwlock);
file.seekp(pos); file.seekp(pos);
file.seekg(pos); file.seekg(pos);
} }
int64_t length() { int64_t length() {
std::shared_lock lock(_rwlock);
auto cur = file.tellg(); auto cur = file.tellg();
file.seekg(0, std::ios::end); file.seekg(0, std::ios::end);
int64_t len = file.tellg(); int64_t len = file.tellg();
@@ -150,20 +154,22 @@ public:
return len; return len;
} }
std::vector<uint8_t> read(int size) { std::vector<uint8_t> read(int size) {
std::shared_lock lock(_rwlock);
std::vector<uint8_t> buf(size); std::vector<uint8_t> buf(size);
file.read(reinterpret_cast<char*>(buf.data()), size); file.read(reinterpret_cast<char*>(buf.data()), size);
return buf; return buf;
} }
void write(const std::vector<uint8_t>& buf) { void write(const std::vector<uint8_t>& buf) {
std::unique_lock lock(_rwlock);
file.write(reinterpret_cast<const char*>(buf.data()), buf.size()); file.write(reinterpret_cast<const char*>(buf.data()), buf.size());
} }
int readInt(int size = 4) { int readInt(int size = 4) {
std::shared_lock lock(_rwlock);
std::vector<uint8_t> buf = read(size); std::vector<uint8_t> buf = read(size);
int result = 0; int result = 0;
for (int i = size - 1; i >= 0; --i) { for (int i = size - 1; i >= 0; --i) {
result = (result << 8) | buf[i]; result = (result << 8) | buf[i];
} }
// Sign extend if MSB is set
int signBit = 1 << (size * 8 - 1); int signBit = 1 << (size * 8 - 1);
if (result & signBit) { if (result & signBit) {
result -= 1 << (size * 8); result -= 1 << (size * 8);
@@ -171,6 +177,7 @@ public:
return result; return result;
} }
void writeInt(int value, int size = 4) { void writeInt(int value, int size = 4) {
std::unique_lock lock(_rwlock);
std::vector<uint8_t> buf(size); std::vector<uint8_t> buf(size);
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
buf[i] = (value >> (i * 8)) & 0xFF; buf[i] = (value >> (i * 8)) & 0xFF;
@@ -178,6 +185,7 @@ public:
write(buf); write(buf);
} }
BT_Pointer readPointer() { BT_Pointer readPointer() {
std::shared_lock lock(_rwlock);
int64_t addr = 0; int64_t addr = 0;
std::vector<uint8_t> buf = read(8); std::vector<uint8_t> buf = read(8);
for (int i = 7; i >= 0; --i) { for (int i = 7; i >= 0; --i) {
@@ -186,6 +194,7 @@ public:
return BT_Pointer(addr); return BT_Pointer(addr);
} }
void writePointer(const BT_Pointer& ptr) { void writePointer(const BT_Pointer& ptr) {
std::unique_lock lock(_rwlock);
int64_t addr = ptr.address; int64_t addr = ptr.address;
std::vector<uint8_t> buf(8); std::vector<uint8_t> buf(8);
for (int i = 0; i < 8; ++i) { for (int i = 0; i < 8; ++i) {
@@ -194,33 +203,39 @@ public:
write(buf); write(buf);
} }
float readFloat32() { float readFloat32() {
std::shared_lock lock(_rwlock);
std::vector<uint8_t> buf = read(4); std::vector<uint8_t> buf = read(4);
float val; float val;
std::memcpy(&val, buf.data(), 4); std::memcpy(&val, buf.data(), 4);
return val; return val;
} }
void writeFloat32(float value) { void writeFloat32(float value) {
std::unique_lock lock(_rwlock);
uint8_t buf[4]; uint8_t buf[4];
std::memcpy(buf, &value, 4); std::memcpy(buf, &value, 4);
write(std::vector<uint8_t>(buf, buf + 4)); write(std::vector<uint8_t>(buf, buf + 4));
} }
double readFloat64() { double readFloat64() {
std::shared_lock lock(_rwlock);
std::vector<uint8_t> buf = read(8); std::vector<uint8_t> buf = read(8);
double val; double val;
std::memcpy(&val, buf.data(), 8); std::memcpy(&val, buf.data(), 8);
return val; return val;
} }
void writeFloat64(double value) { void writeFloat64(double value) {
std::unique_lock lock(_rwlock);
uint8_t buf[8]; uint8_t buf[8];
std::memcpy(buf, &value, 8); std::memcpy(buf, &value, 8);
write(std::vector<uint8_t>(buf, buf + 8)); write(std::vector<uint8_t>(buf, buf + 8));
} }
uint8_t readByte() { uint8_t readByte() {
std::shared_lock lock(_rwlock);
char c; char c;
file.read(&c, 1); file.read(&c, 1);
return static_cast<uint8_t>(c); return static_cast<uint8_t>(c);
} }
void writeByte(uint8_t b) { void writeByte(uint8_t b) {
std::unique_lock lock(_rwlock);
char c = static_cast<char>(b); char c = static_cast<char>(b);
file.write(&c, 1); file.write(&c, 1);
} }
@@ -254,6 +269,7 @@ public:
int size(); int size();
BT_Type elementType(); BT_Type elementType();
std::string to_string(bool readValues = false); std::string to_string(bool readValues = false);
std::vector<BT_Value> fetchSublist(int start = 0, int end = -1);
}; };
// --- binaryDump utility --- // --- binaryDump utility ---
@@ -489,6 +505,29 @@ inline std::string BT_UniformArray::to_string(bool readValues) {
return oss.str(); return oss.str();
} }
inline std::vector<BT_Value> BT_UniformArray::fetchSublist(int start, int end) {
int len = length();
if (len == 0) return {};
if (start < 0 || start > len) throw std::out_of_range("fetchSublist: start out of range");
if (end == -1) end = len;
if (end < start || end > len) throw std::out_of_range("fetchSublist: end out of range");
BT_Type type = elementType();
if (BT_Type_size(type) == -1) throw std::runtime_error("Types with variable size are not supported in uniform arrays");
int elemSize = 1 + BT_Type_size(type);
int bufferStart = 1 + 4 + start * elemSize;
int bufferEnd = 1 + 4 + end * elemSize;
int bufferSize = bufferEnd - bufferStart;
_table->_file->setPosition(_pointer.address + bufferStart);
std::vector<uint8_t> buffer = _table->_file->read(bufferSize);
std::vector<BT_Value> values;
for (int i = 0; i < (end - start); ++i) {
int offset = i * elemSize;
BT_Reference itemRef(_table, BT_Pointer((_pointer.address + bufferStart) + offset));
values.push_back(itemRef.decodeValue());
}
return values;
}
// --- Free List Encoding/Decoding --- // --- Free List Encoding/Decoding ---
inline std::vector<uint8_t> encodeFreeList(const std::vector<BT_FreeListEntry>& freeList) { inline std::vector<uint8_t> encodeFreeList(const std::vector<BT_FreeListEntry>& freeList) {
std::vector<uint8_t> buffer; std::vector<uint8_t> buffer;

View File

@@ -363,6 +363,34 @@ class BT_UniformArray extends BT_Reference {
addAll([value]); addAll([value]);
} }
List<dynamic> fetchSublist([int start = 0, int end = -1]) {
// Read the full array by loading the full buffer of only whats needed
BT_Type? type = elementType;
if (type == null) {
return [];
}
if (type.size == -1) {
throw Exception("Types with variable size are not supported in uniform arrays. Use a non-uniform array instead.");
}
end = end == -1 ? length : end;
int bufferStart = 1 + 4 + start * (1 + type.size);
int bufferEnd = 1 + 4 + end * (1 + type.size);
int bufferSize = bufferEnd - bufferStart;
_table._file.setPositionSync(_pointer.address + bufferStart);
List<int> buffer = _table._file.readSync(bufferSize).toList();
List<dynamic> values = [];
for (int i = 0; i < (end - start); i++) {
int offset = i * (1 + type.size);
BT_Reference itemRef = BT_Reference(_table, BT_Pointer((_pointer.address + bufferStart) + offset));
values.add(itemRef.decodeValue());
}
return values;
}
@override @override
int get size { int get size {
@@ -875,6 +903,12 @@ void main() {
table["int_array"].addAll([420, 69, 1337, 1738]); table["int_array"].addAll([420, 69, 1337, 1738]);
table["float_array"].addAll([6.5, 7.5, 8.5]); table["float_array"].addAll([6.5, 7.5, 8.5]);
// Test the full read method
var intArrayFull = table["int_array"].fetchSublist(0, 3);
var floatArrayFull = table["float_array"].fetchSublist(0, 2);
print("Full read int_array (0-3): $intArrayFull");
print("Full read float_array (0-2): $floatArrayFull");
var readback1 = table["int_array"]; var readback1 = table["int_array"];
var readback2 = table["float_array"]; var readback2 = table["float_array"];
var readback3 = table["empty"]; var readback3 = table["empty"];