// Heterogeneous lookup support on c++17 with robin_hash
// C++20 demo: Heterogeneous lookup for unordered containers (transparent hashing)
// https://en.cppreference.com/w/cpp/container/unordered_map/find
#pragma once
#include <string>
#include <string_view>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include "tsl/robin_map.h"
#include "tsl/robin_set.h"

using namespace std::string_literals;
using namespace std::string_view_literals;

namespace hlookup
{
struct string_hash
{
    using hash_type      = std::hash<std::string_view>;
    using is_transparent = void;

    size_t operator()(const char* str) const { return hash_type{}(str); }
    size_t operator()(std::string_view str) const { return hash_type{}(str); }
    size_t operator()(const std::string& str) const { return hash_type{}(str); }
};

struct equal_to
{
    template <class _Ty1, class _Ty2>
    constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const
        noexcept(noexcept(static_cast<_Ty1&&>(_Left) == static_cast<_Ty2&&>(_Right)))  // strengthened
        -> decltype(static_cast<_Ty1&&>(_Left) == static_cast<_Ty2&&>(_Right))
    {
        return static_cast<_Ty1&&>(_Left) == static_cast<_Ty2&&>(_Right);
    }

    using is_transparent = void;
};

template <typename _Valty>
using stl_string_map = std::map<std::string, _Valty, std::less<>>;
using stl_string_set = std::set<std::string, std::less<>>;

template <typename _Valty>
using string_map = tsl::robin_map<std::string, _Valty, string_hash, equal_to>;
using string_set = tsl::robin_set<std::string, string_hash, equal_to>;

template <typename _Cont, typename _Valty>
inline auto set_item(_Cont& cont, std::string_view k, _Valty&& v)
{
    typename _Cont::iterator it = cont.find(k);
    if (it != cont.end())
        it->second = std::forward<_Valty>(v);
    else
        it = cont.emplace(k, std::forward<_Valty>(v)).first;
    return it;
}

constexpr auto empty_sv = ""sv;

}  // namespace hlookup