// Copyright 2023 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include #include #include #include #include namespace Common::GekkoAssembler::detail { // Hacky implementation of a case insensitive alphanumeric trie supporting extended entries // Standing in for std::map to support case-insensitive lookups while allowing string_views in // lookups template class CaseInsensitiveDict { public: CaseInsensitiveDict(const std::initializer_list>& il) { for (auto&& [k, v] : il) { Add(k, v); } } template V const* Find(const T& key) const { auto&& [last_e, it] = TryFind(key); if (it == key.cend() && last_e->_val) { return &*last_e->_val; } return nullptr; } static constexpr size_t NUM_CONNS = 36 + sizeof...(ExtraMatches); static constexpr uint32_t INVALID_CONN = static_cast(-1); private: struct TrieEntry { std::array _conns; std::optional _val; TrieEntry() { std::fill(_conns.begin(), _conns.end(), INVALID_CONN); } }; constexpr size_t IndexOf(char c) const { size_t idx; if (std::isalpha(c)) { idx = std::tolower(c) - 'a'; } else if (std::isdigit(c)) { idx = c - '0' + 26; } else { idx = 36; // Expands to an equivalent for loop over ExtraMatches if constexpr (sizeof...(ExtraMatches) > 0) { (void)((c != ExtraMatches ? ++idx, true : false) && ...); } } return idx; } template auto TryFind(const T& key) const -> std::pair { std::pair ret(&m_root_entry, key.cbegin()); const auto k_end = key.cend(); for (; ret.second != k_end; ret.second++) { const size_t idx = IndexOf(*ret.second); if (idx >= NUM_CONNS || ret.first->_conns[idx] == INVALID_CONN) { break; } ret.first = &m_entry_pool[ret.first->_conns[idx]]; } return ret; } template auto TryFind(const T& key) -> std::pair { auto&& [e_const, it] = const_cast const*>(this)->TryFind(key); return {const_cast(e_const), it}; } void Add(std::string_view key, const V& val) { auto&& [last_e, it] = TryFind(key); if (it != key.cend()) { for (; it != key.cend(); it++) { const size_t idx = IndexOf(*it); if (idx >= NUM_CONNS) { break; } last_e->_conns[idx] = static_cast(m_entry_pool.size()); last_e = &m_entry_pool.emplace_back(); } } last_e->_val = val; } TrieEntry m_root_entry; std::vector m_entry_pool; }; } // namespace Common::GekkoAssembler::detail