// Copyright 2022 The Dawn & Tint Authors // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // 3. Neither the name of the copyright holder nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef SRC_TINT_UTILS_CONTAINERS_UNIQUE_ALLOCATOR_H_ #define SRC_TINT_UTILS_CONTAINERS_UNIQUE_ALLOCATOR_H_ #include <functional> #include <utility> #include "src/tint/utils/containers/hashmap_base.h" #include "src/tint/utils/memory/block_allocator.h" namespace tint { /// UniqueAllocator is used to allocate unique instances of the template type `T`. template <typename T, typename HASH = Hasher<T>, typename EQUAL = std::equal_to<T>> class UniqueAllocator { public: /// Iterator is the type returned by begin() and end() using Iterator = typename BlockAllocator<T>::ConstIterator; /// @param args the arguments used to construct the object. /// @return a pointer to an instance of `T` with the provided arguments. /// If an existing instance of `T` has been constructed, then the same /// pointer is returned. template <typename TYPE = T, typename... ARGS> TYPE* Get(ARGS&&... args) { … } /// @param args the arguments used to create the temporary used for the search. /// @return a pointer to an instance of `T` with the provided arguments, or nullptr if the item /// was not found. template <typename TYPE = T, typename... ARGS> TYPE* Find(ARGS&&... args) const { … } /// Wrap sets this allocator to the objects created with the content of `inner`. /// The allocator after Wrap is intended to temporarily extend the objects /// of an existing immutable UniqueAllocator. /// As the copied objects are owned by `inner`, `inner` must not be destructed /// or assigned while using this allocator. /// @param o the immutable UniqueAlllocator to extend void Wrap(const UniqueAllocator<T, HASH, EQUAL>& o) { … } /// @returns an iterator to the beginning of the types Iterator begin() const { … } /// @returns an iterator to the end of the types Iterator end() const { … } private: /// Comparator is the hashing function used by the Hashset struct Hasher { /// Hashing function /// @param e the entry /// @returns the hash of the entry HashCode operator()(T* e) const { return HASH{}(*e); } }; /// Equality is the equality function used by the Hashset struct Equality { /// Equality function /// @param a the first entry to compare /// @param b the second entry to compare /// @returns true if the two entries are equal bool operator()(T* a, T* b) const { return EQUAL{}(*a, *b); } }; /// The maximum capacity of Set before it performs heap allocations. static constexpr size_t kFixedSize = 32; /// The key type of Set. using Key = HashmapKey<T*, Hasher, Equality>; /// A custom Hashset implementation that allows keys to be modified. class Set : public HashmapBase<Key, kFixedSize> { public: Key& Add(T* key) { auto idx = this->EditAt(key); if (!idx.entry) { idx.Insert(std::forward<T*>(key)); } return *idx.entry; } T* Get(T* key) const { if (auto* entry = this->GetEntry(key)) { return *entry; } return nullptr; } }; /// The block allocator used to allocate the unique objects BlockAllocator<T> allocator; /// The set of unique item entries Set items; }; } // namespace tint #endif // SRC_TINT_UTILS_CONTAINERS_UNIQUE_ALLOCATOR_H_