// Copyright 2021 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include "Common/TypeUtils.h" template 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 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); static constexpr size_t s_size = static_cast(last_member) + 1; using array_type = std::array; 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 ::value>> constexpr EnumMap(T... values) : m_array{static_cast(values)...} { } constexpr const V& operator[](T key) const { return m_array[static_cast(key)]; } constexpr V& operator[](T key) { return m_array[static_cast(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 constexpr const V& operator[](BitField key) const { static_assert(1 << bits == s_size, "Unsafe indexing into EnumMap (may go out of bounds)"); return m_array[static_cast(key.Value())]; } template constexpr V& operator[](BitField key) { static_assert(1 << bits == s_size, "Unsafe indexing into EnumMap (may go out of bounds)"); return m_array[static_cast(key.value())]; } constexpr bool InBounds(T key) const { return static_cast(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