212 lines
5.2 KiB
C++
212 lines
5.2 KiB
C++
/*
|
|
* Copyright 2015 - 2022 gary@drinkingtea.net
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "defines.hpp"
|
|
#include "stddef.hpp"
|
|
#include "types.hpp"
|
|
#include "typetraits.hpp"
|
|
|
|
namespace ox {
|
|
|
|
template<typename T>
|
|
[[nodiscard]]
|
|
constexpr T byteSwap(typename enable_if<sizeof(T) == 1, T>::type i) noexcept {
|
|
return i;
|
|
}
|
|
|
|
template<typename T>
|
|
[[nodiscard]]
|
|
constexpr T byteSwap(typename enable_if<sizeof(T) == 2, T>::type i) noexcept {
|
|
return static_cast<T>(i << 8) | static_cast<T>(i >> 8);
|
|
}
|
|
|
|
template<typename T>
|
|
[[nodiscard]]
|
|
constexpr T byteSwap(typename enable_if<sizeof(T) == 4, T>::type i) noexcept {
|
|
return ((i >> 24) & 0x000000ff) |
|
|
((i >> 8) & 0x0000ff00) |
|
|
((i << 8) & 0x00ff0000) |
|
|
((i << 24) & 0xff000000);
|
|
}
|
|
|
|
template<typename T>
|
|
[[nodiscard]]
|
|
constexpr T byteSwap(typename enable_if<sizeof(T) == 8, T>::type i) noexcept {
|
|
return ((i >> 56) & 0x00000000000000ff) |
|
|
((i >> 40) & 0x000000000000ff00) |
|
|
((i >> 24) & 0x0000000000ff0000) |
|
|
((i >> 8) & 0x00000000ff000000) |
|
|
((i << 8) & 0x000000ff00000000) |
|
|
((i << 24) & 0x0000ff0000000000) |
|
|
((i << 40) & 0x00ff000000000000) |
|
|
((i << 56) & 0xff00000000000000);
|
|
}
|
|
|
|
|
|
/**
|
|
* Takes an int and byte swaps if the platform is the given condition is true.
|
|
*/
|
|
template<typename T, bool byteSwap>
|
|
[[nodiscard]]
|
|
constexpr T conditionalByteSwap(T i) noexcept {
|
|
if constexpr(byteSwap) {
|
|
return ox::byteSwap<T>(i);
|
|
} else {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
[[nodiscard]]
|
|
constexpr T fromLittleEndian(T i) noexcept {
|
|
return conditionalByteSwap<T, defines::BigEndian>(i);
|
|
}
|
|
|
|
template<typename T>
|
|
[[nodiscard]]
|
|
constexpr T fromBigEndian(T i) noexcept {
|
|
return conditionalByteSwap<T, defines::LittleEndian>(i);
|
|
}
|
|
|
|
template<typename T>
|
|
[[nodiscard]]
|
|
constexpr T toLittleEndian(T i) noexcept {
|
|
return conditionalByteSwap<T, defines::BigEndian>(i);
|
|
}
|
|
|
|
template<typename T>
|
|
[[nodiscard]]
|
|
constexpr T toBigEndian(T i) noexcept {
|
|
return conditionalByteSwap<T, defines::LittleEndian>(i);
|
|
}
|
|
|
|
template<typename T, bool byteSwap>
|
|
class OX_PACKED ByteSwapInteger {
|
|
private:
|
|
T m_value;
|
|
|
|
public:
|
|
constexpr ByteSwapInteger() noexcept = default;
|
|
|
|
constexpr ByteSwapInteger(const ByteSwapInteger &other) noexcept {
|
|
m_value = other.m_value;
|
|
}
|
|
|
|
constexpr ByteSwapInteger(T value) noexcept: m_value(conditionalByteSwap<T, byteSwap>(value)) {
|
|
}
|
|
|
|
constexpr ByteSwapInteger &operator=(const ByteSwapInteger &other) noexcept {
|
|
m_value = other.m_value;
|
|
return *this;
|
|
}
|
|
|
|
constexpr ByteSwapInteger &operator=(T value) noexcept {
|
|
m_value = conditionalByteSwap<T, byteSwap>(value);
|
|
return *this;
|
|
}
|
|
|
|
constexpr operator T() const noexcept {
|
|
return conditionalByteSwap<T, byteSwap>(m_value);
|
|
}
|
|
|
|
constexpr ByteSwapInteger operator+=(T other) noexcept {
|
|
const auto newVal = static_cast<T>(*this + other);
|
|
m_value = conditionalByteSwap<T, byteSwap>(newVal);
|
|
return *this;
|
|
}
|
|
|
|
constexpr ByteSwapInteger operator-=(T other) noexcept {
|
|
const auto newVal = static_cast<T>(*this - other);
|
|
m_value = conditionalByteSwap<T, byteSwap>(newVal);
|
|
return *this;
|
|
}
|
|
|
|
constexpr ByteSwapInteger operator*=(T other) noexcept {
|
|
const auto newVal = static_cast<T>(*this * other);
|
|
m_value = conditionalByteSwap<T, byteSwap>(newVal);
|
|
return *this;
|
|
}
|
|
|
|
constexpr ByteSwapInteger operator/=(T other) noexcept {
|
|
const auto newVal = static_cast<T>(*this / other);
|
|
m_value = conditionalByteSwap<T, byteSwap>(newVal);
|
|
return *this;
|
|
}
|
|
|
|
// Prefix increment
|
|
constexpr ByteSwapInteger operator++() noexcept {
|
|
return operator+=(1);
|
|
}
|
|
|
|
// Prefix decrement
|
|
constexpr ByteSwapInteger operator--() noexcept {
|
|
return operator-=(1);
|
|
}
|
|
|
|
template<typename I>
|
|
constexpr T operator&=(I other) noexcept {
|
|
auto newVal = *this & other;
|
|
m_value = conditionalByteSwap<T, byteSwap>(newVal);
|
|
return newVal;
|
|
}
|
|
|
|
template<typename I>
|
|
constexpr T operator|=(I other) noexcept {
|
|
auto newVal = *this | other;
|
|
m_value = conditionalByteSwap<T, byteSwap>(newVal);
|
|
return newVal;
|
|
}
|
|
|
|
template<typename I>
|
|
constexpr T operator^=(I other) noexcept {
|
|
auto newVal = *this ^ other;
|
|
m_value = conditionalByteSwap<T, byteSwap>(newVal);
|
|
return newVal;
|
|
}
|
|
|
|
template<typename I>
|
|
constexpr T operator>>=(I other) noexcept {
|
|
auto newVal = *this >> other;
|
|
m_value = conditionalByteSwap<T, byteSwap>(newVal);
|
|
return newVal;
|
|
}
|
|
|
|
template<typename I>
|
|
constexpr T operator<<=(I other) noexcept {
|
|
auto newVal = *this << other;
|
|
m_value = conditionalByteSwap<T, byteSwap>(newVal);
|
|
return newVal;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr auto get() const noexcept -> T {
|
|
return static_cast<T>(*this);
|
|
}
|
|
|
|
/**
|
|
* Returns the integer as it is stored. If it is stored as little endian,
|
|
* a little endian integer is returned regardless of the endianness of
|
|
* the system.
|
|
*/
|
|
[[nodiscard]]
|
|
constexpr auto raw() const noexcept -> T {
|
|
return m_value;
|
|
}
|
|
|
|
};
|
|
|
|
template<typename T>
|
|
using LittleEndian = ByteSwapInteger<T, defines::BigEndian>;
|
|
|
|
template<typename T>
|
|
using BigEndian = ByteSwapInteger<T, defines::LittleEndian>;
|
|
|
|
}
|