task_object.hpp 5.2 KB

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