156 lines
4.6 KiB
C++
156 lines
4.6 KiB
C++
/**
|
|
rjp++
|
|
Copyright (C) 2020 rexy712
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef RJP_DISPATCH_HPP
|
|
#define RJP_DISPATCH_HPP
|
|
|
|
#include "rjp_internal.hpp"
|
|
#include <type_traits> //is_same, true_type, false_type
|
|
#include <utility> //forward
|
|
#include <exception>
|
|
|
|
namespace rjp{
|
|
|
|
class missing_dispatch_handler : public std::exception
|
|
{
|
|
public:
|
|
const char* what(void)const noexcept override{
|
|
return "Argument not handled in rjp::dispatch";
|
|
}
|
|
};
|
|
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 T, class Param>
|
|
struct has_operator_for{
|
|
template<class U, class = decltype(std::declval<U>()(std::declval<Param>()))>
|
|
static std::true_type check(U*);
|
|
static std::false_type check(...);
|
|
|
|
static constexpr bool value = std::is_same<std::true_type,decltype(check((void*)0))>::value;
|
|
};
|
|
template<class Param, class T, class... Ts>
|
|
struct has_operator_for_any{
|
|
static constexpr bool value = has_operator_for<T, Param>::value || has_operator_for_any<Param,Ts...>::value;
|
|
};
|
|
template<class Param, class T>
|
|
struct has_operator_for_any<Param,T>{
|
|
static constexpr bool value = has_operator_for<T,Param>::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));
|
|
}
|
|
throw missing_dispatch_handler{}; //deals with -Wreturn-type warnings
|
|
}
|
|
}
|
|
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<typename std::enable_if<!detail::has_operator_for_any<const value&,Ts...>::value,void>::type* = nullptr>
|
|
decltype(auto) operator()(const value&)const{}
|
|
};
|
|
|
|
template<class... Ts>
|
|
dispatcher(Ts&&...) -> dispatcher<Ts...>;
|
|
}
|
|
|
|
#endif
|