Add fetchSublist method to BinaryTable for improved data retrieval
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <shared_mutex>
|
||||
|
||||
// --- BT_Type Enum ---
|
||||
enum class BT_Type : int {
|
||||
@@ -127,10 +128,11 @@ struct BT_FreeListEntry {
|
||||
class BT_File {
|
||||
public:
|
||||
std::fstream file;
|
||||
mutable std::shared_mutex _rwlock;
|
||||
BT_File(const std::string& path) {
|
||||
std::unique_lock lock(_rwlock);
|
||||
file.open(path, std::ios::in | std::ios::out | std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
// Try to create the file if it doesn't exist
|
||||
file.open(path, std::ios::out | std::ios::binary);
|
||||
file.close();
|
||||
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");
|
||||
}
|
||||
void setPosition(int64_t pos) {
|
||||
std::unique_lock lock(_rwlock);
|
||||
file.seekp(pos);
|
||||
file.seekg(pos);
|
||||
}
|
||||
int64_t length() {
|
||||
std::shared_lock lock(_rwlock);
|
||||
auto cur = file.tellg();
|
||||
file.seekg(0, std::ios::end);
|
||||
int64_t len = file.tellg();
|
||||
@@ -150,20 +154,22 @@ public:
|
||||
return len;
|
||||
}
|
||||
std::vector<uint8_t> read(int size) {
|
||||
std::shared_lock lock(_rwlock);
|
||||
std::vector<uint8_t> buf(size);
|
||||
file.read(reinterpret_cast<char*>(buf.data()), size);
|
||||
return buf;
|
||||
}
|
||||
void write(const std::vector<uint8_t>& buf) {
|
||||
std::unique_lock lock(_rwlock);
|
||||
file.write(reinterpret_cast<const char*>(buf.data()), buf.size());
|
||||
}
|
||||
int readInt(int size = 4) {
|
||||
std::shared_lock lock(_rwlock);
|
||||
std::vector<uint8_t> buf = read(size);
|
||||
int result = 0;
|
||||
for (int i = size - 1; i >= 0; --i) {
|
||||
result = (result << 8) | buf[i];
|
||||
}
|
||||
// Sign extend if MSB is set
|
||||
int signBit = 1 << (size * 8 - 1);
|
||||
if (result & signBit) {
|
||||
result -= 1 << (size * 8);
|
||||
@@ -171,6 +177,7 @@ public:
|
||||
return result;
|
||||
}
|
||||
void writeInt(int value, int size = 4) {
|
||||
std::unique_lock lock(_rwlock);
|
||||
std::vector<uint8_t> buf(size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
buf[i] = (value >> (i * 8)) & 0xFF;
|
||||
@@ -178,6 +185,7 @@ public:
|
||||
write(buf);
|
||||
}
|
||||
BT_Pointer readPointer() {
|
||||
std::shared_lock lock(_rwlock);
|
||||
int64_t addr = 0;
|
||||
std::vector<uint8_t> buf = read(8);
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
@@ -186,6 +194,7 @@ public:
|
||||
return BT_Pointer(addr);
|
||||
}
|
||||
void writePointer(const BT_Pointer& ptr) {
|
||||
std::unique_lock lock(_rwlock);
|
||||
int64_t addr = ptr.address;
|
||||
std::vector<uint8_t> buf(8);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
@@ -194,33 +203,39 @@ public:
|
||||
write(buf);
|
||||
}
|
||||
float readFloat32() {
|
||||
std::shared_lock lock(_rwlock);
|
||||
std::vector<uint8_t> buf = read(4);
|
||||
float val;
|
||||
std::memcpy(&val, buf.data(), 4);
|
||||
return val;
|
||||
}
|
||||
void writeFloat32(float value) {
|
||||
std::unique_lock lock(_rwlock);
|
||||
uint8_t buf[4];
|
||||
std::memcpy(buf, &value, 4);
|
||||
write(std::vector<uint8_t>(buf, buf + 4));
|
||||
}
|
||||
double readFloat64() {
|
||||
std::shared_lock lock(_rwlock);
|
||||
std::vector<uint8_t> buf = read(8);
|
||||
double val;
|
||||
std::memcpy(&val, buf.data(), 8);
|
||||
return val;
|
||||
}
|
||||
void writeFloat64(double value) {
|
||||
std::unique_lock lock(_rwlock);
|
||||
uint8_t buf[8];
|
||||
std::memcpy(buf, &value, 8);
|
||||
write(std::vector<uint8_t>(buf, buf + 8));
|
||||
}
|
||||
uint8_t readByte() {
|
||||
std::shared_lock lock(_rwlock);
|
||||
char c;
|
||||
file.read(&c, 1);
|
||||
return static_cast<uint8_t>(c);
|
||||
}
|
||||
void writeByte(uint8_t b) {
|
||||
std::unique_lock lock(_rwlock);
|
||||
char c = static_cast<char>(b);
|
||||
file.write(&c, 1);
|
||||
}
|
||||
@@ -254,6 +269,7 @@ public:
|
||||
int size();
|
||||
BT_Type elementType();
|
||||
std::string to_string(bool readValues = false);
|
||||
std::vector<BT_Value> fetchSublist(int start = 0, int end = -1);
|
||||
};
|
||||
|
||||
// --- binaryDump utility ---
|
||||
@@ -489,6 +505,29 @@ inline std::string BT_UniformArray::to_string(bool readValues) {
|
||||
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 ---
|
||||
inline std::vector<uint8_t> encodeFreeList(const std::vector<BT_FreeListEntry>& freeList) {
|
||||
std::vector<uint8_t> buffer;
|
||||
|
||||
@@ -363,6 +363,34 @@ class BT_UniformArray extends BT_Reference {
|
||||
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
|
||||
int get size {
|
||||
|
||||
@@ -875,6 +903,12 @@ void main() {
|
||||
table["int_array"].addAll([420, 69, 1337, 1738]);
|
||||
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 readback2 = table["float_array"];
|
||||
var readback3 = table["empty"];
|
||||
|
||||
Reference in New Issue
Block a user