Merge branch 'main' into heightmaps
This commit is contained in:
+17
-1
@@ -4,6 +4,8 @@
|
||||
#include <cstring>
|
||||
|
||||
namespace util {
|
||||
/// @brief Template similar to std::unique_ptr stores a buffer with its size
|
||||
/// @tparam T buffer elements type
|
||||
template<typename T>
|
||||
class Buffer {
|
||||
std::unique_ptr<T[]> ptr;
|
||||
@@ -12,7 +14,9 @@ namespace util {
|
||||
Buffer(size_t length)
|
||||
: ptr(std::make_unique<T[]>(length)), length(length) {
|
||||
}
|
||||
Buffer(const Buffer<T>& o) : Buffer(o.data(), o.size()) {}
|
||||
explicit Buffer(const Buffer<T>& o) : Buffer(o.data(), o.size()) {}
|
||||
|
||||
Buffer(Buffer<T>&& o) : ptr(std::move(o.ptr)), length(o.length) {}
|
||||
|
||||
Buffer(std::unique_ptr<T[]> ptr, size_t length)
|
||||
: ptr(std::move(ptr)), length(length) {}
|
||||
@@ -42,16 +46,28 @@ namespace util {
|
||||
return length;
|
||||
}
|
||||
|
||||
/// @brief Take ownership over the buffer unique_ptr
|
||||
std::unique_ptr<T[]> release() {
|
||||
return std::move(ptr);
|
||||
}
|
||||
|
||||
/// @brief Create a buffer copy
|
||||
Buffer clone() const {
|
||||
return Buffer(ptr.get(), length);
|
||||
}
|
||||
|
||||
/// @brief Update buffer size without releasing used memory
|
||||
/// @param size new size (must be less or equal to current)
|
||||
void resizeFast(size_t size) {
|
||||
length = size;
|
||||
}
|
||||
|
||||
const T* begin() const {
|
||||
return ptr.get();
|
||||
}
|
||||
|
||||
const T* end() const {
|
||||
return ptr.get() + length;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -35,5 +35,9 @@ namespace util {
|
||||
freeBuffers.push(ptr);
|
||||
});
|
||||
}
|
||||
|
||||
size_t getBufferSize() const {
|
||||
return bufferSize;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "Buffer.hpp"
|
||||
#include "data_io.hpp"
|
||||
|
||||
namespace util {
|
||||
template<typename T>
|
||||
inline T read_int_le(const uint8_t* src, size_t offset=0) {
|
||||
return dataio::le2h(*(reinterpret_cast<const T*>(src) + offset));
|
||||
}
|
||||
|
||||
/// @brief Simple heap implementation for memory-optimal sparse array of
|
||||
/// small different structures
|
||||
/// @note alignment is not impemented
|
||||
/// (impractical in the context of scripting and memory consumption)
|
||||
/// @tparam Tindex entry index type
|
||||
/// @tparam Tsize entry size type
|
||||
template <typename Tindex, typename Tsize>
|
||||
class SmallHeap {
|
||||
std::vector<uint8_t> buffer;
|
||||
Tindex entriesCount;
|
||||
public:
|
||||
SmallHeap() : entriesCount(0) {}
|
||||
|
||||
/// @brief Find current entry address by index
|
||||
/// @param index entry index
|
||||
/// @return temporary raw pointer or nullptr if entry does not exists
|
||||
/// @attention pointer becomes invalid after allocate(...) or free(...)
|
||||
uint8_t* find(Tindex index) {
|
||||
auto data = buffer.data();
|
||||
for (size_t i = 0; i < entriesCount; i++) {
|
||||
auto nextIndex = read_int_le<Tindex>(data);
|
||||
data += sizeof(Tindex);
|
||||
auto nextSize = read_int_le<Tsize>(data);
|
||||
data += sizeof(Tsize);
|
||||
if (nextIndex == index) {
|
||||
return data;
|
||||
} else if (nextIndex > index) {
|
||||
return nullptr;
|
||||
}
|
||||
data += nextSize;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// @brief Erase entry from the heap
|
||||
/// @param ptr valid entry pointer
|
||||
void free(uint8_t* ptr) {
|
||||
if (ptr == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto entrySize = sizeOf(ptr);
|
||||
auto begin =
|
||||
buffer.begin() +
|
||||
((ptr - sizeof(Tsize) - sizeof(Tindex)) - buffer.data());
|
||||
buffer.erase(
|
||||
begin, begin + entrySize + sizeof(Tsize) + sizeof(Tindex)
|
||||
);
|
||||
entriesCount--;
|
||||
}
|
||||
|
||||
/// @brief Create or update entry (size)
|
||||
/// @param index entry index
|
||||
/// @param size entry size
|
||||
/// @return temporary entry pointer
|
||||
/// @attention pointer becomes invalid after allocate(...) or free(...)
|
||||
uint8_t* allocate(Tindex index, size_t size) {
|
||||
const auto maxSize = std::numeric_limits<Tsize>::max();
|
||||
if (size > maxSize) {
|
||||
throw std::invalid_argument(
|
||||
"requested "+std::to_string(size)+" bytes but limit is "+
|
||||
std::to_string(maxSize));
|
||||
}
|
||||
if (size == 0) {
|
||||
throw std::invalid_argument("zero size");
|
||||
}
|
||||
ptrdiff_t offset = 0;
|
||||
if (auto found = find(index)) {
|
||||
auto entrySize = sizeOf(found);
|
||||
if (size == entrySize) {
|
||||
std::memset(found, 0, entrySize);
|
||||
return found;
|
||||
}
|
||||
this->free(found);
|
||||
return allocate(index, size);
|
||||
}
|
||||
for (size_t i = 0; i < entriesCount; i++) {
|
||||
auto data = buffer.data() + offset;
|
||||
auto nextIndex = read_int_le<Tindex>(data);
|
||||
data += sizeof(Tindex);
|
||||
auto nextSize = read_int_le<Tsize>(data);
|
||||
data += sizeof(Tsize);
|
||||
if (nextIndex > index) {
|
||||
break;
|
||||
}
|
||||
data += nextSize;
|
||||
offset = data - buffer.data();
|
||||
}
|
||||
buffer.insert(
|
||||
buffer.begin() + offset,
|
||||
size + sizeof(Tindex) + sizeof(Tsize),
|
||||
0
|
||||
);
|
||||
entriesCount++;
|
||||
|
||||
auto data = buffer.data() + offset;
|
||||
*reinterpret_cast<Tindex*>(data) = dataio::h2le(index);
|
||||
data += sizeof(Tindex);
|
||||
*reinterpret_cast<Tsize*>(data) = dataio::h2le(size);
|
||||
return data + sizeof(Tsize);
|
||||
}
|
||||
|
||||
/// @param ptr valid entry pointer
|
||||
/// @return entry size
|
||||
Tsize sizeOf(uint8_t* ptr) const {
|
||||
if (ptr == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return read_int_le<Tsize>(ptr, -1);
|
||||
}
|
||||
|
||||
/// @return number of entries
|
||||
Tindex count() const {
|
||||
return entriesCount;
|
||||
}
|
||||
|
||||
/// @return total used bytes including entries metadata
|
||||
size_t size() const {
|
||||
return buffer.size();
|
||||
}
|
||||
|
||||
inline bool operator==(const SmallHeap<Tindex, Tsize>& o) const {
|
||||
if (o.entriesCount != entriesCount) {
|
||||
return false;
|
||||
}
|
||||
return buffer == o.buffer;
|
||||
}
|
||||
|
||||
util::Buffer<uint8_t> serialize() const {
|
||||
util::Buffer<uint8_t> out(sizeof(Tindex) + buffer.size());
|
||||
ubyte* dst = out.data();
|
||||
const ubyte* src = buffer.data();
|
||||
|
||||
*reinterpret_cast<Tindex*>(dst) = dataio::h2le(entriesCount);
|
||||
dst += sizeof(Tindex);
|
||||
|
||||
std::memcpy(dst, src, buffer.size());
|
||||
return out;
|
||||
}
|
||||
|
||||
void deserialize(const ubyte* src, size_t size) {
|
||||
entriesCount = read_int_le<Tindex>(src);
|
||||
buffer.resize(size - sizeof(Tindex));
|
||||
std::memcpy(buffer.data(), src + sizeof(Tindex), buffer.size());
|
||||
}
|
||||
|
||||
struct const_iterator {
|
||||
private:
|
||||
const std::vector<uint8_t>& buffer;
|
||||
public:
|
||||
Tindex index;
|
||||
size_t offset;
|
||||
|
||||
const_iterator(
|
||||
const std::vector<uint8_t>& buffer, Tindex index, size_t offset
|
||||
) : buffer(buffer), index(index), offset(offset) {}
|
||||
|
||||
Tsize size() const {
|
||||
return read_int_le<Tsize>(buffer.data() + offset, -1);
|
||||
}
|
||||
|
||||
bool operator!=(const const_iterator& o) const {
|
||||
return o.offset != offset;
|
||||
}
|
||||
|
||||
const_iterator& operator++() {
|
||||
offset += size();
|
||||
if (offset == buffer.size()) {
|
||||
return *this;
|
||||
}
|
||||
index = read_int_le<Tindex>(buffer.data() + offset);
|
||||
offset += sizeof(Tindex) + sizeof(Tsize);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator& operator*() {
|
||||
return *this;
|
||||
}
|
||||
|
||||
const uint8_t* data() const {
|
||||
return buffer.data() + offset;
|
||||
}
|
||||
};
|
||||
|
||||
const_iterator begin() const {
|
||||
if (buffer.empty()) {
|
||||
return end();
|
||||
}
|
||||
return const_iterator (
|
||||
buffer,
|
||||
read_int_le<Tindex>(buffer.data()),
|
||||
sizeof(Tindex) + sizeof(Tsize));
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return const_iterator (buffer, 0, buffer.size());
|
||||
}
|
||||
};
|
||||
}
|
||||
+75
-6
@@ -3,16 +3,85 @@
|
||||
#include "typedefs.hpp"
|
||||
|
||||
namespace dataio {
|
||||
/* Read big-endian 16 bit signed integer from bytes */
|
||||
/// @brief Swap byte-order for value of type T
|
||||
/// @tparam T value type
|
||||
/// @param value source integer
|
||||
/// @return swapped integer
|
||||
template <typename T>
|
||||
T swap(T value) {
|
||||
union{
|
||||
T value;
|
||||
ubyte bytes[sizeof(T)];
|
||||
} source, dest;
|
||||
|
||||
source.value = value;
|
||||
|
||||
for (size_t i = 0; i < sizeof(T); i++) {
|
||||
dest.bytes[i] = source.bytes[sizeof(T) - i - 1];
|
||||
}
|
||||
return dest.value;
|
||||
}
|
||||
|
||||
inline bool is_big_endian() {
|
||||
uint16_t num = 1;
|
||||
auto bytes = reinterpret_cast<uint8_t*>(&num);
|
||||
return bytes[1] == 1;
|
||||
}
|
||||
|
||||
/// @brief Convert big-endian to hardware byte-order
|
||||
/// @tparam T value type
|
||||
/// @param value source integer
|
||||
/// @return integer with hardware byte-order
|
||||
template <typename T>
|
||||
inline T be2h(T value){
|
||||
if (is_big_endian()) {
|
||||
return value;
|
||||
} else {
|
||||
return swap(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Convert hardware byte-order to big-endian
|
||||
/// @tparam T value type
|
||||
/// @param value source integer
|
||||
/// @return big-endian integer
|
||||
template <typename T>
|
||||
T h2be(T value){
|
||||
return be2h(value);
|
||||
}
|
||||
|
||||
/// @brief Convert little-endian to hardware byte-order
|
||||
/// @tparam T value type
|
||||
/// @param value source integer
|
||||
/// @return integer with hardware byte-order
|
||||
template <typename T>
|
||||
T le2h(T value){
|
||||
if (is_big_endian()) {
|
||||
return swap(value);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Convert hardware byte-order to little-endian
|
||||
/// @tparam T value type
|
||||
/// @param value source integer
|
||||
/// @return little-endian integer
|
||||
template <typename T>
|
||||
T h2le(T value){
|
||||
return le2h(value);
|
||||
}
|
||||
|
||||
/// @brief Read big-endian 16 bit signed integer from bytes
|
||||
inline int16_t read_int16_big(const ubyte* src, size_t offset) {
|
||||
return (src[offset] << 8) | (src[offset + 1]);
|
||||
}
|
||||
/* Read big-endian 32 bit signed integer from bytes */
|
||||
/// @brief Read big-endian 32 bit signed integer from bytes
|
||||
inline int32_t read_int32_big(const ubyte* src, size_t offset) {
|
||||
return (src[offset] << 24) | (src[offset + 1] << 16) |
|
||||
(src[offset + 2] << 8) | (src[offset + 3]);
|
||||
}
|
||||
/* Read big-endian 64 bit signed integer from bytes */
|
||||
/// @brief Read big-endian 64 bit signed integer from bytes
|
||||
inline int64_t read_int64_big(const ubyte* src, size_t offset) {
|
||||
return (int64_t(src[offset]) << 56) | (int64_t(src[offset + 1]) << 48) |
|
||||
(int64_t(src[offset + 2]) << 40) |
|
||||
@@ -21,19 +90,19 @@ namespace dataio {
|
||||
(int64_t(src[offset + 5]) << 16) |
|
||||
(int64_t(src[offset + 6]) << 8) | (int64_t(src[offset + 7]));
|
||||
}
|
||||
/* Write big-endian 16 bit signed integer to bytes */
|
||||
/// @brief Write big-endian 16 bit signed integer to bytes
|
||||
inline void write_int16_big(int16_t value, ubyte* dest, size_t offset) {
|
||||
dest[offset] = (char)(value >> 8 & 255);
|
||||
dest[offset + 1] = (char)(value >> 0 & 255);
|
||||
}
|
||||
/* Write big-endian 32 bit signed integer to bytes */
|
||||
/// @brief Write big-endian 32 bit signed integer to bytes
|
||||
inline void write_int32_big(int32_t value, ubyte* dest, size_t offset) {
|
||||
dest[offset] = (char)(value >> 24 & 255);
|
||||
dest[offset + 1] = (char)(value >> 16 & 255);
|
||||
dest[offset + 2] = (char)(value >> 8 & 255);
|
||||
dest[offset + 3] = (char)(value >> 0 & 255);
|
||||
}
|
||||
/* Write big-endian 64 bit signed integer to bytes */
|
||||
/// @brief Write big-endian 64 bit signed integer to bytes
|
||||
inline void write_int64_big(int64_t value, ubyte* dest, size_t offset) {
|
||||
dest[offset] = (char)(value >> 56 & 255);
|
||||
dest[offset + 1] = (char)(value >> 48 & 255);
|
||||
|
||||
Reference in New Issue
Block a user