##なにこれ 次世代の代数的データ型!plasma.ADTここに極めり!
##極まってないだろ はい。
##使い方 main.cppを読めばわかる。
##注意 今回メモ化バージョンを搭載しておりません。
| #pragma once | |
| // Copyright plasma-effect 2015 | |
| // Distributed under the Boost Software License, Version 1.0. | |
| // (See http://www.boost.org/LICENSE_1_0.txt) | |
| #include<tuple> | |
| #include<utility> | |
| #include<memory> | |
| #include<type_traits> | |
| #include<stdexcept> | |
| #include<typeindex> | |
| #include<boost/variant.hpp> | |
| #include<boost/optional.hpp> | |
| #ifdef _MSC_VER | |
| #define PLASMA_ADT_WILLING_TEMPLATE | |
| #else | |
| #define PLASMA_ADT_WILLING_TEMPLATE template | |
| #endif | |
| namespace adt_willing | |
| { | |
| namespace detail | |
| { | |
| template<class T>struct tuple_transmission | |
| { | |
| typedef std::tuple<T> type; | |
| }; | |
| template<class... Ts>struct tuple_transmission<std::tuple<Ts...>> | |
| { | |
| typedef std::tuple<Ts...> type; | |
| }; | |
| template<>struct tuple_transmission<void> | |
| { | |
| typedef std::tuple<> type; | |
| }; | |
| template<class T>using tuple_transmission_t = typename tuple_transmission<T>::type; | |
| template<class... Ts>using tuple_cat_t = decltype(std::tuple_cat(std::declval<Ts>()...)); | |
| template<class T>struct type_tag | |
| { | |
| typedef T type; | |
| }; | |
| template<int I, class T>struct id_tag | |
| { | |
| typedef T type; | |
| }; | |
| template<int I, class T>using id_tag_t = typename id_tag<I, T>::type; | |
| template<std::size_t Id, class... Ts>struct structure_data {}; | |
| template<class T>struct pattern_instance_tag {}; | |
| struct void_t {}; | |
| template<std::size_t I, class Tuple>constexpr auto get(Tuple const& t, std::enable_if_t<(std::tuple_size<Tuple>::value > I)>* = nullptr) | |
| { | |
| return std::get<I>(t); | |
| } | |
| template<std::size_t I, class Tuple>constexpr auto get(Tuple const&, std::enable_if_t<(std::tuple_size<Tuple>::value <= I)>* = nullptr) | |
| { | |
| return void_t(); | |
| } | |
| constexpr auto select_value(void_t, void_t) | |
| { | |
| return void_t(); | |
| } | |
| template<class T>constexpr auto select_value(void_t, T const& v)->std::enable_if_t<!std::is_same<T, void_t>::value, T> | |
| { | |
| return v; | |
| } | |
| template<class T>constexpr auto select_value(T const& v, void_t)->std::enable_if_t<!std::is_same<T, void_t>::value, T> | |
| { | |
| return v; | |
| } | |
| template<class T, class U>constexpr auto select_value(T const&, U const&) | |
| { | |
| static_assert(std::is_same<T, void_t>::value || std::is_same<U, void_t>::value, "pattern_match conflict"); | |
| return 0; | |
| } | |
| template<class IndexSequence>struct tuple_merge_i; | |
| template<std::size_t... Is>struct tuple_merge_i<std::index_sequence<Is...>> | |
| { | |
| template<class T, class U>static constexpr auto run(T const& t, U const& u) | |
| { | |
| return std::make_tuple(select_value(detail::get<Is>(t), detail::get<Is>(u))...); | |
| } | |
| }; | |
| template<class T, class U>constexpr auto tuple_merge(T const& t, U const& u) | |
| { | |
| return tuple_merge_i<std::make_index_sequence<std::max(std::tuple_size<T>::value, std::tuple_size<U>::value)>>::run(t, u); | |
| } | |
| template<class T>auto optional_merge(boost::none_t, boost::optional<T>const&) | |
| { | |
| return boost::none; | |
| } | |
| template<class U>auto optional_merge(boost::optional<U>const&, boost::none_t) | |
| { | |
| return boost::none; | |
| } | |
| template<class T, class U>auto optional_merge(boost::optional<T>const& t, boost::optional<U>const& u) | |
| { | |
| if(t&&u) | |
| return boost::make_optional(tuple_merge(*t, *u)); | |
| return static_cast<decltype(boost::make_optional(tuple_merge(*t, *u)))>(boost::none); | |
| } | |
| template<class T, class... Ts>auto optional_merge(T const& t, Ts const&... ts) | |
| { | |
| return optional_merge(t, optional_merge(ts...)); | |
| } | |
| template<class IndexSequence>struct make_one_tuple_i; | |
| template<std::size_t... Is>struct make_one_tuple_i<std::index_sequence<Is...>> | |
| { | |
| template<class T>static constexpr auto run(T const& v) | |
| { | |
| return std::make_tuple(id_tag_t<Is, void_t>()..., v); | |
| } | |
| }; | |
| template<std::size_t I, class T>constexpr auto make_one_tuple(T const& v) | |
| { | |
| return make_one_tuple_i<std::make_index_sequence<I>>::run(v); | |
| } | |
| template<class... Ts>struct true_optional; | |
| template<class... Ts>struct true_optional<boost::none_t, Ts...> :true_optional<Ts...> {}; | |
| template<class T, class... Ts>struct true_optional<T, Ts...> | |
| { | |
| typedef T type; | |
| }; | |
| template<>struct true_optional<> | |
| { | |
| typedef boost::none_t type; | |
| }; | |
| template<class... Ts>using true_optional_t = typename true_optional<Ts...>::type; | |
| template<class IndexSequence>struct tuple_call_i; | |
| template<std::size_t... Is>struct tuple_call_i<std::index_sequence<Is...>> | |
| { | |
| template<class Tuple, class Func>static auto run(Func const& func, Tuple const& t) | |
| { | |
| return func(std::get<Is>(t)...); | |
| } | |
| }; | |
| template<class Tuple, class Func>auto tuple_call(Func func, Tuple const& t) | |
| { | |
| return tuple_call_i<std::make_index_sequence<std::tuple_size<Tuple>::value>>::run(func, t); | |
| } | |
| struct pattern_tag {}; | |
| } | |
| namespace place_holder | |
| { | |
| template<int V, int I, int... Is>struct value_t :value_t<10 * V + I, Is...> {}; | |
| template<int V, int I>struct value_t<V, I> :std::integral_constant<int, 10 * V + I> {}; | |
| template<int Id>struct place_holder_t :detail::pattern_tag | |
| { | |
| template<class Func>struct pattern_match_t | |
| { | |
| Func func; | |
| template<class ReturnType, class T, class... Ts>auto normal_call(detail::type_tag<ReturnType>, T const& v, Ts const&... args)const | |
| { | |
| auto d = v.get_data(place_holder_t<0>()); | |
| if (d) | |
| { | |
| return boost::make_optional(detail::tuple_call(func, std::tuple_cat(*d, std::make_tuple(std::cref(args)...)))); | |
| } | |
| return static_cast<decltype(boost::make_optional(detail::tuple_call(func, std::tuple_cat(*d, std::make_tuple(std::cref(args)...)))))>(boost::none); | |
| } | |
| template<class ReturnType,class T, class Recursion, class... Ts>auto recursion_call(detail::type_tag<ReturnType>, Recursion recur, T const& v, Ts const&... args)const | |
| { | |
| auto d = v.get_data(place_holder_t<0>()); | |
| if (d) | |
| { | |
| return boost::make_optional(detail::tuple_call(func, std::tuple_cat(std::make_tuple(recur), *d, std::make_tuple(std::cref(args)...)))); | |
| } | |
| return static_cast<decltype(boost::make_optional(detail::tuple_call(func, std::tuple_cat(std::make_tuple(recur), *d, std::make_tuple(std::cref(args)...)))))>(boost::none); | |
| } | |
| }; | |
| template<class Func>auto operator<=(Func const& func)const | |
| { | |
| return pattern_match_t<Func>{func}; | |
| } | |
| }; | |
| template<char... Cs>constexpr auto operator"" _() | |
| { | |
| return place_holder_t<value_t<0, (Cs - '0')...>::value>(); | |
| } | |
| } | |
| template<class T>struct get_structure | |
| { | |
| typedef typename T::structure type; | |
| }; | |
| template<int I>struct get_structure<place_holder::place_holder_t<I>> | |
| { | |
| typedef place_holder::place_holder_t<I> type; | |
| }; | |
| template<int I>struct get_structure<place_holder::place_holder_t<I> const&> | |
| { | |
| typedef place_holder::place_holder_t<I> type; | |
| }; | |
| template<class T>using get_structure_t = typename get_structure<T>::type; | |
| struct recursion_tag {}; | |
| template<class... Types>struct data_type | |
| { | |
| typedef data_type<Types...> this_type; | |
| typedef std::tuple<detail::tuple_transmission_t<Types>...> template_parameter; | |
| template<std::size_t Id>using parameter_t = std::tuple_element_t<Id, template_parameter>; | |
| template<class IndexSequence>struct container_t; | |
| typedef container_t<std::make_index_sequence<sizeof...(Types)>> container; | |
| typedef std::shared_ptr<container> ptr_type; | |
| ptr_type ptr_; | |
| template<class T, class = void>struct value_data | |
| { | |
| typedef T value_type; | |
| T value_; | |
| value_data(value_type const& v) :value_(v) {} | |
| value_data(value_data const&) = default; | |
| value_data(value_data&&) = default; | |
| value_data& operator=(value_data const&) = default; | |
| value_data& operator=(value_data&&) = default; | |
| ~value_data() = default; | |
| operator value_type const&()const | |
| { | |
| return value_; | |
| } | |
| bool operator==(value_data<T>const& rhs)const | |
| { | |
| return value_ == rhs.value_; | |
| } | |
| template<int I>auto get_data(place_holder::place_holder_t<I>)const | |
| { | |
| return boost::make_optional(detail::make_one_tuple<I>(value_)); | |
| } | |
| }; | |
| template<class T>struct value_data<T, std::enable_if_t<std::is_same<T, recursion_tag>::value>> | |
| { | |
| typedef this_type value_type; | |
| ptr_type value_; | |
| value_data(value_type const& v) :value_(v.ptr_) {} | |
| value_data(value_data const&) = default; | |
| value_data(value_data&&) = default; | |
| value_data& operator=(value_data const&) = default; | |
| value_data& operator=(value_data&&) = default; | |
| ~value_data() = default; | |
| operator value_type const&()const | |
| { | |
| return this_type(value_); | |
| } | |
| bool operator==(value_data<T>const& rhs)const | |
| { | |
| return *value_ == *(rhs.value_); | |
| } | |
| template<class Structure>auto get_data(Structure)const | |
| { | |
| return this_type(value_).get_data(Structure()); | |
| } | |
| }; | |
| template<class T>using value_type = typename value_data<T>::value_type; | |
| template<std::size_t Id, class Tuple>struct inside_data; | |
| template<std::size_t Id, class... Ts>struct inside_data<Id, std::tuple<Ts...>> | |
| { | |
| std::tuple<value_data<Ts>...> value_; | |
| inside_data(value_type<Ts>const&... args) :value_(args...) {} | |
| inside_data(inside_data const&) = default; | |
| inside_data(inside_data&&) = default; | |
| inside_data& operator=(inside_data const&) = default; | |
| inside_data& operator=(inside_data&&) = default; | |
| ~inside_data() = default; | |
| bool operator==(inside_data<Id, std::tuple<Ts...>>const& rhs)const | |
| { | |
| return value_ == rhs.value_; | |
| } | |
| template<class IndexSequence>struct get_data_i; | |
| template<std::size_t... Is>struct get_data_i<std::index_sequence<Is...>> | |
| { | |
| template<class T, std::size_t I>static auto run(T const&, detail::structure_data<I>) | |
| { | |
| return boost::make_optional(std::tuple<>()); | |
| } | |
| template<class T, std::size_t I, class... Us>static auto run(T const& t, detail::structure_data<I, Us...>, std::enable_if_t<sizeof...(Us) != 0>* = nullptr) | |
| { | |
| return detail::optional_merge(std::get<Is>(t).get_data(Us())...); | |
| } | |
| }; | |
| template<std::size_t I, class... Us>auto get_data(detail::structure_data<I, Us...>, std::enable_if_t<(static_cast<std::size_t>(I) == Id) && (sizeof...(Ts) == sizeof...(Us))>* = nullptr)const | |
| { | |
| return get_data_i<std::make_index_sequence<sizeof...(Us)>>::run(value_, detail::structure_data<I, Us...>()); | |
| } | |
| template<std::size_t I, class... Us>auto get_data(detail::structure_data<I, Us...>, std::enable_if_t<(static_cast<std::size_t>(I) != Id) || (sizeof...(Ts) != sizeof...(Us))>* = nullptr)const | |
| { | |
| return boost::none; | |
| } | |
| }; | |
| template<std::size_t Id>using inside_data_t = inside_data<Id, parameter_t<Id>>; | |
| template<std::size_t... Is>struct container_t<std::index_sequence<Is...>> | |
| { | |
| boost::variant<inside_data_t<Is>...> value_; | |
| template<std::size_t Id>container_t(inside_data_t<Id> v) :value_(v) {} | |
| container_t(container_t const&) = default; | |
| container_t(container_t&&) = default; | |
| container_t& operator=(container_t const&) = default; | |
| container_t& operator=(container_t&&) = default; | |
| ~container_t() = default; | |
| bool operator==(container_t<std::index_sequence<Is...>>const& rhs)const | |
| { | |
| return value_ == rhs.value_; | |
| } | |
| template<class Structure>auto get_data(Structure)const | |
| { | |
| typedef detail::true_optional_t<decltype(std::declval<inside_data_t<Is>>().PLASMA_ADT_WILLING_TEMPLATE get_data(std::declval<Structure>()))...> return_type; | |
| return boost::apply_visitor([](auto const& v) {return static_cast<return_type>(v.PLASMA_ADT_WILLING_TEMPLATE get_data(Structure()));}, value_); | |
| } | |
| }; | |
| bool operator==(this_type const& rhs)const | |
| { | |
| return *ptr_ == *rhs.ptr_; | |
| } | |
| template<int I>auto get_data(place_holder::place_holder_t<I>)const | |
| { | |
| return boost::make_optional(detail::make_one_tuple<I>(*this)); | |
| } | |
| template<class Structure>auto get_data(Structure)const | |
| { | |
| return ptr_->get_data(Structure()); | |
| } | |
| template<class T>struct instance_t; | |
| template<std::size_t Id, class... Ts>struct instance_t<inside_data<Id, std::tuple<Ts...>>> :detail::pattern_tag | |
| { | |
| this_type operator()(value_type<Ts>const&... args)const | |
| { | |
| return this_type(std::make_shared<container>(inside_data_t<Id>(args...))); | |
| } | |
| typedef detail::structure_data<Id> structure; | |
| template<class... Us>struct pattern_t :detail::pattern_tag | |
| { | |
| typedef detail::structure_data<Id, get_structure_t<Us>...> structure; | |
| template<class Func>struct pattern_match_t | |
| { | |
| Func func; | |
| template<class ReturnType, class... Cs>auto normal_call(detail::type_tag<ReturnType>, this_type const& v, Cs const&... args)const | |
| { | |
| auto d = v.get_data(structure()); | |
| if (d) | |
| { | |
| return boost::make_optional(detail::tuple_call(func, std::tuple_cat(*d, std::make_tuple(std::cref(args)...)))); | |
| } | |
| return static_cast<decltype(boost::make_optional(detail::tuple_call(func, std::tuple_cat(*d, std::make_tuple(std::cref(args)...)))))>(boost::none); | |
| } | |
| template<class ReturnType, class Recursion, class... Cs>auto recursion_call(detail::type_tag<ReturnType>, Recursion recur, this_type const& v, Cs const&... args)const | |
| { | |
| auto d = v.get_data(structure()); | |
| if (d) | |
| { | |
| return boost::make_optional(detail::tuple_call(func, std::tuple_cat(std::make_tuple(recur), *d, std::make_tuple(std::cref(args)...)))); | |
| } | |
| return static_cast<decltype(boost::make_optional(detail::tuple_call(func, std::tuple_cat(std::make_tuple(recur), *d, std::make_tuple(std::cref(args)...)))))>(boost::none); | |
| } | |
| }; | |
| template<class Func>auto operator<=(Func func)const | |
| { | |
| return pattern_match_t<Func>{func}; | |
| } | |
| }; | |
| template<class U, class... Us>std::enable_if_t<std::is_base_of<detail::pattern_tag,U>::value, pattern_t<U, Us...>> operator()(U const&, Us const&...)const | |
| { | |
| return pattern_t<U, Us...>(); | |
| } | |
| template<class Func>struct pattern_match_t | |
| { | |
| Func func; | |
| template<class ReturnType, class... Cs>auto normal_call(detail::type_tag<ReturnType>, this_type const& v, Cs const&... args)const | |
| { | |
| if (v.ptr_->value_.which() == Id) | |
| { | |
| return boost::make_optional(detail::tuple_call(func, std::make_tuple(std::cref(args)...))); | |
| } | |
| return static_cast<decltype(boost::make_optional(detail::tuple_call(func, std::make_tuple(std::cref(args)...))))>(boost::none); | |
| } | |
| template<class ReturnType, class Recursion, class... Cs>auto recursion_call(detail::type_tag<ReturnType>, Recursion recur, this_type const& v, Cs const&... args)const | |
| { | |
| if (v.ptr_->value_.which() == Id) | |
| { | |
| return boost::make_optional(detail::tuple_call(func, std::tuple_cat(std::make_tuple(recur), std::make_tuple(std::cref(args)...)))); | |
| } | |
| return static_cast<decltype(boost::make_optional(detail::tuple_call(func, std::tuple_cat(std::make_tuple(recur), std::make_tuple(std::cref(args)...)))))>(boost::none); | |
| } | |
| }; | |
| template<class Func>auto operator<=(Func const& func)const | |
| { | |
| return pattern_match_t<Func>{func}; | |
| } | |
| }; | |
| template<std::size_t Id>static auto get_instance_function() | |
| { | |
| return instance_t<inside_data_t<Id>>(); | |
| } | |
| data_type(ptr_type const& ptr) :ptr_(ptr) {} | |
| data_type(data_type const&) = default; | |
| data_type(data_type&&) = default; | |
| data_type& operator=(data_type const&) = default; | |
| data_type& operator=(data_type&&) = default; | |
| ~data_type() = default; | |
| }; | |
| class no_hit_exception :public std::logic_error | |
| { | |
| public: | |
| std::type_index index; | |
| no_hit_exception(std::type_index in) :std::logic_error("pattern match error"), index(in) {} | |
| }; | |
| template<class ReturnType>struct make_pattern_match_t | |
| { | |
| template<class... PatternInstances>struct pattern_match_instance_t | |
| { | |
| std::tuple<PatternInstances...> pis; | |
| template<std::size_t I, class T, class... Ts>std::enable_if_t<(I + 1 != sizeof...(PatternInstances)), ReturnType> run(T const& data, Ts const&...args)const | |
| { | |
| if (auto d = std::get<I>(pis).normal_call(detail::type_tag<ReturnType>(), data, args...)) | |
| { | |
| return *d; | |
| } | |
| return run<I + 1>(data, args...); | |
| } | |
| template<std::size_t I, class T, class... Ts>std::enable_if_t<(I + 1 == sizeof...(PatternInstances)), ReturnType> run(T const& data, Ts const&...args)const | |
| { | |
| if (auto d = std::get<I>(pis).normal_call(detail::type_tag<ReturnType>(), data, args...)) | |
| { | |
| return *d; | |
| } | |
| throw no_hit_exception(typeid(*this)); | |
| } | |
| template<class T, class... Ts>ReturnType operator()(T const& data, Ts const&... args)const | |
| { | |
| return run<0>(data, args...); | |
| } | |
| template<class Instance>auto operator|(Instance const& instance)const | |
| { | |
| return pattern_match_instance_t<PatternInstances..., Instance>{std::tuple_cat(pis, std::make_tuple(instance))}; | |
| } | |
| }; | |
| template<class Instance>auto operator|(Instance const& instance)const | |
| { | |
| return pattern_match_instance_t<Instance>{std::make_tuple(instance)}; | |
| } | |
| }; | |
| template<class ReturnType>auto pattern_match() | |
| { | |
| return make_pattern_match_t<ReturnType>(); | |
| } | |
| template<class ReturnType>struct make_recursion_match_t | |
| { | |
| template<class... PatternInstances>struct pattern_match_instance_t | |
| { | |
| std::tuple<PatternInstances...> pis; | |
| template<std::size_t I, class T, class... Ts>std::enable_if_t<(I + 1 != sizeof...(PatternInstances)), ReturnType> run(T const& data, Ts const&...args)const | |
| { | |
| if (auto d = std::get<I>(pis).recursion_call(detail::type_tag<ReturnType>(),std::cref(*this), data, args...)) | |
| { | |
| return *d; | |
| } | |
| return run<I + 1>(data, args...); | |
| } | |
| template<std::size_t I, class T, class... Ts>std::enable_if_t<(I + 1 == sizeof...(PatternInstances)), ReturnType> run(T const& data, Ts const&...args)const | |
| { | |
| if (auto d = std::get<I>(pis).recursion_call(detail::type_tag<ReturnType>(), std::cref(*this), data, args...)) | |
| { | |
| return *d; | |
| } | |
| throw no_hit_exception(typeid(*this)); | |
| } | |
| template<class T, class... Ts>ReturnType operator()(T const& data, Ts const&... args)const | |
| { | |
| return run<0>(data, args...); | |
| } | |
| template<class Instance>auto operator|(Instance const& instance)const | |
| { | |
| return pattern_match_instance_t<PatternInstances..., Instance>{std::tuple_cat(pis, std::make_tuple(instance))}; | |
| } | |
| }; | |
| template<class Instance>auto operator|(Instance const& instance)const | |
| { | |
| return pattern_match_instance_t<Instance>{std::make_tuple(instance)}; | |
| } | |
| }; | |
| template<class ReturnType>auto recursion_match() | |
| { | |
| return make_recursion_match_t<ReturnType>(); | |
| } | |
| } |
| #include"adt_willing.hpp" | |
| #include<iostream> | |
| using namespace adt_willing; | |
| using namespace place_holder; | |
| typedef data_type<void, std::tuple<int, recursion_tag>> type; | |
| const auto Nil = type::get_instance_function<0>(); | |
| const auto Tree = type::get_instance_function<1>(); | |
| int main() | |
| { | |
| const auto func = recursion_match<int>() | |
| | Tree(0_, Tree(1_, 2_)) <= [](auto f, int x, int y, type t) {return x + y + f(t);} | |
| | Tree(0_, Nil) <= [](auto, int x) {return x;} | |
| | Nil <= [](auto) {return 0;};; | |
| std::cout << func(Tree(1, Tree(2, Nil()))) << std::endl; | |
| std::cout << func(Tree(1, Nil())) << std::endl; | |
| } |
##なにこれ 次世代の代数的データ型!plasma.ADTここに極めり!
##極まってないだろ はい。
##使い方 main.cppを読めばわかる。
##注意 今回メモ化バージョンを搭載しておりません。