#pragma once
|
|
|
|
#include "gp/containers/array.hpp"
|
|
|
|
#include <bit>
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
namespace gp {
|
|
|
|
using endian = std::endian;
|
|
|
|
template <typename T>
|
|
T swap_endian(T value) noexcept {
|
|
union {
|
|
T v;
|
|
uint8_t u8[sizeof(T)];
|
|
} src, dest;
|
|
|
|
src.v = value;
|
|
|
|
for (size_t idx = 0;idx<sizeof(T);idx++) {
|
|
dest.u8[idx] = src.u8[sizeof(T)-idx-1];
|
|
}
|
|
|
|
return dest.v;
|
|
}
|
|
|
|
template<typename T, endian mode = endian::big>
|
|
struct endian_wrapper {
|
|
T value = 0;
|
|
|
|
constexpr endian_wrapper() noexcept = default;
|
|
|
|
endian_wrapper(T v) noexcept
|
|
: value{adjust(v)} {}
|
|
|
|
endian_wrapper& operator=(T v) noexcept {
|
|
value = adjust(v);
|
|
return *this;
|
|
}
|
|
|
|
operator T() const noexcept {
|
|
return adjust(value);
|
|
}
|
|
|
|
auto bytes() const noexcept -> gp::array<uint8_t, sizeof(T)> {
|
|
union {
|
|
T t;
|
|
gp::array<uint8_t, sizeof(T)> bytes;
|
|
} tmp {.t = value};
|
|
|
|
return tmp.bytes;
|
|
}
|
|
|
|
// arithmetic assignment operators
|
|
|
|
endian_wrapper& operator+=(T rhs) noexcept {
|
|
value = adjust(adjust(value) + rhs);
|
|
return *this;
|
|
}
|
|
|
|
endian_wrapper& operator+=(endian_wrapper rhs) noexcept {
|
|
value = adjust(adjust(value) + adjust(rhs.value));
|
|
return *this;
|
|
}
|
|
|
|
endian_wrapper& operator-=(T rhs) noexcept {
|
|
value = adjust(adjust(value) - rhs);
|
|
return *this;
|
|
}
|
|
|
|
endian_wrapper& operator-=(endian_wrapper rhs) noexcept {
|
|
value = adjust(adjust(value) - adjust(rhs.value));
|
|
return *this;
|
|
}
|
|
|
|
private:
|
|
|
|
T adjust(T x) const noexcept {
|
|
return (mode == endian::native ? x : swap_endian(x));
|
|
}
|
|
};
|
|
|
|
}
|