383 lines
11 KiB
C++
383 lines
11 KiB
C++
#pragma once
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <vector>
|
|
#include <cstdint>
|
|
#include <fstream>
|
|
#include <chrono>
|
|
#include <thread>
|
|
#include <cstring>
|
|
#include <algorithm>
|
|
|
|
// 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<uint8_t>& 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<int>(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<int>(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<char>(byte);
|
|
} else {
|
|
buffer << '.';
|
|
}
|
|
}
|
|
}
|
|
|
|
buffer << " | ";
|
|
if (i + 16 < data.size()) buffer << '\n';
|
|
}
|
|
|
|
return buffer.str();
|
|
}
|
|
|
|
inline std::vector<uint8_t> 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<uint8_t> buffer(size);
|
|
if (!file.read(reinterpret_cast<char*>(buffer.data()), size)) {
|
|
throw std::runtime_error("Failed to read file: " + filename);
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
enum class Endian {
|
|
Little,
|
|
Big
|
|
};
|
|
|
|
class RandomAccessMemory {
|
|
private:
|
|
std::vector<uint8_t> _buffer;
|
|
size_t _position;
|
|
|
|
public:
|
|
// Constructors
|
|
RandomAccessMemory() : _position(0) {}
|
|
|
|
explicit RandomAccessMemory(const std::vector<uint8_t>& 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<uint8_t> readSync(size_t count) {
|
|
if (_position + count > _buffer.size()) {
|
|
throw std::range_error("Not enough bytes to read");
|
|
}
|
|
|
|
std::vector<uint8_t> result(_buffer.begin() + _position,
|
|
_buffer.begin() + _position + count);
|
|
_position += count;
|
|
return result;
|
|
}
|
|
|
|
// Write bytes
|
|
void writeFromSync(const std::vector<uint8_t>& 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> bytes = readSync(4);
|
|
float value;
|
|
|
|
if (endianness == Endian::Little) {
|
|
std::memcpy(&value, bytes.data(), 4);
|
|
} else {
|
|
std::vector<uint8_t> reversed(bytes.rbegin(), bytes.rend());
|
|
std::memcpy(&value, reversed.data(), 4);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
void writeFloat32Sync(float value, Endian endianness = Endian::Little) {
|
|
std::vector<uint8_t> 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<uint8_t> bytes = readSync(8);
|
|
double value;
|
|
|
|
if (endianness == Endian::Little) {
|
|
std::memcpy(&value, bytes.data(), 8);
|
|
} else {
|
|
std::vector<uint8_t> reversed(bytes.rbegin(), bytes.rend());
|
|
std::memcpy(&value, reversed.data(), 8);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
void writeFloat64Sync(double value, Endian endianness = Endian::Little) {
|
|
std::vector<uint8_t> bytes(8);
|
|
std::memcpy(bytes.data(), &value, 8);
|
|
|
|
if (endianness == Endian::Big) {
|
|
std::reverse(bytes.begin(), bytes.end());
|
|
}
|
|
|
|
writeFromSync(bytes);
|
|
}
|
|
|
|
// Conversion methods
|
|
std::vector<uint8_t> toVector() const {
|
|
return _buffer;
|
|
}
|
|
|
|
const uint8_t* data() const {
|
|
return _buffer.data();
|
|
}
|
|
|
|
uint8_t* data() {
|
|
return _buffer.data();
|
|
}
|
|
};
|
|
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#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<std::chrono::milliseconds>(now.time_since_epoch()).count();
|
|
return static_cast<int32_t>((millis / 1000) & 0xFFFFFFFF);
|
|
}
|
|
|
|
inline int64_t millisecondsSinceEpoch64() {
|
|
auto now = std::chrono::system_clock::now();
|
|
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(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;
|
|
} |