packaged_task.hpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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_PACKAGED_TASK_HPP
  6. #define BOOST_FIBERS_PACKAGED_TASK_HPP
  7. #include <algorithm>
  8. #include <memory>
  9. #include <type_traits>
  10. #include <utility>
  11. #include <boost/config.hpp>
  12. #include <boost/fiber/detail/disable_overload.hpp>
  13. #include <boost/fiber/exceptions.hpp>
  14. #include <boost/fiber/future/detail/task_base.hpp>
  15. #include <boost/fiber/future/detail/task_object.hpp>
  16. #include <boost/fiber/future/future.hpp>
  17. namespace boost {
  18. namespace fibers {
  19. template< typename Signature >
  20. class packaged_task;
  21. template< typename R, typename ... Args >
  22. class packaged_task< R( Args ... ) > {
  23. private:
  24. typedef typename detail::task_base< R, Args ... >::ptr_type ptr_type;
  25. bool obtained_{ false };
  26. ptr_type task_{};
  27. public:
  28. packaged_task() = default;
  29. template< typename Fn,
  30. typename = detail::disable_overload< packaged_task, Fn >
  31. >
  32. explicit packaged_task( Fn && fn) :
  33. packaged_task{ std::allocator_arg,
  34. std::allocator< packaged_task >{},
  35. std::forward< Fn >( fn) } {
  36. }
  37. template< typename Fn,
  38. typename Allocator
  39. >
  40. explicit packaged_task( std::allocator_arg_t, Allocator const& alloc, Fn && fn) {
  41. typedef detail::task_object<
  42. typename std::decay< Fn >::type, Allocator, R, Args ...
  43. > object_type;
  44. typedef std::allocator_traits<
  45. typename object_type::allocator_type
  46. > traits_type;
  47. typedef pointer_traits< typename traits_type::pointer > ptrait_type;
  48. typename object_type::allocator_type a{ alloc };
  49. typename traits_type::pointer ptr{ traits_type::allocate( a, 1) };
  50. typename ptrait_type::element_type* p = boost::to_address(ptr);
  51. try {
  52. traits_type::construct( a, p, a, std::forward< Fn >( fn) );
  53. } catch (...) {
  54. traits_type::deallocate( a, ptr, 1);
  55. throw;
  56. }
  57. task_.reset(p);
  58. }
  59. ~packaged_task() {
  60. if ( task_ && obtained_) {
  61. task_->owner_destroyed();
  62. }
  63. }
  64. packaged_task( packaged_task const&) = delete;
  65. packaged_task & operator=( packaged_task const&) = delete;
  66. packaged_task( packaged_task && other) noexcept :
  67. obtained_{ other.obtained_ },
  68. task_{ std::move( other.task_) } {
  69. other.obtained_ = false;
  70. }
  71. packaged_task & operator=( packaged_task && other) noexcept {
  72. if ( BOOST_LIKELY( this != & other) ) {
  73. packaged_task tmp{ std::move( other) };
  74. swap( tmp);
  75. }
  76. return * this;
  77. }
  78. void swap( packaged_task & other) noexcept {
  79. std::swap( obtained_, other.obtained_);
  80. task_.swap( other.task_);
  81. }
  82. bool valid() const noexcept {
  83. return nullptr != task_.get();
  84. }
  85. future< R > get_future() {
  86. if ( obtained_) {
  87. throw future_already_retrieved{};
  88. }
  89. if ( BOOST_UNLIKELY( ! valid() ) ) {
  90. throw packaged_task_uninitialized{};
  91. }
  92. obtained_ = true;
  93. return future< R >{
  94. boost::static_pointer_cast< detail::shared_state< R > >( task_) };
  95. }
  96. void operator()( Args ... args) {
  97. if ( BOOST_UNLIKELY( ! valid() ) ) {
  98. throw packaged_task_uninitialized{};
  99. }
  100. task_->run( std::forward< Args >( args) ... );
  101. }
  102. void reset() {
  103. if ( BOOST_UNLIKELY( ! valid() ) ) {
  104. throw packaged_task_uninitialized{};
  105. }
  106. packaged_task tmp;
  107. tmp.task_ = task_;
  108. task_ = tmp.task_->reset();
  109. obtained_ = false;
  110. }
  111. };
  112. template< typename Signature >
  113. void swap( packaged_task< Signature > & l, packaged_task< Signature > & r) noexcept {
  114. l.swap( r);
  115. }
  116. }}
  117. #endif // BOOST_FIBERS_PACKAGED_TASK_HPP