diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
commit | 1a78a62555be32868418fe52f8e330c9d0f95d5a (patch) | |
tree | d3765a80e7d3b9640ec2e930743630cd6b9fce2b /boost/interprocess/allocators | |
download | boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.gz boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.bz2 boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.zip |
Imported Upstream version 1.49.0upstream/1.49.0
Diffstat (limited to 'boost/interprocess/allocators')
-rw-r--r-- | boost/interprocess/allocators/adaptive_pool.hpp | 468 | ||||
-rw-r--r-- | boost/interprocess/allocators/allocator.hpp | 307 | ||||
-rw-r--r-- | boost/interprocess/allocators/cached_adaptive_pool.hpp | 356 | ||||
-rw-r--r-- | boost/interprocess/allocators/cached_node_allocator.hpp | 327 | ||||
-rw-r--r-- | boost/interprocess/allocators/detail/adaptive_node_pool.hpp | 108 | ||||
-rw-r--r-- | boost/interprocess/allocators/detail/allocator_common.hpp | 862 | ||||
-rw-r--r-- | boost/interprocess/allocators/detail/node_pool.hpp | 109 | ||||
-rw-r--r-- | boost/interprocess/allocators/detail/node_tools.hpp | 50 | ||||
-rw-r--r-- | boost/interprocess/allocators/node_allocator.hpp | 452 | ||||
-rw-r--r-- | boost/interprocess/allocators/private_adaptive_pool.hpp | 468 | ||||
-rw-r--r-- | boost/interprocess/allocators/private_node_allocator.hpp | 445 |
11 files changed, 3952 insertions, 0 deletions
diff --git a/boost/interprocess/allocators/adaptive_pool.hpp b/boost/interprocess/allocators/adaptive_pool.hpp new file mode 100644 index 0000000000..846df5d413 --- /dev/null +++ b/boost/interprocess/allocators/adaptive_pool.hpp @@ -0,0 +1,468 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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/intrusive/pointer_traits.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/container/detail/multiallocation_chain.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 ipcdetail{ + +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 ipcdetail::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::intrusive:: + pointer_traits<void_pointer>::template + rebind_pointer<T>::type pointer; + typedef typename boost::intrusive:: + pointer_traits<void_pointer>::template + rebind_pointer<const T>::type const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type difference_type; + + typedef boost::interprocess::version_type<adaptive_pool_base, Version> version; + typedef boost::container::container_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(ipcdetail::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(ipcdetail::to_raw_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(ipcdetail::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() + { ipcdetail::destroy_node_pool_if_last_link(node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))); } + + //!Returns a pointer to the node pool. + //!Never throws + void* get_node_pool() const + { return ipcdetail::to_raw_pointer(mp_node_pool); } + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const + { return node_pool<0>::get(ipcdetail::to_raw_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) + { ipcdetail::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 ipcdetail::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 ipcdetail{ + +/// @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 ipcdetail::adaptive_pool_base + < 2 + , T + , SegmentManager + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > + /// @endcond +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + typedef ipcdetail::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 ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type 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, size_type 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(size_type 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 + diff --git a/boost/interprocess/allocators/allocator.hpp b/boost/interprocess/allocators/allocator.hpp new file mode 100644 index 0000000000..aa4b22dcc9 --- /dev/null +++ b/boost/interprocess/allocators/allocator.hpp @@ -0,0 +1,307 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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/intrusive/pointer_traits.hpp> + +#include <boost/interprocess/interprocess_fwd.hpp> +#include <boost/interprocess/containers/allocation_type.hpp> +#include <boost/container/detail/multiallocation_chain.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 <new> +#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::intrusive:: + pointer_traits<aux_pointer_t>::template + rebind_pointer<const void>::type cvoid_ptr; + + //Pointer to the allocator + typedef typename boost::intrusive:: + pointer_traits<cvoid_ptr>::template + rebind_pointer<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::intrusive:: + pointer_traits<cvoid_ptr>::template + rebind_pointer<T>::type pointer; + typedef typename boost::intrusive:: + pointer_traits<pointer>::template + rebind_pointer<const T>::type const_pointer; + typedef typename ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type difference_type; + + typedef boost::interprocess::version_type<allocator, 2> version; + + /// @cond + + //Experimental. Don't use. + typedef boost::container::container_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 ipcdetail::to_raw_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*)ipcdetail::to_raw_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) + { ipcdetail::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(ipcdetail::to_raw_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, ipcdetail::to_raw_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, size_type 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 + (size_type 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::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)); } + + //!Constructs an object + //!Throws if T's constructor throws + //!For backwards compatibility with libraries using C++03 allocators + template<class P> + void construct(const pointer &ptr, BOOST_FWD_REF(P) p) + { ::new((void*)ipcdetail::to_raw_pointer(ptr)) value_type(::boost::forward<P>(p)); } + + //!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> > +{ + static const bool value = true; +}; +/// @endcond + +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_ALLOCATOR_HPP + diff --git a/boost/interprocess/allocators/cached_adaptive_pool.hpp b/boost/interprocess/allocators/cached_adaptive_pool.hpp new file mode 100644 index 0000000000..bec1050de5 --- /dev/null +++ b/boost/interprocess/allocators/cached_adaptive_pool.hpp @@ -0,0 +1,356 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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 ipcdetail { + +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 ipcdetail::cached_allocator_impl + < T + , ipcdetail::shared_adaptive_node_pool + < SegmentManager + , sizeof_value<T>::value + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > + , 1> +{ + public: + typedef ipcdetail::cached_allocator_impl + < T + , ipcdetail::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; + }; + + typedef typename base_t::size_type size_type; + + cached_adaptive_pool_v1(SegmentManager *segment_mngr, + size_type 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 ipcdetail{ + +/// @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 ipcdetail::cached_allocator_impl + < T + , ipcdetail::shared_adaptive_node_pool + < SegmentManager + , sizeof_value<T>::value + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > + , 2> + /// @endcond +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + typedef ipcdetail::cached_allocator_impl + < T + , ipcdetail::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 ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type 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, size_type 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(size_type 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(size_type newmax); + + //!Returns the max cached nodes parameter. + //!Never throws + size_type 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 + diff --git a/boost/interprocess/allocators/cached_node_allocator.hpp b/boost/interprocess/allocators/cached_node_allocator.hpp new file mode 100644 index 0000000000..03398156db --- /dev/null +++ b/boost/interprocess/allocators/cached_node_allocator.hpp @@ -0,0 +1,327 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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 ipcdetail { + +template < class T + , class SegmentManager + , std::size_t NodesPerBlock = 64 + > +class cached_node_allocator_v1 + : public ipcdetail::cached_allocator_impl + < T + , ipcdetail::shared_node_pool + < SegmentManager + , sizeof_value<T>::value + , NodesPerBlock + > + , 1> +{ + public: + typedef ipcdetail::cached_allocator_impl + < T + , ipcdetail::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; + }; + + typedef typename base_t::size_type size_type; + + cached_node_allocator_v1(SegmentManager *segment_mngr, + size_type 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 ipcdetail{ + +/// @endcond + +template < class T + , class SegmentManager + , std::size_t NodesPerBlock + > +class cached_node_allocator + /// @cond + : public ipcdetail::cached_allocator_impl + < T + , ipcdetail::shared_node_pool + < SegmentManager + , sizeof_value<T>::value + , NodesPerBlock + > + , 2> + /// @endcond +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + typedef ipcdetail::cached_allocator_impl + < T + , ipcdetail::shared_node_pool + < SegmentManager + , sizeof_value<T>::value + , NodesPerBlock + > + , 2> base_t; + + public: + typedef boost::interprocess::version_type<cached_node_allocator, 2> version; + typedef typename base_t::size_type size_type; + + template<class T2> + struct rebind + { + typedef cached_node_allocator<T2, SegmentManager, NodesPerBlock> other; + }; + + cached_node_allocator(SegmentManager *segment_mngr, + size_type 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 ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename SegmentManager::size_type size_type; + typedef typename SegmentManager::difference_type 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, size_type 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(size_type 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(size_type newmax); + + //!Returns the max cached nodes parameter. + //!Never throws + size_type 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 + diff --git a/boost/interprocess/allocators/detail/adaptive_node_pool.hpp b/boost/interprocess/allocators/detail/adaptive_node_pool.hpp new file mode 100644 index 0000000000..4ccc920663 --- /dev/null +++ b/boost/interprocess/allocators/detail/adaptive_node_pool.hpp @@ -0,0 +1,108 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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/interprocess/detail/utilities.hpp> +#include <boost/interprocess/detail/math_functions.hpp> +#include <boost/intrusive/set.hpp> +#include <boost/intrusive/slist.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 <boost/container/detail/adaptive_node_pool_impl.hpp> +#include <boost/assert.hpp> + +//!\file +//!Describes the real adaptive pool shared by many Interprocess pool allocators + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template< class SegmentManager + , std::size_t NodeSize + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks + , unsigned char OverheadPercent + > +class private_adaptive_node_pool + : public boost::container::container_detail::private_adaptive_node_pool_impl + <typename SegmentManager::segment_manager_base_type> +{ + typedef boost::container::container_detail::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; + typedef typename base_t::size_type size_type; + + static const size_type nodes_per_block = NodesPerBlock; + + //Deprecated, use node_per_block + static const size_type 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 ipcdetail::shared_pool_impl + < private_adaptive_node_pool + <SegmentManager, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent> + > +{ + typedef ipcdetail::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 ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_HPP diff --git a/boost/interprocess/allocators/detail/allocator_common.hpp b/boost/interprocess/allocators/detail/allocator_common.hpp new file mode 100644 index 0000000000..ea660b1a90 --- /dev/null +++ b/boost/interprocess/allocators/detail/allocator_common.hpp @@ -0,0 +1,862 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/intrusive/pointer_traits.hpp> + +#include <boost/interprocess/interprocess_fwd.hpp> +#include <boost/interprocess/detail/utilities.hpp> //to_raw_pointer +#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/container/detail/multiallocation_chain.hpp> +#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp> +#include <boost/interprocess/detail/segment_manager_helper.hpp> +#include <boost/move/move.hpp> +#include <boost/interprocess/detail/type_traits.hpp> +#include <boost/interprocess/detail/utilities.hpp> +#include <algorithm> //std::swap +#include <utility> //std::pair +#include <new> + +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 ipcdetail { + +//!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) +{ + ipcdetail::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 boost::intrusive:: + pointer_traits<void_pointer>::template + rebind_pointer<NodePool>::type node_pool_ptr; + typedef typename NodePool::multiallocation_chain multiallocation_chain; + typedef typename NodePool::segment_manager::size_type size_type; + node_pool_ptr mp_node_pool; + multiallocation_chain m_cached_nodes; + size_type m_max_cached_nodes; + + public: + typedef typename NodePool::segment_manager segment_manager; + + cache_impl(segment_manager *segment_mngr, size_type 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(); + ipcdetail::destroy_node_pool_if_last_link(ipcdetail::to_raw_pointer(mp_node_pool)); + } + + NodePool *get_node_pool() const + { return ipcdetail::to_raw_pointer(mp_node_pool); } + + segment_manager *get_segment_manager() const + { return mp_node_pool->get_segment_manager(); } + + size_type 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 = ipcdetail::to_raw_pointer(m_cached_nodes.front()); + m_cached_nodes.pop_front(); + return ret; + } + + multiallocation_chain cached_allocation(size_type n) + { + multiallocation_chain chain; + size_type 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 = ipcdetail::to_raw_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::move(chain); + } + BOOST_CATCH(...){ + this->cached_deallocation(boost::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(size_type 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::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(size_type n) + { + //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. + size_type count(n); + typename multiallocation_chain::iterator it(m_cached_nodes.before_begin()); + while(count--){ + ++it; + } + multiallocation_chain chain; + chain.splice_after(chain.before_begin(), m_cached_nodes, m_cached_nodes.before_begin(), it, n); + //Deallocate all new linked list at once + mp_node_pool->deallocate_nodes(boost::move(chain)); + } + + public: + void swap(cache_impl &other) + { + ipcdetail::do_swap(mp_node_pool, other.mp_node_pool); + m_cached_nodes.swap(other.m_cached_nodes); + ipcdetail::do_swap(m_max_cached_nodes, other.m_max_cached_nodes); + } +}; + +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::intrusive:: + pointer_traits<void_pointer>::template + rebind_pointer<T>::type pointer; + typedef typename boost::intrusive:: + pointer_traits<void_pointer>::template + rebind_pointer<const T>::type const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename SegmentManager::size_type size_type; + typedef typename SegmentManager::difference_type difference_type; + typedef boost::container::container_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(ipcdetail::to_raw_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, ipcdetail::to_raw_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, size_type 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::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)); } + + //!Constructs an object + //!Throws if T's constructor throws + //!For backwards compatibility with libraries using C++03 allocators + template<class P> + void construct(const pointer &ptr, BOOST_FWD_REF(P) p) + { ::new((void*)ipcdetail::to_raw_pointer(ptr)) value_type(::boost::forward<P>(p)); } + + //!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::intrusive:: + pointer_traits<void_pointer>::template + rebind_pointer<const void>::type cvoid_pointer; + + public: + typedef typename boost::intrusive:: + pointer_traits<void_pointer>::template + rebind_pointer<T>::type pointer; + typedef typename boost::intrusive:: + pointer_traits<void_pointer>::template + rebind_pointer<const T>::type const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename SegmentManager::size_type size_type; + typedef typename SegmentManager::difference_type difference_type; + typedef boost::container::container_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(ipcdetail::to_raw_pointer(ptr)); + else + pool->get_segment_manager()->deallocate((void*)ipcdetail::to_raw_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(size_type 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(ipcdetail::to_raw_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::intrusive:: + pointer_traits<void_pointer>::template + rebind_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: + static const std::size_t DEFAULT_MAX_CACHED_NODES = 64; + + cached_allocator_impl(segment_manager *segment_mngr, size_type 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(size_type newmax) + { m_cache.set_max_cached_nodes(newmax); } + + //!Returns the max cached nodes parameter. + //!Never throws + size_type 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(ipcdetail::to_raw_pointer(ptr)); + } + else{ + this->get_segment_manager()->deallocate((void*)ipcdetail::to_raw_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(size_type 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(ipcdetail::to_raw_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::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) + { alloc1.m_cache.swap(alloc2.m_cache); } + + 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; + typedef typename private_node_allocator_t:: + size_type size_type; + + 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, size_type 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 size_type 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, size_type 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::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 + size_type 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 + size_type dec_ref_count() + { + //----------------------- + boost::interprocess::scoped_lock<mutex_type> guard(m_header); + //----------------------- + BOOST_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 + //!the mutex type to allow EBO when using null_mutex + struct header_t : mutex_type + { + size_type m_usecount; //Number of attached allocators + + header_t() + : m_usecount(0) {} + } m_header; +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP diff --git a/boost/interprocess/allocators/detail/node_pool.hpp b/boost/interprocess/allocators/detail/node_pool.hpp new file mode 100644 index 0000000000..7327ff92d5 --- /dev/null +++ b/boost/interprocess/allocators/detail/node_pool.hpp @@ -0,0 +1,109 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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/interprocess/detail/utilities.hpp> +#include <boost/interprocess/allocators/detail/allocator_common.hpp> +#include <boost/container/detail/node_pool_impl.hpp> +#include <cstddef> + + +//!\file +//!Describes the real adaptive pool shared by many Interprocess adaptive pool allocators + +namespace boost { +namespace interprocess { +namespace ipcdetail { + + + +//!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 boost::container::container_detail:: + private_node_pool_impl<typename SegmentManager::segment_manager_base_type> +{ + typedef boost::container::container_detail::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; + typedef typename base_t::size_type size_type; + + static const size_type nodes_per_block = NodesPerBlock; + //Deprecated, use nodes_per_block + static const size_type 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 ipcdetail::shared_pool_impl + < private_node_pool + <SegmentManager, NodeSize, NodesPerBlock> + > +{ + typedef ipcdetail::shared_pool_impl + < private_node_pool + <SegmentManager, NodeSize, NodesPerBlock> + > base_t; + public: + shared_node_pool(SegmentManager *segment_mgnr) + : base_t(segment_mgnr) + {} +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP diff --git a/boost/interprocess/allocators/detail/node_tools.hpp b/boost/interprocess/allocators/detail/node_tools.hpp new file mode 100644 index 0000000000..da7e4668e8 --- /dev/null +++ b/boost/interprocess/allocators/detail/node_tools.hpp @@ -0,0 +1,50 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2011. 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 ipcdetail { + + +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 ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_HPP diff --git a/boost/interprocess/allocators/node_allocator.hpp b/boost/interprocess/allocators/node_allocator.hpp new file mode 100644 index 0000000000..f1c3259d73 --- /dev/null +++ b/boost/interprocess/allocators/node_allocator.hpp @@ -0,0 +1,452 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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/intrusive/pointer_traits.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/container/detail/multiallocation_chain.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 ipcdetail{ + +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 ipcdetail::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::intrusive:: + pointer_traits<void_pointer>::template + rebind_pointer<T>::type pointer; + typedef typename boost::intrusive:: + pointer_traits<void_pointer>::template + rebind_pointer<const T>::type const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type difference_type; + + typedef boost::interprocess::version_type<node_allocator_base, Version> version; + typedef boost::container::container_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(ipcdetail::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(ipcdetail::to_raw_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(ipcdetail::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() + { ipcdetail::destroy_node_pool_if_last_link(node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))); } + + //!Returns a pointer to the node pool. + //!Never throws + void* get_node_pool() const + { return ipcdetail::to_raw_pointer(mp_node_pool); } + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const + { return node_pool<0>::get(ipcdetail::to_raw_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) + { ipcdetail::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 ipcdetail::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 ipcdetail{ + +/// @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 ipcdetail::node_allocator_base + < 2 + , T + , SegmentManager + , NodesPerBlock + > + /// @endcond +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + typedef ipcdetail::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 ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type 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, size_type 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(size_type 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 diff --git a/boost/interprocess/allocators/private_adaptive_pool.hpp b/boost/interprocess/allocators/private_adaptive_pool.hpp new file mode 100644 index 0000000000..301fb92daa --- /dev/null +++ b/boost/interprocess/allocators/private_adaptive_pool.hpp @@ -0,0 +1,468 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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/intrusive/pointer_traits.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/container/detail/multiallocation_chain.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 ipcdetail { + +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 ipcdetail::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::intrusive:: + pointer_traits<void_pointer>::template + rebind_pointer<T>::type pointer; + typedef typename boost::intrusive:: + pointer_traits<void_pointer>::template + rebind_pointer<const T>::type const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::size_type difference_type; + typedef boost::interprocess::version_type + <private_adaptive_pool_base, Version> version; + typedef boost::container::container_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 ipcdetail::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 ipcdetail::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 ipcdetail { + +/// @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 ipcdetail::private_adaptive_pool_base + < 2 + , T + , SegmentManager + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > + /// @endcond +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + typedef ipcdetail::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 ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type 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, size_type 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(size_type 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 + diff --git a/boost/interprocess/allocators/private_node_allocator.hpp b/boost/interprocess/allocators/private_node_allocator.hpp new file mode 100644 index 0000000000..f202e316fa --- /dev/null +++ b/boost/interprocess/allocators/private_node_allocator.hpp @@ -0,0 +1,445 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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/intrusive/pointer_traits.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/container/detail/multiallocation_chain.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 ipcdetail { + +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 ipcdetail::private_node_pool + <SegmentManager + , sizeof_value<T>::value + , NodesPerBlock + > node_pool_t; + + BOOST_STATIC_ASSERT((Version <=2)); + + /// @endcond + + public: + + typedef typename boost::intrusive:: + pointer_traits<void_pointer>::template + rebind_pointer<T>::type pointer; + typedef typename boost::intrusive:: + pointer_traits<void_pointer>::template + rebind_pointer<const T>::type const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type difference_type; + typedef boost::interprocess::version_type + <private_node_allocator_base, Version> version; + typedef boost::container::container_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 ipcdetail::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 ipcdetail::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 ipcdetail { + +/// @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 ipcdetail::private_node_allocator_base + < 2 + , T + , SegmentManager + , NodesPerBlock + > + /// @endcond +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + typedef ipcdetail::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 ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manage::difference_type 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, size_type 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(size_type 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 + |