|
|
- #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));
- }
- };
-
- }
|