kyopro library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub Chipppppppppp/kyopro

:heavy_check_mark: kpr/algorithm/Hash.hpp

Depends on

Required by

Verified with

Code

#pragma once
#include <cstddef>
#include <functional>
#include <iterator>
#include <type_traits>
#include <utility>
#include "../meta/tuple_like.hpp"
#include "../meta/trait.hpp"

namespace kpr {
    // ハッシュ(tuple_like, range対応)

    template<class, class = void>
    struct Hash;

    template<class T>
    struct Hash<T, std::enable_if_t<std::is_scalar_v<T>>> {
        using value_type = T;

        constexpr std::size_t operator ()(T a) const noexcept {
            return std::hash<T>{}(a);
        }
    };

    template<class T>
    struct Hash<T, std::enable_if_t<is_tuple_like_v<T> && !is_range_v<T>>> {
        using value_type = T;

        template<std::size_t i = 0>
        constexpr std::size_t operator ()(const T& a) const noexcept {
            if constexpr (i == tuple_like_size_v<T>) return tuple_like_size_v<T>;
            else {
                std::size_t seed = operator()<i + 1>(a);
                return seed ^ (Hash<tuple_like_element_t<i, T>>{}(get<i>(a)) + 0x9e3779b97f4a7c15LU + (seed << 12) + (seed >> 4));
            }
        }
    };

    template<class T>
    struct Hash<T, std::enable_if_t<is_range_v<T>>>: Hash<range_value_t<T>> {
        using value_type = T;

        constexpr std::size_t operator ()(const T& a) const {
            std::size_t seed = std::size(a);
            for (auto&& i: a) seed ^= Hash<range_value_t<T>>{}(i) + 0x9e3779b97f4a7c15LU + (seed << 12) + (seed >> 4);
            return seed;
        }
    };
} // namespace kpr
#line 2 "kpr/algorithm/Hash.hpp"
#include <cstddef>
#include <functional>
#include <iterator>
#include <type_traits>
#include <utility>
#line 4 "kpr/meta/tuple_like.hpp"
#include <tuple>
#line 6 "kpr/meta/tuple_like.hpp"

namespace kpr {
    namespace helper {
        struct CastableToAny {
            template<class T>
            operator T() const noexcept;
        };

        template<class T, std::size_t... idx, std::void_t<decltype(T{((void)idx, CastableToAny{})...})>* = nullptr>
        constexpr bool is_constructible_with(std::index_sequence<idx...>, bool) noexcept {
            return true;
        }
        template<class T, std::size_t... idx>
        constexpr bool is_constructible_with(std::index_sequence<idx...>, char) noexcept {
            return false;
        }

        template<class T, std::size_t n = sizeof(T) * 8, class = void>
        struct constructible_size {
            static_assert(n != 0, "T is not constructible");
            static constexpr std::size_t value = constructible_size<T, n - 1>::value;
        };

        template<class T, std::size_t n>
        struct constructible_size<T, n, std::enable_if_t<is_constructible_with<T>(std::make_index_sequence<n>(), false)>> {
            static constexpr std::size_t value = n;
        };
    } // namespace helper


    // tuple_likeな型Tの大きさを調べる
    template<class T, class = void>
    struct tuple_like_size {
        static constexpr std::size_t value = helper::constructible_size<T>::value;
    };

    template<class T>
    struct tuple_like_size<T, std::void_t<decltype(std::tuple_size<T>::value)>> {
        static constexpr std::size_t value = std::tuple_size_v<T>;
    };

    // tuple_likeな型Tの大きさを調べる
    template<class T>
    inline constexpr std::size_t tuple_like_size_v = tuple_like_size<T>::value;


    // tuple_likeなオブジェクトのidx(0 <= idx < 8)番目を求める関数クラス
    template<class T, class = void>
    struct GetFunction {
        #define GET(...) \
            { \
                auto&& [__VA_ARGS__] = std::forward<U>(tuple_like); \
                return std::get<idx> (std::forward_as_tuple(__VA_ARGS__)); \
            }

        template<std::size_t idx, class U>
        static constexpr decltype(auto) get(U&& tuple_like) noexcept {
            constexpr std::size_t size = tuple_like_size_v<T>;
            static_assert(size != 0, "The size must not be 0");
            static_assert(size < 9, "The size of tuple_like must be less than 9");
            if constexpr (size == 1) GET(a)
            else if constexpr (size == 2) GET(a, b)
            else if constexpr (size == 3) GET(a, b, c)
            else if constexpr (size == 4) GET(a, b, c, d)
            else if constexpr (size == 5) GET(a, b, c, d, e)
            else if constexpr (size == 6) GET(a, b, c, d, e, f)
            else if constexpr (size == 7) GET(a, b, c, d, e, f, g)
            else GET(a, b, c, d, e, f, g, h)
        }

        #undef GET
    };

    template<class T>
    struct GetFunction<T, std::void_t<decltype(std::tuple_size<T>::value)>> {
        template<std::size_t idx, class U>
        static constexpr decltype(auto) get(U&& tuple_like) noexcept {
            return std::get<idx>(std::forward<U>(tuple_like));
        }
    };

    namespace helper {
        template<std::size_t idx>
        struct GetHelper {
            template<class T>
            constexpr decltype(auto) operator ()(T&& tuple_like) const noexcept {
                return GetFunction<std::decay_t<T>>::template get<idx>(std::forward<T>(tuple_like));
            }
        };
    }

    // tuple-likeなオブジェクトのidx(0 <= idx < 8)番目を求める
    template<std::size_t idx>
    inline constexpr helper::GetHelper<idx> get;


    // tuple-likeな型Tのidx(0 <= idx < 8)番目の要素の型を調べる
    template<std::size_t idx, class T>
    struct tuple_like_element {
        using type = std::decay_t<decltype(get<idx>(std::declval<T>()))>;
    };

    // tuple-likeな型Tのidx(0 <= idx < 8)番目の要素の型を調べる
    template<std::size_t idx, class T>
    using tuple_like_element_t = typename tuple_like_element<idx, T>::type;


    // 型Tがtuple_likeか調べる
    template<class T, class = void>
    struct is_tuple_like {
        static constexpr bool value = std::is_aggregate_v<T>;
    };

    template<class T>
    struct is_tuple_like<T, std::void_t<decltype(std::tuple_size<T>::value)>> {
        static constexpr bool value = true;
    };

    // 型Tがtuple_likeか調べる
    template<class T>
    inline constexpr bool is_tuple_like_v = is_tuple_like<T>::value;
} // namespace kpr
#line 7 "kpr/meta/trait.hpp"

namespace kpr {
    namespace helper {
        template<class T>
        struct is_integer_helper {
            static constexpr bool value = std::is_integral_v<T>;
        };

        #ifdef __SIZEOF_INT128__
        template<>
        struct is_integer_helper<__int128_t> {
            static constexpr bool value = true;
        };
        template<>
        struct is_integer_helper<__uint128_t> {
            static constexpr bool value = true;
        };
        #endif
    } // namespace helper


    // 型Tが整数か調べる

    template<class T>
    struct is_integer {
        static constexpr bool value = helper::is_integer_helper<std::remove_cv_t<T>>::value;
    };
    // 型Tが整数か調べる

    template<class T>
    inline constexpr bool is_integer_v = is_integer<T>::value;

    // 型Tが符号付き整数か調べる

    template<class T>
    struct is_signed_integer {
        static constexpr bool value = is_integer_v<T> && std::is_signed_v<T>;
    };
    // 型Tが符号付き整数か調べる

    template<class T>
    inline constexpr bool is_signed_integer_v = is_signed_integer<T>::value;

    // 型Tが符号無し整数か調べる

    template<class T>
    struct is_unsigned_integer {
        static constexpr bool value = is_integer_v<T> && !std::is_signed_v<T>;
    };
    // 型Tが符号無し整数か調べる

    template<class T>
    inline constexpr bool is_unsigned_integer_v = is_unsigned_integer<T>::value;

    namespace helper {
        template<class T>
        struct is_floating_point_helper {
            static constexpr bool value = std::is_floating_point_v<T>;
        };

        #ifdef __SIZEOF_FLOAT128__
        template<>
        struct is_floating_point_helper<__float128> {
            static constexpr bool value = true;
        };
        #endif
    } // namespace helper


    // 型Tが浮動小数点数か調べる

    template<class T>
    struct is_floating_point {
        static constexpr bool value = helper::is_floating_point_helper<std::remove_cv_t<T>>::value;
    };
    // 型Tが浮動小数点数か調べる

    template<class T>
    inline constexpr bool is_floating_point_v = is_floating_point<T>::value;

    // 型Tが算術型か調べる

    template<class T>
    struct is_arithmetic {
        static constexpr bool value = is_integer_v<T> || is_floating_point_v<T>;
    };
    // 型Tが算術型か調べる

    template<class T>
    inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;

    // 型Tがスカラーか調べる

    template<class T>
    struct is_scalar {
        static constexpr bool value = is_arithmetic_v<T> || std::is_enum_v<T> || std::is_pointer_v<T> || std::is_member_pointer_v<T> || std::is_null_pointer_v<T>;
    };
    // 型Tがスカラーか調べる

    template<class T>
    inline constexpr bool is_scalar_v = is_scalar<T>::value;

    // size以上の大きさを持つ最小の符号付き整数を調べる

    template<std::size_t size>
    struct int_least {
    private:
        static constexpr auto get_type() noexcept {
            static_assert(size <= 128, "The given integer type is too large");
            if constexpr (size <= 8) return std::int_least8_t{};
            else if constexpr (size <= 16) return std::int_least16_t{};
            else if constexpr (size <= 32) return std::int_least32_t{};
            else if constexpr (size <= 64) return std::int_least64_t{};
            else return __int128_t{};
        }

    public:
        using type = decltype(get_type());
    };
    // size以上の大きさを持つ最小の符号付き整数を調べる

    template<std::size_t size>
    using int_least_t = typename int_least<size>::type;

    // size以上の大きさを持つ最小の符号無し整数を調べる

