File indexing completed on 2025-01-30 09:35:35
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_FIBERS_PROMISE_HPP
0008 #define BOOST_FIBERS_PROMISE_HPP
0009
0010 #include <algorithm>
0011 #include <memory>
0012 #include <utility>
0013
0014 #include <boost/config.hpp>
0015 #include <boost/core/pointer_traits.hpp>
0016
0017 #include <boost/fiber/exceptions.hpp>
0018 #include <boost/fiber/future/detail/shared_state.hpp>
0019 #include <boost/fiber/future/detail/shared_state_object.hpp>
0020 #include <boost/fiber/future/future.hpp>
0021
0022 namespace boost {
0023 namespace fibers {
0024 namespace detail {
0025
0026 template< typename R >
0027 struct promise_base {
0028 typedef typename shared_state< R >::ptr_type ptr_type;
0029
0030 bool obtained_{ false };
0031 ptr_type future_{};
0032
0033 promise_base() :
0034 promise_base{ std::allocator_arg, std::allocator< promise_base >{} } {
0035 }
0036
0037 template< typename Allocator >
0038 promise_base( std::allocator_arg_t, Allocator alloc) {
0039 typedef detail::shared_state_object< R, Allocator > object_type;
0040 typedef std::allocator_traits< typename object_type::allocator_type > traits_type;
0041 typedef pointer_traits< typename traits_type::pointer > ptrait_type;
0042 typename object_type::allocator_type a{ alloc };
0043 typename traits_type::pointer ptr{ traits_type::allocate( a, 1) };
0044 typename ptrait_type::element_type* p = boost::to_address(ptr);
0045
0046 try {
0047 traits_type::construct( a, p, a);
0048 } catch (...) {
0049 traits_type::deallocate( a, ptr, 1);
0050 throw;
0051 }
0052 future_.reset(p);
0053 }
0054
0055 ~promise_base() {
0056 if ( future_ && obtained_) {
0057 future_->owner_destroyed();
0058 }
0059 }
0060
0061 promise_base( promise_base const&) = delete;
0062 promise_base & operator=( promise_base const&) = delete;
0063
0064 promise_base( promise_base && other) noexcept :
0065 obtained_{ other.obtained_ },
0066 future_{ std::move( other.future_) } {
0067 other.obtained_ = false;
0068 }
0069
0070 promise_base & operator=( promise_base && other) noexcept {
0071 if ( BOOST_LIKELY( this != & other) ) {
0072 promise_base tmp{ std::move( other) };
0073 swap( tmp);
0074 }
0075 return * this;
0076 }
0077
0078 future< R > get_future() {
0079 if ( BOOST_UNLIKELY( obtained_) ) {
0080 throw future_already_retrieved{};
0081 }
0082 if ( BOOST_UNLIKELY( ! future_) ) {
0083 throw promise_uninitialized{};
0084 }
0085 obtained_ = true;
0086 return future< R >{ future_ };
0087 }
0088
0089 void swap( promise_base & other) noexcept {
0090 std::swap( obtained_, other.obtained_);
0091 future_.swap( other.future_);
0092 }
0093
0094 void set_exception( std::exception_ptr p) {
0095 if ( BOOST_UNLIKELY( ! future_) ) {
0096 throw promise_uninitialized{};
0097 }
0098 future_->set_exception( p);
0099 }
0100 };
0101
0102 }
0103
0104 template< typename R >
0105 class promise : private detail::promise_base< R > {
0106 private:
0107 typedef detail::promise_base< R > base_type;
0108
0109 public:
0110 promise() = default;
0111
0112 template< typename Allocator >
0113 promise( std::allocator_arg_t, Allocator alloc) :
0114 base_type{ std::allocator_arg, alloc } {
0115 }
0116
0117 promise( promise const&) = delete;
0118 promise & operator=( promise const&) = delete;
0119
0120 promise( promise && other) = default;
0121 promise & operator=( promise && other) = default;
0122
0123 void set_value( R const& value) {
0124 if ( BOOST_UNLIKELY( ! base_type::future_) ) {
0125 throw promise_uninitialized{};
0126 }
0127 base_type::future_->set_value( value);
0128 }
0129
0130 void set_value( R && value) {
0131 if ( BOOST_UNLIKELY( ! base_type::future_) ) {
0132 throw promise_uninitialized{};
0133 }
0134 base_type::future_->set_value( std::move( value) );
0135 }
0136
0137 void swap( promise & other) noexcept {
0138 base_type::swap( other);
0139 }
0140
0141 using base_type::get_future;
0142 using base_type::set_exception;
0143 };
0144
0145 template< typename R >
0146 class promise< R & > : private detail::promise_base< R & > {
0147 private:
0148 typedef detail::promise_base< R & > base_type;
0149
0150 public:
0151 promise() = default;
0152
0153 template< typename Allocator >
0154 promise( std::allocator_arg_t, Allocator alloc) :
0155 base_type{ std::allocator_arg, alloc } {
0156 }
0157
0158 promise( promise const&) = delete;
0159 promise & operator=( promise const&) = delete;
0160
0161 promise( promise && other) = default;
0162 promise & operator=( promise && other) = default;
0163
0164 void set_value( R & value) {
0165 if ( BOOST_UNLIKELY( ! base_type::future_) ) {
0166 throw promise_uninitialized{};
0167 }
0168 base_type::future_->set_value( value);
0169 }
0170
0171 void swap( promise & other) noexcept {
0172 base_type::swap( other);
0173 }
0174
0175 using base_type::get_future;
0176 using base_type::set_exception;
0177 };
0178
0179 template<>
0180 class promise< void > : private detail::promise_base< void > {
0181 private:
0182 typedef detail::promise_base< void > base_type;
0183
0184 public:
0185 promise() = default;
0186
0187 template< typename Allocator >
0188 promise( std::allocator_arg_t, Allocator alloc) :
0189 base_type{ std::allocator_arg, alloc } {
0190 }
0191
0192 promise( promise const&) = delete;
0193 promise & operator=( promise const&) = delete;
0194
0195 promise( promise && other) = default;
0196 promise & operator=( promise && other) = default;
0197
0198 inline
0199 void set_value() {
0200 if ( BOOST_UNLIKELY( ! base_type::future_) ) {
0201 throw promise_uninitialized{};
0202 }
0203 base_type::future_->set_value();
0204 }
0205
0206 inline
0207 void swap( promise & other) noexcept {
0208 base_type::swap( other);
0209 }
0210
0211 using base_type::get_future;
0212 using base_type::set_exception;
0213 };
0214
0215 template< typename R >
0216 void swap( promise< R > & l, promise< R > & r) noexcept {
0217 l.swap( r);
0218 }
0219
0220 }}
0221
0222 #endif