Advertisement
zhangsongcui

True Yield V3

Jul 1st, 2017
175
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.51 KB | None | 0 0
  1. #ifdef _WIN32
  2. #   define _WIN32_WINNT 0x0601
  3. #elif defined(__APPLE__)
  4. #   define _XOPEN_SOURCE
  5. #endif
  6.  
  7. #include <functional>
  8. #include <cassert>
  9. #include <iterator>
  10. #include <iostream>
  11. #include <array>
  12. #include <memory>
  13. #include <algorithm>
  14. #ifdef _WIN32
  15. #   ifdef WIN32_LEAD_AND_MEAN
  16. #       include <Windows.h>
  17. #   else
  18. #       define WIN32_LEAD_AND_MEAN 1
  19. #       include <Windows.h>
  20. #       undef WIN32_LEAD_AND_MEAN
  21. #   endif
  22. #else
  23. #   include <ucontext.h>
  24. #endif
  25.  
  26. namespace FiberSpace {
  27.     /** \brief 主纤程类
  28.      *
  29.      * 目前可以嵌套开纤程,但最好只在每个纤程中新开一个纤程
  30.      *
  31.      * \warning 无线程安全
  32.      * \param YieldValueType 子纤程返回类型
  33.      */
  34.     template <typename YieldValueType = void>
  35.     class Fiber {
  36.         Fiber(const Fiber &) = delete;
  37.         Fiber& operator =(const Fiber &) = delete;
  38.  
  39.         typedef std::function<void (Fiber& fiber)> FuncType;
  40.  
  41.         /// \brief 子纤程返回值
  42.         YieldValueType yieldedValue = YieldValueType();
  43.         /// \brief 存储子纤程抛出的异常
  44.         std::exception_ptr eptr = nullptr;
  45.         /// \brief 子纤程是否结束
  46.         bool flagFinish = false;
  47.         /// \brief 真子纤程入口,第一个参数传入纤程对象的引用
  48.         FuncType func;
  49.         /// \brief 纤程信息
  50. #ifdef _WIN32
  51.         PVOID pMainFiber, pNewFiber;
  52.         bool isFormerAThread;
  53. #else
  54.         ucontext_t ctx_main, ctx_fnew;
  55.         const std::unique_ptr<std::array<uint8_t, SIGSTKSZ>> fnew_stack = std::make_unique<std::array<uint8_t, SIGSTKSZ>>();
  56. #endif
  57.  
  58.     public:
  59.         /** \brief 构造函数
  60.          *
  61.          * 把主线程转化为纤程,并创建一个子纤程
  62.          *
  63.          * \param f 子纤程入口
  64.          */
  65.         Fiber(FuncType f) : func(std::move(f)) {
  66. #ifdef _WIN32
  67.             this->isFormerAThread = !IsThreadAFiber();
  68.             if (this->isFormerAThread) {
  69.                 this->pMainFiber = ::ConvertThreadToFiberEx(nullptr, FIBER_FLAG_FLOAT_SWITCH);
  70.             } else {
  71.                 this->pMainFiber = ::GetCurrentFiber();
  72.             }
  73.             // default stack size
  74.             this->pNewFiber = ::CreateFiberEx(0, 0, FIBER_FLAG_FLOAT_SWITCH, (void(*)(void *))&fEntry, this);
  75. #else
  76.             ::getcontext(&this->ctx_fnew);
  77.             this->ctx_fnew.uc_stack.ss_sp = this->fnew_stack.get();
  78.             this->ctx_fnew.uc_stack.ss_size = this->fnew_stack->size();
  79.             this->ctx_fnew.uc_link = &this->ctx_main;
  80.             ::makecontext(&this->ctx_fnew, (void(*)())&fEntry, 1, this);
  81. #endif
  82.         }
  83.         /** \brief 析构函数
  84.          *
  85.          * 删除子纤程,并将主纤程转回线程
  86.          *
  87.          * \warning 为确保子纤程函数内所有对象都已正确析构,主类析构时子纤程必须已经结束 (return)
  88.          */
  89.         ~Fiber() noexcept {
  90.             if (!isFinished())
  91.                 std::terminate();
  92. #ifdef _WIN32
  93.             ::DeleteFiber(this->pNewFiber);
  94.             if (this->isFormerAThread) {
  95.                 ::ConvertFiberToThread();
  96.             }
  97. #endif
  98.         }
  99.  
  100.         /** \brief 调用子纤程
  101.          *
  102.          * 程序流程转入子线程
  103.          *
  104.          * \warning 子纤程必须尚未结束
  105.          * \return 返回子纤程是否尚未结束
  106.          */
  107.         bool next() {
  108.             assert(!isFinished());
  109. #ifdef _WIN32
  110.             assert(GetCurrentFiber() != this->pNewFiber && "如果你想递归自己,请创建一个新纤程");
  111.             ::SwitchToFiber(this->pNewFiber);
  112. #else
  113.             ::swapcontext(&this->ctx_main, &this->ctx_fnew);
  114. #endif
  115.             if (this->eptr) {
  116.                 std::rethrow_exception(std::exchange(this->eptr, nullptr));
  117.             }
  118.  
  119.             return !isFinished();
  120.         }
  121.        
  122.         /** \brief 获得子纤程返回的值
  123.          * \return 子纤程返回的值。如果子纤程没有启动,则返回默认构造值
  124.          */
  125.         YieldValueType current() const {
  126.             return this->yieldedValue;
  127.         }
  128.  
  129.         /** \brief 判断子纤程是否结束
  130.         * \return 子纤程已经结束(return)返回true,否则false
  131.         */
  132.         bool isFinished() const noexcept {
  133.             return this->flagFinish;
  134.         }
  135.  
  136.         /** \brief 转回主纤程并输出值
  137.          *
  138.          * \warning 必须由子纤程调用
  139.          *          参数类型必须与子纤程返回值相同,无类型安全
  140.          * \param value 输出到主纤程的值
  141.          */
  142.         void yield(YieldValueType value) {
  143.             assert(!isFinished());
  144.             this->yieldedValue = std::move(value);
  145. #ifdef _WIN32
  146.             assert(GetCurrentFiber() != this->pMainFiber && "这虽然是游戏,但绝不是可以随便玩的");
  147.             ::SwitchToFiber(this->pMainFiber);
  148. #else
  149.             ::swapcontext(&this->ctx_fnew, &this->ctx_main);
  150. #endif
  151.         }
  152.        
  153.         /** \brief 输出子纤程的所有值
  154.          * \param fiber 另一子纤程
  155.          */
  156.         void yieldAll(Fiber& fiber) {
  157.             assert(&fiber != this);
  158.             while (fiber.next()) {
  159.                 this->yield(fiber.current());
  160.             }
  161.         }
  162.        
  163.         void yieldAll(Fiber&& fiber) {
  164.             this->yieldAll(fiber);
  165.         }
  166.  
  167.     private:
  168.         /// \brief 子纤程入口的warpper
  169.  
  170. #ifdef _WIN32
  171.         static void WINAPI fEntry(Fiber *fiber) {
  172. #else
  173.         static void fEntry(Fiber *fiber) {
  174. #endif
  175.  
  176.             fiber->flagFinish = false;
  177.             try {
  178.                 fiber->func(*fiber);
  179.             } catch (...) {
  180.                 fiber->eptr = std::current_exception();
  181.             }
  182.             fiber->flagFinish = true;
  183. #ifdef _WIN32
  184.             ::SwitchToFiber(fiber->pMainFiber);
  185. #endif
  186.         }
  187.     };
  188.  
  189.     /** \brief 纤程迭代器类
  190.     *
  191.     * 它通过使用 yield 函数对数组或集合类执行自定义迭代。
  192.     * 用于 C++11 for (... : ...)
  193.     */
  194.     template <typename YieldValueType>
  195.     struct FiberIterator : std::iterator<std::input_iterator_tag, YieldValueType> {
  196.         /// \brief 迭代器尾
  197.         FiberIterator() noexcept : fiber(nullptr) {}
  198.         /** \brief 迭代器首
  199.         * \param _f 主线程类的引用
  200.         */
  201.         FiberIterator(Fiber<YieldValueType>& _f) : fiber(&_f) {
  202.             next();
  203.         }
  204.  
  205.         /// \brief 转入子纤程
  206.         FiberIterator& operator ++() {
  207.             next();
  208.             return *this;
  209.         }
  210.  
  211.         /// \brief 取得返回值
  212.         YieldValueType operator *() const {
  213.             assert(fiber != nullptr);
  214.             return std::move(fiber->current());
  215.         }
  216.  
  217.         /** \brief 比较迭代器相等
  218.         *
  219.         * 通常用于判断迭代是否结束
  220.         * 最好别干别的 ;P
  221.         */
  222.         bool operator ==(const FiberIterator& rhs) const noexcept {
  223.             return fiber == rhs.fiber;
  224.         }
  225.         bool operator !=(const FiberIterator& rhs) const noexcept {
  226.             return !(*this == rhs);
  227.         }
  228.  
  229.     private:
  230.         void next() {
  231.             assert(fiber);
  232.             if (!fiber->next()) fiber = nullptr;
  233.         }
  234.    
  235.         Fiber<YieldValueType>* fiber;
  236.     };
  237.  
  238.     /// \brief 返回迭代器首
  239.     template <typename YieldValueType>
  240.     FiberIterator<YieldValueType> begin(Fiber<YieldValueType>& fiber) {
  241.         return FiberIterator<YieldValueType>(fiber);
  242.     }
  243.  
  244.     /// \brief 返回迭代器尾
  245.     template <typename YieldValueType>
  246.     FiberIterator<YieldValueType> end(Fiber<YieldValueType>&) noexcept {
  247.         return FiberIterator<YieldValueType>();
  248.     }
  249. }
  250.  
  251. using namespace std;
  252. using FiberSpace::Fiber;
  253.  
  254. void permutation(Fiber<array<int, 4>>& fiber, array<int, 4> arr, int length) {
  255.     if (length) {
  256.         for (auto i = 0; i < length; ++i) {
  257.             array<int, 4> newArr;
  258.             std::copy_n(arr.begin(), i, newArr.begin());
  259.             std::copy_n(arr.begin() + i + 1, arr.size() - i - 1, newArr.begin() + i);
  260.             newArr.back() = arr[i];
  261.             fiber.yieldAll(Fiber<array<int, 4>>(bind(permutation, placeholders::_1, newArr, length - 1)));
  262.         }
  263.     } else {
  264.         fiber.yield(arr);
  265.     }
  266. }
  267.  
  268. int main() {
  269.     Fiber<array<int, 4>> fiber(
  270.         bind(permutation, placeholders::_1, array<int, 4> {1, 2, 3, 4}, 4)
  271.     );
  272.     for (auto && result : fiber) {
  273.         copy(result.begin(), result.end(), std::ostream_iterator<int>(cout, ","));
  274.         cout << endl;
  275.     }
  276. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement