Skip to content

Instantly share code, notes, and snippets.

@plasma-effect
Last active December 9, 2015 15:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save plasma-effect/23a334c044e99f3d8ac0 to your computer and use it in GitHub Desktop.
Save plasma-effect/23a334c044e99f3d8ac0 to your computer and use it in GitHub Desktop.
plasma.ADT willing
#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を読めばわかる。

##注意 今回メモ化バージョンを搭載しておりません。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment