This commit is contained in:
Jordan Woyak 2025-05-27 18:37:58 -05:00 committed by GitHub
commit 59a7c75c1c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 34 additions and 55 deletions

View File

@ -114,21 +114,17 @@
*/
#pragma pack(1)
template <std::size_t position, std::size_t bits, typename T,
// StorageType is T for non-enum types and the underlying type of T if
// T is an enumeration. Note that T is wrapped within an enable_if in the
// former case to workaround compile errors which arise when using
// std::underlying_type<T>::type directly.
typename StorageType = typename std::conditional_t<
std::is_enum<T>::value, std::underlying_type<T>, std::enable_if<true, T>>::type>
// StorageType is T for non-enum or the underlying-type for an enum.
typename StorageType = std::conditional_t<std::is_enum_v<T>, std::underlying_type<T>,
std::type_identity<T>>::type>
struct BitField
{
private:
public:
// This constructor might be considered ambiguous:
// Would it initialize the storage or just the bitfield?
// Hence, delete it. Use the assignment operator to set bitfield values!
BitField(T val) = delete;
public:
// Force default constructor to be created
// so that we can use this within unions
constexpr BitField() = default;
@ -212,26 +208,22 @@ class BitFieldArrayIterator;
#pragma pack(1)
template <std::size_t position, std::size_t bits, std::size_t size, typename T,
// StorageType is T for non-enum types and the underlying type of T if
// T is an enumeration. Note that T is wrapped within an enable_if in the
// former case to workaround compile errors which arise when using
// std::underlying_type<T>::type directly.
typename StorageType = typename std::conditional_t<
std::is_enum<T>::value, std::underlying_type<T>, std::enable_if<true, T>>::type>
// StorageType is T for non-enum or the underlying-type for an enum.
typename StorageType = std::conditional_t<std::is_enum_v<T>, std::underlying_type<T>,
std::type_identity<T>>::type>
struct BitFieldArray
{
public:
using Ref = BitFieldArrayRef<position, bits, size, T, StorageType>;
using ConstRef = BitFieldArrayConstRef<position, bits, size, T, StorageType>;
using Iterator = BitFieldArrayIterator<position, bits, size, T, StorageType>;
using ConstIterator = BitFieldArrayConstIterator<position, bits, size, T, StorageType>;
private:
// This constructor might be considered ambiguous:
// Would it initialize the storage or just the bitfield?
// Hence, delete it. Use the assignment operator to set bitfield values!
BitFieldArray(T val) = delete;
public:
// Force default constructor to be created
// so that we can use this within unions
constexpr BitFieldArray() = default;
@ -244,7 +236,6 @@ public:
// code expects that this class is trivially copyable.
BitFieldArray& operator=(const BitFieldArray&) = delete;
public:
constexpr bool IsSigned() const { return std::is_signed<T>(); }
constexpr std::size_t StartBit() const { return position; }
constexpr std::size_t NumBits() const { return bits; }

View File

@ -7,7 +7,6 @@
#include <bit>
#include <climits>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <initializer_list>
#include <type_traits>
@ -117,8 +116,8 @@ constexpr Result ExtractBits(const T src) noexcept
template <typename T>
constexpr bool IsValidLowMask(const T mask) noexcept
{
static_assert(std::is_integral<T>::value, "Mask must be an integral type.");
static_assert(std::is_unsigned<T>::value, "Signed masks can introduce hard to find bugs.");
static_assert(std::is_integral_v<T>, "Mask must be an integral type.");
static_assert(std::is_unsigned_v<T>, "Signed masks can introduce hard to find bugs.");
// Can be efficiently determined without looping or bit counting. It's the counterpart
// to https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
@ -138,11 +137,10 @@ public:
explicit BitCastPtrType(PtrType* ptr) : m_ptr(ptr) {}
// Enable operator= only for pointers to non-const data
template <typename S>
inline typename std::enable_if<std::is_same<S, T>() && !std::is_const<PtrType>()>::type
operator=(const S& source)
auto& operator=(const T& source) requires(!std::is_const_v<PtrType>)
{
std::memcpy(m_ptr, &source, sizeof(source));
return *this;
}
inline operator T() const

View File

@ -32,7 +32,6 @@
#include "Common/EnumMap.h"
#include "Common/Flag.h"
#include "Common/Inline.h"
#include "Common/Logging/Log.h"
// Wrapper class
class PointerWrap
@ -195,13 +194,15 @@ public:
DoArray(x.data(), static_cast<u32>(x.size()));
}
template <typename T, typename std::enable_if_t<std::is_trivially_copyable_v<T>, int> = 0>
template <typename T>
requires(std::is_trivially_copyable_v<T>)
void DoArray(T* x, u32 count)
{
DoVoid(x, count * sizeof(T));
}
template <typename T, typename std::enable_if_t<!std::is_trivially_copyable_v<T>, int> = 0>
template <typename T>
requires(!std::is_trivially_copyable_v<T>)
void DoArray(T* x, u32 count)
{
for (u32 i = 0; i < count; ++i)

View File

@ -6,21 +6,14 @@
#include <mutex>
#include <shared_mutex>
#include <string>
#include <type_traits>
#include <utility>
#include "Common/CommonTypes.h"
#include "Common/Config/Enums.h"
#include "Common/TypeUtils.h"
namespace Config
{
namespace detail
{
// std::underlying_type may only be used with enum types, so make sure T is an enum type first.
template <typename T>
using UnderlyingType = typename std::enable_if_t<std::is_enum<T>{}, std::underlying_type<T>>::type;
} // namespace detail
struct Location
{
System system{};
@ -54,8 +47,7 @@ public:
// Make it easy to convert Info<Enum> into Info<UnderlyingType<Enum>>
// so that enum settings can still easily work with code that doesn't care about the enum values.
template <typename Enum,
std::enable_if_t<std::is_same<T, detail::UnderlyingType<Enum>>::value>* = nullptr>
template <Common::TypedEnum<T> Enum>
Info(const Info<Enum>& other)
{
*this = other;
@ -80,8 +72,7 @@ public:
// Make it easy to convert Info<Enum> into Info<UnderlyingType<Enum>>
// so that enum settings can still easily work with code that doesn't care about the enum values.
template <typename Enum,
std::enable_if_t<std::is_same<T, detail::UnderlyingType<Enum>>::value>* = nullptr>
template <Common::TypedEnum<T> Enum>
Info<T>& operator=(const Info<Enum>& other)
{
m_location = other.GetLocation();

View File

@ -23,7 +23,8 @@ struct DefaultState
namespace detail
{
template <typename T, std::enable_if_t<!std::is_enum<T>::value>* = nullptr>
template <typename T>
requires(!Common::Enum<T>)
std::optional<T> TryParse(const std::string& str_value)
{
T value;
@ -32,7 +33,7 @@ std::optional<T> TryParse(const std::string& str_value)
return value;
}
template <typename T, std::enable_if_t<std::is_enum<T>::value>* = nullptr>
template <Common::Enum T>
std::optional<T> TryParse(const std::string& str_value)
{
const auto result = TryParse<std::underlying_type_t<T>>(str_value);

View File

@ -42,11 +42,10 @@
* constexpr formatter() : EnumFormatter(names) {}
* };
*/
template <auto last_member>
template <Common::Enum auto last_member>
class EnumFormatter
{
using T = decltype(last_member);
static_assert(std::is_enum_v<T>);
public:
constexpr auto parse(fmt::format_parse_context& ctx)

View File

@ -4,7 +4,6 @@
#pragma once
#include <array>
#include <type_traits>
#include "Common/TypeUtils.h"
@ -15,11 +14,10 @@ namespace Common
{
// A type that allows lookup of values associated with an enum as the key.
// Designed for enums whose numeric values start at 0 and increment continuously with few gaps.
template <typename V, auto last_member>
template <typename V, Common::Enum auto last_member>
class EnumMap final
{
using T = decltype(last_member);
static_assert(std::is_enum_v<T>);
static constexpr size_t s_size = static_cast<size_t>(last_member) + 1;
using array_type = std::array<V, s_size>;
@ -34,8 +32,9 @@ public:
constexpr EnumMap& operator=(EnumMap&& other) = default;
// Constructor that accepts exactly size Vs (enforcing that all must be specified).
template <typename... T, typename = std::enable_if_t<Common::IsNOf<V, s_size, T...>::value>>
constexpr EnumMap(T... values) : m_array{static_cast<V>(values)...}
template <typename... T>
constexpr EnumMap(T... values) requires(Common::IsNOf<V, s_size, T...>::value)
: m_array{static_cast<V>(values)...}
{
}

View File

@ -3,26 +3,25 @@
#pragma once
#include <type_traits>
#include <SFML/Network/Packet.hpp>
#include "Common/CommonTypes.h"
#include "Common/EnumUtils.h"
#include "Common/Swap.h"
#include "Common/TypeUtils.h"
sf::Packet& operator>>(sf::Packet& packet, Common::BigEndianValue<u16>& data);
sf::Packet& operator>>(sf::Packet& packet, Common::BigEndianValue<u32>& data);
sf::Packet& operator>>(sf::Packet& packet, Common::BigEndianValue<u64>& data);
template <typename Enum, std::enable_if_t<std::is_enum_v<Enum>>* = nullptr>
template <Common::Enum Enum>
sf::Packet& operator<<(sf::Packet& packet, Enum e)
{
using Underlying = std::underlying_type_t<Enum>;
packet << static_cast<Underlying>(e);
packet << Common::ToUnderlying(e);
return packet;
}
template <typename Enum, std::enable_if_t<std::is_enum_v<Enum>>* = nullptr>
template <Common::Enum Enum>
sf::Packet& operator>>(sf::Packet& packet, Enum& e)
{
using Underlying = std::underlying_type_t<Enum>;

View File

@ -70,8 +70,8 @@ static_assert(!std::is_same_v<ObjectType<&Bar::c>, Bar>);
// Template for checking if Types is count occurrences of T.
template <typename T, size_t count, typename... Ts>
struct IsNOf : std::integral_constant<bool, std::conjunction_v<std::is_convertible<Ts, T>...> &&
sizeof...(Ts) == count>
struct IsNOf : std::bool_constant<std::conjunction_v<std::is_convertible<Ts, T>...> &&
sizeof...(Ts) == count>
{
};