//===--- EnumMap.h - A map optimized for having enum keys -------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// /// /// This file defines the EnumMap class template, which is a map data /// structure optimized for working with enumerated keys. It is built on /// top of SmallMap, but it replaces the default large map with a flat /// heap-allocated array of indexes into the elements, which is reasonable /// for small-ish enums. /// /// Currently the map requires the key type to be an enum type. /// The expectation is that the enum has a small number of enumerators /// which are all in the range 0.. namespace swift { /// The maximum number of elements that the map can have before /// it flips from brute-force searching the keys to using a sparse /// array. static constexpr size_t DefaultEnumMapDirectSearchLimit = DefaultSmallMapDirectSearchLimit; /// The primary customization point for an EnumMap. /// /// template <> /// struct EnumMapTraits { /// using IndexType = ; /// struct LargeMapStorage { /// std::optional find(IndexType) const; /// std::pair insert(IndexType key, IndexType value); /// }; /// }; template > struct EnumMapTraits; template , class ElementStorage = llvm::SmallVector> class EnumMap { using IndexType = typename MapTraits::IndexType; // EnumMapTraits is currently designed to be usable directly as a // SmallMapTraits. using MapType = SmallMap; MapType map; public: bool empty() const { return map.empty(); } size_t size() const { return map.size(); } using iterator = typename MapType::iterator; iterator begin() { return map.begin(); } iterator end() { return map.end(); } using const_iterator = typename MapType::const_iterator; const_iterator begin() const { return map.begin(); } const_iterator end() const { return map.end(); } /// Look up a key in the map. Returns end() if the entry is not found. const_iterator find(Key key) const { return map.find(IndexType(key)); } /// Try to insert the given key/value pair. If there's already an element /// with this key, return false and an iterator for the existing element. /// Otherwise, return true and an iterator for the new element. /// /// The value in the set will be constructed by emplacing it with the /// given arguments. template std::pair insert(Key key, Args &&...valueArgs) { return map.insert(IndexType(key), std::forward(valueArgs)...); } }; namespace EnumMapImpl { template struct SufficientIntFor; template struct SufficientIntFor { using type = uint8_t; }; template struct SufficientIntFor { using type = uint16_t; }; template struct SufficientIntFor { static_assert(N < (1ULL << 32), "just how large is this \"enum\" exactly"); using type = uint32_t; }; /// A map from integers in 0.. class FlatMap { public: using IndexType = typename SufficientIntFor::type; using StoredIndexType = typename SufficientIntFor::type; private: StoredIndexType *ptr; public: FlatMap() : ptr(new StoredIndexType[N]) { memset(ptr, 0, N * sizeof(StoredIndexType)); } FlatMap(FlatMap &&other) : ptr(other.ptr) { other.ptr = nullptr; } FlatMap &operator=(FlatMap &&other) { delete ptr; ptr = other.ptr; other.ptr = nullptr; } FlatMap(const FlatMap &other) : ptr(new StoredIndexType[N]) { memcpy(ptr, other.ptr, N * sizeof(StoredIndexType)); } FlatMap &operator=(const FlatMap &other) { memcpy(ptr, other.ptr, N * sizeof(StoredIndexType)); } ~FlatMap() { delete ptr; } std::pair insert(IndexType key, IndexType value) { assert(key < N); StoredIndexType &entry = ptr[key]; if (entry == 0) { entry = StoredIndexType(value) + 1; return std::make_pair(value, true); } else { return std::make_pair(IndexType(entry - 1), false); } } std::optional find(IndexType key) const { assert(key < N); StoredIndexType entry = ptr[key]; if (entry == 0) { return std::nullopt; } else { return IndexType(entry - 1); } }; }; } // end namespace EnumMapImpl /// The default implementation of EnumMapTraits. template struct EnumMapTraits { using Key = Key_; using KeyTraits = KeyTraits_; using LargeMapStorage = EnumMapImpl::FlatMap; using IndexType = typename LargeMapStorage::IndexType; }; } // end namespace swift #endif