#pragma once #include #include #include #include #include #include #include #include #include #include #include // Toggleable debug printing via preprocessor #ifndef SWEEPSTORE_DEBUG #define SWEEPSTORE_DEBUG 0 #endif #if SWEEPSTORE_DEBUG #define debugPrint(msg) std::cout << msg << std::endl #else #define debugPrint(msg) ((void)0) #endif inline void print(const char* message) { // Print the message to the console std::cout << message << std::endl; } inline std::string trim(const std::string& str) { size_t start = str.find_first_not_of(" \t\n\r"); if (start == std::string::npos) return ""; // all whitespace size_t end = str.find_last_not_of(" \t\n\r"); return str.substr(start, end - start + 1); } inline std::string binaryDump(const std::vector& data) { std::ostringstream buffer; for (size_t i = 0; i < data.size(); i += 16) { // Address buffer << "0x" << std::setfill('0') << std::setw(4) << std::uppercase << std::hex << i << " (" << std::dec << std::setw(4) << i << ") | "; // Hex bytes for (size_t j = 0; j < 16; j++) { if (i + j < data.size()) { buffer << std::setfill('0') << std::setw(2) << std::uppercase << std::hex << static_cast(data[i + j]) << " "; } else { buffer << " "; } } buffer << " | "; // Integer representation for (size_t j = 0; j < 16; j++) { if (i + j < data.size()) { buffer << std::dec << std::setw(3) << static_cast(data[i + j]) << " "; } else { buffer << " "; } } buffer << " | "; // ASCII representation for (size_t j = 0; j < 16; j++) { if (i + j < data.size()) { uint8_t byte = data[i + j]; if (byte >= 32 && byte <= 126) { buffer << static_cast(byte); } else { buffer << '.'; } } } buffer << " | "; if (i + 16 < data.size()) buffer << '\n'; } return buffer.str(); } inline std::vector loadFile(const std::string& filename) { std::ifstream file(filename, std::ios::binary | std::ios::ate); if (!file) { throw std::runtime_error("Failed to open file: " + filename); } // Get file size std::streamsize size = file.tellg(); file.seekg(0, std::ios::beg); // Pre-allocate vector and read std::vector buffer(size); if (!file.read(reinterpret_cast(buffer.data()), size)) { throw std::runtime_error("Failed to read file: " + filename); } return buffer; } enum class Endian { Little, Big }; class RandomAccessMemory { private: std::vector _buffer; size_t _position; public: // Constructors RandomAccessMemory() : _position(0) {} explicit RandomAccessMemory(const std::vector& initialData) : _buffer(initialData), _position(0) {} explicit RandomAccessMemory(const uint8_t* data, size_t size) : _buffer(data, data + size), _position(0) {} // Position management size_t positionSync() const { return _position; } void setPositionSync(size_t position) { _position = position; } size_t length() const { return _buffer.size(); } // Read bytes std::vector readSync(size_t count) { if (_position + count > _buffer.size()) { throw std::range_error("Not enough bytes to read"); } std::vector result(_buffer.begin() + _position, _buffer.begin() + _position + count); _position += count; return result; } // Write bytes void writeFromSync(const std::vector& bytes) { for (size_t i = 0; i < bytes.size(); i++) { if (_position + i >= _buffer.size()) { _buffer.push_back(bytes[i]); } else { _buffer[_position + i] = bytes[i]; } } _position += bytes.size(); } // Read/Write Int Dynamic int64_t readIntSync(int size = 4, Endian endianness = Endian::Little) { if (size < 1 || size > 8) { throw std::invalid_argument("Size must be between 1 and 8 bytes"); } std::vector bytes = readSync(size); // Build integer from bytes with proper endianness int64_t result = 0; if (endianness == Endian::Little) { for (int i = size - 1; i >= 0; i--) { result = (result << 8) | bytes[i]; } } else { for (int i = 0; i < size; i++) { result = (result << 8) | bytes[i]; } } // Sign extend if MSB is set int64_t signBit = 1LL << (size * 8 - 1); if (result & signBit) { result -= 1LL << (size * 8); } return result; } uint64_t readUIntSync(int size = 4, Endian endianness = Endian::Little) { if (size < 1 || size > 8) { throw std::invalid_argument("Size must be between 1 and 8 bytes"); } std::vector bytes = readSync(size); // Build integer from bytes with proper endianness uint64_t result = 0; if (endianness == Endian::Little) { for (int i = size - 1; i >= 0; i--) { result = (result << 8) | bytes[i]; } } else { for (int i = 0; i < size; i++) { result = (result << 8) | bytes[i]; } } return result; } void writeIntSync(int64_t value, int size = 4, Endian endianness = Endian::Little) { if (size < 1 || size > 8) { throw std::invalid_argument("Size must be between 1 and 8 bytes"); } std::vector bytes(size, 0); // Extract bytes with proper endianness if (endianness == Endian::Little) { for (int i = 0; i < size; i++) { bytes[i] = (value >> (i * 8)) & 0xFF; } } else { for (int i = 0; i < size; i++) { bytes[size - 1 - i] = (value >> (i * 8)) & 0xFF; } } writeFromSync(bytes); } void writeUIntSync(uint64_t value, int size = 4, Endian endianness = Endian::Little) { if (size < 1 || size > 8) { throw std::invalid_argument("Size must be between 1 and 8 bytes"); } std::vector bytes(size, 0); // Extract bytes with proper endianness if (endianness == Endian::Little) { for (int i = 0; i < size; i++) { bytes[i] = (value >> (i * 8)) & 0xFF; } } else { for (int i = 0; i < size; i++) { bytes[size - 1 - i] = (value >> (i * 8)) & 0xFF; } } writeFromSync(bytes); } // Read/Write Pointers (assuming POINTER size is 8 bytes) SweepstorePointer readPointerSync(int pointerSize = 8) { int64_t offset = readUIntSync(pointerSize); return SweepstorePointer(offset); } void writePointerSync(const SweepstorePointer& pointer, int pointerSize = 8) { writeUIntSync(pointer, pointerSize); } // Read/Write Float32 float readFloat32Sync(Endian endianness = Endian::Little) { std::vector bytes = readSync(4); float value; if (endianness == Endian::Little) { std::memcpy(&value, bytes.data(), 4); } else { std::vector reversed(bytes.rbegin(), bytes.rend()); std::memcpy(&value, reversed.data(), 4); } return value; } void writeFloat32Sync(float value, Endian endianness = Endian::Little) { std::vector bytes(4); std::memcpy(bytes.data(), &value, 4); if (endianness == Endian::Big) { std::reverse(bytes.begin(), bytes.end()); } writeFromSync(bytes); } // Read/Write Float64 (Double) double readFloat64Sync(Endian endianness = Endian::Little) { std::vector bytes = readSync(8); double value; if (endianness == Endian::Little) { std::memcpy(&value, bytes.data(), 8); } else { std::vector reversed(bytes.rbegin(), bytes.rend()); std::memcpy(&value, reversed.data(), 8); } return value; } void writeFloat64Sync(double value, Endian endianness = Endian::Little) { std::vector bytes(8); std::memcpy(bytes.data(), &value, 8); if (endianness == Endian::Big) { std::reverse(bytes.begin(), bytes.end()); } writeFromSync(bytes); } // Conversion methods std::vector toVector() const { return _buffer; } const uint8_t* data() const { return _buffer.data(); } uint8_t* data() { return _buffer.data(); } }; #ifdef _WIN32 #include #endif inline void preciseSleep(std::chrono::nanoseconds duration) { auto start = std::chrono::high_resolution_clock::now(); #ifdef _WIN32 const auto windowsMinSleepTime = std::chrono::milliseconds(1); if (duration < windowsMinSleepTime) { // Pure busy-wait with high-res timer while (std::chrono::high_resolution_clock::now() - start < duration) { // Optionally use _mm_pause() or YieldProcessor() to be nicer to hyperthreading } } else { // Hybrid: sleep most of it, busy-wait the remainder auto sleepDuration = duration - windowsMinSleepTime; std::this_thread::sleep_for(sleepDuration); while (std::chrono::high_resolution_clock::now() - start < duration) {} } #else std::this_thread::sleep_for(duration); #endif } inline int32_t millisecondsSinceEpoch32() { auto now = std::chrono::system_clock::now(); auto millis = std::chrono::duration_cast(now.time_since_epoch()).count(); return static_cast((millis / 1000) & 0xFFFFFFFF); } inline int64_t millisecondsSinceEpoch64() { auto now = std::chrono::system_clock::now(); auto millis = std::chrono::duration_cast(now.time_since_epoch()).count(); return millis; } inline uint64_t bt_hash(const std::string& str) { uint64_t hash = 0xcbf29ce484222325ULL; // FNV offset basis for (unsigned char byte : str) { hash ^= byte; hash *= 0x100000001b3ULL; // FNV prime } return hash; }