#なんすかこれ
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なコンテナです、ご自由にお使いください。
Last active
September 28, 2016 12:52
-
-
Save plasma-effect/b248e47c987468abebda to your computer and use it in GitHub Desktop.
plasma.Coroutine
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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)...)); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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(); | |
} | |
}; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment