Imported existing code

This commit is contained in:
Hazim Gazov
2010-04-02 02:48:44 -03:00
parent 48fbc5ae91
commit 7a86d01598
13996 changed files with 2468699 additions and 0 deletions

View File

@@ -0,0 +1,465 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2008. 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)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_ADAPTIVE_POOL_HPP
#define BOOST_INTERPROCESS_ADAPTIVE_POOL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/allocators/detail/adaptive_node_pool.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
//!\file
//!Describes adaptive_pool pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace detail{
template < unsigned int Version
, class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class adaptive_pool_base
: public node_pool_allocation_impl
< adaptive_pool_base
< Version, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent>
, Version
, T
, SegmentManager
>
{
public:
typedef typename SegmentManager::void_pointer void_pointer;
typedef SegmentManager segment_manager;
typedef adaptive_pool_base
<Version, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> self_t;
/// @cond
template <int dummy>
struct node_pool
{
typedef detail::shared_adaptive_node_pool
< SegmentManager, sizeof_value<T>::value, NodesPerBlock, MaxFreeBlocks, OverheadPercent> type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
/// @endcond
BOOST_STATIC_ASSERT((Version <=2));
public:
//-------
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::interprocess::version_type<adaptive_pool_base, Version> version;
typedef detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
//!Obtains adaptive_pool_base from
//!adaptive_pool_base
template<class T2>
struct rebind
{
typedef adaptive_pool_base<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
/// @cond
private:
//!Not assignable from related adaptive_pool_base
template<unsigned int Version2, class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char O2>
adaptive_pool_base& operator=
(const adaptive_pool_base<Version2, T2, SegmentManager2, N2, F2, O2>&);
/// @endcond
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
adaptive_pool_base(segment_manager *segment_mngr)
: mp_node_pool(detail::get_or_create_node_pool<typename node_pool<0>::type>(segment_mngr)) { }
//!Copy constructor from other adaptive_pool_base. Increments the reference
//!count of the associated node pool. Never throws
adaptive_pool_base(const adaptive_pool_base &other)
: mp_node_pool(other.get_node_pool())
{
node_pool<0>::get(detail::get_pointer(mp_node_pool))->inc_ref_count();
}
//!Assignment from other adaptive_pool_base
adaptive_pool_base& operator=(const adaptive_pool_base &other)
{
adaptive_pool_base c(other);
swap(*this, c);
return *this;
}
//!Copy constructor from related adaptive_pool_base. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
adaptive_pool_base
(const adaptive_pool_base<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: mp_node_pool(detail::get_or_create_node_pool<typename node_pool<0>::type>(other.get_segment_manager())) { }
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~adaptive_pool_base()
{ detail::destroy_node_pool_if_last_link(node_pool<0>::get(detail::get_pointer(mp_node_pool))); }
//!Returns a pointer to the node pool.
//!Never throws
void* get_node_pool() const
{ return detail::get_pointer(mp_node_pool); }
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const
{ return node_pool<0>::get(detail::get_pointer(mp_node_pool))->get_segment_manager(); }
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2)
{ detail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool); }
/// @cond
private:
void_pointer mp_node_pool;
/// @endcond
};
//!Equality test for same type
//!of adaptive_pool_base
template<unsigned int V, class T, class S, std::size_t NPC, std::size_t F, unsigned char OP> inline
bool operator==(const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc1,
const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc2)
{ return alloc1.get_node_pool() == alloc2.get_node_pool(); }
//!Inequality test for same type
//!of adaptive_pool_base
template<unsigned int V, class T, class S, std::size_t NPC, std::size_t F, unsigned char OP> inline
bool operator!=(const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc1,
const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc2)
{ return alloc1.get_node_pool() != alloc2.get_node_pool(); }
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class adaptive_pool_v1
: public adaptive_pool_base
< 1
, T
, SegmentManager
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
{
public:
typedef detail::adaptive_pool_base
< 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
template<class T2>
struct rebind
{
typedef adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
adaptive_pool_v1(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
adaptive_pool_v1
(const adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
};
} //namespace detail{
/// @endcond
//!An STL node allocator that uses a segment manager as memory
//!source. The internal pointer type will of the same type (raw, smart) as
//!"typename SegmentManager::void_pointer" type. This allows
//!placing the allocator in shared memory, memory mapped-files, etc...
//!
//!This node allocator shares a segregated storage between all instances
//!of adaptive_pool with equal sizeof(T) placed in the same segment
//!group. NodesPerBlock is the number of nodes allocated at once when the allocator
//!needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks
//!that the adaptive node pool will hold. The rest of the totally free blocks will be
//!deallocated with the segment manager.
//!
//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator:
//!(memory usable for nodes / total memory allocated from the segment manager)
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class adaptive_pool
/// @cond
: public detail::adaptive_pool_base
< 2
, T
, SegmentManager
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
typedef detail::adaptive_pool_base
< 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
public:
typedef boost::interprocess::version_type<adaptive_pool, 2> version;
template<class T2>
struct rebind
{
typedef adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
adaptive_pool(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
adaptive_pool
(const adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
#else //BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
//!Obtains adaptive_pool from
//!adaptive_pool
template<class T2>
struct rebind
{
typedef adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private:
//!Not assignable from
//!related adaptive_pool
template<class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char OP2>
adaptive_pool& operator=
(const adaptive_pool<T2, SegmentManager2, N2, F2, OP2>&);
//!Not assignable from
//!other adaptive_pool
//adaptive_pool& operator=(const adaptive_pool&);
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
adaptive_pool(segment_manager *segment_mngr);
//!Copy constructor from other adaptive_pool. Increments the reference
//!count of the associated node pool. Never throws
adaptive_pool(const adaptive_pool &other);
//!Copy constructor from related adaptive_pool. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
adaptive_pool
(const adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~adaptive_pool();
//!Returns a pointer to the node pool.
//!Never throws
void* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements);
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain it);
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator==(const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
//!Inequality test for same type
//!of adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator!=(const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_ADAPTIVE_POOL_HPP

View File

@@ -0,0 +1,304 @@
///////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2008. 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)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_ALLOCATOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/containers/allocation_type.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/containers/version_type.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
#include <stdexcept>
//!\file
//!Describes an allocator that allocates portions of fixed size
//!memory buffer (shared memory, mapped file...)
namespace boost {
namespace interprocess {
//!An STL compatible allocator that uses a segment manager as
//!memory source. The internal pointer type will of the same type (raw, smart) as
//!"typename SegmentManager::void_pointer" type. This allows
//!placing the allocator in shared memory, memory mapped-files, etc...
template<class T, class SegmentManager>
class allocator
{
public:
//Segment manager
typedef SegmentManager segment_manager;
typedef typename SegmentManager::void_pointer void_pointer;
/// @cond
private:
//Self type
typedef allocator<T, SegmentManager> self_t;
//Pointer to void
typedef typename segment_manager::void_pointer aux_pointer_t;
//Typedef to const void pointer
typedef typename
boost::pointer_to_other
<aux_pointer_t, const void>::type cvoid_ptr;
//Pointer to the allocator
typedef typename boost::pointer_to_other
<cvoid_ptr, segment_manager>::type alloc_ptr_t;
//Not assignable from related allocator
template<class T2, class SegmentManager2>
allocator& operator=(const allocator<T2, SegmentManager2>&);
//Not assignable from other allocator
allocator& operator=(const allocator&);
//Pointer to the allocator
alloc_ptr_t mp_mngr;
/// @endcond
public:
typedef T value_type;
typedef typename boost::pointer_to_other
<cvoid_ptr, T>::type pointer;
typedef typename boost::
pointer_to_other<pointer, const T>::type const_pointer;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::interprocess::version_type<allocator, 2> version;
/// @cond
//Experimental. Don't use.
typedef boost::interprocess::detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
/// @endcond
//!Obtains an allocator that allocates
//!objects of type T2
template<class T2>
struct rebind
{
typedef allocator<T2, SegmentManager> other;
};
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const
{ return detail::get_pointer(mp_mngr); }
//!Constructor from the segment manager.
//!Never throws
allocator(segment_manager *segment_mngr)
: mp_mngr(segment_mngr) { }
//!Constructor from other allocator.
//!Never throws
allocator(const allocator &other)
: mp_mngr(other.get_segment_manager()){ }
//!Constructor from related allocator.
//!Never throws
template<class T2>
allocator(const allocator<T2, SegmentManager> &other)
: mp_mngr(other.get_segment_manager()){}
//!Allocates memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_ptr hint = 0)
{
(void)hint;
if(count > this->max_size())
throw bad_alloc();
return pointer(static_cast<value_type*>(mp_mngr->allocate(count*sizeof(T))));
}
//!Deallocates memory previously allocated.
//!Never throws
void deallocate(const pointer &ptr, size_type)
{ mp_mngr->deallocate((void*)detail::get_pointer(ptr)); }
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const
{ return mp_mngr->get_size()/sizeof(T); }
//!Swap segment manager. Does not throw. If each allocator is placed in
//!different memory segments, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2)
{ detail::do_swap(alloc1.mp_mngr, alloc2.mp_mngr); }
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const
{
return (size_type)mp_mngr->size(detail::get_pointer(p))/sizeof(T);
}
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0)
{
return mp_mngr->allocation_command
(command, limit_size, preferred_size, received_size, detail::get_pointer(reuse));
}
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many
(size_type elem_size, std::size_t num_elements)
{
return multiallocation_chain(mp_mngr->allocate_many(sizeof(T)*elem_size, num_elements));
}
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many
(const size_type *elem_sizes, size_type n_elements)
{
multiallocation_chain(mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T)));
}
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain)
{
return mp_mngr->deallocate_many(chain.extract_multiallocation_chain());
}
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one()
{ return this->allocate(1); }
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual
(std::size_t num_elements)
{ return this->allocate_many(1, num_elements); }
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p)
{ return this->deallocate(p, 1); }
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain)
{ return this->deallocate_many(boost::interprocess::move(chain)); }
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const
{ return pointer(boost::addressof(value)); }
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const
{ return const_pointer(boost::addressof(value)); }
//!Copy construct an object
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v)
{ new((void*)detail::get_pointer(ptr)) value_type(v); }
//!Default construct an object.
//!Throws if T's default constructor throws
void construct(const pointer &ptr)
{ new((void*)detail::get_pointer(ptr)) value_type; }
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr)
{ BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); }
};
//!Equality test for same type
//!of allocator
template<class T, class SegmentManager> inline
bool operator==(const allocator<T , SegmentManager> &alloc1,
const allocator<T, SegmentManager> &alloc2)
{ return alloc1.get_segment_manager() == alloc2.get_segment_manager(); }
//!Inequality test for same type
//!of allocator
template<class T, class SegmentManager> inline
bool operator!=(const allocator<T, SegmentManager> &alloc1,
const allocator<T, SegmentManager> &alloc2)
{ return alloc1.get_segment_manager() != alloc2.get_segment_manager(); }
} //namespace interprocess {
/// @cond
template<class T>
struct has_trivial_destructor;
template<class T, class SegmentManager>
struct has_trivial_destructor
<boost::interprocess::allocator <T, SegmentManager> >
{
enum { value = true };
};
/// @endcond
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_ALLOCATOR_HPP

View File

@@ -0,0 +1,354 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2008. 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)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CACHED_ADAPTIVE_POOL_HPP
#define BOOST_INTERPROCESS_CACHED_ADAPTIVE_POOL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/allocators/detail/adaptive_node_pool.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/containers/version_type.hpp>
#include <boost/interprocess/allocators/detail/node_tools.hpp>
#include <cstddef>
//!\file
//!Describes cached_adaptive_pool pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace detail {
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class cached_adaptive_pool_v1
: public detail::cached_allocator_impl
< T
, detail::shared_adaptive_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
, 1>
{
public:
typedef detail::cached_allocator_impl
< T
, detail::shared_adaptive_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
, 1> base_t;
template<class T2>
struct rebind
{
typedef cached_adaptive_pool_v1
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
cached_adaptive_pool_v1(SegmentManager *segment_mngr,
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
: base_t(segment_mngr, max_cached_nodes)
{}
template<class T2>
cached_adaptive_pool_v1
(const cached_adaptive_pool_v1
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
};
} //namespace detail{
/// @endcond
//!An STL node allocator that uses a segment manager as memory
//!source. The internal pointer type will of the same type (raw, smart) as
//!"typename SegmentManager::void_pointer" type. This allows
//!placing the allocator in shared memory, memory mapped-files, etc...
//!
//!This node allocator shares a segregated storage between all instances of
//!cached_adaptive_pool with equal sizeof(T) placed in the same
//!memory segment. But also caches some nodes privately to
//!avoid some synchronization overhead.
//!
//!NodesPerBlock is the minimum number of nodes of nodes allocated at once when
//!the allocator needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks
//!that the adaptive node pool will hold. The rest of the totally free blocks will be
//!deallocated with the segment manager.
//!
//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator:
//!(memory usable for nodes / total memory allocated from the segment manager)
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class cached_adaptive_pool
/// @cond
: public detail::cached_allocator_impl
< T
, detail::shared_adaptive_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
, 2>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef detail::cached_allocator_impl
< T
, detail::shared_adaptive_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
, 2> base_t;
public:
typedef boost::interprocess::version_type<cached_adaptive_pool, 2> version;
template<class T2>
struct rebind
{
typedef cached_adaptive_pool
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
cached_adaptive_pool(SegmentManager *segment_mngr,
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
: base_t(segment_mngr, max_cached_nodes)
{}
template<class T2>
cached_adaptive_pool
(const cached_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
#else
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
//!Obtains cached_adaptive_pool from
//!cached_adaptive_pool
template<class T2>
struct rebind
{
typedef cached_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private:
//!Not assignable from
//!related cached_adaptive_pool
template<class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char OP2>
cached_adaptive_pool& operator=
(const cached_adaptive_pool<T2, SegmentManager2, N2, F2, OP2>&);
//!Not assignable from
//!other cached_adaptive_pool
cached_adaptive_pool& operator=(const cached_adaptive_pool&);
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
cached_adaptive_pool(segment_manager *segment_mngr);
//!Copy constructor from other cached_adaptive_pool. Increments the reference
//!count of the associated node pool. Never throws
cached_adaptive_pool(const cached_adaptive_pool &other);
//!Copy constructor from related cached_adaptive_pool. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
cached_adaptive_pool
(const cached_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~cached_adaptive_pool();
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements);
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain);
//!Sets the new max cached nodes value. This can provoke deallocations
//!if "newmax" is less than current cached nodes. Never throws
void set_max_cached_nodes(std::size_t newmax);
//!Returns the max cached nodes parameter.
//!Never throws
std::size_t get_max_cached_nodes() const;
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of cached_adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, std::size_t OP> inline
bool operator==(const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
//!Inequality test for same type
//!of cached_adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, std::size_t OP> inline
bool operator!=(const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_CACHED_ADAPTIVE_POOL_HPP

View File

@@ -0,0 +1,324 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2008. 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)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/allocators/detail/node_pool.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/containers/version_type.hpp>
#include <boost/interprocess/allocators/detail/node_tools.hpp>
#include <cstddef>
//!\file
//!Describes cached_cached_node_allocator pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace detail {
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
>
class cached_node_allocator_v1
: public detail::cached_allocator_impl
< T
, detail::shared_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
>
, 1>
{
public:
typedef detail::cached_allocator_impl
< T
, detail::shared_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
>
, 1> base_t;
template<class T2>
struct rebind
{
typedef cached_node_allocator_v1
<T2, SegmentManager, NodesPerBlock> other;
};
cached_node_allocator_v1(SegmentManager *segment_mngr,
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
: base_t(segment_mngr, max_cached_nodes)
{}
template<class T2>
cached_node_allocator_v1
(const cached_node_allocator_v1
<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
};
} //namespace detail{
/// @endcond
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class cached_node_allocator
/// @cond
: public detail::cached_allocator_impl
< T
, detail::shared_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
>
, 2>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef detail::cached_allocator_impl
< T
, detail::shared_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
>
, 2> base_t;
public:
typedef boost::interprocess::version_type<cached_node_allocator, 2> version;
template<class T2>
struct rebind
{
typedef cached_node_allocator<T2, SegmentManager, NodesPerBlock> other;
};
cached_node_allocator(SegmentManager *segment_mngr,
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
: base_t(segment_mngr, max_cached_nodes)
{}
template<class T2>
cached_node_allocator
(const cached_node_allocator<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
#else
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
//!Obtains cached_node_allocator from
//!cached_node_allocator
template<class T2>
struct rebind
{
typedef cached_node_allocator<T2, SegmentManager> other;
};
private:
//!Not assignable from
//!related cached_node_allocator
template<class T2, class SegmentManager2, std::size_t N2>
cached_node_allocator& operator=
(const cached_node_allocator<T2, SegmentManager2, N2>&);
//!Not assignable from
//!other cached_node_allocator
cached_node_allocator& operator=(const cached_node_allocator&);
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
cached_node_allocator(segment_manager *segment_mngr);
//!Copy constructor from other cached_node_allocator. Increments the reference
//!count of the associated node pool. Never throws
cached_node_allocator(const cached_node_allocator &other);
//!Copy constructor from related cached_node_allocator. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
cached_node_allocator
(const cached_node_allocator<T2, SegmentManager, NodesPerBlock> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~cached_node_allocator();
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Default construct an object.
//!Throws if T's default constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements);
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain it);
//!Sets the new max cached nodes value. This can provoke deallocations
//!if "newmax" is less than current cached nodes. Never throws
void set_max_cached_nodes(std::size_t newmax);
//!Returns the max cached nodes parameter.
//!Never throws
std::size_t get_max_cached_nodes() const;
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of cached_node_allocator
template<class T, class S, std::size_t NPC> inline
bool operator==(const cached_node_allocator<T, S, NPC> &alloc1,
const cached_node_allocator<T, S, NPC> &alloc2);
//!Inequality test for same type
//!of cached_node_allocator
template<class T, class S, std::size_t NPC> inline
bool operator!=(const cached_node_allocator<T, S, NPC> &alloc1,
const cached_node_allocator<T, S, NPC> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP

View File

@@ -0,0 +1,639 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2008. 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)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_HPP
#define BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/min_max.hpp>
#include <boost/interprocess/detail/math_functions.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/intrusive/set.hpp>
#include <boost/intrusive/slist.hpp>
#include <boost/math/common_factor_ct.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
#include <boost/interprocess/allocators/detail/node_tools.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <cstddef>
#include <boost/config/no_tr1/cmath.hpp>
#include <cassert>
//!\file
//!Describes the real adaptive pool shared by many Interprocess pool allocators
namespace boost {
namespace interprocess {
namespace detail {
template<class SegmentManagerBase>
class private_adaptive_node_pool_impl
{
//Non-copyable
private_adaptive_node_pool_impl();
private_adaptive_node_pool_impl(const private_adaptive_node_pool_impl &);
private_adaptive_node_pool_impl &operator=(const private_adaptive_node_pool_impl &);
typedef typename SegmentManagerBase::void_pointer void_pointer;
static const std::size_t PayloadPerAllocation = SegmentManagerBase::PayloadPerAllocation;
public:
typedef typename node_slist<void_pointer>::node_t node_t;
typedef typename node_slist<void_pointer>::node_slist_t free_nodes_t;
typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain;
private:
typedef typename bi::make_set_base_hook
< bi::void_pointer<void_pointer>
, bi::optimize_size<true>
, bi::constant_time_size<false>
, bi::link_mode<bi::normal_link> >::type multiset_hook_t;
struct hdr_offset_holder
{
hdr_offset_holder(std::size_t offset = 0)
: hdr_offset(offset)
{}
std::size_t hdr_offset;
};
struct block_info_t
:
public hdr_offset_holder,
public multiset_hook_t
{
//An intrusive list of free node from this block
free_nodes_t free_nodes;
friend bool operator <(const block_info_t &l, const block_info_t &r)
{
// { return l.free_nodes.size() < r.free_nodes.size(); }
//Let's order blocks first by free nodes and then by address
//so that highest address fully free blocks are deallocated.
//This improves returning memory to the OS (trimming).
const bool is_less = l.free_nodes.size() < r.free_nodes.size();
const bool is_equal = l.free_nodes.size() == r.free_nodes.size();
return is_less || (is_equal && (&l < &r));
}
};
typedef typename bi::make_multiset
<block_info_t, bi::base_hook<multiset_hook_t> >::type block_multiset_t;
typedef typename block_multiset_t::iterator block_iterator;
static const std::size_t MaxAlign = alignment_of<node_t>::value;
static const std::size_t HdrSize = ((sizeof(block_info_t)-1)/MaxAlign+1)*MaxAlign;
static const std::size_t HdrOffsetSize = ((sizeof(hdr_offset_holder)-1)/MaxAlign+1)*MaxAlign;
static std::size_t calculate_alignment
(std::size_t overhead_percent, std::size_t real_node_size)
{
//to-do: handle real_node_size != node_size
const std::size_t divisor = overhead_percent*real_node_size;
const std::size_t dividend = HdrOffsetSize*100;
std::size_t elements_per_subblock = (dividend - 1)/divisor + 1;
std::size_t candidate_power_of_2 =
upper_power_of_2(elements_per_subblock*real_node_size + HdrOffsetSize);
bool overhead_satisfied = false;
//Now calculate the wors-case overhead for a subblock
const std::size_t max_subblock_overhead = HdrSize + PayloadPerAllocation;
while(!overhead_satisfied){
elements_per_subblock = (candidate_power_of_2 - max_subblock_overhead)/real_node_size;
const std::size_t overhead_size = candidate_power_of_2 - elements_per_subblock*real_node_size;
if(overhead_size*100/candidate_power_of_2 < overhead_percent){
overhead_satisfied = true;
}
else{
candidate_power_of_2 <<= 1;
}
}
return candidate_power_of_2;
}
static void calculate_num_subblocks
(std::size_t alignment, std::size_t real_node_size, std::size_t elements_per_block
,std::size_t &num_subblocks, std::size_t &real_num_node, std::size_t overhead_percent)
{
std::size_t elements_per_subblock = (alignment - HdrOffsetSize)/real_node_size;
std::size_t possible_num_subblock = (elements_per_block - 1)/elements_per_subblock + 1;
std::size_t hdr_subblock_elements = (alignment - HdrSize - PayloadPerAllocation)/real_node_size;
while(((possible_num_subblock-1)*elements_per_subblock + hdr_subblock_elements) < elements_per_block){
++possible_num_subblock;
}
elements_per_subblock = (alignment - HdrOffsetSize)/real_node_size;
bool overhead_satisfied = false;
while(!overhead_satisfied){
const std::size_t total_data = (elements_per_subblock*(possible_num_subblock-1) + hdr_subblock_elements)*real_node_size;
const std::size_t total_size = alignment*possible_num_subblock;
if((total_size - total_data)*100/total_size < overhead_percent){
overhead_satisfied = true;
}
else{
++possible_num_subblock;
}
}
num_subblocks = possible_num_subblock;
real_num_node = (possible_num_subblock-1)*elements_per_subblock + hdr_subblock_elements;
}
public:
//!Segment manager typedef
typedef SegmentManagerBase segment_manager_base_type;
//!Constructor from a segment manager. Never throws
private_adaptive_node_pool_impl
( segment_manager_base_type *segment_mngr_base, std::size_t node_size
, std::size_t nodes_per_block, std::size_t max_free_blocks
, unsigned char overhead_percent
)
: m_max_free_blocks(max_free_blocks)
, m_real_node_size(lcm(node_size, std::size_t(alignment_of<node_t>::value)))
//Round the size to a power of two value.
//This is the total memory size (including payload) that we want to
//allocate from the general-purpose allocator
, m_real_block_alignment(calculate_alignment(overhead_percent, m_real_node_size))
//This is the real number of nodes per block
, m_num_subblocks(0)
, m_real_num_node(0)
//General purpose allocator
, mp_segment_mngr_base(segment_mngr_base)
, m_block_multiset()
, m_totally_free_blocks(0)
{
calculate_num_subblocks(m_real_block_alignment, m_real_node_size, nodes_per_block, m_num_subblocks, m_real_num_node, overhead_percent);
}
//!Destructor. Deallocates all allocated blocks. Never throws
~private_adaptive_node_pool_impl()
{ priv_clear(); }
std::size_t get_real_num_node() const
{ return m_real_num_node; }
//!Returns the segment manager. Never throws
segment_manager_base_type* get_segment_manager_base()const
{ return detail::get_pointer(mp_segment_mngr_base); }
//!Allocates array of count elements. Can throw boost::interprocess::bad_alloc
void *allocate_node()
{
priv_invariants();
//If there are no free nodes we allocate a new block
if (m_block_multiset.empty()){
priv_alloc_block(1);
}
//We take the first free node the multiset can't be empty
return priv_take_first_node();
}
//!Deallocates an array pointed by ptr. Never throws
void deallocate_node(void *pElem)
{
multiallocation_chain chain;
chain.push_front(void_pointer(pElem));
this->priv_reinsert_nodes_in_block(chain, 1);
//Update free block count
if(m_totally_free_blocks > m_max_free_blocks){
this->priv_deallocate_free_blocks(m_max_free_blocks);
}
priv_invariants();
}
//!Allocates n nodes.
//!Can throw boost::interprocess::bad_alloc
multiallocation_chain allocate_nodes(const std::size_t n)
{
multiallocation_chain chain;
std::size_t i = 0;
try{
priv_invariants();
while(i != n){
//If there are no free nodes we allocate all needed blocks
if (m_block_multiset.empty()){
priv_alloc_block(((n - i) - 1)/m_real_num_node + 1);
}
free_nodes_t &free_nodes = m_block_multiset.begin()->free_nodes;
const std::size_t free_nodes_count_before = free_nodes.size();
if(free_nodes_count_before == m_real_num_node){
--m_totally_free_blocks;
}
const std::size_t num_elems = ((n-i) < free_nodes_count_before) ? (n-i) : free_nodes_count_before;
for(std::size_t j = 0; j != num_elems; ++j){
void *new_node = &free_nodes.front();
free_nodes.pop_front();
chain.push_back(new_node);
}
if(free_nodes.empty()){
m_block_multiset.erase(m_block_multiset.begin());
}
i += num_elems;
}
}
catch(...){
this->deallocate_nodes(chain, i);
throw;
}
priv_invariants();
return boost::interprocess::move(chain);
}
//!Deallocates a linked list of nodes. Never throws
void deallocate_nodes(multiallocation_chain nodes)
{
return deallocate_nodes(nodes, nodes.size());
}
//!Deallocates the first n nodes of a linked list of nodes. Never throws
void deallocate_nodes(multiallocation_chain &nodes, std::size_t n)
{
this->priv_reinsert_nodes_in_block(nodes, n);
if(m_totally_free_blocks > m_max_free_blocks){
this->priv_deallocate_free_blocks(m_max_free_blocks);
}
}
void deallocate_free_blocks()
{ this->priv_deallocate_free_blocks(0); }
std::size_t num_free_nodes()
{
typedef typename block_multiset_t::const_iterator citerator;
std::size_t count = 0;
citerator it (m_block_multiset.begin()), itend(m_block_multiset.end());
for(; it != itend; ++it){
count += it->free_nodes.size();
}
return count;
}
void swap(private_adaptive_node_pool_impl &other)
{
assert(m_max_free_blocks == other.m_max_free_blocks);
assert(m_real_node_size == other.m_real_node_size);
assert(m_real_block_alignment == other.m_real_block_alignment);
assert(m_real_num_node == other.m_real_num_node);
std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base);
std::swap(m_totally_free_blocks, other.m_totally_free_blocks);
m_block_multiset.swap(other.m_block_multiset);
}
//Deprecated, use deallocate_free_blocks
void deallocate_free_chunks()
{ this->priv_deallocate_free_blocks(0); }
private:
void priv_deallocate_free_blocks(std::size_t max_free_blocks)
{
priv_invariants();
//Now check if we've reached the free nodes limit
//and check if we have free blocks. If so, deallocate as much
//as we can to stay below the limit
for( block_iterator itend = m_block_multiset.end()
; m_totally_free_blocks > max_free_blocks
; --m_totally_free_blocks
){
assert(!m_block_multiset.empty());
block_iterator it = itend;
--it;
std::size_t num_nodes = it->free_nodes.size();
assert(num_nodes == m_real_num_node);
(void)num_nodes;
m_block_multiset.erase_and_dispose
(it, block_destroyer(this));
}
}
void priv_reinsert_nodes_in_block(multiallocation_chain &chain, std::size_t n)
{
block_iterator block_it(m_block_multiset.end());
while(n--){
void *pElem = detail::get_pointer(chain.front());
chain.pop_front();
priv_invariants();
block_info_t *block_info = this->priv_block_from_node(pElem);
assert(block_info->free_nodes.size() < m_real_num_node);
//We put the node at the beginning of the free node list
node_t * to_deallocate = static_cast<node_t*>(pElem);
block_info->free_nodes.push_front(*to_deallocate);
block_iterator this_block(block_multiset_t::s_iterator_to(*block_info));
block_iterator next_block(this_block);
++next_block;
//Cache the free nodes from the block
std::size_t this_block_free_nodes = this_block->free_nodes.size();
if(this_block_free_nodes == 1){
m_block_multiset.insert(m_block_multiset.begin(), *block_info);
}
else{
block_iterator next_block(this_block);
++next_block;
if(next_block != block_it){
std::size_t next_free_nodes = next_block->free_nodes.size();
if(this_block_free_nodes > next_free_nodes){
//Now move the block to the new position
m_block_multiset.erase(this_block);
m_block_multiset.insert(*block_info);
}
}
}
//Update free block count
if(this_block_free_nodes == m_real_num_node){
++m_totally_free_blocks;
}
priv_invariants();
}
}
node_t *priv_take_first_node()
{
assert(m_block_multiset.begin() != m_block_multiset.end());
//We take the first free node the multiset can't be empty
free_nodes_t &free_nodes = m_block_multiset.begin()->free_nodes;
node_t *first_node = &free_nodes.front();
const std::size_t free_nodes_count = free_nodes.size();
assert(0 != free_nodes_count);
free_nodes.pop_front();
if(free_nodes_count == 1){
m_block_multiset.erase(m_block_multiset.begin());
}
else if(free_nodes_count == m_real_num_node){
--m_totally_free_blocks;
}
priv_invariants();
return first_node;
}
class block_destroyer;
friend class block_destroyer;
class block_destroyer
{
public:
block_destroyer(const private_adaptive_node_pool_impl *impl)
: mp_impl(impl)
{}
void operator()(typename block_multiset_t::pointer to_deallocate)
{
std::size_t free_nodes = to_deallocate->free_nodes.size();
(void)free_nodes;
assert(free_nodes == mp_impl->m_real_num_node);
assert(0 == to_deallocate->hdr_offset);
hdr_offset_holder *hdr_off_holder = mp_impl->priv_first_subblock_from_block(detail::get_pointer(to_deallocate));
mp_impl->mp_segment_mngr_base->deallocate(hdr_off_holder);
}
const private_adaptive_node_pool_impl *mp_impl;
};
//This macro will activate invariant checking. Slow, but helpful for debugging the code.
//#define BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS
void priv_invariants()
#ifdef BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS
#undef BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS
{
//We iterate through the block list to free the memory
block_iterator it(m_block_multiset.begin()),
itend(m_block_multiset.end()), to_deallocate;
if(it != itend){
for(++it; it != itend; ++it){
block_iterator prev(it);
--prev;
std::size_t sp = prev->free_nodes.size(),
si = it->free_nodes.size();
assert(sp <= si);
(void)sp; (void)si;
}
}
{
//Check that the total free nodes are correct
it = m_block_multiset.begin();
itend = m_block_multiset.end();
std::size_t total_free_nodes = 0;
for(; it != itend; ++it){
total_free_nodes += it->free_nodes.size();
}
assert(total_free_nodes >= m_totally_free_blocks*m_real_num_node);
}
{
//Check that the total totally free blocks are correct
it = m_block_multiset.begin();
itend = m_block_multiset.end();
std::size_t total_free_blocks = 0;
for(; it != itend; ++it){
total_free_blocks += (it->free_nodes.size() == m_real_num_node);
}
assert(total_free_blocks == m_totally_free_blocks);
}
{
//Check that header offsets are correct
it = m_block_multiset.begin();
for(; it != itend; ++it){
hdr_offset_holder *hdr_off_holder = priv_first_subblock_from_block(&*it);
for(std::size_t i = 0, max = m_num_subblocks; i < max; ++i){
assert(hdr_off_holder->hdr_offset == std::size_t(reinterpret_cast<char*>(&*it)- reinterpret_cast<char*>(hdr_off_holder)));
assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1)));
assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1)));
hdr_off_holder = reinterpret_cast<hdr_offset_holder *>(reinterpret_cast<char*>(hdr_off_holder) + m_real_block_alignment);
}
}
}
}
#else
{} //empty
#endif
//!Deallocates all used memory. Never throws
void priv_clear()
{
#ifndef NDEBUG
block_iterator it = m_block_multiset.begin();
block_iterator itend = m_block_multiset.end();
std::size_t num_free_nodes = 0;
for(; it != itend; ++it){
//Check for memory leak
std::size_t n = (std::size_t)it->free_nodes.size(); (void)n;
assert(it->free_nodes.size() == m_real_num_node);
++num_free_nodes;
}
assert(num_free_nodes == m_totally_free_blocks);
#endif
priv_invariants();
m_block_multiset.clear_and_dispose
(block_destroyer(this));
m_totally_free_blocks = 0;
}
block_info_t *priv_block_from_node(void *node) const
{
hdr_offset_holder *hdr_off_holder =
reinterpret_cast<hdr_offset_holder*>((std::size_t)node & std::size_t(~(m_real_block_alignment - 1)));
assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1)));
assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1)));
block_info_t *block = reinterpret_cast<block_info_t *>
(reinterpret_cast<char*>(hdr_off_holder) + hdr_off_holder->hdr_offset);
assert(block->hdr_offset == 0);
return block;
}
hdr_offset_holder *priv_first_subblock_from_block(block_info_t *block) const
{
hdr_offset_holder *hdr_off_holder = reinterpret_cast<hdr_offset_holder*>
(reinterpret_cast<char*>(block) - (m_num_subblocks-1)*m_real_block_alignment);
assert(hdr_off_holder->hdr_offset == std::size_t(reinterpret_cast<char*>(block) - reinterpret_cast<char*>(hdr_off_holder)));
assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1)));
assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1)));
return hdr_off_holder;
}
//!Allocates a several blocks of nodes. Can throw boost::interprocess::bad_alloc
void priv_alloc_block(std::size_t n)
{
std::size_t real_block_size = m_real_block_alignment*m_num_subblocks - SegmentManagerBase::PayloadPerAllocation;
std::size_t elements_per_subblock = (m_real_block_alignment - HdrOffsetSize)/m_real_node_size;
std::size_t hdr_subblock_elements = (m_real_block_alignment - HdrSize - SegmentManagerBase::PayloadPerAllocation)/m_real_node_size;
for(std::size_t i = 0; i != n; ++i){
//We allocate a new NodeBlock and put it the last
//element of the tree
char *mem_address = static_cast<char*>
(mp_segment_mngr_base->allocate_aligned(real_block_size, m_real_block_alignment));
if(!mem_address) throw std::bad_alloc();
++m_totally_free_blocks;
//First initialize header information on the last subblock
char *hdr_addr = mem_address + m_real_block_alignment*(m_num_subblocks-1);
block_info_t *c_info = new(hdr_addr)block_info_t;
//Some structural checks
assert(static_cast<void*>(&static_cast<hdr_offset_holder*>(c_info)->hdr_offset) ==
static_cast<void*>(c_info));
typename free_nodes_t::iterator prev_insert_pos = c_info->free_nodes.before_begin();
for( std::size_t subblock = 0, maxsubblock = m_num_subblocks - 1
; subblock < maxsubblock
; ++subblock, mem_address += m_real_block_alignment){
//Initialize header offset mark
new(mem_address) hdr_offset_holder(std::size_t(hdr_addr - mem_address));
char *pNode = mem_address + HdrOffsetSize;
for(std::size_t i = 0; i < elements_per_subblock; ++i){
prev_insert_pos = c_info->free_nodes.insert_after(prev_insert_pos, *new (pNode) node_t);
pNode += m_real_node_size;
}
}
{
char *pNode = hdr_addr + HdrSize;
//We initialize all Nodes in Node Block to insert
//them in the free Node list
for(std::size_t i = 0; i < hdr_subblock_elements; ++i){
prev_insert_pos = c_info->free_nodes.insert_after(prev_insert_pos, *new (pNode) node_t);
pNode += m_real_node_size;
}
}
//Insert the block after the free node list is full
m_block_multiset.insert(m_block_multiset.end(), *c_info);
}
}
private:
typedef typename boost::pointer_to_other
<void_pointer, segment_manager_base_type>::type segment_mngr_base_ptr_t;
const std::size_t m_max_free_blocks;
const std::size_t m_real_node_size;
//Round the size to a power of two value.
//This is the total memory size (including payload) that we want to
//allocate from the general-purpose allocator
const std::size_t m_real_block_alignment;
std::size_t m_num_subblocks;
//This is the real number of nodes per block
//const
std::size_t m_real_num_node;
segment_mngr_base_ptr_t mp_segment_mngr_base;//Segment manager
block_multiset_t m_block_multiset; //Intrusive block list
std::size_t m_totally_free_blocks; //Free blocks
};
template< class SegmentManager
, std::size_t NodeSize
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class private_adaptive_node_pool
: public private_adaptive_node_pool_impl
<typename SegmentManager::segment_manager_base_type>
{
typedef private_adaptive_node_pool_impl
<typename SegmentManager::segment_manager_base_type> base_t;
//Non-copyable
private_adaptive_node_pool();
private_adaptive_node_pool(const private_adaptive_node_pool &);
private_adaptive_node_pool &operator=(const private_adaptive_node_pool &);
public:
typedef SegmentManager segment_manager;
static const std::size_t nodes_per_block = NodesPerBlock;
//Deprecated, use node_per_block
static const std::size_t nodes_per_chunk = NodesPerBlock;
//!Constructor from a segment manager. Never throws
private_adaptive_node_pool(segment_manager *segment_mngr)
: base_t(segment_mngr, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent)
{}
//!Returns the segment manager. Never throws
segment_manager* get_segment_manager() const
{ return static_cast<segment_manager*>(base_t::get_segment_manager_base()); }
};
//!Pooled shared memory allocator using adaptive pool. Includes
//!a reference count but the class does not delete itself, this is
//!responsibility of user classes. Node size (NodeSize) and the number of
//!nodes allocated per block (NodesPerBlock) are known at compile time
template< class SegmentManager
, std::size_t NodeSize
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class shared_adaptive_node_pool
: public detail::shared_pool_impl
< private_adaptive_node_pool
<SegmentManager, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent>
>
{
typedef detail::shared_pool_impl
< private_adaptive_node_pool
<SegmentManager, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent>
> base_t;
public:
shared_adaptive_node_pool(SegmentManager *segment_mgnr)
: base_t(segment_mgnr)
{}
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_HPP

View File

@@ -0,0 +1,839 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008. 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)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP
#define BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/detail/utilities.hpp> //get_pointer
#include <utility> //std::pair
#include <boost/utility/addressof.hpp> //boost::addressof
#include <boost/assert.hpp> //BOOST_ASSERT
#include <boost/interprocess/exceptions.hpp> //bad_alloc
#include <boost/interprocess/sync/scoped_lock.hpp> //scoped_lock
#include <boost/interprocess/containers/allocation_type.hpp> //boost::interprocess::allocation_type
#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
#include <boost/interprocess/detail/segment_manager_helper.hpp>
#include <algorithm> //std::swap
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/utilities.hpp>
namespace boost {
namespace interprocess {
template <class T>
struct sizeof_value
{
static const std::size_t value = sizeof(T);
};
template <>
struct sizeof_value<void>
{
static const std::size_t value = sizeof(void*);
};
template <>
struct sizeof_value<const void>
{
static const std::size_t value = sizeof(void*);
};
template <>
struct sizeof_value<volatile void>
{
static const std::size_t value = sizeof(void*);
};
template <>
struct sizeof_value<const volatile void>
{
static const std::size_t value = sizeof(void*);
};
namespace detail {
//!Object function that creates the node allocator if it is not created and
//!increments reference count if it is already created
template<class NodePool>
struct get_or_create_node_pool_func
{
//!This connects or constructs the unique instance of node_pool_t
//!Can throw boost::interprocess::bad_alloc
void operator()()
{
//Find or create the node_pool_t
mp_node_pool = mp_segment_manager->template find_or_construct
<NodePool>(boost::interprocess::unique_instance)(mp_segment_manager);
//If valid, increment link count
if(mp_node_pool != 0)
mp_node_pool->inc_ref_count();
}
//!Constructor. Initializes function
//!object parameters
get_or_create_node_pool_func(typename NodePool::segment_manager *mngr)
: mp_segment_manager(mngr){}
NodePool *mp_node_pool;
typename NodePool::segment_manager *mp_segment_manager;
};
template<class NodePool>
inline NodePool *get_or_create_node_pool(typename NodePool::segment_manager *mgnr)
{
detail::get_or_create_node_pool_func<NodePool> func(mgnr);
mgnr->atomic_func(func);
return func.mp_node_pool;
}
//!Object function that decrements the reference count. If the count
//!reaches to zero destroys the node allocator from memory.
//!Never throws
template<class NodePool>
struct destroy_if_last_link_func
{
//!Decrements reference count and destroys the object if there is no
//!more attached allocators. Never throws
void operator()()
{
//If not the last link return
if(mp_node_pool->dec_ref_count() != 0) return;
//Last link, let's destroy the segment_manager
mp_node_pool->get_segment_manager()->template destroy<NodePool>(boost::interprocess::unique_instance);
}
//!Constructor. Initializes function
//!object parameters
destroy_if_last_link_func(NodePool *pool)
: mp_node_pool(pool)
{}
NodePool *mp_node_pool;
};
//!Destruction function, initializes and executes destruction function
//!object. Never throws
template<class NodePool>
inline void destroy_node_pool_if_last_link(NodePool *pool)
{
//Get segment manager
typename NodePool::segment_manager *mngr = pool->get_segment_manager();
//Execute destruction functor atomically
destroy_if_last_link_func<NodePool>func(pool);
mngr->atomic_func(func);
}
template<class NodePool>
class cache_impl
{
typedef typename NodePool::segment_manager::
void_pointer void_pointer;
typedef typename pointer_to_other
<void_pointer, NodePool>::type node_pool_ptr;
typedef typename NodePool::multiallocation_chain multiallocation_chain;
node_pool_ptr mp_node_pool;
multiallocation_chain m_cached_nodes;
std::size_t m_max_cached_nodes;
public:
typedef typename NodePool::segment_manager segment_manager;
cache_impl(segment_manager *segment_mngr, std::size_t max_cached_nodes)
: mp_node_pool(get_or_create_node_pool<NodePool>(segment_mngr))
, m_max_cached_nodes(max_cached_nodes)
{}
cache_impl(const cache_impl &other)
: mp_node_pool(other.get_node_pool())
, m_max_cached_nodes(other.get_max_cached_nodes())
{
mp_node_pool->inc_ref_count();
}
~cache_impl()
{
this->deallocate_all_cached_nodes();
detail::destroy_node_pool_if_last_link(detail::get_pointer(mp_node_pool));
}
NodePool *get_node_pool() const
{ return detail::get_pointer(mp_node_pool); }
segment_manager *get_segment_manager() const
{ return mp_node_pool->get_segment_manager(); }
std::size_t get_max_cached_nodes() const
{ return m_max_cached_nodes; }
void *cached_allocation()
{
//If don't have any cached node, we have to get a new list of free nodes from the pool
if(m_cached_nodes.empty()){
m_cached_nodes = mp_node_pool->allocate_nodes(m_max_cached_nodes/2);
}
void *ret = detail::get_pointer(m_cached_nodes.front());
m_cached_nodes.pop_front();
return ret;
}
multiallocation_chain cached_allocation(std::size_t n)
{
multiallocation_chain chain;
std::size_t count = n, allocated(0);
BOOST_TRY{
//If don't have any cached node, we have to get a new list of free nodes from the pool
while(!m_cached_nodes.empty() && count--){
void *ret = detail::get_pointer(m_cached_nodes.front());
m_cached_nodes.pop_front();
chain.push_back(ret);
++allocated;
}
if(allocated != n){
multiallocation_chain chain2(mp_node_pool->allocate_nodes(n - allocated));
chain.splice_after(chain.last(), chain2, chain2.before_begin(), chain2.last(), n - allocated);
}
return boost::interprocess::move(chain);
}
BOOST_CATCH(...){
this->cached_deallocation(boost::interprocess::move(chain));
BOOST_RETHROW
}
BOOST_CATCH_END
}
void cached_deallocation(void *ptr)
{
//Check if cache is full
if(m_cached_nodes.size() >= m_max_cached_nodes){
//This only occurs if this allocator deallocate memory allocated
//with other equal allocator. Since the cache is full, and more
//deallocations are probably coming, we'll make some room in cache
//in a single, efficient multi node deallocation.
this->priv_deallocate_n_nodes(m_cached_nodes.size() - m_max_cached_nodes/2);
}
m_cached_nodes.push_front(ptr);
}
void cached_deallocation(multiallocation_chain chain)
{
m_cached_nodes.splice_after(m_cached_nodes.before_begin(), chain);
//Check if cache is full
if(m_cached_nodes.size() >= m_max_cached_nodes){
//This only occurs if this allocator deallocate memory allocated
//with other equal allocator. Since the cache is full, and more
//deallocations are probably coming, we'll make some room in cache
//in a single, efficient multi node deallocation.
this->priv_deallocate_n_nodes(m_cached_nodes.size() - m_max_cached_nodes/2);
}
}
//!Sets the new max cached nodes value. This can provoke deallocations
//!if "newmax" is less than current cached nodes. Never throws
void set_max_cached_nodes(std::size_t newmax)
{
m_max_cached_nodes = newmax;
this->priv_deallocate_remaining_nodes();
}
//!Frees all cached nodes.
//!Never throws
void deallocate_all_cached_nodes()
{
if(m_cached_nodes.empty()) return;
mp_node_pool->deallocate_nodes(boost::interprocess::move(m_cached_nodes));
}
private:
//!Frees all cached nodes at once.
//!Never throws
void priv_deallocate_remaining_nodes()
{
if(m_cached_nodes.size() > m_max_cached_nodes){
priv_deallocate_n_nodes(m_cached_nodes.size()-m_max_cached_nodes);
}
}
//!Frees n cached nodes at once. Never throws
void priv_deallocate_n_nodes(std::size_t n)
{
//Deallocate all new linked list at once
mp_node_pool->deallocate_nodes(m_cached_nodes, n);
}
};
template<class Derived, class T, class SegmentManager>
class array_allocation_impl
{
const Derived *derived() const
{ return static_cast<const Derived*>(this); }
Derived *derived()
{ return static_cast<Derived*>(this); }
typedef typename SegmentManager::void_pointer void_pointer;
public:
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
public:
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const
{
return (size_type)this->derived()->get_segment_manager()->size(detail::get_pointer(p))/sizeof(T);
}
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0)
{
return this->derived()->get_segment_manager()->allocation_command
(command, limit_size, preferred_size, received_size, detail::get_pointer(reuse));
}
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements)
{
return this->derived()->get_segment_manager()->allocate_many(sizeof(T)*elem_size, num_elements);
}
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements)
{
return this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T));
}
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain)
{ return this->derived()->get_segment_manager()->deallocate_many(boost::interprocess::move(chain)); }
//!Returns the number of elements that could be
//!allocated. Never throws
size_type max_size() const
{ return this->derived()->get_segment_manager()->get_size()/sizeof(T); }
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const
{ return pointer(boost::addressof(value)); }
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const
{ return const_pointer(boost::addressof(value)); }
//!Default construct an object.
//!Throws if T's default constructor throws
void construct(const pointer &ptr)
{ new((void*)detail::get_pointer(ptr)) value_type; }
//!Copy construct an object
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v)
{ new((void*)detail::get_pointer(ptr)) value_type(v); }
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr)
{ BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); }
};
template<class Derived, unsigned int Version, class T, class SegmentManager>
class node_pool_allocation_impl
: public array_allocation_impl
< Derived
, T
, SegmentManager>
{
const Derived *derived() const
{ return static_cast<const Derived*>(this); }
Derived *derived()
{ return static_cast<Derived*>(this); }
typedef typename SegmentManager::void_pointer void_pointer;
typedef typename boost::
pointer_to_other<void_pointer, const void>::type cvoid_pointer;
public:
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
template <int Dummy>
struct node_pool
{
typedef typename Derived::template node_pool<0>::type type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
public:
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0)
{
(void)hint;
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
if(count > this->max_size())
throw bad_alloc();
else if(Version == 1 && count == 1)
return pointer(static_cast<value_type*>
(pool->allocate_node()));
else
return pointer(static_cast<value_type*>
(pool->get_segment_manager()->allocate(sizeof(T)*count)));
}
//!Deallocate allocated memory. Never throws
void deallocate(const pointer &ptr, size_type count)
{
(void)count;
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
if(Version == 1 && count == 1)
pool->deallocate_node(detail::get_pointer(ptr));
else
pool->get_segment_manager()->deallocate((void*)detail::get_pointer(ptr));
}
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one()
{
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
return pointer(static_cast<value_type*>(pool->allocate_node()));
}
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements)
{
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
return multiallocation_chain(pool->allocate_nodes(num_elements));
}
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p)
{
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
pool->deallocate_node(detail::get_pointer(p));
}
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain)
{
node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes
(chain.extract_multiallocation_chain());
}
//!Deallocates all free blocks of the pool
void deallocate_free_blocks()
{ node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); }
//!Deprecated, use deallocate_free_blocks.
//!Deallocates all free chunks of the pool.
void deallocate_free_chunks()
{ node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); }
};
template<class T, class NodePool, unsigned int Version>
class cached_allocator_impl
: public array_allocation_impl
<cached_allocator_impl<T, NodePool, Version>, T, typename NodePool::segment_manager>
{
cached_allocator_impl & operator=(const cached_allocator_impl& other);
typedef array_allocation_impl
< cached_allocator_impl
<T, NodePool, Version>
, T
, typename NodePool::segment_manager> base_t;
public:
typedef NodePool node_pool_t;
typedef typename NodePool::segment_manager segment_manager;
typedef typename segment_manager::void_pointer void_pointer;
typedef typename boost::
pointer_to_other<void_pointer, const void>::type cvoid_pointer;
typedef typename base_t::pointer pointer;
typedef typename base_t::size_type size_type;
typedef typename base_t::multiallocation_chain multiallocation_chain;
typedef typename base_t::value_type value_type;
public:
enum { DEFAULT_MAX_CACHED_NODES = 64 };
cached_allocator_impl(segment_manager *segment_mngr, std::size_t max_cached_nodes)
: m_cache(segment_mngr, max_cached_nodes)
{}
cached_allocator_impl(const cached_allocator_impl &other)
: m_cache(other.m_cache)
{}
//!Copy constructor from related cached_adaptive_pool_base. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2, class NodePool2>
cached_allocator_impl
(const cached_allocator_impl
<T2, NodePool2, Version> &other)
: m_cache(other.get_segment_manager(), other.get_max_cached_nodes())
{}
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const
{ return m_cache.get_node_pool(); }
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const
{ return m_cache.get_segment_manager(); }
//!Sets the new max cached nodes value. This can provoke deallocations
//!if "newmax" is less than current cached nodes. Never throws
void set_max_cached_nodes(std::size_t newmax)
{ m_cache.set_max_cached_nodes(newmax); }
//!Returns the max cached nodes parameter.
//!Never throws
std::size_t get_max_cached_nodes() const
{ return m_cache.get_max_cached_nodes(); }
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0)
{
(void)hint;
void * ret;
if(count > this->max_size())
throw bad_alloc();
else if(Version == 1 && count == 1){
ret = m_cache.cached_allocation();
}
else{
ret = this->get_segment_manager()->allocate(sizeof(T)*count);
}
return pointer(static_cast<T*>(ret));
}
//!Deallocate allocated memory. Never throws
void deallocate(const pointer &ptr, size_type count)
{
(void)count;
if(Version == 1 && count == 1){
m_cache.cached_deallocation(detail::get_pointer(ptr));
}
else{
this->get_segment_manager()->deallocate((void*)detail::get_pointer(ptr));
}
}
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one()
{ return pointer(static_cast<value_type*>(this->m_cache.cached_allocation())); }
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements)
{ return multiallocation_chain(this->m_cache.cached_allocation(num_elements)); }
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p)
{ this->m_cache.cached_deallocation(detail::get_pointer(p)); }
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain)
{
typename node_pool_t::multiallocation_chain mem
(chain.extract_multiallocation_chain());
m_cache.cached_deallocation(boost::interprocess::move(mem));
}
//!Deallocates all free blocks of the pool
void deallocate_free_blocks()
{ m_cache.get_node_pool()->deallocate_free_blocks(); }
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different shared memory segments, the result is undefined.
friend void swap(cached_allocator_impl &alloc1, cached_allocator_impl &alloc2)
{
detail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool);
alloc1.m_cached_nodes.swap(alloc2.m_cached_nodes);
detail::do_swap(alloc1.m_max_cached_nodes, alloc2.m_max_cached_nodes);
}
void deallocate_cache()
{ m_cache.deallocate_all_cached_nodes(); }
//!Deprecated use deallocate_free_blocks.
void deallocate_free_chunks()
{ m_cache.get_node_pool()->deallocate_free_blocks(); }
/// @cond
private:
cache_impl<node_pool_t> m_cache;
};
//!Equality test for same type of
//!cached_allocator_impl
template<class T, class N, unsigned int V> inline
bool operator==(const cached_allocator_impl<T, N, V> &alloc1,
const cached_allocator_impl<T, N, V> &alloc2)
{ return alloc1.get_node_pool() == alloc2.get_node_pool(); }
//!Inequality test for same type of
//!cached_allocator_impl
template<class T, class N, unsigned int V> inline
bool operator!=(const cached_allocator_impl<T, N, V> &alloc1,
const cached_allocator_impl<T, N, V> &alloc2)
{ return alloc1.get_node_pool() != alloc2.get_node_pool(); }
//!Pooled shared memory allocator using adaptive pool. Includes
//!a reference count but the class does not delete itself, this is
//!responsibility of user classes. Node size (NodeSize) and the number of
//!nodes allocated per block (NodesPerBlock) are known at compile time
template<class private_node_allocator_t>
class shared_pool_impl
: public private_node_allocator_t
{
public:
//!Segment manager typedef
typedef typename private_node_allocator_t::
segment_manager segment_manager;
typedef typename private_node_allocator_t::
multiallocation_chain multiallocation_chain;
private:
typedef typename segment_manager::mutex_family::mutex_type mutex_type;
public:
//!Constructor from a segment manager. Never throws
shared_pool_impl(segment_manager *segment_mngr)
: private_node_allocator_t(segment_mngr)
{}
//!Destructor. Deallocates all allocated blocks. Never throws
~shared_pool_impl()
{}
//!Allocates array of count elements. Can throw boost::interprocess::bad_alloc
void *allocate_node()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
return private_node_allocator_t::allocate_node();
}
//!Deallocates an array pointed by ptr. Never throws
void deallocate_node(void *ptr)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_node(ptr);
}
/*
//!Allocates a singly linked list of n nodes ending in null pointer.
//!can throw boost::interprocess::bad_alloc
void allocate_nodes(multiallocation_chain &nodes, std::size_t n)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
return private_node_allocator_t::allocate_nodes(nodes, n);
}
*/
//!Allocates n nodes.
//!Can throw boost::interprocess::bad_alloc
multiallocation_chain allocate_nodes(const std::size_t n)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
return private_node_allocator_t::allocate_nodes(n);
}
//!Deallocates a linked list of nodes ending in null pointer. Never throws
void deallocate_nodes(multiallocation_chain &nodes, std::size_t num)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_nodes(nodes, num);
}
//!Deallocates the nodes pointed by the multiallocation iterator. Never throws
void deallocate_nodes(multiallocation_chain chain)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_nodes(boost::interprocess::move(chain));
}
//!Deallocates all the free blocks of memory. Never throws
void deallocate_free_blocks()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_free_blocks();
}
//!Deallocates all used memory from the common pool.
//!Precondition: all nodes allocated from this pool should
//!already be deallocated. Otherwise, undefined behavior. Never throws
void purge_blocks()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::purge_blocks();
}
//!Increments internal reference count and returns new count. Never throws
std::size_t inc_ref_count()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
return ++m_header.m_usecount;
}
//!Decrements internal reference count and returns new count. Never throws
std::size_t dec_ref_count()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
assert(m_header.m_usecount > 0);
return --m_header.m_usecount;
}
//!Deprecated, use deallocate_free_blocks.
void deallocate_free_chunks()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_free_blocks();
}
//!Deprecated, use purge_blocks.
void purge_chunks()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::purge_blocks();
}
private:
//!This struct includes needed data and derives from
//!interprocess_mutex to allow EBO when using null_mutex
struct header_t : mutex_type
{
std::size_t m_usecount; //Number of attached allocators
header_t()
: m_usecount(0) {}
} m_header;
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP

