mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
84 lines
3.3 KiB
C++
84 lines
3.3 KiB
C++
// Copyright 2021 Dolphin Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#pragma once
|
|
|
|
#include <array>
|
|
#include <type_traits>
|
|
|
|
#include "Common/TypeUtils.h"
|
|
|
|
template <std::size_t position, std::size_t bits, typename T, typename StorageType>
|
|
struct BitField;
|
|
|
|
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, typename = decltype(last_member)>
|
|
class EnumMap final
|
|
{
|
|
// The third template argument is needed to avoid compile errors from ambiguity with multiple
|
|
// enums with the same number of members in GCC prior to 8. See https://godbolt.org/z/xcKaW1seW
|
|
// and https://godbolt.org/z/hz7Yqq1P5
|
|
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>;
|
|
using iterator = typename array_type::iterator;
|
|
using const_iterator = typename array_type::const_iterator;
|
|
|
|
public:
|
|
constexpr EnumMap() = default;
|
|
constexpr EnumMap(const EnumMap& other) = default;
|
|
constexpr EnumMap& operator=(const EnumMap& other) = default;
|
|
constexpr EnumMap(EnumMap&& other) = default;
|
|
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)...}
|
|
{
|
|
}
|
|
|
|
constexpr const V& operator[](T key) const { return m_array[static_cast<std::size_t>(key)]; }
|
|
constexpr V& operator[](T key) { return m_array[static_cast<std::size_t>(key)]; }
|
|
|
|
// These only exist to perform the safety check; without them, BitField's implicit conversion
|
|
// would work (but since BitField is used for game-generated data, we need to be careful about
|
|
// bounds-checking)
|
|
template <std::size_t position, std::size_t bits, typename StorageType>
|
|
constexpr const V& operator[](BitField<position, bits, T, StorageType> key) const
|
|
{
|
|
static_assert(1 << bits == s_size, "Unsafe indexing into EnumMap (may go out of bounds)");
|
|
return m_array[static_cast<std::size_t>(key.Value())];
|
|
}
|
|
template <std::size_t position, std::size_t bits, typename StorageType>
|
|
constexpr V& operator[](BitField<position, bits, T, StorageType> key)
|
|
{
|
|
static_assert(1 << bits == s_size, "Unsafe indexing into EnumMap (may go out of bounds)");
|
|
return m_array[static_cast<std::size_t>(key.value())];
|
|
}
|
|
|
|
constexpr bool InBounds(T key) const { return static_cast<std::size_t>(key) < s_size; }
|
|
|
|
constexpr size_t size() const noexcept { return s_size; }
|
|
|
|
constexpr V* data() { return m_array.data(); }
|
|
constexpr const V* data() const { return m_array.data(); }
|
|
|
|
constexpr iterator begin() { return m_array.begin(); }
|
|
constexpr iterator end() { return m_array.end(); }
|
|
constexpr const_iterator begin() const { return m_array.begin(); }
|
|
constexpr const_iterator end() const { return m_array.end(); }
|
|
constexpr const_iterator cbegin() const { return m_array.cbegin(); }
|
|
constexpr const_iterator cend() const { return m_array.cend(); }
|
|
|
|
constexpr void fill(const V& v) { m_array.fill(v); }
|
|
|
|
private:
|
|
array_type m_array{};
|
|
};
|
|
} // namespace Common
|