// Copyright 2022 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef SRC_TINT_UTILS_CONTAINERS_UNIQUE_ALLOCATOR_H_
#define SRC_TINT_UTILS_CONTAINERS_UNIQUE_ALLOCATOR_H_

#include <functional>
#include <unordered_set>
#include <utility>

#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 = std::hash<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) {
        // Create a temporary T instance on the stack so that we can hash it, and
        // use it for equality lookup for the std::unordered_set. If the item is not
        // found in the set, then we create the persisted instance with the
        // allocator.
        TYPE key{args...};
        auto hash = Hasher{}(key);
        auto it = items.find(Entry{hash, &key});
        if (it != items.end()) {
            return static_cast<TYPE*>(it->ptr);
        }
        auto* ptr = allocator.template Create<TYPE>(std::forward<ARGS>(args)...);
        items.emplace_hint(it, Entry{hash, ptr});
        return ptr;
    }

    /// @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 {
        // Create a temporary T instance on the stack so that we can hash it, and
        // use it for equality lookup for the std::unordered_set.
        TYPE key{args...};
        auto hash = Hasher{}(key);
        auto it = items.find(Entry{hash, &key});
        if (it != items.end()) {
            return static_cast<TYPE*>(it->ptr);
        }
        return nullptr;
    }

    /// 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) { items = o.items; }

    /// @returns an iterator to the beginning of the types
    Iterator begin() const { return allocator.Objects().begin(); }
    /// @returns an iterator to the end of the types
    Iterator end() const { return allocator.Objects().end(); }

  private:
    /// The hash function
    using Hasher = HASH;
    /// The equality function
    using Equality = EQUAL;

    /// Entry is used as the entry to the unordered_set
    struct Entry {
        /// The pre-calculated hash of the entry
        size_t hash;
        /// The pointer to the unique object
        T* ptr;
    };
    /// Comparator is the hashing and equality function used by the unordered_set
    struct Comparator {
        /// Hashing function
        /// @param e the entry
        /// @returns the hash of the entry
        size_t operator()(Entry e) const { return e.hash; }

        /// 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()(Entry a, Entry b) const { return EQUAL{}(*a.ptr, *b.ptr); }
    };

    /// The block allocator used to allocate the unique objects
    BlockAllocator<T> allocator;
    /// The unordered_set of unique item entries
    std::unordered_set<Entry, Comparator, Comparator> items;
};

}  // namespace tint

#endif  // SRC_TINT_UTILS_CONTAINERS_UNIQUE_ALLOCATOR_H_
