
// Copyright 2019 Shlomi Steinberg
// 

#include <tuple>
#include <functional>

namespace _tuple_hash_detail {

// Boost hash_combine
template <class T>
inline auto hash_combine(std::size_t seed, const T& v) {
	using hasher = std::hash<T>;
	seed ^= hasher{}(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
	return seed;
}
template<typename Tuple, std::size_t... ids>
std::size_t hash(const Tuple& tuple, std::index_sequence<ids...>) {
    std::size_t hash = 0;
    for(const auto &h : { std::hash<typename std::tuple_element_t<ids, Tuple>>{}(std::get<ids>(tuple))... })
        hash = hash_combine(hash, h);
    return hash;
};

}

template<typename... Ts>
std::size_t tuple_hash(const std::tuple<Ts...>& tuple) {
    return _tuple_hash_detail::hash(tuple, std::make_index_sequence<sizeof...(Ts)>());
}
std::size_t tuple_hash(const std::tuple<>& tuple) {
    return 0;
}
