C++14 & boost::{coroutines|signals2} -> yieldable task system

# 目的

yieldable ( ≈ generative ≈ enumerable ) な task ( ≈ functors ) システムを C++14 と boost::coroutines と boost::signals2 で簡単に実装できて便利に使えるので紹介したい。

## 補助説明

- yieldable: C# の `yield return` のように関数の中間段階で関数の外に結果を渡せる仕組み。表現として yield から連想しやすい事からこの記事では yieldable とした。プログラミング言語一般論としてはジェネレーターと呼ばれる事もある機能。 boost::coroutines により使用可能。
- task system: 様々な処理内容に対応可能な functor 群の実行を管理してくれる機能としてこの記事では task system と表現した。 functor は C++ においては lambda expression や operator() を実装したユーザー定義型による関数オブジェクト、Cスタイルの関数ポインターなど関数呼び出しとして振る舞う事のできるオブジェクトの意味。
- C++14: この記事で紹介するソースコードは C++14 以降の言語規格に対応したコンパイラーを使わないとそのままでは翻訳できない。C++14の恩恵として lambda expression の引数での `auto` によるテンプレート化、それによるコードの記述の簡略化などの恩恵を受けている。
- boost::signals2: C++ では Qt などでお馴染みの signal/slot 機能を実現するための boost の実装。今回は複数の task を slot として task system の signal に持たせる事で簡単な task system の実装として使っている。スレッドセーフな点も便利で安心して使える。

# yieldable task system

- yieldable_task_system.hxx:

```cpp
#include <boost/coroutine/all.hpp>
#include <boost/signals2/signal.hpp>
#include <memory>

namespace usagi
{

class yieldable_task_system_type
{
  boost::signals2::signal< auto () -> void > signal;
public:
  template < typename COROUTINE_TYPE >
  auto push( COROUTINE_TYPE&& coroutine ) -> void
  {
    push( boost::coroutines::coroutine< void >::pull_type( std::move( coroutine ) ) );
  }
  
  auto push( boost::coroutines::coroutine< void >::pull_type&& coroutine ) -> void
  {
    auto shared_coroutine  = std::make_shared< boost::coroutines::coroutine< void >::pull_type >( std::move( coroutine ) );
    auto shared_connection = std::make_shared< boost::signals2::connection >();
    *shared_connection = signal.connect
    ( [ = ]
      {
        if ( not (*shared_coroutine)() )
          shared_connection->disconnect();
      }
    );
  }
  
  auto consume_one() -> bool
  {
    signal();
    return not signal.empty();
  }
  
  auto consume_all() -> void
  {
    while ( consume_one() );
  }
  
  auto operator()() -> void
  {
    consume_all();
  }
};

}
```

## 使用例

- main.cxx:

```cpp
#include "yieldable_task_system.hxx"
#include <chrono>
#include <iostream>

auto main() -> int
{
  using namespace std::chrono;
  
  usagi::yieldable_task_system_type yieldable_task_system;
  
  yieldable_task_system.push
  ( [ t0 = high_resolution_clock::now() ]
    ( auto& yield )
    {
      std::cout << 'a' << std::flush;
      yield();
      
      do
      {
        std::cout << 'b' << std::flush;
        yield();
      }
      while ( high_resolution_clock::now() - t0 < microseconds( 512 ) );
      
      std::cout << 'c' << std::flush;
      yield();
    }
  );
  
  yieldable_task_system.push
  ( []
    ( auto& yield )
    {
      for ( const auto value : { 'X', 'Y', 'Z' } )
      {
        std::cout << value << std::flush;
        yield();
      }
    }
  );
  
  yieldable_task_system.push
  ( []
    ( auto& yield )
    {
      std::cout << '1' << std::flush;
      yield();
      std::cout << '2' << std::flush;
      yield();
    }
  );
  
  yieldable_task_system();
}
```

### 結果

```cpp
aX1bY2bZbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc
```

（註: 処理中に経過時間を観測しているため、実行ごとに結果の `b` の出力回数は異なる可能性があります。）

## wandbox

- http://melpon.org/wandbox/permlink/MxUUIcUGT6hviyQC

# Reference

- http://theboostcpplibraries.com/boost.coroutine
- http://www.boost.org/doc/libs/1_60_0/doc/html/boost/signals2/signal.html
- http://boostjp.github.io/tips/signals.html