Skip to content

Instantly share code, notes, and snippets.

@kim366
Last active April 18, 2019 11:16
Show Gist options
  • Save kim366/8112a8f1603951e81c8d23cff27db135 to your computer and use it in GitHub Desktop.
Save kim366/8112a8f1603951e81c8d23cff27db135 to your computer and use it in GitHub Desktop.
#include <any>
#include <cassert>
#include <utility>
#include <vector>
enum class param_type
{
templated,
normal
};
struct type_name_t
{
type_name_t(const char* name) : name(name) {}
type_name_t(const char* name, std::vector<type_name_t> parameters)
: type(param_type::templated)
, name(name)
, parameters(std::move(parameters))
{
}
param_type type = param_type::normal;
const char* name;
std::vector<type_name_t> parameters;
};
template<typename T>
struct types_match_impl
{
constexpr static bool synced() { return false; }
};
#define IMPL_ASSERT_SYNC \
static_assert(types_match_impl<SyncedT>::synced(), \
"Type not synced (type labelled as SyncedT)!")
#define IMPL_COMMON_TYPE_MATCH(type_name) \
static auto type() \
{ \
static auto type = type_name; \
return type; \
} \
\
constexpr static bool synced() { return true; }
#define SYNC(cpp_type, type_name) \
template<> \
struct types_match_impl<cpp_type> \
{ \
IMPL_COMMON_TYPE_MATCH(type_name) \
\
static bool match(type_name_t other) \
{ \
return other.type == param_type::normal && other.name == type(); \
} \
}
#define SYNC_GENERIC(cpp_template, type_name) \
template<typename... ArgTs> \
struct types_match_impl<cpp_template<ArgTs...>> \
{ \
IMPL_COMMON_TYPE_MATCH(type_name) \
\
static bool match(type_name_t templ_type) \
{ \
return templ_type.type == param_type::templated \
&& sizeof...(ArgTs) == templ_type.parameters.size() \
&& templ_type.name == type() \
&& all_types_match_impl<ArgTs...>::match( \
templ_type.parameters, 0); \
} \
}
template<typename...>
struct all_types_match_impl;
template<typename SyncedT, typename... RestTs>
struct all_types_match_impl<SyncedT, RestTs...>
{
static bool match(std::vector<type_name_t> types, unsigned n)
{
IMPL_ASSERT_SYNC;
return types_match_impl<SyncedT>::match(types[n])
&& all_types_match_impl<RestTs...>::match(types, n + 1);
}
};
template<>
struct all_types_match_impl<>
{
static bool match(std::vector<type_name_t>, unsigned) { return true; }
};
template<typename...>
struct sync_force_resolve_impl;
template<typename T, typename... Ts>
struct sync_force_resolve_impl<T, Ts...>
{
static void resolve()
{
(void)types_match_impl<T>::type();
sync_force_resolve_impl<Ts...>::resolve();
}
};
template<>
struct sync_force_resolve_impl<>
{
static void resolve() {}
};
template<typename... Ts>
void sync_force_resolve()
{
sync_force_resolve_impl<Ts...>::resolve();
}
template<typename SyncedT>
bool types_match(type_name_t name)
{
IMPL_ASSERT_SYNC;
return types_match_impl<SyncedT>::match(name);
}
//////////////////////////////////////////////////
template<typename T, typename U>
struct vec
{
T x;
U y;
};
template<typename T>
struct single_vec
{
T x;
};
SYNC(int, "int");
SYNC(bool, "bool");
SYNC(double, "double");
SYNC_GENERIC(vec, "Vec");
SYNC_GENERIC(single_vec, "SingleVec");
const auto int_vec = type_name_t{"Vec", {"int", "int"}};
const auto mixed_vec = type_name_t{"Vec", {"bool", "double"}};
const auto single_vec_i = type_name_t{"Vec", {"int", "bool"}};
const auto nested_vec = type_name_t{"SingleVec", {single_vec_i}};
int main()
{
sync_force_resolve<int, double>();
assert(types_match<int>("int"));
assert(types_match<double>("double"));
assert(!types_match<int>("double"));
assert((types_match<vec<int, int>>(int_vec)));
assert((types_match<vec<bool, double>>(mixed_vec)));
assert((types_match<single_vec<vec<int, bool>>>(nested_vec)));
assert(!(types_match<single_vec<vec<int, int>>>(nested_vec)));
assert(!(types_match<single_vec<bool>>(nested_vec)));
assert((types_match<vec<int, bool>>(single_vec_i)));
assert(!(types_match<vec<bool, bool>>(single_vec_i)));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment