mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-11-15 11:20:05 +00:00
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.cpp
|
||||||
dynamic_library.h
|
dynamic_library.h
|
||||||
elf.h
|
elf.h
|
||||||
|
enum_util.h
|
||||||
error.cpp
|
error.cpp
|
||||||
error.h
|
error.h
|
||||||
expected.h
|
expected.h
|
||||||
@ -148,6 +149,7 @@ add_library(common STATIC
|
|||||||
tiny_mt.h
|
tiny_mt.h
|
||||||
tree.h
|
tree.h
|
||||||
typed_address.h
|
typed_address.h
|
||||||
|
typed_storage.h
|
||||||
uint128.h
|
uint128.h
|
||||||
unique_function.h
|
unique_function.h
|
||||||
uuid.cpp
|
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 <type_traits>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/typed_storage.h"
|
||||||
|
|
||||||
namespace Common {
|
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 {
|
namespace impl {
|
||||||
|
|
||||||
|
@ -84,6 +84,48 @@ namespace Common {
|
|||||||
return f;
|
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
|
} // Namespace Common
|
||||||
|
|
||||||
template <typename T, typename F>
|
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