Skip to content

Instantly share code, notes, and snippets.

@Holt59
Last active August 23, 2017 13:09
Show Gist options
  • Save Holt59/ef77f74bcd526fbf52b65b759210cfa9 to your computer and use it in GitHub Desktop.
Save Holt59/ef77f74bcd526fbf52b65b759210cfa9 to your computer and use it in GitHub Desktop.
Polymorphic hash implementation, without templated HashAlgorithm
#include <array>
#include <functional>
#include <typeinfo>
#include <unordered_map>
#include <memory>
#include <utility>
#include <iostream>
#include <typeindex>
// std::apply
namespace notstd {
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
namespace details {
template<class F, class Tuple, std::size_t...Is>
auto apply( F&& f, Tuple&& tuple, std::index_sequence<Is...> )
RETURNS( std::forward<F>(f)( std::get<Is>(std::forward<Tuple>(tuple))... ) )
template<class Tuple>
using raw_tuple =
typename std::remove_cv<typename std::remove_reference<Tuple>::type>::type;
template<class Tuple>
using tuple_count = std::tuple_size< raw_tuple<Tuple> >;
}
template<class F, class Tuple>
auto apply( F&& f, Tuple&& tuple )
RETURNS(
::notstd::details::apply(
std::forward<F>(f),
std::forward<Tuple>(tuple),
std::make_index_sequence<
::notstd::details::tuple_count<Tuple>::value
>{}
)
)
}
struct hash_algorithm { };
void hash_append(hash_algorithm &, std::type_info const& x) {
std::cout << "hash_append<std::type_info>(" << x.name() << ")\n";
}
void hash_append(hash_algorithm &, int x) {
std::cout << "hash_append<int>(" << x << ")\n";
}
void hash_append(hash_algorithm &, double x) {
std::cout << "hash_append<double>(" << x << ")\n";
}
template <class... Ts>
void hash_append(hash_algorithm& h, std::tuple<Ts... > const& t) {
notstd::apply([&h](auto&&... args) {
using expander = int[];
(void)expander{0,
(hash_append(h, args), 0)...};
}, t);
}
struct polymorphic_hash_t {
static polymorphic_hash_t& get() {
static polymorphic_hash_t instance;
return instance;
}
template <class T, class F>
polymorphic_hash_t& add(F f) {
// std::function<void(std::function<void(void*)>, void*)> fn;
map_[typeid(T)] = [f](hash_algorithm& h, const void *p) {
T const& t = *static_cast<const T*>(p);
hash_append(h, f(t));
};
return *this;
}
template <class T>
polymorphic_hash_t& add() {
map_[typeid(T)] = [](hash_algorithm &, const void*) { };
return *this;
}
template <class T>
void operator()(hash_algorithm& h, const T& t) const {
hash_append(h, typeid(t));
map_.at(typeid(t))(h, static_cast<const void*>(&t));
}
protected:
polymorphic_hash_t() = default;
std::unordered_map<std::type_index,
std::function<void(hash_algorithm&, const void*)>> map_;
};
struct A {
virtual void f() = 0;
};
struct B: A {
virtual void f() { }
};
struct C: A {
int x;
virtual void f() { }
};
struct D: A {
int x;
double y;
virtual void f() { }
};
void f(A const& a) {
hash_algorithm h;
polymorphic_hash_t::get()(h, a);
}
int main() {
polymorphic_hash_t::get()
.add<B>()
.add<C>([](C const& c) { return std::tie(c.x); })
.add<D>([](D const& d) { return std::tie(d.x, d.y); });
B b;
f(b);
C c;
c.x = 12;
f(c);
c.x = 42;
f(c);
D d;
d.x = 13;
d.y = 3.14;
f(d);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment