diff --git a/include/bluegrass/meta/function_traits.hpp b/include/bluegrass/meta/function_traits.hpp new file mode 100644 index 0000000..a3d4abb --- /dev/null +++ b/include/bluegrass/meta/function_traits.hpp @@ -0,0 +1,244 @@ +#pragma once + +#include "utility.hpp" + +#include +#include + +#define BLUEGRASS_META_HAS_MEMBER_GENERATOR(NAME, MEMBER) \ + template \ + struct has_member_ ## NAME { \ + template struct sfinae {}; \ + template constexpr static char test(sfinae*); \ + template constexpr static int test(...); \ + constexpr static const bool value = sizeof(test(0)) == sizeof(char); \ + }; + +#define BLUEGRASS_HAS_MEMBER(ARG, NAME) \ + bluegrass::meta::overloaded { \ + [](auto&& f, std::enable_if_t> && \ + bluegrass::meta::detail::pass_type< \ + decltype(&std::decay_t::type::NAME)>(), int> = 0) constexpr { \ + return true; \ + }, [](...) constexpr { return false; } \ + }(bluegrass::meta::detail::wrapper_t{}) + +#define BLUEGRASS_HAS_MEMBER_TY(TY, NAME) \ + bluegrass::meta::overloaded { \ + [](auto&& f, std::enable_if_t && \ + bluegrass::meta::detail::pass_type< \ + decltype(&std::decay_t::type::NAME)>(), int> = 0) constexpr { \ + return true; \ + }, [](...) constexpr { return false; } \ + }(bluegrass::meta::detail::wrapper_t{}) + +#define BLUEGRASS_HAS_TEMPLATE_MEMBER(ARG, NAME) \ + bluegrass::meta::overloaded { \ + [&](auto&& f, std::enable_if_t> && \ + bluegrass::meta::detail::pass_type< \ + decltype(&std::decay_t::type::template NAME)>(), int> = 0) constexpr { \ + return true; \ + }, [](...) constexpr { return false; } \ + }(bluegrass::meta::detail::wrapper_t{}) + +#define BLUEGRASS_HAS_TEMPLATE_MEMBER_TY(TY, NAME) \ + bluegrass::meta::overloaded { \ + [](auto&& f, std::enable_if_t && \ + bluegrass::meta::detail::pass_type< \ + decltype(&std::decay_t::type::template NAME)>(), int> = 0) constexpr { \ + return true; \ + }, [](...) constexpr { return false; } \ + }(bluegrass::meta::detail::wrapper_t{}) + + +// Workaround for compiler bug handling C++g17 auto template parameters. +// The parameter is not treated as being type-dependent in all contexts, +// causing early evaluation of the containing expression. +// Tested at Apple LLVM version 10.0.1 (clang-1001.0.46.4) +#define AUTO_PARAM_WORKAROUND(X) bluegrass::meta::detail::make_dependent(X) + +namespace bluegrass { namespace meta { + + struct freestanding {}; + + namespace detail { + template + constexpr bool pass_type() { return true; } + + template + constexpr bool is_callable_impl(...) { + return false; + } + + template + struct wrapper_t { + using type = T; + constexpr wrapper_t() {} + constexpr wrapper_t(T&&) {} + }; + + template + inline constexpr U&& make_dependent(U&& u) { return static_cast(u); } + } + + template + inline constexpr static bool is_callable_v = BLUEGRASS_HAS_MEMBER(AUTO_PARAM_WORKAROUND(FN), operator()); + + template + constexpr bool is_callable(F&& fn) { return BLUEGRASS_HAS_MEMBER(fn, operator()); } + + namespace detail { + template + constexpr auto get_types(R(Args...)) -> std::tuple, Args>...>>; + template + constexpr auto get_types(R (Cls::*)(Args...)) -> std::tuple, Args>...>>; + template + constexpr auto get_types(R (Cls::*)(Args...)const) -> std::tuple, Args>...>>; + template + constexpr auto get_types(R (Cls::*)(Args...)&) -> std::tuple, Args>...>>; + template + constexpr auto get_types(R (Cls::*)(Args...)&&) -> std::tuple, Args>...>>; + template + constexpr auto get_types(R (Cls::*)(Args...)const &) -> std::tuple, Args>...>>; + template + constexpr auto get_types(R (Cls::*)(Args...)const &&) -> std::tuple, Args>...>>; + template + constexpr auto get_types(F&& fn) { + if constexpr (is_callable_v) + return get_types(&F::operator()); + else + return get_types(fn); + } + + template + using get_types_t = decltype(get_types(std::declval())); + + template + struct pack_from; + + template + struct pack_from { + static_assert(Sz > N, "index out of range"); + using type = typename pack_from::type; + }; + + template + struct pack_from { + using type = std::tuple; + }; + + template + using pack_from_t = typename pack_from::type; + + template + constexpr auto parameters_from_impl(R(Args...)) -> pack_from_t; + template + constexpr auto parameters_from_impl(R(Cls::*)(Args...)) -> pack_from_t; + template + constexpr auto parameters_from_impl(R(Cls::*)(Args...)const) -> pack_from_t; + template + constexpr auto parameters_from_impl(R(Cls::*)(Args...)&) -> pack_from_t; + template + constexpr auto parameters_from_impl(R(Cls::*)(Args...)&&) -> pack_from_t; + template + constexpr auto parameters_from_impl(R(Cls::*)(Args...)const &) -> pack_from_t; + template + constexpr auto parameters_from_impl(R(Cls::*)(Args...)const &&) -> pack_from_t; + template + constexpr auto parameters_from_impl(F&& fn) { + if constexpr (is_callable_v) + return parameters_from_impl(&F::operator()); + else + return parameters_from_impl(fn); + } + + template + using parameters_from_impl_t = decltype(parameters_from_impl(std::declval())); + } // ns bluegrass::meta::detail + + template + constexpr bool is_function(R(*)(Args...)) { return true; } + + template + constexpr bool is_function(F&&) { return false; } + + template + constexpr bool is_member_function(R(Cls::*)(Args...)) { return true; } + + template + constexpr bool is_member_function(R(Cls::*)(Args...)const ) { return true; } + + template + constexpr bool is_member_function(R(Cls::*)(Args...)& ) { return true; } + + template + constexpr bool is_member_function(R(Cls::*)(Args...)&& ) { return true; } + + template + constexpr bool is_member_function(R(Cls::*)(Args...)const & ) { return true; } + + template + constexpr bool is_member_function(R(Cls::*)(Args...)const && ) { return true; } + + template + constexpr bool is_member_function(F&&) { return false; } + + template + inline constexpr static bool is_function_v = is_function(AUTO_PARAM_WORKAROUND(FN)); + + template + inline constexpr static bool is_member_function_v = is_member_function(AUTO_PARAM_WORKAROUND(FN)); + + template + constexpr bool is_class(F&&) { return std::is_class_v; } + + template + constexpr auto return_type(F&& fn) -> std::tuple_element_t<0, detail::get_types_t>; + + template + using return_type_t = decltype(return_type(AUTO_PARAM_WORKAROUND(FN))); + + template + constexpr auto class_from_member(F&& fn) -> std::tuple_element_t<1, detail::get_types_t>; + + template + using class_from_member_t = decltype(class_from_member(AUTO_PARAM_WORKAROUND(FN))); + + template + constexpr auto flatten_parameters(F&& fn) -> std::tuple_element_t<2, detail::get_types_t>; + + template + using flatten_parameters_t = decltype(flatten_parameters(AUTO_PARAM_WORKAROUND(FN))); + + template + constexpr auto decayed_flatten_parameters(F&& fn) -> std::tuple_element_t<2, detail::get_types_t>; + + template + using decayed_flatten_parameters_t = decltype(decayed_flatten_parameters(AUTO_PARAM_WORKAROUND(FN))); + + template + constexpr auto parameter_at(F&& fn) -> std::tuple_element_t()))>; + + template + using parameter_at_t = decltype(parameter_at(AUTO_PARAM_WORKAROUND(FN))); + + template + constexpr auto parameters_from(F&& fn) -> detail::parameters_from_impl_t; + + template + using parameters_from_t = decltype(parameters_from(AUTO_PARAM_WORKAROUND(FN))); + + template + inline constexpr static std::size_t arity(F&& fn) { return std::tuple_size_v; } + + template + inline constexpr static std::size_t arity_v = arity(FN); +}} diff --git a/include/bluegrass/meta/preprocessor.hpp b/include/bluegrass/meta/preprocessor.hpp new file mode 100644 index 0000000..d1248cd --- /dev/null +++ b/include/bluegrass/meta/preprocessor.hpp @@ -0,0 +1,78 @@ +#pragma once + +#define BLUEGRASS_META_EXPAND(X) X + +#define BLUEGRASS_META_GET_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, NAME, ...) NAME + +#define BLUEGRASS_META_FE0(MAC, ...) +#define BLUEGRASS_META_FE1(MAC, A, B) MAC(A, B) +#define BLUEGRASS_META_FE2(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE1(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE3(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE2(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE4(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE3(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE5(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE4(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE6(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE5(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE7(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE6(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE8(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE7(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE9(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE8(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE10(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE9(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE11(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE10(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE12(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE11(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE13(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE12(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE14(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE13(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE15(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE14(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE16(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE15(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE17(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE16(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE18(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE17(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE19(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE18(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE20(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE19(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE21(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE20(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE22(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE21(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE23(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE22(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE24(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE23(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE25(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE24(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE26(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE25(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE27(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE26(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE28(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE27(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE29(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE28(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE30(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE29(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE31(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE30(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE32(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE31(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA2(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE1(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA3(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA2(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA4(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA3(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA5(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA4(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA6(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA5(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA7(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA6(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA8(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA7(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA9(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA8(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA10(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA9(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA11(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA10(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA12(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA11(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA13(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA12(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA14(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA13(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA15(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA14(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA16(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA15(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA17(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA16(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA18(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA17(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA19(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA18(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA20(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA19(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA21(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA20(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA22(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA21(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA23(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA22(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA24(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA23(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA25(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA24(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA26(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA25(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA27(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA26(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA28(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA27(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA29(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA28(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA30(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA29(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA31(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA30(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA32(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA31(MAC, A, ##__VA_ARGS__) + +#define BLUEGRASS_META_FOREACH_NO_COMMA(MAC, D, ...) \ + BLUEGRASS_META_GET_NTH_ARG("ignored", ##__VA_ARGS__, \ + BLUEGRASS_META_FE32,BLUEGRASS_META_FE31,BLUEGRASS_META_FE30,BLUEGRASS_META_FE29,BLUEGRASS_META_FE28,BLUEGRASS_META_FE27,BLUEGRASS_META_FE26,BLUEGRASS_META_FE25,BLUEGRASS_META_FE24,BLUEGRASS_META_FE23,BLUEGRASS_META_FE22,BLUEGRASS_META_FE21,BLUEGRASS_META_FE20,BLUEGRASS_META_FE19,BLUEGRASS_META_FE18,BLUEGRASS_META_FE17,BLUEGRASS_META_FE16,BLUEGRASS_META_FE15,BLUEGRASS_META_FE14,BLUEGRASS_META_FE13,BLUEGRASS_META_FE12,BLUEGRASS_META_FE11,BLUEGRASS_META_FE10,BLUEGRASS_META_FE9,BLUEGRASS_META_FE8,BLUEGRASS_META_FE7,BLUEGRASS_META_FE6,BLUEGRASS_META_FE5,BLUEGRASS_META_FE4,BLUEGRASS_META_FE3,BLUEGRASS_META_FE2,BLUEGRASS_META_FE1,BLUEGRASS_META_FE0)(MAC, D, ##__VA_ARGS__) + +#define BLUEGRASS_META_FOREACH(MAC, D, ...) \ + BLUEGRASS_META_GET_NTH_ARG("ignored", ##__VA_ARGS__, \ + BLUEGRASS_META_FE_COMMA32,BLUEGRASS_META_FE_COMMA31,BLUEGRASS_META_FE_COMMA30,BLUEGRASS_META_FE_COMMA29,BLUEGRASS_META_FE_COMMA28,BLUEGRASS_META_FE_COMMA27,BLUEGRASS_META_FE_COMMA26,BLUEGRASS_META_FE_COMMA25,BLUEGRASS_META_FE_COMMA24,BLUEGRASS_META_FE_COMMA23,BLUEGRASS_META_FE_COMMA22,BLUEGRASS_META_FE_COMMA21,BLUEGRASS_META_FE_COMMA20,BLUEGRASS_META_FE_COMMA19,BLUEGRASS_META_FE_COMMA18,BLUEGRASS_META_FE_COMMA17,BLUEGRASS_META_FE_COMMA16,BLUEGRASS_META_FE_COMMA15,BLUEGRASS_META_FE_COMMA14,BLUEGRASS_META_FE_COMMA13,BLUEGRASS_META_FE_COMMA12,BLUEGRASS_META_FE_COMMA11,BLUEGRASS_META_FE_COMMA10,BLUEGRASS_META_FE_COMMA9,BLUEGRASS_META_FE_COMMA8,BLUEGRASS_META_FE_COMMA7,BLUEGRASS_META_FE_COMMA6,BLUEGRASS_META_FE_COMMA5,BLUEGRASS_META_FE_COMMA4,BLUEGRASS_META_FE_COMMA3,BLUEGRASS_META_FE_COMMA2,BLUEGRASS_META_FE1,BLUEGRASS_META_FE0)(MAC, D, ##__VA_ARGS__) diff --git a/include/bluegrass/meta/refl.hpp b/include/bluegrass/meta/refl.hpp new file mode 100644 index 0000000..94a50ef --- /dev/null +++ b/include/bluegrass/meta/refl.hpp @@ -0,0 +1,196 @@ +#pragma once + +#include "function_traits.hpp" +#include "utility.hpp" +#include "preprocessor.hpp" + +#include +#include +#include + +#include + +namespace bluegrass { namespace meta { + template + constexpr inline std::string_view type_name() { + constexpr std::string_view full_name = __PRETTY_FUNCTION__; + constexpr auto start = full_name.find("T = "); +#ifdef __clang__ + constexpr auto end = full_name.find("]"); +#elif __GNUC__ + constexpr auto end = full_name.find(";"); +#else +#error "Currently only supporting Clang and GCC compilers" +#endif + + return full_name.substr(start+4, end - start - 4); + } + + // tag used to define an invalid fields for field_types + struct invalid_fields {}; + + namespace detail { + template + constexpr inline auto which_field_types() { + if constexpr ( BLUEGRASS_HAS_MEMBER_TY(C, _bluegrass_meta_refl_valid) ) + return flatten_parameters_t<&C::_bluegrass_meta_refl_fields>{}; + else + return invalid_fields{}; + } + + template + constexpr inline std::size_t fields_size() { + if constexpr (std::is_same_v) + return 0; + else + return std::tuple_size_v; + } + + template + constexpr inline auto va_args_count_helper(Args&&...) { return sizeof...(Args); } + + template + struct fwd_t { using type = T; }; + + template + constexpr inline auto produce_tuple(std::index_sequence) + -> std::tuple< typename fwd_t::type ...>; + + template + constexpr inline auto homogeneous_field_types() + -> decltype(produce_tuple(std::make_index_sequence{})); + + template + constexpr inline std::size_t homogeneous_field_offset() { + static_assert(N <= Max); + return sizeof(T) * N; + } + } // ns bluegrass::meta::detail + + template + struct meta_object_base { + constexpr static inline std::string_view name = type_name(); + constexpr static inline auto get_name() { return name; } + + using field_types = invalid_fields; + template + using field_type = invalid_fields; + constexpr static inline std::size_t field_count = 0; + constexpr static auto field_names = std::array{}; + + constexpr static inline auto get_field_count() { return Derived::field_count; } + constexpr static inline auto get_field_name(std::size_t n) { return Derived::field_names[n]; } + constexpr static inline auto get_field_names() { return Derived::field_names; } + + template + constexpr static inline auto& get_field(T&& t) { + return Derived::template get_field(std::forward(t)); + } + + template + constexpr static inline auto& get_field(const T& t) { + return Derived::template get_field(t); + } + + template + constexpr inline static auto for_each_field_impl( T&& t, F&& f ) { + if constexpr (N+1 == get_field_count()) + return f(get_field(std::forward(t))); + else { + f(get_field(std::forward(t))); + return for_each_field_impl(std::forward(t), std::forward(f)); + } + } + template + constexpr inline static void for_each_field( T&& t, F&& f ) { + if constexpr (get_field_count() == 0) + return; + else + return for_each_field_impl<0>(t, f); + } + }; + + template + struct meta_object : meta_object_base> { + using base_t = meta_object_base>; + using base_t::name; + using base_t::get_name; + using base_t::for_each_field; + using base_t::get_field_count; + using base_t::get_field_name; + using base_t::get_field_names; + + using field_types = decltype(detail::which_field_types()); + template + using field_type = std::tuple_element_t; + constexpr static inline std::size_t field_count = detail::fields_size(); + constexpr static auto field_names = C::_bluegrass_meta_refl_field_names(); + + template + constexpr static inline auto& get_field(T&& t) { + static_assert(std::is_same_v, C>, "get_field(T), T should be the same type as C"); + using type = std::tuple_element_t; + return *reinterpret_cast(t.template _bluegrass_meta_refl_field_ptr()); + } + + template + constexpr static inline auto& get_field(const T& t) { + static_assert(std::is_same_v, C>, "get_field(T), T should be the same type as C"); + using type = std::tuple_element_t; + return *reinterpret_cast(t.template _bluegrass_meta_refl_field_ptr()); + } + }; + +}} // ns bluegrass::meta + +#define BLUEGRASS_META_ADDRESS( ignore, FIELD ) (void*)&FIELD +#define BLUEGRASS_META_DECLTYPE( ignore, FIELD ) decltype(FIELD) +#define BLUEGRASS_META_PASS_STR( ignore, X ) #X + +#define BLUEGRASS_META_VA_ARGS_SIZE(...) \ + bluegrass::meta::detail::va_args_count_helper( \ + BLUEGRASS_META_FOREACH( \ + BLUEGRASS_META_PASS_STR, "ignored", ##__VA_ARGS__)) + +#define BLUEGRASS_META_REFL(...) \ + constexpr void _bluegrass_meta_refl_valid(); \ + void _bluegrass_meta_refl_fields \ + ( BLUEGRASS_META_FOREACH(BLUEGRASS_META_DECLTYPE, "ignored", ##__VA_ARGS__) ){} \ + inline auto _bluegrass_meta_refl_field_ptrs() const { \ + return std::array{ \ + BLUEGRASS_META_FOREACH(BLUEGRASS_META_ADDRESS, "ignored", ##__VA_ARGS__)}; \ + } \ + template \ + inline void* _bluegrass_meta_refl_field_ptr() const { \ + return _bluegrass_meta_refl_field_ptrs()[N]; \ + } \ + constexpr inline static auto _bluegrass_meta_refl_field_names() { \ + return std::array { \ + BLUEGRASS_META_FOREACH(BLUEGRASS_META_PASS_STR, "ignored", ##__VA_ARGS__) \ + }; \ + } + +// EXPERIMENTAL macro to produce meta_object specializations for homogeneous structures +#define BLUEGRASS_HOM_META(_C, _FT, ...) \ + namespace bluegrass { namespace meta { \ + template <__VA_ARGS__> \ + struct meta_object<_C> : meta_object_base<_C, meta_object<_C>> { \ + using base_t = meta_object_base<_C, meta_object<_C>>; \ + using base_t::name; \ + using base_t::field_names; \ + using base_t::get_name; \ + using base_t::for_each_field; \ + using base_t::get_field_count; \ + using base_t::get_field_name; \ + using base_t::get_field_names; \ + constexpr static inline std::size_t field_count = sizeof(_C) / sizeof(_FT); \ + using field_types = decltype(detail::homogeneous_field_types()); \ + template \ + using field_type = std::tuple_element_t<_N, field_types>; \ + template \ + constexpr static inline auto& get_field(_C& t) { \ + /* very gross and bad code is about to follow */ \ + return *(reinterpret_cast<_FT*>(&t)+_N); \ + } \ + }; \ + }} diff --git a/include/bluegrass/meta/utility.hpp b/include/bluegrass/meta/utility.hpp new file mode 100644 index 0000000..fc908df --- /dev/null +++ b/include/bluegrass/meta/utility.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include +#include + +namespace bluegrass { namespace meta { + // helpers for std::visit + template + struct overloaded : Ts... { + using Ts::operator()...; + }; + template + overloaded(Ts...)->overloaded; + + template + struct ct_string { + constexpr static const char value[] = {Str..., '\0'}; + constexpr static std::size_t size = sizeof...(Str)+1; + }; + + namespace detail { + template + struct ct_string_appender; + template class CTS, char... Str> + struct ct_string_appender> { + using type = ct_string; + }; + template + struct ct_string_reverser; + template class O, char C> + struct ct_string_reverser> { + using type = typename ct_string_appender::type; + }; + template class O, char C, char... Rest> + struct ct_string_reverser> { + using type = typename ct_string_reverser::type, ct_string>::type; + }; + template + struct trim_front; + template