Skip to content

Instantly share code, notes, and snippets.

@plasma-effect
Last active September 28, 2016 12:52
Show Gist options
  • Save plasma-effect/b248e47c987468abebda to your computer and use it in GitHub Desktop.
Save plasma-effect/b248e47c987468abebda to your computer and use it in GitHub Desktop.
plasma.Coroutine
#pragma once
// Copyright plasma-effect 2016.
// Distributed under the Boost Software License, Version 1.0.
// (See http://www.boost.org/LICENSE_1_0.txt)
#include<utility>
#include<tuple>
#include<iterator>
#include<array>
#include<type_traits>
#include<typeinfo>
#include<iostream>
#include<boost/optional.hpp>
#include<boost/variant.hpp>
#include<boost/logic/tribool.hpp>
#ifndef __CLANG_STDINT_H
#define PLASMA_COROUTINE_TEMPLATE
#else
#define PLASMA_COROUTINE_TEMPLATE template
#endif
namespace coroutine
{
namespace enumerable
{
template<class Derived>struct enumerator
{
struct iterator :std::iterator<std::input_iterator_tag, decltype(*std::declval<Derived>())>
{
boost::optional<Derived> etor;
iterator(Derived const& e) :etor(e)
{
operator++();
}
iterator() = default;
iterator(iterator&&) = default;
iterator(iterator const&) = default;
iterator& operator=(iterator&&) = default;
iterator& operator=(iterator const&) = default;
~iterator() = default;
iterator& operator++()
{
if (etor)
{
if (!(++(*etor)))
etor = boost::none;
}
return *this;
}
iterator operator++(int)
{
auto ret = *this;
operator++();
return ret;
}
bool operator!=(iterator const& rhs)const
{
return static_cast<bool>(etor) != static_cast<bool>(rhs.etor);
}
bool operator==(iterator const& rhs)const
{
return static_cast<bool>(etor) == static_cast<bool>(rhs.etor);
}
decltype(auto) operator*()const
{
return **etor;
}
};
iterator begin()const
{
return iterator(static_cast<const Derived&>(*this));
}
iterator end()const
{
return iterator();
}
};
}
namespace constant_map
{
struct end_node_t {};
template<std::size_t Index, class T, class Lhs, class Rhs>struct map
{
Lhs lhs_;
Rhs rhs_;
T val_;
};
template<std::size_t Index, class T>constexpr map<Index, T, end_node_t, end_node_t> make_first_node(T const& v)
{
return map<Index, T, end_node_t, end_node_t>{end_node_t{}, end_node_t{}, v};
}
template<std::size_t Index, class T>constexpr map<Index, T, end_node_t, end_node_t> make_first_node(T&& v)
{
return map<Index, T, end_node_t, end_node_t>{end_node_t{}, end_node_t{}, std::move(v)};
}
template<std::size_t I, std::size_t Index, class T, class Lhs, class Rhs>constexpr auto get(map<Index, T, Lhs, Rhs> const& m, typename std::enable_if<(I<Index)>::type* = nullptr)
{
return get<I>(m.lhs_);
}
template<std::size_t I, std::size_t Index, class T, class Lhs, class Rhs>constexpr auto get(map<Index, T, Lhs, Rhs> const& m, typename std::enable_if<(I>Index)>::type* = nullptr)
{
return get<I>(m.rhs_);
}
template<std::size_t I, std::size_t Index, class T, class Lhs, class Rhs>constexpr auto get(map<Index, T, Lhs, Rhs> const& m, typename std::enable_if<(I == Index)>::type* = nullptr)
{
return m.val_;
}
template<std::size_t I, std::size_t Index, class T, class Lhs, class Rhs>auto& get(map<Index, T, Lhs, Rhs>& m, typename std::enable_if<(I<Index)>::type* = nullptr)
{
return get<I>(m.lhs_);
}
template<std::size_t I, std::size_t Index, class T, class Lhs, class Rhs>auto& get(map<Index, T, Lhs, Rhs>& m, typename std::enable_if<(I>Index)>::type* = nullptr)
{
return get<I>(m.rhs_);
}
template<std::size_t I, std::size_t Index, class T, class Lhs, class Rhs>auto& get(map<Index, T, Lhs, Rhs>& m, typename std::enable_if<(I == Index)>::type* = nullptr)
{
return m.val_;
}
template<std::size_t I>constexpr void* get(end_node_t)
{
static_assert(I < 0, "this map don't have 'I' element");
return nullptr;
}
template<std::size_t I, class U>constexpr auto add(end_node_t, U&& v)
{
return make_first_node<I>(std::forward<U>(v));
}
template<std::size_t I, std::size_t Index, class T, class Lhs, class Rhs, class U>constexpr auto add(map<Index, T, Lhs, Rhs>const& m, U&& v, typename std::enable_if<(I<Index)>::type* = nullptr)
{
return map<Index, T, decltype(add<I>(m.lhs_, std::forward<U>(v))), Rhs>{add<I>(m.lhs_, std::forward<U>(v)), m.rhs_, m.val_};
}
template<std::size_t I, std::size_t Index, class T, class Lhs, class Rhs, class U>constexpr auto add(map<Index, T, Lhs, Rhs>const& m, U&& v, typename std::enable_if<(I>Index)>::type* = nullptr)
{
return map<Index, T, Lhs, decltype(add<I>(m.rhs_, std::forward<U>(v)))>{m.lhs_, add<I>(m.rhs_, std::forward<U>(v)), m.val_};
}
template<std::size_t I, std::size_t Index, class T, class Lhs, class Rhs, class U>constexpr auto add(map<Index, T, Lhs, Rhs>const& m, U const& v, typename std::enable_if<(I == Index)>::type* = nullptr)
{
return map<Index, U, Lhs, Rhs>{v, m.rhs_, m.val_};
}
template<std::size_t I, std::size_t Index, class T, class Lhs, class Rhs, class U>constexpr auto add(map<Index, T, Lhs, Rhs>const& m, U&& v, typename std::enable_if<(I == Index)>::type* = nullptr)
{
return map<Index, U, Lhs, Rhs>{std::move(v), m.rhs_, m.val_};
}
}
namespace type
{
template<class T>struct type_tag
{
typedef T type;
};
template<class T>type_tag<T> make_type_tag(T const&)
{
return type_tag<T>{};
}
template<class T>using remove_cr = std::remove_const_t<std::remove_reference_t<T>>;
template<class T>struct remove_const_refference
{
typedef typename std::remove_const<typename std::remove_reference<T>::type>::type type;
};
}
namespace sentence
{
struct sentence_tag {};
}
namespace expression
{
struct expression_tag {};
template<class Lhs, class Rhs>struct expression_assign :expression_tag
{
constexpr expression_assign(Lhs const& l, Rhs const& r) :lhs(l), rhs(r) {}
expression_assign(expression_assign&&) = default;
expression_assign(expression_assign const&) = default;
expression_assign& operator=(expression_assign&&) = default;
expression_assign& operator=(expression_assign const&) = default;
~expression_assign() = default;
Lhs lhs;
Rhs rhs;
template<class VariableMap, class ArgumentTuple>decltype(auto) operator()(VariableMap& variable, ArgumentTuple& argument)const
{
decltype(auto) a = lhs(variable, argument);
decltype(auto) b = rhs(variable, argument);
return a = b;
}
};
template<class T>struct constant_expression :expression_tag
{
constant_expression(T const& v) :val(v)
{
}
constant_expression(constant_expression&&) = default;
constant_expression(constant_expression const&) = default;
constant_expression& operator=(constant_expression&&) = default;
constant_expression& operator=(constant_expression const&) = default;
~constant_expression() = default;
T val;
template<class VariableMap, class ArgumentTuple>T operator()(VariableMap&, ArgumentTuple&)const
{
return val;
}
};
template<class Expression>constexpr auto make_expression(Expression const& expr, typename std::enable_if<std::is_base_of<expression_tag, Expression>::value>::type* = nullptr)
{
return expr;
}
template<class T>constexpr auto make_expression(T const& v, typename std::enable_if<!std::is_base_of<expression_tag, T>::value>::type* = nullptr)
{
return constant_expression<T>(v);
}
template<class Expr, class Index>struct index_access :expression_tag
{
Expr expr;
Index index;
index_access(Expr e, Index i) :expr(e), index(i) {}
index_access(index_access&&) = default;
index_access(index_access const&) = default;
index_access& operator=(index_access&&) = default;
index_access& operator=(index_access const&) = default;
~index_access() = default;
template<class VariableMap, class ArgumentTuple>decltype(auto)operator()(VariableMap& variable, ArgumentTuple& argument)const
{
return expr(variable, argument)[index(variable, argument)];
}
};
template<std::size_t Index>struct value :expression_tag
{
value() = default;
value(value&&) = default;
value(value const&) = default;
value& operator=(value&&) = default;
value& operator=(value const&) = default;
~value() = default;
template<class VariableMap, class ArgumentTuple>decltype(auto)operator()(VariableMap& variable, ArgumentTuple&)const
{
return constant_map::get<Index>(variable);
}
template<class Expression>auto operator=(Expression&& exp)const
{
return expression_assign<typename type::remove_const_refference<decltype(*this)>::type, decltype(make_expression(std::forward<Expression>(exp)))>(*this, make_expression(std::forward<Expression>(exp)));
}
template<class IndexT>auto operator[](IndexT index)const
{
return index_access<typename type::remove_const_refference<decltype(*this)>::type, decltype(make_expression(index))>(*this, make_expression(index));
}
};
template<std::size_t Index>struct argument :expression_tag
{
argument() = default;
argument(argument&&) = default;
argument(argument const&) = default;
argument& operator=(argument&&) = default;
argument& operator=(argument const&) = default;
~argument() = default;
template<class VariableMap, class ArgumentTuple>decltype(auto)operator()(VariableMap&, ArgumentTuple& argument)const
{
return std::get<Index>(argument);
}
template<class Expression>auto operator=(Expression&& exp)const
{
return expression_assign<typename type::remove_const_refference<decltype(*this)>::type, decltype(make_expression(std::forward<Expression>(exp)))>(*this, make_expression(std::forward<Expression>(exp)));
}
template<class IndexT>auto operator[](IndexT index)const
{
return index_access<typename type::remove_const_refference<decltype(*this)>::type, decltype(make_expression(index))>(*this, make_expression(index));
}
};
template<class Func, class ExpressionTuple, class IndexSequence>struct function_call;
template<class Func, class ExpressionTuple, std::size_t... Is>struct function_call<Func, ExpressionTuple, std::index_sequence<Is...>> :expression_tag
{
constexpr function_call(Func f, ExpressionTuple e) :func(f), exprs(e) {}
function_call(function_call&&) = default;
function_call(function_call const&) = default;
function_call& operator=(function_call&&) = default;
function_call& operator=(function_call const&) = default;
~function_call() = default;
Func func;
ExpressionTuple exprs;
template<class VariableMap,class ArgumentTuple>decltype(auto)
operator()(VariableMap& variable, ArgumentTuple& argument)const
{
return func(std::get<Is>(exprs)(variable, argument)...);
}
};
#define PLASMA_COROUTINE_MAKE_BIOPERATOR(op, name)\
template<class Lhs, class Rhs>struct name :expression_tag\
{\
constexpr name(Lhs const& l, Rhs const& r):lhs(l), rhs(r){}\
name(name &&) = default;\
name(name const&) = default;\
name& operator=(name &&) = default;\
name& operator=(name const&) = default;\
~name()=default;\
\
Lhs lhs;\
Rhs rhs;\
template<class VariableMap, class ArgumentTuple>decltype(auto) operator()(VariableMap& variable, ArgumentTuple& argument)const\
{\
return lhs(variable, argument) op rhs(variable, argument);\
}\
template<class Index>auto operator[](Index index)const\
{\
return index_access<typename type::remove_const_refference<decltype(*this)>::type, decltype(make_expression(index))>(*this, make_expression(index));\
}\
};\
template<class Lhs,class Rhs>constexpr auto operator op(Lhs const& lhs, Rhs const& rhs)\
->typename std::enable_if<!std::is_base_of<sentence::sentence_tag, Lhs>::value,name<decltype(make_expression(lhs)), decltype(make_expression(rhs))>>::type \
{\
return name<decltype(make_expression(lhs)), decltype(make_expression(rhs))>(make_expression(lhs), make_expression(rhs));\
}
PLASMA_COROUTINE_MAKE_BIOPERATOR(+, expression_add);
PLASMA_COROUTINE_MAKE_BIOPERATOR(-, expression_sub);
PLASMA_COROUTINE_MAKE_BIOPERATOR(*, expression_mul);
PLASMA_COROUTINE_MAKE_BIOPERATOR(/, expression_div);
PLASMA_COROUTINE_MAKE_BIOPERATOR(%, expression_mod);
PLASMA_COROUTINE_MAKE_BIOPERATOR(!=, expression_not_equal);
PLASMA_COROUTINE_MAKE_BIOPERATOR(==, expression_equal);
PLASMA_COROUTINE_MAKE_BIOPERATOR(<, expression_less);
PLASMA_COROUTINE_MAKE_BIOPERATOR(<= , expression_less_equal);
PLASMA_COROUTINE_MAKE_BIOPERATOR(>, expression_more);
PLASMA_COROUTINE_MAKE_BIOPERATOR(>=, expression_more_equal);
PLASMA_COROUTINE_MAKE_BIOPERATOR(&&, expression_logic_and);
PLASMA_COROUTINE_MAKE_BIOPERATOR(||, expression_logic_or);
PLASMA_COROUTINE_MAKE_BIOPERATOR(&, expression_bit_and);
PLASMA_COROUTINE_MAKE_BIOPERATOR(| , expression_bit_or);
PLASMA_COROUTINE_MAKE_BIOPERATOR(^ , expression_bit_xor);
template<class Expr>struct increment_t :expression_tag
{
Expr expr;
increment_t(Expr e) :expr(e) {}
increment_t(increment_t&&) = default;
increment_t(increment_t const&) = default;
increment_t& operator=(increment_t&&) = default;
increment_t& operator=(increment_t const&) = default;
~increment_t() = default;
template<class VariableMap, class ArgumentTuple>decltype(auto)operator()(VariableMap& variable, ArgumentTuple& argument)const
{
return ++(expr(variable, argument));
}
};
template<class Expr>auto operator++(Expr expr)
{
return increment_t<type::remove_cr<decltype(make_expression(expr))>>(expr);
}
template<class Expr>struct decrement_t :expression_tag
{
Expr expr;
decrement_t(Expr e) :expr(e) {}
decrement_t(decrement_t&&) = default;
decrement_t(decrement_t const&) = default;
decrement_t& operator=(decrement_t&&) = default;
decrement_t& operator=(decrement_t const&) = default;
~decrement_t() = default;
template<class VariableMap, class ArgumentTuple>decltype(auto)operator()(VariableMap& variable, ArgumentTuple& argument)const
{
return --(expr(variable, argument));
}
};
template<class Expr>auto operator--(Expr expr)
{
return decrement_t<type::remove_cr<decltype(make_expression(expr))>>(expr);
}
template<class Expr>struct access_t :expression_tag
{
Expr expr;
access_t(Expr e) :expr(e) {}
access_t(access_t&&) = default;
access_t(access_t const&) = default;
access_t& operator=(access_t&&) = default;
access_t& operator=(access_t const&) = default;
~access_t() = default;
template<class VariableMap, class ArgumentTuple>decltype(auto)operator()(VariableMap& variable, ArgumentTuple& argument)const
{
return *(expr(variable, argument));
}
};
template<class Expr>auto operator*(Expr expr)
{
return access_t<typename type::remove_const_refference<decltype(make_expression(expr))>::type>(expr);
}
}
namespace sentence
{
namespace detail
{
struct break_t {};
template<class Return>using inside_return_t = boost::variant<break_t, boost::optional<Return>>;
template<class Return>boost::optional<Return> get(inside_return_t<Return>const& inside)
{
return inside.type() != typeid(boost::optional<Return>) ? boost::none : boost::get<boost::optional<Return>>(inside);
}
template<class Return>bool is_break(inside_return_t<Return>const& v)
{
return v.type() == typeid(break_t);
}
template<class Return>bool is_valid(inside_return_t<Return>const& v)
{
return v.type() == typeid(boost::optional<Return>) && static_cast<bool>(boost::get<boost::optional<Return>>(v));
}
template<class Return>bool is_none(inside_return_t<Return>const&v)
{
return !is_break(v) && !is_valid(v);
}
template<class T>auto make_inside(T&& v)->inside_return_t<type::remove_cr<T>>
{
return inside_return_t<type::remove_cr<T>>(boost::make_optional(std::forward<T>(v)));
}
template<class T>auto make_none()
{
return inside_return_t<T>(boost::optional<T>());
}
}
template<class Expr>struct expression_sentence :sentence_tag
{
Expr expr;
template<class Return, class VariableMap, class ArgumentTuple>struct sentence_data
{
boost::optional<Expr> expr;
detail::inside_return_t<Return> run(VariableMap& variable, ArgumentTuple& argument)
{
if (expr)
{
(*expr)(variable, argument);
expr = boost::none;
}
return detail::make_none<Return>();
}
};
template<class Return,class VariableMap,class ArgumentTuple>
sentence_data<Return, VariableMap, ArgumentTuple>get_data(type::type_tag<Return>, type::type_tag<VariableMap>, type::type_tag<ArgumentTuple>)const
{
return sentence_data<Return, VariableMap, ArgumentTuple>{boost::make_optional(expr)};
}
expression_sentence(Expr e) :expr(e) {}
expression_sentence(expression_sentence&&) = default;
expression_sentence(expression_sentence const&) = default;
expression_sentence& operator=(expression_sentence&&) = default;
expression_sentence& operator=(expression_sentence const&) = default;
~expression_sentence() = default;
};
template<class Expr>expression_sentence<Expr> make_sentence(Expr expr, typename std::enable_if<!std::is_base_of<sentence_tag, Expr>::value>::type* = nullptr)
{
return expression_sentence<Expr>(expr);
}
template<class Sentence>Sentence make_sentence(Sentence sentence, typename std::enable_if<std::is_base_of<sentence_tag, Sentence>::value>::type* = nullptr)
{
return sentence;
}
template<class Before, class Now>struct multi_sentence :sentence_tag
{
Before before;
Now now;
template<class Return, class VariableMap, class ArgumentTuple>struct sentence_data
{
typedef decltype(std::declval<Before>().get_data(
type::type_tag<Return>{},
type::type_tag<VariableMap>{},
type::type_tag<ArgumentTuple>{})) before_data;
typedef decltype(std::declval<Now>().get_data(
type::type_tag<Return>{},
type::type_tag<VariableMap>{},
type::type_tag<ArgumentTuple>{})) now_data;
before_data before;
now_data now;
bool flag;
detail::inside_return_t<Return> run(VariableMap& variable, ArgumentTuple& argument)
{
if (!flag)
{
auto v = before.run(variable, argument);
if (!detail::is_none(v))
return v;
flag = true;
}
return now.run(variable, argument);
}
};
template<class Return, class VariableMap, class ArgumentTuple>
sentence_data<Return, VariableMap, ArgumentTuple>get_data(type::type_tag<Return>, type::type_tag<VariableMap>, type::type_tag<ArgumentTuple>)const
{
return sentence_data<Return, VariableMap, ArgumentTuple>{
before.get_data(
type::type_tag<Return>{},
type::type_tag<VariableMap>{},
type::type_tag<ArgumentTuple>{}),
now.get_data(
type::type_tag<Return>{},
type::type_tag<VariableMap>{},
type::type_tag<ArgumentTuple>{}), false};
}
template<class Next>auto operator|(Next next)const
{
return multi_sentence<multi_sentence<Before, Now>, decltype(make_sentence(next))>(*this, make_sentence(next));
}
multi_sentence(Before bef, Now n) :before(bef), now(n) {}
multi_sentence(multi_sentence&&) = default;
multi_sentence(multi_sentence const&) = default;
multi_sentence& operator=(multi_sentence&&) = default;
multi_sentence& operator=(multi_sentence const&) = default;
~multi_sentence() = default;
};
template<class Expr, class Next>auto operator|(Expr expr, Next next)
->typename std::enable_if<std::is_base_of<expression::expression_tag, Expr>::value, multi_sentence<expression_sentence<Expr>, Next>>::type
{
return multi_sentence<expression_sentence<Expr>, Next>(make_sentence(expr), next);
}
template<class Expr, class Next>auto operator|(expression_sentence<Expr> expr, Next next)
->typename std::enable_if<std::is_base_of<expression::expression_tag, Expr>::value, multi_sentence<expression_sentence<Expr>, Next>>::type
{
return multi_sentence<expression_sentence<Expr>, Next>(expr, next);
}
template<class Cond>struct while_t
{
Cond cond;
template<class Sentence>struct instance_t :sentence_tag
{
Cond cond;
Sentence sentence;
template<class Return, class VariableMap, class ArgumentTuple>struct sentence_data
{
Cond cond;
boost::optional<Sentence> sentence;
typedef decltype(std::declval<Sentence>().get_data(
type::type_tag<Return>{},
type::type_tag<VariableMap>{},
type::type_tag<ArgumentTuple>{})) inside_data;
boost::optional<inside_data> data;
detail::inside_return_t<Return> run(VariableMap& variable, ArgumentTuple& argument)
{
if (!sentence)
return detail::make_none<Return>();
loop:
if (!data)
{
if (!cond(variable, argument))
{
sentence.reset();
return detail::make_none<Return>();
}
data = sentence->get_data(
type::type_tag<Return>{},
type::type_tag<VariableMap>{},
type::type_tag<ArgumentTuple>{});
}
auto v = data->run(variable, argument);
if (!detail::is_none(v))
return v;
data.reset();
goto loop;
}
};
template<class Return, class VariableMap, class ArgumentTuple>
sentence_data<Return, VariableMap, ArgumentTuple>get_data(type::type_tag<Return>, type::type_tag<VariableMap>, type::type_tag<ArgumentTuple>)const
{
return sentence_data<Return, VariableMap, ArgumentTuple>{cond, boost::make_optional(sentence)};
}
instance_t(Cond con, Sentence sent) :cond(con), sentence(sent) {}
instance_t(instance_t&&) = default;
instance_t(instance_t const&) = default;
instance_t& operator=(instance_t&&) = default;
instance_t& operator=(instance_t const&) = default;
~instance_t() = default;
template<class Next>auto operator|(Next next)
{
return multi_sentence<type::remove_cr<decltype(*this)>, Next>(*this, next);
}
};
while_t(Cond c) :cond(c) {}
while_t(while_t&&) = default;
while_t(while_t const&) = default;
while_t& operator=(while_t&&) = default;
while_t& operator=(while_t const&) = default;
~while_t() = default;
template<class Sentence>auto operator()(Sentence sentence)
{
return instance_t<type::remove_cr<decltype(make_sentence(sentence))>>(cond, make_sentence(sentence));
}
};
template<class Expr>struct yield_return_t :sentence_tag
{
Expr expr;
template<class Return, class VariableMap, class ArgumentTuple>struct sentence_data
{
boost::optional<Expr> return_expr;
detail::inside_return_t<Return> run(VariableMap& variable, ArgumentTuple& argument)
{
if (return_expr)
{
auto ret = (*return_expr)(variable, argument);
return_expr.reset();
return detail::make_inside(ret);
}
return detail::make_none<Return>();
}
};
yield_return_t(Expr e) :expr(e) {}
yield_return_t(yield_return_t const&) = default;
yield_return_t(yield_return_t&&) = default;
yield_return_t& operator=(yield_return_t const&) = default;
yield_return_t& operator=(yield_return_t&&) = default;
~yield_return_t() = default;
template<class Return, class VariableMap, class ArgumentTuple>
sentence_data<Return, VariableMap, ArgumentTuple>get_data(type::type_tag<Return>, type::type_tag<VariableMap>, type::type_tag<ArgumentTuple>)const
{
return sentence_data<Return, VariableMap, ArgumentTuple>{boost::make_optional(expr)};
}
template<class Next>auto operator|(Next next)
{
return multi_sentence<type::remove_cr<decltype(*this)>, type::remove_cr<decltype(make_sentence(next))>>(*this, make_sentence(next));
}
};
struct yield_break_t :sentence_tag
{
template<class Return, class VariableMap, class ArgumentTuple>struct sentence_data
{
detail::inside_return_t<Return> run(VariableMap&, ArgumentTuple&)
{
return detail::break_t{};
}
};
template<class Return, class VariableMap, class ArgumentTuple>
sentence_data<Return, VariableMap, ArgumentTuple>get_data(type::type_tag<Return>, type::type_tag<VariableMap>, type::type_tag<ArgumentTuple>)const
{
return sentence_data<Return, VariableMap, ArgumentTuple>{};
}
yield_break_t() = default;
yield_break_t(yield_break_t&&) = default;
yield_break_t(yield_break_t const&) = default;
yield_break_t& operator=(yield_break_t&&) = default;
yield_break_t& operator=(yield_break_t const&) = default;
~yield_break_t() = default;
template<class Next>auto operator|(Next next)
{
return multi_sentence<type::remove_cr<decltype(*this)>, type::remove_cr<decltype(make_sentence(next))>>(*this, make_sentence(next));
}
};
template<class Initial, class Cond, class Iterate>struct for_t
{
Initial initial;
Cond cond;
Iterate iterate;
for_t(Initial ini, Cond con, Iterate ite) :initial(ini), cond(con), iterate(ite) {}
for_t(for_t&&) = default;
for_t(for_t const&) = default;
for_t& operator=(for_t&&) = default;
for_t& operator=(for_t const&) = default;
~for_t() = default;
template<class Sentence>auto operator()(Sentence sentence)const
{
return make_sentence(initial) |
((while_t<Cond>{cond})(sentence | iterate));
}
};
}
namespace detail
{
static constant_map::end_node_t null_map{};
static std::tuple<> null_tuple{};
auto make_variable()
{
return constant_map::end_node_t{};
}
template<std::size_t Index, class Rhs, class... Ts>auto make_variable(
expression::expression_assign<expression::value<Index>, Rhs>const& as,
Ts const&... vals)
{
return constant_map::add<Index>(make_variable(vals...), as.rhs(null_map, null_tuple));
}
}
using expression::argument;
using expression::value;
template<class Fty, class VariableMap>struct coroutine_t;
template<class Return, class VariableMap, class... Argument>struct coroutine_t<Return(Argument...), VariableMap>
{
VariableMap first_variable;
template<class Sentence>struct inside_t
{
VariableMap first_variable;
Sentence sentence;
struct enumerator :enumerable::enumerator<enumerator>
{
typedef decltype(std::declval<Sentence>().get_data(
type::type_tag<Return>{},
type::type_tag<VariableMap>{},
type::type_tag<std::tuple<Argument...>>{})) sentence_data;
sentence_data data;
VariableMap variable;
std::tuple<Argument...> argument;
boost::optional<Return> current;
bool operator++()
{
auto v = data.run(variable, argument);
if (sentence::detail::is_valid(v))
{
current = sentence::detail::get(v);
return true;
}
return false;
}
Return operator*()const
{
return *current;
}
enumerator(sentence_data dat, VariableMap val, std::tuple<Argument...> arg) :
data(dat),
variable(val),
argument(arg),
current(boost::none) {}
enumerator(enumerator&&) = default;
enumerator(enumerator const&) = default;
enumerator& operator=(enumerator&&) = default;
enumerator& operator=(enumerator const&) = default;
~enumerator() = default;
};
enumerator operator()(Argument... args)const
{
return enumerator(sentence.get_data(
type::type_tag<Return>{},
type::type_tag<VariableMap>{},
type::type_tag<std::tuple<Argument...>>{}), first_variable, std::make_tuple(args...));
}
};
template<class Sentence>inside_t<Sentence> operator()(Sentence sentence)
{
return inside_t<Sentence>{first_variable, sentence};
}
};
template<class Fty, class... Vals>auto coroutine(Vals... vals)
{
return coroutine_t<Fty, typename type::remove_const_refference<decltype(detail::make_variable(vals...))>::type>{detail::make_variable(vals...)};
}
template<class Expr>auto yield_return(Expr expr)
{
return sentence::yield_return_t<decltype(expression::make_expression(expr))>(expression::make_expression(expr));
}
constexpr sentence::yield_break_t yield_break{};
template<class Cond>auto while_(Cond cond)
{
return sentence::while_t<type::remove_cr<decltype(expression::make_expression(cond))>>(expression::make_expression(cond));
}
template<class Initial, class Cond, class Iterate>auto for_(Initial init, Cond cond, Iterate iter)
{
return sentence::for_t <
type::remove_cr<decltype(expression::make_expression(init))>,
type::remove_cr<decltype(expression::make_expression(cond))>,
type::remove_cr<decltype(expression::make_expression(iter)) >> (
expression::make_expression(init),
expression::make_expression(cond),
expression::make_expression(iter));
}
template<class Func, class... Expr>auto call(Func func, Expr... exprs)
{
return expression::function_call<std::reference_wrapper<const Func>, std::tuple<decltype(expression::make_expression(exprs))...>, std::make_index_sequence<sizeof...(exprs)>>(std::cref(func), std::make_tuple(expression::make_expression(exprs)...));
}
}
#pragma once
// Copyright plasma-effect 2016.
// Distributed under the Boost Software License, Version 1.0.
// (See http://www.boost.org/LICENSE_1_0.txt)
#include<iterator>
#include<memory>
#include<boost/optional.hpp>
namespace enumerable
{
template<class Ty>class Enumerator
{
struct place_holder
{
virtual bool MoveNext() = 0;
virtual Ty Current() = 0;
};
template<class enumerator>struct inside_data :place_holder
{
enumerator etor;
virtual bool MoveNext()final override
{
return ++etor;
}
virtual Ty Current()final override
{
return *etor;
}
inside_data(enumerator e) :etor(e) {}
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;
};
std::shared_ptr<place_holder> inside;
public:
template<class enumerator>Enumerator(enumerator const& etor)
:inside(std::make_shared<enumerator>(etor))
{
}
template<class enumerator>Enumerator(enumerator&& etor)
: inside(std::make_shared<enumerator>(std::move(etor)))
{
}
Enumerator() = default;
Enumerator(Enumerator&&) = default;
Enumerator(Enumerator const&) = default;
Enumerator& operator=(Enumerator&&) = default;
Enumerator& operator=(Enumerator const&) = default;
template<class enumerator>Enumerator& operator=(enumerator const& etor)
{
inside = std::make_shared<inside_data<enumerator>>(etor);
return *this;
}
template<class enumerator>Enumerator& operator=(enumerator&& etor)
{
inside = std::make_shared<inside_data<enumerator>>(std::move(etor));
return *this;
}
Enumerator& operator=(boost::none_t)
{
inside.reset();
return *this
}
bool operator++()
{
return inside->MoveNext();
}
Ty operator*()const
{
return inside->Current();
}
struct iterator :std::iterator<std::input_iterator_tag, Ty>
{
std::shared_ptr<place_holder> inside;
iterator& operator++()
{
if (!inside->MoveNext())inside.reset();
return *this;
}
Ty operator*()const
{
return inside->Current();
}
bool operator!=(iterator const& rhs)const
{
return static_cast<bool>(inside) != static_cast<bool>(rhs.inside);
}
iterator(std::shared_ptr<place_holder> ins) :inside(ins) {}
iterator() = default;
iterator(iterator&&) = default;
iterator(iterator const&) = default;
iterator& operator=(iterator&&) = default;
iterator& operator=(iterator const&) = default;
~iterator() = default;
};
iterator begin()const
{
return iterator(inside);
}
iterator end()const
{
return iterator();
}
};
}
#include<iostream>
#include"coroutine.hpp"
int main()
{
using namespace coroutine;
constexpr argument<0> x;
constexpr value<0> i;
const auto func = coroutine::coroutine<int(int)>(i = 0)
(
for_(i = 0, i != x, ++i)
(
yield_return(call([](int i) {return i + 1;}, i))
)
);
for (int i : func(10))
{
std::cout << i << std::endl;
}
const auto func2 = coroutine::coroutine<int(int)>()
(
yield_return(x) |
yield_return(x + 1) |
yield_return(x + 2)
);
for (int i : func2(1))
{
std::cout << i << std::endl;
}
}
#include<Siv3D.hpp>
#include"coroutine.hpp"
using namespace coroutine;
void Main()
{
s3d::Font const font(16);
constexpr value<0> i{};
constexpr argument<0> x{};
const auto func = coroutine::coroutine<int(int)>(i = 0)
(
for_(i = 1, i <= x, ++i)
(
yield_return(i)
)
);
auto enumerator = func(10);
int v = -1;
while (s3d::System::Update())
{
if (s3d::Input::KeyEnter.clicked)
{
if (++enumerator)
{
v = *enumerator;
}
else
{
return;
}
}
if (v == -1)
{
font(L"Enter Keyを押してください").draw();
}
else
{
font(v).draw();
}
}
}

#なんすかこれ C言語風にコルーチンが書ける。 #導入方法 当然boostのパスは通してるはずなので上のcoroutine.hppをテキトーなディレクトリにコピーしていい感じにincludeして使ってください。 #使い方 上の2つのコードがおおよそそのまま。
ちなみにwhile_とyield_breakもある。 #途中で変数宣言できないの 勘弁して下さい。 #関数はなんでcallってやつを使うの そのまま書くと評価されちゃう。 #言っておかなければならない大切なこと coroutine::coroutineで生成した関数はenumeratorクラスを返します。
これはC#のenumeratorクラスの設計を丸々パクったもので、operator++()で次の要素に進み、operator*()で今の要素を返します。
ここで初期状態では今の要素が存在しません、つまり最初に値を得る前にoperator++()をする必要があります。
operator++()の返り値はboolです。falseが返された場合コルーチンの処理が終了したことを意味します。
またこのクラスはC++のrange-based forに渡すことができ、またstd::begin,std::endフリー関数でイテレータを取ることもできます。 #enumerator.hppは何 type_eraserなコンテナです、ご自由にお使いください。

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