/* * OpenClonk, http://www.openclonk.org * * Copyright (c) 2016, The OpenClonk Team and contributors * * Distributed under the terms of the ISC license; see accompanying file * "COPYING" for details. * * "Clonk" is a registered trademark of Matthes Bender, used with permission. * See accompanying file "TRADEMARK" for details. * * To redistribute this file separately, substitute the full license texts * for the above references. */ #ifndef C4PuncherHash_H #define C4PuncherHash_H #include #include "network/C4NetIO.h" namespace { size_t hash_combiner(size_t left, size_t right) //replacable { return left*2793419347^right; } template struct hash_impl { size_t operator()(size_t a, const std::tuple& t) const { typedef typename std::tuple_element>::type nexttype; hash_impl next; size_t b = std::hash()(std::get(t)); return next(hash_combiner(a, b), t); } }; template struct hash_impl<1, types...> { size_t operator()(size_t a, const std::tuple& t) const { typedef typename std::tuple_element<0, std::tuple>::type nexttype; size_t b = std::hash()(std::get<0>(t)); return hash_combiner(a, b); } }; template struct hash_impl<0, types...> { size_t operator()(size_t a, const std::tuple& t) const { return 0; } }; } namespace std { // Remove this when C++ gets proper tuple hashes. For now, http://stackoverflow.com/questions/7110301/generic-hash-for-tuples-in-unordered-map-unordered-set will do template struct hash> { size_t operator()(const std::tuple& t) const { const size_t begin = std::tuple_size>::value; return hash_impl()(19739, t); } }; template<> struct hash { size_t operator()(const C4NetIO::addr_t& addr) const { switch (addr.GetFamily()) { case C4NetIO::HostAddress::IPv4: { sockaddr_in v4 = addr; auto unpack = make_tuple(v4.sin_family, v4.sin_addr.s_addr, v4.sin_port); return hash()(unpack); } case C4NetIO::HostAddress::IPv6: { sockaddr_in6 v6 = addr; auto unpack = make_tuple(v6.sin6_family, v6.sin6_port, v6.sin6_flowinfo, std::string((char*) v6.sin6_addr.s6_addr, 16), v6.sin6_scope_id); return hash()(unpack); } case C4NetIO::HostAddress::UnknownFamily: assert(!"Unexpected address family"); return 0; } } }; } #endif