task_object.hpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // Copyright Oliver Kowalke 2013.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_FIBERS_DETAIL_TASK_OBJECT_H
  6. #define BOOST_FIBERS_DETAIL_TASK_OBJECT_H
  7. #include <exception>
  8. #include <memory>
  9. #include <tuple>
  10. #include <utility>
  11. #include <boost/config.hpp>
  12. #include <boost/context/detail/config.hpp>
  13. #if defined(BOOST_NO_CXX17_STD_APPLY)
  14. #include <boost/context/detail/apply.hpp>
  15. #endif
  16. #include <boost/core/pointer_traits.hpp>
  17. #include <boost/fiber/detail/config.hpp>
  18. #include <boost/fiber/future/detail/task_base.hpp>
  19. #ifdef BOOST_HAS_ABI_HEADERS
  20. # include BOOST_ABI_PREFIX
  21. #endif
  22. namespace boost {
  23. namespace fibers {
  24. namespace detail {
  25. template< typename Fn, typename Allocator, typename R, typename ... Args >
  26. class task_object : public task_base< R, Args ... > {
  27. private:
  28. typedef task_base< R, Args ... > base_type;
  29. typedef std::allocator_traits< Allocator > allocator_traits;
  30. public:
  31. typedef typename allocator_traits::template rebind_alloc<
  32. task_object
  33. > allocator_type;
  34. task_object( allocator_type const& alloc, Fn const& fn) :
  35. base_type{},
  36. fn_{ fn },
  37. alloc_{ alloc } {
  38. }
  39. task_object( allocator_type const& alloc, Fn && fn) :
  40. base_type{},
  41. fn_{ std::move( fn) },
  42. alloc_{ alloc } {
  43. }
  44. void run( Args && ... args) override final {
  45. try {
  46. this->set_value(
  47. #if defined(BOOST_NO_CXX17_STD_APPLY)
  48. boost::context::detail::apply(
  49. fn_, std::make_tuple( std::forward< Args >( args) ... ) )
  50. #else
  51. std::apply(
  52. fn_, std::make_tuple( std::forward< Args >( args) ... ) )
  53. #endif
  54. );
  55. #if defined(BOOST_CONTEXT_HAS_CXXABI_H)
  56. } catch ( abi::__forced_unwind const&) {
  57. throw;
  58. #endif
  59. } catch (...) {
  60. this->set_exception( std::current_exception() );
  61. }
  62. }
  63. typename base_type::ptr_type reset() override final {
  64. typedef std::allocator_traits< allocator_type > traity_type;
  65. typedef pointer_traits< typename traity_type::pointer> ptrait_type;
  66. typename traity_type::pointer ptr{ traity_type::allocate( alloc_, 1) };
  67. typename ptrait_type::element_type* p = boost::to_address(ptr);
  68. try {
  69. traity_type::construct( alloc_, p, alloc_, std::move( fn_) );
  70. } catch (...) {
  71. traity_type::deallocate( alloc_, ptr, 1);
  72. throw;
  73. }
  74. return { p };
  75. }
  76. protected:
  77. void deallocate_future() noexcept override final {
  78. destroy_( alloc_, this);
  79. }
  80. private:
  81. Fn fn_;
  82. allocator_type alloc_;
  83. static void destroy_( allocator_type const& alloc, task_object * p) noexcept {
  84. allocator_type a{ alloc };
  85. typedef std::allocator_traits< allocator_type > traity_type;
  86. traity_type::destroy( a, p);
  87. traity_type::deallocate( a, p, 1);
  88. }
  89. };
  90. template< typename Fn, typename Allocator, typename ... Args >
  91. class task_object< Fn, Allocator, void, Args ... > : public task_base< void, Args ... > {
  92. private:
  93. typedef task_base< void, Args ... > base_type;
  94. typedef std::allocator_traits< Allocator > allocator_traits;
  95. public:
  96. typedef typename allocator_traits::template rebind_alloc<
  97. task_object< Fn, Allocator, void, Args ... >
  98. > allocator_type;
  99. task_object( allocator_type const& alloc, Fn const& fn) :
  100. base_type{},
  101. fn_{ fn },
  102. alloc_{ alloc } {
  103. }
  104. task_object( allocator_type const& alloc, Fn && fn) :
  105. base_type{},
  106. fn_{ std::move( fn) },
  107. alloc_{ alloc } {
  108. }
  109. void run( Args && ... args) override final {
  110. try {
  111. #if defined(BOOST_NO_CXX17_STD_APPLY)
  112. boost::context::detail::apply(
  113. fn_, std::make_tuple( std::forward< Args >( args) ... ) );
  114. #else
  115. std::apply(
  116. fn_, std::make_tuple( std::forward< Args >( args) ... ) );
  117. #endif
  118. this->set_value();
  119. #if defined(BOOST_CONTEXT_HAS_CXXABI_H)
  120. } catch ( abi::__forced_unwind const&) {
  121. throw;
  122. #endif
  123. } catch (...) {
  124. this->set_exception( std::current_exception() );
  125. }
  126. }
  127. typename base_type::ptr_type reset() override final {
  128. typedef std::allocator_traits< allocator_type > traity_type;
  129. typedef pointer_traits< typename traity_type::pointer> ptrait_type;
  130. typename traity_type::pointer ptr{ traity_type::allocate( alloc_, 1) };
  131. typename ptrait_type::element_type* p = boost::to_address(ptr);
  132. try {
  133. traity_type::construct( alloc_, p, alloc_, std::move( fn_) );
  134. } catch (...) {
  135. traity_type::deallocate( alloc_, ptr, 1);
  136. throw;
  137. }
  138. return { p };
  139. }
  140. protected:
  141. void deallocate_future() noexcept override final {
  142. destroy_( alloc_, this);
  143. }
  144. private:
  145. Fn fn_;
  146. allocator_type alloc_;
  147. static void destroy_( allocator_type const& alloc, task_object * p) noexcept {
  148. allocator_type a{ alloc };
  149. typedef std::allocator_traits< allocator_type > traity_type;
  150. traity_type::destroy( a, p);
  151. traity_type::deallocate( a, p, 1);
  152. }
  153. };
  154. }}}
  155. #ifdef BOOST_HAS_ABI_HEADERS
  156. # include BOOST_ABI_SUFFIX
  157. #endif
  158. #endif // BOOST_FIBERS_DETAIL_TASK_OBJECT_H