2
0
mirror of https://github.com/boostorg/fiber.git synced 2026-02-19 02:12:24 +00:00

use allocator_traits

This commit is contained in:
Oliver Kowalke
2015-12-06 15:53:32 +01:00
parent 117a55d8c6
commit 2d0dbb4fa1
8 changed files with 222 additions and 131 deletions

View File

@@ -37,22 +37,25 @@ public:
private:
struct node {
typedef intrusive_ptr< node > ptr;
typedef typename std::allocator_traits< Allocator >::template rebind_alloc< node > allocator_type;
typedef intrusive_ptr< node > ptr_t;
typedef typename std::allocator_traits< Allocator >::template rebind_alloc<
node
> allocator_t;
typedef std::allocator_traits< allocator_t > allocator_traits_t;
std::size_t use_count{ 0 };
allocator_type & alloc;
T va;
ptr nxt{};
std::size_t use_count{ 0 };
allocator_t alloc;
T va;
ptr_t nxt{};
node( T const& t, allocator_type & alloc_) noexcept :
node( T const& t, allocator_t const& alloc_) noexcept :
alloc{ alloc_ },
va{ t } {
}
node( T && t, allocator_type & alloc_) noexcept :
node( T && t, allocator_t & alloc_) noexcept :
alloc{ alloc_ },
va{ std::forward< T >( t) } {
va{ std::move( t) } {
}
friend
@@ -63,30 +66,32 @@ private:
friend
void intrusive_ptr_release( node * p) noexcept {
if ( 0 == --p->use_count) {
allocator_type & alloc( p->alloc);
std::allocator_traits< allocator_type >::destroy( alloc, p);
std::allocator_traits< allocator_type >::deallocate( alloc, p, 1);
allocator_t alloc( p->alloc);
allocator_traits_t::destroy( alloc, p);
allocator_traits_t::deallocate( alloc, p, 1);
}
}
};
typedef typename std::allocator_traits< Allocator >::template rebind_alloc< node > allocator_type;
using ptr_t = typename node::ptr_t;
using allocator_t = typename node::allocator_t;
using allocator_traits_t = typename node::allocator_traits_t;
enum class queue_status {
open = 0,
closed
};
allocator_type alloc_;
queue_status state_{ queue_status::open };
std::size_t count_{ 0 };
typename node::ptr head_{};
typename node::ptr * tail_;
mutable mutex mtx_{};
condition not_empty_cond_{};
condition not_full_cond_{};
std::size_t hwm_;
std::size_t lwm_;
allocator_t alloc_;
queue_status state_{ queue_status::open };
std::size_t count_{ 0 };
ptr_t head_{};
ptr_t * tail_;
mutable mutex mtx_{};
condition not_empty_cond_{};
condition not_full_cond_{};
std::size_t hwm_;
std::size_t lwm_;
bool is_closed_() const noexcept {
return queue_status::closed == state_;
@@ -111,7 +116,7 @@ private:
return count_ >= hwm_;
}
channel_op_status push_( typename node::ptr const& new_node,
channel_op_status push_( ptr_t new_node,
std::unique_lock< boost::fibers::mutex > & lk) {
if ( is_closed_() ) {
return channel_op_status::closed;
@@ -122,7 +127,7 @@ private:
return push_and_notify_( new_node, lk);
}
channel_op_status try_push_( typename node::ptr const& new_node,
channel_op_status try_push_( ptr_t new_node,
std::unique_lock< boost::fibers::mutex > & lk) noexcept {
if ( is_closed_() ) {
return channel_op_status::closed;
@@ -134,7 +139,7 @@ private:
}
template< typename Clock, typename Duration >
channel_op_status push_wait_until_( typename node::ptr const& new_node,
channel_op_status push_wait_until_( ptr_t new_node,
std::chrono::time_point< Clock, Duration > const& timeout_time,
std::unique_lock< boost::fibers::mutex > & lk) {
if ( is_closed_() ) {
@@ -148,7 +153,7 @@ private:
return push_and_notify_( new_node, lk);
}
channel_op_status push_and_notify_( typename node::ptr const& new_node,
channel_op_status push_and_notify_( ptr_t new_node,
std::unique_lock< boost::fibers::mutex > & lk) noexcept {
push_tail_( new_node);
lk.unlock();
@@ -156,7 +161,7 @@ private:
return channel_op_status::success;
}
void push_tail_( typename node::ptr new_node) noexcept {
void push_tail_( ptr_t new_node) noexcept {
* tail_ = new_node;
tail_ = & new_node->nxt;
++count_;
@@ -179,7 +184,7 @@ private:
return std::move( old_head->va);
}
typename node::ptr pop_head_() noexcept {
ptr_t pop_head_() noexcept {
auto old_head = head_;
head_ = old_head->nxt;
if ( ! head_) {
@@ -236,17 +241,30 @@ public:
}
channel_op_status push( value_type const& va) {
typename node::ptr new_node(
new ( alloc_.allocate( 1) ) node( va, alloc_) );
typename allocator_traits_t::pointer ptr{
allocator_traits_t::allocate( alloc_, 1) };
try {
allocator_traits_t::construct( alloc_, ptr, va, alloc_);
} catch (...) {
allocator_traits_t::deallocate( alloc_, ptr, 1);
throw;
}
std::unique_lock< mutex > lk( mtx_);
return push_( new_node, lk);
return push_( { detail::convert( ptr) }, lk);
}
channel_op_status push( value_type && va) {
typename node::ptr new_node(
new ( alloc_.allocate( 1) ) node( std::forward< value_type >( va), alloc_) );
typename allocator_traits_t::pointer ptr{
allocator_traits_t::allocate( alloc_, 1) };
try {
allocator_traits_t::construct(
alloc_, ptr, std::move( va), alloc_);
} catch (...) {
allocator_traits_t::deallocate( alloc_, ptr, 1);
throw;
}
std::unique_lock< mutex > lk( mtx_);
return push_( new_node, lk);
return push_( { detail::convert( ptr) }, lk);
}
template< typename Rep, typename Period >
@@ -266,33 +284,59 @@ public:
template< typename Clock, typename Duration >
channel_op_status push_wait_until( value_type const& va,
std::chrono::time_point< Clock, Duration > const& timeout_time) {
typename node::ptr new_node(
new ( alloc_.allocate( 1) ) node( va, alloc_) );
typename allocator_traits_t::pointer ptr{
allocator_traits_t::allocate( alloc_, 1) };
try {
allocator_traits_t::construct( alloc_, ptr, va, alloc_);
} catch (...) {
allocator_traits_t::deallocate( alloc_, ptr, 1);
throw;
}
std::unique_lock< mutex > lk( mtx_);
return push_wait_until_( new_node, timeout_time, lk);
return push_wait_until_( { detail::convert( ptr) }, timeout_time, lk);
}
template< typename Clock, typename Duration >
channel_op_status push_wait_until( value_type && va,
std::chrono::time_point< Clock, Duration > const& timeout_time) {
typename node::ptr new_node(
new ( alloc_.allocate( 1) ) node( std::forward< value_type >( va), alloc_) );
typename allocator_traits_t::pointer ptr{
allocator_traits_t::allocate( alloc_, 1) };
try {
allocator_traits_t::construct(
alloc_, ptr, std::move( va), alloc_);
} catch (...) {
allocator_traits_t::deallocate( alloc_, ptr, 1);
throw;
}
std::unique_lock< mutex > lk( mtx_);
return push_wait_until_( new_node, timeout_time, lk);
return push_wait_until_( { detail::convert( ptr) }, timeout_time, lk);
}
channel_op_status try_push( value_type const& va) noexcept {
typename node::ptr new_node(
new ( alloc_.allocate( 1) ) node( va, alloc_) );
typename allocator_traits_t::pointer ptr{
allocator_traits_t::allocate( alloc_, 1) };
try {
allocator_traits_t::construct( alloc_, ptr, va, alloc_);
} catch (...) {
allocator_traits_t::deallocate( alloc_, ptr, 1);
throw;
}
std::unique_lock< mutex > lk( mtx_);
return try_push_( new_node, lk);
return try_push_( { detail::convert( ptr) }, lk);
}
channel_op_status try_push( value_type && va) noexcept {
typename node::ptr new_node(
new ( alloc_.allocate( 1) ) node( std::forward< value_type >( va), alloc_) );
typename allocator_traits_t::pointer ptr{
allocator_traits_t::allocate( alloc_, 1) };
try {
allocator_traits_t::construct(
alloc_, ptr, std::move( va), alloc_);
} catch (...) {
allocator_traits_t::deallocate( alloc_, ptr, 1);
throw;
}
std::unique_lock< mutex > lk( mtx_);
return try_push_( new_node, lk);
return try_push_( { detail::convert( ptr) }, lk);
}
channel_op_status pop( value_type & va) {

View File

@@ -8,6 +8,7 @@
#define BOOST_FIBERS_DETAIL_CONVERT_H
#include <chrono>
#include <memory>
#include <boost/config.hpp>
@@ -33,6 +34,22 @@ std::chrono::steady_clock::time_point convert(
return std::chrono::steady_clock::now() + ( timeout_time - Clock::now() );
}
// suggested by Howard Hinnant
template< typename T >
inline
T * convert( T * p) noexcept {
return p;
}
template< typename Pointer >
inline
typename std::pointer_traits< Pointer >::element_type *
convert( Pointer p) noexcept {
return nullptr != p
? to_raw_pointer( p.operator->() )
: nullptr;
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS

View File

@@ -7,6 +7,8 @@
#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>
@@ -23,9 +25,9 @@ namespace detail {
template< typename R, typename Allocator >
class shared_state_object : public shared_state< R > {
public:
typedef typename Allocator::template rebind<
shared_state_object< R, Allocator >
>::other allocator_t;
typedef typename std::allocator_traits< Allocator >::template rebind_alloc<
shared_state_object
> allocator_t;
shared_state_object( allocator_t const& alloc) :
shared_state< R >(), alloc_( alloc) {

View File

@@ -8,7 +8,8 @@
#define BOOST_FIBERS_DETAIL_TASK_OBJECT_H
#include <exception>
#include <utility> // std::forward()
#include <memory>
#include <utility>
#include <boost/config.hpp>
#include <boost/context/detail/invoke.hpp>
@@ -27,13 +28,13 @@ namespace detail {
template< typename Fn, typename Allocator, typename R, typename ... Args >
class task_object : public task_base< R, Args ... > {
public:
typedef typename Allocator::template rebind<
task_object< Fn, Allocator, R, Args ... >
>::other allocator_t;
typedef typename std::allocator_traits< Allocator >::template rebind_alloc<
task_object
> allocator_t;
explicit task_object( allocator_t const& alloc, Fn && fn) :
task_object( allocator_t const& alloc, Fn && fn) :
task_base< R, Args ... >(),
fn_( std::forward< Fn >( fn) ),
fn_( std::move( fn) ),
alloc_( alloc) {
}
@@ -69,9 +70,9 @@ public:
task_object< Fn, Allocator, void, Args ... >
>::other allocator_t;
explicit task_object( allocator_t const& alloc, Fn && fn) :
task_object( allocator_t const& alloc, Fn && fn) :
task_base< void, Args ... >(),
fn_( std::forward< Fn >( fn) ),
fn_( std::move( fn) ),
alloc_( alloc) {
}

View File

@@ -13,6 +13,7 @@
#include <boost/config.hpp>
#include <boost/fiber/detail/convert.hpp>
#include <boost/fiber/exceptions.hpp>
#include <boost/fiber/future/detail/task_base.hpp>
#include <boost/fiber/future/detail/task_object.hpp>
@@ -42,31 +43,30 @@ public:
}
template< typename Fn >
explicit packaged_task( Fn && fn) {
typedef detail::task_object<
Fn,
std::allocator< packaged_task< R() > >,
R,
Args ...
> object_t;
std::allocator< packaged_task< R() > > alloc;
typename object_t::allocator_t a{ alloc };
task_ = ptr_t{
// placement new
::new( a.allocate( 1) ) object_t{ a, std::forward< Fn >( 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) {
packaged_task( std::allocator_arg_t, Allocator const& alloc, Fn && fn) {
typedef detail::task_object<
Fn,
Allocator,
R
Fn, Allocator, R, Args ...
> object_t;
typedef std::allocator_traits<
typename object_t::allocator_t
> traits_t;
typename object_t::allocator_t a{ alloc };
task_ = ptr_t{
// placement new
::new( a.allocate( 1) ) object_t{ a, std::forward< Fn >( fn) } };
typename traits_t::pointer ptr{ traits_t::allocate( a, 1) };
try {
traits_t::construct( a, ptr, a, std::forward< Fn >( fn) );
} catch (...) {
traits_t::deallocate( a, ptr, 1);
throw;
}
task_.reset( convert( ptr) );
}
packaged_task( packaged_task const&) = delete;

View File

@@ -13,6 +13,7 @@
#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>
@@ -36,10 +37,17 @@ struct promise_base {
template< typename Allocator >
promise_base( std::allocator_arg_t, Allocator alloc) {
typedef detail::shared_state_object< R, Allocator > object_t;
typedef std::allocator_traits< typename object_t::allocator_t > traits_t;
typename object_t::allocator_t a{ alloc };
future_ = ptr_t{
// placement new
::new( a.allocate( 1) ) object_t{ a } };
typename traits_t::pointer ptr{ traits_t::allocate( a, 1) };
try {
traits_t::construct( a, ptr, a);
} catch (...) {
traits_t::deallocate( a, ptr, 1);
throw;
}
future_.reset( convert( ptr) );
}
~promise_base() {

View File

@@ -8,18 +8,19 @@
#ifndef BOOST_FIBERS_UNBOUNDED_CHANNEL_H
#define BOOST_FIBERS_UNBOUNDED_CHANNEL_H
#include <algorithm> // std::move()
#include <algorithm>
#include <chrono>
#include <cstddef>
#include <memory> // std::allocator
#include <mutex> // std::unique_lock
#include <utility> // std::forward()
#include <memory>
#include <mutex>
#include <utility>
#include <boost/config.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/fiber/channel_op_status.hpp>
#include <boost/fiber/condition.hpp>
#include <boost/fiber/detail/convert.hpp>
#include <boost/fiber/exceptions.hpp>
#include <boost/fiber/mutex.hpp>
#include <boost/fiber/operations.hpp>
@@ -38,22 +39,25 @@ public:
private:
struct node {
typedef intrusive_ptr< node > ptr;
typedef typename std::allocator_traits< Allocator >::template rebind_alloc< node > allocator_type;
typedef intrusive_ptr< node > ptr_t;
typedef typename std::allocator_traits< Allocator >::template rebind_alloc<
node
> allocator_t;
typedef std::allocator_traits< allocator_t > allocator_traits_t;
std::size_t use_count{ 0 };
allocator_type & alloc;
T va;
ptr nxt{};
std::size_t use_count{ 0 };
allocator_t alloc;
T va;
ptr_t nxt{};
node( T const& t, allocator_type & alloc_) noexcept :
node( T const& t, allocator_t const& alloc_) noexcept :
alloc{ alloc_ },
va{ t } {
}
node( T && t, allocator_type & alloc_) noexcept :
node( T && t, allocator_t const& alloc_) noexcept :
alloc{ alloc_ },
va{ std::forward< T >( t) } {
va{ std::move( t) } {
}
friend
@@ -64,26 +68,28 @@ private:
friend
void intrusive_ptr_release( node * p) noexcept {
if ( 0 == --p->use_count) {
allocator_type & alloc( p->alloc);
std::allocator_traits< allocator_type >::destroy( alloc, p);
std::allocator_traits< allocator_type >::deallocate( alloc, p, 1);
allocator_t alloc( p->alloc);
allocator_traits_t::destroy( alloc, p);
allocator_traits_t::deallocate( alloc, p, 1);
}
}
};
typedef typename std::allocator_traits< Allocator >::template rebind_alloc< node > allocator_type;
using ptr_t = typename node::ptr_t;
using allocator_t = typename node::allocator_t;
using allocator_traits_t = typename node::allocator_traits_t;
enum class queue_status {
open = 0,
closed
};
allocator_type alloc_;
queue_status state_{ queue_status::open };
typename node::ptr head_{};
typename node::ptr * tail_;
mutable mutex mtx_{};
condition not_empty_cond_{};
allocator_t alloc_;
queue_status state_{ queue_status::open };
ptr_t head_{};
ptr_t * tail_;
mutable mutex mtx_{};
condition not_empty_cond_{};
bool is_closed_() const noexcept {
return queue_status::closed == state_;
@@ -99,7 +105,7 @@ private:
return ! head_;
}
channel_op_status push_( typename node::ptr const& new_node,
channel_op_status push_( ptr_t new_node,
std::unique_lock< mutex > & lk) noexcept {
if ( is_closed_() ) {
return channel_op_status::closed;
@@ -107,7 +113,7 @@ private:
return push_and_notify_( new_node, lk);
}
channel_op_status push_and_notify_( typename node::ptr const& new_node,
channel_op_status push_and_notify_( ptr_t new_node,
std::unique_lock< mutex > & lk) noexcept {
push_tail_( new_node);
lk.unlock();
@@ -115,7 +121,7 @@ private:
return channel_op_status::success;
}
void push_tail_( typename node::ptr new_node) noexcept {
void push_tail_( ptr_t new_node) noexcept {
* tail_ = new_node;
tail_ = & new_node->nxt;
}
@@ -126,7 +132,7 @@ private:
return std::move( old_head->va);
}
typename node::ptr pop_head_() noexcept {
ptr_t pop_head_() noexcept {
auto old_head = head_;
head_ = old_head->nxt;
if ( ! head_) {
@@ -150,18 +156,31 @@ public:
close_( lk);
}
channel_op_status push( value_type const& va) noexcept {
typename node::ptr new_node(
new ( alloc_.allocate( 1) ) node( va, alloc_) );
channel_op_status push( value_type const& va) {
typename allocator_traits_t::pointer ptr{
allocator_traits_t::allocate( alloc_, 1) };
try {
allocator_traits_t::construct( alloc_, ptr, va, alloc_);
} catch (...) {
allocator_traits_t::deallocate( alloc_, ptr, 1);
throw;
}
std::unique_lock< mutex > lk( mtx_);
return push_( new_node, lk);
return push_( { detail::convert( ptr) }, lk);
}
channel_op_status push( value_type && va) noexcept {
typename node::ptr new_node(
new ( alloc_.allocate( 1) ) node( std::forward< value_type >( va), alloc_) );
channel_op_status push( value_type && va) {
typename allocator_traits_t::pointer ptr{
allocator_traits_t::allocate( alloc_, 1) };
try {
allocator_traits_t::construct(
alloc_, ptr, std::move( va), alloc_);
} catch (...) {
allocator_traits_t::deallocate( alloc_, ptr, 1);
throw;
}
std::unique_lock< mutex > lk( mtx_);
return push_( new_node, lk);
return push_( { detail::convert( ptr) }, lk);
}
channel_op_status pop( value_type & va) {

View File

@@ -27,6 +27,22 @@ project boost/fiber/test
<threading>multi
;
run test_future.cpp :
: :
[ requires cxx11_constexpr
cxx11_decltype
cxx11_deleted_functions
cxx11_explicit_conversion_operators
cxx11_hdr_tuple
cxx11_lambdas
cxx11_noexcept
cxx11_nullptr
cxx11_template_aliases
cxx11_rvalue_references
cxx11_variadic_macros
cxx11_variadic_templates
cxx14_initialized_lambda_captures ] ;
run test_fiber.cpp :
: :
[ requires cxx11_constexpr
@@ -139,22 +155,6 @@ run test_fss.cpp :
cxx11_variadic_templates
cxx14_initialized_lambda_captures ] ;
run test_future.cpp :
: :
[ requires cxx11_constexpr
cxx11_decltype
cxx11_deleted_functions
cxx11_explicit_conversion_operators
cxx11_hdr_tuple
cxx11_lambdas
cxx11_noexcept
cxx11_nullptr
cxx11_template_aliases
cxx11_rvalue_references
cxx11_variadic_macros
cxx11_variadic_templates
cxx14_initialized_lambda_captures ] ;
run test_mutex_mt.cpp :
: :
[ requires cxx11_constexpr