1 2 // Copyright Oliver Kowalke 2013. 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 7 #ifndef BOOST_FIBERS_FUTURE_HPP 8 #define BOOST_FIBERS_FUTURE_HPP 9 10 #include <algorithm> 11 #include <chrono> 12 #include <exception> 13 #include <utility> 14 15 #include <boost/config.hpp> 16 17 #include <boost/fiber/detail/config.hpp> 18 #include <boost/fiber/exceptions.hpp> 19 #include <boost/fiber/future/detail/shared_state.hpp> 20 #include <boost/fiber/future/future_status.hpp> 21 22 namespace boost { 23 namespace fibers { 24 namespace detail { 25 26 template< typename R > 27 struct future_base { 28 typedef typename shared_state< R >::ptr_type ptr_type; 29 30 ptr_type state_{}; 31 32 future_base() = default; 33 future_baseboost::fibers::detail::future_base34 explicit future_base( ptr_type p) noexcept : 35 state_{std::move( p )} { 36 } 37 38 ~future_base() = default; 39 future_baseboost::fibers::detail::future_base40 future_base( future_base const& other) : 41 state_{ other.state_ } { 42 } 43 future_baseboost::fibers::detail::future_base44 future_base( future_base && other) noexcept : 45 state_{ other.state_ } { 46 other.state_.reset(); 47 } 48 operator =boost::fibers::detail::future_base49 future_base & operator=( future_base const& other) noexcept { 50 if ( BOOST_LIKELY( this != & other) ) { 51 state_ = other.state_; 52 } 53 return * this; 54 } 55 operator =boost::fibers::detail::future_base56 future_base & operator=( future_base && other) noexcept { 57 if ( BOOST_LIKELY( this != & other) ) { 58 state_ = other.state_; 59 other.state_.reset(); 60 } 61 return * this; 62 } 63 validboost::fibers::detail::future_base64 bool valid() const noexcept { 65 return nullptr != state_.get(); 66 } 67 get_exception_ptrboost::fibers::detail::future_base68 std::exception_ptr get_exception_ptr() { 69 if ( BOOST_UNLIKELY( ! valid() ) ) { 70 throw future_uninitialized{}; 71 } 72 return state_->get_exception_ptr(); 73 } 74 waitboost::fibers::detail::future_base75 void wait() const { 76 if ( BOOST_UNLIKELY( ! valid() ) ) { 77 throw future_uninitialized{}; 78 } 79 state_->wait(); 80 } 81 82 template< typename Rep, typename Period > wait_forboost::fibers::detail::future_base83 future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { 84 if ( BOOST_UNLIKELY( ! valid() ) ) { 85 throw future_uninitialized{}; 86 } 87 return state_->wait_for( timeout_duration); 88 } 89 90 template< typename Clock, typename Duration > wait_untilboost::fibers::detail::future_base91 future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { 92 if ( BOOST_UNLIKELY( ! valid() ) ) { 93 throw future_uninitialized{}; 94 } 95 return state_->wait_until( timeout_time); 96 } 97 }; 98 99 template< typename R > 100 struct promise_base; 101 102 } 103 104 template< typename R > 105 class shared_future; 106 107 template< typename Signature > 108 class packaged_task; 109 110 template< typename R > 111 class future : private detail::future_base< R > { 112 private: 113 typedef detail::future_base< R > base_type; 114 115 friend struct detail::promise_base< R >; 116 friend class shared_future< R >; 117 template< typename Signature > 118 friend class packaged_task; 119 future(typename base_type::ptr_type const & p)120 explicit future( typename base_type::ptr_type const& p) noexcept : 121 base_type{ p } { 122 } 123 124 public: 125 future() = default; 126 127 future( future const&) = delete; 128 future & operator=( future const&) = delete; 129 future(future && other)130 future( future && other) noexcept : 131 base_type{ std::move( other) } { 132 } 133 operator =(future && other)134 future & operator=( future && other) noexcept { 135 if ( BOOST_LIKELY( this != & other) ) { 136 base_type::operator=( std::move( other) ); 137 } 138 return * this; 139 } 140 141 shared_future< R > share(); 142 get()143 R get() { 144 if ( BOOST_UNLIKELY( ! base_type::valid() ) ) { 145 throw future_uninitialized{}; 146 } 147 typename base_type::ptr_type tmp{}; 148 tmp.swap( base_type::state_); 149 return std::move( tmp->get() ); 150 } 151 152 using base_type::valid; 153 using base_type::get_exception_ptr; 154 using base_type::wait; 155 using base_type::wait_for; 156 using base_type::wait_until; 157 }; 158 159 template< typename R > 160 class future< R & > : private detail::future_base< R & > { 161 private: 162 typedef detail::future_base< R & > base_type; 163 164 friend struct detail::promise_base< R & >; 165 friend class shared_future< R & >; 166 template< typename Signature > 167 friend class packaged_task; 168 future(typename base_type::ptr_type const & p)169 explicit future( typename base_type::ptr_type const& p) noexcept : 170 base_type{ p } { 171 } 172 173 public: 174 future() = default; 175 176 future( future const&) = delete; 177 future & operator=( future const&) = delete; 178 future(future && other)179 future( future && other) noexcept : 180 base_type{ std::move( other) } { 181 } 182 operator =(future && other)183 future & operator=( future && other) noexcept { 184 if ( BOOST_LIKELY( this != & other) ) { 185 base_type::operator=( std::move( other) ); 186 } 187 return * this; 188 } 189 190 shared_future< R & > share(); 191 get()192 R & get() { 193 if ( BOOST_UNLIKELY( ! base_type::valid() ) ) { 194 throw future_uninitialized{}; 195 } 196 typename base_type::ptr_type tmp{}; 197 tmp.swap( base_type::state_); 198 return tmp->get(); 199 } 200 201 using base_type::valid; 202 using base_type::get_exception_ptr; 203 using base_type::wait; 204 using base_type::wait_for; 205 using base_type::wait_until; 206 }; 207 208 template<> 209 class future< void > : private detail::future_base< void > { 210 private: 211 typedef detail::future_base< void > base_type; 212 213 friend struct detail::promise_base< void >; 214 friend class shared_future< void >; 215 template< typename Signature > 216 friend class packaged_task; 217 future(base_type::ptr_type const & p)218 explicit future( base_type::ptr_type const& p) noexcept : 219 base_type{ p } { 220 } 221 222 public: 223 future() = default; 224 225 future( future const&) = delete; 226 future & operator=( future const&) = delete; 227 228 inline future(future && other)229 future( future && other) noexcept : 230 base_type{ std::move( other) } { 231 } 232 233 inline operator =(future && other)234 future & operator=( future && other) noexcept { 235 if ( BOOST_LIKELY( this != & other) ) { 236 base_type::operator=( std::move( other) ); 237 } 238 return * this; 239 } 240 241 shared_future< void > share(); 242 243 inline get()244 void get() { 245 if ( BOOST_UNLIKELY( ! base_type::valid() ) ) { 246 throw future_uninitialized{}; 247 } 248 base_type::ptr_type tmp{}; 249 tmp.swap( base_type::state_); 250 tmp->get(); 251 } 252 253 using base_type::valid; 254 using base_type::get_exception_ptr; 255 using base_type::wait; 256 using base_type::wait_for; 257 using base_type::wait_until; 258 }; 259 260 261 template< typename R > 262 class shared_future : private detail::future_base< R > { 263 private: 264 typedef detail::future_base< R > base_type; 265 shared_future(typename base_type::ptr_type const & p)266 explicit shared_future( typename base_type::ptr_type const& p) noexcept : 267 base_type{ p } { 268 } 269 270 public: 271 shared_future() = default; 272 273 ~shared_future() = default; 274 shared_future(shared_future const & other)275 shared_future( shared_future const& other) : 276 base_type{ other } { 277 } 278 shared_future(shared_future && other)279 shared_future( shared_future && other) noexcept : 280 base_type{ std::move( other) } { 281 } 282 shared_future(future<R> && other)283 shared_future( future< R > && other) noexcept : 284 base_type{ std::move( other) } { 285 } 286 operator =(shared_future const & other)287 shared_future & operator=( shared_future const& other) noexcept { 288 if ( BOOST_LIKELY( this != & other) ) { 289 base_type::operator=( other); 290 } 291 return * this; 292 } 293 operator =(shared_future && other)294 shared_future & operator=( shared_future && other) noexcept { 295 if ( BOOST_LIKELY( this != & other) ) { 296 base_type::operator=( std::move( other) ); 297 } 298 return * this; 299 } 300 operator =(future<R> && other)301 shared_future & operator=( future< R > && other) noexcept { 302 base_type::operator=( std::move( other) ); 303 return * this; 304 } 305 get() const306 R const& get() const { 307 if ( BOOST_UNLIKELY( ! valid() ) ) { 308 throw future_uninitialized{}; 309 } 310 return base_type::state_->get(); 311 } 312 313 using base_type::valid; 314 using base_type::get_exception_ptr; 315 using base_type::wait; 316 using base_type::wait_for; 317 using base_type::wait_until; 318 }; 319 320 template< typename R > 321 class shared_future< R & > : private detail::future_base< R & > { 322 private: 323 typedef detail::future_base< R & > base_type; 324 shared_future(typename base_type::ptr_type const & p)325 explicit shared_future( typename base_type::ptr_type const& p) noexcept : 326 base_type{ p } { 327 } 328 329 public: 330 shared_future() = default; 331 332 ~shared_future() = default; 333 shared_future(shared_future const & other)334 shared_future( shared_future const& other) : 335 base_type{ other } { 336 } 337 shared_future(shared_future && other)338 shared_future( shared_future && other) noexcept : 339 base_type{ std::move( other) } { 340 } 341 shared_future(future<R &> && other)342 shared_future( future< R & > && other) noexcept : 343 base_type{ std::move( other) } { 344 } 345 operator =(shared_future const & other)346 shared_future & operator=( shared_future const& other) noexcept { 347 if ( BOOST_LIKELY( this != & other) ) { 348 base_type::operator=( other); 349 } 350 return * this; 351 } 352 operator =(shared_future && other)353 shared_future & operator=( shared_future && other) noexcept { 354 if ( BOOST_LIKELY( this != & other) ) { 355 base_type::operator=( std::move( other) ); 356 } 357 return * this; 358 } 359 operator =(future<R &> && other)360 shared_future & operator=( future< R & > && other) noexcept { 361 base_type::operator=( std::move( other) ); 362 return * this; 363 } 364 get() const365 R & get() const { 366 if ( BOOST_UNLIKELY( ! valid() ) ) { 367 throw future_uninitialized{}; 368 } 369 return base_type::state_->get(); 370 } 371 372 using base_type::valid; 373 using base_type::get_exception_ptr; 374 using base_type::wait; 375 using base_type::wait_for; 376 using base_type::wait_until; 377 }; 378 379 template<> 380 class shared_future< void > : private detail::future_base< void > { 381 private: 382 typedef detail::future_base< void > base_type; 383 shared_future(base_type::ptr_type const & p)384 explicit shared_future( base_type::ptr_type const& p) noexcept : 385 base_type{ p } { 386 } 387 388 public: 389 shared_future() = default; 390 391 ~shared_future() = default; 392 393 inline shared_future(shared_future const & other)394 shared_future( shared_future const& other) : 395 base_type{ other } { 396 } 397 398 inline shared_future(shared_future && other)399 shared_future( shared_future && other) noexcept : 400 base_type{ std::move( other) } { 401 } 402 403 inline shared_future(future<void> && other)404 shared_future( future< void > && other) noexcept : 405 base_type{ std::move( other) } { 406 } 407 408 inline operator =(shared_future const & other)409 shared_future & operator=( shared_future const& other) noexcept { 410 if ( BOOST_LIKELY( this != & other) ) { 411 base_type::operator=( other); 412 } 413 return * this; 414 } 415 416 inline operator =(shared_future && other)417 shared_future & operator=( shared_future && other) noexcept { 418 if ( BOOST_LIKELY( this != & other) ) { 419 base_type::operator=( std::move( other) ); 420 } 421 return * this; 422 } 423 424 inline operator =(future<void> && other)425 shared_future & operator=( future< void > && other) noexcept { 426 base_type::operator=( std::move( other) ); 427 return * this; 428 } 429 430 inline get() const431 void get() const { 432 if ( BOOST_UNLIKELY( ! valid() ) ) { 433 throw future_uninitialized{}; 434 } 435 base_type::state_->get(); 436 } 437 438 using base_type::valid; 439 using base_type::get_exception_ptr; 440 using base_type::wait; 441 using base_type::wait_for; 442 using base_type::wait_until; 443 }; 444 445 446 template< typename R > 447 shared_future< R > share()448future< R >::share() { 449 if ( BOOST_UNLIKELY( ! base_type::valid() ) ) { 450 throw future_uninitialized{}; 451 } 452 return shared_future< R >{ std::move( * this) }; 453 } 454 455 template< typename R > 456 shared_future< R & > share()457future< R & >::share() { 458 if ( BOOST_UNLIKELY( ! base_type::valid() ) ) { 459 throw future_uninitialized{}; 460 } 461 return shared_future< R & >{ std::move( * this) }; 462 } 463 464 inline 465 shared_future< void > share()466future< void >::share() { 467 if ( BOOST_UNLIKELY( ! base_type::valid() ) ) { 468 throw future_uninitialized{}; 469 } 470 return shared_future< void >{ std::move( * this) }; 471 } 472 473 }} 474 475 #endif 476