    template<std::size_t size>
    struct uint_least {
    private:
        static constexpr auto get_type() noexcept {
            static_assert(size <= 128, "The give integer type is too large");
            if constexpr (size <= 8) return std::uint_least8_t{};
            else if constexpr (size <= 16) return std::uint_least16_t{};
            else if constexpr (size <= 32) return std::uint_least32_t{};
            else if constexpr (size <= 64) return std::uint_least64_t{};
            else return __uint128_t{};
        }

    public:
        using type = decltype(get_type());
    };
    // size以上の大きさを持つ最小の符号無し整数を調べる

    template<std::size_t size>
    using uint_least_t = typename uint_least<size>::type;

    // Tの次に大きい整数型を調べる

    template<class T>
    struct next_integer {
        static_assert(is_integer_v<T>, "The given type must be an integer type");
        static_assert(sizeof(T) <= 8, "The given integer type is too large");
        using type = std::conditional_t<std::is_signed_v<T>, int_least_t<sizeof(T) * 16>, uint_least_t<sizeof(T) * 16>>;
    };
    // Tの次に大きい整数型を調べる

    template<class T>
    using next_integer_t = typename next_integer<T>::type;

    // Tの次に小さい整数型を調べる

    template<class T>
    struct prev_integer {
        static_assert(is_integer_v<T>, "The given type must be an integer type");
        static_assert(sizeof(T) >= 2, "The given integer type is too large");
        using type = std::conditional_t<std::is_signed_v<T>, int_least_t<sizeof(T) * 4>, uint_least_t<sizeof(T) * 4>>;
    };
    // Tの次に小さい整数型を調べる

    template<class T>
    using prev_integer_t = typename prev_integer<T>::type;

    // 型Tがイテレータか調べる

    template<class T, class = void>
    struct is_iterator {
        static constexpr bool value = false;
    };
    template<class T>
    struct is_iterator<T, std::void_t<typename std::iterator_traits<T>::iterator_category>> {
        static constexpr bool value = true;
    };
    // 型Tがイテレータか調べる

    template<class T>
    inline constexpr bool is_iterator_v = is_iterator<T>::value;

    // 型TがRangeか調べる

    template<class T, class = void>
    struct is_range {
        static constexpr bool value = false;
    };
    template<class T>
    struct is_range<T, std::void_t<decltype(std::begin(std::declval<std::add_lvalue_reference_t<T>>()), std::end(std::declval<std::add_lvalue_reference_t<T>>()))>> {
        static constexpr bool value = true;
    };
     // 型TがRangeか調べる

    template<class T>
    inline constexpr bool is_range_v = is_range<T>::value;

    // Range型Tからイテレータの型を調べる

    template<class T>
    struct range_iterator {
        using type = std::decay_t<decltype(std::begin(std::declval<T>()))>;
    };
    // Range型Tからイテレータの型を調べる

    template<class T>
    using range_iterator_t = typename range_iterator<T>::type;

    // Range型Tから読み取り専用イテレータの型を調べる

    template<class T>
    struct range_const_iterator {
        using type = std::decay_t<decltype(std::cbegin(std::declval<T>()))>;
    };
    // Range型Tから読み取り専用イテレータの型を調べる

    template<class T>
    using range_const_iterator_t = typename range_iterator<T>::type;

    // Range型Tから要素の型を調べる

    template<class T>
    struct range_value {
        using type = std::decay_t<decltype(*std::begin(std::declval<T>()))>;
    };
    // Range型Tから要素の型を調べる

    template<class T>
    using range_value_t = typename range_value<T>::type;
} // namespace kpr

#line 9 "kpr/algorithm/Hash.hpp"

namespace kpr {
    // ハッシュ(tuple_like, range対応)

    template<class, class = void>
    struct Hash;

    template<class T>
    struct Hash<T, std::enable_if_t<std::is_scalar_v<T>>> {
        using value_type = T;

        constexpr std::size_t operator ()(T a) const noexcept {
            return std::hash<T>{}(a);
        }
    };

    template<class T>
    struct Hash<T, std::enable_if_t<is_tuple_like_v<T> && !is_range_v<T>>> {
        using value_type = T;

        template<std::size_t i = 0>
        constexpr std::size_t operator ()(const T& a) const noexcept {
            if constexpr (i == tuple_like_size_v<T>) return tuple_like_size_v<T>;
            else {
                std::size_t seed = operator()<i + 1>(a);
                return seed ^ (Hash<tuple_like_element_t<i, T>>{}(get<i>(a)) + 0x9e3779b97f4a7c15LU + (seed << 12) + (seed >> 4));
            }
        }
    };

    template<class T>
    struct Hash<T, std::enable_if_t<is_range_v<T>>>: Hash<range_value_t<T>> {
        using value_type = T;

        constexpr std::size_t operator ()(const T& a) const {
            std::size_t seed = std::size(a);
            for (auto&& i: a) seed ^= Hash<range_value_t<T>>{}(i) + 0x9e3779b97f4a7c15LU + (seed << 12) + (seed >> 4);
            return seed;
        }
    };
} // namespace kpr
Back to top page