rjp/rjp++/include/dispatch.hpp

109 lines
2.9 KiB
C++

#ifndef RJP_DISPATCH_HPP
#define RJP_DISPATCH_HPP
#include "rjp_internal.hpp"
#include <type_traits> //is_same, true_type, false_type
#include <utility> //forward
namespace rjp{
namespace detail{
template<RJP_data_type T>
struct to_value_type;
template<>
struct to_value_type<rjp_json_object>{
using type = rjp::object;
};
template<>
struct to_value_type<rjp_json_string>{
using type = rjp::string_val;
};
template<>
struct to_value_type<rjp_json_integer>{
using type = rjp::integer;
};
template<>
struct to_value_type<rjp_json_dfloat>{
using type = rjp::dfloat;
};
template<>
struct to_value_type<rjp_json_boolean>{
using type = rjp::boolean;
};
template<>
struct to_value_type<rjp_json_array>{
using type = rjp::array;
};
template<>
struct to_value_type<rjp_json_null>{
using type = rjp::null;
};
template<RJP_data_type T>
using to_value_type_t = typename to_value_type<T>::type;
template<RJP_data_type T>
struct next_data_type;
template<>
struct next_data_type<rjp_json_object>{
static constexpr RJP_data_type value = rjp_json_string;
};
template<>
struct next_data_type<rjp_json_string>{
static constexpr RJP_data_type value = rjp_json_integer;
};
template<>
struct next_data_type<rjp_json_integer>{
static constexpr RJP_data_type value = rjp_json_dfloat;
};
template<>
struct next_data_type<rjp_json_dfloat>{
static constexpr RJP_data_type value = rjp_json_boolean;
};
template<>
struct next_data_type<rjp_json_boolean>{
static constexpr RJP_data_type value = rjp_json_array;
};
template<>
struct next_data_type<rjp_json_array>{
static constexpr RJP_data_type value = rjp_json_null;
};
template<RJP_data_type T>
struct has_next_data_type_helper{
template<class U, bool = (sizeof(U) == sizeof(U))>
static std::true_type check(U*);
static std::false_type check(...);
static constexpr bool value = std::is_same<std::true_type,decltype(check((next_data_type<T>*)0))>::value;
};
template<RJP_data_type T>
struct has_next_data_type{
static constexpr bool value = has_next_data_type_helper<T>::value;
};
template<class Func, class Val, RJP_data_type T>
decltype(auto) dispatch_helper(Func&& fun, Val&& v){
if(v.type() == T){
return std::forward<Func>(fun)(static_cast<detail::to_value_type_t<T>>(std::forward<Val>(v)));
}
if constexpr(detail::has_next_data_type<T>::value){
return dispatch_helper<Func,Val,detail::next_data_type<T>::value>(std::forward<Func>(fun), std::forward<Val>(v));
}
}
}
template<class Func, class Val>
decltype(auto) dispatch(Func&& fun, Val&& v){
return detail::dispatch_helper<Func,Val,rjp_json_object>(std::forward<Func>(fun), std::forward<Val>(v));
}
template<class... Ts>
struct dispatcher : public Ts...
{
using Ts::operator()...;
};
template<class... Ts>
dispatcher(Ts&&...) -> dispatcher<Ts...>;
}
#endif