common: Add various utility classes
This commit is contained in:
parent
a93d249ac1
commit
12e55ae31b
@ -46,6 +46,7 @@ add_library(common STATIC
|
||||
dynamic_library.cpp
|
||||
dynamic_library.h
|
||||
elf.h
|
||||
enum_util.h
|
||||
error.cpp
|
||||
error.h
|
||||
expected.h
|
||||
@ -148,6 +149,7 @@ add_library(common STATIC
|
||||
tiny_mt.h
|
||||
tree.h
|
||||
typed_address.h
|
||||
typed_storage.h
|
||||
uint128.h
|
||||
unique_function.h
|
||||
uuid.cpp
|
||||
|
20
src/common/enum_util.h
Normal file
20
src/common/enum_util.h
Normal file
@ -0,0 +1,20 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Common {
|
||||
|
||||
template <typename Enum>
|
||||
requires std::is_enum<Enum>::value
|
||||
constexpr typename std::underlying_type<Enum>::type ToUnderlying(Enum e) {
|
||||
return static_cast<typename std::underlying_type<Enum>::type>(e);
|
||||
}
|
||||
|
||||
template <typename Enum>
|
||||
requires std::is_enum<Enum>::value
|
||||
constexpr Enum FromUnderlying(typename std::underlying_type<Enum>::type v) {
|
||||
return static_cast<Enum>(v);
|
||||
}
|
||||
|
||||
} // namespace Common
|
@ -6,27 +6,9 @@
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/typed_storage.h"
|
||||
|
||||
namespace Common {
|
||||
namespace detail {
|
||||
template <typename T, size_t Size, size_t Align>
|
||||
struct TypedStorageImpl {
|
||||
alignas(Align) u8 storage_[Size];
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
using TypedStorage = detail::TypedStorageImpl<T, sizeof(T), alignof(T)>;
|
||||
|
||||
template <typename T>
|
||||
static constexpr T* GetPointer(TypedStorage<T>& ts) {
|
||||
return static_cast<T*>(static_cast<void*>(std::addressof(ts.storage_)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static constexpr const T* GetPointer(const TypedStorage<T>& ts) {
|
||||
return static_cast<const T*>(static_cast<const void*>(std::addressof(ts.storage_)));
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
|
||||
|
@ -84,6 +84,48 @@ namespace Common {
|
||||
return f;
|
||||
}
|
||||
|
||||
consteval bool IsLittleEndian() {
|
||||
return std::endian::native == std::endian::little;
|
||||
}
|
||||
|
||||
consteval bool IsBigEndian() {
|
||||
return std::endian::native == std::endian::big;
|
||||
}
|
||||
static_assert(IsLittleEndian() ^ IsBigEndian());
|
||||
|
||||
template <std::unsigned_integral U>
|
||||
U SwapEndian(const U u) {
|
||||
constexpr std::size_t BitSizeU8 = 8;
|
||||
if constexpr (sizeof(U) * BitSizeU8 == 64) {
|
||||
return swap64(u);
|
||||
} else if constexpr (sizeof(U) * BitSizeU8 == 32) {
|
||||
return swap32(u);
|
||||
} else if constexpr (sizeof(U) * BitSizeU8 == 16) {
|
||||
return swap16(u);
|
||||
} else if constexpr (sizeof(U) * BitSizeU8 == 8) {
|
||||
return u;
|
||||
} else {
|
||||
static_assert(!std::is_same<U, U>::value);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::integral T>
|
||||
constexpr T ConvertToLittleEndian(const T val) {
|
||||
using U = typename std::make_unsigned<T>::type;
|
||||
|
||||
if constexpr (IsBigEndian()) {
|
||||
return static_cast<T>(SwapEndian<U>(static_cast<U>(val)));
|
||||
} else {
|
||||
static_assert(IsLittleEndian());
|
||||
return static_cast<T>(static_cast<U>(val));
|
||||
}
|
||||
}
|
||||
|
||||
template <std::integral T>
|
||||
constexpr T LoadLittleEndian(const T* ptr) {
|
||||
return ConvertToLittleEndian<T>(*ptr);
|
||||
}
|
||||
|
||||
} // Namespace Common
|
||||
|
||||
template <typename T, typename F>
|
||||
|
96
src/common/typed_storage.h
Normal file
96
src/common/typed_storage.h
Normal file
@ -0,0 +1,96 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
template <typename T, size_t Size = sizeof(T), size_t Align = alignof(T)>
|
||||
struct TypedStorage {
|
||||
typename std::aligned_storage<Size, Align>::type _storage;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static T* GetPointer(TypedStorage<T>& ts) {
|
||||
return std::launder(reinterpret_cast<T*>(std::addressof(ts._storage)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static const T* GetPointer(const TypedStorage<T>& ts) {
|
||||
return std::launder(reinterpret_cast<const T*>(std::addressof(ts._storage)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T& GetReference(TypedStorage<T>& ts) {
|
||||
return *GetPointer(ts);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static const T& GetReference(const TypedStorage<T>& ts) {
|
||||
return *GetPointer(ts);
|
||||
}
|
||||
|
||||
namespace Impl {
|
||||
|
||||
template <typename T>
|
||||
static T* GetPointerForConstructAt(TypedStorage<T>& ts) {
|
||||
return reinterpret_cast<T*>(std::addressof(ts._storage));
|
||||
}
|
||||
|
||||
} // namespace Impl
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static T* ConstructAt(TypedStorage<T>& ts, Args&&... args) {
|
||||
return std::construct_at(Impl::GetPointerForConstructAt(ts), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void DestroyAt(TypedStorage<T>& ts) {
|
||||
return std::destroy_at(GetPointer(ts));
|
||||
}
|
||||
|
||||
namespace Impl {
|
||||
|
||||
template <typename T>
|
||||
class TypedStorageGuard {
|
||||
YUZU_NON_COPYABLE(TypedStorageGuard);
|
||||
|
||||
private:
|
||||
TypedStorage<T>& m_ts;
|
||||
bool m_active;
|
||||
|
||||
public:
|
||||
template <typename... Args>
|
||||
TypedStorageGuard(TypedStorage<T>& ts, Args&&... args) : m_ts(ts), m_active(true) {
|
||||
ConstructAt(m_ts, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
~TypedStorageGuard() {
|
||||
if (m_active) {
|
||||
DestroyAt(m_ts);
|
||||
}
|
||||
}
|
||||
|
||||
void Cancel() {
|
||||
m_active = false;
|
||||
}
|
||||
|
||||
TypedStorageGuard(TypedStorageGuard&& rhs) : m_ts(rhs.m_ts), m_active(rhs.m_active) {
|
||||
rhs.Cancel();
|
||||
}
|
||||
|
||||
TypedStorageGuard& operator=(TypedStorageGuard&& rhs) = delete;
|
||||
};
|
||||
|
||||
} // namespace Impl
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static Impl::TypedStorageGuard<T> ConstructAtGuarded(TypedStorage<T>& ts, Args&&... args) {
|
||||
return Impl::TypedStorageGuard<T>(ts, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // namespace Common
|
Loading…
Reference in New Issue
Block a user