HelenOS sources
This source file includes following definitions.
- swap
- set_exception
- set_exception_at_thread_exit
- __state
- abandon_state_
- get_future
- set_value
- set_value
- set_value_at_thread_exit
- set_value_at_thread_exit
- get_future
- set_value
- set_value_at_thread_exit
- get_future
- set_value
- swap
#ifndef LIBCPP_BITS_THREAD_PROMISE
#define LIBCPP_BITS_THREAD_PROMISE
#include <__bits/exception.hpp>
#include <__bits/memory/allocator_traits.hpp>
#include <__bits/thread/future.hpp>
#include <__bits/thread/shared_state.hpp>
#include <__bits/aux.hpp>
#include <utility>
namespace std
{
namespace aux
{
template<class R>
class promise_base
{
public:
promise_base()
: state_{new aux::shared_state<R>{}}
{ }
template<class Allocator>
promise_base(allocator_arg_t, const Allocator& a)
: state_{}
{
typename allocator_traits<
Allocator
>::template rebind_alloc<aux::shared_state<R>> rebound{a};
state_ = rebound.allocate(1);
rebound.construct(state_);
}
promise_base(promise_base&& rhs) noexcept
: state_{}
{
state_ = rhs.state_;
rhs.state_ = nullptr;
}
promise_base(const promise_base&) = delete;
virtual ~promise_base()
{
this->abandon_state_();
}
promise_base& operator=(promise_base&& rhs) noexcept
{
abandon_state_();
promise_base{move(rhs)}.swap(*this);
return *this;
}
promise_base& operator=(const promise_base&) = delete;
void swap(promise_base& other) noexcept
{
std::swap(state_, other.state_);
}
void set_exception(exception_ptr ptr)
{
assert(state_);
state_->set_exception(ptr);
}
void set_exception_at_thread_exit(exception_ptr ptr)
{
assert(state_);
state_->set_exception_ptr(ptr, false);
aux::set_state_exception_at_thread_exit(state_);
}
aux::shared_state<R>* __state()
{
return state_;
}
protected:
void abandon_state_()
{
if (!state_)
return;
if (!state_->is_set())
{
state_->set_exception(make_exception_ptr(
future_error{make_error_code(future_errc::broken_promise)}
));
state_->mark_set(true);
}
if (state_->decrement())
{
state_->destroy();
delete state_;
state_ = nullptr;
}
}
aux::shared_state<R>* state_;
};
}
template<class R>
class promise: public aux::promise_base<R>
{
public:
promise()
: aux::promise_base<R>{}
{ }
template<class Allocator>
promise(allocator_arg_t tag, const Allocator& a)
: aux::promise_base<R>{tag, a}
{ }
promise(promise&& rhs) noexcept
: aux::promise_base<R>{move(rhs)}
{ }
promise(const promise&) = delete;
~promise() override = default;
promise& operator=(promise&& rhs) noexcept = default;
promise& operator=(const promise&) = delete;
future<R> get_future()
{
assert(this->state_);
this->state_->increment();
return future<R>{this->state_};
}
void set_value(const R& val)
{
if (!this->state_)
throw future_error{make_error_code(future_errc::no_state)};
if (this->state_->is_set())
{
throw future_error{
make_error_code(future_errc::promise_already_satisfied)
};
}
this->state_->set_value(val, true);
}
void set_value(R&& val)
{
if (!this->state_)
throw future_error{make_error_code(future_errc::no_state)};
if (this->state_->is_set())
{
throw future_error{
make_error_code(future_errc::promise_already_satisfied)
};
}
this->state_->set_value(forward<R>(val), true);
}
void set_value_at_thread_exit(const R& val)
{
if (!this->state_)
throw future_error{make_error_code(future_errc::no_state)};
if (this->state_->is_set())
{
throw future_error{
make_error_code(future_errc::promise_already_satisfied)
};
}
try
{
this->state_->set_value(val, false);
aux::set_state_value_at_thread_exit(this->state_);
}
catch(const exception& __exception)
{
this->state_->set_exception(make_exception_ptr(__exception), false);
aux::set_state_exception_at_thread_exit(this->state_);
}
}
void set_value_at_thread_exit(R&& val)
{
if (!this->state_)
throw future_error{make_error_code(future_errc::no_state)};
if (this->state_->is_set())
{
throw future_error{
make_error_code(future_errc::promise_already_satisfied)
};
}
try
{
this->state_->set_value(forward<R>(val), false);
aux::set_state_value_at_thread_exit(this->state_);
}
catch(const exception& __exception)
{
this->state_->set_exception(make_exception_ptr(__exception), false);
aux::set_state_exception_at_thread_exit(this->state_);
}
}
};
template<class R>
class promise<R&>: public aux::promise_base<R*>
{
public:
promise()
: aux::promise_base<R*>{}
{ }
template<class Allocator>
promise(allocator_arg_t tag, const Allocator& a)
: aux::promise_base<R*>{tag, a}
{ }
promise(promise&& rhs) noexcept
: aux::promise_base<R*>{move(rhs)}
{ }
promise(const promise&) = delete;
~promise() override = default;
promise& operator=(promise&& rhs) noexcept = default;
promise& operator=(const promise&) = delete;
future<R&> get_future()
{
assert(this->state_);
this->state_->increment();
return future<R&>{this->state_};
}
void set_value(R& val)
{
if (!this->state_)
throw future_error{make_error_code(future_errc::no_state)};
if (this->state_->is_set())
{
throw future_error{
make_error_code(future_errc::promise_already_satisfied)
};
}
this->state_->set_value(&val, true);
}
void set_value_at_thread_exit(R& val)
{
if (!this->state_)
throw future_error{make_error_code(future_errc::no_state)};
if (this->state_->is_set())
{
throw future_error{
make_error_code(future_errc::promise_already_satisfied)
};
}
try
{
this->state_->set_value(&val, false);
aux::set_state_value_at_thread_exit(this->state_);
}
catch(const exception& __exception)
{
this->state_->set_exception(make_exception_ptr(__exception), false);
aux::set_state_exception_at_thread_exit(this->state_);
}
}
};
template<>
class promise<void>: public aux::promise_base<void>
{
public:
promise()
: aux::promise_base<void>{}
{ }
template<class Allocator>
promise(allocator_arg_t tag, const Allocator& a)
: aux::promise_base<void>{tag, a}
{ }
promise(promise&& rhs) noexcept
: aux::promise_base<void>{move(rhs)}
{ }
promise(const promise&) = delete;
~promise() override = default;
promise& operator=(promise&& rhs) noexcept = default;
promise& operator=(const promise&) = delete;
future<void> get_future()
{
assert(this->state_);
this->state_->increment();
return future<void>{this->state_};
}
void set_value()
{
if (!this->state_)
throw future_error{make_error_code(future_errc::no_state)};
if (this->state_->is_set())
{
throw future_error{
make_error_code(future_errc::promise_already_satisfied)
};
}
this->state_->set_value();
}
};
template<class R>
void swap(promise<R>& lhs, promise<R>& rhs) noexcept
{
lhs.swap(rhs);
}
template<class R, class Alloc>
struct uses_allocator<promise<R>, Alloc>: true_type
{ };
}
#endif
HelenOS homepage, sources at GitHub