stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FIBERS_ASYNC_HPP
|
||||
#define BOOST_FIBERS_ASYNC_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/future/future.hpp>
|
||||
#include <boost/fiber/future/packaged_task.hpp>
|
||||
#include <boost/fiber/policy.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
template< typename Fn, typename ... Args >
|
||||
future<
|
||||
typename std::result_of<
|
||||
typename std::enable_if<
|
||||
! detail::is_launch_policy< typename std::decay< Fn >::type >::value,
|
||||
typename std::decay< Fn >::type
|
||||
>::type( typename std::decay< Args >::type ... )
|
||||
>::type
|
||||
>
|
||||
async( Fn && fn, Args && ... args) {
|
||||
typedef typename std::result_of<
|
||||
typename std::decay< Fn >::type( typename std::decay< Args >::type ... )
|
||||
>::type result_type;
|
||||
|
||||
packaged_task< result_type( typename std::decay< Args >::type ... ) > pt{
|
||||
std::forward< Fn >( fn) };
|
||||
future< result_type > f{ pt.get_future() };
|
||||
fiber{ std::move( pt), std::forward< Args >( args) ... }.detach();
|
||||
return f;
|
||||
}
|
||||
|
||||
template< typename Policy, typename Fn, typename ... Args >
|
||||
future<
|
||||
typename std::result_of<
|
||||
typename std::enable_if<
|
||||
detail::is_launch_policy< Policy >::value,
|
||||
typename std::decay< Fn >::type
|
||||
>::type( typename std::decay< Args >::type ...)
|
||||
>::type
|
||||
>
|
||||
async( Policy policy, Fn && fn, Args && ... args) {
|
||||
typedef typename std::result_of<
|
||||
typename std::decay< Fn >::type( typename std::decay< Args >::type ... )
|
||||
>::type result_type;
|
||||
|
||||
packaged_task< result_type( typename std::decay< Args >::type ... ) > pt{
|
||||
std::forward< Fn >( fn) };
|
||||
future< result_type > f{ pt.get_future() };
|
||||
fiber{ policy, std::move( pt), std::forward< Args >( args) ... }.detach();
|
||||
return f;
|
||||
}
|
||||
|
||||
template< typename Policy, typename StackAllocator, typename Fn, typename ... Args >
|
||||
future<
|
||||
typename std::result_of<
|
||||
typename std::enable_if<
|
||||
detail::is_launch_policy< Policy >::value,
|
||||
typename std::decay< Fn >::type
|
||||
>::type( typename std::decay< Args >::type ... )
|
||||
>::type
|
||||
>
|
||||
async( Policy policy, std::allocator_arg_t, StackAllocator salloc, Fn && fn, Args && ... args) {
|
||||
typedef typename std::result_of<
|
||||
typename std::decay< Fn >::type( typename std::decay< Args >::type ... )
|
||||
>::type result_type;
|
||||
|
||||
packaged_task< result_type( typename std::decay< Args >::type ... ) > pt{
|
||||
std::forward< Fn >( fn) };
|
||||
future< result_type > f{ pt.get_future() };
|
||||
fiber{ policy, std::allocator_arg, salloc,
|
||||
std::move( pt), std::forward< Args >( args) ... }.detach();
|
||||
return f;
|
||||
}
|
||||
|
||||
template< typename Policy, typename StackAllocator, typename Allocator, typename Fn, typename ... Args >
|
||||
future<
|
||||
typename std::result_of<
|
||||
typename std::enable_if<
|
||||
detail::is_launch_policy< Policy >::value,
|
||||
typename std::decay< Fn >::type
|
||||
>::type( typename std::decay< Args >::type ... )
|
||||
>::type
|
||||
>
|
||||
async( Policy policy, std::allocator_arg_t, StackAllocator salloc, Allocator alloc, Fn && fn, Args && ... args) {
|
||||
typedef typename std::result_of<
|
||||
typename std::decay< Fn >::type( typename std::decay< Args >::type ... )
|
||||
>::type result_type;
|
||||
|
||||
packaged_task< result_type( typename std::decay< Args >::type ... ) > pt{
|
||||
std::allocator_arg, alloc, std::forward< Fn >( fn) };
|
||||
future< result_type > f{ pt.get_future() };
|
||||
fiber{ policy, std::allocator_arg, salloc,
|
||||
std::move( pt), std::forward< Args >( args) ... }.detach();
|
||||
return f;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif // BOOST_FIBERS_ASYNC_HPP
|
||||
@@ -0,0 +1,313 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_SHARED_STATE_H
|
||||
#define BOOST_FIBERS_DETAIL_SHARED_STATE_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/future/future_status.hpp>
|
||||
#include <boost/fiber/condition_variable.hpp>
|
||||
#include <boost/fiber/exceptions.hpp>
|
||||
#include <boost/fiber/mutex.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
class shared_state_base {
|
||||
private:
|
||||
std::atomic< std::size_t > use_count_{ 0 };
|
||||
mutable condition_variable waiters_{};
|
||||
|
||||
protected:
|
||||
mutable mutex mtx_{};
|
||||
bool ready_{ false };
|
||||
std::exception_ptr except_{};
|
||||
|
||||
void mark_ready_and_notify_( std::unique_lock< mutex > & lk) noexcept {
|
||||
BOOST_ASSERT( lk.owns_lock() );
|
||||
ready_ = true;
|
||||
lk.unlock();
|
||||
waiters_.notify_all();
|
||||
}
|
||||
|
||||
void owner_destroyed_( std::unique_lock< mutex > & lk) {
|
||||
BOOST_ASSERT( lk.owns_lock() );
|
||||
if ( ! ready_) {
|
||||
set_exception_(
|
||||
std::make_exception_ptr( broken_promise() ),
|
||||
lk);
|
||||
}
|
||||
}
|
||||
|
||||
void set_exception_( std::exception_ptr except, std::unique_lock< mutex > & lk) {
|
||||
BOOST_ASSERT( lk.owns_lock() );
|
||||
if ( ready_) {
|
||||
throw promise_already_satisfied();
|
||||
}
|
||||
except_ = except;
|
||||
mark_ready_and_notify_( lk);
|
||||
}
|
||||
|
||||
std::exception_ptr get_exception_ptr_( std::unique_lock< mutex > & lk) {
|
||||
BOOST_ASSERT( lk.owns_lock() );
|
||||
wait_( lk);
|
||||
return except_;
|
||||
}
|
||||
|
||||
void wait_( std::unique_lock< mutex > & lk) const {
|
||||
BOOST_ASSERT( lk.owns_lock() );
|
||||
waiters_.wait( lk, [this](){ return ready_; });
|
||||
}
|
||||
|
||||
template< typename Rep, typename Period >
|
||||
future_status wait_for_( std::unique_lock< mutex > & lk,
|
||||
std::chrono::duration< Rep, Period > const& timeout_duration) const {
|
||||
BOOST_ASSERT( lk.owns_lock() );
|
||||
return waiters_.wait_for( lk, timeout_duration, [this](){ return ready_; })
|
||||
? future_status::ready
|
||||
: future_status::timeout;
|
||||
}
|
||||
|
||||
template< typename Clock, typename Duration >
|
||||
future_status wait_until_( std::unique_lock< mutex > & lk,
|
||||
std::chrono::time_point< Clock, Duration > const& timeout_time) const {
|
||||
BOOST_ASSERT( lk.owns_lock() );
|
||||
return waiters_.wait_until( lk, timeout_time, [this](){ return ready_; })
|
||||
? future_status::ready
|
||||
: future_status::timeout;
|
||||
}
|
||||
|
||||
virtual void deallocate_future() noexcept = 0;
|
||||
|
||||
public:
|
||||
shared_state_base() = default;
|
||||
|
||||
virtual ~shared_state_base() = default;
|
||||
|
||||
shared_state_base( shared_state_base const&) = delete;
|
||||
shared_state_base & operator=( shared_state_base const&) = delete;
|
||||
|
||||
void owner_destroyed() {
|
||||
std::unique_lock< mutex > lk{ mtx_ };
|
||||
owner_destroyed_( lk);
|
||||
}
|
||||
|
||||
void set_exception( std::exception_ptr except) {
|
||||
std::unique_lock< mutex > lk{ mtx_ };
|
||||
set_exception_( except, lk);
|
||||
}
|
||||
|
||||
std::exception_ptr get_exception_ptr() {
|
||||
std::unique_lock< mutex > lk{ mtx_ };
|
||||
return get_exception_ptr_( lk);
|
||||
}
|
||||
|
||||
void wait() const {
|
||||
std::unique_lock< mutex > lk{ mtx_ };
|
||||
wait_( lk);
|
||||
}
|
||||
|
||||
template< typename Rep, typename Period >
|
||||
future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const {
|
||||
std::unique_lock< mutex > lk{ mtx_ };
|
||||
return wait_for_( lk, timeout_duration);
|
||||
}
|
||||
|
||||
template< typename Clock, typename Duration >
|
||||
future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const {
|
||||
std::unique_lock< mutex > lk{ mtx_ };
|
||||
return wait_until_( lk, timeout_time);
|
||||
}
|
||||
|
||||
friend inline
|
||||
void intrusive_ptr_add_ref( shared_state_base * p) noexcept {
|
||||
p->use_count_.fetch_add( 1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
friend inline
|
||||
void intrusive_ptr_release( shared_state_base * p) noexcept {
|
||||
if ( 1 == p->use_count_.fetch_sub( 1, std::memory_order_release) ) {
|
||||
std::atomic_thread_fence( std::memory_order_acquire);
|
||||
p->deallocate_future();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template< typename R >
|
||||
class shared_state : public shared_state_base {
|
||||
private:
|
||||
typename std::aligned_storage< sizeof( R), alignof( R) >::type storage_{};
|
||||
|
||||
void set_value_( R const& value, std::unique_lock< mutex > & lk) {
|
||||
BOOST_ASSERT( lk.owns_lock() );
|
||||
if ( ready_) {
|
||||
throw promise_already_satisfied{};
|
||||
}
|
||||
::new ( static_cast< void * >( std::addressof( storage_) ) ) R{ value };
|
||||
mark_ready_and_notify_( lk);
|
||||
}
|
||||
|
||||
void set_value_( R && value, std::unique_lock< mutex > & lk) {
|
||||
BOOST_ASSERT( lk.owns_lock() );
|
||||
if ( ready_) {
|
||||
throw promise_already_satisfied{};
|
||||
}
|
||||
::new ( static_cast< void * >( std::addressof( storage_) ) ) R{ std::move( value) };
|
||||
mark_ready_and_notify_( lk);
|
||||
}
|
||||
|
||||
R & get_( std::unique_lock< mutex > & lk) {
|
||||
BOOST_ASSERT( lk.owns_lock() );
|
||||
wait_( lk);
|
||||
if ( except_) {
|
||||
std::rethrow_exception( except_);
|
||||
}
|
||||
return * reinterpret_cast< R * >( std::addressof( storage_) );
|
||||
}
|
||||
|
||||
public:
|
||||
typedef intrusive_ptr< shared_state > ptr_type;
|
||||
|
||||
shared_state() = default;
|
||||
|
||||
virtual ~shared_state() {
|
||||
if ( ready_ && ! except_) {
|
||||
reinterpret_cast< R * >( std::addressof( storage_) )->~R();
|
||||
}
|
||||
}
|
||||
|
||||
shared_state( shared_state const&) = delete;
|
||||
shared_state & operator=( shared_state const&) = delete;
|
||||
|
||||
void set_value( R const& value) {
|
||||
std::unique_lock< mutex > lk{ mtx_ };
|
||||
set_value_( value, lk);
|
||||
}
|
||||
|
||||
void set_value( R && value) {
|
||||
std::unique_lock< mutex > lk{ mtx_ };
|
||||
set_value_( std::move( value), lk);
|
||||
}
|
||||
|
||||
R & get() {
|
||||
std::unique_lock< mutex > lk{ mtx_ };
|
||||
return get_( lk);
|
||||
}
|
||||
};
|
||||
|
||||
template< typename R >
|
||||
class shared_state< R & > : public shared_state_base {
|
||||
private:
|
||||
R * value_{ nullptr };
|
||||
|
||||
void set_value_( R & value, std::unique_lock< mutex > & lk) {
|
||||
BOOST_ASSERT( lk.owns_lock() );
|
||||
if ( ready_) {
|
||||
throw promise_already_satisfied();
|
||||
}
|
||||
value_ = std::addressof( value);
|
||||
mark_ready_and_notify_( lk);
|
||||
}
|
||||
|
||||
R & get_( std::unique_lock< mutex > & lk) {
|
||||
BOOST_ASSERT( lk.owns_lock() );
|
||||
wait_( lk);
|
||||
if ( except_) {
|
||||
std::rethrow_exception( except_);
|
||||
}
|
||||
return * value_;
|
||||
}
|
||||
|
||||
public:
|
||||
typedef intrusive_ptr< shared_state > ptr_type;
|
||||
|
||||
shared_state() = default;
|
||||
|
||||
virtual ~shared_state() = default;
|
||||
|
||||
shared_state( shared_state const&) = delete;
|
||||
shared_state & operator=( shared_state const&) = delete;
|
||||
|
||||
void set_value( R & value) {
|
||||
std::unique_lock< mutex > lk{ mtx_ };
|
||||
set_value_( value, lk);
|
||||
}
|
||||
|
||||
R & get() {
|
||||
std::unique_lock< mutex > lk{ mtx_ };
|
||||
return get_( lk);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class shared_state< void > : public shared_state_base {
|
||||
private:
|
||||
inline
|
||||
void set_value_( std::unique_lock< mutex > & lk) {
|
||||
BOOST_ASSERT( lk.owns_lock() );
|
||||
if ( ready_) {
|
||||
throw promise_already_satisfied();
|
||||
}
|
||||
mark_ready_and_notify_( lk);
|
||||
}
|
||||
|
||||
inline
|
||||
void get_( std::unique_lock< mutex > & lk) {
|
||||
BOOST_ASSERT( lk.owns_lock() );
|
||||
wait_( lk);
|
||||
if ( except_) {
|
||||
std::rethrow_exception( except_);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
typedef intrusive_ptr< shared_state > ptr_type;
|
||||
|
||||
shared_state() = default;
|
||||
|
||||
virtual ~shared_state() = default;
|
||||
|
||||
shared_state( shared_state const&) = delete;
|
||||
shared_state & operator=( shared_state const&) = delete;
|
||||
|
||||
inline
|
||||
void set_value() {
|
||||
std::unique_lock< mutex > lk{ mtx_ };
|
||||
set_value_( lk);
|
||||
}
|
||||
|
||||
inline
|
||||
void get() {
|
||||
std::unique_lock< mutex > lk{ mtx_ };
|
||||
get_( lk);
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_SHARED_STATE_H
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_SHARED_STATE_OBJECT_H
|
||||
#define BOOST_FIBERS_DETAIL_SHARED_STATE_OBJECT_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/future/detail/shared_state.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
template< typename R, typename Allocator >
|
||||
class shared_state_object : public shared_state< R > {
|
||||
public:
|
||||
typedef typename std::allocator_traits< Allocator >::template rebind_alloc<
|
||||
shared_state_object
|
||||
> allocator_type;
|
||||
|
||||
shared_state_object( allocator_type const& alloc) :
|
||||
shared_state< R >{},
|
||||
alloc_{ alloc } {
|
||||
}
|
||||
|
||||
protected:
|
||||
void deallocate_future() noexcept override final {
|
||||
destroy_( alloc_, this);
|
||||
}
|
||||
|
||||
private:
|
||||
allocator_type alloc_;
|
||||
|
||||
static void destroy_( allocator_type const& alloc, shared_state_object * p) noexcept {
|
||||
allocator_type a{ alloc };
|
||||
a.destroy( p);
|
||||
a.deallocate( p, 1);
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_SHARED_STATE_OBJECT_H
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_TASK_BASE_H
|
||||
#define BOOST_FIBERS_DETAIL_TASK_BASE_H
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/future/detail/shared_state.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
template< typename R, typename ... Args >
|
||||
struct task_base : public shared_state< R > {
|
||||
typedef intrusive_ptr< task_base > ptr_type;
|
||||
|
||||
virtual ~task_base() {
|
||||
}
|
||||
|
||||
virtual void run( Args && ... args) = 0;
|
||||
|
||||
virtual ptr_type reset() = 0;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_TASK_BASE_H
|
||||
@@ -0,0 +1,170 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_TASK_OBJECT_H
|
||||
#define BOOST_FIBERS_DETAIL_TASK_OBJECT_H
|
||||
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_NO_CXX17_STD_APPLY)
|
||||
#include <boost/context/detail/apply.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/future/detail/task_base.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
template< typename Fn, typename Allocator, typename R, typename ... Args >
|
||||
class task_object : public task_base< R, Args ... > {
|
||||
private:
|
||||
typedef task_base< R, Args ... > base_type;
|
||||
|
||||
public:
|
||||
typedef typename std::allocator_traits< Allocator >::template rebind_alloc<
|
||||
task_object
|
||||
> allocator_type;
|
||||
|
||||
task_object( allocator_type const& alloc, Fn const& fn) :
|
||||
base_type{},
|
||||
fn_{ fn },
|
||||
alloc_{ alloc } {
|
||||
}
|
||||
|
||||
task_object( allocator_type const& alloc, Fn && fn) :
|
||||
base_type{},
|
||||
fn_{ std::move( fn) },
|
||||
alloc_{ alloc } {
|
||||
}
|
||||
|
||||
void run( Args && ... args) override final {
|
||||
try {
|
||||
this->set_value(
|
||||
#if defined(BOOST_NO_CXX17_STD_APPLY)
|
||||
boost::context::detail::apply(
|
||||
fn_, std::make_tuple( std::forward< Args >( args) ... ) )
|
||||
#else
|
||||
std::apply(
|
||||
fn_, std::make_tuple( std::forward< Args >( args) ... ) )
|
||||
#endif
|
||||
);
|
||||
} catch (...) {
|
||||
this->set_exception( std::current_exception() );
|
||||
}
|
||||
}
|
||||
|
||||
typename base_type::ptr_type reset() override final {
|
||||
typedef std::allocator_traits< allocator_type > traity_type;
|
||||
|
||||
typename traity_type::pointer ptr{ traity_type::allocate( alloc_, 1) };
|
||||
try {
|
||||
traity_type::construct( alloc_, ptr, alloc_, std::move( fn_) );
|
||||
} catch (...) {
|
||||
traity_type::deallocate( alloc_, ptr, 1);
|
||||
throw;
|
||||
}
|
||||
return { convert( ptr) };
|
||||
}
|
||||
|
||||
protected:
|
||||
void deallocate_future() noexcept override final {
|
||||
destroy_( alloc_, this);
|
||||
}
|
||||
|
||||
private:
|
||||
Fn fn_;
|
||||
allocator_type alloc_;
|
||||
|
||||
static void destroy_( allocator_type const& alloc, task_object * p) noexcept {
|
||||
allocator_type a{ alloc };
|
||||
a.destroy( p);
|
||||
a.deallocate( p, 1);
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Fn, typename Allocator, typename ... Args >
|
||||
class task_object< Fn, Allocator, void, Args ... > : public task_base< void, Args ... > {
|
||||
private:
|
||||
typedef task_base< void, Args ... > base_type;
|
||||
|
||||
public:
|
||||
typedef typename Allocator::template rebind<
|
||||
task_object< Fn, Allocator, void, Args ... >
|
||||
>::other allocator_type;
|
||||
|
||||
task_object( allocator_type const& alloc, Fn const& fn) :
|
||||
base_type{},
|
||||
fn_{ fn },
|
||||
alloc_{ alloc } {
|
||||
}
|
||||
|
||||
task_object( allocator_type const& alloc, Fn && fn) :
|
||||
base_type{},
|
||||
fn_{ std::move( fn) },
|
||||
alloc_{ alloc } {
|
||||
}
|
||||
|
||||
void run( Args && ... args) override final {
|
||||
try {
|
||||
#if defined(BOOST_NO_CXX17_STD_APPLY)
|
||||
boost::context::detail::apply(
|
||||
fn_, std::make_tuple( std::forward< Args >( args) ... ) );
|
||||
#else
|
||||
std::apply(
|
||||
fn_, std::make_tuple( std::forward< Args >( args) ... ) );
|
||||
#endif
|
||||
this->set_value();
|
||||
} catch (...) {
|
||||
this->set_exception( std::current_exception() );
|
||||
}
|
||||
}
|
||||
|
||||
typename base_type::ptr_type reset() override final {
|
||||
typedef std::allocator_traits< allocator_type > traity_type;
|
||||
|
||||
typename traity_type::pointer ptr{ traity_type::allocate( alloc_, 1) };
|
||||
try {
|
||||
traity_type::construct( alloc_, ptr, alloc_, std::move( fn_) );
|
||||
} catch (...) {
|
||||
traity_type::deallocate( alloc_, ptr, 1);
|
||||
throw;
|
||||
}
|
||||
return { convert( ptr) };
|
||||
}
|
||||
|
||||
protected:
|
||||
void deallocate_future() noexcept override final {
|
||||
destroy_( alloc_, this);
|
||||
}
|
||||
|
||||
private:
|
||||
Fn fn_;
|
||||
allocator_type alloc_;
|
||||
|
||||
static void destroy_( allocator_type const& alloc, task_object * p) noexcept {
|
||||
allocator_type a{ alloc };
|
||||
a.destroy( p);
|
||||
a.deallocate( p, 1);
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_TASK_OBJECT_H
|
||||
@@ -0,0 +1,474 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FIBERS_FUTURE_HPP
|
||||
#define BOOST_FIBERS_FUTURE_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/exceptions.hpp>
|
||||
#include <boost/fiber/future/detail/shared_state.hpp>
|
||||
#include <boost/fiber/future/future_status.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
template< typename R >
|
||||
struct future_base {
|
||||
typedef typename shared_state< R >::ptr_type ptr_type;
|
||||
|
||||
ptr_type state_{};
|
||||
|
||||
future_base() = default;
|
||||
|
||||
explicit future_base( ptr_type const& p) noexcept :
|
||||
state_{ p } {
|
||||
}
|
||||
|
||||
~future_base() = default;
|
||||
|
||||
future_base( future_base const& other) :
|
||||
state_{ other.state_ } {
|
||||
}
|
||||
|
||||
future_base( future_base && other) noexcept :
|
||||
state_{ other.state_ } {
|
||||
other.state_.reset();
|
||||
}
|
||||
|
||||
future_base & operator=( future_base const& other) noexcept {
|
||||
if ( this != & other) {
|
||||
state_ = other.state_;
|
||||
}
|
||||
return * this;
|
||||
}
|
||||
|
||||
future_base & operator=( future_base && other) noexcept {
|
||||
if ( this != & other) {
|
||||
state_ = other.state_;
|
||||
other.state_.reset();
|
||||
}
|
||||
return * this;
|
||||
}
|
||||
|
||||
bool valid() const noexcept {
|
||||
return nullptr != state_.get();
|
||||
}
|
||||
|
||||
std::exception_ptr get_exception_ptr() {
|
||||
if ( ! valid() ) {
|
||||
throw future_uninitialized{};
|
||||
}
|
||||
return state_->get_exception_ptr();
|
||||
}
|
||||
|
||||
void wait() const {
|
||||
if ( ! valid() ) {
|
||||
throw future_uninitialized{};
|
||||
}
|
||||
state_->wait();
|
||||
}
|
||||
|
||||
template< typename Rep, typename Period >
|
||||
future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const {
|
||||
if ( ! valid() ) {
|
||||
throw future_uninitialized{};
|
||||
}
|
||||
return state_->wait_for( timeout_duration);
|
||||
}
|
||||
|
||||
template< typename Clock, typename Duration >
|
||||
future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const {
|
||||
if ( ! valid() ) {
|
||||
throw future_uninitialized{};
|
||||
}
|
||||
return state_->wait_until( timeout_time);
|
||||
}
|
||||
};
|
||||
|
||||
template< typename R >
|
||||
struct promise_base;
|
||||
|
||||
}
|
||||
|
||||
template< typename R >
|
||||
class shared_future;
|
||||
|
||||
template< typename Signature >
|
||||
class packaged_task;
|
||||
|
||||
template< typename R >
|
||||
class future : private detail::future_base< R > {
|
||||
private:
|
||||
typedef detail::future_base< R > base_type;
|
||||
|
||||
friend struct detail::promise_base< R >;
|
||||
friend class shared_future< R >;
|
||||
template< typename Signature >
|
||||
friend class packaged_task;
|
||||
|
||||
explicit future( typename base_type::ptr_type const& p) noexcept :
|
||||
base_type{ p } {
|
||||
}
|
||||
|
||||
public:
|
||||
future() = default;
|
||||
|
||||
future( future const&) = delete;
|
||||
future & operator=( future const&) = delete;
|
||||
|
||||
future( future && other) noexcept :
|
||||
base_type{ std::move( other) } {
|
||||
}
|
||||
|
||||
future & operator=( future && other) noexcept {
|
||||
if ( this != & other) {
|
||||
base_type::operator=( std::move( other) );
|
||||
}
|
||||
return * this;
|
||||
}
|
||||
|
||||
shared_future< R > share();
|
||||
|
||||
R get() {
|
||||
if ( ! base_type::valid() ) {
|
||||
throw future_uninitialized{};
|
||||
}
|
||||
typename base_type::ptr_type tmp{};
|
||||
tmp.swap( base_type::state_);
|
||||
return std::move( tmp->get() );
|
||||
}
|
||||
|
||||
using base_type::valid;
|
||||
using base_type::get_exception_ptr;
|
||||
using base_type::wait;
|
||||
using base_type::wait_for;
|
||||
using base_type::wait_until;
|
||||
};
|
||||
|
||||
template< typename R >
|
||||
class future< R & > : private detail::future_base< R & > {
|
||||
private:
|
||||
typedef detail::future_base< R & > base_type;
|
||||
|
||||
friend struct detail::promise_base< R & >;
|
||||
friend class shared_future< R & >;
|
||||
template< typename Signature >
|
||||
friend class packaged_task;
|
||||
|
||||
explicit future( typename base_type::ptr_type const& p) noexcept :
|
||||
base_type{ p } {
|
||||
}
|
||||
|
||||
public:
|
||||
future() = default;
|
||||
|
||||
future( future const&) = delete;
|
||||
future & operator=( future const&) = delete;
|
||||
|
||||
future( future && other) noexcept :
|
||||
base_type{ std::move( other) } {
|
||||
}
|
||||
|
||||
future & operator=( future && other) noexcept {
|
||||
if ( this != & other) {
|
||||
base_type::operator=( std::move( other) );
|
||||
}
|
||||
return * this;
|
||||
}
|
||||
|
||||
shared_future< R & > share();
|
||||
|
||||
R & get() {
|
||||
if ( ! base_type::valid() ) {
|
||||
throw future_uninitialized{};
|
||||
}
|
||||
typename base_type::ptr_type tmp{};
|
||||
tmp.swap( base_type::state_);
|
||||
return tmp->get();
|
||||
}
|
||||
|
||||
using base_type::valid;
|
||||
using base_type::get_exception_ptr;
|
||||
using base_type::wait;
|
||||
using base_type::wait_for;
|
||||
using base_type::wait_until;
|
||||
};
|
||||
|
||||
template<>
|
||||
class future< void > : private detail::future_base< void > {
|
||||
private:
|
||||
typedef detail::future_base< void > base_type;
|
||||
|
||||
friend struct detail::promise_base< void >;
|
||||
friend class shared_future< void >;
|
||||
template< typename Signature >
|
||||
friend class packaged_task;
|
||||
|
||||
explicit future( base_type::ptr_type const& p) noexcept :
|
||||
base_type{ p } {
|
||||
}
|
||||
|
||||
public:
|
||||
future() = default;
|
||||
|
||||
future( future const&) = delete;
|
||||
future & operator=( future const&) = delete;
|
||||
|
||||
inline
|
||||
future( future && other) noexcept :
|
||||
base_type{ std::move( other) } {
|
||||
}
|
||||
|
||||
inline
|
||||
future & operator=( future && other) noexcept {
|
||||
if ( this != & other) {
|
||||
base_type::operator=( std::move( other) );
|
||||
}
|
||||
return * this;
|
||||
}
|
||||
|
||||
shared_future< void > share();
|
||||
|
||||
inline
|
||||
void get() {
|
||||
if ( ! base_type::valid() ) {
|
||||
throw future_uninitialized{};
|
||||
}
|
||||
base_type::ptr_type tmp{};
|
||||
tmp.swap( base_type::state_);
|
||||
tmp->get();
|
||||
}
|
||||
|
||||
using base_type::valid;
|
||||
using base_type::get_exception_ptr;
|
||||
using base_type::wait;
|
||||
using base_type::wait_for;
|
||||
using base_type::wait_until;
|
||||
};
|
||||
|
||||
|
||||
template< typename R >
|
||||
class shared_future : private detail::future_base< R > {
|
||||
private:
|
||||
typedef detail::future_base< R > base_type;
|
||||
|
||||
explicit shared_future( typename base_type::ptr_type const& p) noexcept :
|
||||
base_type{ p } {
|
||||
}
|
||||
|
||||
public:
|
||||
shared_future() = default;
|
||||
|
||||
~shared_future() = default;
|
||||
|
||||
shared_future( shared_future const& other) :
|
||||
base_type{ other } {
|
||||
}
|
||||
|
||||
shared_future( shared_future && other) noexcept :
|
||||
base_type{ std::move( other) } {
|
||||
}
|
||||
|
||||
shared_future( future< R > && other) noexcept :
|
||||
base_type{ std::move( other) } {
|
||||
}
|
||||
|
||||
shared_future & operator=( shared_future const& other) noexcept {
|
||||
if ( this != & other) {
|
||||
base_type::operator=( other);
|
||||
}
|
||||
return * this;
|
||||
}
|
||||
|
||||
shared_future & operator=( shared_future && other) noexcept {
|
||||
if ( this != & other) {
|
||||
base_type::operator=( std::move( other) );
|
||||
}
|
||||
return * this;
|
||||
}
|
||||
|
||||
shared_future & operator=( future< R > && other) noexcept {
|
||||
base_type::operator=( std::move( other) );
|
||||
return * this;
|
||||
}
|
||||
|
||||
R const& get() const {
|
||||
if ( ! valid() ) {
|
||||
throw future_uninitialized{};
|
||||
}
|
||||
return base_type::state_->get();
|
||||
}
|
||||
|
||||
using base_type::valid;
|
||||
using base_type::get_exception_ptr;
|
||||
using base_type::wait;
|
||||
using base_type::wait_for;
|
||||
using base_type::wait_until;
|
||||
};
|
||||
|
||||
template< typename R >
|
||||
class shared_future< R & > : private detail::future_base< R & > {
|
||||
private:
|
||||
typedef detail::future_base< R & > base_type;
|
||||
|
||||
explicit shared_future( typename base_type::ptr_type const& p) noexcept :
|
||||
base_type{ p } {
|
||||
}
|
||||
|
||||
public:
|
||||
shared_future() = default;
|
||||
|
||||
~shared_future() = default;
|
||||
|
||||
shared_future( shared_future const& other) :
|
||||
base_type{ other } {
|
||||
}
|
||||
|
||||
shared_future( shared_future && other) noexcept :
|
||||
base_type{ std::move( other) } {
|
||||
}
|
||||
|
||||
shared_future( future< R & > && other) noexcept :
|
||||
base_type{ std::move( other) } {
|
||||
}
|
||||
|
||||
shared_future & operator=( shared_future const& other) noexcept {
|
||||
if ( this != & other) {
|
||||
base_type::operator=( other);
|
||||
}
|
||||
return * this;
|
||||
}
|
||||
|
||||
shared_future & operator=( shared_future && other) noexcept {
|
||||
if ( this != & other) {
|
||||
base_type::operator=( std::move( other) );
|
||||
}
|
||||
return * this;
|
||||
}
|
||||
|
||||
shared_future & operator=( future< R & > && other) noexcept {
|
||||
base_type::operator=( std::move( other) );
|
||||
return * this;
|
||||
}
|
||||
|
||||
R & get() const {
|
||||
if ( ! valid() ) {
|
||||
throw future_uninitialized{};
|
||||
}
|
||||
return base_type::state_->get();
|
||||
}
|
||||
|
||||
using base_type::valid;
|
||||
using base_type::get_exception_ptr;
|
||||
using base_type::wait;
|
||||
using base_type::wait_for;
|
||||
using base_type::wait_until;
|
||||
};
|
||||
|
||||
template<>
|
||||
class shared_future< void > : private detail::future_base< void > {
|
||||
private:
|
||||
typedef detail::future_base< void > base_type;
|
||||
|
||||
explicit shared_future( base_type::ptr_type const& p) noexcept :
|
||||
base_type{ p } {
|
||||
}
|
||||
|
||||
public:
|
||||
shared_future() = default;
|
||||
|
||||
~shared_future() = default;
|
||||
|
||||
inline
|
||||
shared_future( shared_future const& other) :
|
||||
base_type{ other } {
|
||||
}
|
||||
|
||||
inline
|
||||
shared_future( shared_future && other) noexcept :
|
||||
base_type{ std::move( other) } {
|
||||
}
|
||||
|
||||
inline
|
||||
shared_future( future< void > && other) noexcept :
|
||||
base_type{ std::move( other) } {
|
||||
}
|
||||
|
||||
inline
|
||||
shared_future & operator=( shared_future const& other) noexcept {
|
||||
if ( this != & other) {
|
||||
base_type::operator=( other);
|
||||
}
|
||||
return * this;
|
||||
}
|
||||
|
||||
inline
|
||||
shared_future & operator=( shared_future && other) noexcept {
|
||||
if ( this != & other) {
|
||||
base_type::operator=( std::move( other) );
|
||||
}
|
||||
return * this;
|
||||
}
|
||||
|
||||
inline
|
||||
shared_future & operator=( future< void > && other) noexcept {
|
||||
base_type::operator=( std::move( other) );
|
||||
return * this;
|
||||
}
|
||||
|
||||
inline
|
||||
void get() const {
|
||||
if ( ! valid() ) {
|
||||
throw future_uninitialized{};
|
||||
}
|
||||
base_type::state_->get();
|
||||
}
|
||||
|
||||
using base_type::valid;
|
||||
using base_type::get_exception_ptr;
|
||||
using base_type::wait;
|
||||
using base_type::wait_for;
|
||||
using base_type::wait_until;
|
||||
};
|
||||
|
||||
|
||||
template< typename R >
|
||||
shared_future< R >
|
||||
future< R >::share() {
|
||||
if ( ! base_type::valid() ) {
|
||||
throw future_uninitialized{};
|
||||
}
|
||||
return shared_future< R >{ std::move( * this) };
|
||||
}
|
||||
|
||||
template< typename R >
|
||||
shared_future< R & >
|
||||
future< R & >::share() {
|
||||
if ( ! base_type::valid() ) {
|
||||
throw future_uninitialized{};
|
||||
}
|
||||
return shared_future< R & >{ std::move( * this) };
|
||||
}
|
||||
|
||||
inline
|
||||
shared_future< void >
|
||||
future< void >::share() {
|
||||
if ( ! base_type::valid() ) {
|
||||
throw future_uninitialized{};
|
||||
}
|
||||
return shared_future< void >{ std::move( * this) };
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FIBERS_FUTURE_STATUS_HPP
|
||||
#define BOOST_FIBERS_FUTURE_STATUS_HPP
|
||||
|
||||
#include <future>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
enum class future_status {
|
||||
ready = 1,
|
||||
timeout,
|
||||
deferred
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif // BOOST_FIBERS_FUTURE_STATUS_HPP
|
||||
@@ -0,0 +1,141 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FIBERS_PACKAGED_TASK_HPP
|
||||
#define BOOST_FIBERS_PACKAGED_TASK_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/detail/convert.hpp>
|
||||
#include <boost/fiber/detail/disable_overload.hpp>
|
||||
#include <boost/fiber/exceptions.hpp>
|
||||
#include <boost/fiber/future/detail/task_base.hpp>
|
||||
#include <boost/fiber/future/detail/task_object.hpp>
|
||||
#include <boost/fiber/future/future.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
template< typename Signature >
|
||||
class packaged_task;
|
||||
|
||||
template< typename R, typename ... Args >
|
||||
class packaged_task< R( Args ... ) > {
|
||||
private:
|
||||
typedef typename detail::task_base< R, Args ... >::ptr_type ptr_type;
|
||||
|
||||
bool obtained_{ false };
|
||||
ptr_type task_{};
|
||||
|
||||
public:
|
||||
packaged_task() = default;
|
||||
|
||||
template< typename Fn,
|
||||
typename = detail::disable_overload< packaged_task, Fn >
|
||||
>
|
||||
explicit packaged_task( Fn && fn) :
|
||||
packaged_task{ std::allocator_arg,
|
||||
std::allocator< packaged_task >{},
|
||||
std::forward< Fn >( fn) } {
|
||||
}
|
||||
|
||||
template< typename Fn,
|
||||
typename Allocator
|
||||
>
|
||||
explicit packaged_task( std::allocator_arg_t, Allocator const& alloc, Fn && fn) {
|
||||
typedef detail::task_object<
|
||||
typename std::decay< Fn >::type, Allocator, R, Args ...
|
||||
> object_type;
|
||||
typedef std::allocator_traits<
|
||||
typename object_type::allocator_type
|
||||
> traits_type;
|
||||
|
||||
typename object_type::allocator_type a{ alloc };
|
||||
typename traits_type::pointer ptr{ traits_type::allocate( a, 1) };
|
||||
try {
|
||||
traits_type::construct( a, ptr, a, std::forward< Fn >( fn) );
|
||||
} catch (...) {
|
||||
traits_type::deallocate( a, ptr, 1);
|
||||
throw;
|
||||
}
|
||||
task_.reset( convert( ptr) );
|
||||
}
|
||||
|
||||
~packaged_task() {
|
||||
if ( task_) {
|
||||
task_->owner_destroyed();
|
||||
}
|
||||
}
|
||||
|
||||
packaged_task( packaged_task const&) = delete;
|
||||
packaged_task & operator=( packaged_task const&) = delete;
|
||||
|
||||
packaged_task( packaged_task && other) noexcept :
|
||||
obtained_{ other.obtained_ },
|
||||
task_{ std::move( other.task_) } {
|
||||
other.obtained_ = false;
|
||||
}
|
||||
|
||||
packaged_task & operator=( packaged_task && other) noexcept {
|
||||
if ( this != & other) {
|
||||
packaged_task tmp{ std::move( other) };
|
||||
swap( tmp);
|
||||
}
|
||||
return * this;
|
||||
}
|
||||
|
||||
void swap( packaged_task & other) noexcept {
|
||||
std::swap( obtained_, other.obtained_);
|
||||
task_.swap( other.task_);
|
||||
}
|
||||
|
||||
bool valid() const noexcept {
|
||||
return nullptr != task_.get();
|
||||
}
|
||||
|
||||
future< R > get_future() {
|
||||
if ( obtained_) {
|
||||
throw future_already_retrieved{};
|
||||
}
|
||||
if ( ! valid() ) {
|
||||
throw packaged_task_uninitialized{};
|
||||
}
|
||||
obtained_ = true;
|
||||
return future< R >{
|
||||
boost::static_pointer_cast< detail::shared_state< R > >( task_) };
|
||||
}
|
||||
|
||||
void operator()( Args ... args) {
|
||||
if ( ! valid() ) {
|
||||
throw packaged_task_uninitialized{};
|
||||
}
|
||||
task_->run( std::forward< Args >( args) ... );
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if ( ! valid() ) {
|
||||
throw packaged_task_uninitialized{};
|
||||
}
|
||||
packaged_task tmp;
|
||||
tmp.task_ = task_;
|
||||
task_ = tmp.task_->reset();
|
||||
obtained_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Signature >
|
||||
void swap( packaged_task< Signature > & l, packaged_task< Signature > & r) noexcept {
|
||||
l.swap( r);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif // BOOST_FIBERS_PACKAGED_TASK_HPP
|
||||
@@ -0,0 +1,220 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FIBERS_PROMISE_HPP
|
||||
#define BOOST_FIBERS_PROMISE_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/detail/convert.hpp>
|
||||
#include <boost/fiber/exceptions.hpp>
|
||||
#include <boost/fiber/future/detail/shared_state.hpp>
|
||||
#include <boost/fiber/future/detail/shared_state_object.hpp>
|
||||
#include <boost/fiber/future/future.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
template< typename R >
|
||||
struct promise_base {
|
||||
typedef typename shared_state< R >::ptr_type ptr_type;
|
||||
|
||||
bool obtained_{ false };
|
||||
ptr_type future_{};
|
||||
|
||||
promise_base() :
|
||||
promise_base{ std::allocator_arg, std::allocator< promise_base >{} } {
|
||||
}
|
||||
|
||||
template< typename Allocator >
|
||||
promise_base( std::allocator_arg_t, Allocator alloc) {
|
||||
typedef detail::shared_state_object< R, Allocator > object_type;
|
||||
typedef std::allocator_traits< typename object_type::allocator_type > traits_type;
|
||||
typename object_type::allocator_type a{ alloc };
|
||||
typename traits_type::pointer ptr{ traits_type::allocate( a, 1) };
|
||||
|
||||
try {
|
||||
traits_type::construct( a, ptr, a);
|
||||
} catch (...) {
|
||||
traits_type::deallocate( a, ptr, 1);
|
||||
throw;
|
||||
}
|
||||
future_.reset( convert( ptr) );
|
||||
}
|
||||
|
||||
~promise_base() {
|
||||
if ( future_) {
|
||||
future_->owner_destroyed();
|
||||
}
|
||||
}
|
||||
|
||||
promise_base( promise_base const&) = delete;
|
||||
promise_base & operator=( promise_base const&) = delete;
|
||||
|
||||
promise_base( promise_base && other) noexcept :
|
||||
obtained_{ other.obtained_ },
|
||||
future_{ std::move( other.future_) } {
|
||||
other.obtained_ = false;
|
||||
}
|
||||
|
||||
promise_base & operator=( promise_base && other) noexcept {
|
||||
if ( this != & other) {
|
||||
promise_base tmp{ std::move( other) };
|
||||
swap( tmp);
|
||||
}
|
||||
return * this;
|
||||
}
|
||||
|
||||
future< R > get_future() {
|
||||
if ( obtained_) {
|
||||
throw future_already_retrieved{};
|
||||
}
|
||||
if ( ! future_) {
|
||||
throw promise_uninitialized{};
|
||||
}
|
||||
obtained_ = true;
|
||||
return future< R >{ future_ };
|
||||
}
|
||||
|
||||
void swap( promise_base & other) noexcept {
|
||||
std::swap( obtained_, other.obtained_);
|
||||
future_.swap( other.future_);
|
||||
}
|
||||
|
||||
void set_exception( std::exception_ptr p) {
|
||||
if ( ! future_) {
|
||||
throw promise_uninitialized{};
|
||||
}
|
||||
future_->set_exception( p);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template< typename R >
|
||||
class promise : private detail::promise_base< R > {
|
||||
private:
|
||||
typedef detail::promise_base< R > base_type;
|
||||
|
||||
public:
|
||||
promise() = default;
|
||||
|
||||
template< typename Allocator >
|
||||
promise( std::allocator_arg_t, Allocator alloc) :
|
||||
base_type{ std::allocator_arg, alloc } {
|
||||
}
|
||||
|
||||
promise( promise const&) = delete;
|
||||
promise & operator=( promise const&) = delete;
|
||||
|
||||
promise( promise && other) noexcept = default;
|
||||
promise & operator=( promise && other) = default;
|
||||
|
||||
void set_value( R const& value) {
|
||||
if ( ! base_type::future_) {
|
||||
throw promise_uninitialized{};
|
||||
}
|
||||
base_type::future_->set_value( value);
|
||||
}
|
||||
|
||||
void set_value( R && value) {
|
||||
if ( ! base_type::future_) {
|
||||
throw promise_uninitialized{};
|
||||
}
|
||||
base_type::future_->set_value( std::move( value) );
|
||||
}
|
||||
|
||||
void swap( promise & other) noexcept {
|
||||
base_type::swap( other);
|
||||
}
|
||||
|
||||
using base_type::get_future;
|
||||
using base_type::set_exception;
|
||||
};
|
||||
|
||||
template< typename R >
|
||||
class promise< R & > : private detail::promise_base< R & > {
|
||||
private:
|
||||
typedef detail::promise_base< R & > base_type;
|
||||
|
||||
public:
|
||||
promise() = default;
|
||||
|
||||
template< typename Allocator >
|
||||
promise( std::allocator_arg_t, Allocator alloc) :
|
||||
base_type{ std::allocator_arg, alloc } {
|
||||
}
|
||||
|
||||
promise( promise const&) = delete;
|
||||
promise & operator=( promise const&) = delete;
|
||||
|
||||
promise( promise && other) noexcept = default;
|
||||
promise & operator=( promise && other) noexcept = default;
|
||||
|
||||
void set_value( R & value) {
|
||||
if ( ! base_type::future_) {
|
||||
throw promise_uninitialized{};
|
||||
}
|
||||
base_type::future_->set_value( value);
|
||||
}
|
||||
|
||||
void swap( promise & other) noexcept {
|
||||
base_type::swap( other);
|
||||
}
|
||||
|
||||
using base_type::get_future;
|
||||
using base_type::set_exception;
|
||||
};
|
||||
|
||||
template<>
|
||||
class promise< void > : private detail::promise_base< void > {
|
||||
private:
|
||||
typedef detail::promise_base< void > base_type;
|
||||
|
||||
public:
|
||||
promise() = default;
|
||||
|
||||
template< typename Allocator >
|
||||
promise( std::allocator_arg_t, Allocator alloc) :
|
||||
base_type{ std::allocator_arg, alloc } {
|
||||
}
|
||||
|
||||
promise( promise const&) = delete;
|
||||
promise & operator=( promise const&) = delete;
|
||||
|
||||
promise( promise && other) noexcept = default;
|
||||
promise & operator=( promise && other) noexcept = default;
|
||||
|
||||
inline
|
||||
void set_value() {
|
||||
if ( ! base_type::future_) {
|
||||
throw promise_uninitialized{};
|
||||
}
|
||||
base_type::future_->set_value();
|
||||
}
|
||||
|
||||
inline
|
||||
void swap( promise & other) noexcept {
|
||||
base_type::swap( other);
|
||||
}
|
||||
|
||||
using base_type::get_future;
|
||||
using base_type::set_exception;
|
||||
};
|
||||
|
||||
template< typename R >
|
||||
void swap( promise< R > & l, promise< R > & r) noexcept {
|
||||
l.swap( r);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif // BOOST_FIBERS_PROMISE_HPP
|
||||
Reference in New Issue
Block a user