980 lines
24 KiB
C++
980 lines
24 KiB
C++
/***
|
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: AuroraUtils.hpp
|
|
Date: 2021-6-9
|
|
Author: Reece
|
|
***/
|
|
#pragma once
|
|
|
|
#if !defined(AURORA_RUNTIME_MAKE_SHARED)
|
|
#define AURORA_RUNTIME_MAKE_SHARED std::make_shared
|
|
#endif
|
|
|
|
template<typename T, typename... Args>
|
|
static inline AuSPtr<T> AuMakeShared(Args... args)
|
|
{
|
|
try
|
|
{
|
|
return AURORA_RUNTIME_MAKE_SHARED<T>(args...);
|
|
}
|
|
catch (...)
|
|
{
|
|
return {};
|
|
}
|
|
}
|
|
|
|
#if !defined(AURORA_RUNTIME_MAKE_PAIR)
|
|
#define AURORA_RUNTIME_MAKE_PAIR std::make_pair
|
|
#endif
|
|
|
|
template<typename... Args>
|
|
static inline auto AuMakePair(Args... args)
|
|
{
|
|
return AURORA_RUNTIME_MAKE_PAIR(args...);
|
|
}
|
|
|
|
#if defined(AURORA_IS_MODERNNT_DERIVED) && defined(_WINDOWS_)
|
|
static inline void AuWin32CloseHandle(HANDLE &handle)
|
|
{
|
|
HANDLE local;
|
|
|
|
if ((local = std::exchange(handle, INVALID_HANDLE_VALUE)) != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(local);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
template<typename T>
|
|
static AuSPtr<T> AuUnsafeRaiiToShared(T *in)
|
|
{
|
|
return AuSPtr<T>(in, [](T *){});
|
|
}
|
|
|
|
template<typename T, int Z>
|
|
static constexpr int AuArraySize(const T(&array)[Z])
|
|
{
|
|
return Z;
|
|
}
|
|
|
|
#if defined(DEBUG) || defined(STAGING)
|
|
|
|
template<typename ... T>
|
|
static inline void __declspec(noreturn) SysPanic(T... args);
|
|
|
|
template<typename Z, typename T>
|
|
static void inline SafeDelete(T *in)
|
|
{
|
|
static_assert(std::is_base_of<T, std::remove_pointer<Z>::type>::value, "Couldn't not safe delete from type T because it is not derived from Z");
|
|
auto cast = dynamic_cast<Z>(in);
|
|
if (cast == nullptr)
|
|
{
|
|
Z re;
|
|
SysPanic("Tried to free: 0x{:x}, type \"{}\" was not inherited from \"{}\"", AuUInt(in), typeid(in).name(), typeid(re).name());
|
|
}
|
|
delete cast;
|
|
}
|
|
|
|
#else
|
|
|
|
template<typename Z, typename T>
|
|
static void inline SafeDelete(T *in)
|
|
{
|
|
static_assert(std::is_base_of<T, std::remove_pointer<Z>::type>::value, "Couldn't not safe delete from type T because it is not derived from Z");
|
|
delete static_cast<Z>(in);
|
|
}
|
|
|
|
#endif
|
|
|
|
static constexpr inline AuUInt32 AuConvertMagicTag32(const char buffer[4])
|
|
{
|
|
AuUInt32 magic {};
|
|
if (Aurora::Build::kCurrentEndian == Aurora::Build::ECPUEndian::eCPULittle)
|
|
{
|
|
magic |= AuUInt32(buffer[0]);
|
|
magic |= AuUInt32(buffer[1]) << 8;
|
|
magic |= AuUInt32(buffer[2]) << 16;
|
|
magic |= AuUInt32(buffer[3]) << 24;
|
|
// LE will look alright in memory dumps
|
|
// MSFT uses tags that read back the initial string value when read back hex ints
|
|
// I prefer binary streams and file headers contain a 4x or 8x ascii char headers (eg. LuaX)
|
|
}
|
|
else
|
|
{
|
|
// Lazy reinterpret cast reads will always be flipped
|
|
// Assume byte buffers read/write machine endian
|
|
// Assume *reinterpret_cast<T*> returns machine endian
|
|
// BE needs to be flipped in memory
|
|
// BE will look fine in memory dumps
|
|
// BE will also look fine in stack/variable dumps when printed in hex
|
|
magic |= AuUInt32(buffer[4]);
|
|
magic |= AuUInt32(buffer[2]) << 8;
|
|
magic |= AuUInt32(buffer[1]) << 16;
|
|
magic |= AuUInt32(buffer[0]) << 24;
|
|
}
|
|
// Determinstic across platforms, perhaps unexpected by endian normalized streams
|
|
// When asserting read(noEndian) against a tag, an endian swap would cause the
|
|
// assertion to fail, thus providing you with the endian match check
|
|
// This step is delegated to a de-facto machine endian buffer builder
|
|
// ByteBuffers that normalize for endianness continue to work with tags
|
|
// irrespective of reader/writer endianness
|
|
return magic;
|
|
}
|
|
|
|
static constexpr inline AuUInt64 AuConvertMagicTag64(const char buffer[8])
|
|
{
|
|
AuUInt64 magic {};
|
|
if (Aurora::Build::kCurrentEndian == Aurora::Build::ECPUEndian::eCPULittle)
|
|
{
|
|
magic |= AuUInt64(buffer[0]);
|
|
magic |= AuUInt64(buffer[1]) << 8;
|
|
magic |= AuUInt64(buffer[2]) << 16;
|
|
magic |= AuUInt64(buffer[3]) << 24;
|
|
magic |= AuUInt64(buffer[4]) << 32;
|
|
magic |= AuUInt64(buffer[5]) << 40;
|
|
magic |= AuUInt64(buffer[6]) << 48;
|
|
magic |= AuUInt64(buffer[7]) << 56;
|
|
}
|
|
else
|
|
{
|
|
magic |= AuUInt64(buffer[7]);
|
|
magic |= AuUInt64(buffer[6]) << 8;
|
|
magic |= AuUInt64(buffer[5]) << 16;
|
|
magic |= AuUInt64(buffer[4]) << 24;
|
|
magic |= AuUInt64(buffer[3]) << 32;
|
|
magic |= AuUInt64(buffer[2]) << 40;
|
|
magic |= AuUInt64(buffer[1]) << 48;
|
|
magic |= AuUInt64(buffer[0]) << 56;
|
|
}
|
|
return magic;
|
|
}
|
|
|
|
template<typename T, typename Z>
|
|
static inline AuOptional<AuSPtr<T>> AuOptionalSharedDynamicCast(AuOptional<AuSPtr<Z>> &in)
|
|
{
|
|
if (!in.has_value()) return {};
|
|
return std::dynamic_pointer_cast<T>(in.value());
|
|
}
|
|
|
|
template<typename T, typename Z>
|
|
static inline AuOptional<AuSPtr<T>> AuOptionalSharedStaticCast(AuOptional<AuSPtr<Z>> &in)
|
|
{
|
|
if (!in.has_value()) return {};
|
|
return std::static_pointer_cast<T>(in.value());
|
|
}
|
|
|
|
static inline bool AuEndsWith(std::string const &value, std::string const &ending)
|
|
{
|
|
if (ending.size() > value.size()) return false;
|
|
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
|
|
}
|
|
|
|
static inline bool AuStartsWith(std::string const &value, std::string const &starting)
|
|
{
|
|
return value.rfind(starting, 0) == 0;
|
|
}
|
|
|
|
template<typename T>
|
|
static inline AuString AuToStringASCIIOp(T op, const AuString &in)
|
|
{
|
|
AuString ret;
|
|
ret.resize(in.size());
|
|
std::transform(in.begin(), in.end(), ret.begin(), [=](const char &c)
|
|
{
|
|
return op(c);
|
|
});
|
|
return ret;
|
|
}
|
|
|
|
static inline AuString AuToLower(const AuString &in)
|
|
{
|
|
return AuToStringASCIIOp<int(*)(int)>(std::tolower, in);
|
|
}
|
|
|
|
static inline AuString AuToUpper(const AuString &in)
|
|
{
|
|
return AuToStringASCIIOp<int(*)(int)>(std::toupper, in);
|
|
}
|
|
|
|
template<typename Map, class Key, typename Value>
|
|
static inline bool AuTryFind(Map &map, const Key &key, Value *&ptr)
|
|
{
|
|
auto itr = map.find(key);
|
|
if (itr != map.end())
|
|
{
|
|
ptr = &itr->second;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
ptr = nullptr;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template<typename Map, class Key, typename Value>
|
|
static inline bool AuTryFind(Map *map, const Key &key, Value *&ptr)
|
|
{
|
|
auto itr = map->find(key);
|
|
if (itr != map->end())
|
|
{
|
|
ptr = &itr->second;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
ptr = nullptr;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template<typename Map, class Key>
|
|
static inline bool AuTryFind(Map &map, const Key &key)
|
|
{
|
|
auto itr = map.find(key);
|
|
if (itr != map.end())
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template<typename Map, class Key>
|
|
static inline bool AuTryFind(Map *map, const Key &key)
|
|
{
|
|
auto itr = map->find(key);
|
|
if (itr != map->end())
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template<typename Map, class Key, typename Value>
|
|
static inline bool AuTryFindGeneric(Map &map, const Key &key, Value *&ptr)
|
|
{
|
|
auto itr = map.find(key);
|
|
if (itr != map.end())
|
|
{
|
|
ptr = &*itr;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
ptr = nullptr;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template<typename Map, class Key>
|
|
static inline bool AuTryDelete(Map &map, const Key &key)
|
|
{
|
|
auto itr = map.find(key);
|
|
if (itr != map.end())
|
|
{
|
|
map.erase(itr);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template<typename List, class Key>
|
|
static inline bool AuTryDeleteList(List &list, const Key &key)
|
|
{
|
|
auto itr = std::find(list.begin(), list.end(), key);
|
|
if (itr != list.end())
|
|
{
|
|
list.erase(itr);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template<typename Container, typename Type>
|
|
static inline bool AuTryInsert(Container &container, const Type &value)
|
|
{
|
|
try
|
|
{
|
|
container.insert(container.end(), value);
|
|
|
|
return true;
|
|
}
|
|
catch (...)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
template<typename Container, typename Type>
|
|
static inline bool AuTryInsert(Container &container, Type &&value)
|
|
{
|
|
try
|
|
{
|
|
container.insert(container.end(), value);
|
|
|
|
return true;
|
|
}
|
|
catch (...)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template<typename Container, typename Type>
|
|
static inline bool AuTryInsert(Container *container, const Type &value)
|
|
{
|
|
try
|
|
{
|
|
container->insert(container->end(), value);
|
|
|
|
return true;
|
|
}
|
|
catch (...)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template<typename Container, typename Type>
|
|
static inline bool AuTryInsert(Container *container, Type &&value)
|
|
{
|
|
try
|
|
{
|
|
container->insert(container->end(), value);
|
|
|
|
return true;
|
|
}
|
|
catch (...)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template<typename Container, typename Type>
|
|
static inline bool AuTryInsertNoEnd(Container &container, Type &&value) // move
|
|
{
|
|
try
|
|
{
|
|
container.insert(value);
|
|
|
|
return true;
|
|
}
|
|
catch (...)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template<typename Container, typename Type>
|
|
static inline bool AuTryInsertNoEnd(Container &container, const Type &value) // copy
|
|
{
|
|
try
|
|
{
|
|
container.insert(value);
|
|
|
|
return true;
|
|
}
|
|
catch (...)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template<typename Container, typename Type>
|
|
static inline bool AuTryInsertNoEnd(Container *container, Type &&value) // move
|
|
{
|
|
try
|
|
{
|
|
container->insert(value);
|
|
|
|
return true;
|
|
}
|
|
catch (...)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template<typename Container, typename Type>
|
|
static inline bool AuTryInsertNoEnd(Container *container, const Type &value) // copy
|
|
{
|
|
try
|
|
{
|
|
container->insert(value);
|
|
|
|
return true;
|
|
}
|
|
catch (...)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
namespace Aurora::Memory
|
|
{
|
|
struct ByteBuffer;
|
|
}
|
|
|
|
template<typename T>
|
|
static inline bool AuTryResize(T &list, AuUInt length)
|
|
{
|
|
try
|
|
{
|
|
if constexpr (std::is_same_v<T, Aurora::Memory::ByteBuffer>)
|
|
{
|
|
return list.Resize(length);
|
|
}
|
|
else
|
|
{
|
|
list.resize(length);
|
|
return true;
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static inline std::string AuReplaceAll(std::string &str, const std::string &from, const std::string &to)
|
|
{
|
|
size_t start_pos = 0;
|
|
while ((start_pos = str.find(from, start_pos)) != std::string::npos)
|
|
{
|
|
str.replace(start_pos, from.length(), to);
|
|
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
|
|
}
|
|
return str;
|
|
}
|
|
|
|
// i told myself not to copy this, required a split function twice, now here we are :D
|
|
static inline AuList<AuString> AuSplitString(const AuString& str, const AuString& delim, bool ignoreEmpty = true)
|
|
{
|
|
AuList<AuString> tokens;
|
|
AuUInt prev = 0, pos = 0;
|
|
do
|
|
{
|
|
pos = str.find(delim, prev);
|
|
if (pos == AuString::npos) pos = str.length();
|
|
auto token = str.substr(prev, pos-prev);
|
|
if ((!token.empty()) && ignoreEmpty) tokens.push_back(token);
|
|
prev = pos + delim.length();
|
|
}
|
|
while (pos < str.length() && prev < str.length());
|
|
return tokens;
|
|
}
|
|
|
|
// more copy/pasta. work smart, not hard.
|
|
// i dont want to waste time working out template kinks between clang and msvc
|
|
template<template<typename...> class base,typename derived>
|
|
struct is_base_of_template_impl_au
|
|
{
|
|
template<typename... Ts>
|
|
static constexpr std::true_type test(const base<Ts...> *);
|
|
static constexpr std::false_type test(...);
|
|
using type = decltype(test(std::declval<derived*>()));
|
|
};
|
|
|
|
template < template <typename...> class base,typename derived>
|
|
using AuIsBaseOfTemplate = typename is_base_of_template_impl_au<base,derived>::type;
|
|
|
|
template<typename T>
|
|
static inline bool AuTestBit(T value, AuUInt8 idx)
|
|
{
|
|
return value & (T(1) << T(idx));
|
|
}
|
|
|
|
template<typename T>
|
|
static inline void AuSetBit(T &value, AuUInt8 idx)
|
|
{
|
|
value |= T(1) << T(idx);
|
|
}
|
|
|
|
template<typename T>
|
|
static inline void AuClearBit(T &value, AuUInt8 idx)
|
|
{
|
|
value &= ~(T(1) << T(idx));
|
|
}
|
|
|
|
#if defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86) || defined(AURORA_ARCH_ARM)
|
|
#define AURORA_PERMIT_ARBITRARY_REF
|
|
#endif
|
|
|
|
template<typename T>
|
|
static inline T AuReadGenericLE(const void *ptr, int offset)
|
|
{
|
|
#if defined(AURORA_PERMIT_ARBITRARY_REF) && defined(AU_CPU_ENDIAN_LITTLE)
|
|
return *reinterpret_cast<const T *>(reinterpret_cast<const AuUInt8 *>(ptr) + offset);
|
|
#else
|
|
T temp;
|
|
std::memcpy(&temp, reinterpret_cast<const AuUInt8 *>(ptr) + offset, sizeof(temp));
|
|
#if !defined(AU_CPU_ENDIAN_LITTLE)
|
|
#if defined(AURORA_COMPILER_MSVC)
|
|
if constexpr (std::is_same_v<T, AuUInt32> || std::is_same_v<T, AuInt32>)
|
|
{
|
|
temp = _byteswap_ulong(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt64> || std::is_same_v<T, AuInt64>)
|
|
{
|
|
temp = _byteswap_uint64(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt16> || std::is_same_v<T, AuInt16>)
|
|
{
|
|
temp = _byteswap_ushort(temp);
|
|
}
|
|
#else
|
|
if constexpr (std::is_same_v<T, AuUInt32> || std::is_same_v<T, AuInt32>)
|
|
{
|
|
temp = __builtin_bswap32(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt64> || std::is_same_v<T, AuInt64>)
|
|
{
|
|
temp = __builtin_bswap64(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt16> || std::is_same_v<T, AuInt16>)
|
|
{
|
|
temp = (temp << 8) | ((temp >> 8) & 0xFF);
|
|
}
|
|
#endif
|
|
#endif
|
|
return temp;
|
|
#endif
|
|
}
|
|
|
|
template<typename T>
|
|
static inline T AuReadGenericBE(const void *ptr, int offset)
|
|
{
|
|
#if defined(AURORA_PERMIT_ARBITRARY_REF) && defined(AU_CPU_ENDIAN_BIG)
|
|
return *reinterpret_cast<const T *>(reinterpret_cast<const AuUInt8 *>(ptr) + offset);
|
|
#else
|
|
T temp;
|
|
std::memcpy(&temp, reinterpret_cast<const AuUInt8 *>(ptr) + offset, sizeof(temp));
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
#if defined(AURORA_COMPILER_MSVC)
|
|
if constexpr (std::is_same_v<T, AuUInt32> || std::is_same_v<T, AuInt32>)
|
|
{
|
|
temp = _byteswap_ulong(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt64> || std::is_same_v<T, AuInt64>)
|
|
{
|
|
temp = _byteswap_uint64(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt16> || std::is_same_v<T, AuInt16>)
|
|
{
|
|
temp = _byteswap_ushort(temp);
|
|
}
|
|
#else
|
|
if constexpr (std::is_same_v<T, AuUInt32> || std::is_same_v<T, AuInt32>)
|
|
{
|
|
temp = __builtin_bswap32(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt64> || std::is_same_v<T, AuInt64>)
|
|
{
|
|
temp = __builtin_bswap64(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt16> || std::is_same_v<T, AuInt16>)
|
|
{
|
|
temp = (temp << 8) | ((temp >> 8) & 0xFF);
|
|
}
|
|
#endif
|
|
#endif
|
|
return temp;
|
|
#endif
|
|
}
|
|
|
|
static inline AuUInt64 AuReadU64LE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericLE<AuUInt64>(ptr, offset);
|
|
}
|
|
|
|
static inline AuUInt32 AuReadU32LE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericLE<AuUInt32>(ptr, offset);
|
|
}
|
|
|
|
static inline AuUInt16 AuReadU16LE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericLE<AuUInt16>(ptr, offset);
|
|
}
|
|
|
|
static inline AuUInt8 AuReadU8LE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericLE<AuUInt8>(ptr, offset);
|
|
}
|
|
|
|
static inline AuInt64 AuReadS64LE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericLE<AuInt64>(ptr, offset);
|
|
}
|
|
|
|
static inline AuInt32 AuReadS32LE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericLE<AuInt32>(ptr, offset);
|
|
}
|
|
|
|
static inline AuInt16 AuReadS16LE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericLE<AuInt16>(ptr, offset);
|
|
}
|
|
|
|
static inline AuInt8 AuReadS8LE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericLE<AuInt8>(ptr, offset);
|
|
}
|
|
|
|
static inline AuUInt64 AuReadU64BE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericBE<AuUInt64>(ptr, offset);
|
|
}
|
|
|
|
static inline AuUInt32 AuReadU32BE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericBE<AuUInt32>(ptr, offset);
|
|
}
|
|
|
|
static inline AuUInt16 AuReadU16BE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericBE<AuUInt16>(ptr, offset);
|
|
}
|
|
|
|
static inline AuUInt8 AuReadU8BE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericBE<AuUInt8>(ptr, offset);
|
|
}
|
|
|
|
static inline AuInt64 AuReadS64BE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericBE<AuInt64>(ptr, offset);
|
|
}
|
|
|
|
static inline AuInt32 AuReadS32BE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericBE<AuInt32>(ptr, offset);
|
|
}
|
|
|
|
static inline AuInt16 AuReadS16BE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericBE<AuInt16>(ptr, offset);
|
|
}
|
|
|
|
static inline AuInt8 AuReadS8BE(const void *ptr, int offset)
|
|
{
|
|
return AuReadGenericBE<AuInt8>(ptr, offset);
|
|
}
|
|
|
|
static inline AuUInt64 AuReadU64(const void *ptr, int offset)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
return AuReadU64LE(ptr, offset);
|
|
#else
|
|
return AuReadU64BE(ptr, offset);
|
|
#endif
|
|
}
|
|
|
|
static inline AuUInt32 AuReadU32(const void *ptr, int offset)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
return AuReadU32LE(ptr, offset);
|
|
#else
|
|
return AuReadU32BE(ptr, offset);
|
|
#endif
|
|
}
|
|
|
|
static inline AuUInt16 AuReadU16(const void *ptr, int offset)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
return AuReadU16LE(ptr, offset);
|
|
#else
|
|
return AuReadU16BE(ptr, offset);
|
|
#endif
|
|
}
|
|
|
|
static inline AuUInt8 AuReadU8(const void *ptr, int offset)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
return AuReadU8LE(ptr, offset);
|
|
#else
|
|
return AuReadU8BE(ptr, offset);
|
|
#endif
|
|
}
|
|
|
|
static inline AuInt64 AuReadS64(const void *ptr, int offset)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
return AuReadS64LE(ptr, offset);
|
|
#else
|
|
return AuReadS64BE(ptr, offset);
|
|
#endif
|
|
}
|
|
|
|
static inline AuInt32 AuReadS32(const void *ptr, int offset)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
return AuReadS32LE(ptr, offset);
|
|
#else
|
|
return AuReadS32BE(ptr, offset);
|
|
#endif
|
|
}
|
|
|
|
static inline AuInt16 AuReadS16(const void *ptr, int offset)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
return AuReadS16LE(ptr, offset);
|
|
#else
|
|
return AuReadS16BE(ptr, offset);
|
|
#endif
|
|
}
|
|
|
|
static inline AuInt8 AuReadS8(const void *ptr, int offset)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
return AuReadS8LE(ptr, offset);
|
|
#else
|
|
return AuReadS8BE(ptr, offset);
|
|
#endif
|
|
}
|
|
|
|
template<typename T>
|
|
static inline void AuWriteGenericLE(void *ptr, int offset, T value)
|
|
{
|
|
#if defined(AURORA_PERMIT_ARBITRARY_REF) && defined(AU_CPU_ENDIAN_LITTLE)
|
|
*reinterpret_cast<T *>(reinterpret_cast<AuUInt8 *>(ptr) + offset) = value;
|
|
#else
|
|
T temp = value;
|
|
#if !defined(AU_CPU_ENDIAN_LITTLE)
|
|
#if defined(AURORA_COMPILER_MSVC)
|
|
if constexpr (std::is_same_v<T, AuUInt32> || std::is_same_v<T, AuInt32>)
|
|
{
|
|
temp = _byteswap_ulong(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt64> || std::is_same_v<T, AuInt64>)
|
|
{
|
|
temp = _byteswap_uint64(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt16> || std::is_same_v<T, AuInt16>)
|
|
{
|
|
temp = _byteswap_ushort(temp);
|
|
}
|
|
#else
|
|
if constexpr (std::is_same_v<T, AuUInt32> || std::is_same_v<T, AuInt32>)
|
|
{
|
|
temp = __builtin_bswap32(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt64> || std::is_same_v<T, AuInt64>)
|
|
{
|
|
temp = __builtin_bswap64(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt16> || std::is_same_v<T, AuInt16>)
|
|
{
|
|
temp = (temp << 8) | ((temp >> 8) & 0xFF);
|
|
}
|
|
#endif
|
|
#endif
|
|
std::memcpy(reinterpret_cast<AuUInt8 *>(ptr) + offset, &temp, sizeof(temp));
|
|
#endif
|
|
}
|
|
|
|
template<typename T>
|
|
static inline void AuWriteGenericBE(void *ptr, T value, int offset)
|
|
{
|
|
#if defined(AURORA_PERMIT_ARBITRARY_REF) && defined(AU_CPU_ENDIAN_BIG)
|
|
*reinterpret_cast<T *>(reinterpret_cast<AuUInt8 *>(ptr) + offset) = value;
|
|
#else
|
|
T temp = value;
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
#if defined(AURORA_COMPILER_MSVC)
|
|
if constexpr (std::is_same_v<T, AuUInt32> || std::is_same_v<T, AuInt32>)
|
|
{
|
|
temp = _byteswap_ulong(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt64> || std::is_same_v<T, AuInt64>)
|
|
{
|
|
temp = _byteswap_uint64(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt16> || std::is_same_v<T, AuInt16>)
|
|
{
|
|
temp = _byteswap_ushort(temp);
|
|
}
|
|
#else
|
|
if constexpr (std::is_same_v<T, AuUInt32> || std::is_same_v<T, AuInt32>)
|
|
{
|
|
temp = __builtin_bswap32(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt64> || std::is_same_v<T, AuInt64>)
|
|
{
|
|
temp = __builtin_bswap64(temp);
|
|
}
|
|
else if constexpr (std::is_same_v<T, AuUInt16> || std::is_same_v<T, AuInt16>)
|
|
{
|
|
temp = (temp << 8) | ((temp >> 8) & 0xFF);
|
|
}
|
|
#endif
|
|
#endif
|
|
std::memcpy(reinterpret_cast<AuUInt8 *>(ptr) + offset, &temp, sizeof(temp));
|
|
#endif
|
|
}
|
|
|
|
static inline void AuWriteU64LE(void *ptr, int offset, AuUInt64 value)
|
|
{
|
|
AuWriteGenericLE<AuUInt64>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteU32LE(void *ptr, int offset, AuUInt32 value)
|
|
{
|
|
AuWriteGenericLE<AuUInt32>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteU16LE(void *ptr, int offset, AuUInt16 value)
|
|
{
|
|
AuWriteGenericLE<AuUInt16>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteU8LE(void *ptr, int offset, AuUInt8 value)
|
|
{
|
|
AuWriteGenericLE<AuUInt8>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteS64LE(void *ptr, int offset, AuInt64 value)
|
|
{
|
|
AuWriteGenericLE<AuInt64>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteS32LE(void *ptr, int offset, AuInt32 value)
|
|
{
|
|
AuWriteGenericLE<AuInt32>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteS16LE(void *ptr, int offset, AuInt16 value)
|
|
{
|
|
AuWriteGenericLE<AuInt16>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteS8LE(void *ptr, int offset, AuInt8 value)
|
|
{
|
|
AuWriteGenericLE<AuInt8>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteU64BE(void *ptr, int offset, AuUInt64 value)
|
|
{
|
|
AuWriteGenericBE<AuUInt64>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteU32BE(void *ptr, int offset, AuUInt32 value)
|
|
{
|
|
AuWriteGenericBE<AuUInt32>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteU16BE(void *ptr, int offset, AuUInt16 value)
|
|
{
|
|
AuWriteGenericBE<AuUInt16>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteU8BE(void *ptr, int offset, AuUInt8 value)
|
|
{
|
|
AuWriteGenericBE<AuUInt8>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteS64BE(void *ptr, int offset, AuInt64 value)
|
|
{
|
|
AuWriteGenericBE<AuInt64>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteS32BE(void *ptr, int offset, AuInt32 value)
|
|
{
|
|
AuWriteGenericBE<AuInt32>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteS16BE(void *ptr, int offset, AuInt16 value)
|
|
{
|
|
AuWriteGenericBE<AuInt16>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteS8BE(void *ptr, int offset, AuInt8 value)
|
|
{
|
|
AuWriteGenericBE<AuInt8>(ptr, offset, value);
|
|
}
|
|
|
|
static inline void AuWriteU64(void *ptr, int offset, AuUInt64 value)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
AuWriteU64LE(ptr, offset, value);
|
|
#else
|
|
AuWriteU64BE(ptr, offset, value);
|
|
#endif
|
|
}
|
|
|
|
static inline void AuWriteU32(void *ptr, int offset, AuUInt32 value)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
AuWriteU32LE(ptr, offset, value);
|
|
#else
|
|
AuWriteU32BE(ptr, offset, value);
|
|
#endif
|
|
}
|
|
|
|
static inline void AuWriteU16(void *ptr, int offset, AuUInt16 value)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
AuWriteU16LE(ptr, offset, value);
|
|
#else
|
|
AuWriteU16BE(ptr, offset, value);
|
|
#endif
|
|
}
|
|
|
|
static inline void AuWriteU8(void *ptr, int offset, AuUInt8 value)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
AuWriteU8LE(ptr, offset, value);
|
|
#else
|
|
AuWriteU8BE(ptr, offset, value);
|
|
#endif
|
|
}
|
|
|
|
static inline void AuWriteS64(void *ptr, int offset, AuInt64 value)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
AuWriteS64LE(ptr, offset, value);
|
|
#else
|
|
AuWriteS64BE(ptr, offset, value);
|
|
#endif
|
|
}
|
|
|
|
static inline void AuWriteS32(void *ptr, int offset, AuInt32 value)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
AuWriteS32LE(ptr, offset, value);
|
|
#else
|
|
AuWriteS32BE(ptr, offset, value);
|
|
#endif
|
|
}
|
|
|
|
static inline void AuWriteS16(void *ptr, int offset, AuInt16 value)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
AuWriteS16LE(ptr, offset, value);
|
|
#else
|
|
AuWriteS16BE(ptr, offset, value);
|
|
#endif
|
|
}
|
|
|
|
static inline void AuWriteS8(void *ptr, int offset, AuInt8 value)
|
|
{
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
AuWriteS8LE(ptr, offset, value);
|
|
#else
|
|
AuWriteS8BE(ptr, offset, value);
|
|
#endif
|
|
}
|