AuroraRuntime/Include/AuroraUtils.hpp

1313 lines
32 KiB
C++
Raw Normal View History

2021-06-27 21:25:29 +00:00
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuroraUtils.hpp
Date: 2021-6-9
Author: Reece
***/
#pragma once
2021-09-06 10:58:08 +00:00
#if !defined(AURORA_RUNTIME_MAKE_SHARED)
#define AURORA_RUNTIME_MAKE_SHARED std::make_shared
#endif
template<typename T, typename... Args>
static auline AuSPtr<T> AuMakeShared(Args&&... args)
2021-09-06 10:58:08 +00:00
{
try
{
return AURORA_RUNTIME_MAKE_SHARED<T>(AuForward<Args>(args)...);
}
catch (...)
{
return {};
}
2021-09-06 10:58:08 +00:00
}
#if !defined(AURORA_RUNTIME_MAKE_PAIR)
#define AURORA_RUNTIME_MAKE_PAIR std::make_pair
#endif
template<typename... Args>
static auline auto AuMakePair(Args&&... args)
2021-09-06 10:58:08 +00:00
{
return AURORA_RUNTIME_MAKE_PAIR(AuForward<Args>(args)...);
2021-09-06 10:58:08 +00:00
}
2022-01-19 17:08:13 +00:00
#if !defined(AURORA_RUNTIME_MAKE_TUPLE)
#define AURORA_RUNTIME_MAKE_TUPLE std::make_tuple
#endif
template<typename... Args>
static auline auto AuMakeTuple(Args&&... args)
{
return AURORA_RUNTIME_MAKE_TUPLE(AuForward<Args>(args)...);
2022-01-19 17:08:13 +00:00
}
#if !defined(AURORA_RUNTIME_TO_STRING)
#define AURORA_RUNTIME_TO_STRING std::to_string
#endif
template<class T>
AuString AuToString(const T &obj)
{
return AURORA_RUNTIME_TO_STRING(obj);
}
#if !defined(AURORA_RUNTIME_EXCHANGE)
#define AURORA_RUNTIME_EXCHANGE std::exchange
#endif
template<class T, class U = T>
T AuExchange(T &obj, U &&new_value)
{
return AURORA_RUNTIME_EXCHANGE(obj, new_value);
}
#if !defined(AURORA_RUNTIME_MEMCMP)
#define AURORA_RUNTIME_MEMCMP std::memcmp
#endif
static auline int AuMemcmp(const void *dest, const void *src, size_t n)
{
return AURORA_RUNTIME_MEMCMP(dest, src, n);
}
#if !defined(AURORA_RUNTIME_MEMSET)
#define AURORA_RUNTIME_MEMSET std::memset
#endif
static auline void *AuMemset(void *dest, AuUInt8 c, size_t n)
{
return AURORA_RUNTIME_MEMSET(dest, c, n);
}
#if !defined(AURORA_RUNTIME_MEMCPY)
#define AURORA_RUNTIME_MEMCPY std::memcpy
#endif
static auline void *AuMemcpy(void *dest, const void *src, size_t n)
{
return AURORA_RUNTIME_MEMCPY(dest, src, n);
}
#if !defined(AURORA_RUNTIME_MEMMOVE)
#define AURORA_RUNTIME_MEMMOVE std::memmove
#endif
static auline void *AuMemmove(void *dest, const void *src, size_t n)
{
return AURORA_RUNTIME_MEMMOVE(dest, src, n);
}
#if defined(AURORA_IS_MODERNNT_DERIVED) && (defined(_WINDOWS_) || defined(_OTHER_MS_MAIN_HEADER_GUARDS_HERE))
static auline void AuWin32CloseHandle(HANDLE &handle)
2021-09-06 10:58:08 +00:00
{
HANDLE local;
2022-01-19 17:08:13 +00:00
if ((local = AuExchange(handle, INVALID_HANDLE_VALUE)) != INVALID_HANDLE_VALUE)
2021-09-06 10:58:08 +00:00
{
CloseHandle(local);
}
}
#endif
template<typename T>
static AuSPtr<T> AuUnsafeRaiiToShared(T *in)
{
return AuSPtr<T>(in, [](T *){});
}
template<typename T, class Z>
static AuSPtr<T> AuUnsafeRaiiToShared(const AuUPtr<T, Z> &in)
{
return AuSPtr<T>(in.get(), [](T *){});
}
2021-06-27 21:25:29 +00:00
template<typename T, int Z>
2021-09-06 10:58:08 +00:00
static constexpr int AuArraySize(const T(&array)[Z])
2021-06-27 21:25:29 +00:00
{
return Z;
}
2021-09-06 10:58:08 +00:00
#if defined(DEBUG) || defined(STAGING)
2021-06-27 21:25:29 +00:00
2021-09-15 01:14:29 +00:00
template<typename ... T>
static auline void __declspec(noreturn) SysPanic(T... args);
2021-09-15 01:14:29 +00:00
2021-06-27 21:25:29 +00:00
template<typename Z, typename T>
static void auline SafeDelete(T *in)
2021-06-27 21:25:29 +00:00
{
static_assert(std::is_base_of<T, typename std::remove_pointer<Z>::type>::value, "Couldn't not safe delete from type T because it is not derived from Z");
2021-06-27 21:25:29 +00:00
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 auline SafeDelete(T *in)
2021-06-27 21:25:29 +00:00
{
static_assert(std::is_base_of<T, typename std::remove_pointer<Z>::type>::value, "Couldn't not safe delete from type T because it is not derived from Z");
2021-06-27 21:25:29 +00:00
delete static_cast<Z>(in);
}
#endif
struct IAuNullDelegate
{
virtual void OnCall() = 0;
};
struct AuNullCallback
{
const AuVoidFunc voidFunc;
const AuSPtr<IAuNullDelegate> callbackFunc;
AU_DEFINE_CTOR_ONE(AuNullCallback, (AuVoidFunc, voidFunc));
AU_DEFINE_CTOR_ONE(AuNullCallback, (AuSPtr<IAuNullDelegate>, callbackFunc));
auline void operator()()
{
if (voidFunc)
{
voidFunc();
}
else if (callbackFunc)
{
callbackFunc->OnCall();
}
}
};
static constexpr auline AuUInt32 AuConvertMagicTag32(const char buffer[4])
2021-06-27 21:25:29 +00:00
{
2021-09-06 10:58:08 +00:00
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;
2021-06-27 21:25:29 +00:00
}
static constexpr auline AuUInt64 AuConvertMagicTag64(const char buffer[8])
2021-06-27 21:25:29 +00:00
{
2021-09-06 10:58:08 +00:00
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;
2021-06-27 21:25:29 +00:00
}
template<typename T, typename Z>
static auline AuOptional<AuSPtr<T>> AuOptionalSharedDynamicCast(AuOptional<AuSPtr<Z>> &in)
2021-06-27 21:25:29 +00:00
{
if (!in.has_value()) return {};
return std::dynamic_pointer_cast<T>(in.value());
}
template<typename T, typename Z>
static auline AuOptional<AuSPtr<T>> AuOptionalSharedStaticCast(AuOptional<AuSPtr<Z>> &in)
2021-06-27 21:25:29 +00:00
{
if (!in.has_value()) return {};
return AuStaticPointerCast<T>(in.value());
2021-06-27 21:25:29 +00:00
}
static auline bool AuEndsWith(AuString const &value, AuString const &ending)
2021-06-27 21:25:29 +00:00
{
if (ending.size() > value.size()) return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
static auline bool AuStartsWith(AuString const &value, AuString const &starting)
2021-06-27 21:25:29 +00:00
{
return value.rfind(starting, 0) == 0;
}
template<typename T>
static auline AuString AuToStringASCIIOp(T op, const AuString &in)
2021-06-27 21:25:29 +00:00
{
AuString ret;
ret.resize(in.size());
std::transform(in.begin(), in.end(), ret.begin(), [=](const char &c)
{
return op(c);
});
return ret;
}
static auline AuString AuToLower(const AuString &in)
2021-06-27 21:25:29 +00:00
{
2021-09-06 10:58:08 +00:00
return AuToStringASCIIOp<int(*)(int)>(std::tolower, in);
2021-06-27 21:25:29 +00:00
}
static auline AuString AuToUpper(const AuString &in)
2021-06-27 21:25:29 +00:00
{
2021-09-06 10:58:08 +00:00
return AuToStringASCIIOp<int(*)(int)>(std::toupper, in);
2021-06-27 21:25:29 +00:00
}
2021-06-30 09:28:52 +00:00
template<typename Map, class Key, typename Value>
static auline bool AuTryFind(Map &map, const Key &key, Value *&ptr)
2021-06-27 21:25:29 +00:00
{
auto itr = map.find(key);
if (itr != map.end())
{
ptr = &itr->second;
return true;
}
else
{
ptr = nullptr;
return false;
}
}
2021-06-30 09:28:52 +00:00
template<typename Map, class Key, typename Value>
static auline bool AuTryFind(Map *map, const Key &key, Value *&ptr)
2021-06-27 21:25:29 +00:00
{
auto itr = map->find(key);
if (itr != map->end())
{
ptr = &itr->second;
return true;
}
else
{
ptr = nullptr;
return false;
}
}
2021-06-30 09:28:52 +00:00
template<typename Map, class Key>
static auline bool AuTryFind(Map &map, const Key &key)
2021-06-27 21:25:29 +00:00
{
auto itr = map.find(key);
if (itr != map.end())
{
return true;
}
else
{
return false;
}
}
2021-10-01 16:36:09 +00:00
template<typename Range, class Key>
static auline bool AuExists(Range &a, const Key &item)
2021-10-01 16:36:09 +00:00
{
return std::find(a.begin(), a.end(), item) != a.end();
}
2021-06-30 09:28:52 +00:00
template<typename Map, class Key>
static auline bool AuTryFind(Map *map, const Key &key)
2021-06-27 21:25:29 +00:00
{
auto itr = map->find(key);
if (itr != map->end())
{
return true;
}
else
{
return false;
}
}
2021-09-06 10:58:08 +00:00
2021-06-30 09:28:52 +00:00
template<typename Map, class Key, typename Value>
static auline bool AuTryFindGeneric(Map &map, const Key &key, Value *&ptr)
2021-06-27 21:25:29 +00:00
{
auto itr = map.find(key);
if (itr != map.end())
{
ptr = &*itr;
return true;
}
else
{
ptr = nullptr;
return false;
}
}
2022-01-19 17:08:13 +00:00
template<typename Map, class Key>
static auline bool AuTryFindGeneric(Map &map, const Key &key)
{
if (map.find(key) != map.end())
{
return true;
}
else
{
return false;
}
}
2021-06-30 09:28:52 +00:00
template<typename Map, class Key>
static auline bool AuTryDelete(Map &map, const Key &key)
2021-06-27 21:25:29 +00:00
{
auto itr = map.find(key);
if (itr != map.end())
{
map.erase(itr);
return true;
}
else
{
return false;
}
}
2021-06-30 09:28:52 +00:00
template<typename List, class Key>
static auline bool AuTryDeleteList(List &list, const Key &key)
2021-06-27 21:25:29 +00:00
{
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 auline bool AuTryInsert(Container &container, const Type &value)
2021-06-27 21:25:29 +00:00
{
try
{
container.insert(container.end(), value);
return true;
}
catch (...)
{
return false;
}
}
template<typename Container, typename Type>
static auline bool AuTryInsert(Container &container, Type &&value)
2021-06-27 21:25:29 +00:00
{
try
{
container.insert(container.end(), value);
return true;
}
catch (...)
{
return false;
}
}
template<typename Container, typename Type>
static auline bool AuTryInsert(Container *container, const Type &value)
2021-06-27 21:25:29 +00:00
{
try
{
container->insert(container->end(), value);
return true;
}
catch (...)
{
return false;
}
}
template<typename Container, typename Type>
static auline bool AuTryInsert(Container *container, Type &&value)
2021-06-27 21:25:29 +00:00
{
try
{
container->insert(container->end(), value);
return true;
}
catch (...)
{
return false;
}
}
template<typename Container, typename Type>
static auline bool AuTryInsertNoEnd(Container &container, Type &&value) // move
2021-06-27 21:25:29 +00:00
{
try
{
container.insert(value);
return true;
}
catch (...)
{
return false;
}
}
template<typename Container, typename Type>
static auline bool AuTryInsertNoEnd(Container &container, const Type &value) // copy
2021-06-27 21:25:29 +00:00
{
try
{
container.insert(value);
return true;
}
catch (...)
{
return false;
}
}
template<typename Container, typename Type>
static auline bool AuTryInsertNoEnd(Container *container, Type &&value) // move
2021-06-27 21:25:29 +00:00
{
try
{
container->insert(value);
return true;
}
catch (...)
{
return false;
}
}
template<typename Container, typename Type>
static auline bool AuTryInsertNoEnd(Container *container, const Type &value) // copy
2021-06-27 21:25:29 +00:00
{
try
{
container->insert(value);
return true;
}
catch (...)
{
return false;
}
}
2021-09-15 01:14:29 +00:00
namespace Aurora::Memory
{
struct ByteBuffer;
}
2021-06-27 21:25:29 +00:00
template<typename T>
static auline bool AuTryResize(T &list, AuUInt length)
2021-06-27 21:25:29 +00:00
{
try
{
2022-01-19 17:08:13 +00:00
if constexpr (AuIsSame_v<T, Aurora::Memory::ByteBuffer>)
{
return list.Resize(length);
}
else
{
list.resize(length);
return true;
}
2021-06-27 21:25:29 +00:00
}
catch (...)
{
return false;
}
}
2021-09-18 20:10:25 +00:00
template<typename T>
static auline bool AuTryDownsize(T &list, AuUInt length)
2021-09-18 20:10:25 +00:00
{
try
{
2022-01-19 17:08:13 +00:00
if constexpr (AuIsSame_v<T, Aurora::Memory::ByteBuffer>)
2021-09-18 20:10:25 +00:00
{
return list.Resize(length);
}
else
{
list.resize(length);
list.shrink_to_fit();
return true;
}
}
catch (...)
{
return false;
}
}
static auline AuString AuReplaceAll(AuString &str, const AuString &from, const AuString &to)
2021-06-27 21:25:29 +00:00
{
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; // :(
2021-06-27 21:25:29 +00:00
}
// i told myself not to copy this, required a split function twice, now here we are :D
static auline AuList<AuString> AuSplitString(const AuString& str, const AuString& delim, bool ignoreEmpty = true)
2021-06-27 21:25:29 +00:00
{
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);
2021-06-27 21:25:29 +00:00
prev = pos + delim.length();
}
while (pos < str.length() && prev < str.length());
return tokens;
}
2021-06-30 09:28:52 +00:00
// more copy/pasta. work smart, not hard.
// i dont want to waste time working out template kinks between clang and msvc
2021-09-06 10:58:08 +00:00
template<template<typename...> class base,typename derived>
struct is_base_of_template_impl_au
2021-06-27 21:25:29 +00:00
{
template<typename... Ts>
static constexpr AuTrueType test(const base<Ts...> *);
static constexpr AuFalseType test(...);
2021-06-27 21:25:29 +00:00
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 Tuple, std::size_t ... Is>
auto AuTuplePopFrontImpl(const Tuple& tuple, std::index_sequence<Is...>)
{
return std::make_tuple(std::get<1 + Is>(tuple)...);
}
template <typename Tuple>
auto AuTuplePopFront(const Tuple& tuple)
{
return AuTuplePopFrontImpl(tuple, std::make_index_sequence<std::tuple_size<Tuple>::value - 1>());
}
template<class T>
constexpr const T AuMin(const T &a, const T &b)
{
return a < b ? a : b;
}
template<class T>
constexpr const T AuMax(const T &a, const T &b)
{
return a > b ? b : a;
}
template<typename T>
static auline bool AuTestBit(T value, AuUInt8 idx)
{
return value & (T(1) << T(idx));
}
template<typename T>
static auline void AuSetBit(T &value, AuUInt8 idx)
{
value |= T(1) << T(idx);
}
template<typename T>
static auline void AuClearBit(T &value, AuUInt8 idx)
{
value &= ~(T(1) << T(idx));
}
template<typename T>
static auline bool AuBitScanForward(AuUInt8 &index, T value)
{
unsigned long ret;
bool success;
success = false;
index = 0;
#if defined(AURORA_COMPILER_MSVC)
2022-01-19 14:29:14 +00:00
if constexpr (sizeof(T) == sizeof(AuUInt64))
#if defined(AURORA_IS_32BIT)
if (!_BitScanForward(&ret, static_cast<AuUInt32>(value & 0xffffffff)))
{
2022-01-20 13:43:37 +00:00
if (!_BitScanForward(&ret, static_cast<AuUInt32>((value >> 32) & 0xffffffff)))
{
return false;
}
ret += 32;
}
#else
success = _BitScanForward64(&ret, static_cast<AuUInt64>(value));
#endif
else success = _BitScanForward(&ret, static_cast<unsigned long>(value));
#elif defined(AURORA_COMPILER_GCC) || defined(AURORA_COMPILER_CLANG)
2022-01-20 13:43:37 +00:00
if (value == 0)
{
return false;
}
if constexpr (sizeof(T) == sizeof(AuUInt64))
#if defined(AURORA_IS_32BIT)
auto lower = static_cast<AuUInt32>(value & 0xffffffff));
if (lower == 0)
{
ret = __builtin_ctzl(static_cast<AuUInt32>((value >> 32) & 0xffffffff));
ret += 32;
}
else
{
ret = __builtin_ctzl(static_cast<AuUInt32>(lower));
}
#else
ret = __builtin_ctzll(static_cast<AuUInt64>(value));
#endif
else if constexpr (sizeof(T) == sizeof(unsigned long))
ret = __builtin_ctzl(static_cast<unsigned long>(value));
2022-01-19 14:29:14 +00:00
else if constexpr (sizeof(T) == sizeof(unsigned int))
ret = __builtin_ctz(static_cast<unsigned int>(value));
success = true;
#endif
index = ret;
return success;
}
template<typename T>
struct AuHalfWord
{
using ReturnType_t = AuConditional_t<AuIsSame_v<T, AuUInt64>, AuUInt32, AuConditional_t<AuIsSame_v<T, AuUInt32>, AuUInt32, AuConditional_t<AuIsSame_v<T, AuUInt16>, AuUInt8, AuFalseType>>>;
static ReturnType_t ToLower(T in)
{
if constexpr (AuIsSame_v<T, AuUInt64>)
{
return in & AuUInt64(0xFFFFFFFF);
}
else if constexpr (AuIsSame_v<T, AuUInt32>)
{
return in & 0xFFFF;
}
else if constexpr (AuIsSame_v<T, AuUInt16>)
{
return in & 0xFF;
}
else
{
return {};
}
}
static ReturnType_t ToHigher(T in)
{
if constexpr (AuIsSame_v<T, AuUInt64>)
{
return (in >> AuUInt64(32)) & AuUInt64(0xFFFFFFFF);
}
else if constexpr (AuIsSame_v<T, AuUInt32>)
{
return (in >> 16) & 0xFFFF;
}
else if constexpr (AuIsSame_v<T, AuUInt16>)
{
return (in >> 8) & 0xFF;
}
else
{
return {};
}
}
};
template<typename T>
static auto AuBitsToLower(T in)
{
return AuHalfWord<T>::ToLower(in);
}
template<typename T>
static auto AuBitsToHigher(T in)
{
return AuHalfWord<T>::ToHigher(in);
}
template<typename T>
static AuUInt8 AuPopCnt(T in)
{
#if defined(AURORA_COMPILER_MSVC)
#if defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86)
#if defined(AURORA_ARCH_X64)
if constexpr (sizeof(T) == sizeof(AuUInt64))
return _mm_popcnt_u64(in);
else
#endif
if constexpr (sizeof(T) < sizeof(AuUInt32))
return __popcnt(in);
else if constexpr (sizeof(T) <= sizeof(AuUInt16))
return __popcnt16(in);
#endif
#else
if constexpr (sizeof(T) == sizeof(unsigned long long))
return __builtin_popcountll(static_cast<unsigned long long>(value));
else if constexpr (sizeof(T) == sizeof(unsigned long))
return __builtin_popcountl(static_cast<unsigned long>(value));
else if constexpr (sizeof(T) == sizeof(unsigned int))
return __builtin_popcount(static_cast<unsigned int>(value));
#endif
#if defined(AU_CPU_ENDIAN_LITTLE)
if constexpr (sizeof(T) == sizeof(AuUInt64))
{
AuUInt64 m1 = 0x5555555555555555ll;
AuUInt64 m2 = 0x3333333333333333ll;
AuUInt64 m4 = 0x0F0F0F0F0F0F0F0Fll;
AuUInt64 h01 = 0x0101010101010101ll;
in -= (in >> 1) & m1;
in = (in & m2) + ((in >> 2) & m2);
in = (in + (in >> 4)) & m4;
return (in * h01) >> 56;
}
else if constexpr (sizeof(T) == sizeof(AuUInt32))
{
in = in - ((in >> 1) & 0x55555555);
in = (in & 0x33333333) + ((in >> 2) & 0x33333333);
return (((in + (in >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
}
#endif
return {};
}
// TODO: AuBitScanReverse
#if defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86) || defined(AURORA_ARCH_ARM)
#define AURORA_PERMIT_ARBITRARY_REF
#endif
// I'm sorry to anyone reading this. I wanted it to be verbose. I should've just used my old friends, macros :(
template<typename T>
static auline 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;
2022-01-19 17:08:13 +00:00
AuMemcpy(&temp, reinterpret_cast<const AuUInt8 *>(ptr) + offset, sizeof(temp));
#if !defined(AU_CPU_ENDIAN_LITTLE)
#if defined(AURORA_COMPILER_MSVC)
2022-01-19 17:08:13 +00:00
if constexpr (AuIsSame_v<T, AuUInt32> || AuIsSame_v<T, AuInt32>)
{
temp = _byteswap_ulong(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt64> || AuIsSame_v<T, AuInt64>)
{
temp = _byteswap_uint64(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt16> || AuIsSame_v<T, AuInt16>)
{
temp = _byteswap_ushort(temp);
}
#else
2022-01-19 17:08:13 +00:00
if constexpr (AuIsSame_v<T, AuUInt32> || AuIsSame_v<T, AuInt32>)
{
temp = __builtin_bswap32(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt64> || AuIsSame_v<T, AuInt64>)
{
temp = __builtin_bswap64(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt16> || AuIsSame_v<T, AuInt16>)
{
temp = (temp << 8) | ((temp >> 8) & 0xFF);
}
#endif
#endif
return temp;
#endif
}
template<typename T>
static auline 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;
2022-01-19 17:08:13 +00:00
AuMemcpy(&temp, reinterpret_cast<const AuUInt8 *>(ptr) + offset, sizeof(temp));
#if defined(AU_CPU_ENDIAN_LITTLE)
#if defined(AURORA_COMPILER_MSVC)
2022-01-19 17:08:13 +00:00
if constexpr (AuIsSame_v<T, AuUInt32> || AuIsSame_v<T, AuInt32>)
{
temp = _byteswap_ulong(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt64> || AuIsSame_v<T, AuInt64>)
{
temp = _byteswap_uint64(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt16> || AuIsSame_v<T, AuInt16>)
{
temp = _byteswap_ushort(temp);
}
#else
2022-01-19 17:08:13 +00:00
if constexpr (AuIsSame_v<T, AuUInt32> || AuIsSame_v<T, AuInt32>)
{
temp = __builtin_bswap32(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt64> || AuIsSame_v<T, AuInt64>)
{
temp = __builtin_bswap64(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt16> || AuIsSame_v<T, AuInt16>)
{
temp = (temp << 8) | ((temp >> 8) & 0xFF);
}
#endif
#endif
return temp;
#endif
}
static auline AuUInt64 AuReadU64LE(const void *ptr, int offset)
{
return AuReadGenericLE<AuUInt64>(ptr, offset);
}
static auline AuUInt32 AuReadU32LE(const void *ptr, int offset)
{
return AuReadGenericLE<AuUInt32>(ptr, offset);
}
static auline AuUInt16 AuReadU16LE(const void *ptr, int offset)
{
return AuReadGenericLE<AuUInt16>(ptr, offset);
}
static auline AuUInt8 AuReadU8LE(const void *ptr, int offset)
{
return AuReadGenericLE<AuUInt8>(ptr, offset);
}
static auline AuInt64 AuReadS64LE(const void *ptr, int offset)
{
return AuReadGenericLE<AuInt64>(ptr, offset);
}
static auline AuInt32 AuReadS32LE(const void *ptr, int offset)
{
return AuReadGenericLE<AuInt32>(ptr, offset);
}
static auline AuInt16 AuReadS16LE(const void *ptr, int offset)
{
return AuReadGenericLE<AuInt16>(ptr, offset);
}
static auline AuInt8 AuReadS8LE(const void *ptr, int offset)
{
return AuReadGenericLE<AuInt8>(ptr, offset);
}
static auline AuUInt64 AuReadU64BE(const void *ptr, int offset)
{
return AuReadGenericBE<AuUInt64>(ptr, offset);
}
static auline AuUInt32 AuReadU32BE(const void *ptr, int offset)
{
return AuReadGenericBE<AuUInt32>(ptr, offset);
}
static auline AuUInt16 AuReadU16BE(const void *ptr, int offset)
{
return AuReadGenericBE<AuUInt16>(ptr, offset);
}
static auline AuUInt8 AuReadU8BE(const void *ptr, int offset)
{
return AuReadGenericBE<AuUInt8>(ptr, offset);
}
static auline AuInt64 AuReadS64BE(const void *ptr, int offset)
{
return AuReadGenericBE<AuInt64>(ptr, offset);
}
static auline AuInt32 AuReadS32BE(const void *ptr, int offset)
{
return AuReadGenericBE<AuInt32>(ptr, offset);
}
static auline AuInt16 AuReadS16BE(const void *ptr, int offset)
{
return AuReadGenericBE<AuInt16>(ptr, offset);
}
static auline AuInt8 AuReadS8BE(const void *ptr, int offset)
{
return AuReadGenericBE<AuInt8>(ptr, offset);
}
static auline AuUInt64 AuReadU64(const void *ptr, int offset)
{
#if defined(AU_CPU_ENDIAN_LITTLE)
return AuReadU64LE(ptr, offset);
#else
return AuReadU64BE(ptr, offset);
#endif
}
static auline AuUInt32 AuReadU32(const void *ptr, int offset)
{
#if defined(AU_CPU_ENDIAN_LITTLE)
return AuReadU32LE(ptr, offset);
#else
return AuReadU32BE(ptr, offset);
#endif
}
static auline AuUInt16 AuReadU16(const void *ptr, int offset)
{
#if defined(AU_CPU_ENDIAN_LITTLE)
return AuReadU16LE(ptr, offset);
#else
return AuReadU16BE(ptr, offset);
#endif
}
static auline AuUInt8 AuReadU8(const void *ptr, int offset)
{
#if defined(AU_CPU_ENDIAN_LITTLE)
return AuReadU8LE(ptr, offset);
#else
return AuReadU8BE(ptr, offset);
#endif
}
static auline AuInt64 AuReadS64(const void *ptr, int offset)
{
#if defined(AU_CPU_ENDIAN_LITTLE)
return AuReadS64LE(ptr, offset);
#else
return AuReadS64BE(ptr, offset);
#endif
}
static auline AuInt32 AuReadS32(const void *ptr, int offset)
{
#if defined(AU_CPU_ENDIAN_LITTLE)
return AuReadS32LE(ptr, offset);
#else
return AuReadS32BE(ptr, offset);
#endif
}
static auline AuInt16 AuReadS16(const void *ptr, int offset)
{
#if defined(AU_CPU_ENDIAN_LITTLE)
return AuReadS16LE(ptr, offset);
#else
return AuReadS16BE(ptr, offset);
#endif
}
static auline 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 auline 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)
2022-01-19 17:08:13 +00:00
if constexpr (AuIsSame_v<T, AuUInt32> || AuIsSame_v<T, AuInt32>)
{
temp = _byteswap_ulong(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt64> || AuIsSame_v<T, AuInt64>)
{
temp = _byteswap_uint64(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt16> || AuIsSame_v<T, AuInt16>)
{
temp = _byteswap_ushort(temp);
}
#else
2022-01-19 17:08:13 +00:00
if constexpr (AuIsSame_v<T, AuUInt32> || AuIsSame_v<T, AuInt32>)
{
temp = __builtin_bswap32(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt64> || AuIsSame_v<T, AuInt64>)
{
temp = __builtin_bswap64(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt16> || AuIsSame_v<T, AuInt16>)
{
temp = (temp << 8) | ((temp >> 8) & 0xFF);
}
#endif
#endif
2022-01-19 17:08:13 +00:00
AuMemcpy(reinterpret_cast<AuUInt8 *>(ptr) + offset, &temp, sizeof(temp));
#endif
}
template<typename T>
static auline 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)
2022-01-19 17:08:13 +00:00
if constexpr (AuIsSame_v<T, AuUInt32> || AuIsSame_v<T, AuInt32>)
{
temp = _byteswap_ulong(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt64> || AuIsSame_v<T, AuInt64>)
{
temp = _byteswap_uint64(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt16> || AuIsSame_v<T, AuInt16>)
{
temp = _byteswap_ushort(temp);
}
#else
2022-01-19 17:08:13 +00:00
if constexpr (AuIsSame_v<T, AuUInt32> || AuIsSame_v<T, AuInt32>)
{
temp = __builtin_bswap32(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt64> || AuIsSame_v<T, AuInt64>)
{
temp = __builtin_bswap64(temp);
}
2022-01-19 17:08:13 +00:00
else if constexpr (AuIsSame_v<T, AuUInt16> || AuIsSame_v<T, AuInt16>)
{
temp = (temp << 8) | ((temp >> 8) & 0xFF);
}
#endif
#endif
2022-01-19 17:08:13 +00:00
AuMemcpy(reinterpret_cast<AuUInt8 *>(ptr) + offset, &temp, sizeof(temp));
#endif
}
static auline void AuWriteU64LE(void *ptr, int offset, AuUInt64 value)
{
AuWriteGenericLE<AuUInt64>(ptr, offset, value);
}
static auline void AuWriteU32LE(void *ptr, int offset, AuUInt32 value)
{
AuWriteGenericLE<AuUInt32>(ptr, offset, value);
}
static auline void AuWriteU16LE(void *ptr, int offset, AuUInt16 value)
{
AuWriteGenericLE<AuUInt16>(ptr, offset, value);
}
static auline void AuWriteU8LE(void *ptr, int offset, AuUInt8 value)
{
AuWriteGenericLE<AuUInt8>(ptr, offset, value);
}
static auline void AuWriteS64LE(void *ptr, int offset, AuInt64 value)
{
AuWriteGenericLE<AuInt64>(ptr, offset, value);
}
static auline void AuWriteS32LE(void *ptr, int offset, AuInt32 value)
{
AuWriteGenericLE<AuInt32>(ptr, offset, value);
}
static auline void AuWriteS16LE(void *ptr, int offset, AuInt16 value)
{
AuWriteGenericLE<AuInt16>(ptr, offset, value);
}
static auline void AuWriteS8LE(void *ptr, int offset, AuInt8 value)
{
AuWriteGenericLE<AuInt8>(ptr, offset, value);
}
static auline void AuWriteU64BE(void *ptr, int offset, AuUInt64 value)
{
AuWriteGenericBE<AuUInt64>(ptr, offset, value);
}
static auline void AuWriteU32BE(void *ptr, int offset, AuUInt32 value)
{
AuWriteGenericBE<AuUInt32>(ptr, offset, value);
}
static auline void AuWriteU16BE(void *ptr, int offset, AuUInt16 value)
{
AuWriteGenericBE<AuUInt16>(ptr, offset, value);
}
static auline void AuWriteU8BE(void *ptr, int offset, AuUInt8 value)
{
AuWriteGenericBE<AuUInt8>(ptr, offset, value);
}
static auline void AuWriteS64BE(void *ptr, int offset, AuInt64 value)
{
AuWriteGenericBE<AuInt64>(ptr, offset, value);
}
static auline void AuWriteS32BE(void *ptr, int offset, AuInt32 value)
{
AuWriteGenericBE<AuInt32>(ptr, offset, value);
}
static auline void AuWriteS16BE(void *ptr, int offset, AuInt16 value)
{
AuWriteGenericBE<AuInt16>(ptr, offset, value);
}
static auline void AuWriteS8BE(void *ptr, int offset, AuInt8 value)
{
AuWriteGenericBE<AuInt8>(ptr, offset, value);
}
static auline 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 auline 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 auline 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 auline 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 auline 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 auline 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 auline 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 auline void AuWriteS8(void *ptr, int offset, AuInt8 value)
{
#if defined(AU_CPU_ENDIAN_LITTLE)
AuWriteS8LE(ptr, offset, value);
#else
AuWriteS8BE(ptr, offset, value);
#endif
}