Merge branch 'main' into heightmaps

This commit is contained in:
MihailRis
2024-10-03 19:12:37 +03:00
64 changed files with 3472 additions and 732 deletions
+17 -1
View File
@@ -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;
}
};
}
+4
View File
@@ -35,5 +35,9 @@ namespace util {
freeBuffers.push(ptr);
});
}
size_t getBufferSize() const {
return bufferSize;
}
};
}
+215
View File
@@ -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
View File
@@ -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);