godot_voxel/util/serialization.h

126 lines
2.8 KiB
C++

#ifndef VOXEL_UTIL_SERIALIZATION_H
#define VOXEL_UTIL_SERIALIZATION_H
#include "array_slice.h"
namespace VoxelUtility {
enum Endianess {
ENDIANESS_BIG_ENDIAN,
ENDIANESS_LITTLE_ENDIAN
};
inline Endianess get_platform_endianess() {
// https://stackoverflow.com/questions/4181951/how-to-check-whether-a-system-is-big-endian-or-little-endian#4181991
const int n = 1;
if (*(char *)&n == 1) {
return ENDIANESS_LITTLE_ENDIAN;
}
return ENDIANESS_BIG_ENDIAN;
// TODO In C++20 we'll be able to use std::endian
}
struct MemoryWriter {
std::vector<uint8_t> &data;
// Using network-order by default
Endianess endianess = ENDIANESS_BIG_ENDIAN;
MemoryWriter(std::vector<uint8_t> &p_data, Endianess p_endianess) :
data(p_data), endianess(p_endianess) {}
inline void store_8(uint8_t v) {
data.push_back(v);
}
inline void store_16(uint16_t v) {
if (endianess == ENDIANESS_BIG_ENDIAN) {
data.push_back(v >> 8);
data.push_back(v & 0xff);
} else {
data.push_back(v & 0xff);
data.push_back(v >> 8);
}
}
inline void store_32(uint32_t v) {
if (endianess == ENDIANESS_BIG_ENDIAN) {
data.push_back(v >> 24);
data.push_back(v >> 16);
data.push_back(v >> 8);
data.push_back(v & 0xff);
} else {
data.push_back(v & 0xff);
data.push_back(v >> 8);
data.push_back(v >> 16);
data.push_back(v >> 24);
}
}
inline void store_float(float v) {
union M {
uint32_t i;
float f;
} m;
m.f = v;
store_32(m.i);
}
};
struct MemoryReader {
ArraySlice<const uint8_t> data;
size_t pos = 0;
// Using network-order by default
Endianess endianess = ENDIANESS_BIG_ENDIAN;
MemoryReader(ArraySlice<const uint8_t> p_data, Endianess p_endianess) :
data(p_data), endianess(p_endianess) {}
inline uint8_t get_8() {
ERR_FAIL_COND_V(pos >= data.size(), 0);
return data[pos++];
}
inline uint16_t get_16() {
ERR_FAIL_COND_V(pos + 1 >= data.size(), 0);
uint16_t v;
if (endianess == ENDIANESS_BIG_ENDIAN) {
v = (static_cast<uint16_t>(data[pos]) << 8) | data[pos + 1];
} else {
v = (static_cast<uint16_t>(data[pos]) | static_cast<uint16_t>(data[pos + 1]) << 8);
}
pos += sizeof(uint16_t);
return v;
}
inline uint32_t get_32() {
ERR_FAIL_COND_V(pos + 3 >= data.size(), 0);
uint32_t v;
if (endianess == ENDIANESS_BIG_ENDIAN) {
v = (static_cast<uint32_t>(data[pos]) << 24) |
(static_cast<uint32_t>(data[pos + 1]) << 16) |
(static_cast<uint32_t>(data[pos + 2]) << 8) |
data[pos + 3];
} else {
v = static_cast<uint32_t>(data[pos]) |
(static_cast<uint32_t>(data[pos + 1]) << 8) |
(static_cast<uint32_t>(data[pos + 2]) << 16) |
(static_cast<uint32_t>(data[pos + 3]) << 24);
}
pos += sizeof(uint32_t);
return v;
}
inline float get_float() {
union M {
uint32_t i;
float f;
} m;
m.i = get_32();
return m.f;
}
};
} // namespace VoxelUtility
#endif // VOXEL_UTIL_SERIALIZATION_H