| 1 | /*
|
|---|
| 2 | * SPDX-FileCopyrightText: 2019 Jaroslav Jindrak
|
|---|
| 3 | *
|
|---|
| 4 | * SPDX-License-Identifier: BSD-3-Clause
|
|---|
| 5 | */
|
|---|
| 6 |
|
|---|
| 7 | #ifndef LIBCPP_BITS_THREAD_SHARED_FUTURE
|
|---|
| 8 | #define LIBCPP_BITS_THREAD_SHARED_FUTURE
|
|---|
| 9 |
|
|---|
| 10 | #include <__bits/thread/future.hpp>
|
|---|
| 11 | #include <__bits/thread/future_common.hpp>
|
|---|
| 12 | #include <type_traits>
|
|---|
| 13 |
|
|---|
| 14 | /**
|
|---|
| 15 | * Note: We do synchronization directly on the shared
|
|---|
| 16 | * state, this means that with the exception of
|
|---|
| 17 | * some member functions (which are only defined
|
|---|
| 18 | * for specializations anyway) our future and
|
|---|
| 19 | * shared_future are basically identical. Because
|
|---|
| 20 | * of that, we can use aux::future_base for
|
|---|
| 21 | * shared_future as well.
|
|---|
| 22 | */
|
|---|
| 23 |
|
|---|
| 24 | namespace std
|
|---|
| 25 | {
|
|---|
| 26 | /**
|
|---|
| 27 | * 30.6.7, class template shared_future:
|
|---|
| 28 | */
|
|---|
| 29 |
|
|---|
| 30 | template<class R>
|
|---|
| 31 | class shared_future: public aux::future_base<aux::future_inner_t<R>>
|
|---|
| 32 | {
|
|---|
| 33 | public:
|
|---|
| 34 | shared_future() noexcept = default;
|
|---|
| 35 |
|
|---|
| 36 | shared_future(const shared_future&) = default;
|
|---|
| 37 |
|
|---|
| 38 | shared_future(shared_future&&) noexcept = default;
|
|---|
| 39 |
|
|---|
| 40 | shared_future(future<R>&& rhs)
|
|---|
| 41 | : aux::future_base<aux::future_inner_t<R>>{move(rhs.state_)}
|
|---|
| 42 | {
|
|---|
| 43 | rhs.state_ = nullptr;
|
|---|
| 44 | }
|
|---|
| 45 |
|
|---|
| 46 | shared_future& operator=(const shared_future&) = default;
|
|---|
| 47 |
|
|---|
| 48 | shared_future& operator=(shared_future&&) noexcept = default;
|
|---|
| 49 |
|
|---|
| 50 | aux::future_return_shared_t<R> get() const
|
|---|
| 51 | {
|
|---|
| 52 | assert(this->state_);
|
|---|
| 53 |
|
|---|
| 54 | this->wait();
|
|---|
| 55 |
|
|---|
| 56 | if (this->state_->has_exception())
|
|---|
| 57 | this->state_->throw_stored_exception();
|
|---|
| 58 |
|
|---|
| 59 | /**
|
|---|
| 60 | * Using constexpr if and the future_inner and future_result
|
|---|
| 61 | * metafunctions we can actually avoid having to create specializations
|
|---|
| 62 | * for R& and void in this case.
|
|---|
| 63 | */
|
|---|
| 64 | if constexpr (!is_same_v<R, void>)
|
|---|
| 65 | {
|
|---|
| 66 | if constexpr (is_reference_v<R>)
|
|---|
| 67 | {
|
|---|
| 68 | assert(this->state_->get());
|
|---|
| 69 |
|
|---|
| 70 | return *this->state_->get();
|
|---|
| 71 | }
|
|---|
| 72 | else
|
|---|
| 73 | return this->state_->get();
|
|---|
| 74 | }
|
|---|
| 75 | }
|
|---|
| 76 |
|
|---|
| 77 | /**
|
|---|
| 78 | * Useful for testing as we can check some information
|
|---|
| 79 | * otherwise unavailable to us without waiting, e.g.
|
|---|
| 80 | * to check whether the state is ready, its reference
|
|---|
| 81 | * count etc.
|
|---|
| 82 | */
|
|---|
| 83 | aux::shared_state<aux::future_inner_t<R>>* __state() noexcept
|
|---|
| 84 | {
|
|---|
| 85 | return this->state_;
|
|---|
| 86 | }
|
|---|
| 87 | };
|
|---|
| 88 | }
|
|---|
| 89 |
|
|---|
| 90 | #endif
|
|---|