ContainerHelpers.h#

Fully qualified name: carb/container/detail/ContainerHelpers.h

File members: carb/container/detail/ContainerHelpers.h

// SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: LicenseRef-NvidiaProprietary
//
// NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
// property and proprietary rights in and to this material, related
// documentation and any modifications thereto. Any use, reproduction,
// disclosure or distribution of this material and related documentation
// without an express license agreement from NVIDIA CORPORATION or
// its affiliates is strictly prohibited.

#pragma once

#include "../../cpp/TypeTraits.h"

#include "TemplateHelpers.h"

#include <type_traits>

namespace carb::container
{

namespace detail
{

template <typename Key, typename Hasher, typename KeyEqual, typename = void>
struct SupportsTransparent : std::false_type
{
};

template <typename Key, typename Hasher, typename KeyEqual>
struct SupportsTransparent<Key, Hasher, KeyEqual, std::void_t<typename Hasher::is_transparent, typename KeyEqual::is_transparent>>
    : std::true_type
{
};

struct is_iterator_impl
{
    template <typename T>
    using iter_traits_category = typename std::iterator_traits<T>::iterator_category;
    template <typename T>
    using input_iter_category =
        std::enable_if_t<std::is_base_of<std::input_iterator_tag, iter_traits_category<T>>::value>;
};

template <typename T>
using is_input_iterator = supports_t<T, is_iterator_impl::iter_traits_category, is_iterator_impl::input_iter_category>;

template <typename T>
constexpr bool is_input_iterator_v = is_input_iterator<T>::value;

template <typename Alloc, bool = std::is_empty_v<Alloc> && !std::is_final_v<Alloc>>
class AllocBase : private Alloc
{
public:
    using allocator_type = Alloc;

    AllocBase() = default;
    AllocBase(allocator_type a) : Alloc(std::move(a))
    {
    }

    allocator_type& a() noexcept
    {
        return *this;
    }
    const allocator_type& a() const noexcept
    {
        return *this;
    }
};

template <typename Alloc>
class AllocBase<Alloc, false>
{
    Alloc m_alloc;

public:
    using allocator_type = Alloc;

    AllocBase() = default;
    AllocBase(Alloc a) : m_alloc(std::move(a))
    {
    }

    allocator_type& a() noexcept
    {
        return m_alloc;
    }
    const allocator_type& a() const noexcept
    {
        return m_alloc;
    }
};

template <typename Hash, bool = std::is_empty_v<Hash> && !std::is_final_v<Hash>>
class HashBase : private Hash
{
public:
    using hasher = Hash;

    HashBase() = default;
    HashBase(hasher h) : Hash(std::move(h))
    {
    }
    const hasher& h() const noexcept
    {
        return *this;
    }
};

template <typename Hash>
class HashBase<Hash, false>
{
    Hash m_hash;

public:
    using hasher = Hash;

    HashBase() = default;
    HashBase(hasher h) : m_hash(std::move(h))
    {
    }
    const hasher& h() const noexcept
    {
        return m_hash;
    }
};

template <typename KeyEqual, bool = std::is_empty_v<KeyEqual> && !std::is_final_v<KeyEqual>>
class KeyEqualBase : private KeyEqual
{
public:
    using key_equal = KeyEqual;

    KeyEqualBase() = default;
    KeyEqualBase(key_equal k) : KeyEqual(std::move(k))
    {
    }
    const key_equal& ke() const noexcept
    {
        return *this;
    }
};

template <typename KeyEqual>
class KeyEqualBase<KeyEqual, false>
{
    KeyEqual m_key_equal;

public:
    using key_equal = KeyEqual;

    KeyEqualBase() = default;
    KeyEqualBase(key_equal k) : m_key_equal(std::move(k))
    {
    }
    const key_equal& ke() const noexcept
    {
        return m_key_equal;
    }
};

template <typename Key, typename Hash, typename KeyEqual>
class HashCompare : private HashBase<Hash>, private KeyEqualBase<KeyEqual>
{
    using is_transparent_hash = SupportsTransparent<Key, Hash, KeyEqual>;

public:
    using hasher = typename HashBase<Hash>::hasher;
    using key_equal = typename KeyEqualBase<KeyEqual>::key_equal;

    HashCompare() = default;
    HashCompare(hasher hash, key_equal equal)
        : HashBase<Hash>(std::move(hash)), KeyEqualBase<KeyEqual>(std::move(equal))
    {
    }

    std::size_t operator()(const Key& key) const
    {
        return std::size_t(this->h()(key));
    }

    bool operator()(const Key& key1, const Key& key2) const
    {
        return this->ke()(key1, key2);
    }

    template <typename K, typename = std::enable_if_t<is_transparent_hash::value, K>>
    std::size_t operator()(const K& key) const
    {
        return std::size_t(this->h()(key));
    }

    template <typename K1, typename K2, typename = std::enable_if_t<is_transparent_hash::value, K1>>
    bool operator()(const K1& key1, const K2& key2) const
    {
        return this->ke()(key1, key2);
    }

    hasher hash_function() const
    {
        return this->h();
    }

    key_equal key_eq() const
    {
        return this->ke();
    }
};

} // namespace detail

} // namespace carb::container