View File

@@ -0,0 +1,409 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2008. 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)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP
#define BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/intrusive/slist.hpp>
#include <boost/math/common_factor_ct.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/math_functions.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/allocators/detail/node_tools.hpp>
#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <cstddef>
#include <functional>
#include <algorithm>
#include <cassert>
//!\file
//!Describes the real adaptive pool shared by many Interprocess adaptive pool allocators
namespace boost {
namespace interprocess {
namespace detail {
template<class SegmentManagerBase>
class private_node_pool_impl
{
//Non-copyable
private_node_pool_impl();
private_node_pool_impl(const private_node_pool_impl &);
private_node_pool_impl &operator=(const private_node_pool_impl &);
//A node object will hold node_t when it's not allocated
public:
typedef typename SegmentManagerBase::void_pointer void_pointer;
typedef typename node_slist<void_pointer>::slist_hook_t slist_hook_t;
typedef typename node_slist<void_pointer>::node_t node_t;
typedef typename node_slist<void_pointer>::node_slist_t free_nodes_t;
typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain;
private:
typedef typename bi::make_slist
< node_t, bi::base_hook<slist_hook_t>
, bi::linear<true>
, bi::constant_time_size<false> >::type blockslist_t;
public:
//!Segment manager typedef
typedef SegmentManagerBase segment_manager_base_type;
//!Constructor from a segment manager. Never throws
private_node_pool_impl(segment_manager_base_type *segment_mngr_base, std::size_t node_size, std::size_t nodes_per_block)
: m_nodes_per_block(nodes_per_block)
, m_real_node_size(detail::lcm(node_size, std::size_t(alignment_of<node_t>::value)))
//General purpose allocator
, mp_segment_mngr_base(segment_mngr_base)
, m_blocklist()
, m_freelist()
//Debug node count
, m_allocated(0)
{}
//!Destructor. Deallocates all allocated blocks. Never throws
~private_node_pool_impl()
{ this->purge_blocks(); }
std::size_t get_real_num_node() const
{ return m_nodes_per_block; }
//!Returns the segment manager. Never throws
segment_manager_base_type* get_segment_manager_base()const
{ return detail::get_pointer(mp_segment_mngr_base); }
//!Allocates array of count elements. Can throw boost::interprocess::bad_alloc
void *allocate_node()
{
//If there are no free nodes we allocate a new block
if (m_freelist.empty())
priv_alloc_block();
//We take the first free node
node_t *n = &m_freelist.front();
m_freelist.pop_front();
++m_allocated;
return n;
}
//!Deallocates an array pointed by ptr. Never throws
void deallocate_node(void *ptr)
{
//We put the node at the beginning of the free node list
node_t * to_deallocate = static_cast<node_t*>(ptr);
m_freelist.push_front(*to_deallocate);
assert(m_allocated>0);
--m_allocated;
}
//!Allocates a singly linked list of n nodes ending in null pointer
//!can throw boost::interprocess::bad_alloc
multiallocation_chain allocate_nodes(const std::size_t n)
{
multiallocation_chain nodes;
std::size_t i = 0;
try{
for(; i < n; ++i){
nodes.push_front(this->allocate_node());
}
}
catch(...){
this->deallocate_nodes(nodes, i);
throw;
}
return boost::interprocess::move(nodes);
}
//!Deallocates the first n nodes of a linked list of nodes. Never throws
void deallocate_nodes(multiallocation_chain &nodes, std::size_t n)
{
for(std::size_t i = 0; i < n; ++i){
void *p = detail::get_pointer(nodes.front());
assert(p);
nodes.pop_front();
this->deallocate_node(p);
}
}
//!Deallocates the nodes pointed by the multiallocation iterator. Never throws
void deallocate_nodes(multiallocation_chain chain)
{
while(!chain.empty()){
void *addr = detail::get_pointer(chain.front());
chain.pop_front();
deallocate_node(addr);
}
}
//!Deallocates all the free blocks of memory. Never throws
void deallocate_free_blocks()
{
typedef typename free_nodes_t::iterator nodelist_iterator;
typename blockslist_t::iterator bit(m_blocklist.before_begin()),
it(m_blocklist.begin()),
itend(m_blocklist.end());
free_nodes_t backup_list;
nodelist_iterator backup_list_last = backup_list.before_begin();
//Execute the algorithm and get an iterator to the last value
std::size_t blocksize = detail::get_rounded_size
(m_real_node_size*m_nodes_per_block, alignment_of<node_t>::value);
while(it != itend){
//Collect all the nodes from the block pointed by it
//and push them in the list
free_nodes_t free_nodes;
nodelist_iterator last_it = free_nodes.before_begin();
const void *addr = get_block_from_hook(&*it, blocksize);
m_freelist.remove_and_dispose_if
(is_between(addr, blocksize), push_in_list(free_nodes, last_it));
//If the number of nodes is equal to m_nodes_per_block
//this means that the block can be deallocated
if(free_nodes.size() == m_nodes_per_block){
//Unlink the nodes
free_nodes.clear();
it = m_blocklist.erase_after(bit);
mp_segment_mngr_base->deallocate((void*)addr);
}
//Otherwise, insert them in the backup list, since the
//next "remove_if" does not need to check them again.
else{
//Assign the iterator to the last value if necessary
if(backup_list.empty() && !m_freelist.empty()){
backup_list_last = last_it;
}
//Transfer nodes. This is constant time.
backup_list.splice_after
( backup_list.before_begin()
, free_nodes
, free_nodes.before_begin()
, last_it
, free_nodes.size());
bit = it;
++it;
}
}
//We should have removed all the nodes from the free list
assert(m_freelist.empty());
//Now pass all the node to the free list again
m_freelist.splice_after
( m_freelist.before_begin()
, backup_list
, backup_list.before_begin()
, backup_list_last
, backup_list.size());
}
std::size_t num_free_nodes()
{ return m_freelist.size(); }
//!Deallocates all used memory. Precondition: all nodes allocated from this pool should
//!already be deallocated. Otherwise, undefined behaviour. Never throws
void purge_blocks()
{
//check for memory leaks
assert(m_allocated==0);
std::size_t blocksize = detail::get_rounded_size
(m_real_node_size*m_nodes_per_block, alignment_of<node_t>::value);
typename blockslist_t::iterator
it(m_blocklist.begin()), itend(m_blocklist.end()), aux;
//We iterate though the NodeBlock list to free the memory
while(!m_blocklist.empty()){
void *addr = get_block_from_hook(&m_blocklist.front(), blocksize);
m_blocklist.pop_front();
mp_segment_mngr_base->deallocate((void*)addr);
}
//Just clear free node list
m_freelist.clear();
}
void swap(private_node_pool_impl &other)
{
std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base);
m_blocklist.swap(other.m_blocklist);
m_freelist.swap(other.m_freelist);
std::swap(m_allocated, other.m_allocated);
}
private:
struct push_in_list
{
push_in_list(free_nodes_t &l, typename free_nodes_t::iterator &it)
: slist_(l), last_it_(it)
{}
void operator()(typename free_nodes_t::pointer p) const
{
slist_.push_front(*p);
if(slist_.size() == 1){ //Cache last element
++last_it_ = slist_.begin();
}
}
private:
free_nodes_t &slist_;
typename free_nodes_t::iterator &last_it_;
};
struct is_between
: std::unary_function<typename free_nodes_t::value_type, bool>
{
is_between(const void *addr, std::size_t size)
: beg_(static_cast<const char *>(addr)), end_(beg_+size)
{}
bool operator()(typename free_nodes_t::const_reference v) const
{
return (beg_ <= reinterpret_cast<const char *>(&v) &&
end_ > reinterpret_cast<const char *>(&v));
}
private:
const char * beg_;
const char * end_;
};
//!Allocates a block of nodes. Can throw boost::interprocess::bad_alloc
void priv_alloc_block()
{
//We allocate a new NodeBlock and put it as first
//element in the free Node list
std::size_t blocksize =
detail::get_rounded_size(m_real_node_size*m_nodes_per_block, alignment_of<node_t>::value);
char *pNode = reinterpret_cast<char*>
(mp_segment_mngr_base->allocate(blocksize + sizeof(node_t)));
if(!pNode) throw bad_alloc();
char *pBlock = pNode;
m_blocklist.push_front(get_block_hook(pBlock, blocksize));
//We initialize all Nodes in Node Block to insert
//them in the free Node list
for(std::size_t i = 0; i < m_nodes_per_block; ++i, pNode += m_real_node_size){
m_freelist.push_front(*new (pNode) node_t);
}
}
//!Deprecated, use deallocate_free_blocks
void deallocate_free_chunks()
{ this->deallocate_free_blocks(); }
//!Deprecated, use purge_blocks
void purge_chunks()
{ this->purge_blocks(); }
private:
//!Returns a reference to the block hook placed in the end of the block
static inline node_t & get_block_hook (void *block, std::size_t blocksize)
{
return *reinterpret_cast<node_t*>(reinterpret_cast<char*>(block) + blocksize);
}
//!Returns the starting address of the block reference to the block hook placed in the end of the block
inline void *get_block_from_hook (node_t *hook, std::size_t blocksize)
{
return (reinterpret_cast<char*>(hook) - blocksize);
}
private:
typedef typename boost::pointer_to_other
<void_pointer, segment_manager_base_type>::type segment_mngr_base_ptr_t;
const std::size_t m_nodes_per_block;
const std::size_t m_real_node_size;
segment_mngr_base_ptr_t mp_segment_mngr_base; //Segment manager
blockslist_t m_blocklist; //Intrusive container of blocks
free_nodes_t m_freelist; //Intrusive container of free nods
std::size_t m_allocated; //Used nodes for debugging
};
//!Pooled shared memory allocator using single segregated storage. Includes
//!a reference count but the class does not delete itself, this is
//!responsibility of user classes. Node size (NodeSize) and the number of
//!nodes allocated per block (NodesPerBlock) are known at compile time
template< class SegmentManager, std::size_t NodeSize, std::size_t NodesPerBlock >
class private_node_pool
//Inherit from the implementation to avoid template bloat
: public private_node_pool_impl<typename SegmentManager::segment_manager_base_type>
{
typedef private_node_pool_impl<typename SegmentManager::segment_manager_base_type> base_t;
//Non-copyable
private_node_pool();
private_node_pool(const private_node_pool &);
private_node_pool &operator=(const private_node_pool &);
public:
typedef SegmentManager segment_manager;
static const std::size_t nodes_per_block = NodesPerBlock;
//Deprecated, use nodes_per_block
static const std::size_t nodes_per_chunk = NodesPerBlock;
//!Constructor from a segment manager. Never throws
private_node_pool(segment_manager *segment_mngr)
: base_t(segment_mngr, NodeSize, NodesPerBlock)
{}
//!Returns the segment manager. Never throws
segment_manager* get_segment_manager() const
{ return static_cast<segment_manager*>(base_t::get_segment_manager_base()); }
};
//!Pooled shared memory allocator using single segregated storage. Includes
//!a reference count but the class does not delete itself, this is
//!responsibility of user classes. Node size (NodeSize) and the number of
//!nodes allocated per block (NodesPerBlock) are known at compile time
//!Pooled shared memory allocator using adaptive pool. Includes
//!a reference count but the class does not delete itself, this is
//!responsibility of user classes. Node size (NodeSize) and the number of
//!nodes allocated per block (NodesPerBlock) are known at compile time
template< class SegmentManager
, std::size_t NodeSize
, std::size_t NodesPerBlock
>
class shared_node_pool
: public detail::shared_pool_impl
< private_node_pool
<SegmentManager, NodeSize, NodesPerBlock>
>
{
typedef detail::shared_pool_impl
< private_node_pool
<SegmentManager, NodeSize, NodesPerBlock>
> base_t;
public:
shared_node_pool(SegmentManager *segment_mgnr)
: base_t(segment_mgnr)
{}
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP

View File

@@ -0,0 +1,50 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2008. 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)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_HPP
#define BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/intrusive/slist.hpp>
namespace boost {
namespace interprocess {
namespace detail {
template<class VoidPointer>
struct node_slist
{
//This hook will be used to chain the individual nodes
typedef typename bi::make_slist_base_hook
<bi::void_pointer<VoidPointer>, bi::link_mode<bi::normal_link> >::type slist_hook_t;
//A node object will hold node_t when it's not allocated
struct node_t
: public slist_hook_t
{};
typedef typename bi::make_slist
<node_t, bi::linear<true>, bi::base_hook<slist_hook_t> >::type node_slist_t;
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_HPP

View File

@@ -0,0 +1,449 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2008. 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)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/allocators/detail/node_pool.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
//!\file
//!Describes node_allocator pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace detail{
template < unsigned int Version
, class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class node_allocator_base
: public node_pool_allocation_impl
< node_allocator_base
< Version, T, SegmentManager, NodesPerBlock>
, Version
, T
, SegmentManager
>
{
public:
typedef typename SegmentManager::void_pointer void_pointer;
typedef SegmentManager segment_manager;
typedef node_allocator_base
<Version, T, SegmentManager, NodesPerBlock> self_t;
/// @cond
template <int dummy>
struct node_pool
{
typedef detail::shared_node_pool
< SegmentManager, sizeof_value<T>::value, NodesPerBlock> type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
/// @endcond
BOOST_STATIC_ASSERT((Version <=2));
public:
//-------
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::interprocess::version_type<node_allocator_base, Version> version;
typedef detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
//!Obtains node_allocator_base from
//!node_allocator_base
template<class T2>
struct rebind
{
typedef node_allocator_base<Version, T2, SegmentManager, NodesPerBlock> other;
};
/// @cond
private:
//!Not assignable from related node_allocator_base
template<unsigned int Version2, class T2, class SegmentManager2, std::size_t N2>
node_allocator_base& operator=
(const node_allocator_base<Version2, T2, SegmentManager2, N2>&);
//!Not assignable from other node_allocator_base
//node_allocator_base& operator=(const node_allocator_base&);
/// @endcond
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
node_allocator_base(segment_manager *segment_mngr)
: mp_node_pool(detail::get_or_create_node_pool<typename node_pool<0>::type>(segment_mngr)) { }
//!Copy constructor from other node_allocator_base. Increments the reference
//!count of the associated node pool. Never throws
node_allocator_base(const node_allocator_base &other)
: mp_node_pool(other.get_node_pool())
{
node_pool<0>::get(detail::get_pointer(mp_node_pool))->inc_ref_count();
}
//!Copy constructor from related node_allocator_base. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
node_allocator_base
(const node_allocator_base<Version, T2, SegmentManager, NodesPerBlock> &other)
: mp_node_pool(detail::get_or_create_node_pool<typename node_pool<0>::type>(other.get_segment_manager())) { }
//!Assignment from other node_allocator_base
node_allocator_base& operator=(const node_allocator_base &other)
{
node_allocator_base c(other);
swap(*this, c);
return *this;
}
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~node_allocator_base()
{ detail::destroy_node_pool_if_last_link(node_pool<0>::get(detail::get_pointer(mp_node_pool))); }
//!Returns a pointer to the node pool.
//!Never throws
void* get_node_pool() const
{ return detail::get_pointer(mp_node_pool); }
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const
{ return node_pool<0>::get(detail::get_pointer(mp_node_pool))->get_segment_manager(); }
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2)
{ detail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool); }
/// @cond
private:
void_pointer mp_node_pool;
/// @endcond
};
//!Equality test for same type
//!of node_allocator_base
template<unsigned int V, class T, class S, std::size_t NPC> inline
bool operator==(const node_allocator_base<V, T, S, NPC> &alloc1,
const node_allocator_base<V, T, S, NPC> &alloc2)
{ return alloc1.get_node_pool() == alloc2.get_node_pool(); }
//!Inequality test for same type
//!of node_allocator_base
template<unsigned int V, class T, class S, std::size_t NPC> inline
bool operator!=(const node_allocator_base<V, T, S, NPC> &alloc1,
const node_allocator_base<V, T, S, NPC> &alloc2)
{ return alloc1.get_node_pool() != alloc2.get_node_pool(); }
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
>
class node_allocator_v1
: public node_allocator_base
< 1
, T
, SegmentManager
, NodesPerBlock
>
{
public:
typedef detail::node_allocator_base
< 1, T, SegmentManager, NodesPerBlock> base_t;
template<class T2>
struct rebind
{
typedef node_allocator_v1<T2, SegmentManager, NodesPerBlock> other;
};
node_allocator_v1(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
node_allocator_v1
(const node_allocator_v1<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
};
} //namespace detail{
/// @endcond
//!An STL node allocator that uses a segment manager as memory
//!source. The internal pointer type will of the same type (raw, smart) as
//!"typename SegmentManager::void_pointer" type. This allows
//!placing the allocator in shared memory, memory mapped-files, etc...
//!This node allocator shares a segregated storage between all instances
//!of node_allocator with equal sizeof(T) placed in the same segment
//!group. NodesPerBlock is the number of nodes allocated at once when the allocator
//!needs runs out of nodes
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class node_allocator
/// @cond
: public detail::node_allocator_base
< 2
, T
, SegmentManager
, NodesPerBlock
>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
typedef detail::node_allocator_base
< 2, T, SegmentManager, NodesPerBlock> base_t;
public:
typedef boost::interprocess::version_type<node_allocator, 2> version;
template<class T2>
struct rebind
{
typedef node_allocator<T2, SegmentManager, NodesPerBlock> other;
};
node_allocator(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
node_allocator
(const node_allocator<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
#else //BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
//!Obtains node_allocator from
//!node_allocator
template<class T2>
struct rebind
{
typedef node_allocator<T2, SegmentManager, NodesPerBlock> other;
};
private:
//!Not assignable from
//!related node_allocator
template<class T2, class SegmentManager2, std::size_t N2>
node_allocator& operator=
(const node_allocator<T2, SegmentManager2, N2>&);
//!Not assignable from
//!other node_allocator
//node_allocator& operator=(const node_allocator&);
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
node_allocator(segment_manager *segment_mngr);
//!Copy constructor from other node_allocator. Increments the reference
//!count of the associated node pool. Never throws
node_allocator(const node_allocator &other);
//!Copy constructor from related node_allocator. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
node_allocator
(const node_allocator<T2, SegmentManager, NodesPerBlock> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~node_allocator();
//!Returns a pointer to the node pool.
//!Never throws
void* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements);
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain);
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of node_allocator
template<class T, class S, std::size_t NPC> inline
bool operator==(const node_allocator<T, S, NPC> &alloc1,
const node_allocator<T, S, NPC> &alloc2);
//!Inequality test for same type
//!of node_allocator
template<class T, class S, std::size_t NPC> inline
bool operator!=(const node_allocator<T, S, NPC> &alloc1,
const node_allocator<T, S, NPC> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP

View File

@@ -0,0 +1,465 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2008. 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)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP
#define BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/allocators/detail/adaptive_node_pool.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
//!\file
//!Describes private_adaptive_pool_base pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace detail {
template < unsigned int Version
, class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class private_adaptive_pool_base
: public node_pool_allocation_impl
< private_adaptive_pool_base < Version, T, SegmentManager, NodesPerBlock
, MaxFreeBlocks, OverheadPercent>
, Version
, T
, SegmentManager
>
{
public:
//Segment manager
typedef SegmentManager segment_manager;
typedef typename SegmentManager::void_pointer void_pointer;
/// @cond
private:
typedef private_adaptive_pool_base
< Version, T, SegmentManager, NodesPerBlock
, MaxFreeBlocks, OverheadPercent> self_t;
typedef detail::private_adaptive_node_pool
<SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
> node_pool_t;
BOOST_STATIC_ASSERT((Version <=2));
/// @endcond
public:
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::interprocess::version_type
<private_adaptive_pool_base, Version> version;
typedef detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
//!Obtains node_allocator from other node_allocator
template<class T2>
struct rebind
{
typedef private_adaptive_pool_base
<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
/// @cond
template <int dummy>
struct node_pool
{
typedef detail::private_adaptive_node_pool
<SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
> type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
private:
//!Not assignable from related private_adaptive_pool_base
template<unsigned int Version2, class T2, class MemoryAlgorithm2, std::size_t N2, std::size_t F2, unsigned char OP2>
private_adaptive_pool_base& operator=
(const private_adaptive_pool_base<Version2, T2, MemoryAlgorithm2, N2, F2, OP2>&);
//!Not assignable from other private_adaptive_pool_base
private_adaptive_pool_base& operator=(const private_adaptive_pool_base&);
/// @endcond
public:
//!Constructor from a segment manager
private_adaptive_pool_base(segment_manager *segment_mngr)
: m_node_pool(segment_mngr)
{}
//!Copy constructor from other private_adaptive_pool_base. Never throws
private_adaptive_pool_base(const private_adaptive_pool_base &other)
: m_node_pool(other.get_segment_manager())
{}
//!Copy constructor from related private_adaptive_pool_base. Never throws.
template<class T2>
private_adaptive_pool_base
(const private_adaptive_pool_base
<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: m_node_pool(other.get_segment_manager())
{}
//!Destructor, frees all used memory. Never throws
~private_adaptive_pool_base()
{}
//!Returns the segment manager. Never throws
segment_manager* get_segment_manager()const
{ return m_node_pool.get_segment_manager(); }
//!Returns the internal node pool. Never throws
node_pool_t* get_node_pool() const
{ return const_cast<node_pool_t*>(&m_node_pool); }
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different shared memory segments, the result is undefined.
friend void swap(self_t &alloc1,self_t &alloc2)
{ alloc1.m_node_pool.swap(alloc2.m_node_pool); }
/// @cond
private:
node_pool_t m_node_pool;
/// @endcond
};
//!Equality test for same type of private_adaptive_pool_base
template<unsigned int V, class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator==(const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc1,
const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc2)
{ return &alloc1 == &alloc2; }
//!Inequality test for same type of private_adaptive_pool_base
template<unsigned int V, class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator!=(const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc1,
const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc2)
{ return &alloc1 != &alloc2; }
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class private_adaptive_pool_v1
: public private_adaptive_pool_base
< 1
, T
, SegmentManager
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
{
public:
typedef detail::private_adaptive_pool_base
< 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
template<class T2>
struct rebind
{
typedef private_adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private_adaptive_pool_v1(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
private_adaptive_pool_v1
(const private_adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
};
} //namespace detail {
/// @endcond
//!An STL node allocator that uses a segment manager as memory
//!source. The internal pointer type will of the same type (raw, smart) as
//!"typename SegmentManager::void_pointer" type. This allows
//!placing the allocator in shared memory, memory mapped-files, etc...
//!This allocator has its own node pool.
//!
//!NodesPerBlock is the minimum number of nodes of nodes allocated at once when
//!the allocator needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks
//!that the adaptive node pool will hold. The rest of the totally free blocks will be
//!deallocated with the segment manager.
//!
//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator:
//!(memory usable for nodes / total memory allocated from the segment manager)
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class private_adaptive_pool
/// @cond
: public detail::private_adaptive_pool_base
< 2
, T
, SegmentManager
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
typedef detail::private_adaptive_pool_base
< 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
public:
typedef boost::interprocess::version_type<private_adaptive_pool, 2> version;
template<class T2>
struct rebind
{
typedef private_adaptive_pool
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private_adaptive_pool(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
private_adaptive_pool
(const private_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
#else
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
//!Obtains private_adaptive_pool from
//!private_adaptive_pool
template<class T2>
struct rebind
{
typedef private_adaptive_pool
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private:
//!Not assignable from
//!related private_adaptive_pool
template<class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char OP2>
private_adaptive_pool& operator=
(const private_adaptive_pool<T2, SegmentManager2, N2, F2>&);
//!Not assignable from
//!other private_adaptive_pool
private_adaptive_pool& operator=(const private_adaptive_pool&);
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
private_adaptive_pool(segment_manager *segment_mngr);
//!Copy constructor from other private_adaptive_pool. Increments the reference
//!count of the associated node pool. Never throws
private_adaptive_pool(const private_adaptive_pool &other);
//!Copy constructor from related private_adaptive_pool. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
private_adaptive_pool
(const private_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~private_adaptive_pool();
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements);
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain);
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of private_adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator==(const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
//!Inequality test for same type
//!of private_adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator!=(const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP

View File

@@ -0,0 +1,441 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2008. 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)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/allocators/detail/node_pool.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
//!\file
//!Describes private_node_allocator_base pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace detail {
template < unsigned int Version
, class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class private_node_allocator_base
: public node_pool_allocation_impl
< private_node_allocator_base < Version, T, SegmentManager, NodesPerBlock>
, Version
, T
, SegmentManager
>
{
public:
//Segment manager
typedef SegmentManager segment_manager;
typedef typename SegmentManager::void_pointer void_pointer;
/// @cond
private:
typedef private_node_allocator_base
< Version, T, SegmentManager, NodesPerBlock> self_t;
typedef detail::private_node_pool
<SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
> node_pool_t;
BOOST_STATIC_ASSERT((Version <=2));
/// @endcond
public:
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::interprocess::version_type
<private_node_allocator_base, Version> version;
typedef detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
//!Obtains node_allocator from other node_allocator
template<class T2>
struct rebind
{
typedef private_node_allocator_base
<Version, T2, SegmentManager, NodesPerBlock> other;
};
/// @cond
template <int dummy>
struct node_pool
{
typedef detail::private_node_pool
<SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
> type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
private:
//!Not assignable from related private_node_allocator_base
template<unsigned int Version2, class T2, class MemoryAlgorithm2, std::size_t N2>
private_node_allocator_base& operator=
(const private_node_allocator_base<Version2, T2, MemoryAlgorithm2, N2>&);
//!Not assignable from other private_node_allocator_base
private_node_allocator_base& operator=(const private_node_allocator_base&);
/// @endcond
public:
//!Constructor from a segment manager
private_node_allocator_base(segment_manager *segment_mngr)
: m_node_pool(segment_mngr)
{}
//!Copy constructor from other private_node_allocator_base. Never throws
private_node_allocator_base(const private_node_allocator_base &other)
: m_node_pool(other.get_segment_manager())
{}
//!Copy constructor from related private_node_allocator_base. Never throws.
template<class T2>
private_node_allocator_base
(const private_node_allocator_base
<Version, T2, SegmentManager, NodesPerBlock> &other)
: m_node_pool(other.get_segment_manager())
{}
//!Destructor, frees all used memory. Never throws
~private_node_allocator_base()
{}
//!Returns the segment manager. Never throws
segment_manager* get_segment_manager()const
{ return m_node_pool.get_segment_manager(); }
//!Returns the internal node pool. Never throws
node_pool_t* get_node_pool() const
{ return const_cast<node_pool_t*>(&m_node_pool); }
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different shared memory segments, the result is undefined.
friend void swap(self_t &alloc1,self_t &alloc2)
{ alloc1.m_node_pool.swap(alloc2.m_node_pool); }
/// @cond
private:
node_pool_t m_node_pool;
/// @endcond
};
//!Equality test for same type of private_node_allocator_base
template<unsigned int V, class T, class S, std::size_t NPC> inline
bool operator==(const private_node_allocator_base<V, T, S, NPC> &alloc1,
const private_node_allocator_base<V, T, S, NPC> &alloc2)
{ return &alloc1 == &alloc2; }
//!Inequality test for same type of private_node_allocator_base
template<unsigned int V, class T, class S, std::size_t NPC> inline
bool operator!=(const private_node_allocator_base<V, T, S, NPC> &alloc1,
const private_node_allocator_base<V, T, S, NPC> &alloc2)
{ return &alloc1 != &alloc2; }
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
>
class private_node_allocator_v1
: public private_node_allocator_base
< 1
, T
, SegmentManager
, NodesPerBlock
>
{
public:
typedef detail::private_node_allocator_base
< 1, T, SegmentManager, NodesPerBlock> base_t;
template<class T2>
struct rebind
{
typedef private_node_allocator_v1<T2, SegmentManager, NodesPerBlock> other;
};
private_node_allocator_v1(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
private_node_allocator_v1
(const private_node_allocator_v1<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
};
} //namespace detail {
/// @endcond
//!An STL node allocator that uses a segment manager as memory
//!source. The internal pointer type will of the same type (raw, smart) as
//!"typename SegmentManager::void_pointer" type. This allows
//!placing the allocator in shared memory, memory mapped-files, etc...
//!This allocator has its own node pool. NodesPerBlock is the number of nodes allocated
//!at once when the allocator needs runs out of nodes
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class private_node_allocator
/// @cond
: public detail::private_node_allocator_base
< 2
, T
, SegmentManager
, NodesPerBlock
>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
typedef detail::private_node_allocator_base
< 2, T, SegmentManager, NodesPerBlock> base_t;
public:
typedef boost::interprocess::version_type<private_node_allocator, 2> version;
template<class T2>
struct rebind
{
typedef private_node_allocator
<T2, SegmentManager, NodesPerBlock> other;
};
private_node_allocator(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
private_node_allocator
(const private_node_allocator<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
#else
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
//!Obtains private_node_allocator from
//!private_node_allocator
template<class T2>
struct rebind
{
typedef private_node_allocator
<T2, SegmentManager, NodesPerBlock> other;
};
private:
//!Not assignable from
//!related private_node_allocator
template<class T2, class SegmentManager2, std::size_t N2>
private_node_allocator& operator=
(const private_node_allocator<T2, SegmentManager2, N2>&);
//!Not assignable from
//!other private_node_allocator
private_node_allocator& operator=(const private_node_allocator&);
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
private_node_allocator(segment_manager *segment_mngr);
//!Copy constructor from other private_node_allocator. Increments the reference
//!count of the associated node pool. Never throws
private_node_allocator(const private_node_allocator &other);
//!Copy constructor from related private_node_allocator. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
private_node_allocator
(const private_node_allocator<T2, SegmentManager, NodesPerBlock> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~private_node_allocator();
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements);
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain);
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of private_node_allocator
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator==(const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc1,
const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc2);
//!Inequality test for same type
//!of private_node_allocator
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator!=(const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc1,
const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP