promise.hpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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_PROMISE_HPP
  6. #define BOOST_FIBERS_PROMISE_HPP
  7. #include <algorithm>
  8. #include <memory>
  9. #include <utility>
  10. #include <boost/config.hpp>
  11. #include <boost/core/pointer_traits.hpp>
  12. #include <boost/fiber/exceptions.hpp>
  13. #include <boost/fiber/future/detail/shared_state.hpp>
  14. #include <boost/fiber/future/detail/shared_state_object.hpp>
  15. #include <boost/fiber/future/future.hpp>
  16. namespace boost {
  17. namespace fibers {
  18. namespace detail {
  19. template< typename R >
  20. struct promise_base {
  21. typedef typename shared_state< R >::ptr_type ptr_type;
  22. bool obtained_{ false };
  23. ptr_type future_{};
  24. promise_base() :
  25. promise_base{ std::allocator_arg, std::allocator< promise_base >{} } {
  26. }
  27. template< typename Allocator >
  28. promise_base( std::allocator_arg_t, Allocator alloc) {
  29. typedef detail::shared_state_object< R, Allocator > object_type;
  30. typedef std::allocator_traits< typename object_type::allocator_type > traits_type;
  31. typedef pointer_traits< typename traits_type::pointer > ptrait_type;
  32. typename object_type::allocator_type a{ alloc };
  33. typename traits_type::pointer ptr{ traits_type::allocate( a, 1) };
  34. typename ptrait_type::element_type* p = boost::to_address(ptr);
  35. try {
  36. traits_type::construct( a, p, a);
  37. } catch (...) {
  38. traits_type::deallocate( a, ptr, 1);
  39. throw;
  40. }
  41. future_.reset(p);
  42. }
  43. ~promise_base() {
  44. if ( future_ && obtained_) {
  45. future_->owner_destroyed();
  46. }
  47. }
  48. promise_base( promise_base const&) = delete;
  49. promise_base & operator=( promise_base const&) = delete;
  50. promise_base( promise_base && other) noexcept :
  51. obtained_{ other.obtained_ },
  52. future_{ std::move( other.future_) } {
  53. other.obtained_ = false;
  54. }
  55. promise_base & operator=( promise_base && other) noexcept {
  56. if ( BOOST_LIKELY( this != & other) ) {
  57. promise_base tmp{ std::move( other) };
  58. swap( tmp);
  59. }
  60. return * this;
  61. }
  62. future< R > get_future() {
  63. if ( BOOST_UNLIKELY( obtained_) ) {
  64. throw future_already_retrieved{};
  65. }
  66. if ( BOOST_UNLIKELY( ! future_) ) {
  67. throw promise_uninitialized{};
  68. }
  69. obtained_ = true;
  70. return future< R >{ future_ };
  71. }
  72. void swap( promise_base & other) noexcept {
  73. std::swap( obtained_, other.obtained_);
  74. future_.swap( other.future_);
  75. }
  76. void set_exception( std::exception_ptr p) {
  77. if ( BOOST_UNLIKELY( ! future_) ) {
  78. throw promise_uninitialized{};
  79. }
  80. future_->set_exception( p);
  81. }
  82. };
  83. }
  84. template< typename R >
  85. class promise : private detail::promise_base< R > {
  86. private:
  87. typedef detail::promise_base< R > base_type;
  88. public:
  89. promise() = default;
  90. template< typename Allocator >
  91. promise( std::allocator_arg_t, Allocator alloc) :
  92. base_type{ std::allocator_arg, alloc } {
  93. }
  94. promise( promise const&) = delete;
  95. promise & operator=( promise const&) = delete;
  96. promise( promise && other) noexcept = default;
  97. promise & operator=( promise && other) = default;
  98. void set_value( R const& value) {
  99. if ( BOOST_UNLIKELY( ! base_type::future_) ) {
  100. throw promise_uninitialized{};
  101. }
  102. base_type::future_->set_value( value);
  103. }
  104. void set_value( R && value) {
  105. if ( BOOST_UNLIKELY( ! base_type::future_) ) {
  106. throw promise_uninitialized{};
  107. }
  108. base_type::future_->set_value( std::move( value) );
  109. }
  110. void swap( promise & other) noexcept {
  111. base_type::swap( other);
  112. }
  113. using base_type::get_future;
  114. using base_type::set_exception;
  115. };
  116. template< typename R >
  117. class promise< R & > : private detail::promise_base< R & > {
  118. private:
  119. typedef detail::promise_base< R & > base_type;
  120. public:
  121. promise() = default;
  122. template< typename Allocator >
  123. promise( std::allocator_arg_t, Allocator alloc) :
  124. base_type{ std::allocator_arg, alloc } {
  125. }
  126. promise( promise const&) = delete;
  127. promise & operator=( promise const&) = delete;
  128. promise( promise && other) noexcept = default;
  129. promise & operator=( promise && other) noexcept = default;
  130. void set_value( R & value) {
  131. if ( BOOST_UNLIKELY( ! base_type::future_) ) {
  132. throw promise_uninitialized{};
  133. }
  134. base_type::future_->set_value( value);
  135. }
  136. void swap( promise & other) noexcept {
  137. base_type::swap( other);
  138. }
  139. using base_type::get_future;
  140. using base_type::set_exception;
  141. };
  142. template<>
  143. class promise< void > : private detail::promise_base< void > {
  144. private:
  145. typedef detail::promise_base< void > base_type;
  146. public:
  147. promise() = default;
  148. template< typename Allocator >
  149. promise( std::allocator_arg_t, Allocator alloc) :
  150. base_type{ std::allocator_arg, alloc } {
  151. }
  152. promise( promise const&) = delete;
  153. promise & operator=( promise const&) = delete;
  154. promise( promise && other) noexcept = default;
  155. promise & operator=( promise && other) noexcept = default;
  156. inline
  157. void set_value() {
  158. if ( BOOST_UNLIKELY( ! base_type::future_) ) {
  159. throw promise_uninitialized{};
  160. }
  161. base_type::future_->set_value();
  162. }
  163. inline
  164. void swap( promise & other) noexcept {
  165. base_type::swap( other);
  166. }
  167. using base_type::get_future;
  168. using base_type::set_exception;
  169. };
  170. template< typename R >
  171. void swap( promise< R > & l, promise< R > & r) noexcept {
  172. l.swap( r);
  173. }
  174. }}
  175. #endif // BOOST_FIBERS_PROMISE_HPP