diff --git a/include/boost/interprocess/allocators/adaptive_pool.hpp b/include/boost/interprocess/allocators/adaptive_pool.hpp index fab13ca..cf12947 100644 --- a/include/boost/interprocess/allocators/adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/adaptive_pool.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -80,9 +82,9 @@ class adaptive_pool_base public: //------- - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -92,13 +94,9 @@ class adaptive_pool_base typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type version; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef boost::interprocess::version_type version; + typedef detail::transform_multiallocation_chain + multiallocation_chain; //!Obtains adaptive_pool_base from //!adaptive_pool_base @@ -266,7 +264,7 @@ class adaptive_pool typedef detail::adaptive_pool_base < 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -388,7 +386,7 @@ class adaptive_pool size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -399,12 +397,12 @@ class adaptive_pool //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements); //!Allocates n_elements elements, each one of size elem_sizes[i]in a //!contiguous block //!of memory. The elements must be deallocated - multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + 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, @@ -412,7 +410,7 @@ class adaptive_pool //!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_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -425,7 +423,7 @@ class adaptive_pool //!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_iterator allocate_individual(std::size_t num_elements); + multiallocation_chain allocate_individual(std::size_t num_elements); //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated @@ -438,7 +436,7 @@ class adaptive_pool //!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_iterator it); + void deallocate_individual(multiallocation_chain it); #endif }; diff --git a/include/boost/interprocess/allocators/allocator.hpp b/include/boost/interprocess/allocators/allocator.hpp index 60c7fb6..2918689 100644 --- a/include/boost/interprocess/allocators/allocator.hpp +++ b/include/boost/interprocess/allocators/allocator.hpp @@ -18,15 +18,17 @@ #include #include +#include + #include -#include +#include +#include #include -#include +#include #include #include #include #include -#include #include #include @@ -64,11 +66,11 @@ class allocator //Typedef to const void pointer typedef typename - detail::pointer_to_other + boost::pointer_to_other ::type cvoid_ptr; //Pointer to the allocator - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type alloc_ptr_t; //Not assignable from related allocator @@ -84,9 +86,9 @@ class allocator public: typedef T value_type; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef typename detail::add_reference ::type reference; @@ -95,20 +97,13 @@ class allocator typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type version; + typedef boost::interprocess::version_type version; /// @cond //Experimental. Don't use. - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef detail::multiallocation_chain_adaptor - multiallocation_chain; - + typedef boost::interprocess::detail::transform_multiallocation_chain + multiallocation_chain; /// @endcond //!Obtains an allocator that allocates @@ -174,7 +169,7 @@ class allocator } std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0) @@ -189,19 +184,19 @@ class allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements) + multiallocation_chain allocate_many + (size_type elem_size, std::size_t num_elements) { - return multiallocation_iterator - (mp_mngr->allocate_many(sizeof(T)*elem_size, 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_iterator allocate_many(const size_type *elem_sizes, size_type n_elements) + multiallocation_chain allocate_many + (const size_type *elem_sizes, size_type n_elements) { - return multiallocation_iterator - (mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T))); + multiallocation_chain(mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T))); } //!Allocates many elements of size elem_size in a contiguous block @@ -210,8 +205,10 @@ class allocator //!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_iterator it) - { return mp_mngr->deallocate_many(it.base()); } + 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(). @@ -225,7 +222,8 @@ class allocator //!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_iterator allocate_individual(std::size_t num_elements) + multiallocation_chain allocate_individual + (std::size_t num_elements) { return this->allocate_many(1, num_elements); } //!Deallocates memory previously allocated with allocate_one(). @@ -240,8 +238,8 @@ class allocator //!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_iterator it) - { return this->deallocate_many(it); } + void deallocate_individual(multiallocation_chain chain) + { return this->deallocate_many(boost::interprocess::move(chain)); } //!Returns address of mutable object. //!Never throws diff --git a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp index fc94fb7..f2fa301 100644 --- a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -143,7 +143,7 @@ class cached_adaptive_pool , 2> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -267,7 +267,7 @@ class cached_adaptive_pool size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -278,12 +278,12 @@ class cached_adaptive_pool //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements); //!Allocates n_elements elements, each one of size elem_sizes[i]in a //!contiguous block //!of memory. The elements must be deallocated - multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + 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, @@ -291,7 +291,7 @@ class cached_adaptive_pool //!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_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -304,7 +304,7 @@ class cached_adaptive_pool //!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_iterator allocate_individual(std::size_t num_elements); + multiallocation_chain allocate_individual(std::size_t num_elements); //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated @@ -317,7 +317,7 @@ class cached_adaptive_pool //!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_iterator it); + void deallocate_individual(multiallocation_chain chain); //!Sets the new max cached nodes value. This can provoke deallocations //!if "newmax" is less than current cached nodes. Never throws void set_max_cached_nodes(std::size_t newmax); diff --git a/include/boost/interprocess/allocators/cached_node_allocator.hpp b/include/boost/interprocess/allocators/cached_node_allocator.hpp index 3801dc6..5799d6b 100644 --- a/include/boost/interprocess/allocators/cached_node_allocator.hpp +++ b/include/boost/interprocess/allocators/cached_node_allocator.hpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -115,7 +115,7 @@ class cached_node_allocator , 2> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -238,7 +238,7 @@ class cached_node_allocator size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -249,12 +249,12 @@ class cached_node_allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements); //!Allocates n_elements elements, each one of size elem_sizes[i]in a //!contiguous block //!of memory. The elements must be deallocated - multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + 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, @@ -262,7 +262,7 @@ class cached_node_allocator //!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_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -275,7 +275,7 @@ class cached_node_allocator //!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_iterator allocate_individual(std::size_t num_elements); + multiallocation_chain allocate_individual(std::size_t num_elements); //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated @@ -288,7 +288,7 @@ class cached_node_allocator //!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_iterator it); + void deallocate_individual(multiallocation_chain it); //!Sets the new max cached nodes value. This can provoke deallocations //!if "newmax" is less than current cached nodes. Never throws void set_max_cached_nodes(std::size_t newmax); diff --git a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp index 30a6c07..6a20fb8 100644 --- a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -53,7 +55,6 @@ class private_adaptive_node_pool_impl public: typedef typename node_slist::node_t node_t; typedef typename node_slist::node_slist_t free_nodes_t; - typedef typename SegmentManagerBase::multiallocation_iterator multiallocation_iterator; typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain; private: @@ -200,8 +201,9 @@ class private_adaptive_node_pool_impl //!Deallocates an array pointed by ptr. Never throws void deallocate_node(void *pElem) { - this->priv_reinsert_nodes_in_block - (multiallocation_iterator::create_simple_range(pElem)); + multiallocation_chain chain; + chain.push_front(void_pointer(pElem)); + this->priv_reinsert_nodes_in_block(chain, 1); //Update free block count if(m_totally_free_blocks > m_max_free_blocks){ this->priv_deallocate_free_blocks(m_max_free_blocks); @@ -209,13 +211,14 @@ class private_adaptive_node_pool_impl priv_invariants(); } - //!Allocates a singly linked list of n nodes ending in null pointer. - //!can throw boost::interprocess::bad_alloc - void allocate_nodes(multiallocation_chain &nodes, const std::size_t n) + //!Allocates n nodes. + //!Can throw boost::interprocess::bad_alloc + multiallocation_chain allocate_nodes(const std::size_t n) { + multiallocation_chain chain; + std::size_t i = 0; try{ priv_invariants(); - std::size_t i = 0; while(i != n){ //If there are no free nodes we allocate all needed blocks if (m_block_multiset.empty()){ @@ -230,9 +233,9 @@ class private_adaptive_node_pool_impl for(std::size_t j = 0; j != num_elems; ++j){ void *new_node = &free_nodes.front(); free_nodes.pop_front(); - nodes.push_back(new_node); + chain.push_back(new_node); } - + if(free_nodes.empty()){ m_block_multiset.erase(m_block_multiset.begin()); } @@ -240,41 +243,23 @@ class private_adaptive_node_pool_impl } } catch(...){ - this->deallocate_nodes(nodes, nodes.size()); + this->deallocate_nodes(chain, i); throw; } priv_invariants(); - } - - //!Allocates n nodes, pointed by the multiallocation_iterator. - //!Can throw boost::interprocess::bad_alloc - multiallocation_iterator allocate_nodes(const std::size_t n) - { - multiallocation_chain chain; - this->allocate_nodes(chain, n); - return chain.get_it(); + return boost::interprocess::move(chain); } //!Deallocates a linked list of nodes. Never throws - void deallocate_nodes(multiallocation_chain &nodes) + void deallocate_nodes(multiallocation_chain nodes) { - this->deallocate_nodes(nodes.get_it()); - nodes.reset(); + return deallocate_nodes(nodes, nodes.size()); } //!Deallocates the first n nodes of a linked list of nodes. Never throws void deallocate_nodes(multiallocation_chain &nodes, std::size_t n) { - assert(nodes.size() >= n); - for(std::size_t i = 0; i < n; ++i){ - this->deallocate_node(nodes.pop_front()); - } - } - - //!Deallocates the nodes pointed by the multiallocation iterator. Never throws - void deallocate_nodes(multiallocation_iterator it) - { - this->priv_reinsert_nodes_in_block(it); + this->priv_reinsert_nodes_in_block(nodes, n); if(m_totally_free_blocks > m_max_free_blocks){ this->priv_deallocate_free_blocks(m_max_free_blocks); } @@ -331,13 +316,12 @@ class private_adaptive_node_pool_impl } } - void priv_reinsert_nodes_in_block(multiallocation_iterator it) + void priv_reinsert_nodes_in_block(multiallocation_chain &chain, std::size_t n) { - multiallocation_iterator itend; block_iterator block_it(m_block_multiset.end()); - while(it != itend){ - void *pElem = &*it; - ++it; + while(n--){ + void *pElem = detail::get_pointer(chain.front()); + chain.pop_front(); priv_invariants(); block_info_t *block_info = this->priv_block_from_node(pElem); assert(block_info->free_nodes.size() < m_real_num_node); @@ -484,6 +468,7 @@ class private_adaptive_node_pool_impl std::size_t num_free_nodes = 0; for(; it != itend; ++it){ //Check for memory leak + std::size_t n = (std::size_t)it->free_nodes.size(); (void)n; assert(it->free_nodes.size() == m_real_num_node); ++num_free_nodes; } @@ -565,7 +550,7 @@ class private_adaptive_node_pool_impl } private: - typedef typename pointer_to_other + typedef typename boost::pointer_to_other ::type segment_mngr_base_ptr_t; const std::size_t m_max_free_blocks; diff --git a/include/boost/interprocess/allocators/detail/allocator_common.hpp b/include/boost/interprocess/allocators/detail/allocator_common.hpp index f5ccddd..998c415 100644 --- a/include/boost/interprocess/allocators/detail/allocator_common.hpp +++ b/include/boost/interprocess/allocators/detail/allocator_common.hpp @@ -8,25 +8,63 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_NODE_ALLOCATOR_COMMON_HPP -#define BOOST_INTERPROCESS_DETAIL_NODE_ALLOCATOR_COMMON_HPP +#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP +#define BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP #include #include -#include + +#include + #include -#include //pointer_to_other, get_pointer +#include //get_pointer #include //std::pair #include //boost::addressof #include //BOOST_ASSERT #include //bad_alloc #include //scoped_lock -#include //allocation_type +#include //boost::interprocess::allocation_type +#include +#include #include //std::swap +#include +#include +#include namespace boost { namespace interprocess { + +template +struct sizeof_value +{ + static const std::size_t value = sizeof(T); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + namespace detail { //!Object function that creates the node allocator if it is not created and @@ -41,7 +79,7 @@ struct get_or_create_node_pool_func { //Find or create the node_pool_t mp_node_pool = mp_segment_manager->template find_or_construct - (unique_instance)(mp_segment_manager); + (boost::interprocess::unique_instance)(mp_segment_manager); //If valid, increment link count if(mp_node_pool != 0) mp_node_pool->inc_ref_count(); @@ -78,7 +116,7 @@ struct destroy_if_last_link_func 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(unique_instance); + mp_node_pool->get_segment_manager()->template destroy(boost::interprocess::unique_instance); } //!Constructor. Initializes function @@ -106,16 +144,15 @@ template class cache_impl { typedef typename NodePool::segment_manager:: - void_pointer void_pointer; + void_pointer void_pointer; typedef typename pointer_to_other - ::type node_pool_ptr; - typedef typename NodePool::multiallocation_chain multiallocation_chain; - node_pool_ptr mp_node_pool; - multiallocation_chain m_cached_nodes; - std::size_t m_max_cached_nodes; + ::type node_pool_ptr; + typedef typename NodePool::multiallocation_chain multiallocation_chain; + node_pool_ptr mp_node_pool; + multiallocation_chain m_cached_nodes; + std::size_t m_max_cached_nodes; public: - typedef typename NodePool::multiallocation_iterator multiallocation_iterator; typedef typename NodePool::segment_manager segment_manager; cache_impl(segment_manager *segment_mngr, std::size_t max_cached_nodes) @@ -149,31 +186,34 @@ class cache_impl { //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()){ - mp_node_pool->allocate_nodes(m_cached_nodes, m_max_cached_nodes/2); + m_cached_nodes = mp_node_pool->allocate_nodes(m_max_cached_nodes/2); } - return m_cached_nodes.pop_front(); + void *ret = detail::get_pointer(m_cached_nodes.front()); + m_cached_nodes.pop_front(); + return ret; } - multiallocation_iterator cached_allocation(std::size_t n) + multiallocation_chain cached_allocation(std::size_t n) { multiallocation_chain chain; - std::size_t count = n; + std::size_t count = n, allocated(0); BOOST_TRY{ //If don't have any cached node, we have to get a new list of free nodes from the pool while(!m_cached_nodes.empty() && count--){ - void *ret = m_cached_nodes.pop_front(); + void *ret = detail::get_pointer(m_cached_nodes.front()); + m_cached_nodes.pop_front(); chain.push_back(ret); + ++allocated; } - if(chain.size() != n){ - mp_node_pool->allocate_nodes(chain, n - chain.size()); + 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); } - assert(chain.size() == n); - chain.splice_back(m_cached_nodes); - return multiallocation_iterator(chain.get_it()); + return boost::interprocess::move(chain); } BOOST_CATCH(...){ - this->cached_deallocation(multiallocation_iterator(chain.get_it())); + this->cached_deallocation(boost::interprocess::move(chain)); BOOST_RETHROW } BOOST_CATCH_END @@ -192,15 +232,9 @@ class cache_impl m_cached_nodes.push_front(ptr); } - void cached_deallocation(multiallocation_iterator it) + void cached_deallocation(multiallocation_chain chain) { - multiallocation_iterator itend; - - while(it != itend){ - void *addr = &*it; - ++it; - m_cached_nodes.push_front(addr); - } + 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){ @@ -225,7 +259,7 @@ class cache_impl void deallocate_all_cached_nodes() { if(m_cached_nodes.empty()) return; - mp_node_pool->deallocate_nodes(m_cached_nodes); + mp_node_pool->deallocate_nodes(boost::interprocess::move(m_cached_nodes)); } private: @@ -257,9 +291,9 @@ class array_allocation_impl typedef typename SegmentManager::void_pointer void_pointer; public: - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -268,12 +302,9 @@ class array_allocation_impl ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef detail::transform_multiallocation_chain + multiallocation_chain; + public: //!Returns maximum the number of objects the previously allocated memory @@ -285,7 +316,7 @@ class array_allocation_impl } std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0) @@ -300,19 +331,17 @@ class array_allocation_impl //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements) + multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements) { - return multiallocation_iterator - (this->derived()->get_segment_manager()->allocate_many(sizeof(T)*elem_size, 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_iterator allocate_many(const size_type *elem_sizes, size_type n_elements) + multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements) { - return multiallocation_iterator - (this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T))); + 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 @@ -321,8 +350,8 @@ class array_allocation_impl //!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_iterator it) - { return this->derived()->get_segment_manager()->deallocate_many(it.base()); } + void deallocate_many(multiallocation_chain chain) + { return this->derived()->get_segment_manager()->deallocate_many(boost::interprocess::move(chain)); } //!Returns the number of elements that could be //!allocated. Never throws @@ -369,13 +398,13 @@ class node_pool_allocation_impl { return static_cast(this); } typedef typename SegmentManager::void_pointer void_pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type cvoid_pointer; public: - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -384,12 +413,9 @@ class node_pool_allocation_impl ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef detail::transform_multiallocation_chain + multiallocation_chain; + template struct node_pool @@ -445,11 +471,11 @@ class node_pool_allocation_impl //!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_iterator allocate_individual(std::size_t num_elements) + multiallocation_chain allocate_individual(std::size_t num_elements) { typedef typename node_pool<0>::type node_pool_t; node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); - return multiallocation_iterator(pool->allocate_nodes(num_elements)); + return multiallocation_chain(pool->allocate_nodes(num_elements)); } //!Deallocates memory previously allocated with allocate_one(). @@ -468,8 +494,11 @@ class node_pool_allocation_impl //!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_iterator it) - { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes(it.base()); } + 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() @@ -497,11 +526,10 @@ class cached_allocator_impl typedef NodePool node_pool_t; typedef typename NodePool::segment_manager segment_manager; typedef typename segment_manager::void_pointer void_pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type cvoid_pointer; typedef typename base_t::pointer pointer; typedef typename base_t::size_type size_type; - typedef typename base_t::multiallocation_iterator multiallocation_iterator; typedef typename base_t::multiallocation_chain multiallocation_chain; typedef typename base_t::value_type value_type; @@ -587,8 +615,8 @@ class cached_allocator_impl //!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_iterator allocate_individual(std::size_t num_elements) - { return multiallocation_iterator(this->m_cache.cached_allocation(num_elements)); } + multiallocation_chain allocate_individual(std::size_t num_elements) + { return multiallocation_chain(this->m_cache.cached_allocation(num_elements)); } //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated @@ -602,8 +630,12 @@ class cached_allocator_impl //!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_iterator it) - { m_cache.cached_deallocation(it.base()); } + void deallocate_individual(multiallocation_chain chain) + { + typename node_pool_t::multiallocation_chain mem + (chain.extract_multiallocation_chain()); + m_cache.cached_deallocation(boost::interprocess::move(mem)); + } //!Deallocates all free blocks of the pool void deallocate_free_blocks() @@ -655,11 +687,10 @@ class shared_pool_impl { public: //!Segment manager typedef - typedef typename private_node_allocator_t::segment_manager segment_manager; typedef typename private_node_allocator_t:: - multiallocation_iterator multiallocation_iterator; + segment_manager segment_manager; typedef typename private_node_allocator_t:: - multiallocation_chain multiallocation_chain; + multiallocation_chain multiallocation_chain; private: typedef typename segment_manager::mutex_family::mutex_type mutex_type; @@ -691,7 +722,7 @@ class shared_pool_impl //----------------------- private_node_allocator_t::deallocate_node(ptr); } - +/* //!Allocates a singly linked list of n nodes ending in null pointer. //!can throw boost::interprocess::bad_alloc void allocate_nodes(multiallocation_chain &nodes, std::size_t n) @@ -701,10 +732,10 @@ class shared_pool_impl //----------------------- return private_node_allocator_t::allocate_nodes(nodes, n); } - - //!Allocates n nodes, pointed by the multiallocation_iterator. +*/ + //!Allocates n nodes. //!Can throw boost::interprocess::bad_alloc - multiallocation_iterator allocate_nodes(const std::size_t n) + multiallocation_chain allocate_nodes(const std::size_t n) { //----------------------- boost::interprocess::scoped_lock guard(m_header); @@ -721,22 +752,13 @@ class shared_pool_impl private_node_allocator_t::deallocate_nodes(nodes, num); } - //!Deallocates a linked list of nodes ending in null pointer. Never throws - void deallocate_nodes(multiallocation_chain &nodes) - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - private_node_allocator_t::deallocate_nodes(nodes); - } - //!Deallocates the nodes pointed by the multiallocation iterator. Never throws - void deallocate_nodes(multiallocation_iterator it) + void deallocate_nodes(multiallocation_chain chain) { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - private_node_allocator_t::deallocate_nodes(it); + private_node_allocator_t::deallocate_nodes(boost::interprocess::move(chain)); } //!Deallocates all the free blocks of memory. Never throws @@ -814,4 +836,4 @@ class shared_pool_impl #include -#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_ALLOCATOR_COMMON_HPP +#endif //#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP diff --git a/include/boost/interprocess/allocators/detail/node_pool.hpp b/include/boost/interprocess/allocators/detail/node_pool.hpp index bf6c758..7d7631b 100644 --- a/include/boost/interprocess/allocators/detail/node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/node_pool.hpp @@ -18,14 +18,17 @@ #include #include +#include +#include +#include + #include #include #include -#include -#include #include #include #include +#include #include #include #include @@ -53,7 +56,6 @@ class private_node_pool_impl typedef typename node_slist::slist_hook_t slist_hook_t; typedef typename node_slist::node_t node_t; typedef typename node_slist::node_slist_t free_nodes_t; - typedef typename SegmentManagerBase::multiallocation_iterator multiallocation_iterator; typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain; private: @@ -112,25 +114,9 @@ class private_node_pool_impl --m_allocated; } - //!Allocates a singly linked list of n nodes ending in null pointer and pushes them in the chain. - //!can throw boost::interprocess::bad_alloc - void allocate_nodes(multiallocation_chain &nodes, const std::size_t n) - { - std::size_t i = 0; - try{ - for(; i < n; ++i){ - nodes.push_front(this->allocate_node()); - } - } - catch(...){ - this->deallocate_nodes(nodes, i); - throw; - } - } - //!Allocates a singly linked list of n nodes ending in null pointer //!can throw boost::interprocess::bad_alloc - multiallocation_iterator allocate_nodes(const std::size_t n) + multiallocation_chain allocate_nodes(const std::size_t n) { multiallocation_chain nodes; std::size_t i = 0; @@ -143,32 +129,26 @@ class private_node_pool_impl this->deallocate_nodes(nodes, i); throw; } - return nodes.get_it(); - } - - //!Deallocates a linked list of nodes. Never throws - void deallocate_nodes(multiallocation_chain &nodes) - { - this->deallocate_nodes(nodes.get_it()); - nodes.reset(); + return boost::interprocess::move(nodes); } //!Deallocates the first n nodes of a linked list of nodes. Never throws - void deallocate_nodes(multiallocation_chain &nodes, std::size_t num) + void deallocate_nodes(multiallocation_chain &nodes, std::size_t n) { - assert(nodes.size() >= num); - for(std::size_t i = 0; i < num; ++i){ - deallocate_node(nodes.pop_front()); + for(std::size_t i = 0; i < n; ++i){ + void *p = detail::get_pointer(nodes.front()); + assert(p); + nodes.pop_front(); + this->deallocate_node(p); } } //!Deallocates the nodes pointed by the multiallocation iterator. Never throws - void deallocate_nodes(multiallocation_iterator it) + void deallocate_nodes(multiallocation_chain chain) { - multiallocation_iterator itend; - while(it != itend){ - void *addr = &*it; - ++it; + while(!chain.empty()){ + void *addr = detail::get_pointer(chain.front()); + chain.pop_front(); deallocate_node(addr); } } @@ -347,7 +327,7 @@ class private_node_pool_impl } private: - typedef typename pointer_to_other + typedef typename boost::pointer_to_other ::type segment_mngr_base_ptr_t; const std::size_t m_nodes_per_block; diff --git a/include/boost/interprocess/allocators/node_allocator.hpp b/include/boost/interprocess/allocators/node_allocator.hpp index 0ee43c3..49bb201 100644 --- a/include/boost/interprocess/allocators/node_allocator.hpp +++ b/include/boost/interprocess/allocators/node_allocator.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -77,9 +79,9 @@ class node_allocator_base public: //------- - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -89,13 +91,9 @@ class node_allocator_base typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type version; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef boost::interprocess::version_type version; + typedef detail::transform_multiallocation_chain + multiallocation_chain; //!Obtains node_allocator_base from //!node_allocator_base @@ -251,7 +249,7 @@ class node_allocator typedef detail::node_allocator_base < 2, T, SegmentManager, NodesPerBlock> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -373,7 +371,7 @@ class node_allocator size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -384,12 +382,12 @@ class node_allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements); //!Allocates n_elements elements, each one of size elem_sizes[i]in a //!contiguous block //!of memory. The elements must be deallocated - multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + 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, @@ -397,7 +395,7 @@ class node_allocator //!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_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -410,7 +408,7 @@ class node_allocator //!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_iterator allocate_individual(std::size_t num_elements); + multiallocation_chain allocate_individual(std::size_t num_elements); //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated @@ -423,7 +421,7 @@ class node_allocator //!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_iterator it); + void deallocate_individual(multiallocation_chain chain); #endif }; diff --git a/include/boost/interprocess/allocators/private_adaptive_pool.hpp b/include/boost/interprocess/allocators/private_adaptive_pool.hpp index c9b4e18..d958fdb 100644 --- a/include/boost/interprocess/allocators/private_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/private_adaptive_pool.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -78,9 +80,9 @@ class private_adaptive_pool_base /// @endcond public: - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -89,14 +91,10 @@ class private_adaptive_pool_base ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type + typedef boost::interprocess::version_type version; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef detail::transform_multiallocation_chain + multiallocation_chain; //!Obtains node_allocator from other node_allocator template @@ -264,7 +262,7 @@ class private_adaptive_pool typedef detail::private_adaptive_pool_base < 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -388,7 +386,7 @@ class private_adaptive_pool size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -399,12 +397,12 @@ class private_adaptive_pool //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements); //!Allocates n_elements elements, each one of size elem_sizes[i]in a //!contiguous block //!of memory. The elements must be deallocated - multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + 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, @@ -412,7 +410,7 @@ class private_adaptive_pool //!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_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -425,7 +423,7 @@ class private_adaptive_pool //!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_iterator allocate_individual(std::size_t num_elements); + multiallocation_chain allocate_individual(std::size_t num_elements); //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated @@ -438,7 +436,7 @@ class private_adaptive_pool //!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_iterator it); + void deallocate_individual(multiallocation_chain chain); #endif }; diff --git a/include/boost/interprocess/allocators/private_node_allocator.hpp b/include/boost/interprocess/allocators/private_node_allocator.hpp index a7320f1..e8c3c5e 100644 --- a/include/boost/interprocess/allocators/private_node_allocator.hpp +++ b/include/boost/interprocess/allocators/private_node_allocator.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -72,9 +74,9 @@ class private_node_allocator_base /// @endcond public: - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -83,14 +85,10 @@ class private_node_allocator_base ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type + typedef boost::interprocess::version_type version; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef detail::transform_multiallocation_chain + multiallocation_chain; //!Obtains node_allocator from other node_allocator template @@ -240,7 +238,7 @@ class private_node_allocator typedef detail::private_node_allocator_base < 2, T, SegmentManager, NodesPerBlock> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -364,7 +362,7 @@ class private_node_allocator size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -375,12 +373,12 @@ class private_node_allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements); //!Allocates n_elements elements, each one of size elem_sizes[i]in a //!contiguous block //!of memory. The elements must be deallocated - multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + 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, @@ -388,7 +386,7 @@ class private_node_allocator //!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_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -401,7 +399,7 @@ class private_node_allocator //!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_iterator allocate_individual(std::size_t num_elements); + multiallocation_chain allocate_individual(std::size_t num_elements); //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated @@ -414,7 +412,7 @@ class private_node_allocator //!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_iterator it); + void deallocate_individual(multiallocation_chain chain); #endif }; diff --git a/include/boost/interprocess/anonymous_shared_memory.hpp b/include/boost/interprocess/anonymous_shared_memory.hpp index e933e3c..0c19a35 100644 --- a/include/boost/interprocess/anonymous_shared_memory.hpp +++ b/include/boost/interprocess/anonymous_shared_memory.hpp @@ -19,7 +19,7 @@ #include #include -#if (!defined(BOOST_WINDOWS)) || defined(BOOST_DISABLE_WIN32) +#if (!defined(BOOST_INTERPROCESS_WINDOWS)) # include //open, O_CREAT, O_*... # include //mmap # include //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, @@ -42,12 +42,7 @@ namespace detail{ class raw_mapped_region_creator { public: - static - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - mapped_region - #else - move_return - #endif + static mapped_region create_posix_mapped_region(void *address, offset_t offset, std::size_t size) { mapped_region region; @@ -67,14 +62,10 @@ namespace detail{ //!Otherwise the operating system will choose the mapping address. //!The function returns a mapped_region holding that segment or throws //!interprocess_exception if the function fails. -static -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE -mapped_region -#else -detail::move_return -#endif +//static mapped_region +static mapped_region anonymous_shared_memory(std::size_t size, void *address = 0) -#if (!defined(BOOST_WINDOWS)) || defined(BOOST_DISABLE_WIN32) +#if (!defined(BOOST_INTERPROCESS_WINDOWS)) { int flags; int fd = -1; @@ -115,8 +106,7 @@ anonymous_shared_memory(std::size_t size, void *address = 0) #else { windows_shared_memory anonymous_mapping(create_only, 0, read_write, size); - mapped_region region(anonymous_mapping, read_write, 0, size, address); - return region; + return mapped_region(anonymous_mapping, read_write, 0, size, address); } #endif diff --git a/include/boost/interprocess/containers/allocation_type.hpp b/include/boost/interprocess/containers/allocation_type.hpp new file mode 100644 index 0000000..a22425f --- /dev/null +++ b/include/boost/interprocess/containers/allocation_type.hpp @@ -0,0 +1,40 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_ALLOCATION_TYPE_HPP +#define BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +/// @cond +typedef int allocation_type; +/// @endcond +static const allocation_type allocate_new = boost::interprocess_container::allocate_new; +static const allocation_type expand_fwd = boost::interprocess_container::expand_fwd; +static const allocation_type expand_bwd = boost::interprocess_container::expand_bwd; +static const allocation_type shrink_in_place = boost::interprocess_container::shrink_in_place; +static const allocation_type try_shrink_in_place= boost::interprocess_container::try_shrink_in_place; +static const allocation_type nothrow_allocation = boost::interprocess_container::nothrow_allocation; +static const allocation_type zero_memory = boost::interprocess_container::zero_memory; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP diff --git a/include/boost/interprocess/containers/container/containers_fwd.hpp b/include/boost/interprocess/containers/container/containers_fwd.hpp new file mode 100644 index 0000000..3e2eb21 --- /dev/null +++ b/include/boost/interprocess/containers/container/containers_fwd.hpp @@ -0,0 +1,153 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_CONTAINERS_FWD_HPP +#define BOOST_CONTAINERS_CONTAINERS_FWD_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +////////////////////////////////////////////////////////////////////////////// +// Standard predeclarations +////////////////////////////////////////////////////////////////////////////// + +/// @cond + +namespace boost{ +namespace intrusive{ + //Create namespace to avoid compilation errors +}} + +namespace boost{ namespace interprocess_container{ namespace containers_detail{ + +namespace bi = boost::intrusive; + +}}} + +namespace std { + +template +class allocator; + +template +struct less; + +template +struct pair; + +template +struct char_traits; + +} //namespace std { + +/// @endcond + +////////////////////////////////////////////////////////////////////////////// +// Containers +////////////////////////////////////////////////////////////////////////////// + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +//vector class +template > +class vector; + +//vector class +template > +class deque; + +//list class +template > +class list; + +//slist class +template > +class slist; + +//set class +template + ,class Alloc = std::allocator > +class set; + +//multiset class +template + ,class Alloc = std::allocator > +class multiset; + +//map class +template + ,class Alloc = std::allocator > > +class map; + +//multimap class +template + ,class Alloc = std::allocator > > +class multimap; + +//flat_set class +template + ,class Alloc = std::allocator > +class flat_set; + +//flat_multiset class +template + ,class Alloc = std::allocator > +class flat_multiset; + +//flat_map class +template + ,class Alloc = std::allocator > > +class flat_map; + +//flat_multimap class +template + ,class Alloc = std::allocator > > +class flat_multimap; + +//basic_string class +template + ,class Alloc = std::allocator > +class basic_string; + +//string class +typedef basic_string + + ,std::allocator > +string; + +}} //namespace boost { namespace interprocess_container { + +#endif //#ifndef BOOST_CONTAINERS_CONTAINERS_FWD_HPP + diff --git a/include/boost/interprocess/containers/container/deque.hpp b/include/boost/interprocess/containers/container/deque.hpp new file mode 100644 index 0000000..0963e18 --- /dev/null +++ b/include/boost/interprocess/containers/container/deque.hpp @@ -0,0 +1,1482 @@ +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2006. 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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's stl_deque.h and stl_uninitialized.h files. +// Modified by Ion Gaztanaga 2005. +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DEQUE_HPP +#define BOOST_CONTAINERS_DEQUE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +template +class deque; + +template +struct deque_value_traits +{ + typedef T value_type; + typedef A allocator_type; + static const bool trivial_dctr = boost::has_trivial_destructor::value; + static const bool trivial_dctr_after_move = + boost::interprocess::has_trivial_destructor_after_move::value || trivial_dctr; + static const bool trivial_copy = has_trivial_copy::value; + static const bool nothrow_copy = has_nothrow_copy::value; + static const bool trivial_assign = has_trivial_assign::value; + static const bool nothrow_assign = has_nothrow_assign::value; + +}; + +// Note: this function is simply a kludge to work around several compilers' +// bugs in handling constant expressions. +inline std::size_t deque_buf_size(std::size_t size) + { return size < 512 ? std::size_t(512 / size) : std::size_t(1); } + +// Deque base class. It has two purposes. First, its constructor +// and destructor allocate (but don't initialize) storage. This makes +// exception safety easier. +template +class deque_base +{ + public: + typedef typename Alloc::value_type val_alloc_val; + typedef typename Alloc::pointer val_alloc_ptr; + typedef typename Alloc::const_pointer val_alloc_cptr; + typedef typename Alloc::reference val_alloc_ref; + typedef typename Alloc::const_reference val_alloc_cref; + typedef typename Alloc::value_type val_alloc_diff; + typedef typename Alloc::template rebind + ::other ptr_alloc_t; + typedef typename ptr_alloc_t::value_type ptr_alloc_val; + typedef typename ptr_alloc_t::pointer ptr_alloc_ptr; + typedef typename ptr_alloc_t::const_pointer ptr_alloc_cptr; + typedef typename ptr_alloc_t::reference ptr_alloc_ref; + typedef typename ptr_alloc_t::const_reference ptr_alloc_cref; + typedef typename Alloc::template + rebind::other allocator_type; + typedef allocator_type stored_allocator_type; + + protected: + + typedef deque_value_traits traits_t; + typedef typename Alloc::template + rebind::other map_allocator_type; + + static std::size_t s_buffer_size() { return deque_buf_size(sizeof(T)); } + + val_alloc_ptr priv_allocate_node() + { return this->alloc().allocate(s_buffer_size()); } + + void priv_deallocate_node(val_alloc_ptr p) + { this->alloc().deallocate(p, s_buffer_size()); } + + ptr_alloc_ptr priv_allocate_map(std::size_t n) + { return this->ptr_alloc().allocate(n); } + + void priv_deallocate_map(ptr_alloc_ptr p, std::size_t n) + { this->ptr_alloc().deallocate(p, n); } + + public: + // Class invariants: + // For any nonsingular iterator i: + // i.node is the address of an element in the map array. The + // contents of i.node is a pointer to the beginning of a node. + // i.first == //(i.node) + // i.last == i.first + node_size + // i.cur is a pointer in the range [i.first, i.last). NOTE: + // the implication of this is that i.cur is always a dereferenceable + // pointer, even if i is a past-the-end iterator. + // Start and Finish are always nonsingular iterators. NOTE: this means + // that an empty deque must have one node, and that a deque + // with N elements, where N is the buffer size, must have two nodes. + // For every node other than start.node and finish.node, every element + // in the node is an initialized object. If start.node == finish.node, + // then [start.cur, finish.cur) are initialized objects, and + // the elements outside that range are uninitialized storage. Otherwise, + // [start.cur, start.last) and [finish.first, finish.cur) are initialized + // objects, and [start.first, start.cur) and [finish.cur, finish.last) + // are uninitialized storage. + // [map, map + map_size) is a valid, non-empty range. + // [start.node, finish.node] is a valid range contained within + // [map, map + map_size). + // A pointer in the range [map, map + map_size) points to an allocated node + // if and only if the pointer is in the range [start.node, finish.node]. + class const_iterator + : public std::iterator + { + public: + static std::size_t s_buffer_size() { return deque_base::s_buffer_size(); } + + typedef std::random_access_iterator_tag iterator_category; + typedef val_alloc_val value_type; + typedef val_alloc_cptr pointer; + typedef val_alloc_cref reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef ptr_alloc_ptr index_pointer; + typedef const_iterator self_t; + + friend class deque; + friend class deque_base; + + protected: + val_alloc_ptr m_cur; + val_alloc_ptr m_first; + val_alloc_ptr m_last; + index_pointer m_node; + + public: + const_iterator(val_alloc_ptr x, index_pointer y) + : m_cur(x), m_first(*y), + m_last(*y + s_buffer_size()), m_node(y) {} + + const_iterator() : m_cur(0), m_first(0), m_last(0), m_node(0) {} + + const_iterator(const const_iterator& x) + : m_cur(x.m_cur), m_first(x.m_first), + m_last(x.m_last), m_node(x.m_node) {} + + reference operator*() const + { return *this->m_cur; } + + pointer operator->() const + { return this->m_cur; } + + difference_type operator-(const self_t& x) const + { + if(!this->m_cur && !x.m_cur){ + return 0; + } + return difference_type(this->s_buffer_size()) * (this->m_node - x.m_node - 1) + + (this->m_cur - this->m_first) + (x.m_last - x.m_cur); + } + + self_t& operator++() + { + ++this->m_cur; + if (this->m_cur == this->m_last) { + this->priv_set_node(this->m_node + 1); + this->m_cur = this->m_first; + } + return *this; + } + + self_t operator++(int) + { + self_t tmp = *this; + ++*this; + return tmp; + } + + self_t& operator--() + { + if (this->m_cur == this->m_first) { + this->priv_set_node(this->m_node - 1); + this->m_cur = this->m_last; + } + --this->m_cur; + return *this; + } + + self_t operator--(int) + { + self_t tmp = *this; + --*this; + return tmp; + } + + self_t& operator+=(difference_type n) + { + difference_type offset = n + (this->m_cur - this->m_first); + if (offset >= 0 && offset < difference_type(this->s_buffer_size())) + this->m_cur += n; + else { + difference_type node_offset = + offset > 0 ? offset / difference_type(this->s_buffer_size()) + : -difference_type((-offset - 1) / this->s_buffer_size()) - 1; + this->priv_set_node(this->m_node + node_offset); + this->m_cur = this->m_first + + (offset - node_offset * difference_type(this->s_buffer_size())); + } + return *this; + } + + self_t operator+(difference_type n) const + { self_t tmp = *this; return tmp += n; } + + self_t& operator-=(difference_type n) + { return *this += -n; } + + self_t operator-(difference_type n) const + { self_t tmp = *this; return tmp -= n; } + + reference operator[](difference_type n) const + { return *(*this + n); } + + bool operator==(const self_t& x) const + { return this->m_cur == x.m_cur; } + + bool operator!=(const self_t& x) const + { return !(*this == x); } + + bool operator<(const self_t& x) const + { + return (this->m_node == x.m_node) ? + (this->m_cur < x.m_cur) : (this->m_node < x.m_node); + } + + bool operator>(const self_t& x) const + { return x < *this; } + + bool operator<=(const self_t& x) const + { return !(x < *this); } + + bool operator>=(const self_t& x) const + { return !(*this < x); } + + void priv_set_node(index_pointer new_node) + { + this->m_node = new_node; + this->m_first = *new_node; + this->m_last = this->m_first + difference_type(this->s_buffer_size()); + } + + friend const_iterator operator+(std::ptrdiff_t n, const const_iterator& x) + { return x + n; } + }; + + //Deque iterator + class iterator : public const_iterator + { + public: + typedef std::random_access_iterator_tag iterator_category; + typedef val_alloc_val value_type; + typedef val_alloc_ptr pointer; + typedef val_alloc_ref reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef ptr_alloc_ptr index_pointer; + typedef const_iterator self_t; + + friend class deque; + friend class deque_base; + + private: + explicit iterator(const const_iterator& x) : const_iterator(x){} + + public: + //Constructors + iterator(val_alloc_ptr x, index_pointer y) : const_iterator(x, y){} + iterator() : const_iterator(){} + //iterator(const const_iterator &cit) : const_iterator(cit){} + iterator(const iterator& x) : const_iterator(x){} + + //Pointer like operators + reference operator*() const { return *this->m_cur; } + pointer operator->() const { return this->m_cur; } + + reference operator[](difference_type n) const { return *(*this + n); } + + //Increment / Decrement + iterator& operator++() + { this->const_iterator::operator++(); return *this; } + + iterator operator++(int) + { iterator tmp = *this; ++*this; return tmp; } + + iterator& operator--() + { this->const_iterator::operator--(); return *this; } + + iterator operator--(int) + { iterator tmp = *this; --*this; return tmp; } + + // Arithmetic + iterator& operator+=(difference_type off) + { this->const_iterator::operator+=(off); return *this; } + + iterator operator+(difference_type off) const + { return iterator(this->const_iterator::operator+(off)); } + + friend iterator operator+(difference_type off, const iterator& right) + { return iterator(off+static_cast(right)); } + + iterator& operator-=(difference_type off) + { this->const_iterator::operator-=(off); return *this; } + + iterator operator-(difference_type off) const + { return iterator(this->const_iterator::operator-(off)); } + + difference_type operator-(const const_iterator& right) const + { return static_cast(*this) - right; } + }; + + deque_base(const allocator_type& a, std::size_t num_elements) + : members_(a) + { this->priv_initialize_map(num_elements); } + + deque_base(const allocator_type& a) + : members_(a) + {} + + ~deque_base() + { + if (this->members_.m_map) { + this->priv_destroy_nodes(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1); + this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); + } + } + + private: + deque_base(const deque_base&); + + protected: + + void priv_initialize_map(std::size_t num_elements) + { +// if(num_elements){ + std::size_t num_nodes = num_elements / s_buffer_size() + 1; + + this->members_.m_map_size = containers_detail::max_value((std::size_t) InitialMapSize, num_nodes + 2); + this->members_.m_map = this->priv_allocate_map(this->members_.m_map_size); + + ptr_alloc_ptr nstart = this->members_.m_map + (this->members_.m_map_size - num_nodes) / 2; + ptr_alloc_ptr nfinish = nstart + num_nodes; + + BOOST_TRY { + this->priv_create_nodes(nstart, nfinish); + } + BOOST_CATCH(...){ + this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); + this->members_.m_map = 0; + this->members_.m_map_size = 0; + BOOST_RETHROW + } + BOOST_CATCH_END + + this->members_.m_start.priv_set_node(nstart); + this->members_.m_finish.priv_set_node(nfinish - 1); + this->members_.m_start.m_cur = this->members_.m_start.m_first; + this->members_.m_finish.m_cur = this->members_.m_finish.m_first + + num_elements % s_buffer_size(); +// } + } + + void priv_create_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) + { + ptr_alloc_ptr cur; + BOOST_TRY { + for (cur = nstart; cur < nfinish; ++cur) + *cur = this->priv_allocate_node(); + } + BOOST_CATCH(...){ + this->priv_destroy_nodes(nstart, cur); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + void priv_destroy_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) + { + for (ptr_alloc_ptr n = nstart; n < nfinish; ++n) + this->priv_deallocate_node(*n); + } + + enum { InitialMapSize = 8 }; + + protected: + struct members_holder + : public ptr_alloc_t + , public allocator_type + { + members_holder(const allocator_type &a) + : map_allocator_type(a), allocator_type(a) + , m_map(0), m_map_size(0) + , m_start(), m_finish(m_start) + {} + + ptr_alloc_ptr m_map; + std::size_t m_map_size; + iterator m_start; + iterator m_finish; + } members_; + + ptr_alloc_t &ptr_alloc() + { return members_; } + + const ptr_alloc_t &ptr_alloc() const + { return members_; } + + allocator_type &alloc() + { return members_; } + + const allocator_type &alloc() const + { return members_; } +}; +/// @endcond + +//! Deque class +//! +template +class deque : protected deque_base +{ + /// @cond + typedef deque_base Base; + + public: // Basic types + typedef typename Alloc::value_type val_alloc_val; + typedef typename Alloc::pointer val_alloc_ptr; + typedef typename Alloc::const_pointer val_alloc_cptr; + typedef typename Alloc::reference val_alloc_ref; + typedef typename Alloc::const_reference val_alloc_cref; + typedef typename Alloc::template + rebind::other ptr_alloc_t; + typedef typename ptr_alloc_t::value_type ptr_alloc_val; + typedef typename ptr_alloc_t::pointer ptr_alloc_ptr; + typedef typename ptr_alloc_t::const_pointer ptr_alloc_cptr; + typedef typename ptr_alloc_t::reference ptr_alloc_ref; + typedef typename ptr_alloc_t::const_reference ptr_alloc_cref; + /// @endcond + + typedef T value_type; + typedef val_alloc_ptr pointer; + typedef val_alloc_cptr const_pointer; + typedef val_alloc_ref reference; + typedef val_alloc_cref const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef typename Base::allocator_type allocator_type; + + public: // Iterators + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + typedef std::reverse_iterator const_reverse_iterator; + typedef std::reverse_iterator reverse_iterator; + + /// @cond + private: // Internal typedefs + typedef ptr_alloc_ptr index_pointer; + static std::size_t s_buffer_size() + { return Base::s_buffer_size(); } + typedef containers_detail::advanced_insert_aux_int advanced_insert_aux_int_t; + typedef repeat_iterator r_iterator; + typedef boost::interprocess::move_iterator move_it; + + /// @endcond + + allocator_type get_allocator() const { return Base::alloc(); } + + public: // Basic accessors + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(deque) + + iterator begin() + { return this->members_.m_start; } + + iterator end() + { return this->members_.m_finish; } + + const_iterator begin() const + { return this->members_.m_start; } + + const_iterator end() const + { return this->members_.m_finish; } + + reverse_iterator rbegin() + { return reverse_iterator(this->members_.m_finish); } + + reverse_iterator rend() + { return reverse_iterator(this->members_.m_start); } + + const_reverse_iterator rbegin() const + { return const_reverse_iterator(this->members_.m_finish); } + + const_reverse_iterator rend() const + { return const_reverse_iterator(this->members_.m_start); } + + const_iterator cbegin() const + { return this->members_.m_start; } + + const_iterator cend() const + { return this->members_.m_finish; } + + const_reverse_iterator crbegin() const + { return const_reverse_iterator(this->members_.m_finish); } + + const_reverse_iterator crend() const + { return const_reverse_iterator(this->members_.m_start); } + + reference operator[](size_type n) + { return this->members_.m_start[difference_type(n)]; } + + const_reference operator[](size_type n) const + { return this->members_.m_start[difference_type(n)]; } + + void priv_range_check(size_type n) const + { if (n >= this->size()) BOOST_RETHROW std::out_of_range("deque"); } + + reference at(size_type n) + { this->priv_range_check(n); return (*this)[n]; } + + const_reference at(size_type n) const + { this->priv_range_check(n); return (*this)[n]; } + + reference front() { return *this->members_.m_start; } + + reference back() { return *(end()-1); } + + const_reference front() const + { return *this->members_.m_start; } + + const_reference back() const { return *(cend()-1); } + + size_type size() const + { return this->members_.m_finish - this->members_.m_start; } + + size_type max_size() const + { return this->alloc().max_size(); } + + bool empty() const + { return this->members_.m_finish == this->members_.m_start; } + + explicit deque(const allocator_type& a = allocator_type()) + : Base(a) + {} + + deque(const deque& x) + : Base(x.alloc()) + { + if(x.size()){ + this->priv_initialize_map(x.size()); + std::uninitialized_copy(x.begin(), x.end(), this->members_.m_start); + } + } + + deque(BOOST_INTERPROCESS_RV_REF(deque) mx) + : Base(mx.alloc()) + { this->swap(mx); } + + deque(size_type n, const value_type& value, + const allocator_type& a = allocator_type()) : Base(a, n) + { this->priv_fill_initialize(value); } + + explicit deque(size_type n) : Base(allocator_type(), n) + { this->resize(n); } + + // Check whether it's an integral type. If so, it's not an iterator. + template + deque(InpIt first, InpIt last, const allocator_type& a = allocator_type()) + : Base(a) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_initialize_dispatch(first, last, Result()); + } + + ~deque() + { + priv_destroy_range(this->members_.m_start, this->members_.m_finish); + } + + deque& operator= (const deque& x) + { + const size_type len = size(); + if (&x != this) { + if (len >= x.size()) + this->erase(std::copy(x.begin(), x.end(), this->members_.m_start), this->members_.m_finish); + else { + const_iterator mid = x.begin() + difference_type(len); + std::copy(x.begin(), mid, this->members_.m_start); + this->insert(this->members_.m_finish, mid, x.end()); + } + } + return *this; + } + + deque& operator= (BOOST_INTERPROCESS_RV_REF(deque) x) + { + this->clear(); + this->swap(x); + return *this; + } + + void swap(deque &x) + { + std::swap(this->members_.m_start, x.members_.m_start); + std::swap(this->members_.m_finish, x.members_.m_finish); + std::swap(this->members_.m_map, x.members_.m_map); + std::swap(this->members_.m_map_size, x.members_.m_map_size); + } + + void assign(size_type n, const T& val) + { this->priv_fill_assign(n, val); } + + template + void assign(InpIt first, InpIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_assign_dispatch(first, last, Result()); + } + + void push_back(const value_type& t) + { + if(this->priv_push_back_simple_available()){ + new(this->priv_push_back_simple_pos())value_type(t); + this->priv_push_back_simple_commit(); + } + else{ + this->priv_insert_aux(cend(), size_type(1), t); + } + } + + void push_back(BOOST_INTERPROCESS_RV_REF(value_type) t) + { + if(this->priv_push_back_simple_available()){ + new(this->priv_push_back_simple_pos())value_type(boost::interprocess::move(t)); + this->priv_push_back_simple_commit(); + } + else{ + this->priv_insert_aux(cend(), move_it(r_iterator(t, 1)), move_it(r_iterator())); + } + } + + void push_front(const value_type& t) + { + if(this->priv_push_front_simple_available()){ + new(this->priv_push_front_simple_pos())value_type(t); + this->priv_push_front_simple_commit(); + } + else{ + this->priv_insert_aux(cbegin(), size_type(1), t); + } + } + + void push_front(BOOST_INTERPROCESS_RV_REF(value_type) t) + { + if(this->priv_push_front_simple_available()){ + new(this->priv_push_front_simple_pos())value_type(boost::interprocess::move(t)); + this->priv_push_front_simple_commit(); + } + else{ + this->priv_insert_aux(cbegin(), move_it(r_iterator(t, 1)), move_it(r_iterator())); + } + } + + void pop_back() + { + if (this->members_.m_finish.m_cur != this->members_.m_finish.m_first) { + --this->members_.m_finish.m_cur; + containers_detail::get_pointer(this->members_.m_finish.m_cur)->~value_type(); + } + else + this->priv_pop_back_aux(); + } + + void pop_front() + { + if (this->members_.m_start.m_cur != this->members_.m_start.m_last - 1) { + containers_detail::get_pointer(this->members_.m_start.m_cur)->~value_type(); + ++this->members_.m_start.m_cur; + } + else + this->priv_pop_front_aux(); + } + + iterator insert(const_iterator position, const value_type& x) + { + if (position == cbegin()){ + this->push_front(x); + return begin(); + } + else if (position == cend()){ + this->push_back(x); + return (end()-1); + } + else { + size_type n = position - cbegin(); + this->priv_insert_aux(position, size_type(1), x); + return iterator(this->begin() + n); + } + } + + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) mx) + { + if (position == cbegin()) { + this->push_front(boost::interprocess::move(mx)); + return begin(); + } + else if (position == cend()) { + this->push_back(boost::interprocess::move(mx)); + return(end()-1); + } + else { + //Just call more general insert(pos, size, value) and return iterator + size_type n = position - begin(); + this->priv_insert_aux(position, move_it(r_iterator(mx, 1)), move_it(r_iterator())); + return iterator(this->begin() + n); + } + } + + void insert(const_iterator pos, size_type n, const value_type& x) + { this->priv_fill_insert(pos, n, x); } + + // Check whether it's an integral type. If so, it's not an iterator. + template + void insert(const_iterator pos, InpIt first, InpIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_dispatch(pos, first, last, Result()); + } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + template + void emplace_back(Args&&... args) + { + if(this->priv_push_back_simple_available()){ + new(this->priv_push_back_simple_pos())value_type(boost::interprocess::forward(args)...); + this->priv_push_back_simple_commit(); + } + else{ + containers_detail::advanced_insert_aux_emplace proxy(boost::interprocess::forward(args)...); + this->priv_insert_aux_impl(this->cend(), 1, proxy); + } + } + + template + void emplace_front(Args&&... args) + { + if(this->priv_push_front_simple_available()){ + new(this->priv_push_front_simple_pos())value_type(boost::interprocess::forward(args)...); + this->priv_push_front_simple_commit(); + } + else{ + containers_detail::advanced_insert_aux_emplace proxy(boost::interprocess::forward(args)...); + this->priv_insert_aux_impl(this->cbegin(), 1, proxy); + } + } + + template + iterator emplace(const_iterator p, Args&&... args) + { + if(p == this->cbegin()){ + this->emplace_front(boost::interprocess::forward(args)...); + return this->begin(); + } + else if(p == this->cend()){ + this->emplace_back(boost::interprocess::forward(args)...); + return (this->end()-1); + } + else{ + size_type n = p - this->cbegin(); + containers_detail::advanced_insert_aux_emplace proxy(boost::interprocess::forward(args)...); + this->priv_insert_aux_impl(p, 1, proxy); + return iterator(this->begin() + n); + } + } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //0 args + void emplace_back() + { + if(priv_push_front_simple_available()){ + new(priv_push_front_simple_pos())value_type(); + priv_push_front_simple_commit(); + } + else{ + containers_detail::advanced_insert_aux_emplace proxy; + priv_insert_aux_impl(cend(), 1, proxy); + } + } + + void emplace_front() + { + if(priv_push_front_simple_available()){ + new(priv_push_front_simple_pos())value_type(); + priv_push_front_simple_commit(); + } + else{ + containers_detail::advanced_insert_aux_emplace proxy; + priv_insert_aux_impl(cbegin(), 1, proxy); + } + } + + iterator emplace(const_iterator p) + { + if(p == cbegin()){ + emplace_front(); + return begin(); + } + else if(p == cend()){ + emplace_back(); + return (end()-1); + } + else{ + size_type n = p - cbegin(); + containers_detail::advanced_insert_aux_emplace proxy; + priv_insert_aux_impl(p, 1, proxy); + return iterator(this->begin() + n); + } + } + + //advanced_insert_int.hpp includes all necessary preprocessor machinery... + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + if(priv_push_back_simple_available()){ \ + new(priv_push_back_simple_pos())value_type \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_push_back_simple_commit(); \ + } \ + else{ \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_insert_aux_impl(cend(), 1, proxy); \ + } \ + } \ + \ + template \ + void emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + if(priv_push_front_simple_available()){ \ + new(priv_push_front_simple_pos())value_type \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_push_front_simple_commit(); \ + } \ + else{ \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_insert_aux_impl(cbegin(), 1, proxy); \ + } \ + } \ + \ + template \ + iterator emplace(const_iterator p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + if(p == this->cbegin()){ \ + this->emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + return this->begin(); \ + } \ + else if(p == cend()){ \ + this->emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + return (this->end()-1); \ + } \ + else{ \ + size_type pos_num = p - this->cbegin(); \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + this->priv_insert_aux_impl(p, 1, proxy); \ + return iterator(this->begin() + pos_num); \ + } \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + void resize(size_type new_size, const value_type& x) + { + const size_type len = size(); + if (new_size < len) + this->erase(this->members_.m_start + new_size, this->members_.m_finish); + else + this->insert(this->members_.m_finish, new_size - len, x); + } + + void resize(size_type new_size) + { + const size_type len = size(); + if (new_size < len) + this->erase(this->members_.m_start + new_size, this->members_.m_finish); + else{ + size_type n = new_size - this->size(); + containers_detail::default_construct_aux_proxy proxy(n); + priv_insert_aux_impl(this->cend(), n, proxy); + } + } + + iterator erase(const_iterator pos) + { + const_iterator next = pos; + ++next; + difference_type index = pos - this->members_.m_start; + if (size_type(index) < (this->size() >> 1)) { + boost::interprocess::move_backward(begin(), iterator(pos), iterator(next)); + pop_front(); + } + else { + boost::interprocess::move(iterator(next), end(), iterator(pos)); + pop_back(); + } + return this->members_.m_start + index; + } + + iterator erase(const_iterator first, const_iterator last) + { + if (first == this->members_.m_start && last == this->members_.m_finish) { + this->clear(); + return this->members_.m_finish; + } + else { + difference_type n = last - first; + difference_type elems_before = first - this->members_.m_start; + if (elems_before < static_cast(this->size() - n) - elems_before) { + boost::interprocess::move_backward(begin(), iterator(first), iterator(last)); + iterator new_start = this->members_.m_start + n; + if(!Base::traits_t::trivial_dctr_after_move) + this->priv_destroy_range(this->members_.m_start, new_start); + this->priv_destroy_nodes(new_start.m_node, this->members_.m_start.m_node); + this->members_.m_start = new_start; + } + else { + boost::interprocess::move(iterator(last), end(), iterator(first)); + iterator new_finish = this->members_.m_finish - n; + if(!Base::traits_t::trivial_dctr_after_move) + this->priv_destroy_range(new_finish, this->members_.m_finish); + this->priv_destroy_nodes(new_finish.m_node + 1, this->members_.m_finish.m_node + 1); + this->members_.m_finish = new_finish; + } + return this->members_.m_start + elems_before; + } + } + + void clear() + { + for (index_pointer node = this->members_.m_start.m_node + 1; + node < this->members_.m_finish.m_node; + ++node) { + this->priv_destroy_range(*node, *node + this->s_buffer_size()); + this->priv_deallocate_node(*node); + } + + if (this->members_.m_start.m_node != this->members_.m_finish.m_node) { + this->priv_destroy_range(this->members_.m_start.m_cur, this->members_.m_start.m_last); + this->priv_destroy_range(this->members_.m_finish.m_first, this->members_.m_finish.m_cur); + this->priv_deallocate_node(this->members_.m_finish.m_first); + } + else + this->priv_destroy_range(this->members_.m_start.m_cur, this->members_.m_finish.m_cur); + + this->members_.m_finish = this->members_.m_start; + } + + /// @cond + private: + + bool priv_push_back_simple_available() const + { + return this->members_.m_map && + (this->members_.m_finish.m_cur != (this->members_.m_finish.m_last - 1)); + } + + void *priv_push_back_simple_pos() const + { + return static_cast(containers_detail::get_pointer(this->members_.m_finish.m_cur)); + } + + void priv_push_back_simple_commit() + { + ++this->members_.m_finish.m_cur; + } + + bool priv_push_front_simple_available() const + { + return this->members_.m_map && + (this->members_.m_start.m_cur != this->members_.m_start.m_first); + } + + void *priv_push_front_simple_pos() const + { return static_cast(containers_detail::get_pointer(this->members_.m_start.m_cur) - 1); } + + void priv_push_front_simple_commit() + { --this->members_.m_start.m_cur; } + + template + void priv_insert_aux(const_iterator pos, InpIt first, InpIt last, std::input_iterator_tag) + { + for(;first != last; ++first){ + this->insert(pos, boost::interprocess::move(value_type(*first))); + } + } + + template + void priv_insert_aux(const_iterator pos, FwdIt first, FwdIt last, std::forward_iterator_tag) + { this->priv_insert_aux(pos, first, last); } + + // assign(), a generalized assignment member function. Two + // versions: one that takes a count, and one that takes a range. + // The range version is a member template, so we dispatch on whether + // or not the type is an integer. + void priv_fill_assign(size_type n, const T& val) + { + if (n > size()) { + std::fill(begin(), end(), val); + this->insert(cend(), n - size(), val); + } + else { + this->erase(cbegin() + n, cend()); + std::fill(begin(), end(), val); + } + } + + template + void priv_initialize_dispatch(Integer n, Integer x, containers_detail::true_) + { + this->priv_initialize_map(n); + this->priv_fill_initialize(x); + } + + template + void priv_initialize_dispatch(InpIt first, InpIt last, containers_detail::false_) + { + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_range_initialize(first, last, ItCat()); + } + + void priv_destroy_range(iterator p, iterator p2) + { + for(;p != p2; ++p) + containers_detail::get_pointer(&*p)->~value_type(); + } + + void priv_destroy_range(pointer p, pointer p2) + { + for(;p != p2; ++p) + containers_detail::get_pointer(&*p)->~value_type(); + } + + template + void priv_assign_dispatch(Integer n, Integer val, containers_detail::true_) + { this->priv_fill_assign((size_type) n, (T) val); } + + template + void priv_assign_dispatch(InpIt first, InpIt last, containers_detail::false_) + { + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_assign_aux(first, last, ItCat()); + } + + template + void priv_assign_aux(InpIt first, InpIt last, std::input_iterator_tag) + { + iterator cur = begin(); + for ( ; first != last && cur != end(); ++cur, ++first) + *cur = *first; + if (first == last) + this->erase(cur, cend()); + else + this->insert(cend(), first, last); + } + + template + void priv_assign_aux(FwdIt first, FwdIt last, std::forward_iterator_tag) + { + size_type len = std::distance(first, last); + if (len > size()) { + FwdIt mid = first; + std::advance(mid, size()); + std::copy(first, mid, begin()); + this->insert(cend(), mid, last); + } + else + this->erase(std::copy(first, last, begin()), cend()); + } + + template + void priv_insert_dispatch(const_iterator pos, Integer n, Integer x, containers_detail::true_) + { this->priv_fill_insert(pos, (size_type) n, (value_type) x); } + + template + void priv_insert_dispatch(const_iterator pos,InpIt first, InpIt last, containers_detail::false_) + { + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_insert_aux(pos, first, last, ItCat()); + } + + void priv_insert_aux(const_iterator pos, size_type n, const value_type& x) + { + typedef constant_iterator c_it; + this->priv_insert_aux(pos, c_it(x, n), c_it()); + } + + //Just forward all operations to priv_insert_aux_impl + template + void priv_insert_aux(const_iterator p, FwdIt first, FwdIt last) + { + containers_detail::advanced_insert_aux_proxy proxy(first, last); + priv_insert_aux_impl(p, (size_type)std::distance(first, last), proxy); + } + + void priv_insert_aux_impl(const_iterator p, size_type n, advanced_insert_aux_int_t &interf) + { + iterator pos(p); + if(!this->members_.m_map){ + this->priv_initialize_map(0); + pos = this->begin(); + } + + const difference_type elemsbefore = pos - this->members_.m_start; + size_type length = this->size(); + if (elemsbefore < static_cast(length / 2)) { + iterator new_start = this->priv_reserve_elements_at_front(n); + iterator old_start = this->members_.m_start; + pos = this->members_.m_start + elemsbefore; + if (elemsbefore >= difference_type(n)) { + iterator start_n = this->members_.m_start + difference_type(n); + boost::interprocess::uninitialized_move(this->members_.m_start, start_n, new_start); + this->members_.m_start = new_start; + boost::interprocess::move(start_n, pos, old_start); + interf.copy_all_to(pos - difference_type(n)); + } + else { + difference_type mid_count = (difference_type(n) - elemsbefore); + iterator mid_start = old_start - mid_count; + interf.uninitialized_copy_some_and_update(mid_start, mid_count, true); + this->members_.m_start = mid_start; + boost::interprocess::uninitialized_move(old_start, pos, new_start); + this->members_.m_start = new_start; + interf.copy_all_to(old_start); + } + } + else { + iterator new_finish = this->priv_reserve_elements_at_back(n); + iterator old_finish = this->members_.m_finish; + const difference_type elemsafter = + difference_type(length) - elemsbefore; + pos = this->members_.m_finish - elemsafter; + if (elemsafter >= difference_type(n)) { + iterator finish_n = this->members_.m_finish - difference_type(n); + boost::interprocess::uninitialized_move(finish_n, this->members_.m_finish, this->members_.m_finish); + this->members_.m_finish = new_finish; + boost::interprocess::move_backward(pos, finish_n, old_finish); + interf.copy_all_to(pos); + } + else { + interf.uninitialized_copy_some_and_update(old_finish, elemsafter, false); + this->members_.m_finish += n-elemsafter; + boost::interprocess::uninitialized_move(pos, old_finish, this->members_.m_finish); + this->members_.m_finish = new_finish; + interf.copy_all_to(pos); + } + } + } + + void priv_fill_insert(const_iterator pos, size_type n, const value_type& x) + { + typedef constant_iterator c_it; + this->insert(pos, c_it(x, n), c_it()); + } + + // Precondition: this->members_.m_start and this->members_.m_finish have already been initialized, + // but none of the deque's elements have yet been constructed. + void priv_fill_initialize(const value_type& value) + { + index_pointer cur; + BOOST_TRY { + for (cur = this->members_.m_start.m_node; cur < this->members_.m_finish.m_node; ++cur){ + std::uninitialized_fill(*cur, *cur + this->s_buffer_size(), value); + } + std::uninitialized_fill(this->members_.m_finish.m_first, this->members_.m_finish.m_cur, value); + } + BOOST_CATCH(...){ + this->priv_destroy_range(this->members_.m_start, iterator(*cur, cur)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + void priv_range_initialize(InpIt first, InpIt last, std::input_iterator_tag) + { + this->priv_initialize_map(0); + BOOST_TRY { + for ( ; first != last; ++first) + this->push_back(*first); + } + BOOST_CATCH(...){ + this->clear(); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + void priv_range_initialize(FwdIt first, FwdIt last, std::forward_iterator_tag) + { + size_type n = 0; + n = std::distance(first, last); + this->priv_initialize_map(n); + + index_pointer cur_node; + BOOST_TRY { + for (cur_node = this->members_.m_start.m_node; + cur_node < this->members_.m_finish.m_node; + ++cur_node) { + FwdIt mid = first; + std::advance(mid, this->s_buffer_size()); + boost::interprocess::uninitialized_copy_or_move(first, mid, *cur_node); + first = mid; + } + boost::interprocess::uninitialized_copy_or_move(first, last, this->members_.m_finish.m_first); + } + BOOST_CATCH(...){ + this->priv_destroy_range(this->members_.m_start, iterator(*cur_node, cur_node)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + // Called only if this->members_.m_finish.m_cur == this->members_.m_finish.m_first. + void priv_pop_back_aux() + { + this->priv_deallocate_node(this->members_.m_finish.m_first); + this->members_.m_finish.priv_set_node(this->members_.m_finish.m_node - 1); + this->members_.m_finish.m_cur = this->members_.m_finish.m_last - 1; + containers_detail::get_pointer(this->members_.m_finish.m_cur)->~value_type(); + } + + // Called only if this->members_.m_start.m_cur == this->members_.m_start.m_last - 1. Note that + // if the deque has at least one element (a precondition for this member + // function), and if this->members_.m_start.m_cur == this->members_.m_start.m_last, then the deque + // must have at least two nodes. + void priv_pop_front_aux() + { + containers_detail::get_pointer(this->members_.m_start.m_cur)->~value_type(); + this->priv_deallocate_node(this->members_.m_start.m_first); + this->members_.m_start.priv_set_node(this->members_.m_start.m_node + 1); + this->members_.m_start.m_cur = this->members_.m_start.m_first; + } + + iterator priv_reserve_elements_at_front(size_type n) + { + size_type vacancies = this->members_.m_start.m_cur - this->members_.m_start.m_first; + if (n > vacancies){ + size_type new_elems = n-vacancies; + size_type new_nodes = (new_elems + this->s_buffer_size() - 1) / + this->s_buffer_size(); + size_type s = (size_type)(this->members_.m_start.m_node - this->members_.m_map); + if (new_nodes > s){ + this->priv_reallocate_map(new_nodes, true); + } + size_type i = 1; + BOOST_TRY { + for (; i <= new_nodes; ++i) + *(this->members_.m_start.m_node - i) = this->priv_allocate_node(); + } + BOOST_CATCH(...) { + for (size_type j = 1; j < i; ++j) + this->priv_deallocate_node(*(this->members_.m_start.m_node - j)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + return this->members_.m_start - difference_type(n); + } + + iterator priv_reserve_elements_at_back(size_type n) + { + size_type vacancies = (this->members_.m_finish.m_last - this->members_.m_finish.m_cur) - 1; + if (n > vacancies){ + size_type new_elems = n - vacancies; + size_type new_nodes = (new_elems + this->s_buffer_size() - 1)/s_buffer_size(); + size_type s = (size_type)(this->members_.m_map_size - (this->members_.m_finish.m_node - this->members_.m_map)); + if (new_nodes + 1 > s){ + this->priv_reallocate_map(new_nodes, false); + } + size_type i; + BOOST_TRY { + for (i = 1; i <= new_nodes; ++i) + *(this->members_.m_finish.m_node + i) = this->priv_allocate_node(); + } + BOOST_CATCH(...) { + for (size_type j = 1; j < i; ++j) + this->priv_deallocate_node(*(this->members_.m_finish.m_node + j)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + return this->members_.m_finish + difference_type(n); + } + + void priv_reallocate_map(size_type nodes_to_add, bool add_at_front) + { + size_type old_num_nodes = this->members_.m_finish.m_node - this->members_.m_start.m_node + 1; + size_type new_num_nodes = old_num_nodes + nodes_to_add; + + index_pointer new_nstart; + if (this->members_.m_map_size > 2 * new_num_nodes) { + new_nstart = this->members_.m_map + (this->members_.m_map_size - new_num_nodes) / 2 + + (add_at_front ? nodes_to_add : 0); + if (new_nstart < this->members_.m_start.m_node) + boost::interprocess::move(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart); + else + boost::interprocess::move_backward + (this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart + old_num_nodes); + } + else { + size_type new_map_size = + this->members_.m_map_size + containers_detail::max_value(this->members_.m_map_size, nodes_to_add) + 2; + + index_pointer new_map = this->priv_allocate_map(new_map_size); + new_nstart = new_map + (new_map_size - new_num_nodes) / 2 + + (add_at_front ? nodes_to_add : 0); + boost::interprocess::move(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart); + this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); + + this->members_.m_map = new_map; + this->members_.m_map_size = new_map_size; + } + + this->members_.m_start.priv_set_node(new_nstart); + this->members_.m_finish.priv_set_node(new_nstart + old_num_nodes - 1); + } + /// @endcond +}; + +// Nonmember functions. +template +inline bool operator==(const deque& x, + const deque& y) +{ + return x.size() == y.size() && equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool operator<(const deque& x, + const deque& y) +{ + return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); +} + +template +inline bool operator!=(const deque& x, + const deque& y) + { return !(x == y); } + +template +inline bool operator>(const deque& x, + const deque& y) + { return y < x; } + +template +inline bool operator<=(const deque& x, + const deque& y) + { return !(y < x); } + +template +inline bool operator>=(const deque& x, + const deque& y) + { return !(x < y); } + + +template +inline void swap(deque& x, deque& y) +{ x.swap(y); } + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + enum { value = has_trivial_destructor::value }; +}; + +}} + +/// @endcond + +#include + +#endif // #ifndef BOOST_CONTAINERS_DEQUE_HPP diff --git a/include/boost/interprocess/detail/advanced_insert_int.hpp b/include/boost/interprocess/containers/container/detail/advanced_insert_int.hpp similarity index 77% rename from include/boost/interprocess/detail/advanced_insert_int.hpp rename to include/boost/interprocess/containers/container/detail/advanced_insert_int.hpp index 42b2f31..35ed645 100644 --- a/include/boost/interprocess/detail/advanced_insert_int.hpp +++ b/include/boost/interprocess/containers/container/detail/advanced_insert_int.hpp @@ -4,26 +4,26 @@ // 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. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_ADVANCED_INSERT_INT_HPP -#define BOOST_INTERPROCESS_ADVANCED_INSERT_INT_HPP +#ifndef BOOST_CONTAINERS_ADVANCED_INSERT_INT_HPP +#define BOOST_CONTAINERS_ADVANCED_INSERT_INT_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include +#include +#include #include #include //std::iterator_traits #include //std::copy, std::uninitialized_copy #include //placement new #include -namespace boost { namespace interprocess { namespace detail { +namespace boost { namespace interprocess_container { namespace containers_detail { //This class will be interface for operations dependent on FwdIt types used advanced_insert_aux_impl template @@ -51,21 +51,21 @@ struct advanced_insert_aux_proxy {} virtual void copy_all_to(Iterator p) - { *std::copy(first_, last_, p); } + { std::copy(first_, last_, p); } virtual void uninitialized_copy_all_to(Iterator p) - { std::uninitialized_copy(first_, last_, p); } + { boost::interprocess::uninitialized_copy_or_move(first_, last_, p); } virtual void uninitialized_copy_some_and_update(Iterator pos, difference_type division_count, bool first_n) { FwdIt mid = first_; std::advance(mid, division_count); if(first_n){ - std::uninitialized_copy(first_, mid, pos); + boost::interprocess::uninitialized_copy_or_move(first_, mid, pos); first_ = mid; } else{ - std::uninitialized_copy(mid, last_, pos); + boost::interprocess::uninitialized_copy_or_move(mid, last_, pos); last_ = mid; } } @@ -104,12 +104,12 @@ struct default_construct_aux_proxy SizeType i = 0; try{ for(; i < n; ++i, ++p){ - new(detail::get_pointer(&*p))T(); + new(containers_detail::get_pointer(&*p))T(); } } catch(...){ while(i--){ - detail::get_pointer(&*orig_p++)->~T(); + containers_detail::get_pointer(&*orig_p++)->~T(); } throw; } @@ -159,18 +159,18 @@ struct default_construct_aux_proxy SizeType count_; }; -}}} //namespace boost { namespace interprocess { namespace detail { +}}} //namespace boost { namespace interprocess_container { namespace containers_detail { -#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING -#include +#include #include #include //#include //For debugging purposes namespace boost { -namespace interprocess { -namespace detail { +namespace interprocess_container { +namespace containers_detail { //This class template will adapt each FwIt types to advanced_insert_aux_int template @@ -204,8 +204,8 @@ struct advanced_insert_aux_emplace void priv_copy_all_to(const index_tuple&, Iterator p) { if(!used_){ - T object(detail::forward_impl(get(args_))...); - *p = detail::move_impl(object); + T object(boost::interprocess::forward(get(args_))...); + *p = boost::interprocess::move(object); used_ = true; } } @@ -214,7 +214,7 @@ struct advanced_insert_aux_emplace void priv_uninitialized_copy_all_to(const index_tuple&, Iterator p) { if(!used_){ - new(detail::get_pointer(&*p))T(detail::forward_impl(get(args_))...); + new(containers_detail::get_pointer(&*p))T(boost::interprocess::forward(get(args_))...); used_ = true; } } @@ -225,7 +225,7 @@ struct advanced_insert_aux_emplace assert(division_count <=1); if((first_n && division_count == 1) || (!first_n && division_count == 0)){ if(!used_){ - new(detail::get_pointer(&*p))T(detail::forward_impl(get(args_))...); + new(containers_detail::get_pointer(&*p))T(boost::interprocess::forward(get(args_))...); used_ = true; } } @@ -237,8 +237,8 @@ struct advanced_insert_aux_emplace assert(division_count <=1); if((first_n && division_count == 1) || (!first_n && division_count == 0)){ if(!used_){ - T object(detail::forward_impl(get(args_))...); - *p = detail::move_impl(object); + T object(boost::interprocess::forward(get(args_))...); + *p = boost::interprocess::move(object); used_ = true; } } @@ -247,25 +247,16 @@ struct advanced_insert_aux_emplace bool used_; }; -}}} //namespace boost { namespace interprocess { namespace detail { +}}} //namespace boost { namespace interprocess_container { namespace containers_detail { -#else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING -#include +#include +#include namespace boost { -namespace interprocess { -namespace detail { - -template -struct value_init_helper -{ - value_init_helper() - : m_t() - {} - - T m_t; -}; +namespace interprocess_container { +namespace containers_detail { //This class template will adapt each FwIt types to advanced_insert_aux_int template @@ -283,8 +274,8 @@ struct advanced_insert_aux_emplace virtual void copy_all_to(Iterator p) { if(!used_){ - value_init_helperv; - *p = detail::move_impl(v.m_t); + value_initv; + *p = boost::interprocess::move(v.m_t); used_ = true; } } @@ -292,7 +283,7 @@ struct advanced_insert_aux_emplace virtual void uninitialized_copy_all_to(Iterator p) { if(!used_){ - new(detail::get_pointer(&*p))T(); + new(containers_detail::get_pointer(&*p))T(); used_ = true; } } @@ -302,7 +293,7 @@ struct advanced_insert_aux_emplace assert(division_count <=1); if((first_n && division_count == 1) || (!first_n && division_count == 0)){ if(!used_){ - new(detail::get_pointer(&*p))T(); + new(containers_detail::get_pointer(&*p))T(); used_ = true; } } @@ -313,8 +304,8 @@ struct advanced_insert_aux_emplace assert(division_count <=1); if((first_n && division_count == 1) || (!first_n && division_count == 0)){ if(!used_){ - value_init_helperv; - *p = detail::move_impl(v.m_t); + value_initv; + *p = boost::interprocess::move(v.m_t); used_ = true; } } @@ -331,14 +322,14 @@ struct advanced_insert_aux_emplace typedef typename advanced_insert_aux_int::difference_type difference_type; \ \ BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ - ( BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _) ) \ - : used_(false), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_AUX_PARAM_INIT, _) {} \ + ( BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _) ) \ + : used_(false), BOOST_PP_ENUM(n, BOOST_CONTAINERS_AUX_PARAM_INIT, _) {} \ \ virtual void copy_all_to(Iterator p) \ { \ if(!used_){ \ - T v(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \ - *p = detail::move_impl(v); \ + T v(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ + *p = boost::interprocess::move(v); \ used_ = true; \ } \ } \ @@ -346,8 +337,8 @@ struct advanced_insert_aux_emplace virtual void uninitialized_copy_all_to(Iterator p) \ { \ if(!used_){ \ - new(detail::get_pointer(&*p))T \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \ + new(containers_detail::get_pointer(&*p))T \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ used_ = true; \ } \ } \ @@ -358,8 +349,8 @@ struct advanced_insert_aux_emplace assert(division_count <=1); \ if((first_n && division_count == 1) || (!first_n && division_count == 0)){ \ if(!used_){ \ - new(detail::get_pointer(&*p))T \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \ + new(containers_detail::get_pointer(&*p))T \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ used_ = true; \ } \ } \ @@ -371,25 +362,25 @@ struct advanced_insert_aux_emplace assert(division_count <=1); \ if((first_n && division_count == 1) || (!first_n && division_count == 0)){ \ if(!used_){ \ - T v(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \ - *p = detail::move_impl(v); \ + T v(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ + *p = boost::interprocess::move(v); \ used_ = true; \ } \ } \ } \ \ bool used_; \ - BOOST_PP_REPEAT(n, BOOST_INTERPROCESS_AUX_PARAM_DEFINE, _) \ + BOOST_PP_REPEAT(n, BOOST_CONTAINERS_AUX_PARAM_DEFINE, _) \ }; \ //! -#define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) +#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() -}}} //namespace boost { namespace interprocess { namespace detail { +}}} //namespace boost { namespace interprocess_container { namespace containers_detail { -#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING -#include +#include -#endif //#ifndef BOOST_INTERPROCESS_ADVANCED_INSERT_INT_HPP +#endif //#ifndef BOOST_CONTAINERS_ADVANCED_INSERT_INT_HPP diff --git a/include/boost/interprocess/detail/algorithms.hpp b/include/boost/interprocess/containers/container/detail/algorithms.hpp similarity index 69% rename from include/boost/interprocess/detail/algorithms.hpp rename to include/boost/interprocess/containers/container/detail/algorithms.hpp index 534dfef..100ffff 100644 --- a/include/boost/interprocess/detail/algorithms.hpp +++ b/include/boost/interprocess/containers/container/detail/algorithms.hpp @@ -6,71 +6,81 @@ // (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. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_ALGORITHMS_HPP -#define BOOST_INTERPROCESS_DETAIL_ALGORITHMS_HPP +#ifndef BOOST_CONTAINERS_DETAIL_ALGORITHMS_HPP +#define BOOST_CONTAINERS_DETAIL_ALGORITHMS_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include -#include -#include +#include +#include + #include #include #include #include + +#include +#include +#include + + #include namespace boost { -namespace interprocess { - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) || !defined(BOOST_INTERPROCESS_RVALUE_PAIR) +namespace interprocess_container { +#if !defined(BOOST_HAS_RVALUE_REFS) template struct has_own_construct_from_it { static const bool value = false; }; -namespace detail { +namespace containers_detail { template -inline void construct_in_place_impl(T* dest, const InpIt &source, detail::true_) +inline void construct_in_place_impl(T* dest, const InpIt &source, containers_detail::true_) { T::construct(dest, *source); } template -inline void construct_in_place_impl(T* dest, const InpIt &source, detail::false_) +inline void construct_in_place_impl(T* dest, const InpIt &source, containers_detail::false_) { new((void*)dest)T(*source); } -} //namespace detail { +} //namespace containers_detail { template inline void construct_in_place(T* dest, InpIt source) { - typedef detail::bool_::value> boolean_t; - detail::construct_in_place_impl(dest, source, boolean_t()); + typedef containers_detail::bool_::value> boolean_t; + containers_detail::construct_in_place_impl(dest, source, boolean_t()); } #else template inline void construct_in_place(T* dest, InpIt source) -{ new((void*)dest)T(*source); } +{ ::new((void*)dest)T(*source); } #endif template inline void construct_in_place(T *dest, default_construct_iterator) { - new((void*)dest)T(); + ::new((void*)dest)T(); +} + +template +inline void construct_in_place(T *dest, emplace_iterator ei) +{ + ei.construct_in_place(dest); } template @@ -108,7 +118,7 @@ struct optimize_copy {}; template inline -OutIt copy_n_dispatch(InIt first, typename std::iterator_traits::difference_type length, OutIt dest, detail::bool_) +OutIt copy_n_dispatch(InIt first, typename std::iterator_traits::difference_type length, OutIt dest, containers_detail::bool_) { for (; length--; ++dest, ++first) *dest = *first; @@ -116,7 +126,7 @@ OutIt copy_n_dispatch(InIt first, typename std::iterator_traits::differenc } template inline -T *copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, detail::bool_) +T *copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, containers_detail::bool_) { std::size_t size = length*sizeof(T); return (static_cast(std::memmove(dest, first, size))) + size; @@ -126,14 +136,14 @@ template inline OutIt copy_n(InIt first, typename std::iterator_traits::difference_type length, OutIt dest) { const bool do_optimized_assign = optimize_assign::value; - return copy_n_dispatch(first, length, dest, detail::bool_()); + return copy_n_dispatch(first, length, dest, containers_detail::bool_()); } template inline FwdIt uninitialized_copy_n_dispatch (InIt first, typename std::iterator_traits::difference_type count, - FwdIt dest, detail::bool_) + FwdIt dest, containers_detail::bool_) { typedef typename std::iterator_traits::value_type value_type; //Save initial destination position @@ -143,14 +153,14 @@ FwdIt uninitialized_copy_n_dispatch BOOST_TRY{ //Try to build objects for (; --new_count; ++dest, ++first){ - construct_in_place(detail::get_pointer(&*dest), first); + construct_in_place(containers_detail::get_pointer(&*dest), first); } } BOOST_CATCH(...){ //Call destructors new_count = count - new_count; for (; new_count--; ++dest_init){ - detail::get_pointer(&*dest_init)->~value_type(); + containers_detail::get_pointer(&*dest_init)->~value_type(); } BOOST_RETHROW } @@ -158,7 +168,7 @@ FwdIt uninitialized_copy_n_dispatch return dest; } template inline -T *uninitialized_copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, detail::bool_) +T *uninitialized_copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, containers_detail::bool_) { std::size_t size = length*sizeof(T); return (static_cast(std::memmove(dest, first, size))) + size; @@ -171,7 +181,7 @@ FwdIt uninitialized_copy_n FwdIt dest) { const bool do_optimized_copy = optimize_copy::value; - return uninitialized_copy_n_dispatch(first, count, dest, detail::bool_()); + return uninitialized_copy_n_dispatch(first, count, dest, containers_detail::bool_()); } // uninitialized_copy_copy @@ -189,17 +199,17 @@ FwdIt uninitialized_copy_copy } BOOST_CATCH(...){ for(;result != mid; ++result){ - detail::get_pointer(&*result)->~value_type(); + containers_detail::get_pointer(&*result)->~value_type(); } BOOST_RETHROW } BOOST_CATCH_END } -} //namespace interprocess { +} //namespace interprocess_container { } //namespace boost { -#include +#include -#endif //#ifndef BOOST_INTERPROCESS_DETAIL_ALGORITHMS_HPP +#endif //#ifndef BOOST_CONTAINERS_DETAIL_ALGORITHMS_HPP diff --git a/include/boost/interprocess/allocators/allocation_type.hpp b/include/boost/interprocess/containers/container/detail/allocation_type.hpp similarity index 75% rename from include/boost/interprocess/allocators/allocation_type.hpp rename to include/boost/interprocess/containers/container/detail/allocation_type.hpp index 1894d11..7cbffb3 100644 --- a/include/boost/interprocess/allocators/allocation_type.hpp +++ b/include/boost/interprocess/containers/container/detail/allocation_type.hpp @@ -4,22 +4,22 @@ // 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. +// See http://www.boost.org/libs/container for documentation. // /////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_TYPE_COMMAND_HPP -#define BOOST_INTERPROCESS_TYPE_COMMAND_HPP +#ifndef BOOST_CONTAINERS_ALLOCATION_TYPE_HPP +#define BOOST_CONTAINERS_ALLOCATION_TYPE_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include +#include +#include namespace boost { -namespace interprocess { +namespace interprocess_container { /// @cond enum allocation_type_v @@ -46,10 +46,9 @@ static const allocation_type try_shrink_in_place= (allocation_type)try_shrink_in static const allocation_type nothrow_allocation = (allocation_type)nothrow_allocation_v; static const allocation_type zero_memory = (allocation_type)zero_memory_v; -} //namespace interprocess { +} //namespace interprocess_container { } //namespace boost { -#include - -#endif //BOOST_INTERPROCESS_TYPE_COMMAND_HPP +#include +#endif //BOOST_CONTAINERS_ALLOCATION_TYPE_HPP diff --git a/include/boost/interprocess/containers/container/detail/config_begin.hpp b/include/boost/interprocess/containers/container/detail/config_begin.hpp new file mode 100644 index 0000000..814b00c --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/config_begin.hpp @@ -0,0 +1,47 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_CONFIG_INCLUDED +#define BOOST_CONTAINERS_CONTAINER_DETAIL_CONFIG_INCLUDED +#include +#endif + +#ifdef BOOST_MSVC + #ifndef _CRT_SECURE_NO_DEPRECATE + #define BOOST_CONTAINERS_DETAIL_CRT_SECURE_NO_DEPRECATE + #define _CRT_SECURE_NO_DEPRECATE + #endif + #pragma warning (push) + #pragma warning (disable : 4702) // unreachable code + #pragma warning (disable : 4706) // assignment within conditional expression + #pragma warning (disable : 4127) // conditional expression is constant + #pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned + #pragma warning (disable : 4284) // odd return type for operator-> + #pragma warning (disable : 4244) // possible loss of data + #pragma warning (disable : 4251) // "identifier" : class "type" needs to have dll-interface to be used by clients of class "type2" + #pragma warning (disable : 4267) // conversion from "X" to "Y", possible loss of data + #pragma warning (disable : 4275) // non DLL-interface classkey "identifier" used as base for DLL-interface classkey "identifier" + #pragma warning (disable : 4355) // "this" : used in base member initializer list + #pragma warning (disable : 4503) // "identifier" : decorated name length exceeded, name was truncated + #pragma warning (disable : 4511) // copy constructor could not be generated + #pragma warning (disable : 4512) // assignment operator could not be generated + #pragma warning (disable : 4514) // unreferenced inline removed + #pragma warning (disable : 4521) // Disable "multiple copy constructors specified" + #pragma warning (disable : 4522) // "class" : multiple assignment operators specified + #pragma warning (disable : 4675) // "method" should be declared "static" and have exactly one parameter + #pragma warning (disable : 4710) // function not inlined + #pragma warning (disable : 4711) // function selected for automatic inline expansion + #pragma warning (disable : 4786) // identifier truncated in debug info + #pragma warning (disable : 4996) // "function": was declared deprecated + #pragma warning (disable : 4197) // top-level volatile in cast is ignored + #pragma warning (disable : 4541) // 'typeid' used on polymorphic type 'boost::exception' + // with /GR-; unpredictable behavior may result + #pragma warning (disable : 4673) // throwing '' the following types will not be considered at the catch site + #pragma warning (disable : 4671) // the copy constructor is inaccessible +#endif diff --git a/include/boost/interprocess/containers/container/detail/config_end.hpp b/include/boost/interprocess/containers/container/detail/config_end.hpp new file mode 100644 index 0000000..a6c46ef --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/config_end.hpp @@ -0,0 +1,17 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#if defined BOOST_MSVC + #pragma warning (pop) + #ifdef BOOST_CONTAINERS_DETAIL_CRT_SECURE_NO_DEPRECATE + #undef BOOST_CONTAINERS_DETAIL_CRT_SECURE_NO_DEPRECATE + #undef _CRT_SECURE_NO_DEPRECATE + #endif +#endif + diff --git a/include/boost/interprocess/containers/container/detail/destroyers.hpp b/include/boost/interprocess/containers/container/detail/destroyers.hpp new file mode 100644 index 0000000..c16139b --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/destroyers.hpp @@ -0,0 +1,154 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2009. +// +// 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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DESTROYERS_HPP +#define BOOST_CONTAINERS_DESTROYERS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +//!A deleter for scoped_ptr that deallocates the memory +//!allocated for an array of objects using a STL allocator. +template +struct scoped_array_deallocator +{ + typedef typename Allocator::pointer pointer; + typedef typename Allocator::size_type size_type; + + scoped_array_deallocator(pointer p, Allocator& a, size_type length) + : m_ptr(p), m_alloc(a), m_length(length) {} + + ~scoped_array_deallocator() + { if (m_ptr) m_alloc.deallocate(m_ptr, m_length); } + + void release() + { m_ptr = 0; } + + private: + pointer m_ptr; + Allocator& m_alloc; + size_type m_length; +}; + +template +struct null_scoped_array_deallocator +{ + typedef typename Allocator::pointer pointer; + typedef typename Allocator::size_type size_type; + + null_scoped_array_deallocator(pointer, Allocator&, size_type) + {} + + void release() + {} +}; + + +//!A deleter for scoped_ptr that destroys +//!an object using a STL allocator. +template +struct scoped_destructor_n +{ + typedef typename Allocator::pointer pointer; + typedef typename Allocator::value_type value_type; + typedef typename Allocator::size_type size_type; + + pointer m_p; + size_type m_n; + + scoped_destructor_n(pointer p, size_type n) + : m_p(p), m_n(n) + {} + + void release() + { m_p = 0; } + + void increment_size(size_type inc) + { m_n += inc; } + + ~scoped_destructor_n() + { + if(!m_p) return; + value_type *raw_ptr = containers_detail::get_pointer(m_p); + for(std::size_t i = 0; i < m_n; ++i, ++raw_ptr) + raw_ptr->~value_type(); + } +}; + +//!A deleter for scoped_ptr that destroys +//!an object using a STL allocator. +template +struct null_scoped_destructor_n +{ + typedef typename Allocator::pointer pointer; + typedef typename Allocator::size_type size_type; + + null_scoped_destructor_n(pointer, size_type) + {} + + void increment_size(size_type) + {} + + void release() + {} +}; + +template +class allocator_destroyer +{ + typedef typename A::value_type value_type; + typedef containers_detail::integral_constant::value> alloc_version; + typedef containers_detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + + private: + A & a_; + + private: + void priv_deallocate(const typename A::pointer &p, allocator_v1) + { a_.deallocate(p, 1); } + + void priv_deallocate(const typename A::pointer &p, allocator_v2) + { a_.deallocate_one(p); } + + public: + allocator_destroyer(A &a) + : a_(a) + {} + + void operator()(const typename A::pointer &p) + { + containers_detail::get_pointer(p)->~value_type(); + priv_deallocate(p, alloc_version()); + } +}; + + +} //namespace containers_detail { +} //namespace interprocess_container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DESTROYERS_HPP diff --git a/include/boost/interprocess/containers/detail/flat_tree.hpp b/include/boost/interprocess/containers/container/detail/flat_tree.hpp similarity index 80% rename from include/boost/interprocess/containers/detail/flat_tree.hpp rename to include/boost/interprocess/containers/container/detail/flat_tree.hpp index c2ebfc1..438fa75 100644 --- a/include/boost/interprocess/containers/detail/flat_tree.hpp +++ b/include/boost/interprocess/containers/container/detail/flat_tree.hpp @@ -4,7 +4,7 @@ // 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. +// See http://www.boost.org/libs/container for documentation. // //////////////////////////////////////////////////////////////////////////////// // The Loki Library @@ -25,35 +25,40 @@ // //////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_FLAT_TREE_HPP -#define BOOST_INTERPROCESS_FLAT_TREE_HPP +#ifndef BOOST_CONTAINERS_FLAT_TREE_HPP +#define BOOST_CONTAINERS_FLAT_TREE_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include +#include +#include -#include -#include -#include -#include #include #include #include +#include +#include + +#include +#include +#include +#include +#include + namespace boost { -namespace interprocess { +namespace interprocess_container { -namespace detail { +namespace containers_detail { template class flat_tree { - typedef boost::interprocess::vector vector_t; + typedef boost::interprocess_container::vector vector_t; typedef Alloc allocator_t; public: @@ -105,6 +110,7 @@ class flat_tree Data m_data; public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(flat_tree) typedef typename vector_t::value_type value_type; typedef typename vector_t::pointer pointer; @@ -133,15 +139,9 @@ class flat_tree : m_data(x.m_data, x.m_data.m_vect) { } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_tree(detail::moved_object x) - : m_data(detail::move_impl(x.get().m_data)) + flat_tree(BOOST_INTERPROCESS_RV_REF(flat_tree) x) + : m_data(boost::interprocess::move(x.m_data)) { } - #else - flat_tree(flat_tree &&x) - : m_data(detail::move_impl(x.m_data)) - { } - #endif ~flat_tree() { } @@ -149,13 +149,8 @@ class flat_tree flat_tree& operator=(const flat_tree& x) { m_data = x.m_data; return *this; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_tree& operator=(detail::moved_object mx) - { m_data = detail::move_impl(mx.get().m_data); return *this; } - #else - flat_tree& operator=(flat_tree &&mx) - { m_data = detail::move_impl(mx.m_data); return *this; } - #endif + flat_tree& operator=(BOOST_INTERPROCESS_RV_REF(flat_tree) mx) + { m_data = boost::interprocess::move(mx.m_data); return *this; } public: // accessors: @@ -220,20 +215,12 @@ class flat_tree { value_compare& mycomp = this->m_data; value_compare& othercomp = other.m_data; - detail::do_swap(mycomp, othercomp); + containers_detail::do_swap(mycomp, othercomp); vector_t & myvect = this->m_data.m_vect; vector_t & othervect = other.m_data.m_vect; myvect.swap(othervect); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(detail::moved_object other) - { this->swap(other.get()); } - #else - void swap(flat_tree &&other) - { this->swap(other); } - #endif - public: // insert/erase std::pair insert_unique(const value_type& val) @@ -246,18 +233,12 @@ class flat_tree return ret; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - std::pair insert_unique(detail::moved_object mval) + std::pair insert_unique(BOOST_INTERPROCESS_RV_REF(value_type) val) { - value_type &val = mval.get(); - #else - std::pair insert_unique(value_type && val) - { - #endif insert_commit_data data; std::pair ret = priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret; } @@ -270,21 +251,12 @@ class flat_tree return i; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert_equal(detail::moved_object mval) - { - iterator i = this->upper_bound(KeyOfValue()(mval.get())); - i = this->m_data.m_vect.insert(i, mval); - return i; - } - #else - iterator insert_equal(value_type && mval) + iterator insert_equal(BOOST_INTERPROCESS_RV_REF(value_type) mval) { iterator i = this->upper_bound(KeyOfValue()(mval)); - i = this->m_data.m_vect.insert(i, detail::move_impl(mval)); + i = this->m_data.m_vect.insert(i, boost::interprocess::move(mval)); return i; } - #endif iterator insert_unique(const_iterator pos, const value_type& val) { @@ -296,27 +268,15 @@ class flat_tree return ret.first; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert_unique(const_iterator pos, detail::moved_object mval) - { - insert_commit_data data; - std::pair ret = priv_insert_unique_prepare(pos, mval.get(), data); - if(ret.second){ - ret.first = priv_insert_commit(data, mval); - } - return ret.first; - } - #else - iterator insert_unique(const_iterator pos, value_type&&mval) + iterator insert_unique(const_iterator pos, BOOST_INTERPROCESS_RV_REF(value_type) mval) { insert_commit_data data; std::pair ret = priv_insert_unique_prepare(pos, mval, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(mval)); + ret.first = priv_insert_commit(data, boost::interprocess::move(mval)); } return ret.first; } - #endif iterator insert_equal(const_iterator pos, const value_type& val) { @@ -325,21 +285,12 @@ class flat_tree return priv_insert_commit(data, val); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert_equal(const_iterator pos, detail::moved_object mval) - { - insert_commit_data data; - priv_insert_equal_prepare(pos, mval.get(), data); - return priv_insert_commit(data, mval); - } - #else - iterator insert_equal(const_iterator pos, value_type && mval) + iterator insert_equal(const_iterator pos, BOOST_INTERPROCESS_RV_REF(value_type) mval) { insert_commit_data data; priv_insert_equal_prepare(pos, mval, data); - return priv_insert_commit(data, detail::move_impl(mval)); + return priv_insert_commit(data, boost::interprocess::move(mval)); } - #endif template void insert_unique(InIt first, InIt last) @@ -356,17 +307,17 @@ class flat_tree priv_insert_equal(first, last, ItCat()); } - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING template iterator emplace_unique(Args&&... args) { - value_type val(detail::forward_impl(args)...); + value_type val(boost::interprocess::forward(args)...); insert_commit_data data; std::pair ret = priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret.first; } @@ -374,11 +325,11 @@ class flat_tree template iterator emplace_hint_unique(const_iterator hint, Args&&... args) { - value_type val(detail::forward_impl(args)...); + value_type val(boost::interprocess::forward(args)...); insert_commit_data data; std::pair ret = priv_insert_unique_prepare(hint, val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret.first; } @@ -386,115 +337,115 @@ class flat_tree template iterator emplace_equal(Args&&... args) { - value_type val(detail::forward_impl(args)...); + value_type val(boost::interprocess::forward(args)...); iterator i = this->upper_bound(KeyOfValue()(val)); - i = this->m_data.m_vect.insert(i, detail::move_impl(val)); + i = this->m_data.m_vect.insert(i, boost::interprocess::move(val)); return i; } template iterator emplace_hint_equal(const_iterator hint, Args&&... args) { - value_type val(detail::forward_impl(args)...); + value_type val(boost::interprocess::forward(args)...); insert_commit_data data; priv_insert_equal_prepare(hint, val, data); - return priv_insert_commit(data, detail::move_impl(val)); + return priv_insert_commit(data, boost::interprocess::move(val)); } - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING iterator emplace_unique() { - detail::value_init vval; + containers_detail::value_init vval; value_type &val = vval.m_t; insert_commit_data data; std::pair ret = priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret.first; } iterator emplace_hint_unique(const_iterator hint) { - detail::value_init vval; + containers_detail::value_init vval; value_type &val = vval.m_t; insert_commit_data data; std::pair ret = priv_insert_unique_prepare(hint, val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret.first; } iterator emplace_equal() { - detail::value_init vval; + containers_detail::value_init vval; value_type &val = vval.m_t; iterator i = this->upper_bound(KeyOfValue()(val)); - i = this->m_data.m_vect.insert(i, detail::move_impl(val)); + i = this->m_data.m_vect.insert(i, boost::interprocess::move(val)); return i; } iterator emplace_hint_equal(const_iterator hint) { - detail::value_init vval; + containers_detail::value_init vval; value_type &val = vval.m_t; insert_commit_data data; priv_insert_equal_prepare(hint, val, data); - return priv_insert_commit(data, detail::move_impl(val)); + return priv_insert_commit(data, boost::interprocess::move(val)); } #define BOOST_PP_LOCAL_MACRO(n) \ template \ - iterator emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ insert_commit_data data; \ std::pair ret = priv_insert_unique_prepare(val, data); \ if(ret.second){ \ - ret.first = priv_insert_commit(data, detail::move_impl(val)); \ + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); \ } \ return ret.first; \ } \ \ template \ iterator emplace_hint_unique(const_iterator hint, \ - BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ insert_commit_data data; \ std::pair ret = priv_insert_unique_prepare(hint, val, data); \ if(ret.second){ \ - ret.first = priv_insert_commit(data, detail::move_impl(val)); \ + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); \ } \ return ret.first; \ } \ \ template \ - iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ iterator i = this->upper_bound(KeyOfValue()(val)); \ - i = this->m_data.m_vect.insert(i, detail::move_impl(val)); \ + i = this->m_data.m_vect.insert(i, boost::interprocess::move(val)); \ return i; \ } \ \ template \ iterator emplace_hint_equal(const_iterator hint, \ - BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ insert_commit_data data; \ priv_insert_equal_prepare(hint, val, data); \ - return priv_insert_commit(data, detail::move_impl(val)); \ + return priv_insert_commit(data, boost::interprocess::move(val)); \ } \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING iterator erase(const_iterator position) { return this->m_data.m_vect.erase(position); } @@ -682,17 +633,14 @@ class flat_tree } } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template iterator priv_insert_commit - (insert_commit_data &commit_data, const Convertible &convertible) - { return this->m_data.m_vect.insert(commit_data.position, convertible); } - #else - template - iterator priv_insert_commit - (insert_commit_data &commit_data, Convertible &&convertible) - { return this->m_data.m_vect.insert(commit_data.position, detail::forward_impl(convertible)); } - #endif + (insert_commit_data &commit_data, BOOST_INTERPROCESS_FWD_REF(Convertible) convertible) + { + return this->m_data.m_vect.insert + ( commit_data.position + , boost::interprocess::forward(convertible)); + } template RanIt priv_lower_bound(RanIt first, RanIt last, @@ -865,23 +813,25 @@ swap(flat_tree& x, flat_tree& y) { x.swap(y); } -} //namespace detail { +} //namespace containers_detail { + +} //namespace interprocess_container { + +namespace interprocess { //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations template -struct has_trivial_destructor_after_move > +class C, class A> +struct has_trivial_destructor_after_move > { - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; }; } //namespace interprocess { } //namespace boost { -#include +#include -#endif // BOOST_INTERPROCESS_FLAT_TREE_HPP +#endif // BOOST_CONTAINERS_FLAT_TREE_HPP diff --git a/include/boost/interprocess/detail/iterators.hpp b/include/boost/interprocess/containers/container/detail/iterators.hpp similarity index 65% rename from include/boost/interprocess/detail/iterators.hpp rename to include/boost/interprocess/containers/container/detail/iterators.hpp index c566159..64841b1 100644 --- a/include/boost/interprocess/detail/iterators.hpp +++ b/include/boost/interprocess/containers/container/detail/iterators.hpp @@ -7,27 +7,31 @@ // (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. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_ITERATORS_HPP -#define BOOST_INTERPROCESS_DETAIL_ITERATORS_HPP +#ifndef BOOST_CONTAINERS_DETAIL_ITERATORS_HPP +#define BOOST_CONTAINERS_DETAIL_ITERATORS_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include +#include +#include +#include -#include +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING +#include +#else +#include +#endif #include -#include namespace boost { -namespace interprocess { +namespace interprocess_container { template class constant_iterator @@ -324,152 +328,165 @@ class repeat_iterator { return m_num - other.m_num; } }; -template -struct operator_arrow_proxy +template +class emplace_iterator + : public std::iterator + { - operator_arrow_proxy(const PseudoReference &px) - : m_value(px) - {} + typedef emplace_iterator this_type; - PseudoReference* operator->() const { return &m_value; } - // This function is needed for MWCW and BCC, which won't call operator-> - // again automatically per 13.3.1.2 para 8 -// operator T*() const { return &m_value; } - mutable PseudoReference m_value; -}; - -template -struct operator_arrow_proxy -{ - operator_arrow_proxy(T &px) - : m_value(px) - {} - - T* operator->() const { return &m_value; } - // This function is needed for MWCW and BCC, which won't call operator-> - // again automatically per 13.3.1.2 para 8 -// operator T*() const { return &m_value; } - mutable T &m_value; -}; - -template -class transform_iterator - : public UnaryFunction - , public std::iterator - < typename Iterator::iterator_category - , typename detail::remove_reference::type - , typename Iterator::difference_type - , operator_arrow_proxy - , typename UnaryFunction::result_type> -{ public: - explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction()) - : UnaryFunction(f), m_it(it) - {} + explicit emplace_iterator(E&e) + : m_num(1), m_pe(&e){} - explicit transform_iterator() - : UnaryFunction(), m_it() - {} + emplace_iterator() + : m_num(0), m_pe(0){} - //Constructors - transform_iterator& operator++() + this_type& operator++() { increment(); return *this; } - - transform_iterator operator++(int) + + this_type operator++(int) { - transform_iterator result (*this); + this_type result (*this); increment(); return result; } - friend bool operator== (const transform_iterator& i, const transform_iterator& i2) + friend bool operator== (const this_type& i, const this_type& i2) { return i.equal(i2); } - friend bool operator!= (const transform_iterator& i, const transform_iterator& i2) + friend bool operator!= (const this_type& i, const this_type& i2) { return !(i == i2); } -/* - friend bool operator> (const transform_iterator& i, const transform_iterator& i2) + friend bool operator< (const this_type& i, const this_type& i2) + { return i.less(i2); } + + friend bool operator> (const this_type& i, const this_type& i2) { return i2 < i; } - friend bool operator<= (const transform_iterator& i, const transform_iterator& i2) + friend bool operator<= (const this_type& i, const this_type& i2) { return !(i > i2); } - friend bool operator>= (const transform_iterator& i, const transform_iterator& i2) + friend bool operator>= (const this_type& i, const this_type& i2) { return !(i < i2); } -*/ - friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2) + + friend std::ptrdiff_t operator- (const this_type& i, const this_type& i2) { return i2.distance_to(i); } //Arithmetic - transform_iterator& operator+=(typename Iterator::difference_type off) + this_type& operator+=(std::ptrdiff_t off) { this->advance(off); return *this; } - transform_iterator operator+(typename Iterator::difference_type off) const + this_type operator+(std::ptrdiff_t off) const { - transform_iterator other(*this); + this_type other(*this); other.advance(off); return other; } - friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right) + friend this_type operator+(std::ptrdiff_t off, const this_type& right) { return right + off; } - transform_iterator& operator-=(typename Iterator::difference_type off) + this_type& operator-=(std::ptrdiff_t off) { this->advance(-off); return *this; } - transform_iterator operator-(typename Iterator::difference_type off) const + this_type operator-(std::ptrdiff_t off) const { return *this + (-off); } - typename UnaryFunction::result_type operator*() const + const T& operator*() const { return dereference(); } - operator_arrow_proxy - operator->() const - { return operator_arrow_proxy(dereference()); } + const T* operator->() const + { return &(dereference()); } - Iterator & base() - { return m_it; } - - const Iterator & base() const - { return m_it; } + void construct_in_place(T* ptr) + { (*m_pe)(ptr); } private: - Iterator m_it; + std::ptrdiff_t m_num; + E * m_pe; void increment() - { ++m_it; } + { --m_num; } void decrement() - { --m_it; } + { ++m_num; } - bool equal(const transform_iterator &other) const - { return m_it == other.m_it; } + bool equal(const this_type &other) const + { return m_num == other.m_num; } - bool less(const transform_iterator &other) const - { return other.m_it < m_it; } + bool less(const this_type &other) const + { return other.m_num < m_num; } - typename UnaryFunction::result_type dereference() const - { return UnaryFunction::operator()(*m_it); } + const T & dereference() const + { + static T dummy; + return dummy; + } - void advance(typename Iterator::difference_type n) - { std::advance(m_it, n); } + void advance(std::ptrdiff_t n) + { m_num -= n; } - typename Iterator::difference_type distance_to(const transform_iterator &other)const - { return std::distance(other.m_it, m_it); } + std::ptrdiff_t distance_to(const this_type &other)const + { return m_num - other.m_num; } }; -template -transform_iterator -make_transform_iterator(Iterator it, UnaryFunc fun) -{ - return transform_iterator(it, fun); -} +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING -} //namespace interprocess { +template +struct emplace_functor +{ + typedef typename containers_detail::build_number_seq::type index_tuple_t; + + emplace_functor(Args&&... args) + : args_(args...) + {} + + void operator()(T *ptr) + { emplace_functor::inplace_impl(ptr, index_tuple_t()); } + + template + void inplace_impl(T* ptr, const containers_detail::index_tuple&) + { ::new(ptr) T(boost::interprocess::forward(containers_detail::get(args_))...); } + + containers_detail::tuple args_; +}; + +#else + +template +struct emplace_functor +{ + emplace_functor() + {} + void operator()(T *ptr) + { new(ptr) T(); } +}; + +#define BOOST_PP_LOCAL_MACRO(n) \ + template \ + struct BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + { \ + BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + ( BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _) ) \ + : BOOST_PP_ENUM(n, BOOST_CONTAINERS_AUX_PARAM_INIT, _) {} \ + \ + void operator()(T *ptr) \ + { \ + new(ptr)T (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ + } \ + BOOST_PP_REPEAT(n, BOOST_CONTAINERS_AUX_PARAM_DEFINE, _) \ + }; \ + //! +#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) +#include BOOST_PP_LOCAL_ITERATE() + +#endif + +} //namespace interprocess_container { } //namespace boost { -#include +#include -#endif //#ifndef BOOST_INTERPROCESS_DETAIL_ITERATORS_HPP +#endif //#ifndef BOOST_CONTAINERS_DETAIL_ITERATORS_HPP diff --git a/include/boost/interprocess/containers/container/detail/mpl.hpp b/include/boost/interprocess/containers/container/detail/mpl.hpp new file mode 100644 index 0000000..fbdcb44 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/mpl.hpp @@ -0,0 +1,152 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_MPL_HPP +#define BOOST_CONTAINERS_CONTAINER_DETAIL_MPL_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +struct integral_constant +{ + static const T value = val; + typedef integral_constant type; +}; + +template< bool C_ > +struct bool_ : integral_constant +{ + static const bool value = C_; +}; + +typedef bool_ true_; +typedef bool_ false_; + +typedef true_ true_type; +typedef false_ false_type; + +typedef char yes_type; +struct no_type +{ + char padding[8]; +}; + +template +struct enable_if_c { + typedef T type; +}; + +template +struct enable_if_c {}; + +template +struct enable_if : public enable_if_c {}; + +template +struct disable_if : public enable_if_c {}; + +template +class is_convertible +{ + typedef char true_t; + class false_t { char dummy[2]; }; + static true_t dispatch(U); + static false_t dispatch(...); + static T trigger(); + public: + enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) }; +}; + +template< + bool C + , typename T1 + , typename T2 + > +struct if_c +{ + typedef T1 type; +}; + +template< + typename T1 + , typename T2 + > +struct if_c +{ + typedef T2 type; +}; + +template< + typename T1 + , typename T2 + , typename T3 + > +struct if_ +{ + typedef typename if_c<0 != T1::value, T2, T3>::type type; +}; + + +template +struct select1st +// : public std::unary_function +{ + template + const typename Pair::first_type& operator()(const OtherPair& x) const + { return x.first; } + + const typename Pair::first_type& operator()(const typename Pair::first_type& x) const + { return x; } +}; + +// identity is an extension: it is not part of the standard. +template +struct identity +// : public std::unary_function +{ + typedef T type; + const T& operator()(const T& x) const + { return x; } +}; + +template +struct ls_zeros +{ + static const std::size_t value = (S & std::size_t(1)) ? 0 : (1u + ls_zeros<(S >> 1u)>::value); +}; + +template<> +struct ls_zeros<0> +{ + static const std::size_t value = 0; +}; + +template<> +struct ls_zeros<1> +{ + static const std::size_t value = 0; +}; + +} //namespace containers_detail { +} //namespace interprocess_container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_MPL_HPP + diff --git a/include/boost/interprocess/containers/container/detail/multiallocation_chain.hpp b/include/boost/interprocess/containers/container/detail/multiallocation_chain.hpp new file mode 100644 index 0000000..1f3f2c5 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/multiallocation_chain.hpp @@ -0,0 +1,554 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_MULTIALLOCATION_CHAIN_HPP +#define BOOST_CONTAINERS_DETAIL_MULTIALLOCATION_CHAIN_HPP + +#include +#include +#include +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +class basic_multiallocation_slist +{ +public: + typedef VoidPointer void_pointer; + +private: + static VoidPointer &priv_get_ref(const VoidPointer &p) + { return *static_cast(containers_detail::get_pointer(p)); } + + basic_multiallocation_slist(basic_multiallocation_slist &); + basic_multiallocation_slist &operator=(basic_multiallocation_slist &); + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_slist) + + //!This iterator is returned by "allocate_many" functions so that + //!the user can access the multiple buffers allocated in a single call + class iterator + : public std::iterator + { + friend class basic_multiallocation_slist; + void unspecified_bool_type_func() const {} + typedef void (iterator::*unspecified_bool_type)() const; + + iterator(void_pointer node_range) + : next_node_(node_range) + {} + + public: + typedef char value_type; + typedef value_type & reference; + typedef value_type * pointer; + + iterator() + : next_node_(0) + {} + + iterator &operator=(const iterator &other) + { next_node_ = other.next_node_; return *this; } + + public: + iterator& operator++() + { + next_node_ = *static_cast(containers_detail::get_pointer(next_node_)); + return *this; + } + + iterator operator++(int) + { + iterator result(*this); + ++*this; + return result; + } + + bool operator== (const iterator& other) const + { return next_node_ == other.next_node_; } + + bool operator!= (const iterator& other) const + { return !operator== (other); } + + reference operator*() const + { return *static_cast(containers_detail::get_pointer(next_node_)); } + + operator unspecified_bool_type() const + { return next_node_? &iterator::unspecified_bool_type_func : 0; } + + pointer operator->() const + { return &(*(*this)); } + + private: + void_pointer next_node_; + }; + +private: + iterator it_; + +public: + basic_multiallocation_slist() + : it_(iterator()) + {} + + basic_multiallocation_slist(void_pointer p) + : it_(p ? iterator_to(p) : iterator()) + {} + + basic_multiallocation_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_slist) other) + : it_(iterator()) + { this->swap(other); } + + basic_multiallocation_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_slist) other) + { + basic_multiallocation_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + bool empty() const + { return !it_; } + + iterator before_begin() const + { return iterator(void_pointer(const_cast(static_cast(&it_.next_node_)))); } + + iterator begin() const + { return it_; } + + iterator end() const + { return iterator(); } + + void clear() + { this->it_.next_node_ = void_pointer(0); } + + iterator insert_after(iterator it, void_pointer m) + { + priv_get_ref(m) = priv_get_ref(it.next_node_); + priv_get_ref(it.next_node_) = m; + return iterator(m); + } + + void push_front(void_pointer m) + { + priv_get_ref(m) = this->it_.next_node_; + this->it_.next_node_ = m; + } + + void pop_front() + { ++it_; } + + void *front() const + { return containers_detail::get_pointer(it_.next_node_); } + + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { + if (after_this != before_begin && after_this != before_end && before_begin != before_end) { + void_pointer next_b = priv_get_ref(before_begin.next_node_); + void_pointer next_e = priv_get_ref(before_end.next_node_); + void_pointer next_p = priv_get_ref(after_this.next_node_); + priv_get_ref(before_begin.next_node_) = next_e; + priv_get_ref(before_end.next_node_) = next_p; + priv_get_ref(after_this.next_node_) = next_b; + } + } + + void swap(basic_multiallocation_slist &other_chain) + { + std::swap(this->it_, other_chain.it_); + } + + static iterator iterator_to(void_pointer p) + { return iterator(p); } + + void_pointer extract_data() + { + void_pointer ret = empty() ? void_pointer(0) : void_pointer(&*it_); + it_ = iterator(); + return ret; + } +}; + +template +class basic_multiallocation_cached_slist +{ +private: + basic_multiallocation_slist slist_; + typename basic_multiallocation_slist::iterator last_; + + basic_multiallocation_cached_slist(basic_multiallocation_cached_slist &); + basic_multiallocation_cached_slist &operator=(basic_multiallocation_cached_slist &); + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_cached_slist) + + typedef typename basic_multiallocation_slist::void_pointer void_pointer; + typedef typename basic_multiallocation_slist::iterator iterator; + + basic_multiallocation_cached_slist() + : slist_(), last_(slist_.before_begin()) + {} + /* + basic_multiallocation_cached_slist(iterator first_node) + : slist_(first_node), last_(slist_.before_begin()) + { + iterator end; + while(first_node != end){ + ++last_; + } + }*/ + + basic_multiallocation_cached_slist(void_pointer p1, void_pointer p2) + : slist_(p1), last_(p2 ? iterator_to(p2) : slist_.before_begin()) + {} + + basic_multiallocation_cached_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_slist) other) + : slist_(), last_(slist_.before_begin()) + { this->swap(other); } + + basic_multiallocation_cached_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_slist) other) + { + basic_multiallocation_cached_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + bool empty() const + { return slist_.empty(); } + + iterator before_begin() const + { return slist_.before_begin(); } + + iterator begin() const + { return slist_.begin(); } + + iterator end() const + { return slist_.end(); } + + iterator last() const + { return last_; } + + void clear() + { + slist_.clear(); + last_ = slist_.before_begin(); + } + + iterator insert_after(iterator it, void_pointer m) + { + slist_.insert_after(it, m); + if(it == last_){ + last_ = slist_.iterator_to(m); + } + return iterator_to(m); + } + + void push_front(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void push_back(void_pointer m) + { this->insert_after(last_, m); } + + void pop_front() + { + if(last_ == slist_.begin()){ + last_ = slist_.before_begin(); + } + slist_.pop_front(); + } + + void *front() const + { return slist_.front(); } + + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { + if(before_begin == before_end) + return; + if(after_this == last_){ + last_ = before_end; + } + slist_.splice_after(after_this, before_begin, before_end); + } + + void swap(basic_multiallocation_cached_slist &x) + { + slist_.swap(x.slist_); + using std::swap; + swap(last_, x.last_); + if(last_ == x.before_begin()){ + last_ = this->before_begin(); + } + if(x.last_ == this->before_begin()){ + x.last_ = x.before_begin(); + } + } + + static iterator iterator_to(void_pointer p) + { return basic_multiallocation_slist::iterator_to(p); } + + std::pair extract_data() + { + if(this->empty()){ + return std::pair(void_pointer(0), void_pointer(0)); + } + else{ + void_pointer p1 = slist_.extract_data(); + void_pointer p2 = void_pointer(&*last_); + last_ = iterator(); + return std::pair(p1, p2); + } + } +}; + +template +class basic_multiallocation_cached_counted_slist +{ +private: + MultiallocatorCachedSlist cached_slist_; + std::size_t size_; + + basic_multiallocation_cached_counted_slist(basic_multiallocation_cached_counted_slist &); + basic_multiallocation_cached_counted_slist &operator=(basic_multiallocation_cached_counted_slist &); + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_cached_counted_slist) + + typedef typename MultiallocatorCachedSlist::void_pointer void_pointer; + typedef typename MultiallocatorCachedSlist::iterator iterator; + + basic_multiallocation_cached_counted_slist() + : cached_slist_(), size_(0) + {} + + basic_multiallocation_cached_counted_slist(void_pointer p1, void_pointer p2, std::size_t n) + : cached_slist_(p1, p2), size_(n) + {} + + basic_multiallocation_cached_counted_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_counted_slist) other) + : cached_slist_(), size_(0) + { this->swap(other); } + + basic_multiallocation_cached_counted_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_counted_slist) other) + { + basic_multiallocation_cached_counted_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + basic_multiallocation_cached_counted_slist (MultiallocatorCachedSlist mem, std::size_t n) + : cached_slist_(boost::interprocess::move(mem)), size_(n) + {} + + bool empty() const + { return cached_slist_.empty(); } + + std::size_t size() const + { return size_; } + + iterator before_begin() const + { return cached_slist_.before_begin(); } + + iterator begin() const + { return cached_slist_.begin(); } + + iterator end() const + { return cached_slist_.end(); } + + iterator last() const + { return cached_slist_.last(); } + + void clear() + { + cached_slist_.clear(); + size_ = 0; + } + + iterator insert_after(iterator it, void_pointer m) + { + iterator ret = cached_slist_.insert_after(it, m); + ++size_; + return ret; + } + + void push_front(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void push_back(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void pop_front() + { + cached_slist_.pop_front(); + --size_; + } + + void *front() const + { return cached_slist_.front(); } + + void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x, iterator before_begin, iterator before_end) + { + std::size_t n = static_cast(std::distance(before_begin, before_end)); + this->splice_after(after_this, x, before_begin, before_end, n); + } + + void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x, iterator before_begin, iterator before_end, std::size_t n) + { + cached_slist_.splice_after(after_this, before_begin, before_end); + size_ += n; + x.size_ -= n; + } + + void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x) + { + cached_slist_.splice_after(after_this, x.before_begin(), x.last()); + size_ += x.size_; + x.size_ = 0; + } + + void swap(basic_multiallocation_cached_counted_slist &x) + { + cached_slist_.swap(x.cached_slist_); + using std::swap; + swap(size_, x.size_); + } + + static iterator iterator_to(void_pointer p) + { return MultiallocatorCachedSlist::iterator_to(p); } + + std::pair extract_data() + { + size_ = 0; + return cached_slist_.extract_data(); + } +}; + +template +struct cast_functor +{ + typedef typename containers_detail::add_reference::type result_type; + result_type operator()(char &ptr) const + { return *static_cast(static_cast(&ptr)); } +}; + + +template +class transform_multiallocation_chain +{ +private: + + MultiallocationChain holder_; + typedef typename MultiallocationChain::void_pointer void_pointer; + typedef typename boost::pointer_to_other + ::type pointer; + + transform_multiallocation_chain(transform_multiallocation_chain &); + transform_multiallocation_chain &operator=(transform_multiallocation_chain &); + + static pointer cast(void_pointer p) + { + return pointer(static_cast(containers_detail::get_pointer(p))); + } + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(transform_multiallocation_chain) + + typedef transform_iterator + < typename MultiallocationChain::iterator + , containers_detail::cast_functor > iterator; + + transform_multiallocation_chain(void_pointer p1, void_pointer p2, std::size_t n) + : holder_(p1, p2, n) + {} + + transform_multiallocation_chain() + : holder_() + {} + + transform_multiallocation_chain(BOOST_INTERPROCESS_RV_REF(transform_multiallocation_chain) other) + : holder_() + { this->swap(other); } + + transform_multiallocation_chain(BOOST_INTERPROCESS_RV_REF(MultiallocationChain) other) + : holder_(boost::interprocess::move(other)) + {} + + transform_multiallocation_chain& operator=(BOOST_INTERPROCESS_RV_REF(transform_multiallocation_chain) other) + { + transform_multiallocation_chain tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + void push_front(pointer mem) + { holder_.push_front(mem); } + + void swap(transform_multiallocation_chain &other_chain) + { holder_.swap(other_chain.holder_); } + /* + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { holder_.splice_after(after_this.base(), before_begin.base(), before_end.base()); } + */ + void splice_after(iterator after_this, transform_multiallocation_chain &x, iterator before_begin, iterator before_end, std::size_t n) + { holder_.splice_after(after_this.base(), x.holder_, before_begin.base(), before_end.base(), n); } + + void pop_front() + { holder_.pop_front(); } + + pointer front() const + { return cast(holder_.front()); } + + bool empty() const + { return holder_.empty(); } + + iterator before_begin() const + { return iterator(holder_.before_begin()); } + + iterator begin() const + { return iterator(holder_.begin()); } + + iterator end() const + { return iterator(holder_.end()); } + + iterator last() const + { return iterator(holder_.last()); } + + std::size_t size() const + { return holder_.size(); } + + void clear() + { holder_.clear(); } + + iterator insert_after(iterator it, pointer m) + { return iterator(holder_.insert_after(it.base(), m)); } + + static iterator iterator_to(pointer p) + { return iterator(MultiallocationChain::iterator_to(p)); } + + std::pair extract_data() + { return holder_.extract_data(); } + + MultiallocationChain extract_multiallocation_chain() + { + return MultiallocationChain(boost::interprocess::move(holder_)); + } +}; + +}}} + +// namespace containers_detail { +// namespace interprocess_container { +// namespace boost { + +#include + +#endif //BOOST_CONTAINERS_DETAIL_MULTIALLOCATION_CHAIN_HPP diff --git a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp b/include/boost/interprocess/containers/container/detail/node_alloc_holder.hpp similarity index 58% rename from include/boost/interprocess/containers/detail/node_alloc_holder.hpp rename to include/boost/interprocess/containers/container/detail/node_alloc_holder.hpp index 6e88903..6a5160d 100644 --- a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp +++ b/include/boost/interprocess/containers/container/detail/node_alloc_holder.hpp @@ -4,36 +4,137 @@ // 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. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_NODE_ALLOC_HPP_ -#define BOOST_INTERPROCESS_DETAIL_NODE_ALLOC_HPP_ +#ifndef BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_ +#define BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_ #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include #include #include +#include +#include + +#include +#include +#include +#include +#include + +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +#include +#endif + +#include + namespace boost { -namespace interprocess { -namespace detail { +namespace interprocess_container { +namespace containers_detail { + +//!A deleter for scoped_ptr that deallocates the memory +//!allocated for an object using a STL allocator. +template +struct scoped_deallocator +{ + typedef typename Allocator::pointer pointer; + typedef containers_detail::integral_constant::value> alloc_version; + typedef containers_detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + + private: + void priv_deallocate(allocator_v1) + { m_alloc.deallocate(m_ptr, 1); } + + void priv_deallocate(allocator_v2) + { m_alloc.deallocate_one(m_ptr); } + + scoped_deallocator(scoped_deallocator &); + scoped_deallocator& operator=(scoped_deallocator &); + + public: + + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(scoped_deallocator) + + pointer m_ptr; + Allocator& m_alloc; + + scoped_deallocator(pointer p, Allocator& a) + : m_ptr(p), m_alloc(a) + {} + + ~scoped_deallocator() + { if (m_ptr)priv_deallocate(alloc_version()); } + + scoped_deallocator(BOOST_INTERPROCESS_RV_REF(scoped_deallocator) o) + : m_ptr(o.m_ptr), m_alloc(o.m_alloc) + { o.release(); } + + pointer get() const + { return m_ptr; } + + void release() + { m_ptr = 0; } +}; + +template +class allocator_destroyer_and_chain_builder +{ + typedef typename A::value_type value_type; + typedef typename A::multiallocation_chain multiallocation_chain; + + A & a_; + multiallocation_chain &c_; + + public: + allocator_destroyer_and_chain_builder(A &a, multiallocation_chain &c) + : a_(a), c_(c) + {} + + void operator()(const typename A::pointer &p) + { + value_type *vp = containers_detail::get_pointer(p); + vp->~value_type(); + c_.push_front(vp); + } +}; + +template +class allocator_multialloc_chain_node_deallocator +{ + typedef typename A::value_type value_type; + typedef typename A::multiallocation_chain multiallocation_chain; + typedef allocator_destroyer_and_chain_builder chain_builder; + + A & a_; + multiallocation_chain c_; + + public: + allocator_multialloc_chain_node_deallocator(A &a) + : a_(a), c_() + {} + + chain_builder get_chain_builder() + { return chain_builder(a_, c_); } + + ~allocator_multialloc_chain_node_deallocator() + { + if(!c_.empty()) + a_.deallocate_individual(boost::interprocess::move(c_)); + } +}; + template struct node_compare @@ -66,18 +167,25 @@ struct node_alloc_holder typedef typename A::template rebind::other NodeAlloc; typedef A ValAlloc; typedef typename NodeAlloc::pointer NodePtr; - typedef detail::scoped_deallocator Deallocator; + typedef containers_detail::scoped_deallocator Deallocator; typedef typename NodeAlloc::size_type size_type; typedef typename NodeAlloc::difference_type difference_type; - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant allocator_v2; - typedef detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + typedef containers_detail::integral_constant::value> alloc_version; typedef typename ICont::iterator icont_iterator; typedef typename ICont::const_iterator icont_citerator; typedef allocator_destroyer Destroyer; + private: + node_alloc_holder(node_alloc_holder&); + node_alloc_holder & operator=(node_alloc_holder&); + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(node_alloc_holder) + node_alloc_holder(const ValAlloc &a) : members_(a) {} @@ -86,32 +194,19 @@ struct node_alloc_holder : members_(other.node_alloc()) {} - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - node_alloc_holder(detail::moved_object other) - : members_(detail::move_impl(other.get().node_alloc())) - { this->swap(other.get()); } - #else - node_alloc_holder(node_alloc_holder &&other) - : members_(detail::move_impl(other.node_alloc())) + node_alloc_holder(BOOST_INTERPROCESS_RV_REF(node_alloc_holder) other) + : members_(boost::interprocess::move(other.node_alloc())) { this->swap(other); } - #endif template node_alloc_holder(const ValAlloc &a, const Pred &c) : members_(a, typename ICont::value_compare(c)) {} - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - node_alloc_holder(detail::moved_object a, const Pred &c) - : members_(a.get(), typename ICont::value_compare(c)) - {} - #else - template - node_alloc_holder(ValAlloc &&a, const Pred &c) + node_alloc_holder(BOOST_INTERPROCESS_RV_REF(ValAlloc) a, const Pred &c) : members_(a, typename ICont::value_compare(c)) {} - #endif template node_alloc_holder(const node_alloc_holder &other, const Pred &c) @@ -142,46 +237,27 @@ struct node_alloc_holder void deallocate_one(NodePtr p, allocator_v2) { this->node_alloc().deallocate_one(p); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - static void construct(const NodePtr &ptr, detail::moved_object > value) - { - typedef typename Node::hook_type hook_type; - typedef typename Node::value_type::first_type first_type; - typedef typename Node::value_type::second_type second_type; - Node *nodeptr = detail::get_pointer(ptr); - - //Hook constructor does not throw - new(static_cast(nodeptr))hook_type(); - //Now construct pair members_holder - value_type *valueptr = &nodeptr->get_data(); - new((void*)&valueptr->first) first_type(detail::move_impl(value.get().first)); - BOOST_TRY{ - new((void*)&valueptr->second) second_type(detail::move_impl(value.get().second)); - } - BOOST_CATCH(...){ - valueptr->first.~first_type(); - static_cast(nodeptr)->~hook_type(); - BOOST_RETHROW - } - BOOST_CATCH_END - } - #else - template - static void construct(const NodePtr &ptr, std::pair &&value) + static void construct(const NodePtr &ptr, + #ifdef BOOST_HAS_RVALUE_REFS + std::pair && + #else + boost::interprocess::rv > & + #endif + value) { typedef typename Node::hook_type hook_type; typedef typename Node::value_type::first_type first_type; typedef typename Node::value_type::second_type second_type; - Node *nodeptr = detail::get_pointer(ptr); + Node *nodeptr = containers_detail::get_pointer(ptr); //Hook constructor does not throw new(static_cast(nodeptr))hook_type(); //Now construct pair members_holder value_type *valueptr = &nodeptr->get_data(); - new((void*)&valueptr->first) first_type(detail::move_impl(value.first)); + new((void*)&valueptr->first) first_type(boost::interprocess::move(value.first)); BOOST_TRY{ - new((void*)&valueptr->second) second_type(detail::move_impl(value.second)); + new((void*)&valueptr->second) second_type(boost::interprocess::move(value.second)); } BOOST_CATCH(...){ valueptr->first.~first_type(); @@ -190,44 +266,35 @@ struct node_alloc_holder } BOOST_CATCH_END } - #endif static void destroy(const NodePtr &ptr) - { detail::get_pointer(ptr)->~Node(); } + { containers_detail::get_pointer(ptr)->~Node(); } - - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - Deallocator - #else - move_return - #endif - create_node_and_deallocator() + Deallocator create_node_and_deallocator() { - NodePtr p = this->allocate_one(); - Deallocator node_deallocator(p, this->node_alloc()); - return node_deallocator; + return Deallocator(this->allocate_one(), this->node_alloc()); } - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING template static void construct(const NodePtr &ptr, Args &&...args) - { new((void*)detail::get_pointer(ptr)) Node(detail::forward_impl(args)...); } + { new((void*)containers_detail::get_pointer(ptr)) Node(boost::interprocess::forward(args)...); } template NodePtr create_node(Args &&...args) { NodePtr p = this->allocate_one(); Deallocator node_deallocator(p, this->node_alloc()); - self_t::construct(p, detail::forward_impl(args)...); + self_t::construct(p, boost::interprocess::forward(args)...); node_deallocator.release(); return (p); } - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING static void construct(const NodePtr &ptr) - { new((void*)detail::get_pointer(ptr)) Node(); } + { new((void*)containers_detail::get_pointer(ptr)) Node(); } NodePtr create_node() { @@ -240,37 +307,37 @@ struct node_alloc_holder #define BOOST_PP_LOCAL_MACRO(n) \ template \ - void construct(const NodePtr &ptr, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + void construct(const NodePtr &ptr, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - new((void*)detail::get_pointer(ptr)) \ - Node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + new((void*)containers_detail::get_pointer(ptr)) \ + Node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ } \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() #define BOOST_PP_LOCAL_MACRO(n) \ template \ - NodePtr create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + NodePtr create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ NodePtr p = this->allocate_one(); \ Deallocator node_deallocator(p, this->node_alloc()); \ - self_t::construct(p, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + self_t::construct(p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ node_deallocator.release(); \ return (p); \ } \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING template NodePtr create_node_from_it(It it) { NodePtr p = this->allocate_one(); Deallocator node_deallocator(p, this->node_alloc()); - ::boost::interprocess::construct_in_place(detail::get_pointer(p), it); + ::boost::interprocess_container::construct_in_place(containers_detail::get_pointer(p), it); node_deallocator.release(); return (p); } @@ -287,7 +354,7 @@ struct node_alloc_holder NodeAlloc& other_alloc = x.node_alloc(); if (this_alloc != other_alloc){ - detail::do_swap(this_alloc, other_alloc); + containers_detail::do_swap(this_alloc, other_alloc); } this->icont().swap(x.icont()); @@ -298,19 +365,19 @@ struct node_alloc_holder (FwdIterator beg, difference_type n, Inserter inserter) { if(n){ - typedef typename NodeAlloc::multiallocation_iterator multiallocation_iterator; + typedef typename NodeAlloc::multiallocation_chain multiallocation_chain; //Try to allocate memory in a single block - multiallocation_iterator itbeg = - this->node_alloc().allocate_individual(n), itend, itold; + multiallocation_chain mem(this->node_alloc().allocate_individual(n)); int constructed = 0; Node *p = 0; BOOST_TRY{ for(difference_type i = 0; i < n; ++i, ++beg, --constructed){ - p = &*itbeg; - ++itbeg; + p = containers_detail::get_pointer(mem.front()); + mem.pop_front(); //This can throw - boost::interprocess::construct_in_place(p, beg); + constructed = 0; + boost::interprocess_container::construct_in_place(p, beg); ++constructed; //This can throw in some containers (predicate might throw) inserter(*p); @@ -320,7 +387,7 @@ struct node_alloc_holder if(constructed){ this->destroy(p); } - this->node_alloc().deallocate_many(itbeg); + this->node_alloc().deallocate_individual(boost::interprocess::move(mem)); BOOST_RETHROW } BOOST_CATCH_END @@ -334,8 +401,12 @@ struct node_alloc_holder void clear(allocator_v2) { - allocator_multialloc_chain_node_deallocator chain_holder(this->node_alloc()); - this->icont().clear_and_dispose(chain_holder.get_chain_builder()); + typename NodeAlloc::multiallocation_chain chain; + allocator_destroyer_and_chain_builder builder(this->node_alloc(), chain); + this->icont().clear_and_dispose(builder); + BOOST_STATIC_ASSERT((boost::interprocess::is_movable::value == true)); + if(!chain.empty()) + this->node_alloc().deallocate_individual(boost::interprocess::move(chain)); } icont_iterator erase_range(icont_iterator first, icont_iterator last, allocator_v1) @@ -419,10 +490,10 @@ struct node_alloc_holder { return static_cast(this->members_); } }; -} //namespace detail { -} //namespace interprocess { +} //namespace containers_detail { +} //namespace interprocess_container { } //namespace boost { -#include +#include -#endif // BOOST_INTERPROCESS_DETAIL_NODE_ALLOC_HPP_ +#endif // BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_ diff --git a/include/boost/interprocess/containers/container/detail/pair.hpp b/include/boost/interprocess/containers/container/detail/pair.hpp new file mode 100644 index 0000000..72f4ab0 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/pair.hpp @@ -0,0 +1,189 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2009. +// +// 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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_CONTAINERS_DETAIL_PAIR_HPP +#define BOOST_CONTAINERS_CONTAINERS_DETAIL_PAIR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include + +#include //std::pair + +#include + +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +#include +#endif + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +struct pair +{ + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(pair) + + typedef T1 first_type; + typedef T2 second_type; + + T1 first; + T2 second; + + //std::pair compatibility + template + pair(const std::pair& p) + : first(p.first), second(p.second) + {} + + //To resolve ambiguity with the variadic constructor of 1 argument + //and the previous constructor + pair(std::pair& x) + : first(x.first), second(x.second) + {} + + template + pair(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(std::pair, D, S) p) + : first(boost::interprocess::move(p.first)), second(boost::interprocess::move(p.second)) + {} + + pair() + : first(), second() + {} + + pair(const pair& x) + : first(x.first), second(x.second) + {} + + //To resolve ambiguity with the variadic constructor of 1 argument + //and the copy constructor + pair(pair& x) + : first(x.first), second(x.second) + {} + + pair(BOOST_INTERPROCESS_RV_REF(pair) p) + : first(boost::interprocess::move(p.first)), second(boost::interprocess::move(p.second)) + {} + + template + pair(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(pair, D, S) p) + : first(boost::interprocess::move(p.first)), second(boost::interprocess::move(p.second)) + {} + + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + template + pair(U &&u, Args &&... args) + : first(boost::interprocess::forward(u)) + , second(boost::interprocess::forward(args)...) + {} + + #else + + template + pair( BOOST_CONTAINERS_PARAM(U, u) + #ifndef BOOST_HAS_RVALUE_REFS + , typename containers_detail::disable_if + < containers_detail::is_same > >::type* = 0 + #endif + ) + : first(boost::interprocess::forward(const_cast(u))) + {} + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + pair(BOOST_CONTAINERS_PARAM(U, u) \ + ,BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : first(boost::interprocess::forward(const_cast(u))) \ + , second(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ + {} \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + #endif + + pair& operator=(BOOST_INTERPROCESS_RV_REF(pair) p) + { + first = boost::interprocess::move(p.first); + second = boost::interprocess::move(p.second); + return *this; + } + + pair& operator=(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(std::pair, T1, T2) p) + { + first = boost::interprocess::move(p.first); + second = boost::interprocess::move(p.second); + return *this; + } + + template + pair& operator=(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(std::pair, D, S) p) + { + first = boost::interprocess::move(p.first); + second = boost::interprocess::move(p.second); + return *this; + } + + void swap(pair& p) + { std::swap(*this, p); } +}; + +template +inline bool operator==(const pair& x, const pair& y) +{ return static_cast(x.first == y.first && x.second == y.second); } + +template +inline bool operator< (const pair& x, const pair& y) +{ return static_cast(x.first < y.first || + (!(y.first < x.first) && x.second < y.second)); } + +template +inline bool operator!=(const pair& x, const pair& y) +{ return static_cast(!(x == y)); } + +template +inline bool operator> (const pair& x, const pair& y) +{ return y < x; } + +template +inline bool operator>=(const pair& x, const pair& y) +{ return static_cast(!(x < y)); } + +template +inline bool operator<=(const pair& x, const pair& y) +{ return static_cast(!(y < x)); } + +template +inline pair make_pair(T1 x, T2 y) +{ return pair(x, y); } + +template +inline void swap(pair& x, pair& y) +{ + swap(x.first, y.first); + swap(x.second, y.second); +} + +} //namespace containers_detail { +} //namespace interprocess_container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_PAIR_HPP diff --git a/include/boost/interprocess/containers/container/detail/preprocessor.hpp b/include/boost/interprocess/containers/container/detail/preprocessor.hpp new file mode 100644 index 0000000..ecd143d --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/preprocessor.hpp @@ -0,0 +1,101 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_PREPROCESSOR_HPP +#define BOOST_CONTAINERS_DETAIL_PREPROCESSOR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING +#error "This file is not needed when perfect forwarding is available" +#endif + +#include +#include +#include +#include +#include + +#define BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS 10 + +//Note: +//We define template parameters as const references to +//be able to bind temporaries. After that we will un-const them. +//This cast is ugly but it is necessary until "perfect forwarding" +//is achieved in C++0x. Meanwhile, if we want to be able to +//bind rvalues with non-const references, we have to be ugly +#ifdef BOOST_HAS_RVALUE_REFS + #define BOOST_CONTAINERS_PP_PARAM_LIST(z, n, data) \ + BOOST_PP_CAT(P, n) && BOOST_PP_CAT(p, n) \ + //! +#else + #define BOOST_CONTAINERS_PP_PARAM_LIST(z, n, data) \ + const BOOST_PP_CAT(P, n) & BOOST_PP_CAT(p, n) \ + //! +#endif + +#ifdef BOOST_HAS_RVALUE_REFS + #define BOOST_CONTAINERS_PARAM(U, u) \ + U && u \ + //! +#else + #define BOOST_CONTAINERS_PARAM(U, u) \ + const U & u \ + //! +#endif + +#ifdef BOOST_HAS_RVALUE_REFS +#define BOOST_CONTAINERS_AUX_PARAM_INIT(z, n, data) \ + BOOST_PP_CAT(m_p, n) (BOOST_PP_CAT(p, n)) \ +//! +#else +#define BOOST_CONTAINERS_AUX_PARAM_INIT(z, n, data) \ + BOOST_PP_CAT(m_p, n) (const_cast(BOOST_PP_CAT(p, n))) \ +//! +#endif + +#define BOOST_CONTAINERS_AUX_PARAM_INC(z, n, data) \ + BOOST_PP_CAT(++m_p, n) \ +//! + +#ifdef BOOST_HAS_RVALUE_REFS +#define BOOST_CONTAINERS_AUX_PARAM_DEFINE(z, n, data) \ + BOOST_PP_CAT(P, n) && BOOST_PP_CAT(m_p, n); \ +//! +#else +#define BOOST_CONTAINERS_AUX_PARAM_DEFINE(z, n, data) \ + BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \ +//! +#endif + +#define BOOST_CONTAINERS_PP_PARAM_FORWARD(z, n, data) \ +boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \ +//! + +#define BOOST_CONTAINERS_PP_MEMBER_FORWARD(z, n, data) \ +boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \ +//! + +#define BOOST_CONTAINERS_PP_MEMBER_IT_FORWARD(z, n, data) \ +BOOST_PP_CAT(*m_p, n) \ +//! + +#include + +#else +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING +#error "This file is not needed when perfect forwarding is available" +#endif +#endif //#ifndef BOOST_CONTAINERS_DETAIL_PREPROCESSOR_HPP diff --git a/include/boost/interprocess/containers/container/detail/transform_iterator.hpp b/include/boost/interprocess/containers/container/detail/transform_iterator.hpp new file mode 100644 index 0000000..8610dcc --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/transform_iterator.hpp @@ -0,0 +1,176 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// 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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_TRANSFORM_ITERATORS_HPP +#define BOOST_CONTAINERS_DETAIL_TRANSFORM_ITERATORS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include + +namespace boost { +namespace interprocess_container { + +template +struct operator_arrow_proxy +{ + operator_arrow_proxy(const PseudoReference &px) + : m_value(px) + {} + + PseudoReference* operator->() const { return &m_value; } + // This function is needed for MWCW and BCC, which won't call operator-> + // again automatically per 13.3.1.2 para 8 +// operator T*() const { return &m_value; } + mutable PseudoReference m_value; +}; + +template +struct operator_arrow_proxy +{ + operator_arrow_proxy(T &px) + : m_value(px) + {} + + T* operator->() const { return &m_value; } + // This function is needed for MWCW and BCC, which won't call operator-> + // again automatically per 13.3.1.2 para 8 +// operator T*() const { return &m_value; } + mutable T &m_value; +}; + +template +class transform_iterator + : public UnaryFunction + , public std::iterator + < typename Iterator::iterator_category + , typename containers_detail::remove_reference::type + , typename Iterator::difference_type + , operator_arrow_proxy + , typename UnaryFunction::result_type> +{ + public: + explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction()) + : UnaryFunction(f), m_it(it) + {} + + explicit transform_iterator() + : UnaryFunction(), m_it() + {} + + //Constructors + transform_iterator& operator++() + { increment(); return *this; } + + transform_iterator operator++(int) + { + transform_iterator result (*this); + increment(); + return result; + } + + friend bool operator== (const transform_iterator& i, const transform_iterator& i2) + { return i.equal(i2); } + + friend bool operator!= (const transform_iterator& i, const transform_iterator& i2) + { return !(i == i2); } + +/* + friend bool operator> (const transform_iterator& i, const transform_iterator& i2) + { return i2 < i; } + + friend bool operator<= (const transform_iterator& i, const transform_iterator& i2) + { return !(i > i2); } + + friend bool operator>= (const transform_iterator& i, const transform_iterator& i2) + { return !(i < i2); } +*/ + friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + transform_iterator& operator+=(typename Iterator::difference_type off) + { this->advance(off); return *this; } + + transform_iterator operator+(typename Iterator::difference_type off) const + { + transform_iterator other(*this); + other.advance(off); + return other; + } + + friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right) + { return right + off; } + + transform_iterator& operator-=(typename Iterator::difference_type off) + { this->advance(-off); return *this; } + + transform_iterator operator-(typename Iterator::difference_type off) const + { return *this + (-off); } + + typename UnaryFunction::result_type operator*() const + { return dereference(); } + + operator_arrow_proxy + operator->() const + { return operator_arrow_proxy(dereference()); } + + Iterator & base() + { return m_it; } + + const Iterator & base() const + { return m_it; } + + private: + Iterator m_it; + + void increment() + { ++m_it; } + + void decrement() + { --m_it; } + + bool equal(const transform_iterator &other) const + { return m_it == other.m_it; } + + bool less(const transform_iterator &other) const + { return other.m_it < m_it; } + + typename UnaryFunction::result_type dereference() const + { return UnaryFunction::operator()(*m_it); } + + void advance(typename Iterator::difference_type n) + { std::advance(m_it, n); } + + typename Iterator::difference_type distance_to(const transform_iterator &other)const + { return std::distance(other.m_it, m_it); } +}; + +template +transform_iterator +make_transform_iterator(Iterator it, UnaryFunc fun) +{ + return transform_iterator(it, fun); +} + +} //namespace interprocess_container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_TRANSFORM_ITERATORS_HPP diff --git a/include/boost/interprocess/containers/detail/tree.hpp b/include/boost/interprocess/containers/container/detail/tree.hpp similarity index 80% rename from include/boost/interprocess/containers/detail/tree.hpp rename to include/boost/interprocess/containers/container/detail/tree.hpp index 408ce3d..77e77eb 100644 --- a/include/boost/interprocess/containers/detail/tree.hpp +++ b/include/boost/interprocess/containers/container/detail/tree.hpp @@ -4,7 +4,7 @@ // 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. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// // @@ -39,21 +39,25 @@ * purpose. It is provided "as is" without express or implied warranty. * */ -#ifndef BOOST_INTERPROCESS_TREE_HPP -#define BOOST_INTERPROCESS_TREE_HPP +#ifndef BOOST_CONTAINERS_TREE_HPP +#define BOOST_CONTAINERS_TREE_HPP -#include -#include +#include +#include #include -#include -#include +#include #include #include -#include #include -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -#include + +#include +#include +#include +#include +#include +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +#include #endif #include //std::pair @@ -61,8 +65,8 @@ #include namespace boost { -namespace interprocess { -namespace detail { +namespace interprocess_container { +namespace containers_detail { template struct value_compare_impl @@ -91,10 +95,10 @@ struct value_compare_impl template struct rbtree_hook { - typedef typename bi::make_set_base_hook - < bi::void_pointer - , bi::link_mode - , bi::optimize_size + typedef typename containers_detail::bi::make_set_base_hook + < containers_detail::bi::void_pointer + , containers_detail::bi::link_mode + , containers_detail::bi::optimize_size >::type type; }; @@ -107,7 +111,7 @@ struct rbtree_type template struct rbtree_type< std::pair > { - typedef detail::pair type; + typedef pair type; }; template @@ -121,28 +125,32 @@ struct rbtree_node typedef rbtree_node node_type; - #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING + #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING rbtree_node() : m_data() {} + rbtree_node(const rbtree_node &other) + : m_data(other.m_data) + {} + #define BOOST_PP_LOCAL_MACRO(n) \ template \ - rbtree_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - : m_data(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)) \ + rbtree_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : m_data(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ {} \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() - #else //#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING + #else //#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING template rbtree_node(Args &&...args) - : m_data(detail::forward_impl(args)...) + : m_data(boost::interprocess::forward(args)...) {} - #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING + #endif//#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING rbtree_node &operator=(const rbtree_node &other) { do_assign(other.m_data); return *this; } @@ -170,7 +178,7 @@ struct rbtree_node } template - void do_assign(const detail::pair &p) + void do_assign(const pair &p) { const_cast(m_data.first) = p.first; m_data.second = p.second; @@ -182,64 +190,58 @@ struct rbtree_node public: template - - static void construct(node_type *ptr - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) - , const Convertible &value) - #else - , Convertible &&value) - #endif - { new(ptr) node_type(detail::forward_impl(value)); } + static void construct(node_type *ptr, BOOST_INTERPROCESS_FWD_REF(Convertible) convertible) + { new(ptr) node_type(boost::interprocess::forward(convertible)); } }; -}//namespace detail { -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) || !defined(BOOST_INTERPROCESS_RVALUE_PAIR) +}//namespace containers_detail { +#if !defined(BOOST_HAS_RVALUE_REFS) template struct has_own_construct_from_it - < boost::interprocess::detail::rbtree_node > + < boost::interprocess_container::containers_detail::rbtree_node > { static const bool value = true; }; #endif -namespace detail { +namespace containers_detail { template struct intrusive_rbtree_type { typedef typename A::value_type value_type; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type void_pointer; - typedef typename detail::rbtree_node + typedef typename containers_detail::rbtree_node node_type; typedef node_compare node_compare_type; - typedef typename bi::make_rbtree + typedef typename containers_detail::bi::make_rbtree - ,bi::base_hook::type> - ,bi::constant_time_size - ,bi::size_type + ,containers_detail::bi::compare + ,containers_detail::bi::base_hook::type> + ,containers_detail::bi::constant_time_size + ,containers_detail::bi::size_type >::type container_type; typedef container_type type ; }; -} //namespace detail { +} //namespace containers_detail { -namespace detail { +namespace containers_detail { template class rbtree - : protected detail::node_alloc_holder - >::type > { - typedef typename detail::intrusive_rbtree_type + typedef typename containers_detail::intrusive_rbtree_type >::type Icont; - typedef detail::node_alloc_holder AllocHolder; + typedef containers_detail::node_alloc_holder AllocHolder; typedef typename AllocHolder::NodePtr NodePtr; typedef rbtree < Key, Value, KeyOfValue , KeyCompare, A> ThisType; @@ -248,7 +250,7 @@ class rbtree typedef typename AllocHolder::Node Node; typedef typename Icont::iterator iiterator; typedef typename Icont::const_iterator iconst_iterator; - typedef detail::allocator_destroyer Destroyer; + typedef containers_detail::allocator_destroyer Destroyer; typedef typename AllocHolder::allocator_v1 allocator_v1; typedef typename AllocHolder::allocator_v2 allocator_v2; typedef typename AllocHolder::alloc_version alloc_version; @@ -293,6 +295,8 @@ class rbtree }; public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(rbtree) + typedef Key key_type; typedef Value value_type; typedef A allocator_type; @@ -450,15 +454,9 @@ class rbtree (x.icont(), typename AllocHolder::cloner(*this), Destroyer(this->node_alloc())); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - rbtree(detail::moved_object x) - : AllocHolder(x.get(), x.get().key_comp()) - { this->swap(x.get()); } - #else - rbtree(rbtree &&x) + rbtree(BOOST_INTERPROCESS_RV_REF(rbtree) x) : AllocHolder(x, x.key_comp()) { this->swap(x); } - #endif ~rbtree() {} //AllocHolder clears the tree @@ -488,13 +486,8 @@ class rbtree return *this; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - rbtree& operator=(detail::moved_object mx) - { this->clear(); this->swap(mx.get()); return *this; } - #else - rbtree& operator=(rbtree &&mx) + rbtree& operator=(BOOST_INTERPROCESS_RV_REF(rbtree) mx) { this->clear(); this->swap(mx); return *this; } - #endif public: // accessors: @@ -583,14 +576,6 @@ class rbtree void swap(ThisType& x) { AllocHolder::swap(x); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(detail::moved_object mt) - { this->swap(mt.get()); } - #else - void swap(rbtree &&mt) - { this->swap(mt); } - #endif - public: typedef typename Icont::insert_commit_data insert_commit_data; @@ -619,25 +604,14 @@ class rbtree return iterator(it); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template iterator insert_unique_commit - (detail::moved_object mv, insert_commit_data &data) + (BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv, insert_commit_data &data) { - NodePtr tmp = AllocHolder::create_node(mv); + NodePtr tmp = AllocHolder::create_node(boost::interprocess::forward(mv)); iiterator it(this->icont().insert_unique_commit(*tmp, data)); return iterator(it); } - #else - template - iterator insert_unique_commit - (MovableConvertible && mv, insert_commit_data &data) - { - NodePtr tmp = AllocHolder::create_node(detail::forward_impl(mv)); - iiterator it(this->icont().insert_unique_commit(*tmp, data)); - return iterator(it); - } - #endif std::pair insert_unique(const value_type& v) { @@ -650,21 +624,8 @@ class rbtree (this->insert_unique_commit(v, data), true); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - std::pair insert_unique(detail::moved_object mv) - { - insert_commit_data data; - std::pair ret = - this->insert_unique_check(KeyOfValue()(mv.get()), data); - if(!ret.second) - return ret; - return std::pair - (this->insert_unique_commit(mv, data), true); - } - #else - template - std::pair insert_unique(MovableConvertible &&mv) + std::pair insert_unique(BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv) { insert_commit_data data; std::pair ret = @@ -672,9 +633,8 @@ class rbtree if(!ret.second) return ret; return std::pair - (this->insert_unique_commit(detail::forward_impl(mv), data), true); + (this->insert_unique_commit(boost::interprocess::forward(mv), data), true); } - #endif private: iterator emplace_unique_impl(NodePtr p) @@ -705,31 +665,31 @@ class rbtree public: - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING template iterator emplace_unique(Args&&... args) - { return this->emplace_unique_impl(AllocHolder::create_node(detail::forward_impl(args)...)); } + { return this->emplace_unique_impl(AllocHolder::create_node(boost::interprocess::forward(args)...)); } template iterator emplace_hint_unique(const_iterator hint, Args&&... args) - { return this->emplace_unique_hint_impl(hint, AllocHolder::create_node(detail::forward_impl(args)...)); } + { return this->emplace_unique_hint_impl(hint, AllocHolder::create_node(boost::interprocess::forward(args)...)); } template iterator emplace_equal(Args&&... args) { - NodePtr p(AllocHolder::create_node(detail::forward_impl(args)...)); + NodePtr p(AllocHolder::create_node(boost::interprocess::forward(args)...)); return iterator(this->icont().insert_equal(this->icont().end(), *p)); } template iterator emplace_hint_equal(const_iterator hint, Args&&... args) { - NodePtr p(AllocHolder::create_node(detail::forward_impl(args)...)); + NodePtr p(AllocHolder::create_node(boost::interprocess::forward(args)...)); return iterator(this->icont().insert_equal(hint.get(), *p)); } - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING iterator emplace_unique() { return this->emplace_unique_impl(AllocHolder::create_node()); } @@ -751,37 +711,37 @@ class rbtree #define BOOST_PP_LOCAL_MACRO(n) \ template \ - iterator emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ return this->emplace_unique_impl \ - (AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ + (AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ } \ \ template \ - iterator emplace_hint_unique(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_hint_unique(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ return this->emplace_unique_hint_impl \ - (hint, AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ + (hint, AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ } \ \ template \ - iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ + NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ return iterator(this->icont().insert_equal(this->icont().end(), *p)); \ } \ \ template \ - iterator emplace_hint_equal(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_hint_equal(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ + NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ return iterator(this->icont().insert_equal(hint.get(), *p)); \ } \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING iterator insert_unique(const_iterator hint, const value_type& v) { @@ -793,30 +753,16 @@ class rbtree return this->insert_unique_commit(v, data); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - iterator insert_unique(const_iterator hint, detail::moved_object mv) - { - insert_commit_data data; - std::pair ret = - this->insert_unique_check(hint, KeyOfValue()(mv.get()), data); - if(!ret.second) - return ret.first; - return this->insert_unique_commit(mv, data); - } - #else - template - iterator insert_unique - (const_iterator hint, MovableConvertible &&mv) + iterator insert_unique(const_iterator hint, BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv) { insert_commit_data data; std::pair ret = this->insert_unique_check(hint, KeyOfValue()(mv), data); if(!ret.second) return ret.first; - return this->insert_unique_commit(detail::forward_impl(mv), data); + return this->insert_unique_commit(boost::interprocess::forward(mv), data); } - #endif template void insert_unique(InputIterator first, InputIterator last) @@ -840,21 +786,12 @@ class rbtree return iterator(this->icont().insert_equal(this->icont().end(), *p)); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - iterator insert_equal(detail::moved_object mv) + iterator insert_equal(BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv) { - NodePtr p(AllocHolder::create_node(mv)); + NodePtr p(AllocHolder::create_node(boost::interprocess::forward(mv))); return iterator(this->icont().insert_equal(this->icont().end(), *p)); } - #else - template - iterator insert_equal(MovableConvertible &&mv) - { - NodePtr p(AllocHolder::create_node(detail::forward_impl(mv))); - return iterator(this->icont().insert_equal(this->icont().end(), *p)); - } - #endif iterator insert_equal(const_iterator hint, const value_type& v) { @@ -862,21 +799,12 @@ class rbtree return iterator(this->icont().insert_equal(hint.get(), *p)); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - iterator insert_equal(const_iterator hint, detail::moved_object mv) + iterator insert_equal(const_iterator hint, BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv) { - NodePtr p(AllocHolder::create_node(mv)); + NodePtr p(AllocHolder::create_node(boost::interprocess::forward(mv))); return iterator(this->icont().insert_equal(hint.get(), *p)); } - #else - template - iterator insert_equal(const_iterator hint, MovableConvertible &&mv) - { - NodePtr p(AllocHolder::create_node(detail::move_impl(mv))); - return iterator(this->icont().insert_equal(hint.get(), *p)); - } - #endif template void insert_equal(InputIterator first, InputIterator last) @@ -1066,46 +994,25 @@ swap(rbtree& x, x.swap(y); } -} //namespace detail { +} //namespace containers_detail { +} //namespace interprocess_container { -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -/* -template -struct is_movable > -{ - enum { value = true }; -}; -*/ +namespace interprocess { //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations template -struct has_trivial_destructor_after_move > +class C, class A> +struct has_trivial_destructor_after_move + > { - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; }; +} //namespace interprocess { -} //namespace interprocess { } //namespace boost { -#include +#include -#endif //BOOST_INTERPROCESS_TREE_HPP +#endif //BOOST_CONTAINERS_TREE_HPP diff --git a/include/boost/interprocess/containers/container/detail/type_traits.hpp b/include/boost/interprocess/containers/container/detail/type_traits.hpp new file mode 100644 index 0000000..cb103d9 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/type_traits.hpp @@ -0,0 +1,166 @@ +////////////////////////////////////////////////////////////////////////////// +// (C) Copyright John Maddock 2000. +// (C) Copyright Ion Gaztanaga 2005-2008. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +// The alignment_of implementation comes from John Maddock's boost::alignment_of code +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_TYPE_TRAITS_HPP +#define BOOST_CONTAINERS_CONTAINER_DETAIL_TYPE_TRAITS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +struct nat{}; + +//boost::alignment_of yields to 10K lines of preprocessed code, so we +//need an alternative +template struct alignment_of; + +template +struct alignment_of_hack +{ + char c; + T t; + alignment_of_hack(); +}; + +template +struct alignment_logic +{ + enum{ value = A < S ? A : S }; +}; + +template< typename T > +struct alignment_of +{ + enum{ value = alignment_logic + < sizeof(alignment_of_hack) - sizeof(T) + , sizeof(T)>::value }; +}; + +//This is not standard, but should work with all compilers +union max_align +{ + char char_; + short short_; + int int_; + long long_; + #ifdef BOOST_HAS_LONG_LONG + long long long_long_; + #endif + float float_; + double double_; + long double long_double_; + void * void_ptr_; +}; + +template +struct remove_reference +{ + typedef T type; +}; + +template +struct remove_reference +{ + typedef T type; +}; + +template +struct is_reference +{ + enum { value = false }; +}; + +template +struct is_reference +{ + enum { value = true }; +}; + +template +struct is_pointer +{ + enum { value = false }; +}; + +template +struct is_pointer +{ + enum { value = true }; +}; + +template +struct add_reference +{ + typedef T& type; +}; + +template +struct add_reference +{ + typedef T& type; +}; + +template<> +struct add_reference +{ + typedef nat &type; +}; + +template<> +struct add_reference +{ + typedef const nat &type; +}; + +template +struct add_const_reference +{ typedef const T &type; }; + +template +struct add_const_reference +{ typedef T& type; }; + +template +struct is_same +{ + typedef char yes_type; + struct no_type + { + char padding[8]; + }; + + template + static yes_type is_same_tester(V*, V*); + static no_type is_same_tester(...); + + static T *t; + static U *u; + + static const bool value = sizeof(yes_type) == sizeof(is_same_tester(t,u)); +}; + +} // namespace containers_detail +} //namespace interprocess_container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_TYPE_TRAITS_HPP + +#include + diff --git a/include/boost/interprocess/containers/container/detail/utilities.hpp b/include/boost/interprocess/containers/container/detail/utilities.hpp new file mode 100644 index 0000000..5dad0dc --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/utilities.hpp @@ -0,0 +1,95 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_UTILITIES_HPP +#define BOOST_CONTAINERS_DETAIL_UTILITIES_HPP + +#include +#include +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +SizeType + get_next_capacity(const SizeType max_size + ,const SizeType capacity + ,const SizeType n) +{ +// if (n > max_size - capacity) +// throw std::length_error("get_next_capacity"); + + const SizeType m3 = max_size/3; + + if (capacity < m3) + return capacity + max_value(3*(capacity+1)/5, n); + + if (capacity < m3*2) + return capacity + max_value((capacity+1)/2, n); + + return max_size; +} + +template +const T &max_value(const T &a, const T &b) +{ return a > b ? a : b; } + +template +const T &min_value(const T &a, const T &b) +{ return a < b ? a : b; } + +template +struct smart_ptr_type +{ + typedef typename SmartPtr::value_type value_type; + typedef value_type *pointer; + static pointer get (const SmartPtr &smartptr) + { return smartptr.get();} +}; + +template +struct smart_ptr_type +{ + typedef T value_type; + typedef value_type *pointer; + static pointer get (pointer ptr) + { return ptr;} +}; + +//!Overload for smart pointers to avoid ADL problems with get_pointer +template +inline typename smart_ptr_type::pointer +get_pointer(const Ptr &ptr) +{ return smart_ptr_type::get(ptr); } + +//!To avoid ADL problems with swap +template +inline void do_swap(T& x, T& y) +{ + using std::swap; + swap(x, y); +} + +template +struct ct_rounded_size +{ + enum { value = ((OrigSize-1)/RoundTo+1)*RoundTo }; +}; + +} //namespace containers_detail { +} //namespace interprocess_container { +} //namespace boost { + + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_UTILITIES_HPP diff --git a/include/boost/interprocess/containers/container/detail/value_init.hpp b/include/boost/interprocess/containers/container/detail/value_init.hpp new file mode 100644 index 0000000..4918379 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/value_init.hpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2009. +// +// 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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_VALUE_INIT_HPP +#define BOOST_CONTAINERS_DETAIL_VALUE_INIT_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +struct value_init +{ + value_init() + : m_t() + {} + + T m_t; +}; + +} //namespace containers_detail { +} //namespace interprocess_container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_VALUE_INIT_HPP diff --git a/include/boost/interprocess/containers/container/detail/variadic_templates_tools.hpp b/include/boost/interprocess/containers/container/detail/variadic_templates_tools.hpp new file mode 100644 index 0000000..ba46e85 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/variadic_templates_tools.hpp @@ -0,0 +1,153 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP +#define BOOST_CONTAINERS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include //std::size_t + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +class tuple; + +template<> class tuple<> +{}; + +template +class tuple + : private tuple +{ + typedef tuple inherited; + + public: + tuple() { } + + // implicit copy-constructor is okay + // Construct tuple from separate arguments. + tuple(typename add_const_reference::type v, + typename add_const_reference::type... vtail) + : inherited(vtail...), m_head(v) + {} + + // Construct tuple from another tuple. + template + tuple(const tuple& other) + : m_head(other.head()), inherited(other.tail()) + {} + + template + tuple& operator=(const tuple& other) + { + m_head = other.head(); + tail() = other.tail(); + return this; + } + + typename add_reference::type head() { return m_head; } + typename add_reference::type head() const { return m_head; } + + inherited& tail() { return *this; } + const inherited& tail() const { return *this; } + + protected: + Head m_head; +}; + + +template +tuple tie_forward(Values&&... values) +{ return tuple(values...); } + +template +struct tuple_element; + +template +struct tuple_element > +{ + typedef typename tuple_element >::type type; +}; + +template +struct tuple_element<0, tuple > +{ + typedef Head type; +}; + +template +class get_impl; + +template +class get_impl > +{ + typedef typename tuple_element >::type Element; + typedef get_impl > Next; + + public: + typedef typename add_reference::type type; + typedef typename add_const_reference::type const_type; + static type get(tuple& t) { return Next::get(t.tail()); } + static const_type get(const tuple& t) { return Next::get(t.tail()); } +}; + +template +class get_impl<0, tuple > +{ + public: + typedef typename add_reference::type type; + typedef typename add_const_reference::type const_type; + static type get(tuple& t) { return t.head(); } + static const_type get(const tuple& t){ return t.head(); } +}; + +template +typename get_impl >::type get(tuple& t) +{ return get_impl >::get(t); } + +template +typename get_impl >::const_type get(const tuple& t) +{ return get_impl >::get(t); } + +//////////////////////////////////////////////////// +// Builds an index_tuple<0, 1, 2, ..., Num-1>, that will +// be used to "unpack" into comma-separated values +// in a function call. +//////////////////////////////////////////////////// + +template +struct index_tuple{}; + +template > +struct build_number_seq; + +template +struct build_number_seq > + : build_number_seq > +{}; + +template +struct build_number_seq<0, index_tuple > +{ typedef index_tuple type; }; + + +}}} //namespace boost { namespace interprocess_container { namespace containers_detail { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP diff --git a/include/boost/interprocess/detail/version_type.hpp b/include/boost/interprocess/containers/container/detail/version_type.hpp similarity index 66% rename from include/boost/interprocess/detail/version_type.hpp rename to include/boost/interprocess/containers/container/detail/version_type.hpp index ed43623..f7075dd 100644 --- a/include/boost/interprocess/detail/version_type.hpp +++ b/include/boost/interprocess/containers/container/detail/version_type.hpp @@ -4,7 +4,7 @@ // 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. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// // @@ -13,22 +13,22 @@ ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP -#define BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP +#ifndef BOOST_CONTAINERS_DETAIL_VERSION_TYPE_HPP +#define BOOST_CONTAINERS_DETAIL_VERSION_TYPE_HPP -#include -#include +#include +#include namespace boost{ -namespace interprocess{ -namespace detail{ +namespace interprocess_container { +namespace containers_detail { //using namespace boost; template struct version_type - : public detail::integral_constant + : public containers_detail::integral_constant { typedef T type; @@ -38,7 +38,7 @@ struct version_type namespace impl{ template , typename T::version>::value> + bool = containers_detail::is_convertible, typename T::version>::value> struct extract_version { static const unsigned value = 1; @@ -78,12 +78,12 @@ struct version template struct version - : public detail::integral_constant::value> + : public containers_detail::integral_constant::value> { }; -} //namespace detail{ -} //namespace interprocess{ +} //namespace containers_detail { +} //namespace interprocess_container { } //namespace boost{ -#endif //#define BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP +#endif //#define BOOST_CONTAINERS_DETAIL_VERSION_TYPE_HPP diff --git a/include/boost/interprocess/containers/container/detail/workaround.hpp b/include/boost/interprocess/containers/container/detail/workaround.hpp new file mode 100644 index 0000000..60abf6c --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/workaround.hpp @@ -0,0 +1,24 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_WORKAROUND_HPP +#define BOOST_CONTAINERS_DETAIL_WORKAROUND_HPP + +#include + +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)\ + && !defined(BOOST_INTERPROCESS_DISABLE_VARIADIC_TMPL) +#define BOOST_CONTAINERS_PERFECT_FORWARDING + +#endif + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_WORKAROUND_HPP diff --git a/include/boost/interprocess/containers/container/flat_map.hpp b/include/boost/interprocess/containers/container/flat_map.hpp new file mode 100644 index 0000000..b3b9b79 --- /dev/null +++ b/include/boost/interprocess/containers/container/flat_map.hpp @@ -0,0 +1,1390 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_FLAT_MAP_HPP +#define BOOST_CONTAINERS_FLAT_MAP_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +// Forward declarations of operators == and <, needed for friend declarations. +template +class flat_map; + +template +inline bool operator==(const flat_map& x, + const flat_map& y); + +template +inline bool operator<(const flat_map& x, + const flat_map& y); +/// @endcond + +//! A flat_map is a kind of associative container that supports unique keys (contains at +//! most one of each key value) and provides for fast retrieval of values of another +//! type T based on the keys. The flat_map class supports random-access iterators. +//! +//! A flat_map satisfies all of the requirements of a container and of a reversible +//! container and of an associative container. A flat_map also provides +//! most operations described for unique keys. For a +//! flat_map the key_type is Key and the value_type is std::pair +//! (unlike std::map which value_type is std::pair<const Key, T>). +//! +//! Pred is the ordering function for Keys (e.g. std::less). +//! +//! Alloc is the allocator to allocate the value_types +//! (e.g. allocator< std::pair >). +//! +//! flat_map is similar to std::map but it's implemented like an ordered vector. +//! This means that inserting a new element into a flat_map invalidates +//! previous iterators and references +//! +//! Erasing an element of a flat_map invalidates iterators and references +//! pointing to elements that come after (their keys are bigger) the erased element. +template +class flat_map +{ + /// @cond + private: + //This is the tree that we should store if pair was movable + typedef containers_detail::flat_tree, + containers_detail::select1st< std::pair >, + Pred, + Alloc> tree_t; + + //This is the real tree stored here. It's based on a movable pair + typedef containers_detail::flat_tree, + containers_detail::select1st >, + Pred, + typename Alloc::template + rebind >::other> impl_tree_t; + impl_tree_t m_flat_tree; // flat tree representing flat_map + + typedef typename impl_tree_t::value_type impl_value_type; + typedef typename impl_tree_t::pointer impl_pointer; + typedef typename impl_tree_t::const_pointer impl_const_pointer; + typedef typename impl_tree_t::reference impl_reference; + typedef typename impl_tree_t::const_reference impl_const_reference; + typedef typename impl_tree_t::value_compare impl_value_compare; + typedef typename impl_tree_t::iterator impl_iterator; + typedef typename impl_tree_t::const_iterator impl_const_iterator; + typedef typename impl_tree_t::reverse_iterator impl_reverse_iterator; + typedef typename impl_tree_t::const_reverse_iterator impl_const_reverse_iterator; + typedef typename impl_tree_t::allocator_type impl_allocator_type; + + template + static D &force(const S &s) + { return *const_cast(reinterpret_cast(&s)); } + + template + static D force_copy(S s) + { + value_type *vp = reinterpret_cast(&*s); + return D(vp); + } + + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(flat_map) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef typename tree_t::value_compare value_compare; + typedef T mapped_type; + typedef typename tree_t::key_compare key_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + + //! Effects: Constructs an empty flat_map using the specified + //! comparison object and allocator. + //! + //! Complexity: Constant. + explicit flat_map(const Pred& comp = Pred(), const allocator_type& a = allocator_type()) + : m_flat_tree(comp, force(a)) {} + + //! Effects: Constructs an empty flat_map using the specified comparison object and + //! allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + flat_map(InputIterator first, InputIterator last, const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, force(a)) + { m_flat_tree.insert_unique(first, last); } + + //! Effects: Copy constructs a flat_map. + //! + //! Complexity: Linear in x.size(). + flat_map(const flat_map& x) + : m_flat_tree(x.m_flat_tree) {} + + //! Effects: Move constructs a flat_map. + //! Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + flat_map(BOOST_INTERPROCESS_RV_REF(flat_map) x) + : m_flat_tree(boost::interprocess::move(x.m_flat_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + flat_map& operator=(const flat_map& x) + { m_flat_tree = x.m_flat_tree; return *this; } + + //! Effects: Move constructs a flat_map. + //! Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + flat_map& operator=(BOOST_INTERPROCESS_RV_REF(flat_map) mx) + { m_flat_tree = boost::interprocess::move(mx.m_flat_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return force(m_flat_tree.key_comp()); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return value_compare(force(m_flat_tree.key_comp())); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return force(m_flat_tree.get_allocator()); } + + const stored_allocator_type &get_stored_allocator() const + { return force(m_flat_tree.get_stored_allocator()); } + + stored_allocator_type &get_stored_allocator() + { return force(m_flat_tree.get_stored_allocator()); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return force_copy(m_flat_tree.begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return force(m_flat_tree.begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return force(m_flat_tree.cbegin()); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return force_copy(m_flat_tree.end()); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return force(m_flat_tree.end()); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return force(m_flat_tree.cend()); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return force(m_flat_tree.rbegin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return force(m_flat_tree.rbegin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return force(m_flat_tree.crbegin()); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return force(m_flat_tree.rend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return force(m_flat_tree.rend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return force(m_flat_tree.crend()); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_flat_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_flat_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_flat_tree.max_size(); } + + //! Effects: If there is no key equivalent to x in the flat_map, inserts + //! value_type(x, T()) into the flat_map. + //! + //! Returns: A reference to the mapped_type corresponding to x in *this. + //! + //! Complexity: Logarithmic. + T &operator[](const key_type& k) + { + iterator i = lower_bound(k); + // i->first is greater than or equivalent to k. + if (i == end() || key_comp()(k, (*i).first)) + i = insert(i, value_type(k, T())); + return (*i).second; + } + + //! Effects: If there is no key equivalent to x in the flat_map, inserts + //! value_type(move(x), T()) into the flat_map (the key is move-constructed) + //! + //! Returns: A reference to the mapped_type corresponding to x in *this. + //! + //! Complexity: Logarithmic. + T &operator[](BOOST_INTERPROCESS_RV_REF(key_type) mk) + { + key_type &k = mk; + iterator i = lower_bound(k); + // i->first is greater than or equivalent to k. + if (i == end() || key_comp()(k, (*i).first)) + i = insert(i, value_type(boost::interprocess::move(k), boost::interprocess::move(T()))); + return (*i).second; + } + + //! Returns: A reference to the element whose key is equivalent to x. + //! Throws: An exception object of type out_of_range if no such element is present. + //! Complexity: logarithmic. + T& at(const key_type& k) + { + iterator i = this->find(k); + if(i == this->end()){ + throw std::out_of_range("key not found"); + } + return i->second; + } + + //! Returns: A reference to the element whose key is equivalent to x. + //! Throws: An exception object of type out_of_range if no such element is present. + //! Complexity: logarithmic. + const T& at(const key_type& k) const + { + const_iterator i = this->find(k); + if(i == this->end()){ + throw std::out_of_range("key not found"); + } + return i->second; + } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(flat_map& x) + { m_flat_tree.swap(x.m_flat_tree); } + + //! Effects: Inserts x if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(const value_type& x) + { return force >( + m_flat_tree.insert_unique(force(x))); } + + //! Effects: Inserts a new value_type move constructed from the pair if and + //! only if there is no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return force >( + m_flat_tree.insert_unique(boost::interprocess::move(force(x)))); } + + //! Effects: Inserts a new value_type move constructed from the pair if and + //! only if there is no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(BOOST_INTERPROCESS_RV_REF(impl_value_type) x) + { + return force > + (m_flat_tree.insert_unique(boost::interprocess::move(x))); + } + + //! Effects: Inserts a copy of x in the container if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, const value_type& x) + { return force_copy( + m_flat_tree.insert_unique(force(position), force(x))); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return force_copy( + m_flat_tree.insert_unique(force(position), boost::interprocess::move(force(x)))); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(impl_value_type) x) + { + return force_copy( + m_flat_tree.insert_unique(force(position), boost::interprocess::move(x))); + } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) if and only + //! if there is no element with key equivalent to the key of that element. + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + //! search time plus N*size() insertion time. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + void insert(InputIterator first, InputIterator last) + { m_flat_tree.insert_unique(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return force_copy(m_flat_tree.emplace_unique(boost::interprocess::forward(args)...)); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return force_copy(m_flat_tree.emplace_hint_unique(force(hint), boost::interprocess::forward(args)...)); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return force_copy(m_flat_tree.emplace_unique()); } + + iterator emplace_hint(const_iterator hint) + { return force_copy(m_flat_tree.emplace_hint_unique(force(hint))); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_unique \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ + } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_hint_unique \ + (force(hint), \ + BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Linear to the elements with keys bigger than position + //! + //! Note: Invalidates elements with keys + //! not less than the erased element. + iterator erase(const_iterator position) + { return force_copy(m_flat_tree.erase(force(position))); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + size_type erase(const key_type& x) + { return m_flat_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: size()*N where N is the distance from first to last. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + iterator erase(const_iterator first, const_iterator last) + { return force_copy(m_flat_tree.erase(force(first), force(last))); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_flat_tree.clear(); } + + //! Effects: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { m_flat_tree.shrink_to_fit(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return force_copy(m_flat_tree.find(x)); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic.s + const_iterator find(const key_type& x) const + { return force(m_flat_tree.find(x)); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return force_copy(m_flat_tree.lower_bound(x)); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return force(m_flat_tree.lower_bound(x)); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return force_copy(m_flat_tree.upper_bound(x)); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return force(m_flat_tree.upper_bound(x)); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) + { return force >(m_flat_tree.equal_range(x)); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) const + { return force >(m_flat_tree.equal_range(x)); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return m_flat_tree.capacity(); } + + //! Effects: If n is less than or equal to capacity(), this call has no + //! effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + //! + //! Note: If capacity() is less than "count", iterators and references to + //! to values might be invalidated. + void reserve(size_type count) + { m_flat_tree.reserve(count); } + + /// @cond + template + friend bool operator== (const flat_map&, + const flat_map&); + template + friend bool operator< (const flat_map&, + const flat_map&); + /// @endcond +}; + +template +inline bool operator==(const flat_map& x, + const flat_map& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_map& x, + const flat_map& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_map& x, + const flat_map& y) + { return !(x == y); } + +template +inline bool operator>(const flat_map& x, + const flat_map& y) + { return y < x; } + +template +inline bool operator<=(const flat_map& x, + const flat_map& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_map& x, + const flat_map& y) + { return !(x < y); } + +template +inline void swap(flat_map& x, + flat_map& y) + { x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +// Forward declaration of operators < and ==, needed for friend declaration. +template +class flat_multimap; + +template +inline bool operator==(const flat_multimap& x, + const flat_multimap& y); + +template +inline bool operator<(const flat_multimap& x, + const flat_multimap& y); +/// @endcond + +//! A flat_multimap is a kind of associative container that supports equivalent keys +//! (possibly containing multiple copies of the same key value) and provides for +//! fast retrieval of values of another type T based on the keys. The flat_multimap +//! class supports random-access iterators. +//! +//! A flat_multimap satisfies all of the requirements of a container and of a reversible +//! container and of an associative container. For a +//! flat_multimap the key_type is Key and the value_type is std::pair +//! (unlike std::multimap which value_type is std::pair<const Key, T>). +//! +//! Pred is the ordering function for Keys (e.g. std::less). +//! +//! Alloc is the allocator to allocate the value_types +//! (e.g. allocator< std::pair >). +template +class flat_multimap +{ + /// @cond + private: + typedef containers_detail::flat_tree, + containers_detail::select1st< std::pair >, + Pred, + Alloc> tree_t; + //This is the real tree stored here. It's based on a movable pair + typedef containers_detail::flat_tree, + containers_detail::select1st >, + Pred, + typename Alloc::template + rebind >::other> impl_tree_t; + impl_tree_t m_flat_tree; // flat tree representing flat_map + + typedef typename impl_tree_t::value_type impl_value_type; + typedef typename impl_tree_t::pointer impl_pointer; + typedef typename impl_tree_t::const_pointer impl_const_pointer; + typedef typename impl_tree_t::reference impl_reference; + typedef typename impl_tree_t::const_reference impl_const_reference; + typedef typename impl_tree_t::value_compare impl_value_compare; + typedef typename impl_tree_t::iterator impl_iterator; + typedef typename impl_tree_t::const_iterator impl_const_iterator; + typedef typename impl_tree_t::reverse_iterator impl_reverse_iterator; + typedef typename impl_tree_t::const_reverse_iterator impl_const_reverse_iterator; + typedef typename impl_tree_t::allocator_type impl_allocator_type; + + template + static D &force(const S &s) + { return *const_cast((reinterpret_cast(&s))); } + + template + static D force_copy(S s) + { + value_type *vp = reinterpret_cast(&*s); + return D(vp); + } + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(flat_multimap) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef typename tree_t::value_compare value_compare; + typedef T mapped_type; + typedef typename tree_t::key_compare key_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + + //! Effects: Constructs an empty flat_multimap using the specified comparison + //! object and allocator. + //! + //! Complexity: Constant. + explicit flat_multimap(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, force(a)) { } + + //! Effects: Constructs an empty flat_multimap using the specified comparison object + //! and allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + flat_multimap(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, force(a)) + { m_flat_tree.insert_equal(first, last); } + + //! Effects: Copy constructs a flat_multimap. + //! + //! Complexity: Linear in x.size(). + flat_multimap(const flat_multimap& x) + : m_flat_tree(x.m_flat_tree) { } + + //! Effects: Move constructs a flat_multimap. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + flat_multimap(BOOST_INTERPROCESS_RV_REF(flat_multimap) x) + : m_flat_tree(boost::interprocess::move(x.m_flat_tree)) + { } + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + flat_multimap& operator=(const flat_multimap& x) + { m_flat_tree = x.m_flat_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + flat_multimap& operator=(BOOST_INTERPROCESS_RV_REF(flat_multimap) mx) + { m_flat_tree = boost::interprocess::move(mx.m_flat_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return force(m_flat_tree.key_comp()); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return value_compare(force(m_flat_tree.key_comp())); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return force(m_flat_tree.get_allocator()); } + + const stored_allocator_type &get_stored_allocator() const + { return force(m_flat_tree.get_stored_allocator()); } + + stored_allocator_type &get_stored_allocator() + { return force(m_flat_tree.get_stored_allocator()); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return force_copy(m_flat_tree.begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return force(m_flat_tree.begin()); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return force_copy(m_flat_tree.end()); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return force(m_flat_tree.end()); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return force(m_flat_tree.rbegin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return force(m_flat_tree.rbegin()); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return force(m_flat_tree.rend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return force(m_flat_tree.rend()); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_flat_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_flat_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_flat_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(flat_multimap& x) + { m_flat_tree.swap(x.m_flat_tree); } + + //! Effects: Inserts x and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const value_type& x) + { return force_copy(m_flat_tree.insert_equal(force(x))); } + + //! Effects: Inserts a new value move-constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return force_copy(m_flat_tree.insert_equal(boost::interprocess::move(x))); } + + //! Effects: Inserts a new value move-constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(BOOST_INTERPROCESS_RV_REF(impl_value_type) x) + { return force_copy(m_flat_tree.insert_equal(boost::interprocess::move(x))); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant time if the value + //! is to be inserted before p) plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, const value_type& x) + { return force_copy(m_flat_tree.insert_equal(force(position), force(x))); } + + //! Effects: Inserts a value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant time if the value + //! is to be inserted before p) plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { + return force_copy + (m_flat_tree.insert_equal(force(position) + , boost::interprocess::move(x))); + } + + //! Effects: Inserts a value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant time if the value + //! is to be inserted before p) plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(impl_value_type) x) + { + return force_copy( + m_flat_tree.insert_equal(force(position), boost::interprocess::move(x))); + } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) . + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + //! search time plus N*size() insertion time. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + void insert(InputIterator first, InputIterator last) + { m_flat_tree.insert_equal(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return force_copy(m_flat_tree.emplace_equal(boost::interprocess::forward(args)...)); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant time if the value + //! is to be inserted before p) plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { + return force_copy(m_flat_tree.emplace_hint_equal + (force(hint), boost::interprocess::forward(args)...)); + } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return force_copy(m_flat_tree.emplace_equal()); } + + iterator emplace_hint(const_iterator hint) + { return force_copy(m_flat_tree.emplace_hint_equal(force(hint))); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_equal \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ + } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_hint_equal \ + (force(hint), \ + BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Linear to the elements with keys bigger than position + //! + //! Note: Invalidates elements with keys + //! not less than the erased element. + iterator erase(const_iterator position) + { return force_copy(m_flat_tree.erase(force(position))); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + size_type erase(const key_type& x) + { return m_flat_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: size()*N where N is the distance from first to last. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + iterator erase(const_iterator first, const_iterator last) + { return force_copy(m_flat_tree.erase(force(first), force(last))); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_flat_tree.clear(); } + + //! Effects: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { m_flat_tree.shrink_to_fit(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return force_copy(m_flat_tree.find(x)); } + + //! Returns: An const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return force(m_flat_tree.find(x)); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_flat_tree.count(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + {return force_copy(m_flat_tree.lower_bound(x)); } + + //! Returns: A const iterator pointing to the first element with key + //! not less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return force(m_flat_tree.lower_bound(x)); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + {return force_copy(m_flat_tree.upper_bound(x)); } + + //! Returns: A const iterator pointing to the first element with key + //! not less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return force(m_flat_tree.upper_bound(x)); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) + { return force_copy >(m_flat_tree.equal_range(x)); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return force_copy >(m_flat_tree.equal_range(x)); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return m_flat_tree.capacity(); } + + //! Effects: If n is less than or equal to capacity(), this call has no + //! effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + //! + //! Note: If capacity() is less than "count", iterators and references to + //! to values might be invalidated. + void reserve(size_type count) + { m_flat_tree.reserve(count); } + + /// @cond + template + friend bool operator== (const flat_multimap& x, + const flat_multimap& y); + + template + friend bool operator< (const flat_multimap& x, + const flat_multimap& y); + /// @endcond +}; + +template +inline bool operator==(const flat_multimap& x, + const flat_multimap& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_multimap& x, + const flat_multimap& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_multimap& x, + const flat_multimap& y) + { return !(x == y); } + +template +inline bool operator>(const flat_multimap& x, + const flat_multimap& y) + { return y < x; } + +template +inline bool operator<=(const flat_multimap& x, + const flat_multimap& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_multimap& x, + const flat_multimap& y) + { return !(x < y); } + +template +inline void swap(flat_multimap& x, flat_multimap& y) + { x.swap(y); } + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move< boost::interprocess_container::flat_multimap > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { +} //namespace boost { + +/// @endcond + +#include + +#endif /* BOOST_CONTAINERS_FLAT_MAP_HPP */ diff --git a/include/boost/interprocess/containers/container/flat_set.hpp b/include/boost/interprocess/containers/container/flat_set.hpp new file mode 100644 index 0000000..2c00cb7 --- /dev/null +++ b/include/boost/interprocess/containers/container/flat_set.hpp @@ -0,0 +1,1172 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_FLAT_SET_HPP +#define BOOST_CONTAINERS_FLAT_SET_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +// Forward declarations of operators < and ==, needed for friend declaration. + +template +class flat_set; + +template +inline bool operator==(const flat_set& x, + const flat_set& y); + +template +inline bool operator<(const flat_set& x, + const flat_set& y); +/// @endcond + +//! flat_set is a Sorted Associative Container that stores objects of type Key. +//! flat_set is a Simple Associative Container, meaning that its value type, +//! as well as its key type, is Key. It is also a Unique Associative Container, +//! meaning that no two elements are the same. +//! +//! flat_set is similar to std::set but it's implemented like an ordered vector. +//! This means that inserting a new element into a flat_set invalidates +//! previous iterators and references +//! +//! Erasing an element of a flat_set invalidates iterators and references +//! pointing to elements that come after (their keys are bigger) the erased element. +template +class flat_set +{ + /// @cond + private: + typedef containers_detail::flat_tree, Pred, Alloc> tree_t; + tree_t m_flat_tree; // flat tree representing flat_set + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(flat_set) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef typename tree_t::key_compare key_compare; + typedef typename tree_t::value_compare value_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + + //! Effects: Constructs an empty flat_map using the specified + //! comparison object and allocator. + //! + //! Complexity: Constant. + explicit flat_set(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, a) + {} + + //! Effects: Constructs an empty map using the specified comparison object and + //! allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + flat_set(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, a) + { m_flat_tree.insert_unique(first, last); } + + //! Effects: Copy constructs a map. + //! + //! Complexity: Linear in x.size(). + flat_set(const flat_set& x) + : m_flat_tree(x.m_flat_tree) {} + + //! Effects: Move constructs a map. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + flat_set(BOOST_INTERPROCESS_RV_REF(flat_set) mx) + : m_flat_tree(boost::interprocess::move(mx.m_flat_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + flat_set& operator=(const flat_set& x) + { m_flat_tree = x.m_flat_tree; return *this; } + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + flat_set& operator=(BOOST_INTERPROCESS_RV_REF(flat_set) mx) + { m_flat_tree = boost::interprocess::move(mx.m_flat_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_flat_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return m_flat_tree.key_comp(); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return m_flat_tree.get_allocator(); } + + const stored_allocator_type &get_stored_allocator() const + { return m_flat_tree.get_stored_allocator(); } + + stored_allocator_type &get_stored_allocator() + { return m_flat_tree.get_stored_allocator(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_flat_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_flat_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_flat_tree.cbegin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_flat_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_flat_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_flat_tree.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_flat_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_flat_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_flat_tree.crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_flat_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_flat_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_flat_tree.crend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_flat_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_flat_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_flat_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(flat_set& x) + { m_flat_tree.swap(x.m_flat_tree); } + + //! Effects: Inserts x if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(const value_type& x) + { return m_flat_tree.insert_unique(x); } + + //! Effects: Inserts a new value_type move constructed from the pair if and + //! only if there is no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_flat_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, const value_type& x) + { return m_flat_tree.insert_unique(position, x); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_flat_tree.insert_unique(position, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) if and only + //! if there is no element with key equivalent to the key of that element. + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + //! search time plus N*size() insertion time. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + void insert(InputIterator first, InputIterator last) + { m_flat_tree.insert_unique(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return m_flat_tree.emplace_unique(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_flat_tree.emplace_hint_unique(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return m_flat_tree.emplace_unique(); } + + iterator emplace_hint(const_iterator hint) + { return m_flat_tree.emplace_hint_unique(hint); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_flat_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_flat_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); }\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Linear to the elements with keys bigger than position + //! + //! Note: Invalidates elements with keys + //! not less than the erased element. + iterator erase(const_iterator position) + { return m_flat_tree.erase(position); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + size_type erase(const key_type& x) + { return m_flat_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: size()*N where N is the distance from first to last. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + iterator erase(const_iterator first, const_iterator last) + { return m_flat_tree.erase(first, last); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_flat_tree.clear(); } + + //! Effects: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { m_flat_tree.shrink_to_fit(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_flat_tree.find(x); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic.s + const_iterator find(const key_type& x) const + { return m_flat_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_flat_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_flat_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_flat_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_flat_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_flat_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) + { return m_flat_tree.equal_range(x); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return m_flat_tree.capacity(); } + + //! Effects: If n is less than or equal to capacity(), this call has no + //! effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + //! + //! Note: If capacity() is less than "count", iterators and references to + //! to values might be invalidated. + void reserve(size_type count) + { m_flat_tree.reserve(count); } + + /// @cond + template + friend bool operator== (const flat_set&, const flat_set&); + + template + friend bool operator< (const flat_set&, const flat_set&); + /// @endcond +}; + +template +inline bool operator==(const flat_set& x, + const flat_set& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_set& x, + const flat_set& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_set& x, + const flat_set& y) + { return !(x == y); } + +template +inline bool operator>(const flat_set& x, + const flat_set& y) + { return y < x; } + +template +inline bool operator<=(const flat_set& x, + const flat_set& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_set& x, + const flat_set& y) + { return !(x < y); } + +template +inline void swap(flat_set& x, flat_set& y) + { x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value &&has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +// Forward declaration of operators < and ==, needed for friend declaration. + +template +class flat_multiset; + +template +inline bool operator==(const flat_multiset& x, + const flat_multiset& y); + +template +inline bool operator<(const flat_multiset& x, + const flat_multiset& y); +/// @endcond + +//! flat_multiset is a Sorted Associative Container that stores objects of type Key. +//! flat_multiset is a Simple Associative Container, meaning that its value type, +//! as well as its key type, is Key. +//! flat_Multiset can store multiple copies of the same key value. +//! +//! flat_multiset is similar to std::multiset but it's implemented like an ordered vector. +//! This means that inserting a new element into a flat_multiset invalidates +//! previous iterators and references +//! +//! Erasing an element of a flat_multiset invalidates iterators and references +//! pointing to elements that come after (their keys are equal or bigger) the erased element. +template +class flat_multiset +{ + /// @cond + private: + typedef containers_detail::flat_tree, Pred, Alloc> tree_t; + tree_t m_flat_tree; // flat tree representing flat_multiset + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(flat_multiset) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef typename tree_t::key_compare key_compare; + typedef typename tree_t::value_compare value_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + + // allocation/deallocation + explicit flat_multiset(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, a) {} + + template + flat_multiset(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, a) + { m_flat_tree.insert_equal(first, last); } + + flat_multiset(const flat_multiset& x) + : m_flat_tree(x.m_flat_tree) {} + + flat_multiset(BOOST_INTERPROCESS_RV_REF(flat_multiset) x) + : m_flat_tree(boost::interprocess::move(x.m_flat_tree)) + {} + + flat_multiset& operator=(const flat_multiset& x) + { m_flat_tree = x.m_flat_tree; return *this; } + + flat_multiset& operator=(BOOST_INTERPROCESS_RV_REF(flat_multiset) mx) + { m_flat_tree = boost::interprocess::move(mx.m_flat_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_flat_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return m_flat_tree.key_comp(); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return m_flat_tree.get_allocator(); } + + const stored_allocator_type &get_stored_allocator() const + { return m_flat_tree.get_stored_allocator(); } + + stored_allocator_type &get_stored_allocator() + { return m_flat_tree.get_stored_allocator(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_flat_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_flat_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_flat_tree.cbegin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_flat_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_flat_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_flat_tree.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_flat_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_flat_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_flat_tree.crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_flat_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_flat_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_flat_tree.crend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_flat_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_flat_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_flat_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(flat_multiset& x) + { m_flat_tree.swap(x.m_flat_tree); } + + //! Effects: Inserts x and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const value_type& x) + { return m_flat_tree.insert_equal(x); } + + //! Effects: Inserts a new value_type move constructed from x + //! and returns the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_flat_tree.insert_equal(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, const value_type& x) + { return m_flat_tree.insert_equal(position, x); } + + //! Effects: Inserts a new value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_flat_tree.insert_equal(position, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) . + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + //! search time plus N*size() insertion time. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + void insert(InputIterator first, InputIterator last) + { m_flat_tree.insert_equal(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return m_flat_tree.emplace_equal(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_flat_tree.emplace_hint_equal(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return m_flat_tree.emplace_equal(); } + + iterator emplace_hint(const_iterator hint) + { return m_flat_tree.emplace_hint_equal(hint); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_flat_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_flat_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Linear to the elements with keys bigger than position + //! + //! Note: Invalidates elements with keys + //! not less than the erased element. + iterator erase(const_iterator position) + { return m_flat_tree.erase(position); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + size_type erase(const key_type& x) + { return m_flat_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: size()*N where N is the distance from first to last. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + iterator erase(const_iterator first, const_iterator last) + { return m_flat_tree.erase(first, last); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_flat_tree.clear(); } + + //! Effects: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { m_flat_tree.shrink_to_fit(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_flat_tree.find(x); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic.s + const_iterator find(const key_type& x) const + { return m_flat_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_flat_tree.count(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_flat_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_flat_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_flat_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_flat_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_flat_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) + { return m_flat_tree.equal_range(x); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return m_flat_tree.capacity(); } + + //! Effects: If n is less than or equal to capacity(), this call has no + //! effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + //! + //! Note: If capacity() is less than "count", iterators and references to + //! to values might be invalidated. + void reserve(size_type count) + { m_flat_tree.reserve(count); } + + /// @cond + template + friend bool operator== (const flat_multiset&, + const flat_multiset&); + template + friend bool operator< (const flat_multiset&, + const flat_multiset&); + /// @endcond +}; + +template +inline bool operator==(const flat_multiset& x, + const flat_multiset& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_multiset& x, + const flat_multiset& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_multiset& x, + const flat_multiset& y) + { return !(x == y); } + +template +inline bool operator>(const flat_multiset& x, + const flat_multiset& y) + { return y < x; } + +template +inline bool operator<=(const flat_multiset& x, + const flat_multiset& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_multiset& x, + const flat_multiset& y) +{ return !(x < y); } + +template +inline void swap(flat_multiset& x, flat_multiset& y) + { x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} + +#include + +#endif /* BOOST_CONTAINERS_FLAT_SET_HPP */ diff --git a/include/boost/interprocess/containers/container/list.hpp b/include/boost/interprocess/containers/container/list.hpp new file mode 100644 index 0000000..e7d0f89 --- /dev/null +++ b/include/boost/interprocess/containers/container/list.hpp @@ -0,0 +1,1372 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's stl_list.h file. Modified by Ion Gaztanaga 2004 +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef BOOST_CONTAINERS_LIST_HPP_ +#define BOOST_CONTAINERS_LIST_HPP_ + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +//Preprocessor library to emulate perfect forwarding +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +namespace containers_detail { + +template +struct list_hook +{ + typedef typename containers_detail::bi::make_list_base_hook + , containers_detail::bi::link_mode >::type type; +}; + +template +struct list_node + : public list_hook::type +{ + + #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + list_node() + : m_data() + {} + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + list_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : m_data(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ + {} \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #else //#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + template + list_node(Args &&...args) + : m_data(boost::interprocess::forward(args)...) + {} + #endif//#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + T m_data; +}; + +template +struct intrusive_list_type +{ + typedef typename A::value_type value_type; + typedef typename boost::pointer_to_other + ::type void_pointer; + typedef typename containers_detail::list_node + node_type; + typedef typename containers_detail::bi::make_list + < node_type + , containers_detail::bi::base_hook::type> + , containers_detail::bi::constant_time_size + , containers_detail::bi::size_type + >::type container_type; + typedef container_type type ; +}; + +} //namespace containers_detail { +/// @endcond + +//! A list is a doubly linked list. That is, it is a Sequence that supports both +//! forward and backward traversal, and (amortized) constant time insertion and +//! removal of elements at the beginning or the end, or in the middle. Lists have +//! the important property that insertion and splicing do not invalidate iterators +//! to list elements, and that even removal invalidates only the iterators that point +//! to the elements that are removed. The ordering of iterators may be changed +//! (that is, list::iterator might have a different predecessor or successor +//! after a list operation than it did before), but the iterators themselves will +//! not be invalidated or made to point to different elements unless that invalidation +//! or mutation is explicit. +template +class list + : protected containers_detail::node_alloc_holder + ::type> +{ + /// @cond + typedef typename + containers_detail::intrusive_list_type::type Icont; + typedef list ThisType; + typedef containers_detail::node_alloc_holder AllocHolder; + typedef typename AllocHolder::NodePtr NodePtr; + typedef typename AllocHolder::NodeAlloc NodeAlloc; + typedef typename AllocHolder::ValAlloc ValAlloc; + typedef typename AllocHolder::Node Node; + typedef containers_detail::allocator_destroyer Destroyer; + typedef typename AllocHolder::allocator_v1 allocator_v1; + typedef typename AllocHolder::allocator_v2 allocator_v2; + typedef typename AllocHolder::alloc_version alloc_version; + + class equal_to_value + { + typedef typename AllocHolder::value_type value_type; + const value_type &t_; + + public: + equal_to_value(const value_type &t) + : t_(t) + {} + + bool operator()(const value_type &t)const + { return t_ == t; } + }; + + template + struct ValueCompareToNodeCompare + : Pred + { + ValueCompareToNodeCompare(Pred pred) + : Pred(pred) + {} + + bool operator()(const Node &a, const Node &b) const + { return static_cast(*this)(a.m_data, b.m_data); } + + bool operator()(const Node &a) const + { return static_cast(*this)(a.m_data); } + }; + /// @endcond + + public: + //! The type of object, T, stored in the list + typedef T value_type; + //! Pointer to T + typedef typename A::pointer pointer; + //! Const pointer to T + typedef typename A::const_pointer const_pointer; + //! Reference to T + typedef typename A::reference reference; + //! Const reference to T + typedef typename A::const_reference const_reference; + //! An unsigned integral type + typedef typename A::size_type size_type; + //! A signed integral type + typedef typename A::difference_type difference_type; + //! The allocator type + typedef A allocator_type; + //! The stored allocator type + typedef NodeAlloc stored_allocator_type; + + /// @cond + private: + typedef difference_type list_difference_type; + typedef pointer list_pointer; + typedef const_pointer list_const_pointer; + typedef reference list_reference; + typedef const_reference list_const_reference; + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(list) + + //! Const iterator used to iterate through a list. + class const_iterator + /// @cond + : public std::iterator + { + + protected: + typename Icont::iterator m_it; + explicit const_iterator(typename Icont::iterator it) : m_it(it){} + void prot_incr() { ++m_it; } + void prot_decr() { --m_it; } + + private: + typename Icont::iterator get() + { return this->m_it; } + + public: + friend class list; + typedef list_difference_type difference_type; + + //Constructors + const_iterator() + : m_it() + {} + + //Pointer like operators + const_reference operator*() const + { return m_it->m_data; } + + const_pointer operator->() const + { return const_pointer(&m_it->m_data); } + + //Increment / Decrement + const_iterator& operator++() + { prot_incr(); return *this; } + + const_iterator operator++(int) + { typename Icont::iterator tmp = m_it; ++*this; return const_iterator(tmp); } + + const_iterator& operator--() + { prot_decr(); return *this; } + + const_iterator operator--(int) + { typename Icont::iterator tmp = m_it; --*this; return const_iterator(tmp); } + + //Comparison operators + bool operator== (const const_iterator& r) const + { return m_it == r.m_it; } + + bool operator!= (const const_iterator& r) const + { return m_it != r.m_it; } + } + /// @endcond + ; + + //! Iterator used to iterate through a list + class iterator + /// @cond + : public const_iterator + { + + private: + explicit iterator(typename Icont::iterator it) + : const_iterator(it) + {} + + typename Icont::iterator get() + { return this->m_it; } + + public: + friend class list; + typedef list_pointer pointer; + typedef list_reference reference; + + //Constructors + iterator(){} + + //Pointer like operators + reference operator*() const { return this->m_it->m_data; } + pointer operator->() const { return pointer(&this->m_it->m_data); } + + //Increment / Decrement + iterator& operator++() + { this->prot_incr(); return *this; } + + iterator operator++(int) + { typename Icont::iterator tmp = this->m_it; ++*this; return iterator(tmp); } + + iterator& operator--() + { this->prot_decr(); return *this; } + + iterator operator--(int) + { iterator tmp = *this; --*this; return tmp; } + }; + /// @endcond + + //! Iterator used to iterate backwards through a list. + typedef std::reverse_iterator reverse_iterator; + //! Const iterator used to iterate backwards through a list. + typedef std::reverse_iterator const_reverse_iterator; + + //! Effects: Constructs a list taking the allocator as parameter. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + explicit list(const allocator_type &a = A()) + : AllocHolder(a) + {} + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + list(size_type n) + : AllocHolder(A()) + { this->resize(n); } + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + list(size_type n, const T& value, const A& a = A()) + : AllocHolder(a) + { this->insert(this->cbegin(), n, value); } + + //! Effects: Copy constructs a list. + //! + //! Postcondition: x == *this. + //! + //! Throws: If allocator_type's default constructor or copy constructor throws. + //! + //! Complexity: Linear to the elements x contains. + list(const list& x) + : AllocHolder(x) + { this->insert(this->cbegin(), x.begin(), x.end()); } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + list(BOOST_INTERPROCESS_RV_REF(list) x) + : AllocHolder(boost::interprocess::move((AllocHolder&)x)) + {} + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts a copy of the range [first, last) in the list. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's constructor taking an dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + list(InpIt first, InpIt last, const A &a = A()) + : AllocHolder(a) + { this->insert(this->cbegin(), first, last); } + + //! Effects: Destroys the list. All stored values are destroyed + //! and used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements. + ~list() + {} //AllocHolder clears the list + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return allocator_type(this->node_alloc()); } + + const stored_allocator_type &get_stored_allocator() const + { return this->node_alloc(); } + + stored_allocator_type &get_stored_allocator() + { return this->node_alloc(); } + + //! Effects: Erases all the elements of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements in the list. + void clear() + { AllocHolder::clear(alloc_version()); } + + //! Effects: Returns an iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return iterator(this->icont().begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return this->cbegin(); } + + //! Effects: Returns an iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return iterator(this->icont().end()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return this->cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return reverse_iterator(end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return this->crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return reverse_iterator(begin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return this->crend(); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(this->non_const_icont().begin()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(this->non_const_icont().end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return const_reverse_iterator(this->cend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return const_reverse_iterator(this->cbegin()); } + + //! Effects: Returns true if the list contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return !this->size(); } + + //! Effects: Returns the number of the elements contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return this->icont().size(); } + + //! Effects: Returns the largest possible size of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return AllocHolder::max_size(); } + + //! Effects: Inserts a copy of t in the beginning of the list. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_front(const T& x) + { this->insert(this->cbegin(), x); } + + //! Effects: Constructs a new element in the beginning of the list + //! and moves the resources of t to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_front(BOOST_INTERPROCESS_RV_REF(T) x) + { this->insert(this->cbegin(), boost::interprocess::move(x)); } + + //! Effects: Removes the last element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void push_back (const T& x) + { this->insert(this->cend(), x); } + + //! Effects: Removes the first element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void push_back (BOOST_INTERPROCESS_RV_REF(T) x) + { this->insert(this->cend(), boost::interprocess::move(x)); } + + //! Effects: Removes the first element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void pop_front() + { this->erase(this->cbegin()); } + + //! Effects: Removes the last element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void pop_back() + { const_iterator tmp = this->cend(); this->erase(--tmp); } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() + { return *this->begin(); } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const + { return *this->begin(); } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference back() + { return *(--this->end()); } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference back() const + { return *(--this->end()); } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size, const T& x) + { + const_iterator iend = this->cend(); + size_type len = this->size(); + + if(len > new_size){ + size_type to_erase = len - new_size; + while(to_erase--){ + --iend; + } + this->erase(iend, this->cend()); + } + else{ + this->priv_create_and_insert_nodes(iend, new_size - len, x); + } + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size) + { + const_iterator iend = this->end(); + size_type len = this->size(); + + if(len > new_size){ + size_type to_erase = len - new_size; + const_iterator ifirst; + if(to_erase < len/2u){ + ifirst = iend; + while(to_erase--){ + --ifirst; + } + } + else{ + ifirst = this->begin(); + size_type to_skip = len - to_erase; + while(to_skip--){ + ++ifirst; + } + } + this->erase(ifirst, iend); + } + else{ + this->priv_create_and_insert_nodes(this->cend(), new_size - len); + } + } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() + //! allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(ThisType& x) + { AllocHolder::swap(x); } + + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + ThisType& operator=(const ThisType& x) + { + if (this != &x) { + this->assign(x.begin(), x.end()); + } + return *this; + } + + //! Effects: Move assignment. All mx's values are transferred to *this. + //! + //! Postcondition: x.empty(). *this contains a the elements x had + //! before the function. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + ThisType& operator=(BOOST_INTERPROCESS_RV_REF(ThisType) mx) + { + this->clear(); + this->swap(mx); + return *this; + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Inserts n copies of x before p. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void insert(const_iterator p, size_type n, const T& x) + { this->priv_create_and_insert_nodes(p, n, x); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [first, last) range before p. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws. + //! + //! Complexity: Linear to std::distance [first, last). + template + void insert(const_iterator p, InpIt first, InpIt last) + { + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_dispatch(p, first, last, Result()); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before p. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: Amortized constant time. + iterator insert(const_iterator p, const T& x) + { + NodePtr tmp = AllocHolder::create_node(x); + return iterator(this->icont().insert(p.get(), *tmp)); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a new element before p with mx's resources. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + iterator insert(const_iterator p, BOOST_INTERPROCESS_RV_REF(T) x) + { + NodePtr tmp = AllocHolder::create_node(boost::interprocess::move(x)); + return iterator(this->icont().insert(p.get(), *tmp)); + } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the list. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + void emplace_back(Args&&... args) + { + this->emplace(this->cend(), boost::interprocess::forward(args)...); + } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the beginning of the list. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + void emplace_front(Args&&... args) + { + this->emplace(this->cbegin(), boost::interprocess::forward(args)...); + } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before p. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + iterator emplace(const_iterator p, Args&&... args) + { + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); + new ((void*)containers_detail::get_pointer(d.get())) Node(boost::interprocess::forward(args)...); + NodePtr node = d.get(); + d.release(); + return iterator(this->icont().insert(p.get(), *node)); + } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //0 args + void emplace_back() + { this->emplace(this->cend()); } + + void emplace_front() + { this->emplace(this->cbegin()); } + + iterator emplace(const_iterator p) + { + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); + new ((void*)containers_detail::get_pointer(d.get())) Node(); + NodePtr node = d.get(); + d.release(); + return iterator(this->icont().insert(p.get(), *node)); + } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + this->emplace(this->cend(), BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + } \ + \ + template \ + void emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { this->emplace(this->cbegin(), BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _));} \ + \ + template \ + iterator emplace(const_iterator p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); \ + new ((void*)containers_detail::get_pointer(d.get())) \ + Node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + NodePtr node = d.get(); \ + d.release(); \ + return iterator(this->icont().insert(p.get(), *node)); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Erases the element at p p. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + iterator erase(const_iterator p) + { return iterator(this->icont().erase_and_dispose(p.get(), Destroyer(this->node_alloc()))); } + + //! Requires: first and last must be valid iterator to elements in *this. + //! + //! Effects: Erases the elements pointed by [first, last). + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the distance between first and last. + iterator erase(const_iterator first, const_iterator last) + { return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); } + + //! Effects: Assigns the n copies of val to *this. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void assign(size_type n, const T& val) + { this->priv_fill_assign(n, val); } + + //! Effects: Assigns the the range [first, last) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing InpIt throws. + //! + //! Complexity: Linear to n. + template + void assign(InpIt first, InpIt last) + { + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_assign_dispatch(first, last, Result()); + } + + //! Requires: p must point to an element contained + //! by the list. x != *this + //! + //! Effects: Transfers all the elements of list x to this list, before the + //! the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of + //! this list. Iterators of this list and all the references are not invalidated. + void splice(iterator p, ThisType& x) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice(p.get(), x.icont()); + } + else{ + throw std::runtime_error("list::splice called with unequal allocators"); + } + } + + //! Requires: p must point to an element contained + //! by this list. i must point to an element contained in list x. + //! + //! Effects: Transfers the value pointed by i, from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! If p == i or p == ++i, this function is a null operation. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, ThisType &x, const_iterator i) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice(p.get(), x.icont(), i.get()); + } + else{ + throw std::runtime_error("list::splice called with unequal allocators"); + } + } + + //! Requires: p must point to an element contained + //! by this list. first and last must point to elements contained in list x. + //! + //! Effects: Transfers the range pointed by first and last from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear to the number of elements transferred. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice(p.get(), x.icont(), first.get(), last.get()); + } + else{ + throw std::runtime_error("list::splice called with unequal allocators"); + } + } + + //! Requires: p must point to an element contained + //! by this list. first and last must point to elements contained in list x. + //! n == std::distance(first, last) + //! + //! Effects: Transfers the range pointed by first and last from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last, size_type n) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice(p.get(), x.icont(), first.get(), last.get(), n); + } + else{ + throw std::runtime_error("list::splice called with unequal allocators"); + } + } + + //! Effects: Reverses the order of elements in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time. + //! + //! Note: Iterators and references are not invalidated + void reverse() + { this->icont().reverse(); } + + //! Effects: Removes all the elements that compare equal to value. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + void remove(const T& value) + { remove_if(equal_to_value(value)); } + + //! Effects: Removes all the elements for which a specified + //! predicate is satisfied. + //! + //! Throws: If pred throws. + //! + //! Complexity: Linear time. It performs exactly size() calls to the predicate. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_if(Pred pred) + { + typedef ValueCompareToNodeCompare Predicate; + this->icont().remove_and_dispose_if(Predicate(pred), Destroyer(this->node_alloc())); + } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that are equal from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear time (size()-1 comparisons calls to pred()). + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + void unique() + { this->unique(value_equal()); } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that satisfy some binary predicate from the list. + //! + //! Throws: If pred throws. + //! + //! Complexity: Linear time (size()-1 comparisons equality comparisons). + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique(BinaryPredicate binary_pred) + { + typedef ValueCompareToNodeCompare Predicate; + this->icont().unique_and_dispose(Predicate(binary_pred), Destroyer(this->node_alloc())); + } + + //! Requires: The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this according to std::less. The merge is stable; + //! that is, if an element from *this is equivalent to one from x, then the element + //! from *this will precede the one from x. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + void merge(list& x) + { this->merge(x, value_less()); } + + //! Requires: p must be a comparison function that induces a strict weak + //! ordering and both *this and x must be sorted according to that ordering + //! The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this. The merge is stable; that is, if an element from *this is + //! equivalent to one from x, then the element from *this will precede the one from x. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references to *this are not invalidated. + template + void merge(list &x, StrictWeakOrdering comp) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().merge(x.icont(), + ValueCompareToNodeCompare(comp)); + } + else{ + throw std::runtime_error("list::merge called with unequal allocators"); + } + } + + //! Effects: This function sorts the list *this according to std::less. + //! The sort is stable, that is, the relative order of equivalent elements is preserved. + //! + //! Throws: Nothing. + //! + //! Notes: Iterators and references are not invalidated. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + void sort() + { this->sort(value_less()); } + + //! Effects: This function sorts the list *this according to std::less. + //! The sort is stable, that is, the relative order of equivalent elements is preserved. + //! + //! Throws: Nothing. + //! + //! Notes: Iterators and references are not invalidated. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + template + void sort(StrictWeakOrdering comp) + { + // nothing if the list has length 0 or 1. + if (this->size() < 2) + return; + this->icont().sort(ValueCompareToNodeCompare(comp)); + } + + /// @cond + private: + + //Iterator range version + template + void priv_create_and_insert_nodes + (const_iterator pos, InpIterator beg, InpIterator end) + { + typedef typename std::iterator_traits::iterator_category ItCat; + priv_create_and_insert_nodes(pos, beg, end, alloc_version(), ItCat()); + } + + template + void priv_create_and_insert_nodes + (const_iterator pos, InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) + { + for (; beg != end; ++beg){ + this->icont().insert(pos.get(), *this->create_node_from_it(beg)); + } + } + + template + void priv_create_and_insert_nodes + (const_iterator pos, InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) + { //Just forward to the default one + priv_create_and_insert_nodes(pos, beg, end, allocator_v1(), std::input_iterator_tag()); + } + + class insertion_functor; + friend class insertion_functor; + + class insertion_functor + { + Icont &icont_; + typename Icont::const_iterator pos_; + + public: + insertion_functor(Icont &icont, typename Icont::const_iterator pos) + : icont_(icont), pos_(pos) + {} + + void operator()(Node &n) + { this->icont_.insert(pos_, n); } + }; + + + template + void priv_create_and_insert_nodes + (const_iterator pos, FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag) + { + if(beg != end){ + //Optimized allocation and construction + this->allocate_many_and_construct + (beg, std::distance(beg, end), insertion_functor(this->icont(), pos.get())); + } + } + + //Default constructed version + void priv_create_and_insert_nodes(const_iterator pos, size_type n) + { + typedef default_construct_iterator default_iterator; + this->priv_create_and_insert_nodes(pos, default_iterator(n), default_iterator()); + } + + //Copy constructed version + void priv_create_and_insert_nodes(const_iterator pos, size_type n, const T& x) + { + typedef constant_iterator cvalue_iterator; + this->priv_create_and_insert_nodes(pos, cvalue_iterator(x, n), cvalue_iterator()); + } + + //Dispatch to detect iterator range or integer overloads + template + void priv_insert_dispatch(const_iterator p, + InputIter first, InputIter last, + containers_detail::false_) + { this->priv_create_and_insert_nodes(p, first, last); } + + template + void priv_insert_dispatch(const_iterator p, Integer n, Integer x, containers_detail::true_) + { this->insert(p, (size_type)n, x); } + + void priv_fill_assign(size_type n, const T& val) + { + iterator i = this->begin(), iend = this->end(); + + for ( ; i != iend && n > 0; ++i, --n) + *i = val; + if (n > 0){ + this->priv_create_and_insert_nodes(this->cend(), n, val); + } + else{ + this->erase(i, cend()); + } + } + + template + void priv_assign_dispatch(Integer n, Integer val, containers_detail::true_) + { this->priv_fill_assign((size_type) n, (T) val); } + + template + void priv_assign_dispatch(InputIter first2, InputIter last2, containers_detail::false_) + { + iterator first1 = this->begin(); + iterator last1 = this->end(); + for ( ; first1 != last1 && first2 != last2; ++first1, ++first2) + *first1 = *first2; + if (first2 == last2) + this->erase(first1, last1); + else{ + this->priv_create_and_insert_nodes(last1, first2, last2); + } + } + + //Functors for member algorithm defaults + struct value_less + { + bool operator()(const value_type &a, const value_type &b) const + { return a < b; } + }; + + struct value_equal + { + bool operator()(const value_type &a, const value_type &b) const + { return a == b; } + }; + /// @endcond + +}; + +template +inline bool operator==(const list& x, const list& y) +{ + if(x.size() != y.size()){ + return false; + } + typedef typename list::const_iterator const_iterator; + const_iterator end1 = x.end(); + + const_iterator i1 = x.begin(); + const_iterator i2 = y.begin(); + while (i1 != end1 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1; +} + +template +inline bool operator<(const list& x, + const list& y) +{ + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); +} + +template +inline bool operator!=(const list& x, const list& y) +{ + return !(x == y); +} + +template +inline bool operator>(const list& x, const list& y) +{ + return y < x; +} + +template +inline bool operator<=(const list& x, const list& y) +{ + return !(y < x); +} + +template +inline bool operator>=(const list& x, const list& y) +{ + return !(x < y); +} + +template +inline void swap(list& x, list& y) +{ + x.swap(y); +} + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} + +#include + +#endif // BOOST_CONTAINERS_LIST_HPP_ diff --git a/include/boost/interprocess/containers/container/map.hpp b/include/boost/interprocess/containers/container/map.hpp new file mode 100644 index 0000000..c0033c7 --- /dev/null +++ b/include/boost/interprocess/containers/container/map.hpp @@ -0,0 +1,1266 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's stl_map/stl_multimap files. Modified by Ion Gaztanaga. +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef BOOST_CONTAINERS_MAP_HPP +#define BOOST_CONTAINERS_MAP_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +// Forward declarations of operators == and <, needed for friend declarations. +template +inline bool operator==(const map& x, + const map& y); + +template +inline bool operator<(const map& x, + const map& y); +/// @endcond + +//! A map is a kind of associative container that supports unique keys (contains at +//! most one of each key value) and provides for fast retrieval of values of another +//! type T based on the keys. The map class supports bidirectional iterators. +//! +//! A map satisfies all of the requirements of a container and of a reversible +//! container and of an associative container. For a +//! map the key_type is Key and the value_type is std::pair. +//! +//! Pred is the ordering function for Keys (e.g. std::less). +//! +//! Alloc is the allocator to allocate the value_types +//! (e.g. allocator< std::pair > ). +template +class map +{ + /// @cond + private: + typedef containers_detail::rbtree, + containers_detail::select1st< std::pair >, + Pred, + Alloc> tree_t; + tree_t m_tree; // red-black tree representing map + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(map) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef T mapped_type; + typedef Pred key_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + typedef std::pair nonconst_value_type; + typedef containers_detail::pair + nonconst_impl_value_type; + + /// @cond + class value_compare_impl + : public Pred, + public std::binary_function + { + friend class map; + protected : + value_compare_impl(const Pred &c) : Pred(c) {} + public: + bool operator()(const value_type& x, const value_type& y) const { + return Pred::operator()(x.first, y.first); + } + }; + /// @endcond + typedef value_compare_impl value_compare; + + //! Effects: Constructs an empty map using the specified comparison object + //! and allocator. + //! + //! Complexity: Constant. + explicit map(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(comp, a) + {} + + //! Effects: Constructs an empty map using the specified comparison object and + //! allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + map(InputIterator first, InputIterator last, const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(first, last, comp, a, true) + {} + + //! Effects: Copy constructs a map. + //! + //! Complexity: Linear in x.size(). + map(const map& x) + : m_tree(x.m_tree) + {} + + //! Effects: Move constructs a map. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + map(BOOST_INTERPROCESS_RV_REF(map) x) + : m_tree(boost::interprocess::move(x.m_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + map& operator=(const map& x) + { m_tree = x.m_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + map& operator=(BOOST_INTERPROCESS_RV_REF(map) x) + { m_tree = boost::interprocess::move(x.m_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return value_compare(m_tree.key_comp()); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return m_tree.get_allocator(); } + + const stored_allocator_type &get_stored_allocator() const + { return m_tree.get_stored_allocator(); } + + stored_allocator_type &get_stored_allocator() + { return m_tree.get_stored_allocator(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_tree.begin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_tree.end(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_tree.rbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_tree.rend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_tree.max_size(); } + + //! Effects: If there is no key equivalent to x in the map, inserts + //! value_type(x, T()) into the map. + //! + //! Returns: A reference to the mapped_type corresponding to x in *this. + //! + //! Complexity: Logarithmic. + T& operator[](const key_type& k) + { + //we can optimize this + iterator i = lower_bound(k); + // i->first is greater than or equivalent to k. + if (i == end() || key_comp()(k, (*i).first)){ + containers_detail::value_init v; + value_type val(k, boost::interprocess::move(v.m_t)); + i = insert(i, boost::interprocess::move(val)); + } + return (*i).second; + } + + //! Effects: If there is no key equivalent to x in the map, inserts + //! value_type(boost::interprocess::move(x), T()) into the map (the key is move-constructed) + //! + //! Returns: A reference to the mapped_type corresponding to x in *this. + //! + //! Complexity: Logarithmic. + T& operator[](BOOST_INTERPROCESS_RV_REF(key_type) mk) + { + key_type &k = mk; + //we can optimize this + iterator i = lower_bound(k); + // i->first is greater than or equivalent to k. + if (i == end() || key_comp()(k, (*i).first)){ + value_type val(boost::interprocess::move(k), boost::interprocess::move(T())); + i = insert(i, boost::interprocess::move(val)); + } + return (*i).second; + } + + //! Returns: A reference to the element whose key is equivalent to x. + //! Throws: An exception object of type out_of_range if no such element is present. + //! Complexity: logarithmic. + T& at(const key_type& k) + { + iterator i = this->find(k); + if(i == this->end()){ + throw std::out_of_range("key not found"); + } + return i->second; + } + + //! Returns: A reference to the element whose key is equivalent to x. + //! Throws: An exception object of type out_of_range if no such element is present. + //! Complexity: logarithmic. + const T& at(const key_type& k) const + { + const_iterator i = this->find(k); + if(i == this->end()){ + throw std::out_of_range("key not found"); + } + return i->second; + } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(map& x) + { m_tree.swap(x.m_tree); } + + //! Effects: Inserts x if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + std::pair insert(const value_type& x) + { return m_tree.insert_unique(x); } + + //! Effects: Inserts a new value_type created from the pair if and only if + //! there is no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + std::pair insert(const nonconst_value_type& x) + { return m_tree.insert_unique(x); } + + //! Effects: Inserts a new value_type move constructed from the pair if and + //! only if there is no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_INTERPROCESS_RV_REF(nonconst_value_type) x) + { return m_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: Inserts a new value_type move constructed from the pair if and + //! only if there is no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_INTERPROCESS_RV_REF(nonconst_impl_value_type) x) + { return m_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: Move constructs a new value from x if and only if there is + //! no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, const value_type& x) + { return m_tree.insert_unique(position, x); } + + //! Effects: Move constructs a new value from x if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(nonconst_value_type) x) + { return m_tree.insert_unique(position, boost::interprocess::move(x)); } + + //! Effects: Move constructs a new value from x if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(nonconst_impl_value_type) x) + { return m_tree.insert_unique(position, boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + iterator insert(iterator position, const nonconst_value_type& x) + { return m_tree.insert_unique(position, x); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_unique(position, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) if and only + //! if there is no element with key equivalent to the key of that element. + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + template + void insert(InputIterator first, InputIterator last) + { m_tree.insert_unique(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container if and only if there is + //! no element in the container with an equivalent key. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_unique(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container if and only if there is + //! no element in the container with an equivalent key. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_unique(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return m_tree.emplace_unique(); } + + iterator emplace_hint(const_iterator hint) + { return m_tree.emplace_hint_unique(hint); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _));}\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Amortized constant time + iterator erase(const_iterator position) + { return m_tree.erase(position); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: log(size()) + count(k) + size_type erase(const key_type& x) + { return m_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: log(size())+N where N is the distance from first to last. + iterator erase(const_iterator first, const_iterator last) + { return m_tree.erase(first, last); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_tree.clear(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_tree.find(x); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return m_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_tree.find(x) == m_tree.end() ? 0 : 1; } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + /// @cond + template + friend bool operator== (const map&, + const map&); + template + friend bool operator< (const map&, + const map&); + /// @endcond +}; + +template +inline bool operator==(const map& x, + const map& y) + { return x.m_tree == y.m_tree; } + +template +inline bool operator<(const map& x, + const map& y) + { return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const map& x, + const map& y) + { return !(x == y); } + +template +inline bool operator>(const map& x, + const map& y) + { return y < x; } + +template +inline bool operator<=(const map& x, + const map& y) + { return !(y < x); } + +template +inline bool operator>=(const map& x, + const map& y) + { return !(x < y); } + +template +inline void swap(map& x, map& y) + { x.swap(y); } + +/// @cond + +// Forward declaration of operators < and ==, needed for friend declaration. + +template +inline bool operator==(const multimap& x, + const multimap& y); + +template +inline bool operator<(const multimap& x, + const multimap& y); + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +//! A multimap is a kind of associative container that supports equivalent keys +//! (possibly containing multiple copies of the same key value) and provides for +//! fast retrieval of values of another type T based on the keys. The multimap class +//! supports bidirectional iterators. +//! +//! A multimap satisfies all of the requirements of a container and of a reversible +//! container and of an associative container. For a +//! map the key_type is Key and the value_type is std::pair. +//! +//! Pred is the ordering function for Keys (e.g. std::less). +//! +//! Alloc is the allocator to allocate the value_types +//!(e.g. allocator< std::pair<const Key, T> >). +template +class multimap +{ + /// @cond + private: + typedef containers_detail::rbtree, + containers_detail::select1st< std::pair >, + Pred, + Alloc> tree_t; + tree_t m_tree; // red-black tree representing map + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(multimap) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef T mapped_type; + typedef Pred key_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + typedef std::pair nonconst_value_type; + typedef containers_detail::pair + nonconst_impl_value_type; + + /// @cond + class value_compare_impl + : public Pred, + public std::binary_function + { + friend class multimap; + protected : + value_compare_impl(const Pred &c) : Pred(c) {} + public: + bool operator()(const value_type& x, const value_type& y) const { + return Pred::operator()(x.first, y.first); + } + }; + /// @endcond + typedef value_compare_impl value_compare; + + //! Effects: Constructs an empty multimap using the specified comparison + //! object and allocator. + //! + //! Complexity: Constant. + explicit multimap(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(comp, a) + {} + + //! Effects: Constructs an empty multimap using the specified comparison object + //! and allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + multimap(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(first, last, comp, a, false) + {} + + //! Effects: Copy constructs a multimap. + //! + //! Complexity: Linear in x.size(). + multimap(const multimap& x) + : m_tree(x.m_tree) + {} + + //! Effects: Move constructs a multimap. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + multimap(BOOST_INTERPROCESS_RV_REF(multimap) x) + : m_tree(boost::interprocess::move(x.m_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + multimap& operator=(const multimap& x) + { m_tree = x.m_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + multimap& operator=(BOOST_INTERPROCESS_RV_REF(multimap) x) + { m_tree = boost::interprocess::move(x.m_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return value_compare(m_tree.key_comp()); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return m_tree.get_allocator(); } + + const stored_allocator_type &get_stored_allocator() const + { return m_tree.get_stored_allocator(); } + + stored_allocator_type &get_stored_allocator() + { return m_tree.get_stored_allocator(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_tree.begin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_tree.end(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_tree.rbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_tree.rend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(multimap& x) + { m_tree.swap(x.m_tree); } + + //! Effects: Inserts x and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(const value_type& x) + { return m_tree.insert_equal(x); } + + //! Effects: Inserts a new value constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(const nonconst_value_type& x) + { return m_tree.insert_equal(x); } + + //! Effects: Inserts a new value move-constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(BOOST_INTERPROCESS_RV_REF(nonconst_value_type) x) + { return m_tree.insert_equal(boost::interprocess::move(x)); } + + //! Effects: Inserts a new value move-constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(BOOST_INTERPROCESS_RV_REF(nonconst_impl_value_type) x) + { return m_tree.insert_equal(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, const value_type& x) + { return m_tree.insert_equal(position, x); } + + //! Effects: Inserts a new value constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, const nonconst_value_type& x) + { return m_tree.insert_equal(position, x); } + + //! Effects: Inserts a new value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(nonconst_value_type) x) + { return m_tree.insert_equal(position, boost::interprocess::move(x)); } + + //! Effects: Inserts a new value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(nonconst_impl_value_type) x) + { return m_tree.insert_equal(position, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) . + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + template + void insert(InputIterator first, InputIterator last) + { m_tree.insert_equal(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_equal(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_equal(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return m_tree.emplace_equal(); } + + iterator emplace_hint(const_iterator hint) + { return m_tree.emplace_hint_equal(hint); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); }\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Amortized constant time + iterator erase(const_iterator position) + { return m_tree.erase(position); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: log(size()) + count(k) + size_type erase(const key_type& x) + { return m_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: log(size())+N where N is the distance from first to last. + iterator erase(const_iterator first, const_iterator last) + { return m_tree.erase(first, last); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_tree.clear(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_tree.find(x); } + + //! Returns: A const iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return m_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_tree.count(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + {return m_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + /// @cond + template + friend bool operator== (const multimap& x, + const multimap& y); + + template + friend bool operator< (const multimap& x, + const multimap& y); + /// @endcond +}; + +template +inline bool operator==(const multimap& x, + const multimap& y) +{ return x.m_tree == y.m_tree; } + +template +inline bool operator<(const multimap& x, + const multimap& y) +{ return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const multimap& x, + const multimap& y) +{ return !(x == y); } + +template +inline bool operator>(const multimap& x, + const multimap& y) +{ return y < x; } + +template +inline bool operator<=(const multimap& x, + const multimap& y) +{ return !(y < x); } + +template +inline bool operator>=(const multimap& x, + const multimap& y) +{ return !(x < y); } + +template +inline void swap(multimap& x, multimap& y) +{ x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} + +#include + +#endif /* BOOST_CONTAINERS_MAP_HPP */ + diff --git a/include/boost/interprocess/containers/container/set.hpp b/include/boost/interprocess/containers/container/set.hpp new file mode 100644 index 0000000..bf5234a --- /dev/null +++ b/include/boost/interprocess/containers/container/set.hpp @@ -0,0 +1,1112 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's stl_set/stl_multiset files. Modified by Ion Gaztanaga 2004. +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef BOOST_CONTAINERS_SET_HPP +#define BOOST_CONTAINERS_SET_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +#include +#endif + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +// Forward declarations of operators < and ==, needed for friend declaration. +template +inline bool operator==(const set& x, + const set& y); + +template +inline bool operator<(const set& x, + const set& y); +/// @endcond + +//! A set is a kind of associative container that supports unique keys (contains at +//! most one of each key value) and provides for fast retrieval of the keys themselves. +//! Class set supports bidirectional iterators. +//! +//! A set satisfies all of the requirements of a container and of a reversible container +//! , and of an associative container. A set also provides most operations described in +//! for unique keys. +template +class set +{ + /// @cond + private: + typedef containers_detail::rbtree, Pred, Alloc> tree_t; + tree_t m_tree; // red-black tree representing set + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(set) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef Pred key_compare; + typedef Pred value_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + + //! Effects: Constructs an empty set using the specified comparison object + //! and allocator. + //! + //! Complexity: Constant. + explicit set(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(comp, a) + {} + + //! Effects: Constructs an empty set using the specified comparison object and + //! allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + set(InputIterator first, InputIterator last, const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(first, last, comp, a, true) + {} + + //! Effects: Copy constructs a set. + //! + //! Complexity: Linear in x.size(). + set(const set& x) + : m_tree(x.m_tree) + {} + + //! Effects: Move constructs a set. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + set(BOOST_INTERPROCESS_RV_REF(set) x) + : m_tree(boost::interprocess::move(x.m_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + set& operator=(const set& x) + { m_tree = x.m_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + set& operator=(BOOST_INTERPROCESS_RV_REF(set) x) + { m_tree = boost::interprocess::move(x.m_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return m_tree.get_allocator(); } + + const stored_allocator_type &get_stored_allocator() const + { return m_tree.get_stored_allocator(); } + + stored_allocator_type &get_stored_allocator() + { return m_tree.get_stored_allocator(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant + iterator begin() + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_tree.begin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_tree.end(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_tree.rbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_tree.rend(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_tree.cbegin(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_tree.cend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_tree.crbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_tree.crend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(set& x) + { m_tree.swap(x.m_tree); } + + //! Effects: Inserts x if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + std::pair insert(const value_type& x) + { return m_tree.insert_unique(x); } + + //! Effects: Move constructs a new value from x if and only if there is + //! no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(const_iterator p, const value_type& x) + { return m_tree.insert_unique(p, x); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + iterator insert(const_iterator p, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_unique(p, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) if and only + //! if there is no element with key equivalent to the key of that element. + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + template + void insert(InputIterator first, InputIterator last) + { m_tree.insert_unique(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... if and only if there is + //! no element in the container with equivalent value. + //! and returns the iterator pointing to the + //! newly inserted element. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Logarithmic. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_unique(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... if and only if there is + //! no element in the container with equivalent value. + //! p is a hint pointing to where the insert + //! should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_unique(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return m_tree.emplace_unique(); } + + iterator emplace_hint(const_iterator hint) + { return m_tree.emplace_hint_unique(hint); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _));}\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by p. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Amortized constant time + iterator erase(const_iterator p) + { return m_tree.erase(p); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: log(size()) + count(k) + size_type erase(const key_type& x) + { return m_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: log(size())+N where N is the distance from first to last. + iterator erase(const_iterator first, const_iterator last) + { return m_tree.erase(first, last); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_tree.clear(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_tree.find(x); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return m_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_tree.find(x) == m_tree.end() ? 0 : 1; } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + /// @cond + template + friend bool operator== (const set&, const set&); + + template + friend bool operator< (const set&, const set&); + /// @endcond +}; + +template +inline bool operator==(const set& x, + const set& y) +{ return x.m_tree == y.m_tree; } + +template +inline bool operator<(const set& x, + const set& y) +{ return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const set& x, + const set& y) +{ return !(x == y); } + +template +inline bool operator>(const set& x, + const set& y) +{ return y < x; } + +template +inline bool operator<=(const set& x, + const set& y) +{ return !(y < x); } + +template +inline bool operator>=(const set& x, + const set& y) +{ return !(x < y); } + +template +inline void swap(set& x, set& y) +{ x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +// Forward declaration of operators < and ==, needed for friend declaration. + +template +inline bool operator==(const multiset& x, + const multiset& y); + +template +inline bool operator<(const multiset& x, + const multiset& y); +/// @endcond + +//! A multiset is a kind of associative container that supports equivalent keys +//! (possibly contains multiple copies of the same key value) and provides for +//! fast retrieval of the keys themselves. Class multiset supports bidirectional iterators. +//! +//! A multiset satisfies all of the requirements of a container and of a reversible +//! container, and of an associative container). multiset also provides most operations +//! described for duplicate keys. +template +class multiset +{ + /// @cond + private: + typedef containers_detail::rbtree, Pred, Alloc> tree_t; + tree_t m_tree; // red-black tree representing multiset + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(multiset) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef Pred key_compare; + typedef Pred value_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + + //! Effects: Constructs an empty multiset using the specified comparison + //! object and allocator. + //! + //! Complexity: Constant. + explicit multiset(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(comp, a) + {} + + //! Effects: Constructs an empty multiset using the specified comparison object + //! and allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + multiset(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(first, last, comp, a, false) + {} + + //! Effects: Copy constructs a multiset. + //! + //! Complexity: Linear in x.size(). + multiset(const multiset& x) + : m_tree(x.m_tree) + {} + + //! Effects: Move constructs a multiset. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + multiset(BOOST_INTERPROCESS_RV_REF(multiset) x) + : m_tree(boost::interprocess::move(x.m_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + multiset& operator=(const multiset& x) + { m_tree = x.m_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + multiset& operator=(BOOST_INTERPROCESS_RV_REF(multiset) x) + { m_tree = boost::interprocess::move(x.m_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return m_tree.get_allocator(); } + + const stored_allocator_type &get_stored_allocator() const + { return m_tree.get_stored_allocator(); } + + stored_allocator_type &get_stored_allocator() + { return m_tree.get_stored_allocator(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_tree.begin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_tree.end(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_tree.rbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_tree.rend(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_tree.cbegin(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_tree.cend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_tree.crbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_tree.crend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(multiset& x) + { m_tree.swap(x.m_tree); } + + //! Effects: Inserts x and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(const value_type& x) + { return m_tree.insert_equal(x); } + + //! Effects: Inserts a copy of x in the container. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_equal(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(const_iterator p, const value_type& x) + { return m_tree.insert_equal(p, x); } + + //! Effects: Inserts a value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(const_iterator p, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_equal(p, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) . + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + template + void insert(InputIterator first, InputIterator last) + { m_tree.insert_equal(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_equal(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_equal(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return m_tree.emplace_equal(); } + + iterator emplace_hint(const_iterator hint) + { return m_tree.emplace_hint_equal(hint); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); }\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by p. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Amortized constant time + iterator erase(const_iterator p) + { return m_tree.erase(p); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: log(size()) + count(k) + size_type erase(const key_type& x) + { return m_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: log(size())+N where N is the distance from first to last. + iterator erase(const_iterator first, const_iterator last) + { return m_tree.erase(first, last); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_tree.clear(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_tree.find(x); } + + //! Returns: A const iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return m_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_tree.count(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + /// @cond + template + friend bool operator== (const multiset&, + const multiset&); + template + friend bool operator< (const multiset&, + const multiset&); + /// @endcond +}; + +template +inline bool operator==(const multiset& x, + const multiset& y) +{ return x.m_tree == y.m_tree; } + +template +inline bool operator<(const multiset& x, + const multiset& y) +{ return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const multiset& x, + const multiset& y) +{ return !(x == y); } + +template +inline bool operator>(const multiset& x, + const multiset& y) +{ return y < x; } + +template +inline bool operator<=(const multiset& x, + const multiset& y) +{ return !(y < x); } + +template +inline bool operator>=(const multiset& x, + const multiset& y) +{ return !(x < y); } + +template +inline void swap(multiset& x, multiset& y) +{ x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} + +#include + +#endif /* BOOST_CONTAINERS_SET_HPP */ + diff --git a/include/boost/interprocess/containers/container/slist.hpp b/include/boost/interprocess/containers/container/slist.hpp new file mode 100644 index 0000000..6e60ae1 --- /dev/null +++ b/include/boost/interprocess/containers/container/slist.hpp @@ -0,0 +1,1524 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's stl_slist.h file. Modified by Ion Gaztanaga 2004-2008 +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef BOOST_CONTAINERS_SLIST_HPP +#define BOOST_CONTAINERS_SLIST_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +//Preprocessor library to emulate perfect forwarding +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond + +namespace containers_detail { + +template +struct slist_hook +{ + typedef typename containers_detail::bi::make_slist_base_hook + , containers_detail::bi::link_mode >::type type; +}; + +template +struct slist_node + : public slist_hook::type +{ + #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + slist_node() + : m_data() + {} + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + slist_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : m_data(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ + {} \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #else //#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + template + slist_node(Args &&...args) + : m_data(boost::interprocess::forward(args)...) + {} + #endif//#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + T m_data; +}; + +template +struct intrusive_slist_type +{ + typedef typename A::value_type value_type; + typedef typename boost::pointer_to_other + ::type void_pointer; + typedef typename containers_detail::slist_node + node_type; + + typedef typename containers_detail::bi::make_slist + ::type> + ,containers_detail::bi::constant_time_size + ,containers_detail::bi::size_type + >::type container_type; + typedef container_type type ; +}; + +} //namespace containers_detail { + +/// @endcond + +//! An slist is a singly linked list: a list where each element is linked to the next +//! element, but not to the previous element. That is, it is a Sequence that +//! supports forward but not backward traversal, and (amortized) constant time +//! insertion and removal of elements. Slists, like lists, have the important +//! property that insertion and splicing do not invalidate iterators to list elements, +//! and that even removal invalidates only the iterators that point to the elements +//! that are removed. The ordering of iterators may be changed (that is, +//! slist::iterator might have a different predecessor or successor after a list +//! operation than it did before), but the iterators themselves will not be invalidated +//! or made to point to different elements unless that invalidation or mutation is explicit. +//! +//! The main difference between slist and list is that list's iterators are bidirectional +//! iterators, while slist's iterators are forward iterators. This means that slist is +//! less versatile than list; frequently, however, bidirectional iterators are +//! unnecessary. You should usually use slist unless you actually need the extra +//! functionality of list, because singly linked lists are smaller and faster than double +//! linked lists. +//! +//! Important performance note: like every other Sequence, slist defines the member +//! functions insert and erase. Using these member functions carelessly, however, can +//! result in disastrously slow programs. The problem is that insert's first argument is +//! an iterator p, and that it inserts the new element(s) before p. This means that +//! insert must find the iterator just before p; this is a constant-time operation +//! for list, since list has bidirectional iterators, but for slist it must find that +//! iterator by traversing the list from the beginning up to p. In other words: +//! insert and erase are slow operations anywhere but near the beginning of the slist. +//! +//! Slist provides the member functions insert_after and erase_after, which are constant +//! time operations: you should always use insert_after and erase_after whenever +//! possible. If you find that insert_after and erase_after aren't adequate for your +//! needs, and that you often need to use insert and erase in the middle of the list, +//! then you should probably use list instead of slist. +template +class slist + : protected containers_detail::node_alloc_holder + ::type> +{ + /// @cond + typedef typename + containers_detail::intrusive_slist_type::type Icont; + typedef containers_detail::node_alloc_holder AllocHolder; + typedef typename AllocHolder::NodePtr NodePtr; + typedef slist ThisType; + typedef typename AllocHolder::NodeAlloc NodeAlloc; + typedef typename AllocHolder::ValAlloc ValAlloc; + typedef typename AllocHolder::Node Node; + typedef containers_detail::allocator_destroyer Destroyer; + typedef typename AllocHolder::allocator_v1 allocator_v1; + typedef typename AllocHolder::allocator_v2 allocator_v2; + typedef typename AllocHolder::alloc_version alloc_version; + + class equal_to_value + { + typedef typename AllocHolder::value_type value_type; + const value_type &t_; + + public: + equal_to_value(const value_type &t) + : t_(t) + {} + + bool operator()(const value_type &t)const + { return t_ == t; } + }; + + template + struct ValueCompareToNodeCompare + : Pred + { + ValueCompareToNodeCompare(Pred pred) + : Pred(pred) + {} + + bool operator()(const Node &a, const Node &b) const + { return static_cast(*this)(a.m_data, b.m_data); } + + bool operator()(const Node &a) const + { return static_cast(*this)(a.m_data); } + }; + /// @endcond + public: + //! The type of object, T, stored in the list + typedef T value_type; + //! Pointer to T + typedef typename A::pointer pointer; + //! Const pointer to T + typedef typename A::const_pointer const_pointer; + //! Reference to T + typedef typename A::reference reference; + //! Const reference to T + typedef typename A::const_reference const_reference; + //! An unsigned integral type + typedef typename A::size_type size_type; + //! A signed integral type + typedef typename A::difference_type difference_type; + //! The allocator type + typedef A allocator_type; + //! The stored allocator type + typedef NodeAlloc stored_allocator_type; + + /// @cond + private: + typedef difference_type list_difference_type; + typedef pointer list_pointer; + typedef const_pointer list_const_pointer; + typedef reference list_reference; + typedef const_reference list_const_reference; + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(slist) + + //! Const iterator used to iterate through a list. + class const_iterator + /// @cond + : public std::iterator + { + + protected: + typename Icont::iterator m_it; + explicit const_iterator(typename Icont::iterator it) : m_it(it){} + void prot_incr(){ ++m_it; } + + private: + typename Icont::iterator get() + { return this->m_it; } + + public: + friend class slist; + typedef list_difference_type difference_type; + + //Constructors + const_iterator() + : m_it() + {} + + //Pointer like operators + const_reference operator*() const + { return m_it->m_data; } + + const_pointer operator->() const + { return const_pointer(&m_it->m_data); } + + //Increment / Decrement + const_iterator& operator++() + { prot_incr(); return *this; } + + const_iterator operator++(int) + { typename Icont::iterator tmp = m_it; ++*this; return const_iterator(tmp); } + + //Comparison operators + bool operator== (const const_iterator& r) const + { return m_it == r.m_it; } + + bool operator!= (const const_iterator& r) const + { return m_it != r.m_it; } + } + /// @endcond + ; + + //! Iterator used to iterate through a list + class iterator + /// @cond + : public const_iterator + { + + private: + explicit iterator(typename Icont::iterator it) + : const_iterator(it) + {} + + typename Icont::iterator get() + { return this->m_it; } + + public: + friend class slist; + typedef list_pointer pointer; + typedef list_reference reference; + + //Constructors + iterator(){} + + //Pointer like operators + reference operator*() const { return this->m_it->m_data; } + pointer operator->() const { return pointer(&this->m_it->m_data); } + + //Increment / Decrement + iterator& operator++() + { this->prot_incr(); return *this; } + + iterator operator++(int) + { typename Icont::iterator tmp = this->m_it; ++*this; return iterator(tmp); } + } + /// @endcond + ; + + public: + //! Effects: Constructs a list taking the allocator as parameter. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + explicit slist(const allocator_type& a = allocator_type()) + : AllocHolder(a) + {} + + explicit slist(size_type n) + : AllocHolder(allocator_type()) + { this->resize(n); } + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + explicit slist(size_type n, const value_type& x, const allocator_type& a = allocator_type()) + : AllocHolder(a) + { this->priv_create_and_insert_nodes(this->before_begin(), n, x); } + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts a copy of the range [first, last) in the list. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's constructor taking an dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + slist(InpIt first, InpIt last, + const allocator_type& a = allocator_type()) + : AllocHolder(a) + { this->insert_after(this->before_begin(), first, last); } + + //! Effects: Copy constructs a list. + //! + //! Postcondition: x == *this. + //! + //! Throws: If allocator_type's default constructor or copy constructor throws. + //! + //! Complexity: Linear to the elements x contains. + slist(const slist& x) + : AllocHolder(x) + { this->insert_after(this->before_begin(), x.begin(), x.end()); } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + slist(BOOST_INTERPROCESS_RV_REF(slist) x) + : AllocHolder(boost::interprocess::move((AllocHolder&)x)) + {} + + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + slist& operator= (const slist& x) + { + if (&x != this){ + this->assign(x.begin(), x.end()); + } + return *this; + } + + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + slist& operator= (BOOST_INTERPROCESS_RV_REF(slist) mx) + { + if (&mx != this){ + this->clear(); + this->swap(mx); + } + return *this; + } + + //! Effects: Destroys the list. All stored values are destroyed + //! and used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements. + ~slist() + {} //AllocHolder clears the slist + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return allocator_type(this->node_alloc()); } + + const stored_allocator_type &get_stored_allocator() const + { return this->node_alloc(); } + + stored_allocator_type &get_stored_allocator() + { return this->node_alloc(); } + + public: + + //! Effects: Assigns the n copies of val to *this. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void assign(size_type n, const T& val) + { this->priv_fill_assign(n, val); } + + //! Effects: Assigns the range [first, last) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing InpIt throws. + //! + //! Complexity: Linear to n. + template + void assign(InpIt first, InpIt last) + { + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_assign_dispatch(first, last, Result()); + } + + //! Effects: Returns an iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return iterator(this->icont().begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return this->cbegin(); } + + //! Effects: Returns an iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return iterator(this->icont().end()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return this->cend(); } + + //! Effects: Returns a non-dereferenceable iterator that, + //! when incremented, yields begin(). This iterator may be used + //! as the argument toinsert_after, erase_after, etc. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator before_begin() + { return iterator(end()); } + + //! Effects: Returns a non-dereferenceable const_iterator + //! that, when incremented, yields begin(). This iterator may be used + //! as the argument toinsert_after, erase_after, etc. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator before_begin() const + { return this->cbefore_begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(this->non_const_icont().begin()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(this->non_const_icont().end()); } + + //! Effects: Returns a non-dereferenceable const_iterator + //! that, when incremented, yields begin(). This iterator may be used + //! as the argument toinsert_after, erase_after, etc. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbefore_begin() const + { return const_iterator(end()); } + + //! Effects: Returns the number of the elements contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return this->icont().size(); } + + //! Effects: Returns the largest possible size of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return AllocHolder::max_size(); } + + //! Effects: Returns true if the list contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return !this->size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() + //! allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements on *this and x. + void swap(slist& x) + { AllocHolder::swap(x); } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() + { return *this->begin(); } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const + { return *this->begin(); } + + //! Effects: Inserts a copy of t in the beginning of the list. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_front(const value_type& x) + { this->icont().push_front(*this->create_node(x)); } + + //! Effects: Constructs a new element in the beginning of the list + //! and moves the resources of t to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_front(BOOST_INTERPROCESS_RV_REF(T) x) + { this->icont().push_front(*this->create_node(boost::interprocess::move(x))); } + + //! Effects: Removes the first element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void pop_front() + { this->icont().pop_front_and_dispose(Destroyer(this->node_alloc())); } + + //! Returns: The iterator to the element before i in the sequence. + //! Returns the end-iterator, if either i is the begin-iterator or the + //! sequence is empty. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before i. + iterator previous(iterator p) + { return iterator(this->icont().previous(p.get())); } + + //! Returns: The const_iterator to the element before i in the sequence. + //! Returns the end-const_iterator, if either i is the begin-const_iterator or + //! the sequence is empty. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before i. + const_iterator previous(const_iterator p) + { return const_iterator(this->icont().previous(p.get())); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Inserts a copy of the value after the p pointed + //! by prev_p. + //! + //! Returns: An iterator to the inserted element. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + //! + //! Note: Does not affect the validity of iterators and references of + //! previous values. + iterator insert_after(const_iterator prev_pos, const value_type& x) + { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(x))); } + + //! Requires: prev_pos must be a valid iterator of *this. + //! + //! Effects: Inserts a move constructed copy object from the value after the + //! p pointed by prev_pos. + //! + //! Returns: An iterator to the inserted element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + //! + //! Note: Does not affect the validity of iterators and references of + //! previous values. + iterator insert_after(const_iterator prev_pos, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(boost::interprocess::move(x)))); } + + //! Requires: prev_pos must be a valid iterator of *this. + //! + //! Effects: Inserts n copies of x after prev_pos. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + //! + //! Note: Does not affect the validity of iterators and references of + //! previous values. + void insert_after(const_iterator prev_pos, size_type n, const value_type& x) + { this->priv_create_and_insert_nodes(prev_pos, n, x); } + + //! Requires: prev_pos must be a valid iterator of *this. + //! + //! Effects: Inserts the range pointed by [first, last) + //! after the p prev_pos. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws. + //! + //! Complexity: Linear to the number of elements inserted. + //! + //! Note: Does not affect the validity of iterators and references of + //! previous values. + template + void insert_after(const_iterator prev_pos, InIter first, InIter last) + { + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_after_range_dispatch(prev_pos, first, last, Result()); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before p. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: Linear to the elements before p. + iterator insert(const_iterator p, const value_type& x) + { return this->insert_after(previous(p), x); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a new element before p with mx's resources. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Linear to the elements before p. + iterator insert(const_iterator p, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return this->insert_after(previous(p), boost::interprocess::move(x)); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Inserts n copies of x before p. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n plus linear to the elements before p. + void insert(const_iterator p, size_type n, const value_type& x) + { return this->insert_after(previous(p), n, x); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [first, last) range before p. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws. + //! + //! Complexity: Linear to std::distance [first, last) plus + //! linear to the elements before p. + template + void insert(const_iterator p, InIter first, InIter last) + { return this->insert_after(previous(p), first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the front of the list + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + template + void emplace_front(Args&&... args) + { this->emplace_after(this->cbefore_begin(), boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before p + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Linear to the elements before p + template + iterator emplace(const_iterator p, Args&&... args) + { return this->emplace_after(this->previous(p), boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... after prev + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + iterator emplace_after(const_iterator prev, Args&&... args) + { + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); + new ((void*)containers_detail::get_pointer(d.get())) Node(boost::interprocess::forward(args)...); + NodePtr node = d.get(); + d.release(); + return iterator(this->icont().insert_after(prev.get(), *node)); + } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //0 args + void emplace_front() + { this->emplace_after(this->cbefore_begin()); } + + iterator emplace(const_iterator p) + { return this->emplace_after(this->previous(p)); } + + iterator emplace_after(const_iterator prev) + { + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); + new ((void*)containers_detail::get_pointer(d.get())) Node(); + NodePtr node = d.get(); + d.release(); + return iterator(this->icont().insert_after(prev.get(), *node)); + } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + void emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + this->emplace \ + (this->cbegin(), BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + } \ + \ + template \ + iterator emplace \ + (const_iterator p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return this->emplace_after \ + (this->previous(p), BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + } \ + \ + template \ + iterator emplace_after \ + (const_iterator prev, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); \ + new ((void*)containers_detail::get_pointer(d.get())) \ + Node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + NodePtr node = d.get(); \ + d.release(); \ + return iterator(this->icont().insert_after(prev.get(), *node)); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element after the element pointed by prev_pos + //! of the list. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not invalidate iterators or references to non erased elements. + iterator erase_after(const_iterator prev_pos) + { + return iterator(this->icont().erase_after_and_dispose(prev_pos.get(), Destroyer(this->node_alloc()))); + } + + //! Effects: Erases the range (before_first, last) from + //! the list. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of erased elements. + //! + //! Note: Does not invalidate iterators or references to non erased elements. + iterator erase_after(const_iterator before_first, const_iterator last) + { + return iterator(this->icont().erase_after_and_dispose(before_first.get(), last.get(), Destroyer(this->node_alloc()))); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Erases the element at p p. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before p. + iterator erase(const_iterator p) + { return iterator(this->erase_after(previous(p))); } + + //! Requires: first and last must be valid iterator to elements in *this. + //! + //! Effects: Erases the elements pointed by [first, last). + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the distance between first and last plus + //! linear to the elements before first. + iterator erase(const_iterator first, const_iterator last) + { return iterator(this->erase_after(previous(first), last)); } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size, const T& x) + { + typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next; + while (++(cur_next = cur) != end_n && new_size > 0){ + --new_size; + cur = cur_next; + } + if (cur_next != end_n) + this->erase_after(const_iterator(cur), const_iterator(end_n)); + else + this->insert_after(const_iterator(cur), new_size, x); + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size) + { + typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next; + size_type len = this->size(); + size_type left = new_size; + + while (++(cur_next = cur) != end_n && left > 0){ + --left; + cur = cur_next; + } + if (cur_next != end_n){ + this->erase_after(const_iterator(cur), const_iterator(end_n)); + } + else{ + this->priv_create_and_insert_nodes(const_iterator(cur), new_size - len); + } + } + + //! Effects: Erases all the elements of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements in the list. + void clear() + { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); } + + //! Requires: p must point to an element contained + //! by the list. x != *this + //! + //! Effects: Transfers all the elements of list x to this list, after the + //! the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear to the elements in x. + //! + //! Note: Iterators of values obtained from list x now point to elements of + //! this list. Iterators of this list and all the references are not invalidated. + void splice_after(const_iterator prev_pos, slist& x) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice_after(prev_pos.get(), x.icont()); + } + else{ + throw std::runtime_error("slist::splice called with unequal allocators"); + } + } + + //! Requires: prev_pos must be a valid iterator of this. + //! i must point to an element contained in list x. + //! + //! Effects: Transfers the value pointed by i, from list x to this list, + //! after the element pointed by prev_pos. + //! If prev_pos == prev or prev_pos == ++prev, this function is a null operation. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice_after(const_iterator prev_pos, slist& x, const_iterator prev) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice_after(prev_pos.get(), x.icont(), prev.get()); + } + else{ + throw std::runtime_error("slist::splice called with unequal allocators"); + } + } + + //! Requires: prev_pos must be a valid iterator of this. + //! before_first and before_last must be valid iterators of x. + //! prev_pos must not be contained in [before_first, before_last) range. + //! + //! Effects: Transfers the range [before_first + 1, before_last + 1) + //! from list x to this list, after the element pointed by prev_pos. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear to the number of transferred elements. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice_after(const_iterator prev_pos, slist& x, + const_iterator before_first, const_iterator before_last) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice_after + (prev_pos.get(), x.icont(), before_first.get(), before_last.get()); + } + else{ + throw std::runtime_error("slist::splice called with unequal allocators"); + } + } + + //! Requires: prev_pos must be a valid iterator of this. + //! before_first and before_last must be valid iterators of x. + //! prev_pos must not be contained in [before_first, before_last) range. + //! n == std::distance(before_first, before_last) + //! + //! Effects: Transfers the range [before_first + 1, before_last + 1) + //! from list x to this list, after the element pointed by prev_pos. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice_after(const_iterator prev_pos, slist& x, + const_iterator before_first, const_iterator before_last, + size_type n) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice_after + (prev_pos.get(), x.icont(), before_first.get(), before_last.get(), n); + } + else{ + throw std::runtime_error("slist::splice called with unequal allocators"); + } + } + + //! Requires: p must point to an element contained + //! by the list. x != *this + //! + //! Effects: Transfers all the elements of list x to this list, before the + //! the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), and linear in x.size(). + //! + //! Note: Iterators of values obtained from list x now point to elements of + //! this list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, ThisType& x) + { this->splice_after(this->previous(p), x); } + + //! Requires: p must point to an element contained + //! by this list. i must point to an element contained in list x. + //! + //! Effects: Transfers the value pointed by i, from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! If p == i or p == ++i, this function is a null operation. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), and in distance(x.begin(), i). + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, slist& x, const_iterator i) + { this->splice_after(previous(p), x, i); } + + //! Requires: p must point to an element contained + //! by this list. first and last must point to elements contained in list x. + //! + //! Effects: Transfers the range pointed by first and last from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), in distance(x.begin(), first), + //! and in distance(first, last). + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, slist& x, const_iterator first, const_iterator last) + { this->splice_after(previous(p), x, previous(first), previous(last)); } + + //! Effects: Reverses the order of elements in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time. + //! + //! Note: Iterators and references are not invalidated + void reverse() + { this->icont().reverse(); } + + //! Effects: Removes all the elements that compare equal to value. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + void remove(const T& value) + { remove_if(equal_to_value(value)); } + + //! Effects: Removes all the elements for which a specified + //! predicate is satisfied. + //! + //! Throws: If pred throws. + //! + //! Complexity: Linear time. It performs exactly size() calls to the predicate. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_if(Pred pred) + { + typedef ValueCompareToNodeCompare Predicate; + this->icont().remove_and_dispose_if(Predicate(pred), Destroyer(this->node_alloc())); + } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that are equal from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear time (size()-1 comparisons calls to pred()). + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + void unique() + { this->unique(value_equal()); } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that satisfy some binary predicate from the list. + //! + //! Throws: If pred throws. + //! + //! Complexity: Linear time (size()-1 comparisons equality comparisons). + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique(Pred pred) + { + typedef ValueCompareToNodeCompare Predicate; + this->icont().unique_and_dispose(Predicate(pred), Destroyer(this->node_alloc())); + } + + //! Requires: The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this according to std::less. The merge is stable; + //! that is, if an element from *this is equivalent to one from x, then the element + //! from *this will precede the one from x. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + void merge(slist & x) + { this->merge(x, value_less()); } + + //! Requires: p must be a comparison function that induces a strict weak + //! ordering and both *this and x must be sorted according to that ordering + //! The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this. The merge is stable; that is, if an element from *this is + //! equivalent to one from x, then the element from *this will precede the one from x. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references to *this are not invalidated. + template + void merge(slist& x, StrictWeakOrdering comp) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().merge(x.icont(), + ValueCompareToNodeCompare(comp)); + } + else{ + throw std::runtime_error("list::merge called with unequal allocators"); + } + } + + //! Effects: This function sorts the list *this according to std::less. + //! The sort is stable, that is, the relative order of equivalent elements is preserved. + //! + //! Throws: Nothing. + //! + //! Notes: Iterators and references are not invalidated. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + void sort() + { this->sort(value_less()); } + + //! Effects: This function sorts the list *this according to std::less. + //! The sort is stable, that is, the relative order of equivalent elements is preserved. + //! + //! Throws: Nothing. + //! + //! Notes: Iterators and references are not invalidated. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + template + void sort(StrictWeakOrdering comp) + { + // nothing if the slist has length 0 or 1. + if (this->size() < 2) + return; + this->icont().sort(ValueCompareToNodeCompare(comp)); + } + + /// @cond + private: + + //Iterator range version + template + void priv_create_and_insert_nodes + (const_iterator prev, InpIterator beg, InpIterator end) + { + typedef typename std::iterator_traits::iterator_category ItCat; + priv_create_and_insert_nodes(prev, beg, end, alloc_version(), ItCat()); + } + + template + void priv_create_and_insert_nodes + (const_iterator prev, InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) + { + for (; beg != end; ++beg){ + this->icont().insert_after(prev.get(), *this->create_node_from_it(beg)); + ++prev; + } + } + + template + void priv_create_and_insert_nodes + (const_iterator prev, InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) + { //Just forward to the default one + priv_create_and_insert_nodes(prev, beg, end, allocator_v1(), std::input_iterator_tag()); + } + + class insertion_functor; + friend class insertion_functor; + + class insertion_functor + { + Icont &icont_; + typename Icont::const_iterator prev_; + + public: + insertion_functor(Icont &icont, typename Icont::const_iterator prev) + : icont_(icont), prev_(prev) + {} + + void operator()(Node &n) + { prev_ = this->icont_.insert_after(prev_, n); } + }; + + template + void priv_create_and_insert_nodes + (const_iterator prev, FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag) + { + //Optimized allocation and construction + this->allocate_many_and_construct + (beg, std::distance(beg, end), insertion_functor(this->icont(), prev.get())); + } + + //Default constructed version + void priv_create_and_insert_nodes(const_iterator prev, size_type n) + { + typedef default_construct_iterator default_iterator; + this->priv_create_and_insert_nodes(prev, default_iterator(n), default_iterator()); + } + + //Copy constructed version + void priv_create_and_insert_nodes(const_iterator prev, size_type n, const T& x) + { + typedef constant_iterator cvalue_iterator; + this->priv_create_and_insert_nodes(prev, cvalue_iterator(x, n), cvalue_iterator()); + } + + //Dispatch to detect iterator range or integer overloads + template + void priv_insert_dispatch(const_iterator prev, + InputIter first, InputIter last, + containers_detail::false_) + { this->priv_create_and_insert_nodes(prev, first, last); } + + template + void priv_insert_dispatch(const_iterator prev, Integer n, Integer x, containers_detail::true_) + { this->priv_create_and_insert_nodes(prev, n, x); } + + void priv_fill_assign(size_type n, const T& val) + { + iterator end_n(this->end()); + iterator prev(this->before_begin()); + iterator node(this->begin()); + for ( ; node != end_n && n > 0 ; --n){ + *node = val; + prev = node; + ++node; + } + if (n > 0) + this->priv_create_and_insert_nodes(prev, n, val); + else + this->erase_after(prev, end_n); + } + + template + void priv_assign_dispatch(Int n, Int val, containers_detail::true_) + { this->priv_fill_assign((size_type) n, (T)val); } + + template + void priv_assign_dispatch(InpIt first, InpIt last, containers_detail::false_) + { + iterator end_n(this->end()); + iterator prev(this->before_begin()); + iterator node(this->begin()); + while (node != end_n && first != last){ + *node = *first; + prev = node; + ++node; + ++first; + } + if (first != last) + this->priv_create_and_insert_nodes(prev, first, last); + else + this->erase_after(prev, end_n); + } + + template + void priv_insert_after_range_dispatch(const_iterator prev_pos, Int n, Int x, containers_detail::true_) + { this->priv_create_and_insert_nodes(prev_pos, n, x); } + + template + void priv_insert_after_range_dispatch(const_iterator prev_pos, InIter first, InIter last, containers_detail::false_) + { this->priv_create_and_insert_nodes(prev_pos, first, last); } + + //Functors for member algorithm defaults + struct value_less + { + bool operator()(const value_type &a, const value_type &b) const + { return a < b; } + }; + + struct value_equal + { + bool operator()(const value_type &a, const value_type &b) const + { return a == b; } + }; + + struct value_equal_to_this + { + explicit value_equal_to_this(const value_type &ref) + : m_ref(ref){} + + bool operator()(const value_type &val) const + { return m_ref == val; } + + const value_type &m_ref; + }; + /// @endcond +}; + +template +inline bool +operator==(const slist& x, const slist& y) +{ + if(x.size() != y.size()){ + return false; + } + typedef typename slist::const_iterator const_iterator; + const_iterator end1 = x.end(); + + const_iterator i1 = x.begin(); + const_iterator i2 = y.begin(); + while (i1 != end1 && *i1 == *i2){ + ++i1; + ++i2; + } + return i1 == end1; +} + +template +inline bool +operator<(const slist& sL1, const slist& sL2) +{ + return std::lexicographical_compare + (sL1.begin(), sL1.end(), sL2.begin(), sL2.end()); +} + +template +inline bool +operator!=(const slist& sL1, const slist& sL2) + { return !(sL1 == sL2); } + +template +inline bool +operator>(const slist& sL1, const slist& sL2) + { return sL2 < sL1; } + +template +inline bool +operator<=(const slist& sL1, const slist& sL2) + { return !(sL2 < sL1); } + +template +inline bool +operator>=(const slist& sL1, const slist& sL2) + { return !(sL1 < sL2); } + +template +inline void swap(slist& x, slist& y) + { x.swap(y); } + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} //namespace boost{ namespace interprocess_container { + +// Specialization of insert_iterator so that insertions will be constant +// time rather than linear time. + +///@cond + +//Ummm, I don't like to define things in namespace std, but +//there is no other way +namespace std { + +template +class insert_iterator > +{ + protected: + typedef boost::interprocess_container::slist Container; + Container* container; + typename Container::iterator iter; + public: + typedef Container container_type; + typedef output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; + + insert_iterator(Container& x, + typename Container::iterator i, + bool is_previous = false) + : container(&x), iter(is_previous ? i : x.previous(i)){ } + + insert_iterator& + operator=(const typename Container::value_type& value) + { + iter = container->insert_after(iter, value); + return *this; + } + insert_iterator& operator*(){ return *this; } + insert_iterator& operator++(){ return *this; } + insert_iterator& operator++(int){ return *this; } +}; + +} //namespace std; + +///@endcond + +#include + +#endif /* BOOST_CONTAINERS_SLIST_HPP */ diff --git a/include/boost/interprocess/containers/container/stable_vector.hpp b/include/boost/interprocess/containers/container/stable_vector.hpp new file mode 100644 index 0000000..c530226 --- /dev/null +++ b/include/boost/interprocess/containers/container/stable_vector.hpp @@ -0,0 +1,1352 @@ +/* Stable vector. + * + * Copyright 2008 Joaquin M Lopez Munoz. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#ifndef STABLE_VECTOR_HPP_3A7EB5C0_55BF_11DD_AE16_0800200C9A66 +#define STABLE_VECTOR_HPP_3A7EB5C0_55BF_11DD_AE16_0800200C9A66 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STABLE_VECTOR_USE_CONTAINERS_VECTOR + +#if defined (STABLE_VECTOR_USE_CONTAINERS_VECTOR) +#include +#else +#include +#endif //STABLE_VECTOR_USE_CONTAINERS_VECTOR + +//#define STABLE_VECTOR_ENABLE_INVARIANT_CHECKING + +#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) +#include +#endif + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond + +namespace stable_vector_detail{ + +template +struct smart_ptr_type +{ + typedef typename SmartPtr::value_type value_type; + typedef value_type *pointer; + static pointer get (const SmartPtr &smartptr) + { return smartptr.get();} +}; + +template +struct smart_ptr_type +{ + typedef T value_type; + typedef value_type *pointer; + static pointer get (pointer ptr) + { return ptr;} +}; + +template +inline typename smart_ptr_type::pointer get_pointer(const Ptr &ptr) +{ return smart_ptr_type::get(ptr); } + +template +class clear_on_destroy +{ + public: + clear_on_destroy(C &c) + : c_(c), do_clear_(true) + {} + + void release() + { do_clear_ = false; } + + ~clear_on_destroy() + { + if(do_clear_){ + c_.clear(); + c_.clear_pool(); + } + } + + private: + C &c_; + bool do_clear_; +}; + +template +class constant_iterator + : public std::iterator + +{ + typedef constant_iterator this_type; + + public: + explicit constant_iterator(const T &ref, Difference range_size) + : m_ptr(&ref), m_num(range_size){} + + //Constructors + constant_iterator() + : m_ptr(0), m_num(0){} + + constant_iterator& operator++() + { increment(); return *this; } + + constant_iterator operator++(int) + { + constant_iterator result (*this); + increment(); + return result; + } + + friend bool operator== (const constant_iterator& i, const constant_iterator& i2) + { return i.equal(i2); } + + friend bool operator!= (const constant_iterator& i, const constant_iterator& i2) + { return !(i == i2); } + + friend bool operator< (const constant_iterator& i, const constant_iterator& i2) + { return i.less(i2); } + + friend bool operator> (const constant_iterator& i, const constant_iterator& i2) + { return i2 < i; } + + friend bool operator<= (const constant_iterator& i, const constant_iterator& i2) + { return !(i > i2); } + + friend bool operator>= (const constant_iterator& i, const constant_iterator& i2) + { return !(i < i2); } + + friend Difference operator- (const constant_iterator& i, const constant_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + constant_iterator& operator+=(Difference off) + { this->advance(off); return *this; } + + constant_iterator operator+(Difference off) const + { + constant_iterator other(*this); + other.advance(off); + return other; + } + + friend constant_iterator operator+(Difference off, const constant_iterator& right) + { return right + off; } + + constant_iterator& operator-=(Difference off) + { this->advance(-off); return *this; } + + constant_iterator operator-(Difference off) const + { return *this + (-off); } + + const T& operator*() const + { return dereference(); } + + const T* operator->() const + { return &(dereference()); } + + private: + const T * m_ptr; + Difference m_num; + + void increment() + { --m_num; } + + void decrement() + { ++m_num; } + + bool equal(const this_type &other) const + { return m_num == other.m_num; } + + bool less(const this_type &other) const + { return other.m_num < m_num; } + + const T & dereference() const + { return *m_ptr; } + + void advance(Difference n) + { m_num -= n; } + + Difference distance_to(const this_type &other)const + { return m_num - other.m_num; } +}; + +template +struct node_type_base +{/* + node_type_base(VoidPtr p) + : up(p) + {}*/ + node_type_base() + {} + void set_pointer(VoidPtr p) + { up = p; } + + VoidPtr up; +}; + +template +struct node_type + : public node_type_base +{ + #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + node_type() + : value() + {} + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + node_type(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : value(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ + {} \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #else //#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + template + node_type(Args &&...args) + : value(boost::interprocess::forward(args)...) + {} + #endif//#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + void set_pointer(VoidPointer p) + { node_type_base::set_pointer(p); } + + T value; +}; + +template +class iterator + : public std::iterator< std::random_access_iterator_tag + , const typename std::iterator_traits::value_type + , typename std::iterator_traits::difference_type + , Pointer + , Value &> +{ + + typedef typename boost::pointer_to_other + ::type void_ptr; + typedef node_type node_type_t; + typedef typename boost::pointer_to_other + ::type node_type_ptr_t; + typedef typename boost::pointer_to_other + ::type void_ptr_ptr; + + friend class iterator::type>; + + public: + typedef std::random_access_iterator_tag iterator_category; + typedef Value value_type; + typedef typename std::iterator_traits + ::difference_type difference_type; + typedef Pointer pointer; + typedef Value & reference; + + iterator() + {} + + explicit iterator(node_type_ptr_t pn) + : pn(pn) + {} + + iterator(const iterator::type >& x) + : pn(x.pn) + {} + + private: + static node_type_ptr_t node_ptr_cast(void_ptr p) + { + using boost::get_pointer; + return node_type_ptr_t(static_cast(stable_vector_detail::get_pointer(p))); + } + + static void_ptr_ptr void_ptr_ptr_cast(void_ptr p) + { + using boost::get_pointer; + return void_ptr_ptr(static_cast(stable_vector_detail::get_pointer(p))); + } + + Value& dereference() const + { return pn->value; } + bool equal(const iterator& x) const + { return pn==x.pn; } + void increment() + { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+1)); } + void decrement() + { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)-1)); } + void advance(std::ptrdiff_t n) + { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+n)); } + std::ptrdiff_t distance_to(const iterator& x)const + { return void_ptr_ptr_cast(x.pn->up) - void_ptr_ptr_cast(pn->up); } + + public: + //Pointer like operators + reference operator*() const { return this->dereference(); } + pointer operator->() const { return pointer(&this->dereference()); } + + //Increment / Decrement + iterator& operator++() + { this->increment(); return *this; } + + iterator operator++(int) + { iterator tmp(*this); ++*this; return iterator(tmp); } + + iterator& operator--() + { this->decrement(); return *this; } + + iterator operator--(int) + { iterator tmp(*this); --*this; return iterator(tmp); } + + reference operator[](difference_type off) const + { + iterator tmp(*this); + tmp += off; + return *tmp; + } + + iterator& operator+=(difference_type off) + { + pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+off)); + return *this; + } + + iterator operator+(difference_type off) const + { + iterator tmp(*this); + tmp += off; + return tmp; + } + + friend iterator operator+(difference_type off, const iterator& right) + { + iterator tmp(right); + tmp += off; + return tmp; + } + + iterator& operator-=(difference_type off) + { *this += -off; return *this; } + + iterator operator-(difference_type off) const + { + iterator tmp(*this); + tmp -= off; + return tmp; + } + + difference_type operator-(const iterator& right) const + { + void_ptr_ptr p1 = void_ptr_ptr_cast(this->pn->up); + void_ptr_ptr p2 = void_ptr_ptr_cast(right.pn->up); + return p1 - p2; + } + + //Comparison operators + bool operator== (const iterator& r) const + { return pn == r.pn; } + + bool operator!= (const iterator& r) const + { return pn != r.pn; } + + bool operator< (const iterator& r) const + { return void_ptr_ptr_cast(pn->up) < void_ptr_ptr_cast(r.pn->up); } + + bool operator<= (const iterator& r) const + { return void_ptr_ptr_cast(pn->up) <= void_ptr_ptr_cast(r.pn->up); } + + bool operator> (const iterator& r) const + { return void_ptr_ptr_cast(pn->up) > void_ptr_ptr_cast(r.pn->up); } + + bool operator>= (const iterator& r) const + { return void_ptr_ptr_cast(pn->up) >= void_ptr_ptr_cast(r.pn->up); } + + node_type_ptr_t pn; +}; + +/* +class node_access +{ + public: + template + static typename iterator::node_type_t* get(const iterator& it) + { + return stable_vector_detail::get_pointer(it.pn); + } +}; +*/ + +template +struct select_multiallocation_chain +{ + typedef typename Allocator::multiallocation_chain type; +}; + +template +struct select_multiallocation_chain +{ + typedef typename Allocator::template + rebind::other::pointer void_ptr; + typedef containers_detail::basic_multiallocation_cached_slist multialloc_cached; + typedef containers_detail::basic_multiallocation_cached_counted_slist + multialloc_cached_counted; + typedef boost::interprocess_container::containers_detail::transform_multiallocation_chain + type; +}; + +} //namespace stable_vector_detail + +#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) + +#define STABLE_VECTOR_CHECK_INVARIANT \ +invariant_checker BOOST_JOIN(check_invariant_,__LINE__)(*this); \ +BOOST_JOIN(check_invariant_,__LINE__).touch(); +#else + +#define STABLE_VECTOR_CHECK_INVARIANT + +#endif //#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) + +/// @endcond + +template > +class stable_vector +{ + typedef typename Allocator::template + rebind::other::pointer void_ptr; + typedef typename Allocator::template + rebind::other::pointer void_ptr_ptr; + typedef stable_vector_detail::node_type + node_type_t; + typedef typename Allocator::template + rebind::other::pointer node_type_ptr_t; + typedef stable_vector_detail::node_type_base + node_type_base_t; + typedef typename Allocator::template + rebind::other::pointer node_type_base_ptr_t; + typedef + #if defined (STABLE_VECTOR_USE_CONTAINERS_VECTOR) + ::boost::interprocess_container:: + #else + ::std:: + #endif //STABLE_VECTOR_USE_CONTAINERS_VECTOR + vector::other + > impl_type; + typedef typename impl_type::iterator impl_iterator; + typedef typename impl_type::const_iterator const_impl_iterator; + + typedef ::boost::interprocess_container::containers_detail:: + integral_constant allocator_v1; + typedef ::boost::interprocess_container::containers_detail:: + integral_constant allocator_v2; + typedef ::boost::interprocess_container::containers_detail::integral_constant + ::value> alloc_version; + typedef typename Allocator:: + template rebind::other node_allocator_type; + + node_type_ptr_t allocate_one() + { return this->allocate_one(alloc_version()); } + + node_type_ptr_t allocate_one(allocator_v1) + { return get_al().allocate(1); } + + node_type_ptr_t allocate_one(allocator_v2) + { return get_al().allocate_one(); } + + void deallocate_one(node_type_ptr_t p) + { return this->deallocate_one(p, alloc_version()); } + + void deallocate_one(node_type_ptr_t p, allocator_v1) + { get_al().deallocate(p, 1); } + + void deallocate_one(node_type_ptr_t p, allocator_v2) + { get_al().deallocate_one(p); } + + friend class stable_vector_detail::clear_on_destroy; + + public: + // types: + + typedef typename Allocator::reference reference; + typedef typename Allocator::const_reference const_reference; + typedef typename Allocator::pointer pointer; + typedef typename Allocator::const_pointer const_pointer; + typedef stable_vector_detail::iterator + iterator; + typedef stable_vector_detail::iterator + const_iterator; + typedef typename impl_type::size_type size_type; + typedef typename iterator::difference_type difference_type; + typedef T value_type; + typedef Allocator allocator_type; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + private: + static const size_type ExtraPointers = 3; + typedef typename stable_vector_detail:: + select_multiallocation_chain + < node_allocator_type + , alloc_version::value + >::type multiallocation_chain; + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(stable_vector) + + // construct/copy/destroy: + explicit stable_vector(const Allocator& al=Allocator()) + : internal_data(al),impl(al) + { + STABLE_VECTOR_CHECK_INVARIANT; + } + + stable_vector(size_type n,const T& t=T(),const Allocator& al=Allocator()) + : internal_data(al),impl(al) + { + stable_vector_detail::clear_on_destroy cod(*this); + this->insert(this->cbegin(), n, t); + STABLE_VECTOR_CHECK_INVARIANT; + cod.release(); + } + + template + stable_vector(InputIterator first,InputIterator last,const Allocator& al=Allocator()) + : internal_data(al),impl(al) + { + stable_vector_detail::clear_on_destroy cod(*this); + this->insert(this->cbegin(), first, last); + STABLE_VECTOR_CHECK_INVARIANT; + cod.release(); + } + + stable_vector(const stable_vector& x) + : internal_data(x.get_al()),impl(x.get_al()) + { + stable_vector_detail::clear_on_destroy cod(*this); + this->insert(this->cbegin(), x.begin(), x.end()); + STABLE_VECTOR_CHECK_INVARIANT; + cod.release(); + } + + stable_vector(BOOST_INTERPROCESS_RV_REF(stable_vector) x) + : internal_data(x.get_al()),impl(x.get_al()) + { this->swap(x); } + + ~stable_vector() + { + this->clear(); + clear_pool(); + } + + stable_vector& operator=(const stable_vector &x) + { + STABLE_VECTOR_CHECK_INVARIANT; + if (this != &x) { + this->assign(x.begin(), x.end()); + } + return *this; + } + + stable_vector& operator=(BOOST_INTERPROCESS_RV_REF(stable_vector) x) + { + if (&x != this){ + this->swap(x); + x.clear(); + } + return *this; + } + + template + void assign(InputIterator first,InputIterator last) + { + assign_dispatch(first, last, boost::is_integral()); + } + + void assign(size_type n,const T& t) + { + typedef stable_vector_detail::constant_iterator cvalue_iterator; + return assign_dispatch(cvalue_iterator(t, n), cvalue_iterator(), boost::mpl::false_()); + } + + allocator_type get_allocator()const {return get_al();} + + // iterators: + + iterator begin() + { return (impl.empty()) ? end(): iterator(node_ptr_cast(impl.front())) ; } + + const_iterator begin()const + { return (impl.empty()) ? cend() : const_iterator(node_ptr_cast(impl.front())) ; } + + iterator end() {return iterator(get_end_node());} + const_iterator end()const {return const_iterator(get_end_node());} + + reverse_iterator rbegin() {return reverse_iterator(this->end());} + const_reverse_iterator rbegin()const {return const_reverse_iterator(this->end());} + reverse_iterator rend() {return reverse_iterator(this->begin());} + const_reverse_iterator rend()const {return const_reverse_iterator(this->begin());} + + const_iterator cbegin()const {return this->begin();} + const_iterator cend()const {return this->end();} + const_reverse_iterator crbegin()const{return this->rbegin();} + const_reverse_iterator crend()const {return this->rend();} + + // capacity: + size_type size() const + { return impl.empty() ? 0 : (impl.size() - ExtraPointers); } + + size_type max_size() const + { return impl.max_size() - ExtraPointers; } + + size_type capacity() const + { + if(!impl.capacity()){ + return 0; + } + else{ + const size_type num_nodes = this->impl.size() + this->internal_data.pool_size; + const size_type num_buck = this->impl.capacity(); + return (num_nodes < num_buck) ? num_nodes : num_buck; + } + } + + bool empty() const + { return impl.empty() || impl.size() == ExtraPointers; } + + void resize(size_type n, const T& t) + { + STABLE_VECTOR_CHECK_INVARIANT; + if(n > size()) + this->insert(this->cend(), n - this->size(), t); + else if(n < this->size()) + this->erase(this->cbegin() + n, this->cend()); + } + + void resize(size_type n) + { + typedef default_construct_iterator default_iterator; + STABLE_VECTOR_CHECK_INVARIANT; + if(n > size()) + this->insert(this->cend(), default_iterator(n - this->size()), default_iterator()); + else if(n < this->size()) + this->erase(this->cbegin() + n, this->cend()); + } + + void reserve(size_type n) + { + STABLE_VECTOR_CHECK_INVARIANT; + if(n > this->max_size()) + throw std::bad_alloc(); + + size_type size = this->size(); + size_type old_capacity = this->capacity(); + if(n > old_capacity){ + this->initialize_end_node(n); + const void * old_ptr = &impl[0]; + impl.reserve(n + ExtraPointers); + bool realloced = &impl[0] != old_ptr; + //Fix the pointers for the newly allocated buffer + if(realloced){ + this->align_nodes(impl.begin(), impl.begin()+size+1); + } + //Now fill pool if data is not enough + if((n - size) > this->internal_data.pool_size){ + this->add_to_pool((n - size) - this->internal_data.pool_size, alloc_version()); + } + } + } + + template + void clear_pool(AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::value>::type * = 0) + { + if(!impl.empty() && impl.back()){ + void_ptr &p1 = *(impl.end()-2); + void_ptr &p2 = impl.back(); + + multiallocation_chain holder(p1, p2, this->internal_data.pool_size); + while(!holder.empty()){ + node_type_ptr_t n = holder.front(); + holder.pop_front(); + this->deallocate_one(n); + } + p1 = p2 = 0; + this->internal_data.pool_size = 0; + } + } + + template + void clear_pool(AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::value>::type * = 0) + { + + if(!impl.empty() && impl.back()){ + void_ptr &p1 = *(impl.end()-2); + void_ptr &p2 = impl.back(); + multiallocation_chain holder(p1, p2, this->internal_data.pool_size); + get_al().deallocate_individual(boost::interprocess::move(holder)); + p1 = p2 = 0; + this->internal_data.pool_size = 0; + } + } + + void clear_pool() + { + this->clear_pool(alloc_version()); + } + + template + void add_to_pool(size_type n, AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::value>::type * = 0) + { + size_type remaining = n; + while(remaining--){ + this->put_in_pool(this->allocate_one()); + } + } + + template + void add_to_pool(size_type n, AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::value>::type * = 0) + { + void_ptr &p1 = *(impl.end()-2); + void_ptr &p2 = impl.back(); + multiallocation_chain holder(p1, p2, this->internal_data.pool_size); + BOOST_STATIC_ASSERT((boost::interprocess::is_movable::value == true)); + multiallocation_chain m (get_al().allocate_individual(n)); + holder.splice_after(holder.before_begin(), m, m.before_begin(), m.last(), n); + this->internal_data.pool_size += n; + std::pair data(holder.extract_data()); + p1 = data.first; + p2 = data.second; + } + + void put_in_pool(node_type_ptr_t p) + { + void_ptr &p1 = *(impl.end()-2); + void_ptr &p2 = impl.back(); + multiallocation_chain holder(p1, p2, internal_data.pool_size); + holder.push_front(p); + ++this->internal_data.pool_size; + std::pair ret(holder.extract_data()); + p1 = ret.first; + p2 = ret.second; + } + + node_type_ptr_t get_from_pool() + { + if(!impl.back()){ + return node_type_ptr_t(0); + } + else{ + void_ptr &p1 = *(impl.end()-2); + void_ptr &p2 = impl.back(); + multiallocation_chain holder(p1, p2, internal_data.pool_size); + node_type_ptr_t ret = holder.front(); + holder.pop_front(); + std::pair data(holder.extract_data()); + p1 = data.first; + p2 = data.second; + --this->internal_data.pool_size; + return ret; + } + } + + // element access: + + reference operator[](size_type n){return value(impl[n]);} + const_reference operator[](size_type n)const{return value(impl[n]);} + + const_reference at(size_type n)const + { + if(n>=size()) + throw std::out_of_range("invalid subscript at stable_vector::at"); + return operator[](n); + } + + reference at(size_type n) + { + if(n>=size()) + throw std::out_of_range("invalid subscript at stable_vector::at"); + return operator[](n); + } + + reference front() + { return value(impl.front()); } + + const_reference front()const + { return value(impl.front()); } + + reference back() + { return value(*(&impl.back() - ExtraPointers)); } + + const_reference back()const + { return value(*(&impl.back() - ExtraPointers)); } + + // modifiers: + + void push_back(const T& t) + { this->insert(end(), t); } + + void push_back(BOOST_INTERPROCESS_RV_REF(T) t) + { this->insert(end(), boost::interprocess::move(t)); } + + void pop_back() + { this->erase(this->end()-1); } + + iterator insert(const_iterator position, const T& t) + { + typedef stable_vector_detail::constant_iterator cvalue_iterator; + return this->insert_iter(position, cvalue_iterator(t, 1), cvalue_iterator(), std::forward_iterator_tag()); + } + + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(T) x) + { + typedef repeat_iterator repeat_it; + typedef boost::interprocess::move_iterator repeat_move_it; + //Just call more general insert(pos, size, value) and return iterator + size_type pos_n = position - cbegin(); + this->insert(position + ,repeat_move_it(repeat_it(x, 1)) + ,repeat_move_it(repeat_it())); + return iterator(this->begin() + pos_n); + } + + void insert(const_iterator position, size_type n, const T& t) + { + STABLE_VECTOR_CHECK_INVARIANT; + this->insert_not_iter(position, n, t); + } + + template + void insert(const_iterator position,InputIterator first, InputIterator last) + { + STABLE_VECTOR_CHECK_INVARIANT; + this->insert_iter(position,first,last, + boost::mpl::not_ >()); + } + + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the vector. + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: Amortized constant time. + template + void emplace_back(Args &&...args) + { + typedef emplace_functor EmplaceFunctor; + typedef emplace_iterator EmplaceIterator; + EmplaceFunctor ef(boost::interprocess::forward(args)...); + this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); + } + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before position + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + template + iterator emplace(const_iterator position, Args && ...args) + { + //Just call more general insert(pos, size, value) and return iterator + size_type pos_n = position - cbegin(); + typedef emplace_functor EmplaceFunctor; + typedef emplace_iterator EmplaceIterator; + EmplaceFunctor ef(boost::interprocess::forward(args)...); + this->insert(position, EmplaceIterator(ef), EmplaceIterator()); + return iterator(this->begin() + pos_n); + } + + #else + + void emplace_back() + { + typedef emplace_functor EmplaceFunctor; + typedef emplace_iterator EmplaceIterator; + EmplaceFunctor ef; + this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); + } + + iterator emplace(const_iterator position) + { + typedef emplace_functor EmplaceFunctor; + typedef emplace_iterator EmplaceIterator; + EmplaceFunctor ef; + size_type pos_n = position - this->cbegin(); + this->insert(position, EmplaceIterator(ef), EmplaceIterator()); + return iterator(this->begin() + pos_n); + } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + typedef BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + EmplaceFunctor; \ + typedef emplace_iterator EmplaceIterator; \ + EmplaceFunctor ef(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); \ + } \ + \ + template \ + iterator emplace(const_iterator pos, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + typedef BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + EmplaceFunctor; \ + typedef emplace_iterator EmplaceIterator; \ + EmplaceFunctor ef(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + size_type pos_n = pos - this->cbegin(); \ + this->insert(pos, EmplaceIterator(ef), EmplaceIterator()); \ + return iterator(this->begin() + pos_n); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator erase(const_iterator position) + { + STABLE_VECTOR_CHECK_INVARIANT; + difference_type d=position-this->cbegin(); + impl_iterator it=impl.begin()+d; + this->delete_node(*it); + impl.erase(it); + this->align_nodes(impl.begin()+d,get_last_align()); + return this->begin()+d; + } + + iterator erase(const_iterator first, const_iterator last) + { return priv_erase(first, last, alloc_version()); } + + void swap(stable_vector & x) + { + STABLE_VECTOR_CHECK_INVARIANT; + this->swap_impl(*this,x); + } + + void clear() + { this->erase(this->cbegin(),this->cend()); } + + /// @cond + private: + + void insert_iter_prolog(size_type n, difference_type d) + { + initialize_end_node(n); + const void* old_ptr = &impl[0]; + //size_type old_capacity = capacity(); + //size_type old_size = size(); + impl.insert(impl.begin()+d, n, 0); + bool realloced = &impl[0] != old_ptr; + //Fix the pointers for the newly allocated buffer + if(realloced){ + align_nodes(impl.begin(), impl.begin()+d); + } + } + + template + void assign_dispatch(InputIterator first, InputIterator last, boost::mpl::false_) + { + STABLE_VECTOR_CHECK_INVARIANT; + iterator first1 = this->begin(); + iterator last1 = this->end(); + for ( ; first1 != last1 && first != last; ++first1, ++first) + *first1 = *first; + if (first == last){ + this->erase(first1, last1); + } + else{ + this->insert(last1, first, last); + } + } + + template + void assign_dispatch(Integer n, Integer t, boost::mpl::true_) + { + typedef stable_vector_detail::constant_iterator cvalue_iterator; + this->assign_dispatch(cvalue_iterator(t, n), cvalue_iterator(), boost::mpl::false_()); + } + + iterator priv_erase(const_iterator first, const_iterator last, allocator_v1) + { + STABLE_VECTOR_CHECK_INVARIANT; + difference_type d1 = first - this->cbegin(), d2 = last - this->cbegin(); + if(d1 != d2){ + impl_iterator it1(impl.begin() + d1), it2(impl.begin() + d2); + for(impl_iterator it = it1; it != it2; ++it) + this->delete_node(*it); + impl.erase(it1, it2); + this->align_nodes(impl.begin() + d1, get_last_align()); + } + return iterator(this->begin() + d1); + } + + impl_iterator get_last_align() + { + return impl.end() - (ExtraPointers - 1); + } + + const_impl_iterator get_last_align() const + { + return impl.cend() - (ExtraPointers - 1); + } + + template + iterator priv_erase(const_iterator first, const_iterator last, AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::value>::type * = 0) + { + STABLE_VECTOR_CHECK_INVARIANT; + return priv_erase(first, last, allocator_v1()); + } + + static node_type_ptr_t node_ptr_cast(void_ptr p) + { + using boost::get_pointer; + return node_type_ptr_t(static_cast(stable_vector_detail::get_pointer(p))); + } + + static node_type_base_ptr_t node_base_ptr_cast(void_ptr p) + { + using boost::get_pointer; + return node_type_base_ptr_t(static_cast(stable_vector_detail::get_pointer(p))); + } + + static value_type& value(void_ptr p) + { + return node_ptr_cast(p)->value; + } + + void initialize_end_node(size_type impl_capacity = 0) + { + if(impl.empty()){ + impl.reserve(impl_capacity + ExtraPointers); + impl.resize (ExtraPointers, void_ptr(0)); + impl[0] = &this->internal_data.end_node; + this->internal_data.end_node.up = &impl[0]; + } + } + + void readjust_end_node() + { + if(!this->impl.empty()){ + void_ptr &end_node_ref = *(this->get_last_align()-1); + end_node_ref = this->get_end_node(); + this->internal_data.end_node.up = &end_node_ref; + } + else{ + this->internal_data.end_node.up = void_ptr(&this->internal_data.end_node.up); + } + } + + node_type_ptr_t get_end_node() const + { + const node_type_base_t* cp = &this->internal_data.end_node; + node_type_base_t* p = const_cast(cp); + return node_ptr_cast(p); + } + + template + void_ptr new_node(void_ptr up, Iter it) + { + node_type_ptr_t p = this->allocate_one(); + try{ + boost::interprocess_container::construct_in_place(&*p, it); + p->set_pointer(up); + } + catch(...){ + this->deallocate_one(p); + throw; + } + return p; + } + + void delete_node(void_ptr p) + { + node_type_ptr_t n(node_ptr_cast(p)); + n->~node_type_t(); + this->put_in_pool(n); + } + + static void align_nodes(impl_iterator first,impl_iterator last) + { + while(first!=last){ + node_ptr_cast(*first)->up = void_ptr(&*first); + ++first; + } + } + + void insert_not_iter(const_iterator position, size_type n, const T& t) + { + typedef stable_vector_detail::constant_iterator cvalue_iterator; + this->insert_iter(position, cvalue_iterator(t, n), cvalue_iterator(), std::forward_iterator_tag()); + } + + template + void insert_iter(const_iterator position,InputIterator first,InputIterator last, boost::mpl::true_) + { + typedef typename std::iterator_traits::iterator_category category; + this->insert_iter(position, first, last, category()); + } + + template + void insert_iter(const_iterator position,InputIterator first,InputIterator last,std::input_iterator_tag) + { + for(; first!=last; ++first){ + this->insert(position, *first); + } + } + + template + iterator insert_iter(const_iterator position, InputIterator first, InputIterator last, std::forward_iterator_tag) + { + size_type n = (size_type)std::distance(first,last); + difference_type d = position-this->cbegin(); + if(n){ + this->insert_iter_prolog(n, d); + const impl_iterator it(impl.begin() + d); + this->insert_iter_fwd(it, first, last, n); + //Fix the pointers for the newly allocated buffer + this->align_nodes(it + n, get_last_align()); + } + return this->begin() + d; + } + + template + void insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v1) + { + size_type i=0; + try{ + while(first!=last){ + *(it + i) = this->new_node(void_ptr((void*)(&*(it + i))), first); + ++first; + ++i; + } + } + catch(...){ + impl.erase(it + i, it + n); + this->align_nodes(it + i, get_last_align()); + throw; + } + } + + template + void insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v2) + { + multiallocation_chain mem(get_al().allocate_individual(n)); + + size_type i = 0; + node_type_ptr_t p = 0; + try{ + while(first != last){ + p = mem.front(); + mem.pop_front(); + //This can throw + boost::interprocess_container::construct_in_place(&*p, first); + p->set_pointer(void_ptr((void*)(&*(it + i)))); + ++first; + *(it + i) = p; + ++i; + } + } + catch(...){ + get_al().deallocate_one(p); + get_al().deallocate_many(boost::interprocess::move(mem)); + impl.erase(it+i, it+n); + this->align_nodes(it+i,get_last_align()); + throw; + } + } + + template + void insert_iter_fwd(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n) + { + size_type i = 0; + node_type_ptr_t p = 0; + try{ + while(first != last){ + p = get_from_pool(); + if(!p){ + insert_iter_fwd_alloc(it+i, first, last, n-i, alloc_version()); + break; + } + //This can throw + boost::interprocess_container::construct_in_place(&*p, first); + p->set_pointer(void_ptr(&*(it+i))); + ++first; + *(it+i)=p; + ++i; + } + } + catch(...){ + put_in_pool(p); + impl.erase(it+i,it+n); + this->align_nodes(it+i,get_last_align()); + throw; + } + } + + template + void insert_iter(const_iterator position,InputIterator first,InputIterator last, boost::mpl::false_) + { + this->insert_not_iter(position,first,last); + } + + static void swap_impl(stable_vector& x,stable_vector& y) + { + using std::swap; + swap(x.get_al(),y.get_al()); + swap(x.impl,y.impl); + swap(x.internal_data.pool_size, y.internal_data.pool_size); + x.readjust_end_node(); + y.readjust_end_node(); + } + + #if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) + bool invariant()const + { + if(impl.empty()) + return !capacity() && !size(); + if(get_end_node() != *(impl.end() - ExtraPointers)){ + return false; + } + for(const_impl_iterator it=impl.begin(),it_end=get_last_align();it!=it_end;++it){ + if(node_ptr_cast(*it)->up != &*it) + return false; + } + size_type n = capacity()-size(); + const void_ptr &pool_head = impl.back(); + size_type num_pool = 0; + node_type_ptr_t p = node_ptr_cast(pool_head); + while(p){ + ++num_pool; + p = p->up; + } + return n >= num_pool; + } + + class invariant_checker:private boost::noncopyable + { + const stable_vector* p; + public: + invariant_checker(const stable_vector& v):p(&v){} + ~invariant_checker(){BOOST_ASSERT(p->invariant());} + void touch(){} + }; + #endif + + struct ebo_holder + : node_allocator_type + { + ebo_holder(const allocator_type &a) + : node_allocator_type(a), pool_size(0), end_node() + { + end_node.set_pointer(void_ptr(&end_node.up)); + } + size_type pool_size; + node_type_base_t end_node; + } internal_data; + + node_allocator_type &get_al() { return internal_data; } + const node_allocator_type &get_al() const { return internal_data; } + + impl_type impl; + /// @endcond +}; + +template +bool operator==(const stable_vector& x,const stable_vector& y) +{ + return x.size()==y.size()&&std::equal(x.begin(),x.end(),y.begin()); +} + +template +bool operator< (const stable_vector& x,const stable_vector& y) +{ + return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end()); +} + +template +bool operator!=(const stable_vector& x,const stable_vector& y) +{ + return !(x==y); +} + +template +bool operator> (const stable_vector& x,const stable_vector& y) +{ + return y +bool operator>=(const stable_vector& x,const stable_vector& y) +{ + return !(x +bool operator<=(const stable_vector& x,const stable_vector& y) +{ + return !(x>y); +} + +// specialized algorithms: + +template +void swap(stable_vector& x,stable_vector& y) +{ + x.swap(y); +} + +/// @cond + +#undef STABLE_VECTOR_CHECK_INVARIANT + +/// @endcond + +}} + +#endif diff --git a/include/boost/interprocess/containers/container/string.hpp b/include/boost/interprocess/containers/container/string.hpp new file mode 100644 index 0000000..cb061ad --- /dev/null +++ b/include/boost/interprocess/containers/container/string.hpp @@ -0,0 +1,2320 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's string file. Modified by Ion Gaztanaga 2004-2008 +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 1994 +// Hewlett-Packard Company +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. Hewlett-Packard Company makes no +// representations about the suitability of this software for any +// purpose. It is provided "as is" without express or implied warranty. + +#ifndef BOOST_CONTAINERS_STRING_HPP +#define BOOST_CONTAINERS_STRING_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +namespace containers_detail { +// ------------------------------------------------------------ +// Class basic_string_base. + +// basic_string_base is a helper class that makes it it easier to write +// an exception-safe version of basic_string. The constructor allocates, +// but does not initialize, a block of memory. The destructor +// deallocates, but does not destroy elements within, a block of +// memory. The destructor assumes that the memory either is the internal buffer, +// or else points to a block of memory that was allocated using _String_base's +// allocator and whose size is this->m_storage. +template +class basic_string_base +{ + basic_string_base(); + basic_string_base(basic_string_base&); + basic_string_base & operator=(basic_string_base&); + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_string_base) + + typedef A allocator_type; + //! The stored allocator type + typedef allocator_type stored_allocator_type; + typedef typename A::pointer pointer; + typedef typename A::value_type value_type; + typedef typename A::size_type size_type; + + basic_string_base(const allocator_type& a) + : members_(a) + { init(); } + + basic_string_base(const allocator_type& a, std::size_t n) + : members_(a) + { + this->init(); + this->allocate_initial_block(n); + } + + basic_string_base(BOOST_INTERPROCESS_RV_REF(basic_string_base) b) + : members_(b.members_) + { + init(); + this->swap(b); + } + + ~basic_string_base() + { + this->deallocate_block(); + if(!this->is_short()){ + static_cast(static_cast(&this->members_.m_repr.r))->~long_t(); + } + } + + private: + + //This is the structure controlling a long string + struct long_t + { + size_type is_short : 1; + size_type length : (sizeof(size_type)*CHAR_BIT - 1); + size_type storage; + pointer start; + + long_t() + {} + + long_t(const long_t &other) + { + this->is_short = other.is_short; + length = other.length; + storage = other.storage; + start = other.start; + } + + long_t &operator =(const long_t &other) + { + this->is_short = other.is_short; + length = other.length; + storage = other.storage; + start = other.start; + return *this; + } + }; + + //This basic type should have the same alignment as long_t +//iG typedef typename type_with_alignment::value>::type +// long_alignment_type; + typedef void *long_alignment_type; + BOOST_STATIC_ASSERT((containers_detail::alignment_of::value % + containers_detail::alignment_of::value) == 0); + + + //This type is the first part of the structure controlling a short string + //The "data" member stores + struct short_header + { + unsigned char is_short : 1; + unsigned char length : (CHAR_BIT - 1); + }; + + //This type has the same alignment and size as long_t but it's POD + //so, unlike long_t, it can be placed in a union + struct long_raw_t + { + long_alignment_type a; + unsigned char b[sizeof(long_t) - sizeof(long_alignment_type)]; + }; + + protected: + static const size_type MinInternalBufferChars = 8; + static const size_type AlignmentOfValueType = + alignment_of::value; + static const size_type ShortDataOffset = + containers_detail::ct_rounded_size::value; + static const size_type ZeroCostInternalBufferChars = + (sizeof(long_t) - ShortDataOffset)/sizeof(value_type); + static const size_type UnalignedFinalInternalBufferChars = + (ZeroCostInternalBufferChars > MinInternalBufferChars) ? + ZeroCostInternalBufferChars : MinInternalBufferChars; + + struct short_t + { + short_header h; + value_type data[UnalignedFinalInternalBufferChars]; + }; + + union repr_t + { + long_raw_t r; + short_t s; + + short_t &short_repr() const + { return *const_cast(&s); } + + long_t &long_repr() const + { return *static_cast(const_cast(static_cast(&r))); } + }; + + struct members_holder + : public A + { + members_holder(const A &a) + : A(a) + {} + + repr_t m_repr; + } members_; + + const A &alloc() const + { return members_; } + + A &alloc() + { return members_; } + + static const size_type InternalBufferChars = (sizeof(repr_t) - ShortDataOffset)/sizeof(value_type); + + private: + + static const size_type MinAllocation = InternalBufferChars*2; + + protected: + bool is_short() const + { return static_cast(this->members_.m_repr.s.h.is_short != 0); } + + void is_short(bool yes) + { + if(yes && !this->is_short()){ + static_cast(static_cast(&this->members_.m_repr.r))->~long_t(); + } + else{ + new(static_cast(&this->members_.m_repr.r))long_t(); + } + this->members_.m_repr.s.h.is_short = yes; + } + + private: + void init() + { + this->members_.m_repr.s.h.is_short = 1; + this->members_.m_repr.s.h.length = 0; + } + + protected: + + typedef containers_detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + typedef containers_detail::integral_constant::value> alloc_version; + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, pointer reuse = 0) + { + if(this->is_short() && (command & (expand_fwd | expand_bwd)) ){ + reuse = pointer(0); + command &= ~(expand_fwd | expand_bwd); + } + return this->allocation_command + (command, limit_size, preferred_size, received_size, reuse, alloc_version()); + } + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, + const pointer &reuse, + allocator_v1) + { + (void)limit_size; + (void)reuse; + if(!(command & allocate_new)) + return std::pair(pointer(0), 0); + received_size = preferred_size; + return std::make_pair(this->alloc().allocate(received_size), false); + } + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, + pointer reuse, + allocator_v2) + { + return this->alloc().allocation_command(command, limit_size, preferred_size, + received_size, reuse); + } + + size_type next_capacity(size_type additional_objects) const + { return get_next_capacity(this->alloc().max_size(), this->priv_storage(), additional_objects); } + + void deallocate(pointer p, std::size_t n) + { + if (p && (n > InternalBufferChars)) + this->alloc().deallocate(p, n); + } + + void construct(pointer p, const value_type &value = value_type()) + { new((void*)containers_detail::get_pointer(p)) value_type(value); } + + void destroy(pointer p, size_type n) + { + for(; n--; ++p) + containers_detail::get_pointer(p)->~value_type(); + } + + void destroy(pointer p) + { containers_detail::get_pointer(p)->~value_type(); } + + void allocate_initial_block(std::size_t n) + { + if (n <= this->max_size()) { + if(n > InternalBufferChars){ + size_type new_cap = this->next_capacity(n); + pointer p = this->allocation_command(allocate_new, n, new_cap, new_cap).first; + this->is_short(false); + this->priv_addr(p); + this->priv_size(0); + this->priv_storage(new_cap); + } + } + else + throw_length_error(); + } + + void deallocate_block() + { this->deallocate(this->priv_addr(), this->priv_storage()); } + + std::size_t max_size() const + { return this->alloc().max_size() - 1; } + + // Helper functions for exception handling. + void throw_length_error() const + { throw(std::length_error("basic_string")); } + + void throw_out_of_range() const + { throw(std::out_of_range("basic_string")); } + + protected: + size_type priv_capacity() const + { return this->priv_storage() - 1; } + + pointer priv_addr() const + { return this->is_short() ? pointer(&this->members_.m_repr.short_repr().data[0]) : this->members_.m_repr.long_repr().start; } + + void priv_addr(pointer addr) + { this->members_.m_repr.long_repr().start = addr; } + + size_type priv_storage() const + { return this->is_short() ? InternalBufferChars : this->members_.m_repr.long_repr().storage; } + + void priv_storage(size_type storage) + { + if(!this->is_short()) + this->members_.m_repr.long_repr().storage = storage; + } + + size_type priv_size() const + { return this->is_short() ? this->members_.m_repr.short_repr().h.length : this->members_.m_repr.long_repr().length; } + + void priv_size(size_type sz) + { + if(this->is_short()) + this->members_.m_repr.s.h.length = (unsigned char)sz; + else + this->members_.m_repr.long_repr().length = static_cast(sz); + } + + void swap(basic_string_base& other) + { + if(this->is_short()){ + if(other.is_short()){ + std::swap(this->members_.m_repr, other.members_.m_repr); + } + else{ + repr_t copied(this->members_.m_repr); + this->members_.m_repr.long_repr() = other.members_.m_repr.long_repr(); + other.members_.m_repr = copied; + } + } + else{ + if(other.is_short()){ + repr_t copied(other.members_.m_repr); + other.members_.m_repr.long_repr() = this->members_.m_repr.long_repr(); + this->members_.m_repr = copied; + } + else{ + std::swap(this->members_.m_repr.long_repr(), other.members_.m_repr.long_repr()); + } + } + + allocator_type & this_al = this->alloc(), &other_al = other.alloc(); + if(this_al != other_al){ + containers_detail::do_swap(this_al, other_al); + } + } +}; + +} //namespace containers_detail { + +/// @endcond + +//! The basic_string class represents a Sequence of characters. It contains all the +//! usual operations of a Sequence, and, additionally, it contains standard string +//! operations such as search and concatenation. +//! +//! The basic_string class is parameterized by character type, and by that type's +//! Character Traits. +//! +//! This class has performance characteristics very much like vector<>, meaning, +//! for example, that it does not perform reference-count or copy-on-write, and that +//! concatenation of two strings is an O(N) operation. +//! +//! Some of basic_string's member functions use an unusual method of specifying positions +//! and ranges. In addition to the conventional method using iterators, many of +//! basic_string's member functions use a single value pos of type size_type to represent a +//! position (in which case the position is begin() + pos, and many of basic_string's +//! member functions use two values, pos and n, to represent a range. In that case pos is +//! the beginning of the range and n is its size. That is, the range is +//! [begin() + pos, begin() + pos + n). +//! +//! Note that the C++ standard does not specify the complexity of basic_string operations. +//! In this implementation, basic_string has performance characteristics very similar to +//! those of vector: access to a single character is O(1), while copy and concatenation +//! are O(N). +//! +//! In this implementation, begin(), +//! end(), rbegin(), rend(), operator[], c_str(), and data() do not invalidate iterators. +//! In this implementation, iterators are only invalidated by member functions that +//! explicitly change the string's contents. +template +class basic_string + : private containers_detail::basic_string_base +{ + /// @cond + private: + typedef containers_detail::basic_string_base base_t; + static const typename base_t::size_type InternalBufferChars = base_t::InternalBufferChars; + + protected: + // A helper class to use a char_traits as a function object. + + template + struct Eq_traits + : public std::binary_function + { + bool operator()(const typename Tr::char_type& x, + const typename Tr::char_type& y) const + { return Tr::eq(x, y); } + }; + + template + struct Not_within_traits + : public std::unary_function + { + typedef const typename Tr::char_type* Pointer; + const Pointer m_first; + const Pointer m_last; + + Not_within_traits(Pointer f, Pointer l) + : m_first(f), m_last(l) {} + + bool operator()(const typename Tr::char_type& x) const + { + return std::find_if(m_first, m_last, + std::bind1st(Eq_traits(), x)) == m_last; + } + }; + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_string) + + //! The allocator type + typedef A allocator_type; + //! The stored allocator type + typedef allocator_type stored_allocator_type; + //! The type of object, CharT, stored in the string + typedef CharT value_type; + //! The second template parameter Traits + typedef Traits traits_type; + //! Pointer to CharT + typedef typename A::pointer pointer; + //! Const pointer to CharT + typedef typename A::const_pointer const_pointer; + //! Reference to CharT + typedef typename A::reference reference; + //! Const reference to CharT + typedef typename A::const_reference const_reference; + //! An unsigned integral type + typedef typename A::size_type size_type; + //! A signed integral type + typedef typename A::difference_type difference_type; + //! Iterator used to iterate through a string. It's a Random Access Iterator + typedef pointer iterator; + //! Const iterator used to iterate through a string. It's a Random Access Iterator + typedef const_pointer const_iterator; + //! Iterator used to iterate backwards through a string + typedef std::reverse_iterator reverse_iterator; + //! Const iterator used to iterate backwards through a string + typedef std::reverse_iterator const_reverse_iterator; + //! The largest possible value of type size_type. That is, size_type(-1). + static const size_type npos; + + /// @cond + private: + typedef constant_iterator cvalue_iterator; + /// @endcond + + public: // Constructor, destructor, assignment. + /// @cond + struct reserve_t {}; + /// @endcond + + basic_string(reserve_t, std::size_t n, + const allocator_type& a = allocator_type()) + : base_t(a, n + 1) + { this->priv_terminate_string(); } + + //! Effects: Constructs a basic_string taking the allocator as parameter. + //! + //! Throws: If allocator_type's copy constructor throws. + explicit basic_string(const allocator_type& a = allocator_type()) + : base_t(a, InternalBufferChars) + { this->priv_terminate_string(); } + + //! Effects: Copy constructs a basic_string. + //! + //! Postcondition: x == *this. + //! + //! Throws: If allocator_type's default constructor or copy constructor throws. + basic_string(const basic_string& s) + : base_t(s.alloc()) + { this->priv_range_initialize(s.begin(), s.end()); } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + basic_string(BOOST_INTERPROCESS_RV_REF(basic_string) s) + : base_t(boost::interprocess::move((base_t&)s)) + {} + + //! Effects: Constructs a basic_string taking the allocator as parameter, + //! and is initialized by a specific number of characters of the s string. + basic_string(const basic_string& s, size_type pos, size_type n = npos, + const allocator_type& a = allocator_type()) + : base_t(a) + { + if (pos > s.size()) + this->throw_out_of_range(); + else + this->priv_range_initialize + (s.begin() + pos, s.begin() + pos + containers_detail::min_value(n, s.size() - pos)); + } + + //! Effects: Constructs a basic_string taking the allocator as parameter, + //! and is initialized by a specific number of characters of the s c-string. + basic_string(const CharT* s, size_type n, + const allocator_type& a = allocator_type()) + : base_t(a) + { this->priv_range_initialize(s, s + n); } + + //! Effects: Constructs a basic_string taking the allocator as parameter, + //! and is initialized by the null-terminated s c-string. + basic_string(const CharT* s, + const allocator_type& a = allocator_type()) + : base_t(a) + { this->priv_range_initialize(s, s + Traits::length(s)); } + + //! Effects: Constructs a basic_string taking the allocator as parameter, + //! and is initialized by n copies of c. + basic_string(size_type n, CharT c, + const allocator_type& a = allocator_type()) + : base_t(a) + { + this->priv_range_initialize(cvalue_iterator(c, n), + cvalue_iterator()); + } + + //! Effects: Constructs a basic_string taking the allocator as parameter, + //! and a range of iterators. + template + basic_string(InputIterator f, InputIterator l, + const allocator_type& a = allocator_type()) + : base_t(a) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_initialize_dispatch(f, l, Result()); + } + + //! Effects: Destroys the basic_string. All used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + ~basic_string() + {} + + //! Effects: Copy constructs a string. + //! + //! Postcondition: x == *this. + //! + //! Complexity: Linear to the elements x contains. + basic_string& operator=(const basic_string& s) + { + if (&s != this) + this->assign(s.begin(), s.end()); + return *this; + } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + basic_string& operator=(BOOST_INTERPROCESS_RV_REF(basic_string) ms) + { + basic_string &s = ms; + if (&s != this){ + this->swap(s); + } + return *this; + } + + //! Effects: Assignment from a null-terminated c-string. + basic_string& operator=(const CharT* s) + { return this->assign(s, s + Traits::length(s)); } + + //! Effects: Assignment from character. + basic_string& operator=(CharT c) + { return this->assign(static_cast(1), c); } + + //! Effects: Returns an iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return this->priv_addr(); } + + //! Effects: Returns a const_iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return this->priv_addr(); } + + //! Effects: Returns an iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return this->priv_addr() + this->priv_size(); } + + //! Effects: Returns a const_iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return this->priv_addr() + this->priv_size(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return reverse_iterator(this->priv_addr() + this->priv_size()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return const_reverse_iterator(this->priv_addr() + this->priv_size()); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return reverse_iterator(this->priv_addr()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return const_reverse_iterator(this->priv_addr()); } + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return this->alloc(); } + + //! Effects: Returns the number of the elements contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return this->priv_size(); } + + //! Effects: Returns the number of the elements contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type length() const + { return this->size(); } + + //! Effects: Returns the largest possible size of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return base_t::max_size(); } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type n, CharT c) + { + if (n <= size()) + this->erase(this->begin() + n, this->end()); + else + this->append(n - this->size(), c); + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type n) + { resize(n, this->priv_null()); } + + //! Effects: If n is less than or equal to capacity(), this call has no + //! effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + void reserve(size_type res_arg) + { + if (res_arg > this->max_size()) + this->throw_length_error(); + + if (this->capacity() < res_arg){ + size_type n = containers_detail::max_value(res_arg, this->size()) + 1; + size_type new_cap = this->next_capacity(n); + pointer new_start = this->allocation_command + (allocate_new, n, new_cap, new_cap).first; + size_type new_length = 0; + + new_length += priv_uninitialized_copy + (this->priv_addr(), this->priv_addr() + this->priv_size(), new_start); + this->priv_construct_null(new_start + new_length); + this->deallocate_block(); + this->is_short(false); + this->priv_addr(new_start); + this->priv_size(new_length); + this->priv_storage(new_cap); + } + } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return this->priv_capacity(); } + + //! Effects: Erases all the elements of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements in the vector. + void clear() + { + if (!empty()) { + Traits::assign(*this->priv_addr(), this->priv_null()); + this->priv_size(0); + } + } + + //! Effects: Returns true if the vector contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return !this->priv_size(); } + + //! Requires: size() < n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference operator[](size_type n) + { return *(this->priv_addr() + n); } + + //! Requires: size() < n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference operator[](size_type n) const + { return *(this->priv_addr() + n); } + + //! Requires: size() < n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + reference at(size_type n) { + if (n >= size()) + this->throw_out_of_range(); + return *(this->priv_addr() + n); + } + + //! Requires: size() < n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + const_reference at(size_type n) const { + if (n >= size()) + this->throw_out_of_range(); + return *(this->priv_addr() + n); + } + + //! Effects: Appends string s to *this. + basic_string& operator+=(const basic_string& s) + { return this->append(s); } + + //! Effects: Appends c-string s to *this. + basic_string& operator+=(const CharT* s) + { return this->append(s); } + + //! Effects: Appends character c to *this. + basic_string& operator+=(CharT c) + { this->push_back(c); return *this; } + + //! Effects: Appends string s to *this. + basic_string& append(const basic_string& s) + { return this->append(s.begin(), s.end()); } + + //! Effects: Appends the range [pos, pos + n) from string s to *this. + basic_string& append(const basic_string& s, size_type pos, size_type n) + { + if (pos > s.size()) + this->throw_out_of_range(); + return this->append(s.begin() + pos, + s.begin() + pos + containers_detail::min_value(n, s.size() - pos)); + } + + //! Effects: Appends the range [s, s + n) from c-string s to *this. + basic_string& append(const CharT* s, size_type n) + { return this->append(s, s + n); } + + //! Effects: Appends the c-string s to *this. + basic_string& append(const CharT* s) + { return this->append(s, s + Traits::length(s)); } + + //! Effects: Appends the n times the character c to *this. + basic_string& append(size_type n, CharT c) + { return this->append(cvalue_iterator(c, n), cvalue_iterator()); } + + //! Effects: Appends the range [first, last) *this. + template + basic_string& append(InputIter first, InputIter last) + { this->insert(this->end(), first, last); return *this; } + + //! Effects: Inserts a copy of c at the end of the vector. + void push_back(CharT c) + { + if (this->priv_size() < this->capacity()){ + this->priv_construct_null(this->priv_addr() + (this->priv_size() + 1)); + Traits::assign(this->priv_addr()[this->priv_size()], c); + this->priv_size(this->priv_size()+1); + } + else{ + //No enough memory, insert a new object at the end + this->append((size_type)1, c); + } + } + + //! Effects: Removes the last element from the vector. + void pop_back() + { + Traits::assign(this->priv_addr()[this->priv_size()-1], this->priv_null()); + this->priv_size(this->priv_size()-1);; + } + + //! Effects: Assigns the value s to *this. + basic_string& assign(const basic_string& s) + { return this->operator=(s); } + + //! Effects: Moves the resources from ms *this. + basic_string& assign(BOOST_INTERPROCESS_RV_REF(basic_string) ms) + { return this->operator=(ms);} + + //! Effects: Assigns the range [pos, pos + n) from s to *this. + basic_string& assign(const basic_string& s, + size_type pos, size_type n) { + if (pos > s.size()) + this->throw_out_of_range(); + return this->assign(s.begin() + pos, + s.begin() + pos + containers_detail::min_value(n, s.size() - pos)); + } + + //! Effects: Assigns the range [s, s + n) from s to *this. + basic_string& assign(const CharT* s, size_type n) + { return this->assign(s, s + n); } + + //! Effects: Assigns the c-string s to *this. + basic_string& assign(const CharT* s) + { return this->assign(s, s + Traits::length(s)); } + + //! Effects: Assigns the character c n-times to *this. + basic_string& assign(size_type n, CharT c) + { return this->assign(cvalue_iterator(c, n), cvalue_iterator()); } + + //! Effects: Assigns the range [first, last) to *this. + template + basic_string& assign(InputIter first, InputIter last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + return this->priv_assign_dispatch(first, last, Result()); + } + + //! Effects: Assigns the range [f, l) to *this. + basic_string& assign(const CharT* f, const CharT* l) + { + const std::ptrdiff_t n = l - f; + if (static_cast(n) <= size()) { + Traits::copy(containers_detail::get_pointer(this->priv_addr()), f, n); + this->erase(this->priv_addr() + n, this->priv_addr() + this->priv_size()); + } + else { + Traits::copy(containers_detail::get_pointer(this->priv_addr()), f, this->priv_size()); + this->append(f + this->priv_size(), l); + } + return *this; + } + + //! Effects: Inserts the string s before pos. + basic_string& insert(size_type pos, const basic_string& s) + { + if (pos > size()) + this->throw_out_of_range(); + if (this->size() > this->max_size() - s.size()) + this->throw_length_error(); + this->insert(this->priv_addr() + pos, s.begin(), s.end()); + return *this; + } + + //! Effects: Inserts the range [pos, pos + n) from string s before pos. + basic_string& insert(size_type pos, const basic_string& s, + size_type beg, size_type n) + { + if (pos > this->size() || beg > s.size()) + this->throw_out_of_range(); + size_type len = containers_detail::min_value(n, s.size() - beg); + if (this->size() > this->max_size() - len) + this->throw_length_error(); + const CharT *beg_ptr = containers_detail::get_pointer(s.begin()) + beg; + const CharT *end_ptr = beg_ptr + len; + this->insert(this->priv_addr() + pos, beg_ptr, end_ptr); + return *this; + } + + //! Effects: Inserts the range [s, s + n) before pos. + basic_string& insert(size_type pos, const CharT* s, size_type n) + { + if (pos > this->size()) + this->throw_out_of_range(); + if (this->size() > this->max_size() - n) + this->throw_length_error(); + this->insert(this->priv_addr() + pos, s, s + n); + return *this; + } + + //! Effects: Inserts the c-string s before pos. + basic_string& insert(size_type pos, const CharT* s) + { + if (pos > size()) + this->throw_out_of_range(); + size_type len = Traits::length(s); + if (this->size() > this->max_size() - len) + this->throw_length_error(); + this->insert(this->priv_addr() + pos, s, s + len); + return *this; + } + + //! Effects: Inserts the character c n-times before pos. + basic_string& insert(size_type pos, size_type n, CharT c) + { + if (pos > this->size()) + this->throw_out_of_range(); + if (this->size() > this->max_size() - n) + this->throw_length_error(); + this->insert(this->priv_addr() + pos, n, c); + return *this; + } + + //! Effects: Inserts the character c before position. + iterator insert(iterator position, CharT c) + { + size_type new_offset = position - this->priv_addr() + 1; + this->insert(position, cvalue_iterator(c, 1), + cvalue_iterator()); + return this->priv_addr() + new_offset; + } + + //! Effects: Inserts the character c n-times before position. + void insert(iterator position, std::size_t n, CharT c) + { + this->insert(position, cvalue_iterator(c, n), + cvalue_iterator()); + } + + //! Effects: Inserts the range [first, last) before position. + template + void insert(iterator p, InputIter first, InputIter last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_dispatch(p, first, last, Result()); + } + + //! Effects: Inserts the range [pos, pos + n). + basic_string& erase(size_type pos = 0, size_type n = npos) + { + if (pos > size()) + this->throw_out_of_range(); + erase(this->priv_addr() + pos, this->priv_addr() + pos + containers_detail::min_value(n, size() - pos)); + return *this; + } + + //! Effects: Erases the character pointed by position. + iterator erase(iterator position) + { + // The move includes the terminating null. + Traits::move(containers_detail::get_pointer(position), + containers_detail::get_pointer(position + 1), + this->priv_size() - (position - this->priv_addr())); + this->priv_size(this->priv_size()-1); + return position; + } + + //! Effects: Erases the range [first, last). + iterator erase(iterator first, iterator last) + { + if (first != last) { // The move includes the terminating null. + size_type num_erased = last - first; + Traits::move(containers_detail::get_pointer(first), + containers_detail::get_pointer(last), + (this->priv_size() + 1)-(last - this->priv_addr())); + size_type new_length = this->priv_size() - num_erased; + this->priv_size(new_length); + } + return first; + } + + //! Effects: Replaces a substring of *this with the string s. + basic_string& replace(size_type pos, size_type n, + const basic_string& s) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = containers_detail::min_value(n, size() - pos); + if (this->size() - len >= this->max_size() - s.size()) + this->throw_length_error(); + return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, + s.begin(), s.end()); + } + + //! Effects: Replaces a substring of *this with a substring of s. + basic_string& replace(size_type pos1, size_type n1, + const basic_string& s, + size_type pos2, size_type n2) + { + if (pos1 > size() || pos2 > s.size()) + this->throw_out_of_range(); + const size_type len1 = containers_detail::min_value(n1, size() - pos1); + const size_type len2 = containers_detail::min_value(n2, s.size() - pos2); + if (this->size() - len1 >= this->max_size() - len2) + this->throw_length_error(); + return this->replace(this->priv_addr() + pos1, this->priv_addr() + pos1 + len1, + s.priv_addr() + pos2, s.priv_addr() + pos2 + len2); + } + + //! Effects: Replaces a substring of *this with the first n1 characters of s. + basic_string& replace(size_type pos, size_type n1, + const CharT* s, size_type n2) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = containers_detail::min_value(n1, size() - pos); + if (n2 > this->max_size() || size() - len >= this->max_size() - n2) + this->throw_length_error(); + return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, + s, s + n2); + } + + //! Effects: Replaces a substring of *this with a null-terminated character array. + basic_string& replace(size_type pos, size_type n1, + const CharT* s) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = containers_detail::min_value(n1, size() - pos); + const size_type n2 = Traits::length(s); + if (n2 > this->max_size() || size() - len >= this->max_size() - n2) + this->throw_length_error(); + return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, + s, s + Traits::length(s)); + } + + //! Effects: Replaces a substring of *this with n1 copies of c. + basic_string& replace(size_type pos, size_type n1, + size_type n2, CharT c) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = containers_detail::min_value(n1, size() - pos); + if (n2 > this->max_size() || size() - len >= this->max_size() - n2) + this->throw_length_error(); + return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, n2, c); + } + + //! Effects: Replaces a substring of *this with the string s. + basic_string& replace(iterator first, iterator last, + const basic_string& s) + { return this->replace(first, last, s.begin(), s.end()); } + + //! Effects: Replaces a substring of *this with the first n characters of s. + basic_string& replace(iterator first, iterator last, + const CharT* s, size_type n) + { return this->replace(first, last, s, s + n); } + + //! Effects: Replaces a substring of *this with a null-terminated character array. + basic_string& replace(iterator first, iterator last, + const CharT* s) + { return this->replace(first, last, s, s + Traits::length(s)); } + + //! Effects: Replaces a substring of *this with n copies of c. + basic_string& replace(iterator first, iterator last, + size_type n, CharT c) + { + const size_type len = static_cast(last - first); + if (len >= n) { + Traits::assign(containers_detail::get_pointer(first), n, c); + erase(first + n, last); + } + else { + Traits::assign(containers_detail::get_pointer(first), len, c); + insert(last, n - len, c); + } + return *this; + } + + //! Effects: Replaces a substring of *this with the range [f, l) + template + basic_string& replace(iterator first, iterator last, + InputIter f, InputIter l) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + return this->priv_replace_dispatch(first, last, f, l, Result()); + } + + //! Effects: Copies a substring of *this to a buffer. + size_type copy(CharT* s, size_type n, size_type pos = 0) const + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = containers_detail::min_value(n, size() - pos); + Traits::copy(s, containers_detail::get_pointer(this->priv_addr() + pos), len); + return len; + } + + //! Effects: Swaps the contents of two strings. + void swap(basic_string& x) + { base_t::swap(x); } + + //! Returns: Returns a pointer to a null-terminated array of characters + //! representing the string's contents. For any string s it is guaranteed + //! that the first s.size() characters in the array pointed to by s.c_str() + //! are equal to the character in s, and that s.c_str()[s.size()] is a null + //! character. Note, however, that it not necessarily the first null character. + //! Characters within a string are permitted to be null. + const CharT* c_str() const + { return containers_detail::get_pointer(this->priv_addr()); } + + //! Returns: Returns a pointer to an array of characters, not necessarily + //! null-terminated, representing the string's contents. data() is permitted, + //! but not required, to be identical to c_str(). The first size() characters + //! of that array are guaranteed to be identical to the characters in *this. + //! The return value of data() is never a null pointer, even if size() is zero. + const CharT* data() const + { return containers_detail::get_pointer(this->priv_addr()); } + + //! Effects: Searches for s as a substring of *this, beginning at + //! character pos of *this. + size_type find(const basic_string& s, size_type pos = 0) const + { return find(s.c_str(), pos, s.size()); } + + //! Effects: Searches for a null-terminated character array as a + //! substring of *this, beginning at character pos of *this. + size_type find(const CharT* s, size_type pos = 0) const + { return find(s, pos, Traits::length(s)); } + + //! Effects: Searches for the first n characters of s as a substring + //! of *this, beginning at character pos of *this. + size_type find(const CharT* s, size_type pos, size_type n) const + { + if (pos + n > size()) + return npos; + else { + pointer finish = this->priv_addr() + this->priv_size(); + const const_iterator result = + std::search(containers_detail::get_pointer(this->priv_addr() + pos), + containers_detail::get_pointer(finish), + s, s + n, Eq_traits()); + return result != finish ? result - begin() : npos; + } + } + + //! Effects: Searches for the character c, beginning at character + //! position pos. + size_type find(CharT c, size_type pos = 0) const + { + if (pos >= size()) + return npos; + else { + pointer finish = this->priv_addr() + this->priv_size(); + const const_iterator result = + std::find_if(this->priv_addr() + pos, finish, + std::bind2nd(Eq_traits(), c)); + return result != finish ? result - begin() : npos; + } + } + + //! Effects: Searches backward for s as a substring of *this, + //! beginning at character position min(pos, size()) + size_type rfind(const basic_string& s, size_type pos = npos) const + { return rfind(s.c_str(), pos, s.size()); } + + //! Effects: Searches backward for a null-terminated character array + //! as a substring of *this, beginning at character min(pos, size()) + size_type rfind(const CharT* s, size_type pos = npos) const + { return rfind(s, pos, Traits::length(s)); } + + //! Effects: Searches backward for the first n characters of s as a + //! substring of *this, beginning at character position min(pos, size()). + size_type rfind(const CharT* s, size_type pos, size_type n) const + { + const std::size_t len = size(); + + if (n > len) + return npos; + else if (n == 0) + return containers_detail::min_value(len, pos); + else { + const const_iterator last = begin() + containers_detail::min_value(len - n, pos) + n; + const const_iterator result = find_end(begin(), last, + s, s + n, + Eq_traits()); + return result != last ? result - begin() : npos; + } + } + + //! Effects: Searches backward for a null-terminated character array + //! as a substring of *this, beginning at character min(pos, size()). + size_type rfind(CharT c, size_type pos = npos) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = begin() + containers_detail::min_value(len - 1, pos) + 1; + const_reverse_iterator rresult = + std::find_if(const_reverse_iterator(last), rend(), + std::bind2nd(Eq_traits(), c)); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is equal to any character within s. + size_type find_first_of(const basic_string& s, size_type pos = 0) const + { return find_first_of(s.c_str(), pos, s.size()); } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is equal to any character within s. + size_type find_first_of(const CharT* s, size_type pos = 0) const + { return find_first_of(s, pos, Traits::length(s)); } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is equal to any character within the first n characters of s. + size_type find_first_of(const CharT* s, size_type pos, + size_type n) const + { + if (pos >= size()) + return npos; + else { + pointer finish = this->priv_addr() + this->priv_size(); + const_iterator result = std::find_first_of(this->priv_addr() + pos, finish, + s, s + n, + Eq_traits()); + return result != finish ? result - begin() : npos; + } + } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is equal to c. + size_type find_first_of(CharT c, size_type pos = 0) const + { return find(c, pos); } + + //! Effects: Searches backward within *this, beginning at min(pos, size()), + //! for the first character that is equal to any character within s. + size_type find_last_of(const basic_string& s, + size_type pos = npos) const + { return find_last_of(s.c_str(), pos, s.size()); } + + //! Effects: Searches backward *this, beginning at min(pos, size()), for + //! the first character that is equal to any character within s. + size_type find_last_of(const CharT* s, size_type pos = npos) const + { return find_last_of(s, pos, Traits::length(s)); } + + //! Effects: Searches backward within *this, beginning at min(pos, size()), + //! for the first character that is equal to any character within the first n + //! characters of s. + size_type find_last_of(const CharT* s, size_type pos, size_type n) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = this->priv_addr() + containers_detail::min_value(len - 1, pos) + 1; + const const_reverse_iterator rresult = + std::find_first_of(const_reverse_iterator(last), rend(), + s, s + n, + Eq_traits()); + return rresult != rend() ? (rresult.base() - 1) - this->priv_addr() : npos; + } + } + + //! Effects: Searches backward *this, beginning at min(pos, size()), for + //! the first character that is equal to c. + size_type find_last_of(CharT c, size_type pos = npos) const + { return rfind(c, pos); } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is not equal to any character within s. + size_type find_first_not_of(const basic_string& s, + size_type pos = 0) const + { return find_first_not_of(s.c_str(), pos, s.size()); } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is not equal to any character within s. + size_type find_first_not_of(const CharT* s, size_type pos = 0) const + { return find_first_not_of(s, pos, Traits::length(s)); } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is not equal to any character within the first n + //! characters of s. + size_type find_first_not_of(const CharT* s, size_type pos, + size_type n) const + { + if (pos > size()) + return npos; + else { + pointer finish = this->priv_addr() + this->priv_size(); + const_iterator result = std::find_if(this->priv_addr() + pos, finish, + Not_within_traits(s, s + n)); + return result != finish ? result - this->priv_addr() : npos; + } + } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is not equal to c. + size_type find_first_not_of(CharT c, size_type pos = 0) const + { + if (pos > size()) + return npos; + else { + pointer finish = this->priv_addr() + this->priv_size(); + const_iterator result + = std::find_if(this->priv_addr() + pos, finish, + std::not1(std::bind2nd(Eq_traits(), c))); + return result != finish ? result - begin() : npos; + } + } + + //! Effects: Searches backward within *this, beginning at min(pos, size()), + //! for the first character that is not equal to any character within s. + size_type find_last_not_of(const basic_string& s, + size_type pos = npos) const + { return find_last_not_of(s.c_str(), pos, s.size()); } + + //! Effects: Searches backward *this, beginning at min(pos, size()), + //! for the first character that is not equal to any character within s. + size_type find_last_not_of(const CharT* s, size_type pos = npos) const + { return find_last_not_of(s, pos, Traits::length(s)); } + + //! Effects: Searches backward within *this, beginning at min(pos, size()), + //! for the first character that is not equal to any character within the first + //! n characters of s. + size_type find_last_not_of(const CharT* s, size_type pos, size_type n) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = begin() + containers_detail::min_value(len - 1, pos) + 1; + const const_reverse_iterator rresult = + std::find_if(const_reverse_iterator(last), rend(), + Not_within_traits(s, s + n)); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + //! Effects: Searches backward *this, beginning at min(pos, size()), + //! for the first character that is not equal to c. + size_type find_last_not_of(CharT c, size_type pos = npos) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = begin() + containers_detail::min_value(len - 1, pos) + 1; + const_reverse_iterator rresult = + std::find_if(const_reverse_iterator(last), rend(), + std::not1(std::bind2nd(Eq_traits(), c))); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + //! Effects: Returns a substring of *this. + basic_string substr(size_type pos = 0, size_type n = npos) const + { + if (pos > size()) + this->throw_out_of_range(); + return basic_string(this->priv_addr() + pos, + this->priv_addr() + pos + containers_detail::min_value(n, size() - pos), this->alloc()); + } + + //! Effects: Three-way lexicographical comparison of s and *this. + int compare(const basic_string& s) const + { return s_compare(this->priv_addr(), this->priv_addr() + this->priv_size(), s.priv_addr(), s.priv_addr() + s.priv_size()); } + + //! Effects: Three-way lexicographical comparison of s and a substring + //! of *this. + int compare(size_type pos1, size_type n1, const basic_string& s) const + { + if (pos1 > size()) + this->throw_out_of_range(); + return s_compare(this->priv_addr() + pos1, + this->priv_addr() + pos1 + containers_detail::min_value(n1, size() - pos1), + s.priv_addr(), s.priv_addr() + s.priv_size()); + } + + //! Effects: Three-way lexicographical comparison of a substring of s + //! and a substring of *this. + int compare(size_type pos1, size_type n1, + const basic_string& s, + size_type pos2, size_type n2) const { + if (pos1 > size() || pos2 > s.size()) + this->throw_out_of_range(); + return s_compare(this->priv_addr() + pos1, + this->priv_addr() + pos1 + containers_detail::min_value(n1, size() - pos1), + s.priv_addr() + pos2, + s.priv_addr() + pos2 + containers_detail::min_value(n2, size() - pos2)); + } + + //! Effects: Three-way lexicographical comparison of s and *this. + int compare(const CharT* s) const + { return s_compare(this->priv_addr(), this->priv_addr() + this->priv_size(), s, s + Traits::length(s)); } + + + //! Effects: Three-way lexicographical comparison of the first + //! min(len, traits::length(s) characters of s and a substring of *this. + int compare(size_type pos1, size_type n1, const CharT* s, + size_type n2 = npos) const + { + if (pos1 > size()) + this->throw_out_of_range(); + return s_compare(this->priv_addr() + pos1, + this->priv_addr() + pos1 + containers_detail::min_value(n1, size() - pos1), + s, s + n2); + } + + /// @cond + private: + static int s_compare(const_pointer f1, const_pointer l1, + const_pointer f2, const_pointer l2) + { + const std::ptrdiff_t n1 = l1 - f1; + const std::ptrdiff_t n2 = l2 - f2; + const int cmp = Traits::compare(containers_detail::get_pointer(f1), + containers_detail::get_pointer(f2), + containers_detail::min_value(n1, n2)); + return cmp != 0 ? cmp : (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0)); + } + + void priv_construct_null(pointer p) + { this->construct(p, 0); } + + static CharT priv_null() + { return (CharT) 0; } + + // Helper functions used by constructors. It is a severe error for + // any of them to be called anywhere except from within constructors. + void priv_terminate_string() + { this->priv_construct_null(this->priv_addr() + this->priv_size()); } + + template + void priv_range_initialize(InputIter f, InputIter l, + std::input_iterator_tag) + { + this->allocate_initial_block(InternalBufferChars); + this->priv_construct_null(this->priv_addr() + this->priv_size()); + this->append(f, l); + } + + template + void priv_range_initialize(ForwardIter f, ForwardIter l, + std::forward_iterator_tag) + { + difference_type n = std::distance(f, l); + this->allocate_initial_block(containers_detail::max_value(n+1, InternalBufferChars)); + priv_uninitialized_copy(f, l, this->priv_addr()); + this->priv_size(n); + this->priv_terminate_string(); + } + + template + void priv_range_initialize(InputIter f, InputIter l) + { + typedef typename std::iterator_traits::iterator_category Category; + this->priv_range_initialize(f, l, Category()); + } + + template + void priv_initialize_dispatch(Integer n, Integer x, containers_detail::true_) + { + this->allocate_initial_block(containers_detail::max_value(n+1, InternalBufferChars)); + priv_uninitialized_fill_n(this->priv_addr(), n, x); + this->priv_size(n); + this->priv_terminate_string(); + } + + template + void priv_initialize_dispatch(InputIter f, InputIter l, containers_detail::false_) + { this->priv_range_initialize(f, l); } + + template inline + void priv_uninitialized_fill_n(FwdIt first, Count count, const CharT val) + { + //Save initial position + FwdIt init = first; + + BOOST_TRY{ + //Construct objects + for (; count--; ++first){ + this->construct(first, val); + } + } + BOOST_CATCH(...){ + //Call destructors + for (; init != first; ++init){ + this->destroy(init); + } + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template inline + size_type priv_uninitialized_copy(InpIt first, InpIt last, FwdIt dest) + { + //Save initial destination position + FwdIt dest_init = dest; + size_type constructed = 0; + + BOOST_TRY{ + //Try to build objects + for (; first != last; ++dest, ++first, ++constructed){ + this->construct(dest, *first); + } + } + BOOST_CATCH(...){ + //Call destructors + for (; constructed--; ++dest_init){ + this->destroy(dest_init); + } + BOOST_RETHROW + } + BOOST_CATCH_END + return (constructed); + } + + template + basic_string& priv_assign_dispatch(Integer n, Integer x, containers_detail::true_) + { return this->assign((size_type) n, (CharT) x); } + + template + basic_string& priv_assign_dispatch(InputIter f, InputIter l, + containers_detail::false_) + { + size_type cur = 0; + CharT *ptr = containers_detail::get_pointer(this->priv_addr()); + while (f != l && cur != this->priv_size()) { + Traits::assign(*ptr, *f); + ++f; + ++cur; + ++ptr; + } + if (f == l) + this->erase(this->priv_addr() + cur, this->priv_addr() + this->priv_size()); + else + this->append(f, l); + return *this; + } + + template + void priv_insert(iterator p, InputIter first, InputIter last, std::input_iterator_tag) + { + for ( ; first != last; ++first, ++p) { + p = this->insert(p, *first); + } + } + + template + void priv_insert(iterator position, ForwardIter first, + ForwardIter last, std::forward_iterator_tag) + { + if (first != last) { + size_type n = std::distance(first, last); + size_type remaining = this->capacity() - this->priv_size(); + const size_type old_size = this->size(); + pointer old_start = this->priv_addr(); + bool enough_capacity = false; + std::pair allocation_ret; + size_type new_cap = 0; + + //Check if we have enough capacity + if (remaining >= n){ + enough_capacity = true; + } + else { + //Otherwise expand current buffer or allocate new storage + new_cap = this->next_capacity(n); + allocation_ret = this->allocation_command + (allocate_new | expand_fwd | expand_bwd, old_size + n + 1, + new_cap, new_cap, old_start); + + //Check forward expansion + if(old_start == allocation_ret.first){ + enough_capacity = true; + this->priv_storage(new_cap); + } + } + + //Reuse same buffer + if(enough_capacity){ + const size_type elems_after = + this->priv_size() - (position - this->priv_addr()); + size_type old_length = this->priv_size(); + if (elems_after >= n) { + pointer pointer_past_last = this->priv_addr() + this->priv_size() + 1; + priv_uninitialized_copy(this->priv_addr() + (this->priv_size() - n + 1), + pointer_past_last, pointer_past_last); + + this->priv_size(this->priv_size()+n); + Traits::move(containers_detail::get_pointer(position + n), + containers_detail::get_pointer(position), + (elems_after - n) + 1); + this->priv_copy(first, last, position); + } + else { + ForwardIter mid = first; + std::advance(mid, elems_after + 1); + + priv_uninitialized_copy(mid, last, this->priv_addr() + this->priv_size() + 1); + this->priv_size(this->priv_size() + (n - elems_after)); + priv_uninitialized_copy + (position, this->priv_addr() + old_length + 1, + this->priv_addr() + this->priv_size()); + this->priv_size(this->priv_size() + elems_after); + this->priv_copy(first, mid, position); + } + } + else{ + pointer new_start = allocation_ret.first; + if(!allocation_ret.second){ + //Copy data to new buffer + size_type new_length = 0; + //This can't throw, since characters are POD + new_length += priv_uninitialized_copy + (this->priv_addr(), position, new_start); + new_length += priv_uninitialized_copy + (first, last, new_start + new_length); + new_length += priv_uninitialized_copy + (position, this->priv_addr() + this->priv_size(), + new_start + new_length); + this->priv_construct_null(new_start + new_length); + + this->deallocate_block(); + this->is_short(false); + this->priv_addr(new_start); + this->priv_size(new_length); + this->priv_storage(new_cap); + } + else{ + //value_type is POD, so backwards expansion is much easier + //than with vector + value_type *oldbuf = containers_detail::get_pointer(old_start); + value_type *newbuf = containers_detail::get_pointer(new_start); + value_type *pos = containers_detail::get_pointer(position); + size_type before = pos - oldbuf; + + //First move old data + Traits::move(newbuf, oldbuf, before); + Traits::move(newbuf + before + n, pos, old_size - before); + //Now initialize the new data + priv_uninitialized_copy(first, last, new_start + before); + this->priv_construct_null(new_start + (old_size + n)); + this->is_short(false); + this->priv_addr(new_start); + this->priv_size(old_size + n); + this->priv_storage(new_cap); + } + } + } + } + + template + void priv_insert_dispatch(iterator p, Integer n, Integer x, + containers_detail::true_) + { insert(p, (size_type) n, (CharT) x); } + + template + void priv_insert_dispatch(iterator p, InputIter first, InputIter last, + containers_detail::false_) + { + typedef typename std::iterator_traits::iterator_category Category; + priv_insert(p, first, last, Category()); + } + + template + void priv_copy(InputIterator first, InputIterator last, iterator result) + { + for ( ; first != last; ++first, ++result) + Traits::assign(*result, *first); + } + + void priv_copy(const CharT* first, const CharT* last, CharT* result) + { Traits::copy(result, first, last - first); } + + template + basic_string& priv_replace_dispatch(iterator first, iterator last, + Integer n, Integer x, + containers_detail::true_) + { return this->replace(first, last, (size_type) n, (CharT) x); } + + template + basic_string& priv_replace_dispatch(iterator first, iterator last, + InputIter f, InputIter l, + containers_detail::false_) + { + typedef typename std::iterator_traits::iterator_category Category; + return this->priv_replace(first, last, f, l, Category()); + } + + + template + basic_string& priv_replace(iterator first, iterator last, + InputIter f, InputIter l, std::input_iterator_tag) + { + for ( ; first != last && f != l; ++first, ++f) + Traits::assign(*first, *f); + + if (f == l) + this->erase(first, last); + else + this->insert(last, f, l); + return *this; + } + + template + basic_string& priv_replace(iterator first, iterator last, + ForwardIter f, ForwardIter l, + std::forward_iterator_tag) + { + difference_type n = std::distance(f, l); + const difference_type len = last - first; + if (len >= n) { + this->priv_copy(f, l, first); + this->erase(first + n, last); + } + else { + ForwardIter m = f; + std::advance(m, len); + this->priv_copy(f, m, first); + this->insert(last, m, l); + } + return *this; + } + /// @endcond +}; + +/// @cond + +template +const typename basic_string::size_type +basic_string::npos + = (typename basic_string::size_type) -1; + +/// @endcond + +// ------------------------------------------------------------ +// Non-member functions. + +// Operator+ + +template +inline basic_string +operator+(const basic_string& x, + const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, x.size() + y.size(), x.alloc()); + result.append(x); + result.append(y); + return result; +} + +template inline +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) + operator+( + BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) mx + , const basic_string& y) +{ + mx += y; + return boost::interprocess::move(mx); +} + +template inline +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) + operator+(const basic_string& x, + BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) my) +{ + typedef typename basic_string::size_type size_type; + return my.replace(size_type(0), size_type(0), x); +} + +template +inline basic_string +operator+(const CharT* s, const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + const std::size_t n = Traits::length(s); + str_t result(reserve, n + y.size()); + result.append(s, s + n); + result.append(y); + return result; +} + +template inline +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) +operator+(const CharT* s, + BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) my) +{ + typedef typename basic_string::size_type size_type; + return boost::interprocess::move(my.get().replace(size_type(0), size_type(0), s)); +} + +template +inline basic_string +operator+(CharT c, const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, 1 + y.size()); + result.push_back(c); + result.append(y); + return result; +} + +template inline +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) +operator+(CharT c, + BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) my) +{ + typedef typename basic_string::size_type size_type; + return my.replace(size_type(0), size_type(0), &c, &c + 1); +} + +template +inline basic_string +operator+(const basic_string& x, const CharT* s) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + const std::size_t n = Traits::length(s); + str_t result(reserve, x.size() + n, x.alloc()); + result.append(x); + result.append(s, s + n); + return result; +} + +template +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) +operator+(BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) mx + , const CharT* s) +{ + mx += s; + return boost::interprocess::move(mx); +} + +template +inline basic_string +operator+(const basic_string& x, const CharT c) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, x.size() + 1, x.alloc()); + result.append(x); + result.push_back(c); + return result; +} + +template +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) +operator+( BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) mx + , const CharT c) +{ + mx += c; + return boost::interprocess::move(mx); +} + +// Operator== and operator!= + +template +inline bool +operator==(const basic_string& x, + const basic_string& y) +{ + return x.size() == y.size() && + Traits::compare(x.data(), y.data(), x.size()) == 0; +} + +template +inline bool +operator==(const CharT* s, const basic_string& y) +{ + std::size_t n = Traits::length(s); + return n == y.size() && Traits::compare(s, y.data(), n) == 0; +} + +template +inline bool +operator==(const basic_string& x, const CharT* s) +{ + std::size_t n = Traits::length(s); + return x.size() == n && Traits::compare(x.data(), s, n) == 0; +} + +template +inline bool +operator!=(const basic_string& x, + const basic_string& y) + { return !(x == y); } + +template +inline bool +operator!=(const CharT* s, const basic_string& y) + { return !(s == y); } + +template +inline bool +operator!=(const basic_string& x, const CharT* s) + { return !(x == s); } + + +// Operator< (and also >, <=, and >=). + +template +inline bool +operator<(const basic_string& x, const basic_string& y) +{ + return x.compare(y) < 0; +// return basic_string +// ::s_compare(x.begin(), x.end(), y.begin(), y.end()) < 0; +} + +template +inline bool +operator<(const CharT* s, const basic_string& y) +{ + return y.compare(s) > 0; +// std::size_t n = Traits::length(s); +// return basic_string +// ::s_compare(s, s + n, y.begin(), y.end()) < 0; +} + +template +inline bool +operator<(const basic_string& x, + const CharT* s) +{ + return x.compare(s) < 0; +// std::size_t n = Traits::length(s); +// return basic_string +// ::s_compare(x.begin(), x.end(), s, s + n) < 0; +} + +template +inline bool +operator>(const basic_string& x, + const basic_string& y) { + return y < x; +} + +template +inline bool +operator>(const CharT* s, const basic_string& y) { + return y < s; +} + +template +inline bool +operator>(const basic_string& x, const CharT* s) +{ + return s < x; +} + +template +inline bool +operator<=(const basic_string& x, + const basic_string& y) +{ + return !(y < x); +} + +template +inline bool +operator<=(const CharT* s, const basic_string& y) + { return !(y < s); } + +template +inline bool +operator<=(const basic_string& x, const CharT* s) + { return !(s < x); } + +template +inline bool +operator>=(const basic_string& x, + const basic_string& y) + { return !(x < y); } + +template +inline bool +operator>=(const CharT* s, const basic_string& y) + { return !(s < y); } + +template +inline bool +operator>=(const basic_string& x, const CharT* s) + { return !(x < s); } + +// Swap. +template +inline void swap(basic_string& x, basic_string& y) +{ x.swap(y); } + +/// @cond +// I/O. +namespace containers_detail { + +template +inline bool +string_fill(std::basic_ostream& os, + std::basic_streambuf* buf, + std::size_t n) +{ + CharT f = os.fill(); + std::size_t i; + bool ok = true; + + for (i = 0; i < n; i++) + ok = ok && !Traits::eq_int_type(buf->sputc(f), Traits::eof()); + return ok; +} + +} //namespace containers_detail { +/// @endcond + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const basic_string& s) +{ + typename std::basic_ostream::sentry sentry(os); + bool ok = false; + + if (sentry) { + ok = true; + std::size_t n = s.size(); + std::size_t pad_len = 0; + const bool left = (os.flags() & std::ios::left) != 0; + const std::size_t w = os.width(0); + std::basic_streambuf* buf = os.rdbuf(); + + if (w != 0 && n < w) + pad_len = w - n; + + if (!left) + ok = containers_detail::string_fill(os, buf, pad_len); + + ok = ok && + buf->sputn(s.data(), std::streamsize(n)) == std::streamsize(n); + + if (left) + ok = ok && containers_detail::string_fill(os, buf, pad_len); + } + + if (!ok) + os.setstate(std::ios_base::failbit); + + return os; +} + + +template +std::basic_istream& +operator>>(std::basic_istream& is, basic_string& s) +{ + typename std::basic_istream::sentry sentry(is); + + if (sentry) { + std::basic_streambuf* buf = is.rdbuf(); + const std::ctype& ctype = std::use_facet >(is.getloc()); + + s.clear(); + std::size_t n = is.width(0); + if (n == 0) + n = static_cast(-1); + else + s.reserve(n); + + while (n-- > 0) { + typename Traits::int_type c1 = buf->sbumpc(); + + if (Traits::eq_int_type(c1, Traits::eof())) { + is.setstate(std::ios_base::eofbit); + break; + } + else { + CharT c = Traits::to_char_type(c1); + + if (ctype.is(std::ctype::space, c)) { + if (Traits::eq_int_type(buf->sputbackc(c), Traits::eof())) + is.setstate(std::ios_base::failbit); + break; + } + else + s.push_back(c); + } + } + + // If we have read no characters, then set failbit. + if (s.size() == 0) + is.setstate(std::ios_base::failbit); + } + else + is.setstate(std::ios_base::failbit); + + return is; +} + +template +std::basic_istream& +getline(std::istream& is, basic_string& s,CharT delim) +{ + std::size_t nread = 0; + typename std::basic_istream::sentry sentry(is, true); + if (sentry) { + std::basic_streambuf* buf = is.rdbuf(); + s.clear(); + + int c1; + while (nread < s.max_size()) { + int c1 = buf->sbumpc(); + if (Traits::eq_int_type(c1, Traits::eof())) { + is.setstate(std::ios_base::eofbit); + break; + } + else { + ++nread; + CharT c = Traits::to_char_type(c1); + if (!Traits::eq(c, delim)) + s.push_back(c); + else + break; // Character is extracted but not appended. + } + } + } + if (nread == 0 || nread >= s.max_size()) + is.setstate(std::ios_base::failbit); + + return is; +} + +template +inline std::basic_istream& +getline(std::basic_istream& is, basic_string& s) +{ + return getline(is, s, '\n'); +} + +template +inline std::size_t hash_value(basic_string, A> const& v) +{ + return hash_range(v.begin(), v.end()); +} + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value; +}; + +}} + +/// @endcond + +#include + +#endif // BOOST_CONTAINERS_STRING_HPP diff --git a/include/boost/interprocess/containers/container/vector.hpp b/include/boost/interprocess/containers/container/vector.hpp new file mode 100644 index 0000000..4c38e25 --- /dev/null +++ b/include/boost/interprocess/containers/container/vector.hpp @@ -0,0 +1,1933 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's stl_vector.h file. Modified by Ion Gaztanaga. +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 1994 +// Hewlett-Packard Company +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. Hewlett-Packard Company makes no +// representations about the suitability of this software for any +// purpose. It is provided "as is" without express or implied warranty. +// +// +// Copyright (c) 1996 +// Silicon Graphics Computer Systems, Inc. +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. Silicon Graphics makes no +// representations about the suitability of this software for any +// purpose. It is provided "as is" without express or implied warranty. + +#ifndef BOOST_CONTAINERS_CONTAINERS_VECTOR_HPP +#define BOOST_CONTAINERS_CONTAINERS_VECTOR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond + +namespace containers_detail { + +//! Const vector_iterator used to iterate through a vector. +template +class vector_const_iterator + : public std::iterator::value_type + ,typename std::iterator_traits::difference_type + ,typename boost::pointer_to_other + ::value_type + >::type + ,const typename std::iterator_traits::value_type &> +{ + public: + typedef const typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename boost::pointer_to_other::type pointer; + typedef value_type& reference; + + /// @cond + protected: + Pointer m_ptr; + + public: + Pointer get_ptr() const { return m_ptr; } + explicit vector_const_iterator(Pointer ptr) : m_ptr(ptr){} + /// @endcond + + public: + + //Constructors + vector_const_iterator() : m_ptr(0){} + + //Pointer like operators + reference operator*() const + { return *m_ptr; } + + const value_type * operator->() const + { return containers_detail::get_pointer(m_ptr); } + + reference operator[](difference_type off) const + { return m_ptr[off]; } + + //Increment / Decrement + vector_const_iterator& operator++() + { ++m_ptr; return *this; } + + vector_const_iterator operator++(int) + { Pointer tmp = m_ptr; ++*this; return vector_const_iterator(tmp); } + + vector_const_iterator& operator--() + { --m_ptr; return *this; } + + vector_const_iterator operator--(int) + { Pointer tmp = m_ptr; --*this; return vector_const_iterator(tmp); } + + //Arithmetic + vector_const_iterator& operator+=(difference_type off) + { m_ptr += off; return *this; } + + vector_const_iterator operator+(difference_type off) const + { return vector_const_iterator(m_ptr+off); } + + friend vector_const_iterator operator+(difference_type off, const vector_const_iterator& right) + { return vector_const_iterator(off + right.m_ptr); } + + vector_const_iterator& operator-=(difference_type off) + { m_ptr -= off; return *this; } + + vector_const_iterator operator-(difference_type off) const + { return vector_const_iterator(m_ptr-off); } + + difference_type operator-(const vector_const_iterator& right) const + { return m_ptr - right.m_ptr; } + + //Comparison operators + bool operator== (const vector_const_iterator& r) const + { return m_ptr == r.m_ptr; } + + bool operator!= (const vector_const_iterator& r) const + { return m_ptr != r.m_ptr; } + + bool operator< (const vector_const_iterator& r) const + { return m_ptr < r.m_ptr; } + + bool operator<= (const vector_const_iterator& r) const + { return m_ptr <= r.m_ptr; } + + bool operator> (const vector_const_iterator& r) const + { return m_ptr > r.m_ptr; } + + bool operator>= (const vector_const_iterator& r) const + { return m_ptr >= r.m_ptr; } +}; + +//! Iterator used to iterate through a vector +template +class vector_iterator + : public vector_const_iterator +{ + public: + explicit vector_iterator(Pointer ptr) + : vector_const_iterator(ptr) + {} + + public: + typedef typename std::iterator_traits::value_type value_type; + typedef typename vector_const_iterator::difference_type difference_type; + typedef Pointer pointer; + typedef value_type& reference; + + //Constructors + vector_iterator() + {} + + //Pointer like operators + reference operator*() const + { return *this->m_ptr; } + + value_type* operator->() const + { return containers_detail::get_pointer(this->m_ptr); } + + reference operator[](difference_type off) const + { return this->m_ptr[off]; } + + //Increment / Decrement + vector_iterator& operator++() + { ++this->m_ptr; return *this; } + + vector_iterator operator++(int) + { pointer tmp = this->m_ptr; ++*this; return vector_iterator(tmp); } + + vector_iterator& operator--() + { --this->m_ptr; return *this; } + + vector_iterator operator--(int) + { vector_iterator tmp = *this; --*this; return vector_iterator(tmp); } + + // Arithmetic + vector_iterator& operator+=(difference_type off) + { this->m_ptr += off; return *this; } + + vector_iterator operator+(difference_type off) const + { return vector_iterator(this->m_ptr+off); } + + friend vector_iterator operator+(difference_type off, const vector_iterator& right) + { return vector_iterator(off + right.m_ptr); } + + vector_iterator& operator-=(difference_type off) + { this->m_ptr -= off; return *this; } + + vector_iterator operator-(difference_type off) const + { return vector_iterator(this->m_ptr-off); } + + difference_type operator-(const vector_const_iterator& right) const + { return static_cast&>(*this) - right; } +}; + +template +struct vector_value_traits +{ + typedef T value_type; + typedef A allocator_type; + static const bool trivial_dctr = boost::has_trivial_destructor::value; + static const bool trivial_dctr_after_move = + boost::interprocess::has_trivial_destructor_after_move::value || trivial_dctr; + static const bool trivial_copy = has_trivial_copy::value; + static const bool nothrow_copy = has_nothrow_copy::value; + static const bool trivial_assign = has_trivial_assign::value; + static const bool nothrow_assign = has_nothrow_assign::value; + + //This is the anti-exception array destructor + //to deallocate values already constructed + typedef typename containers_detail::if_c + + ,containers_detail::scoped_destructor_n + >::type OldArrayDestructor; + //This is the anti-exception array destructor + //to destroy objects created with copy construction + typedef typename containers_detail::if_c + + ,containers_detail::scoped_destructor_n + >::type UCopiedArrayDestructor; + //This is the anti-exception array deallocator + typedef typename containers_detail::if_c + + ,containers_detail::scoped_array_deallocator + >::type UCopiedArrayDeallocator; +}; + +//!This struct deallocates and allocated memory +template +struct vector_alloc_holder +{ + typedef typename A::pointer pointer; + typedef typename A::size_type size_type; + typedef typename A::value_type value_type; + typedef vector_value_traits value_traits; + + //Constructor, does not throw + vector_alloc_holder(const A &a) + : members_(a) + {} + + //Constructor, does not throw + vector_alloc_holder(const vector_alloc_holder &h) + : members_(h.alloc()) + {} + + //Destructor + ~vector_alloc_holder() + { + this->prot_destroy_all(); + this->prot_deallocate(); + } + + typedef containers_detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + typedef containers_detail::integral_constant::value> alloc_version; + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, const pointer &reuse = 0) + { + return allocation_command(command, limit_size, preferred_size, + received_size, reuse, alloc_version()); + } + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, + const pointer &reuse, + allocator_v1) + { + (void)limit_size; + (void)reuse; + if(!(command & allocate_new)) + return std::pair(pointer(0), 0); + received_size = preferred_size; + return std::make_pair(this->alloc().allocate(received_size), false); + } + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, + const pointer &reuse, + allocator_v2) + { + return this->alloc().allocation_command + (command, limit_size, preferred_size, received_size, reuse); + } + + size_type next_capacity(size_type additional_objects) const + { return get_next_capacity(this->alloc().max_size(), this->members_.m_capacity, additional_objects); } + + struct members_holder + : public A + { + private: + members_holder(const members_holder&); + + public: + members_holder(const A &alloc) + : A(alloc), m_start(0), m_size(0), m_capacity(0) + {} + + pointer m_start; + size_type m_size; + size_type m_capacity; + } members_; + + protected: + void prot_deallocate() + { + if(!this->members_.m_capacity) return; + this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); + this->members_.m_start = 0; + this->members_.m_size = 0; + this->members_.m_capacity = 0; + } + + void destroy(value_type* p) + { + if(!value_traits::trivial_dctr) + containers_detail::get_pointer(p)->~value_type(); + } + + void destroy_n(value_type* p, size_type n) + { + if(!value_traits::trivial_dctr) + for(; n--; ++p) p->~value_type(); + } + + void prot_destroy_all() + { + this->destroy_n(containers_detail::get_pointer(this->members_.m_start), this->members_.m_size); + this->members_.m_size = 0; + } + + A &alloc() + { return members_; } + + const A &alloc() const + { return members_; } +}; + +} //namespace containers_detail { +/// @endcond + +//! \class ::boost::interprocess::vector boost/interprocess/containers/container/vector.hpp +//! A vector is a sequence that supports random access to elements, constant +//! time insertion and removal of elements at the end, and linear time insertion +//! and removal of elements at the beginning or in the middle. The number of +//! elements in a vector may vary dynamically; memory management is automatic. +//! boost::interprocess_container::vector is similar to std::vector but it's compatible +//! with shared memory and memory mapped files. +template +class vector : private containers_detail::vector_alloc_holder +{ + /// @cond + typedef vector self_t; + typedef containers_detail::vector_alloc_holder base_t; + /// @endcond + public: + //! The type of object, T, stored in the vector + typedef T value_type; + //! Pointer to T + typedef typename A::pointer pointer; + //! Const pointer to T + typedef typename A::const_pointer const_pointer; + //! Reference to T + typedef typename A::reference reference; + //! Const reference to T + typedef typename A::const_reference const_reference; + //! An unsigned integral type + typedef typename A::size_type size_type; + //! A signed integral type + typedef typename A::difference_type difference_type; + //! The allocator type + typedef A allocator_type; + //! The random access iterator + typedef containers_detail::vector_iterator iterator; + //! The random access const_iterator + typedef containers_detail::vector_const_iterator const_iterator; + + //! Iterator used to iterate backwards through a vector. + typedef std::reverse_iterator + reverse_iterator; + //! Const iterator used to iterate backwards through a vector. + typedef std::reverse_iterator + const_reverse_iterator; + //! The stored allocator type + typedef allocator_type stored_allocator_type; + + /// @cond + private: + typedef containers_detail::advanced_insert_aux_int advanced_insert_aux_int_t; + typedef containers_detail::vector_value_traits value_traits; + + typedef typename base_t::allocator_v1 allocator_v1; + typedef typename base_t::allocator_v2 allocator_v2; + typedef typename base_t::alloc_version alloc_version; + + typedef constant_iterator cvalue_iterator; + typedef repeat_iterator repeat_it; + typedef boost::interprocess::move_iterator repeat_move_it; + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(vector) + + //! Effects: Constructs a vector taking the allocator as parameter. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + explicit vector(const A& a = A()) + : base_t(a) + {} + + //! Effects: Constructs a vector that will use a copy of allocator a + //! and inserts n default contructed values. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + vector(size_type n) + : base_t(allocator_type()) + { this->resize(n); } + + //! Effects: Constructs a vector that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + vector(size_type n, const T& value, const allocator_type& a = allocator_type()) + : base_t(a) + { this->insert(this->cend(), n, value); } + + //! Effects: Copy constructs a vector. + //! + //! Postcondition: x == *this. + //! + //! Complexity: Linear to the elements x contains. + vector(const vector& x) + : base_t((base_t&)x) + { *this = x; } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + vector(BOOST_INTERPROCESS_RV_REF(vector) mx) + : base_t(boost::interprocess::move(mx)) + { this->swap(mx); } + + //! Effects: Constructs a vector that will use a copy of allocator a + //! and inserts a copy of the range [first, last) in the vector. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's constructor taking an dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + vector(InIt first, InIt last, const allocator_type& a = allocator_type()) + : base_t(a) + { this->assign(first, last); } + + //! Effects: Destroys the vector. All stored values are destroyed + //! and used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements. + ~vector() + {} //vector_alloc_holder clears the data + + //! Effects: Returns an iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return iterator(this->members_.m_start); } + + //! Effects: Returns a const_iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return const_iterator(this->members_.m_start); } + + //! Effects: Returns an iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return iterator(this->members_.m_start + this->members_.m_size); } + + //! Effects: Returns a const_iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return this->cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return reverse_iterator(this->end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin()const + { return this->crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return reverse_iterator(this->begin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return this->crend(); } + + //! Effects: Returns a const_iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(this->members_.m_start); } + + //! Effects: Returns a const_iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(this->members_.m_start + this->members_.m_size); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin()const + { return const_reverse_iterator(this->end());} + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return const_reverse_iterator(this->begin()); } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() + { return *this->members_.m_start; } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const + { return *this->members_.m_start; } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference back() + { return this->members_.m_start[this->members_.m_size - 1]; } + + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference back() const + { return this->members_.m_start[this->members_.m_size - 1]; } + + //! Returns: A pointer such that [data(),data() + size()) is a valid range. + //! For a non-empty vector, data() == &front(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + pointer data() + { return this->members_.m_start; } + + //! Returns: A pointer such that [data(),data() + size()) is a valid range. + //! For a non-empty vector, data() == &front(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_pointer data() const + { return this->members_.m_start; } + + //! Effects: Returns the number of the elements contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return this->members_.m_size; } + + //! Effects: Returns the largest possible size of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return this->alloc().max_size(); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return this->members_.m_capacity; } + + //! Effects: Returns true if the vector contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return !this->members_.m_size; } + + //! Requires: size() < n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference operator[](size_type n) + { return this->members_.m_start[n]; } + + //! Requires: size() < n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference operator[](size_type n) const + { return this->members_.m_start[n]; } + + //! Requires: size() < n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + reference at(size_type n) + { this->priv_check_range(n); return this->members_.m_start[n]; } + + //! Requires: size() < n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + const_reference at(size_type n) const + { this->priv_check_range(n); return this->members_.m_start[n]; } + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return this->alloc(); } + + const stored_allocator_type &get_stored_allocator() const + { return this->alloc(); } + + stored_allocator_type &get_stored_allocator() + { return this->alloc(); } + + //! Effects: If n is less than or equal to capacity(), this call has no + //! effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + void reserve(size_type new_cap) + { + if (this->capacity() < new_cap){ + //There is not enough memory, allocate a new + //buffer or expand the old one. + bool same_buffer_start; + size_type real_cap = 0; + std::pair ret = + this->allocation_command + (allocate_new | expand_fwd | expand_bwd, + new_cap, new_cap, real_cap, this->members_.m_start); + + //Check for forward expansion + same_buffer_start = ret.second && this->members_.m_start == ret.first; + if(same_buffer_start){ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_expand_fwd; + #endif + this->members_.m_capacity = real_cap; + } + + //If there is no forward expansion, move objects + else{ + //We will reuse insert code, so create a dummy input iterator + T *dummy_it(containers_detail::get_pointer(this->members_.m_start)); + containers_detail::advanced_insert_aux_proxy, T*> + proxy(boost::interprocess::make_move_iterator(dummy_it), boost::interprocess::make_move_iterator(dummy_it)); + //Backwards (and possibly forward) expansion + if(ret.second){ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_expand_bwd; + #endif + this->priv_range_insert_expand_backwards + ( containers_detail::get_pointer(ret.first) + , real_cap + , containers_detail::get_pointer(this->members_.m_start) + , 0 + , proxy); + } + //New buffer + else{ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + this->priv_range_insert_new_allocation + ( containers_detail::get_pointer(ret.first) + , real_cap + , containers_detail::get_pointer(this->members_.m_start) + , 0 + , proxy); + } + } + } + } + + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + vector& operator=(const vector& x) + { + if (&x != this){ + this->assign(x.members_.m_start, x.members_.m_start + x.members_.m_size); + } + return *this; + } + + //! Effects: Move assignment. All mx's values are transferred to *this. + //! + //! Postcondition: x.empty(). *this contains a the elements x had + //! before the function. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + vector& operator=(BOOST_INTERPROCESS_RV_REF(vector) x) + { + if (&x != this){ + this->swap(x); + x.clear(); + } + return *this; + } + + //! Effects: Assigns the n copies of val to *this. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void assign(size_type n, const value_type& val) + { this->assign(cvalue_iterator(val, n), cvalue_iterator()); } + + //! Effects: Assigns the the range [first, last) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing InpIt throws. + //! + //! Complexity: Linear to n. + template + void assign(InIt first, InIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_assign_dispatch(first, last, Result()); + } + + //! Effects: Inserts a copy of x at the end of the vector. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_back(const T& x) + { + if (this->members_.m_size < this->members_.m_capacity){ + //There is more memory, just construct a new object at the end + new((void*)(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size))value_type(x); + ++this->members_.m_size; + } + else{ + this->insert(this->cend(), x); + } + } + + //! Effects: Constructs a new element in the end of the vector + //! and moves the resources of mx to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_back(BOOST_INTERPROCESS_RV_REF(T) x) + { + if (this->members_.m_size < this->members_.m_capacity){ + //There is more memory, just construct a new object at the end + new((void*)containers_detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(boost::interprocess::move(x)); + ++this->members_.m_size; + } + else{ + this->insert(this->cend(), boost::interprocess::move(x)); + } + } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the vector. + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: Amortized constant time. + template + void emplace_back(Args &&...args) + { + T* back_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; + if (this->members_.m_size < this->members_.m_capacity){ + //There is more memory, just construct a new object at the end + new((void*)(back_pos))value_type(boost::interprocess::forward(args)...); + ++this->members_.m_size; + } + else{ + containers_detail::advanced_insert_aux_emplace proxy + (boost::interprocess::forward(args)...); + priv_range_insert(back_pos, 1, proxy); + } + } + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before position + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + template + iterator emplace(const_iterator position, Args && ...args) + { + //Just call more general insert(pos, size, value) and return iterator + size_type pos_n = position - cbegin(); + containers_detail::advanced_insert_aux_emplace proxy + (boost::interprocess::forward(args)...); + priv_range_insert(position.get_ptr(), 1, proxy); + return iterator(this->members_.m_start + pos_n); + } + + #else + + void emplace_back() + { + T* back_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; + if (this->members_.m_size < this->members_.m_capacity){ + //There is more memory, just construct a new object at the end + new((void*)(back_pos))value_type(); + ++this->members_.m_size; + } + else{ + containers_detail::advanced_insert_aux_emplace proxy; + priv_range_insert(back_pos, 1, proxy); + } + } + + iterator emplace(const_iterator position) + { + size_type pos_n = position - cbegin(); + containers_detail::advanced_insert_aux_emplace proxy; + priv_range_insert(containers_detail::get_pointer(position.get_ptr()), 1, proxy); + return iterator(this->members_.m_start + pos_n); + } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + T* back_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; \ + if (this->members_.m_size < this->members_.m_capacity){ \ + new((void*)(back_pos))value_type \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + ++this->members_.m_size; \ + } \ + else{ \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_range_insert(back_pos, 1, proxy); \ + } \ + } \ + \ + template \ + iterator emplace(const_iterator pos, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + size_type pos_n = pos - cbegin(); \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_range_insert(containers_detail::get_pointer(pos.get_ptr()), 1, proxy); \ + return iterator(this->members_.m_start + pos_n); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() + //! allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(vector& x) + { + allocator_type &this_al = this->alloc(), &other_al = x.alloc(); + //Just swap internals + containers_detail::do_swap(this->members_.m_start, x.members_.m_start); + containers_detail::do_swap(this->members_.m_size, x.members_.m_size); + containers_detail::do_swap(this->members_.m_capacity, x.members_.m_capacity); + + if (this_al != other_al){ + containers_detail::do_swap(this_al, other_al); + } + } + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before position. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + iterator insert(const_iterator position, const T& x) + { + //Just call more general insert(pos, size, value) and return iterator + size_type pos_n = position - cbegin(); + this->insert(position, (size_type)1, x); + return iterator(this->members_.m_start + pos_n); + } + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Insert a new element before position with mx's resources. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(T) x) + { + //Just call more general insert(pos, size, value) and return iterator + size_type pos_n = position - cbegin(); + this->insert(position + ,repeat_move_it(repeat_it(x, 1)) + ,repeat_move_it(repeat_it())); + return iterator(this->members_.m_start + pos_n); + } + + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [first, last) range before pos. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws or T's copy constructor throws. + //! + //! Complexity: Linear to std::distance [first, last). + template + void insert(const_iterator pos, InIt first, InIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_dispatch(pos, first, last, Result()); + } + + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert n copies of x before pos. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void insert(const_iterator p, size_type n, const T& x) + { this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); } + + //! Effects: Removes the last element from the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + void pop_back() + { + //Destroy last element + --this->members_.m_size; + this->destroy(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size); + } + + //! Effects: Erases the element at position pos. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements between pos and the + //! last element. Constant if pos is the first or the last element. + iterator erase(const_iterator position) + { + T *pos = containers_detail::get_pointer(position.get_ptr()); + T *beg = containers_detail::get_pointer(this->members_.m_start); + boost::interprocess::move(pos + 1, beg + this->members_.m_size, pos); + --this->members_.m_size; + //Destroy last element + base_t::destroy(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size); + return iterator(position.get_ptr()); + } + + //! Effects: Erases the elements pointed by [first, last). + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the distance between first and last. + iterator erase(const_iterator first, const_iterator last) + { + if (first != last){ // worth doing, copy down over hole + T* end_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; + T* ptr = containers_detail::get_pointer(boost::interprocess::move + (containers_detail::get_pointer(last.get_ptr()) + ,end_pos + ,containers_detail::get_pointer(first.get_ptr()) + )); + size_type destroyed = (end_pos - ptr); + this->destroy_n(ptr, destroyed); + this->members_.m_size -= destroyed; + } + return iterator(first.get_ptr()); + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size, const T& x) + { + pointer finish = this->members_.m_start + this->members_.m_size; + if (new_size < size()){ + //Destroy last elements + this->erase(const_iterator(this->members_.m_start + new_size), this->end()); + } + else{ + //Insert new elements at the end + this->insert(const_iterator(finish), new_size - this->size(), x); + } + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size) + { + if (new_size < this->size()){ + //Destroy last elements + this->erase(const_iterator(this->members_.m_start + new_size), this->end()); + } + else{ + size_type n = new_size - this->size(); + this->reserve(new_size); + containers_detail::default_construct_aux_proxy proxy(n); + priv_range_insert(this->cend().get_ptr(), n, proxy); + } + } + + //! Effects: Erases all the elements of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements in the vector. + void clear() + { this->prot_destroy_all(); } + + /// @cond + + //! Effects: Tries to deallocate the excess of memory created + //! with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { priv_shrink_to_fit(alloc_version()); } + + private: + void priv_shrink_to_fit(allocator_v1) + { + if(this->members_.m_capacity){ + if(!size()){ + this->prot_deallocate(); + } + else{ + //This would not work with stateful allocators + vector(*this).swap(*this); + } + } + } + + void priv_shrink_to_fit(allocator_v2) + { + if(this->members_.m_capacity){ + if(!size()){ + this->prot_deallocate(); + } + else{ + size_type received_size; + if(this->alloc().allocation_command + ( shrink_in_place | nothrow_allocation + , this->capacity(), this->size() + , received_size, this->members_.m_start).first){ + this->members_.m_capacity = received_size; + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_shrink; + #endif + } + } + } + } + + template + void priv_range_insert(pointer pos, FwdIt first, FwdIt last, std::forward_iterator_tag) + { + if(first != last){ + const size_type n = std::distance(first, last); + containers_detail::advanced_insert_aux_proxy proxy(first, last); + priv_range_insert(pos, n, proxy); + } + } + + void priv_range_insert(pointer pos, const size_type n, advanced_insert_aux_int_t &interf) + { + //Check if we have enough memory or try to expand current memory + size_type remaining = this->members_.m_capacity - this->members_.m_size; + bool same_buffer_start; + std::pair ret; + size_type real_cap = this->members_.m_capacity; + + //Check if we already have room + if (n <= remaining){ + same_buffer_start = true; + } + else{ + //There is not enough memory, allocate a new + //buffer or expand the old one. + size_type new_cap = this->next_capacity(n); + ret = this->allocation_command + (allocate_new | expand_fwd | expand_bwd, + this->members_.m_size + n, new_cap, real_cap, this->members_.m_start); + + //Check for forward expansion + same_buffer_start = ret.second && this->members_.m_start == ret.first; + if(same_buffer_start){ + this->members_.m_capacity = real_cap; + } + } + + //If we had room or we have expanded forward + if (same_buffer_start){ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_expand_fwd; + #endif + this->priv_range_insert_expand_forward + (containers_detail::get_pointer(pos), n, interf); + } + //Backwards (and possibly forward) expansion + else if(ret.second){ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_expand_bwd; + #endif + this->priv_range_insert_expand_backwards + ( containers_detail::get_pointer(ret.first) + , real_cap + , containers_detail::get_pointer(pos) + , n + , interf); + } + //New buffer + else{ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + this->priv_range_insert_new_allocation + ( containers_detail::get_pointer(ret.first) + , real_cap + , containers_detail::get_pointer(pos) + , n + , interf); + } + } + + void priv_range_insert_expand_forward(T* pos, size_type n, advanced_insert_aux_int_t &interf) + { + //There is enough memory + T* old_finish = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; + const size_type elems_after = old_finish - pos; + + if (elems_after > n){ + //New elements can be just copied. + //Move to uninitialized memory last objects + boost::interprocess::uninitialized_move(old_finish - n, old_finish, old_finish); + this->members_.m_size += n; + //Copy previous to last objects to the initialized end + boost::interprocess::move_backward(pos, old_finish - n, old_finish); + //Insert new objects in the pos + interf.copy_all_to(pos); + } + else { + //The new elements don't fit in the [pos, end()) range. Copy + //to the beginning of the unallocated zone the last new elements. + interf.uninitialized_copy_some_and_update(old_finish, elems_after, false); + this->members_.m_size += n - elems_after; + //Copy old [pos, end()) elements to the uninitialized memory + boost::interprocess::uninitialized_move + ( pos, old_finish, containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size); + this->members_.m_size += elems_after; + //Copy first new elements in pos + interf.copy_all_to(pos); + } + } + + void priv_range_insert_new_allocation + (T* new_start, size_type new_cap, T* pos, size_type n, advanced_insert_aux_int_t &interf) + { + T* new_finish = new_start; + T *old_finish; + //Anti-exception rollbacks + typename value_traits::UCopiedArrayDeallocator scoped_alloc(new_start, this->alloc(), new_cap); + typename value_traits::UCopiedArrayDestructor constructed_values_destroyer(new_start, 0u); + + //Initialize with [begin(), pos) old buffer + //the start of the new buffer + new_finish = boost::interprocess::uninitialized_move + (containers_detail::get_pointer(this->members_.m_start), pos, old_finish = new_finish); + constructed_values_destroyer.increment_size(new_finish - old_finish); + //Initialize new objects, starting from previous point + interf.uninitialized_copy_all_to(old_finish = new_finish); + new_finish += n; + constructed_values_destroyer.increment_size(new_finish - old_finish); + //Initialize from the rest of the old buffer, + //starting from previous point + new_finish = boost::interprocess::uninitialized_move + ( pos, containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size, new_finish); + //All construction successful, disable rollbacks + constructed_values_destroyer.release(); + scoped_alloc.release(); + //Destroy and deallocate old elements + //If there is allocated memory, destroy and deallocate + if(this->members_.m_start != 0){ + if(!value_traits::trivial_dctr_after_move) + this->destroy_n(containers_detail::get_pointer(this->members_.m_start), this->members_.m_size); + this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); + } + this->members_.m_start = new_start; + this->members_.m_size = new_finish - new_start; + this->members_.m_capacity = new_cap; + } + + void priv_range_insert_expand_backwards + (T* new_start, size_type new_capacity, + T* pos, const size_type n, advanced_insert_aux_int_t &interf) + { + //Backup old data + T* old_start = containers_detail::get_pointer(this->members_.m_start); + T* old_finish = old_start + this->members_.m_size; + size_type old_size = this->members_.m_size; + + //We can have 8 possibilities: + const size_type elemsbefore = (size_type)(pos - old_start); + const size_type s_before = (size_type)(old_start - new_start); + + //Update the vector buffer information to a safe state + this->members_.m_start = new_start; + this->members_.m_capacity = new_capacity; + this->members_.m_size = 0; + + //If anything goes wrong, this object will destroy + //all the old objects to fulfill previous vector state + typename value_traits::OldArrayDestructor old_values_destroyer(old_start, old_size); + //Check if s_before is big enough to hold the beginning of old data + new data + if(difference_type(s_before) >= difference_type(elemsbefore + n)){ + //Copy first old values before pos, after that the new objects + boost::interprocess::uninitialized_move(old_start, pos, new_start); + this->members_.m_size = elemsbefore; + interf.uninitialized_copy_all_to(new_start + elemsbefore); + this->members_.m_size += n; + //Check if s_before is so big that even copying the old data + new data + //there is a gap between the new data and the old data + if(s_before >= (old_size + n)){ + //Old situation: + // _________________________________________________________ + //| raw_mem | old_begin | old_end | + //| __________________________________|___________|_________| + // + //New situation: + // _________________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|__________|_________|________________________| + // + //Now initialize the rest of memory with the last old values + boost::interprocess::uninitialized_move + (pos, old_finish, new_start + elemsbefore + n); + //All new elements correctly constructed, avoid new element destruction + this->members_.m_size = old_size + n; + //Old values destroyed automatically with "old_values_destroyer" + //when "old_values_destroyer" goes out of scope unless the have trivial + //destructor after move. + if(value_traits::trivial_dctr_after_move) + old_values_destroyer.release(); + } + //s_before is so big that divides old_end + else{ + //Old situation: + // __________________________________________________ + //| raw_mem | old_begin | old_end | + //| ___________________________|___________|_________| + // + //New situation: + // __________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|__________|_________|_________________| + // + //Now initialize the rest of memory with the last old values + //All new elements correctly constructed, avoid new element destruction + size_type raw_gap = s_before - (elemsbefore + n); + //Now initialize the rest of s_before memory with the + //first of elements after new values + boost::interprocess::uninitialized_move(pos, pos + raw_gap, new_start + elemsbefore + n); + //Update size since we have a contiguous buffer + this->members_.m_size = old_size + s_before; + //All new elements correctly constructed, avoid old element destruction + old_values_destroyer.release(); + //Now copy remaining last objects in the old buffer begin + T *to_destroy = boost::interprocess::move(pos + raw_gap, old_finish, old_start); + //Now destroy redundant elements except if they were moved and + //they have trivial destructor after move + size_type n_destroy = old_finish - to_destroy; + if(!value_traits::trivial_dctr_after_move) + this->destroy_n(to_destroy, n_destroy); + this->members_.m_size -= n_destroy; + } + } + else{ + //Check if we have to do the insertion in two phases + //since maybe s_before is not big enough and + //the buffer was expanded both sides + // + //Old situation: + // _________________________________________________ + //| raw_mem | old_begin + old_end | raw_mem | + //|_________|_____________________|_________________| + // + //New situation with do_after: + // _________________________________________________ + //| old_begin + new + old_end | raw_mem | + //|___________________________________|_____________| + // + //New without do_after: + // _________________________________________________ + //| old_begin + new + old_end | raw_mem | + //|____________________________|____________________| + // + bool do_after = n > s_before; + + //Now we can have two situations: the raw_mem of the + //beginning divides the old_begin, or the new elements: + if (s_before <= elemsbefore) { + //The raw memory divides the old_begin group: + // + //If we need two phase construction (do_after) + //new group is divided in new = new_beg + new_end groups + //In this phase only new_beg will be inserted + // + //Old situation: + // _________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|_________|___________|_________|_________________| + // + //New situation with do_after(1): + //This is not definitive situation, the second phase + //will include + // _________________________________________________ + //| old_begin | new_beg | old_end | raw_mem | + //|___________|_________|_________|_________________| + // + //New situation without do_after: + // _________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|_____|_________|_____________________| + // + //Copy the first part of old_begin to raw_mem + T *start_n = old_start + difference_type(s_before); + boost::interprocess::uninitialized_move(old_start, start_n, new_start); + //The buffer is all constructed until old_end, + //release destroyer and update size + old_values_destroyer.release(); + this->members_.m_size = old_size + s_before; + //Now copy the second part of old_begin overwriting himself + T* next = boost::interprocess::move(start_n, pos, old_start); + if(do_after){ + //Now copy the new_beg elements + interf.copy_some_and_update(next, s_before, true); + } + else{ + //Now copy the all the new elements + interf.copy_all_to(next); + T* move_start = next + n; + //Now displace old_end elements + T* move_end = boost::interprocess::move(pos, old_finish, move_start); + //Destroy remaining moved elements from old_end except if + //they have trivial destructor after being moved + difference_type n_destroy = s_before - n; + if(!value_traits::trivial_dctr_after_move) + this->destroy_n(move_end, n_destroy); + this->members_.m_size -= n_destroy; + } + } + else { + //If we have to expand both sides, + //we will play if the first new values so + //calculate the upper bound of new values + + //The raw memory divides the new elements + // + //If we need two phase construction (do_after) + //new group is divided in new = new_beg + new_end groups + //In this phase only new_beg will be inserted + // + //Old situation: + // _______________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|_______________|___________|_________|_________________| + // + //New situation with do_after(): + // ____________________________________________________ + //| old_begin | new_beg | old_end | raw_mem | + //|___________|_______________|_________|______________| + // + //New situation without do_after: + // ______________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|_____|_________|__________________________| + // + //First copy whole old_begin and part of new to raw_mem + boost::interprocess::uninitialized_move(old_start, pos, new_start); + this->members_.m_size = elemsbefore; + + const size_type mid_n = difference_type(s_before) - elemsbefore; + interf.uninitialized_copy_some_and_update(new_start + elemsbefore, mid_n, true); + this->members_.m_size = old_size + s_before; + //The buffer is all constructed until old_end, + //release destroyer and update size + old_values_destroyer.release(); + + if(do_after){ + //Copy new_beg part + interf.copy_some_and_update(old_start, s_before - mid_n, true); + } + else{ + //Copy all new elements + interf.copy_all_to(old_start); + T* move_start = old_start + (n-mid_n); + //Displace old_end + T* move_end = boost::interprocess::move(pos, old_finish, move_start); + //Destroy remaining moved elements from old_end except if they + //have trivial destructor after being moved + difference_type n_destroy = s_before - n; + if(!value_traits::trivial_dctr_after_move) + this->destroy_n(move_end, n_destroy); + this->members_.m_size -= n_destroy; + } + } + + //This is only executed if two phase construction is needed + //This can be executed without exception handling since we + //have to just copy and append in raw memory and + //old_values_destroyer has been released in phase 1. + if(do_after){ + //The raw memory divides the new elements + // + //Old situation: + // ______________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|______________|___________|____________|______________| + // + //New situation with do_after(1): + // _______________________________________________________ + //| old_begin + new_beg | new_end |old_end | raw_mem | + //|__________________________|_________|________|_________| + // + //New situation with do_after(2): + // ______________________________________________________ + //| old_begin + new | old_end |raw | + //|_______________________________________|_________|____| + // + const size_type n_after = n - s_before; + const difference_type elemsafter = old_size - elemsbefore; + + //We can have two situations: + if (elemsafter > difference_type(n_after)){ + //The raw_mem from end will divide displaced old_end + // + //Old situation: + // ______________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|______________|___________|____________|______________| + // + //New situation with do_after(1): + // _______________________________________________________ + //| old_begin + new_beg | new_end |old_end | raw_mem | + //|__________________________|_________|________|_________| + // + //First copy the part of old_end raw_mem + T* finish_n = old_finish - difference_type(n_after); + boost::interprocess::uninitialized_move(finish_n, old_finish, old_finish); + this->members_.m_size += n_after; + //Displace the rest of old_end to the new position + boost::interprocess::move_backward(pos, finish_n, old_finish); + //Now overwrite with new_end + //The new_end part is [first + (n - n_after), last) + interf.copy_all_to(pos); + } + else { + //The raw_mem from end will divide new_end part + // + //Old situation: + // _____________________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|______________|___________|____________|_____________________| + // + //New situation with do_after(2): + // _____________________________________________________________ + //| old_begin + new_beg | new_end |old_end | raw_mem | + //|__________________________|_______________|________|_________| + // + size_type mid_last_dist = n_after - elemsafter; + //First initialize data in raw memory + //The new_end part is [first + (n - n_after), last) + interf.uninitialized_copy_some_and_update(old_finish, elemsafter, false); + this->members_.m_size += mid_last_dist; + boost::interprocess::uninitialized_move(pos, old_finish, old_finish + mid_last_dist); + this->members_.m_size += n_after - mid_last_dist; + //Now copy the part of new_end over constructed elements + interf.copy_all_to(pos); + } + } + } + } + + template + void priv_range_insert(const_iterator pos, InIt first, InIt last, std::input_iterator_tag) + { + for(;first != last; ++first){ + this->insert(pos, boost::interprocess::move(value_type(*first))); + } + } + + template + void priv_assign_aux(InIt first, InIt last, std::input_iterator_tag) + { + //Overwrite all elements we can from [first, last) + iterator cur = begin(); + for ( ; first != last && cur != end(); ++cur, ++first){ + *cur = *first; + } + + if (first == last){ + //There are no more elements in the sequence, erase remaining + this->erase(cur, cend()); + } + else{ + //There are more elements in the range, insert the remaining ones + this->insert(this->cend(), first, last); + } + } + + template + void priv_assign_aux(FwdIt first, FwdIt last, std::forward_iterator_tag) + { + size_type n = std::distance(first, last); + //Check if we have enough memory or try to expand current memory + size_type remaining = this->members_.m_capacity - this->members_.m_size; + bool same_buffer_start; + std::pair ret; + size_type real_cap = this->members_.m_capacity; + + if (n <= remaining){ + same_buffer_start = true; + } + else{ + //There is not enough memory, allocate a new buffer + size_type new_cap = this->next_capacity(n); + ret = this->allocation_command + (allocate_new | expand_fwd | expand_bwd, + this->size() + n, new_cap, real_cap, this->members_.m_start); + same_buffer_start = ret.second && this->members_.m_start == ret.first; + if(same_buffer_start){ + this->members_.m_capacity = real_cap; + } + } + + if(same_buffer_start){ + T *start = containers_detail::get_pointer(this->members_.m_start); + if (this->size() >= n){ + //There is memory, but there are more old elements than new ones + //Overwrite old elements with new ones + // iG std::copy(first, last, start); + std::copy(first, last, start); + //Destroy remaining old elements + this->destroy_n(start + n, this->members_.m_size - n); + this->members_.m_size = n; + } + else{ + //There is memory, but there are less old elements than new ones + //First overwrite some old elements with new ones + FwdIt mid = first; + std::advance(mid, this->size()); + // iG T *end = std::copy(first, mid, start); + T *end = std::copy(first, mid, start); + //Initialize the remaining new elements in the uninitialized memory + // iG std::uninitialized_copy(mid, last, end); + boost::interprocess::uninitialized_copy_or_move(mid, last, end); + this->members_.m_size = n; + } + } + else if(!ret.second){ + typename value_traits::UCopiedArrayDeallocator scoped_alloc(ret.first, this->alloc(), real_cap); + // iG std::uninitialized_copy(first, last, containers_detail::get_pointer(ret.first)); + boost::interprocess::uninitialized_copy_or_move(first, last, containers_detail::get_pointer(ret.first)); + scoped_alloc.release(); + //Destroy and deallocate old buffer + if(this->members_.m_start != 0){ + this->destroy_n(containers_detail::get_pointer(this->members_.m_start), this->members_.m_size); + this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); + } + this->members_.m_start = ret.first; + this->members_.m_size = n; + this->members_.m_capacity = real_cap; + } + else{ + //Backwards expansion + //If anything goes wrong, this object will destroy old objects + T *old_start = containers_detail::get_pointer(this->members_.m_start); + size_type old_size = this->members_.m_size; + typename value_traits::OldArrayDestructor old_values_destroyer(old_start, old_size); + //If something goes wrong size will be 0 + //but holding the whole buffer + this->members_.m_size = 0; + this->members_.m_start = ret.first; + this->members_.m_capacity = real_cap; + + //Backup old buffer data + size_type old_offset = old_start - containers_detail::get_pointer(ret.first); + size_type first_count = containers_detail::min_value(n, old_offset); + + FwdIt mid = first; + std::advance(mid, first_count); + // iG std::uninitialized_copy(first, mid, containers_detail::get_pointer(ret.first)); + boost::interprocess::uninitialized_copy_or_move(first, mid, containers_detail::get_pointer(ret.first)); + + if(old_offset > n){ + //All old elements will be destroyed by "old_values_destroyer" + this->members_.m_size = n; + } + else{ + //We have constructed objects from the new begin until + //the old end so release the rollback destruction + old_values_destroyer.release(); + this->members_.m_start = ret.first; + this->members_.m_size = first_count + old_size; + //Now overwrite the old values + size_type second_count = containers_detail::min_value(old_size, n - first_count); + FwdIt mid2 = mid; + std::advance(mid2, second_count); + // iG std::copy(mid, mid2, old_start); + std::copy(mid, mid2, old_start); + + //Check if we still have to append elements in the + //uninitialized end + if(second_count == old_size){ + // iG std::copy(mid2, last, old_start + old_size); + std::copy(mid2, last, old_start + old_size); + } + else{ + //We have to destroy some old values + this->destroy_n + (old_start + second_count, old_size - second_count); + this->members_.m_size = n; + } + this->members_.m_size = n; + } + } + } + + template + void priv_assign_dispatch(Integer n, Integer val, containers_detail::true_) + { this->assign((size_type) n, (T) val); } + + template + void priv_assign_dispatch(InIt first, InIt last, containers_detail::false_) + { + //Dispatch depending on integer/iterator + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_assign_aux(first, last, ItCat()); + } + + template + void priv_insert_dispatch(const_iterator pos, Integer n, Integer val, containers_detail::true_) + { this->insert(pos, (size_type)n, (T)val); } + + template + void priv_insert_dispatch(const_iterator pos, InIt first, + InIt last, containers_detail::false_) + { + //Dispatch depending on integer/iterator + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_range_insert(pos.get_ptr(), first, last, ItCat()); + } + + void priv_check_range(size_type n) const + { + //If n is out of range, throw an out_of_range exception + if (n >= size()) + throw std::out_of_range("vector::at"); + } + + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + public: + unsigned int num_expand_fwd; + unsigned int num_expand_bwd; + unsigned int num_shrink; + unsigned int num_alloc; + void reset_alloc_stats() + { num_expand_fwd = num_expand_bwd = num_alloc = 0, num_shrink = 0; } + #endif + /// @endcond +}; + +template +inline bool +operator==(const vector& x, const vector& y) +{ + //Check first size and each element if needed + return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool +operator!=(const vector& x, const vector& y) +{ + //Check first size and each element if needed + return x.size() != y.size() || !std::equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool +operator<(const vector& x, const vector& y) +{ + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); +} + +template +inline void swap(vector& x, vector& y) +{ x.swap(y); } + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value; +}; + +}} + +/// @endcond + +#include + +#endif // #ifndef BOOST_CONTAINERS_CONTAINERS_VECTOR_HPP + diff --git a/include/boost/interprocess/containers/deque.hpp b/include/boost/interprocess/containers/deque.hpp index e820596..249fda6 100644 --- a/include/boost/interprocess/containers/deque.hpp +++ b/include/boost/interprocess/containers/deque.hpp @@ -1,1538 +1,32 @@ -/* - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2006. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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. // ////////////////////////////////////////////////////////////////////////////// -// -// This file comes from SGI's stl_deque.h and stl_uninitialized.h files. -// Modified by Ion Gaztanaga 2005. -// Renaming, isolating and porting to generic algorithms. Pointer typedef -// set to allocator::pointer to allow placing it in shared memory. -// -/////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DEQUE_HPP -#define BOOST_INTERPROCESS_DEQUE_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP +#define BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace interprocess { -/// @cond -template -class deque; - -template -struct deque_value_traits -{ - typedef T value_type; - typedef A allocator_type; - static const bool trivial_dctr = boost::has_trivial_destructor::value; - static const bool trivial_dctr_after_move = - has_trivial_destructor_after_move::value || trivial_dctr; - static const bool trivial_copy = has_trivial_copy::value; - static const bool nothrow_copy = has_nothrow_copy::value; - static const bool trivial_assign = has_trivial_assign::value; - static const bool nothrow_assign = has_nothrow_assign::value; - -}; - -// Note: this function is simply a kludge to work around several compilers' -// bugs in handling constant expressions. -inline std::size_t deque_buf_size(std::size_t size) - { return size < 512 ? std::size_t(512 / size) : std::size_t(1); } - -// Deque base class. It has two purposes. First, its constructor -// and destructor allocate (but don't initialize) storage. This makes -// exception safety easier. -template -class deque_base -{ - public: - typedef typename Alloc::value_type val_alloc_val; - typedef typename Alloc::pointer val_alloc_ptr; - typedef typename Alloc::const_pointer val_alloc_cptr; - typedef typename Alloc::reference val_alloc_ref; - typedef typename Alloc::const_reference val_alloc_cref; - typedef typename Alloc::value_type val_alloc_diff; - typedef typename Alloc::template rebind - ::other ptr_alloc_t; - typedef typename ptr_alloc_t::value_type ptr_alloc_val; - typedef typename ptr_alloc_t::pointer ptr_alloc_ptr; - typedef typename ptr_alloc_t::const_pointer ptr_alloc_cptr; - typedef typename ptr_alloc_t::reference ptr_alloc_ref; - typedef typename ptr_alloc_t::const_reference ptr_alloc_cref; - typedef typename Alloc::template - rebind::other allocator_type; - typedef allocator_type stored_allocator_type; - - protected: - - typedef deque_value_traits traits_t; - typedef typename Alloc::template - rebind::other map_allocator_type; - - static std::size_t s_buffer_size() { return deque_buf_size(sizeof(T)); } - - val_alloc_ptr priv_allocate_node() - { return this->alloc().allocate(s_buffer_size()); } - - void priv_deallocate_node(val_alloc_ptr p) - { this->alloc().deallocate(p, s_buffer_size()); } - - ptr_alloc_ptr priv_allocate_map(std::size_t n) - { return this->ptr_alloc().allocate(n); } - - void priv_deallocate_map(ptr_alloc_ptr p, std::size_t n) - { this->ptr_alloc().deallocate(p, n); } - - public: - // Class invariants: - // For any nonsingular iterator i: - // i.node is the address of an element in the map array. The - // contents of i.node is a pointer to the beginning of a node. - // i.first == //(i.node) - // i.last == i.first + node_size - // i.cur is a pointer in the range [i.first, i.last). NOTE: - // the implication of this is that i.cur is always a dereferenceable - // pointer, even if i is a past-the-end iterator. - // Start and Finish are always nonsingular iterators. NOTE: this means - // that an empty deque must have one node, and that a deque - // with N elements, where N is the buffer size, must have two nodes. - // For every node other than start.node and finish.node, every element - // in the node is an initialized object. If start.node == finish.node, - // then [start.cur, finish.cur) are initialized objects, and - // the elements outside that range are uninitialized storage. Otherwise, - // [start.cur, start.last) and [finish.first, finish.cur) are initialized - // objects, and [start.first, start.cur) and [finish.cur, finish.last) - // are uninitialized storage. - // [map, map + map_size) is a valid, non-empty range. - // [start.node, finish.node] is a valid range contained within - // [map, map + map_size). - // A pointer in the range [map, map + map_size) points to an allocated node - // if and only if the pointer is in the range [start.node, finish.node]. - class const_iterator - : public std::iterator - { - public: - static std::size_t s_buffer_size() { return deque_base::s_buffer_size(); } - - typedef std::random_access_iterator_tag iterator_category; - typedef val_alloc_val value_type; - typedef val_alloc_cptr pointer; - typedef val_alloc_cref reference; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - typedef ptr_alloc_ptr index_pointer; - typedef const_iterator self_t; - - friend class deque; - friend class deque_base; - - protected: - val_alloc_ptr m_cur; - val_alloc_ptr m_first; - val_alloc_ptr m_last; - index_pointer m_node; - - public: - const_iterator(val_alloc_ptr x, index_pointer y) - : m_cur(x), m_first(*y), - m_last(*y + s_buffer_size()), m_node(y) {} - - const_iterator() : m_cur(0), m_first(0), m_last(0), m_node(0) {} - - const_iterator(const const_iterator& x) - : m_cur(x.m_cur), m_first(x.m_first), - m_last(x.m_last), m_node(x.m_node) {} - - reference operator*() const - { return *this->m_cur; } - - pointer operator->() const - { return this->m_cur; } - - difference_type operator-(const self_t& x) const - { - if(!this->m_cur && !x.m_cur){ - return 0; - } - return difference_type(this->s_buffer_size()) * (this->m_node - x.m_node - 1) + - (this->m_cur - this->m_first) + (x.m_last - x.m_cur); - } - - self_t& operator++() - { - ++this->m_cur; - if (this->m_cur == this->m_last) { - this->priv_set_node(this->m_node + 1); - this->m_cur = this->m_first; - } - return *this; - } - - self_t operator++(int) - { - self_t tmp = *this; - ++*this; - return tmp; - } - - self_t& operator--() - { - if (this->m_cur == this->m_first) { - this->priv_set_node(this->m_node - 1); - this->m_cur = this->m_last; - } - --this->m_cur; - return *this; - } - - self_t operator--(int) - { - self_t tmp = *this; - --*this; - return tmp; - } - - self_t& operator+=(difference_type n) - { - difference_type offset = n + (this->m_cur - this->m_first); - if (offset >= 0 && offset < difference_type(this->s_buffer_size())) - this->m_cur += n; - else { - difference_type node_offset = - offset > 0 ? offset / difference_type(this->s_buffer_size()) - : -difference_type((-offset - 1) / this->s_buffer_size()) - 1; - this->priv_set_node(this->m_node + node_offset); - this->m_cur = this->m_first + - (offset - node_offset * difference_type(this->s_buffer_size())); - } - return *this; - } - - self_t operator+(difference_type n) const - { self_t tmp = *this; return tmp += n; } - - self_t& operator-=(difference_type n) - { return *this += -n; } - - self_t operator-(difference_type n) const - { self_t tmp = *this; return tmp -= n; } - - reference operator[](difference_type n) const - { return *(*this + n); } - - bool operator==(const self_t& x) const - { return this->m_cur == x.m_cur; } - - bool operator!=(const self_t& x) const - { return !(*this == x); } - - bool operator<(const self_t& x) const - { - return (this->m_node == x.m_node) ? - (this->m_cur < x.m_cur) : (this->m_node < x.m_node); - } - - bool operator>(const self_t& x) const - { return x < *this; } - - bool operator<=(const self_t& x) const - { return !(x < *this); } - - bool operator>=(const self_t& x) const - { return !(*this < x); } - - void priv_set_node(index_pointer new_node) - { - this->m_node = new_node; - this->m_first = *new_node; - this->m_last = this->m_first + difference_type(this->s_buffer_size()); - } - - friend const_iterator operator+(std::ptrdiff_t n, const const_iterator& x) - { return x + n; } - }; - - //Deque iterator - class iterator : public const_iterator - { - public: - typedef std::random_access_iterator_tag iterator_category; - typedef val_alloc_val value_type; - typedef val_alloc_ptr pointer; - typedef val_alloc_ref reference; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - typedef ptr_alloc_ptr index_pointer; - typedef const_iterator self_t; - - friend class deque; - friend class deque_base; - - private: - explicit iterator(const const_iterator& x) : const_iterator(x){} - - public: - //Constructors - iterator(val_alloc_ptr x, index_pointer y) : const_iterator(x, y){} - iterator() : const_iterator(){} - //iterator(const const_iterator &cit) : const_iterator(cit){} - iterator(const iterator& x) : const_iterator(x){} - - //Pointer like operators - reference operator*() const { return *this->m_cur; } - pointer operator->() const { return this->m_cur; } - - reference operator[](difference_type n) const { return *(*this + n); } - - //Increment / Decrement - iterator& operator++() - { this->const_iterator::operator++(); return *this; } - - iterator operator++(int) - { iterator tmp = *this; ++*this; return tmp; } - - iterator& operator--() - { this->const_iterator::operator--(); return *this; } - - iterator operator--(int) - { iterator tmp = *this; --*this; return tmp; } - - // Arithmetic - iterator& operator+=(difference_type off) - { this->const_iterator::operator+=(off); return *this; } - - iterator operator+(difference_type off) const - { return iterator(this->const_iterator::operator+(off)); } - - friend iterator operator+(difference_type off, const iterator& right) - { return iterator(off+static_cast(right)); } - - iterator& operator-=(difference_type off) - { this->const_iterator::operator-=(off); return *this; } - - iterator operator-(difference_type off) const - { return iterator(this->const_iterator::operator-(off)); } - - difference_type operator-(const const_iterator& right) const - { return static_cast(*this) - right; } - }; - - deque_base(const allocator_type& a, std::size_t num_elements) - : members_(a) - { this->priv_initialize_map(num_elements); } - - deque_base(const allocator_type& a) - : members_(a) - {} - - ~deque_base() - { - if (this->members_.m_map) { - this->priv_destroy_nodes(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1); - this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); - } - } - - private: - deque_base(const deque_base&); - - protected: - - void priv_initialize_map(std::size_t num_elements) - { -// if(num_elements){ - std::size_t num_nodes = num_elements / s_buffer_size() + 1; - - this->members_.m_map_size = max_value((std::size_t) InitialMapSize, num_nodes + 2); - this->members_.m_map = this->priv_allocate_map(this->members_.m_map_size); - - ptr_alloc_ptr nstart = this->members_.m_map + (this->members_.m_map_size - num_nodes) / 2; - ptr_alloc_ptr nfinish = nstart + num_nodes; - - BOOST_TRY { - this->priv_create_nodes(nstart, nfinish); - } - BOOST_CATCH(...){ - this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); - this->members_.m_map = 0; - this->members_.m_map_size = 0; - BOOST_RETHROW - } - BOOST_CATCH_END - - this->members_.m_start.priv_set_node(nstart); - this->members_.m_finish.priv_set_node(nfinish - 1); - this->members_.m_start.m_cur = this->members_.m_start.m_first; - this->members_.m_finish.m_cur = this->members_.m_finish.m_first + - num_elements % s_buffer_size(); -// } - } - - void priv_create_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) - { - ptr_alloc_ptr cur; - BOOST_TRY { - for (cur = nstart; cur < nfinish; ++cur) - *cur = this->priv_allocate_node(); - } - BOOST_CATCH(...){ - this->priv_destroy_nodes(nstart, cur); - BOOST_RETHROW - } - BOOST_CATCH_END - } - - void priv_destroy_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) - { - for (ptr_alloc_ptr n = nstart; n < nfinish; ++n) - this->priv_deallocate_node(*n); - } - - enum { InitialMapSize = 8 }; - - protected: - struct members_holder - : public ptr_alloc_t - , public allocator_type - { - members_holder(const allocator_type &a) - : map_allocator_type(a), allocator_type(a) - , m_map(0), m_map_size(0) - , m_start(), m_finish(m_start) - {} - - ptr_alloc_ptr m_map; - std::size_t m_map_size; - iterator m_start; - iterator m_finish; - } members_; - - ptr_alloc_t &ptr_alloc() - { return members_; } - - const ptr_alloc_t &ptr_alloc() const - { return members_; } - - allocator_type &alloc() - { return members_; } - - const allocator_type &alloc() const - { return members_; } -}; -/// @endcond - -//! Deque class -//! -template -class deque : protected deque_base -{ - /// @cond - typedef deque_base Base; - - public: // Basic types - typedef typename Alloc::value_type val_alloc_val; - typedef typename Alloc::pointer val_alloc_ptr; - typedef typename Alloc::const_pointer val_alloc_cptr; - typedef typename Alloc::reference val_alloc_ref; - typedef typename Alloc::const_reference val_alloc_cref; - typedef typename Alloc::template - rebind::other ptr_alloc_t; - typedef typename ptr_alloc_t::value_type ptr_alloc_val; - typedef typename ptr_alloc_t::pointer ptr_alloc_ptr; - typedef typename ptr_alloc_t::const_pointer ptr_alloc_cptr; - typedef typename ptr_alloc_t::reference ptr_alloc_ref; - typedef typename ptr_alloc_t::const_reference ptr_alloc_cref; - /// @endcond - - typedef T value_type; - typedef val_alloc_ptr pointer; - typedef val_alloc_cptr const_pointer; - typedef val_alloc_ref reference; - typedef val_alloc_cref const_reference; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - typedef typename Base::allocator_type allocator_type; - - public: // Iterators - typedef typename Base::iterator iterator; - typedef typename Base::const_iterator const_iterator; - - typedef std::reverse_iterator const_reverse_iterator; - typedef std::reverse_iterator reverse_iterator; - - /// @cond - private: // Internal typedefs - typedef ptr_alloc_ptr index_pointer; - static std::size_t s_buffer_size() - { return Base::s_buffer_size(); } - typedef detail::advanced_insert_aux_int advanced_insert_aux_int_t; - typedef repeat_iterator r_iterator; - typedef detail::move_iterator move_it; - - /// @endcond - - allocator_type get_allocator() const { return Base::alloc(); } - - public: // Basic accessors - iterator begin() - { return this->members_.m_start; } - - iterator end() - { return this->members_.m_finish; } - - const_iterator begin() const - { return this->members_.m_start; } - - const_iterator end() const - { return this->members_.m_finish; } - - reverse_iterator rbegin() - { return reverse_iterator(this->members_.m_finish); } - - reverse_iterator rend() - { return reverse_iterator(this->members_.m_start); } - - const_reverse_iterator rbegin() const - { return const_reverse_iterator(this->members_.m_finish); } - - const_reverse_iterator rend() const - { return const_reverse_iterator(this->members_.m_start); } - - const_iterator cbegin() const - { return this->members_.m_start; } - - const_iterator cend() const - { return this->members_.m_finish; } - - const_reverse_iterator crbegin() const - { return const_reverse_iterator(this->members_.m_finish); } - - const_reverse_iterator crend() const - { return const_reverse_iterator(this->members_.m_start); } - - reference operator[](size_type n) - { return this->members_.m_start[difference_type(n)]; } - - const_reference operator[](size_type n) const - { return this->members_.m_start[difference_type(n)]; } - - void priv_range_check(size_type n) const - { if (n >= this->size()) BOOST_RETHROW std::out_of_range("deque"); } - - reference at(size_type n) - { this->priv_range_check(n); return (*this)[n]; } - - const_reference at(size_type n) const - { this->priv_range_check(n); return (*this)[n]; } - - reference front() { return *this->members_.m_start; } - - reference back() { return *(end()-1); } - - const_reference front() const - { return *this->members_.m_start; } - - const_reference back() const { return *(cend()-1); } - - size_type size() const - { return this->members_.m_finish - this->members_.m_start; } - - size_type max_size() const - { return this->alloc().max_size(); } - - bool empty() const - { return this->members_.m_finish == this->members_.m_start; } - - explicit deque(const allocator_type& a = allocator_type()) - : Base(a) - {} - - deque(const deque& x) - : Base(x.alloc()) - { - if(x.size()){ - this->priv_initialize_map(x.size()); - std::uninitialized_copy(x.begin(), x.end(), this->members_.m_start); - } - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - deque(detail::moved_object mx) - : Base(mx.get().alloc()) - { this->swap(mx.get()); } - #else - deque(deque &&x) - : Base(x.alloc()) - { this->swap(x); } - #endif - - deque(size_type n, const value_type& value, - const allocator_type& a = allocator_type()) : Base(a, n) - { this->priv_fill_initialize(value); } - - explicit deque(size_type n) : Base(allocator_type(), n) - { this->resize(n); } - - // Check whether it's an integral type. If so, it's not an iterator. - template - deque(InpIt first, InpIt last, const allocator_type& a = allocator_type()) - : Base(a) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_initialize_dispatch(first, last, Result()); - } - - ~deque() - { - priv_destroy_range(this->members_.m_start, this->members_.m_finish); - } - - deque& operator= (const deque& x) - { - const size_type len = size(); - if (&x != this) { - if (len >= x.size()) - this->erase(std::copy(x.begin(), x.end(), this->members_.m_start), this->members_.m_finish); - else { - const_iterator mid = x.begin() + difference_type(len); - std::copy(x.begin(), mid, this->members_.m_start); - this->insert(this->members_.m_finish, mid, x.end()); - } - } - return *this; - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - deque& operator= (detail::moved_object mx) - { - deque &x = mx.get(); - #else - deque& operator= (deque &&x) - { - #endif - this->clear(); - this->swap(x); - return *this; - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(deque& x) - #else - void swap(deque &&x) - #endif - { - std::swap(this->members_.m_start, x.members_.m_start); - std::swap(this->members_.m_finish, x.members_.m_finish); - std::swap(this->members_.m_map, x.members_.m_map); - std::swap(this->members_.m_map_size, x.members_.m_map_size); - } - - void assign(size_type n, const T& val) - { this->priv_fill_assign(n, val); } - - template - void assign(InpIt first, InpIt last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); - } - - void push_back(const value_type& t) - { - if(this->priv_push_back_simple_available()){ - new(this->priv_push_back_simple_pos())value_type(t); - this->priv_push_back_simple_commit(); - } - else{ - this->priv_insert_aux(cend(), size_type(1), t); - } - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_back(detail::moved_object mt) - { - value_type &t = mt.get(); - #else - void push_back(value_type &&t) - { - #endif - if(this->priv_push_back_simple_available()){ - new(this->priv_push_back_simple_pos())value_type(detail::move_impl(t)); - this->priv_push_back_simple_commit(); - } - else{ - this->priv_insert_aux(cend(), move_it(r_iterator(t, 1)), move_it(r_iterator())); - } - } - - void push_front(const value_type& t) - { - if(this->priv_push_front_simple_available()){ - new(this->priv_push_front_simple_pos())value_type(t); - this->priv_push_front_simple_commit(); - } - else{ - this->priv_insert_aux(cbegin(), size_type(1), t); - } - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_front(detail::moved_object mt) - { - value_type &t = mt.get(); - #else - void push_front(value_type &&t) - { - #endif - if(this->priv_push_front_simple_available()){ - new(this->priv_push_front_simple_pos())value_type(detail::move_impl(t)); - this->priv_push_front_simple_commit(); - } - else{ - this->priv_insert_aux(cbegin(), move_it(r_iterator(t, 1)), move_it(r_iterator())); - } - } - - void pop_back() - { - if (this->members_.m_finish.m_cur != this->members_.m_finish.m_first) { - --this->members_.m_finish.m_cur; - detail::get_pointer(this->members_.m_finish.m_cur)->~value_type(); - } - else - this->priv_pop_back_aux(); - } - - void pop_front() - { - if (this->members_.m_start.m_cur != this->members_.m_start.m_last - 1) { - detail::get_pointer(this->members_.m_start.m_cur)->~value_type(); - ++this->members_.m_start.m_cur; - } - else - this->priv_pop_front_aux(); - } - - iterator insert(const_iterator position, const value_type& x) - { - if (position == cbegin()){ - this->push_front(x); - return begin(); - } - else if (position == cend()){ - this->push_back(x); - return (end()-1); - } - else { - size_type n = position - cbegin(); - this->priv_insert_aux(position, size_type(1), x); - return iterator(this->begin() + n); - } - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object m) - { - value_type &mx = m.get(); - #else - iterator insert(const_iterator position, value_type &&mx) - { - #endif - if (position == cbegin()) { - this->push_front(detail::move_impl(mx)); - return begin(); - } - else if (position == cend()) { - this->push_back(detail::move_impl(mx)); - return(end()-1); - } - else { - //Just call more general insert(pos, size, value) and return iterator - size_type n = position - begin(); - this->priv_insert_aux(position, move_it(r_iterator(mx, 1)), move_it(r_iterator())); - return iterator(this->begin() + n); - } - } - - void insert(const_iterator pos, size_type n, const value_type& x) - { this->priv_fill_insert(pos, n, x); } - - // Check whether it's an integral type. If so, it's not an iterator. - template - void insert(const_iterator pos, InpIt first, InpIt last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_dispatch(pos, first, last, Result()); - } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - template - void emplace_back(Args&&... args) - { - if(this->priv_push_back_simple_available()){ - new(this->priv_push_back_simple_pos())value_type(detail::forward_impl(args)...); - this->priv_push_back_simple_commit(); - } - else{ - detail::advanced_insert_aux_emplace proxy(detail::forward_impl(args)...); - this->priv_insert_aux_impl(this->cend(), 1, proxy); - } - } - - template - void emplace_front(Args&&... args) - { - if(this->priv_push_front_simple_available()){ - new(this->priv_push_front_simple_pos())value_type(detail::forward_impl(args)...); - this->priv_push_front_simple_commit(); - } - else{ - detail::advanced_insert_aux_emplace proxy(detail::forward_impl(args)...); - this->priv_insert_aux_impl(this->cbegin(), 1, proxy); - } - } - - template - iterator emplace(const_iterator p, Args&&... args) - { - if(p == this->cbegin()){ - this->emplace_front(detail::forward_impl(args)...); - return this->begin(); - } - else if(p == this->cend()){ - this->emplace_back(detail::forward_impl(args)...); - return (this->end()-1); - } - else{ - size_type n = p - this->cbegin(); - detail::advanced_insert_aux_emplace proxy(detail::forward_impl(args)...); - this->priv_insert_aux_impl(p, 1, proxy); - return iterator(this->begin() + n); - } - } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //0 args - void emplace_back() - { - if(priv_push_front_simple_available()){ - new(priv_push_front_simple_pos())value_type(); - priv_push_front_simple_commit(); - } - else{ - detail::advanced_insert_aux_emplace proxy; - priv_insert_aux_impl(cend(), 1, proxy); - } - } - - void emplace_front() - { - if(priv_push_front_simple_available()){ - new(priv_push_front_simple_pos())value_type(); - priv_push_front_simple_commit(); - } - else{ - detail::advanced_insert_aux_emplace proxy; - priv_insert_aux_impl(cbegin(), 1, proxy); - } - } - - iterator emplace(const_iterator p) - { - if(p == cbegin()){ - emplace_front(); - return begin(); - } - else if(p == cend()){ - emplace_back(); - return (end()-1); - } - else{ - size_type n = p - cbegin(); - detail::advanced_insert_aux_emplace proxy; - priv_insert_aux_impl(p, 1, proxy); - return iterator(this->begin() + n); - } - } - - //advanced_insert_int.hpp includes all necessary preprocessor machinery... - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - void emplace_back(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - if(priv_push_back_simple_available()){ \ - new(priv_push_back_simple_pos())value_type \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_push_back_simple_commit(); \ - } \ - else{ \ - detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ - \ - proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_insert_aux_impl(cend(), 1, proxy); \ - } \ - } \ - \ - template \ - void emplace_front(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - if(priv_push_front_simple_available()){ \ - new(priv_push_front_simple_pos())value_type \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_push_front_simple_commit(); \ - } \ - else{ \ - detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ - \ - proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_insert_aux_impl(cbegin(), 1, proxy); \ - } \ - } \ - \ - template \ - iterator emplace(const_iterator p, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - if(p == this->cbegin()){ \ - this->emplace_front(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - return this->begin(); \ - } \ - else if(p == cend()){ \ - this->emplace_back(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - return (this->end()-1); \ - } \ - else{ \ - size_type pos_num = p - this->cbegin(); \ - detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ - \ - proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - this->priv_insert_aux_impl(p, 1, proxy); \ - return iterator(this->begin() + pos_num); \ - } \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - void resize(size_type new_size, const value_type& x) - { - const size_type len = size(); - if (new_size < len) - this->erase(this->members_.m_start + new_size, this->members_.m_finish); - else - this->insert(this->members_.m_finish, new_size - len, x); - } - - void resize(size_type new_size) - { - const size_type len = size(); - if (new_size < len) - this->erase(this->members_.m_start + new_size, this->members_.m_finish); - else{ - size_type n = new_size - this->size(); - detail::default_construct_aux_proxy proxy(n); - priv_insert_aux_impl(this->cend(), n, proxy); - } - } - - iterator erase(const_iterator pos) - { - const_iterator next = pos; - ++next; - difference_type index = pos - this->members_.m_start; - if (size_type(index) < (this->size() >> 1)) { - std::copy_backward( detail::make_move_iterator(begin()) - , detail::make_move_iterator(iterator(pos)) - , iterator(next)); - pop_front(); - } - else { - std::copy( detail::make_move_iterator(iterator(next)) - , detail::make_move_iterator(end()) - , iterator(pos)); - pop_back(); - } - return this->members_.m_start + index; - } - - iterator erase(const_iterator first, const_iterator last) - { - if (first == this->members_.m_start && last == this->members_.m_finish) { - this->clear(); - return this->members_.m_finish; - } - else { - difference_type n = last - first; - difference_type elems_before = first - this->members_.m_start; - if (elems_before < static_cast(this->size() - n) - elems_before) { - std::copy_backward( detail::make_move_iterator(begin()) - , detail::make_move_iterator(iterator(first)) - , iterator(last)); - iterator new_start = this->members_.m_start + n; - if(!Base::traits_t::trivial_dctr_after_move) - this->priv_destroy_range(this->members_.m_start, new_start); - this->priv_destroy_nodes(new_start.m_node, this->members_.m_start.m_node); - this->members_.m_start = new_start; - } - else { - std::copy( detail::make_move_iterator(iterator(last)) - , detail::make_move_iterator(end()) - , iterator(first)); - iterator new_finish = this->members_.m_finish - n; - if(!Base::traits_t::trivial_dctr_after_move) - this->priv_destroy_range(new_finish, this->members_.m_finish); - this->priv_destroy_nodes(new_finish.m_node + 1, this->members_.m_finish.m_node + 1); - this->members_.m_finish = new_finish; - } - return this->members_.m_start + elems_before; - } - } - - void clear() - { - for (index_pointer node = this->members_.m_start.m_node + 1; - node < this->members_.m_finish.m_node; - ++node) { - this->priv_destroy_range(*node, *node + this->s_buffer_size()); - this->priv_deallocate_node(*node); - } - - if (this->members_.m_start.m_node != this->members_.m_finish.m_node) { - this->priv_destroy_range(this->members_.m_start.m_cur, this->members_.m_start.m_last); - this->priv_destroy_range(this->members_.m_finish.m_first, this->members_.m_finish.m_cur); - this->priv_deallocate_node(this->members_.m_finish.m_first); - } - else - this->priv_destroy_range(this->members_.m_start.m_cur, this->members_.m_finish.m_cur); - - this->members_.m_finish = this->members_.m_start; - } - - /// @cond - private: - - bool priv_push_back_simple_available() const - { - return this->members_.m_map && - (this->members_.m_finish.m_cur != (this->members_.m_finish.m_last - 1)); - } - - void *priv_push_back_simple_pos() const - { - return static_cast(detail::get_pointer(this->members_.m_finish.m_cur)); - } - - void priv_push_back_simple_commit() - { - ++this->members_.m_finish.m_cur; - } - - bool priv_push_front_simple_available() const - { - return this->members_.m_map && - (this->members_.m_start.m_cur != this->members_.m_start.m_first); - } - - void *priv_push_front_simple_pos() const - { return static_cast(detail::get_pointer(this->members_.m_start.m_cur) - 1); } - - void priv_push_front_simple_commit() - { --this->members_.m_start.m_cur; } - - template - void priv_insert_aux(const_iterator pos, InpIt first, InpIt last, std::input_iterator_tag) - { - for(;first != last; ++first){ - this->insert(pos, move_impl(value_type(*first))); - } - } - - template - void priv_insert_aux(const_iterator pos, FwdIt first, FwdIt last, std::forward_iterator_tag) - { this->priv_insert_aux(pos, first, last); } - - // assign(), a generalized assignment member function. Two - // versions: one that takes a count, and one that takes a range. - // The range version is a member template, so we dispatch on whether - // or not the type is an integer. - void priv_fill_assign(size_type n, const T& val) - { - if (n > size()) { - std::fill(begin(), end(), val); - this->insert(cend(), n - size(), val); - } - else { - this->erase(cbegin() + n, cend()); - std::fill(begin(), end(), val); - } - } - - template - void priv_initialize_dispatch(Integer n, Integer x, detail::true_) - { - this->priv_initialize_map(n); - this->priv_fill_initialize(x); - } - - template - void priv_initialize_dispatch(InpIt first, InpIt last, detail::false_) - { - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_range_initialize(first, last, ItCat()); - } - - void priv_destroy_range(iterator p, iterator p2) - { - for(;p != p2; ++p) - detail::get_pointer(&*p)->~value_type(); - } - - void priv_destroy_range(pointer p, pointer p2) - { - for(;p != p2; ++p) - detail::get_pointer(&*p)->~value_type(); - } - - template - void priv_assign_dispatch(Integer n, Integer val, detail::true_) - { this->priv_fill_assign((size_type) n, (T) val); } - - template - void priv_assign_dispatch(InpIt first, InpIt last, detail::false_) - { - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_assign_aux(first, last, ItCat()); - } - - template - void priv_assign_aux(InpIt first, InpIt last, std::input_iterator_tag) - { - iterator cur = begin(); - for ( ; first != last && cur != end(); ++cur, ++first) - *cur = *first; - if (first == last) - this->erase(cur, cend()); - else - this->insert(cend(), first, last); - } - - template - void priv_assign_aux(FwdIt first, FwdIt last, std::forward_iterator_tag) - { - size_type len = std::distance(first, last); - if (len > size()) { - FwdIt mid = first; - std::advance(mid, size()); - std::copy(first, mid, begin()); - this->insert(cend(), mid, last); - } - else - this->erase(std::copy(first, last, begin()), cend()); - } - - template - void priv_insert_dispatch(const_iterator pos, Integer n, Integer x, detail::true_) - { this->priv_fill_insert(pos, (size_type) n, (value_type) x); } - - template - void priv_insert_dispatch(const_iterator pos,InpIt first, InpIt last, detail::false_) - { - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_insert_aux(pos, first, last, ItCat()); - } - - void priv_insert_aux(const_iterator pos, size_type n, const value_type& x) - { - typedef constant_iterator c_it; - this->priv_insert_aux(pos, c_it(x, n), c_it()); - } - - //Just forward all operations to priv_insert_aux_impl - template - void priv_insert_aux(const_iterator p, FwdIt first, FwdIt last) - { - detail::advanced_insert_aux_proxy proxy(first, last); - priv_insert_aux_impl(p, (size_type)std::distance(first, last), proxy); - } - - void priv_insert_aux_impl(const_iterator p, size_type n, advanced_insert_aux_int_t &interf) - { - iterator pos(p); - if(!this->members_.m_map){ - this->priv_initialize_map(0); - pos = this->begin(); - } - - const difference_type elemsbefore = pos - this->members_.m_start; - size_type length = this->size(); - if (elemsbefore < static_cast(length / 2)) { - iterator new_start = this->priv_reserve_elements_at_front(n); - iterator old_start = this->members_.m_start; - pos = this->members_.m_start + elemsbefore; - if (elemsbefore >= difference_type(n)) { - iterator start_n = this->members_.m_start + difference_type(n); - std::uninitialized_copy(detail::make_move_iterator(this->members_.m_start), detail::make_move_iterator(start_n), new_start); - this->members_.m_start = new_start; - std::copy(detail::make_move_iterator(start_n), detail::make_move_iterator(pos), old_start); - interf.copy_all_to(pos - difference_type(n)); - } - else { - difference_type mid_count = (difference_type(n) - elemsbefore); - iterator mid_start = old_start - mid_count; - interf.uninitialized_copy_some_and_update(mid_start, mid_count, true); - this->members_.m_start = mid_start; - std::uninitialized_copy(detail::make_move_iterator(old_start), detail::make_move_iterator(pos), new_start); - this->members_.m_start = new_start; - interf.copy_all_to(old_start); - } - } - else { - iterator new_finish = this->priv_reserve_elements_at_back(n); - iterator old_finish = this->members_.m_finish; - const difference_type elemsafter = - difference_type(length) - elemsbefore; - pos = this->members_.m_finish - elemsafter; - if (elemsafter >= difference_type(n)) { - iterator finish_n = this->members_.m_finish - difference_type(n); - std::uninitialized_copy(detail::make_move_iterator(finish_n), detail::make_move_iterator(this->members_.m_finish), this->members_.m_finish); - this->members_.m_finish = new_finish; - std::copy_backward(detail::make_move_iterator(pos), detail::make_move_iterator(finish_n), old_finish); - interf.copy_all_to(pos); - } - else { - interf.uninitialized_copy_some_and_update(old_finish, elemsafter, false); - this->members_.m_finish += n-elemsafter; - std::uninitialized_copy(detail::make_move_iterator(pos), detail::make_move_iterator(old_finish), this->members_.m_finish); - this->members_.m_finish = new_finish; - interf.copy_all_to(pos); - } - } - } - - void priv_fill_insert(const_iterator pos, size_type n, const value_type& x) - { - typedef constant_iterator c_it; - this->insert(pos, c_it(x, n), c_it()); - } - - // Precondition: this->members_.m_start and this->members_.m_finish have already been initialized, - // but none of the deque's elements have yet been constructed. - void priv_fill_initialize(const value_type& value) - { - index_pointer cur; - BOOST_TRY { - for (cur = this->members_.m_start.m_node; cur < this->members_.m_finish.m_node; ++cur){ - std::uninitialized_fill(*cur, *cur + this->s_buffer_size(), value); - } - std::uninitialized_fill(this->members_.m_finish.m_first, this->members_.m_finish.m_cur, value); - } - BOOST_CATCH(...){ - this->priv_destroy_range(this->members_.m_start, iterator(*cur, cur)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - - template - void priv_range_initialize(InpIt first, InpIt last, std::input_iterator_tag) - { - this->priv_initialize_map(0); - BOOST_TRY { - for ( ; first != last; ++first) - this->push_back(*first); - } - BOOST_CATCH(...){ - this->clear(); - BOOST_RETHROW - } - BOOST_CATCH_END - } - - template - void priv_range_initialize(FwdIt first, FwdIt last, std::forward_iterator_tag) - { - size_type n = 0; - n = std::distance(first, last); - this->priv_initialize_map(n); - - index_pointer cur_node; - BOOST_TRY { - for (cur_node = this->members_.m_start.m_node; - cur_node < this->members_.m_finish.m_node; - ++cur_node) { - FwdIt mid = first; - std::advance(mid, this->s_buffer_size()); - std::uninitialized_copy(first, mid, *cur_node); - first = mid; - } - std::uninitialized_copy(first, last, this->members_.m_finish.m_first); - } - BOOST_CATCH(...){ - this->priv_destroy_range(this->members_.m_start, iterator(*cur_node, cur_node)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - - // Called only if this->members_.m_finish.m_cur == this->members_.m_finish.m_first. - void priv_pop_back_aux() - { - this->priv_deallocate_node(this->members_.m_finish.m_first); - this->members_.m_finish.priv_set_node(this->members_.m_finish.m_node - 1); - this->members_.m_finish.m_cur = this->members_.m_finish.m_last - 1; - detail::get_pointer(this->members_.m_finish.m_cur)->~value_type(); - } - - // Called only if this->members_.m_start.m_cur == this->members_.m_start.m_last - 1. Note that - // if the deque has at least one element (a precondition for this member - // function), and if this->members_.m_start.m_cur == this->members_.m_start.m_last, then the deque - // must have at least two nodes. - void priv_pop_front_aux() - { - detail::get_pointer(this->members_.m_start.m_cur)->~value_type(); - this->priv_deallocate_node(this->members_.m_start.m_first); - this->members_.m_start.priv_set_node(this->members_.m_start.m_node + 1); - this->members_.m_start.m_cur = this->members_.m_start.m_first; - } - - iterator priv_reserve_elements_at_front(size_type n) - { - size_type vacancies = this->members_.m_start.m_cur - this->members_.m_start.m_first; - if (n > vacancies){ - size_type new_elems = n-vacancies; - size_type new_nodes = (new_elems + this->s_buffer_size() - 1) / - this->s_buffer_size(); - size_type s = (size_type)(this->members_.m_start.m_node - this->members_.m_map); - if (new_nodes > s){ - this->priv_reallocate_map(new_nodes, true); - } - size_type i = 1; - BOOST_TRY { - for (; i <= new_nodes; ++i) - *(this->members_.m_start.m_node - i) = this->priv_allocate_node(); - } - BOOST_CATCH(...) { - for (size_type j = 1; j < i; ++j) - this->priv_deallocate_node(*(this->members_.m_start.m_node - j)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - return this->members_.m_start - difference_type(n); - } - - iterator priv_reserve_elements_at_back(size_type n) - { - size_type vacancies = (this->members_.m_finish.m_last - this->members_.m_finish.m_cur) - 1; - if (n > vacancies){ - size_type new_elems = n - vacancies; - size_type new_nodes = (new_elems + this->s_buffer_size() - 1)/s_buffer_size(); - size_type s = (size_type)(this->members_.m_map_size - (this->members_.m_finish.m_node - this->members_.m_map)); - if (new_nodes + 1 > s){ - this->priv_reallocate_map(new_nodes, false); - } - size_type i; - BOOST_TRY { - for (i = 1; i <= new_nodes; ++i) - *(this->members_.m_finish.m_node + i) = this->priv_allocate_node(); - } - BOOST_CATCH(...) { - for (size_type j = 1; j < i; ++j) - this->priv_deallocate_node(*(this->members_.m_finish.m_node + j)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - return this->members_.m_finish + difference_type(n); - } - - void priv_reallocate_map(size_type nodes_to_add, bool add_at_front) - { - size_type old_num_nodes = this->members_.m_finish.m_node - this->members_.m_start.m_node + 1; - size_type new_num_nodes = old_num_nodes + nodes_to_add; - - index_pointer new_nstart; - if (this->members_.m_map_size > 2 * new_num_nodes) { - new_nstart = this->members_.m_map + (this->members_.m_map_size - new_num_nodes) / 2 - + (add_at_front ? nodes_to_add : 0); - if (new_nstart < this->members_.m_start.m_node) - std::copy(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart); - else - std::copy_backward(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, - new_nstart + old_num_nodes); - } - else { - size_type new_map_size = - this->members_.m_map_size + max_value(this->members_.m_map_size, nodes_to_add) + 2; - - index_pointer new_map = this->priv_allocate_map(new_map_size); - new_nstart = new_map + (new_map_size - new_num_nodes) / 2 - + (add_at_front ? nodes_to_add : 0); - std::copy(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart); - this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); - - this->members_.m_map = new_map; - this->members_.m_map_size = new_map_size; - } - - this->members_.m_start.priv_set_node(new_nstart); - this->members_.m_finish.priv_set_node(new_nstart + old_num_nodes - 1); - } - /// @endcond -}; - -// Nonmember functions. -template -inline bool operator==(const deque& x, - const deque& y) -{ - return x.size() == y.size() && equal(x.begin(), x.end(), y.begin()); -} - -template -inline bool operator<(const deque& x, - const deque& y) -{ - return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); -} - -template -inline bool operator!=(const deque& x, - const deque& y) - { return !(x == y); } - -template -inline bool operator>(const deque& x, - const deque& y) - { return y < x; } - -template -inline bool operator<=(const deque& x, - const deque& y) - { return !(y < x); } - -template -inline bool operator>=(const deque& x, - const deque& y) - { return !(x < y); } - - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(deque& x, deque& y) -{ x.swap(y); } - -template -inline void swap(detail::moved_object > x, deque& y) -{ x.get().swap(y); } - -template -inline void swap(deque &x, detail::moved_object > y) -{ x.swap(y.get()); } -#else -template -inline void swap(deque&&x, deque&&y) -{ x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::value }; -}; -/// @endcond +using boost::interprocess_container::deque; } //namespace interprocess { } //namespace boost { #include -#endif // #ifndef BOOST_INTERPROCESS_DEQUE_HPP +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP diff --git a/include/boost/interprocess/containers/flat_map.hpp b/include/boost/interprocess/containers/flat_map.hpp index 3649906..4129bbb 100644 --- a/include/boost/interprocess/containers/flat_map.hpp +++ b/include/boost/interprocess/containers/flat_map.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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) // @@ -8,1434 +8,25 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_FLAT_MAP_HPP -#define BOOST_INTERPROCESS_FLAT_MAP_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP +#define BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +namespace boost { +namespace interprocess { -namespace boost { namespace interprocess { +using boost::interprocess_container::flat_map; +using boost::interprocess_container::flat_multimap; -/// @cond -// Forward declarations of operators == and <, needed for friend declarations. -template -class flat_map; - -template -inline bool operator==(const flat_map& x, - const flat_map& y); - -template -inline bool operator<(const flat_map& x, - const flat_map& y); -/// @endcond - -//! A flat_map is a kind of associative container that supports unique keys (contains at -//! most one of each key value) and provides for fast retrieval of values of another -//! type T based on the keys. The flat_map class supports random-access iterators. -//! -//! A flat_map satisfies all of the requirements of a container and of a reversible -//! container and of an associative container. A flat_map also provides -//! most operations described for unique keys. For a -//! flat_map the key_type is Key and the value_type is std::pair -//! (unlike std::map which value_type is std::pair<const Key, T>). -//! -//! Pred is the ordering function for Keys (e.g. std::less). -//! -//! Alloc is the allocator to allocate the value_types -//! (e.g. boost::interprocess:allocator< std::pair). -//! -//! flat_map is similar to std::map but it's implemented like an ordered vector. -//! This means that inserting a new element into a flat_map invalidates -//! previous iterators and references -//! -//! Erasing an element of a flat_map invalidates iterators and references -//! pointing to elements that come after (their keys are bigger) the erased element. -template -class flat_map -{ - /// @cond - private: - //This is the tree that we should store if pair was movable - typedef detail::flat_tree, - detail::select1st< std::pair >, - Pred, - Alloc> tree_t; - - //#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - //This is the real tree stored here. It's based on a movable pair - typedef detail::flat_tree, - detail::select1st< detail::pair >, - Pred, - typename Alloc::template - rebind >::other> impl_tree_t; -/* - #else - typedef tree_t impl_tree_t; - #endif -*/ - impl_tree_t m_flat_tree; // flat tree representing flat_map - - typedef typename impl_tree_t::value_type impl_value_type; - typedef typename impl_tree_t::pointer impl_pointer; - typedef typename impl_tree_t::const_pointer impl_const_pointer; - typedef typename impl_tree_t::reference impl_reference; - typedef typename impl_tree_t::const_reference impl_const_reference; - typedef typename impl_tree_t::value_compare impl_value_compare; - typedef typename impl_tree_t::iterator impl_iterator; - typedef typename impl_tree_t::const_iterator impl_const_iterator; - typedef typename impl_tree_t::reverse_iterator impl_reverse_iterator; - typedef typename impl_tree_t::const_reverse_iterator impl_const_reverse_iterator; - typedef typename impl_tree_t::allocator_type impl_allocator_type; - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - typedef detail::moved_object impl_moved_value_type; - #endif - - //#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - static D &force(const S &s) - { return *const_cast(reinterpret_cast(&s)); } - - template - static D force_copy(S s) - { - value_type *vp = reinterpret_cast(&*s); - return D(vp); - } - - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef typename tree_t::value_compare value_compare; - typedef T mapped_type; - typedef typename tree_t::key_compare key_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty flat_map using the specified - //! comparison object and allocator. - //! - //! Complexity: Constant. - explicit flat_map(const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_flat_tree(comp, force(a)) {} - - //! Effects: Constructs an empty flat_map using the specified comparison object and - //! allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - flat_map(InputIterator first, InputIterator last, const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, force(a)) - { m_flat_tree.insert_unique(first, last); } - - //! Effects: Copy constructs a flat_map. - //! - //! Complexity: Linear in x.size(). - flat_map(const flat_map& x) - : m_flat_tree(x.m_flat_tree) {} - - //! Effects: Move constructs a flat_map. - //! Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_map(detail::moved_object > x) - : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) {} - - #else - flat_map(flat_map && x) - : m_flat_tree(detail::move_impl(x.m_flat_tree)) {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - flat_map& operator=(const flat_map& x) - { m_flat_tree = x.m_flat_tree; return *this; } - - //! Effects: Move constructs a flat_map. - //! Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_map& operator=(detail::moved_object > mx) - { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } - #else - flat_map& operator=(flat_map && mx) - { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return force(m_flat_tree.key_comp()); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return value_compare(force(m_flat_tree.key_comp())); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return force(m_flat_tree.get_allocator()); } - - const stored_allocator_type &get_stored_allocator() const - { return force(m_flat_tree.get_stored_allocator()); } - - stored_allocator_type &get_stored_allocator() - { return force(m_flat_tree.get_stored_allocator()); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return force_copy(m_flat_tree.begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return force(m_flat_tree.begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return force(m_flat_tree.cbegin()); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return force_copy(m_flat_tree.end()); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return force(m_flat_tree.end()); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return force(m_flat_tree.cend()); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return force(m_flat_tree.rbegin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return force(m_flat_tree.rbegin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return force(m_flat_tree.crbegin()); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return force(m_flat_tree.rend()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return force(m_flat_tree.rend()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return force(m_flat_tree.crend()); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_flat_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_flat_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_flat_tree.max_size(); } - - //! Effects: If there is no key equivalent to x in the flat_map, inserts - //! value_type(x, T()) into the flat_map. - //! - //! Returns: A reference to the mapped_type corresponding to x in *this. - //! - //! Complexity: Logarithmic. - T &operator[](const key_type& k) - { - iterator i = lower_bound(k); - // i->first is greater than or equivalent to k. - if (i == end() || key_comp()(k, (*i).first)) - i = insert(i, value_type(k, T())); - return (*i).second; - } - - //! Effects: If there is no key equivalent to x in the flat_map, inserts - //! value_type(move(x), T()) into the flat_map (the key is move-constructed) - //! - //! Returns: A reference to the mapped_type corresponding to x in *this. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - T &operator[](detail::moved_object mk) - { - key_type &k = mk.get(); - iterator i = lower_bound(k); - // i->first is greater than or equivalent to k. - if (i == end() || key_comp()(k, (*i).first)) - i = insert(i, value_type(k, detail::move_impl(T()))); - return (*i).second; - } - #else - T &operator[](key_type &&mk) - { - key_type &k = mk; - iterator i = lower_bound(k); - // i->first is greater than or equivalent to k. - if (i == end() || key_comp()(k, (*i).first)) - i = insert(i, value_type(detail::forward_impl(k), detail::move_impl(T()))); - return (*i).second; - } - #endif - - //! Returns: A reference to the element whose key is equivalent to x. - //! Throws: An exception object of type out_of_range if no such element is present. - //! Complexity: logarithmic. - T& at(const key_type& k) - { - iterator i = this->find(k); - if(i == this->end()){ - throw std::out_of_range("key not found"); - } - return i->second; - } - - //! Returns: A reference to the element whose key is equivalent to x. - //! Throws: An exception object of type out_of_range if no such element is present. - //! Complexity: logarithmic. - const T& at(const key_type& k) const - { - const_iterator i = this->find(k); - if(i == this->end()){ - throw std::out_of_range("key not found"); - } - return i->second; - } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(flat_map& x) - #else - void swap(flat_map &&x) - #endif - { m_flat_tree.swap(x.m_flat_tree); } - - //! Effects: Inserts x if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - std::pair insert(const value_type& x) - { return force >( - m_flat_tree.insert_unique(force(x))); } - - //! Effects: Inserts a new value_type move constructed from the pair if and - //! only if there is no element in the container with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object x) - { return force >( - m_flat_tree.insert_unique(force(x))); } - #else - std::pair insert(value_type &&x) - { return force >( - m_flat_tree.insert_unique(detail::move_impl(force(x)))); } - #endif - - //! Effects: Inserts a copy of x in the container if and only if there is - //! no element in the container with key equivalent to the key of x. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const_iterator position, const value_type& x) - { return force_copy( - m_flat_tree.insert_unique(force(position), force(x))); } - - //! Effects: Inserts an element move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object x) - { return force_copy( - m_flat_tree.insert_unique(force(position), force(x))); } - #else - iterator insert(const_iterator position, value_type &&x) - { return force_copy( - m_flat_tree.insert_unique(force(position), detail::move_impl(force(x)))); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) if and only - //! if there is no element with key equivalent to the key of that element. - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - //! search time plus N*size() insertion time. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - void insert(InputIterator first, InputIterator last) - { m_flat_tree.insert_unique(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace(Args&&... args) - { return force_copy(m_flat_tree.emplace_unique(detail::forward_impl(args)...)); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container if and only if there is - //! no element in the container with key equivalent to the key of x. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return force_copy(m_flat_tree.emplace_hint_unique(force(hint), detail::forward_impl(args)...)); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return force_copy(m_flat_tree.emplace_unique()); } - - iterator emplace_hint(const_iterator hint) - { return force_copy(m_flat_tree.emplace_hint_unique(force(hint))); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - return force_copy(m_flat_tree.emplace_unique \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ - } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - return force_copy(m_flat_tree.emplace_hint_unique \ - (force(hint), \ - BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Linear to the elements with keys bigger than position - //! - //! Note: Invalidates elements with keys - //! not less than the erased element. - iterator erase(const_iterator position) - { return force_copy(m_flat_tree.erase(force(position))); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - size_type erase(const key_type& x) - { return m_flat_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: size()*N where N is the distance from first to last. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - iterator erase(const_iterator first, const_iterator last) - { return force_copy(m_flat_tree.erase(force(first), force(last))); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_flat_tree.clear(); } - - //! Effects: Tries to deallocate the excess of memory created - // with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { m_flat_tree.shrink_to_fit(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return force_copy(m_flat_tree.find(x)); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic.s - const_iterator find(const key_type& x) const - { return force(m_flat_tree.find(x)); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return force_copy(m_flat_tree.lower_bound(x)); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return force(m_flat_tree.lower_bound(x)); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return force_copy(m_flat_tree.upper_bound(x)); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return force(m_flat_tree.upper_bound(x)); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) - { return force >(m_flat_tree.equal_range(x)); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) const - { return force >(m_flat_tree.equal_range(x)); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return m_flat_tree.capacity(); } - - //! Effects: If n is less than or equal to capacity(), this call has no - //! effect. Otherwise, it is a request for allocation of additional memory. - //! If the request is successful, then capacity() is greater than or equal to - //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - //! - //! Note: If capacity() is less than "count", iterators and references to - //! to values might be invalidated. - void reserve(size_type count) - { m_flat_tree.reserve(count); } - - /// @cond - template - friend bool operator== (const flat_map&, - const flat_map&); - template - friend bool operator< (const flat_map&, - const flat_map&); - /// @endcond -}; - -template -inline bool operator==(const flat_map& x, - const flat_map& y) - { return x.m_flat_tree == y.m_flat_tree; } - -template -inline bool operator<(const flat_map& x, - const flat_map& y) - { return x.m_flat_tree < y.m_flat_tree; } - -template -inline bool operator!=(const flat_map& x, - const flat_map& y) - { return !(x == y); } - -template -inline bool operator>(const flat_map& x, - const flat_map& y) - { return y < x; } - -template -inline bool operator<=(const flat_map& x, - const flat_map& y) - { return !(y < x); } - -template -inline bool operator>=(const flat_map& x, - const flat_map& y) - { return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(flat_map& x, - flat_map& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, - flat_map& y) - { x.get().swap(y); } - -template -inline void swap(flat_map& x, - detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(flat_map&&x, - flat_map&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; - -// Forward declaration of operators < and ==, needed for friend declaration. -template -class flat_multimap; - -template -inline bool operator==(const flat_multimap& x, - const flat_multimap& y); - -template -inline bool operator<(const flat_multimap& x, - const flat_multimap& y); -/// @endcond - -//! A flat_multimap is a kind of associative container that supports equivalent keys -//! (possibly containing multiple copies of the same key value) and provides for -//! fast retrieval of values of another type T based on the keys. The flat_multimap -//! class supports random-access iterators. -//! -//! A flat_multimap satisfies all of the requirements of a container and of a reversible -//! container and of an associative container. For a -//! flat_multimap the key_type is Key and the value_type is std::pair -//! (unlike std::multimap which value_type is std::pair<const Key, T>). -//! -//! Pred is the ordering function for Keys (e.g. std::less). -//! -//! Alloc is the allocator to allocate the value_types -//! (e.g. boost::interprocess:allocator< std::pair). -template -class flat_multimap -{ - /// @cond - private: - typedef detail::flat_tree, - detail::select1st< std::pair >, - Pred, - Alloc> tree_t; - //#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - //This is the real tree stored here. It's based on a movable pair - typedef detail::flat_tree, - detail::select1st< detail::pair >, - Pred, - typename Alloc::template - rebind >::other> impl_tree_t; -/* - #else - typedef tree_t impl_tree_t; - #endif -*/ - impl_tree_t m_flat_tree; // flat tree representing flat_map - - typedef typename impl_tree_t::value_type impl_value_type; - typedef typename impl_tree_t::pointer impl_pointer; - typedef typename impl_tree_t::const_pointer impl_const_pointer; - typedef typename impl_tree_t::reference impl_reference; - typedef typename impl_tree_t::const_reference impl_const_reference; - typedef typename impl_tree_t::value_compare impl_value_compare; - typedef typename impl_tree_t::iterator impl_iterator; - typedef typename impl_tree_t::const_iterator impl_const_iterator; - typedef typename impl_tree_t::reverse_iterator impl_reverse_iterator; - typedef typename impl_tree_t::const_reverse_iterator impl_const_reverse_iterator; - typedef typename impl_tree_t::allocator_type impl_allocator_type; - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - typedef detail::moved_object impl_moved_value_type; - #endif - - //#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - static D &force(const S &s) - { return *const_cast((reinterpret_cast(&s))); } - - template - static D force_copy(S s) - { - value_type *vp = reinterpret_cast(&*s); - return D(vp); - } - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef typename tree_t::value_compare value_compare; - typedef T mapped_type; - typedef typename tree_t::key_compare key_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty flat_multimap using the specified comparison - //! object and allocator. - //! - //! Complexity: Constant. - explicit flat_multimap(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, force(a)) { } - - //! Effects: Constructs an empty flat_multimap using the specified comparison object - //! and allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - flat_multimap(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, force(a)) - { m_flat_tree.insert_equal(first, last); } - - //! Effects: Copy constructs a flat_multimap. - //! - //! Complexity: Linear in x.size(). - flat_multimap(const flat_multimap& x) - : m_flat_tree(x.m_flat_tree) { } - - //! Effects: Move constructs a flat_multimap. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_multimap(detail::moved_object > x) - : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) { } - #else - flat_multimap(flat_multimap && x) - : m_flat_tree(detail::move_impl(x.m_flat_tree)) { } - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - flat_multimap& operator=(const flat_multimap& x) - { m_flat_tree = x.m_flat_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_multimap& operator=(detail::moved_object > mx) - { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } - #else - flat_multimap& operator=(flat_multimap && mx) - { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return force(m_flat_tree.key_comp()); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return value_compare(force(m_flat_tree.key_comp())); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return force(m_flat_tree.get_allocator()); } - - const stored_allocator_type &get_stored_allocator() const - { return force(m_flat_tree.get_stored_allocator()); } - - stored_allocator_type &get_stored_allocator() - { return force(m_flat_tree.get_stored_allocator()); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return force_copy(m_flat_tree.begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return force(m_flat_tree.begin()); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return force_copy(m_flat_tree.end()); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return force(m_flat_tree.end()); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return force(m_flat_tree.rbegin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return force(m_flat_tree.rbegin()); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return force(m_flat_tree.rend()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return force(m_flat_tree.rend()); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_flat_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_flat_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_flat_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(flat_multimap& x) - #else - void swap(flat_multimap &&x) - #endif - { m_flat_tree.swap(x.m_flat_tree); } - - //! Effects: Inserts x and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const value_type& x) - { return force_copy(m_flat_tree.insert_equal(force(x))); } - - //! Effects: Inserts a new value move-constructed from x and returns - //! the iterator pointing to the newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(detail::moved_object x) - { return force_copy(m_flat_tree.insert_equal(force(x))); } - #else - iterator insert(value_type &&x) - { return force_copy(m_flat_tree.insert_equal(detail::move_impl(x))); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant time if the value - //! is to be inserted before p) plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const_iterator position, const value_type& x) - { return force_copy(m_flat_tree.insert_equal(force(position), force(x))); } - - //! Effects: Inserts a value move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant time if the value - //! is to be inserted before p) plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object x) - { return force_copy(m_flat_tree.insert_equal(force(position), force(x))); } - #else - iterator insert(const_iterator position, value_type &&x) - { return force_copy(m_flat_tree.insert_equal(force(position), detail::move_impl(x))); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) . - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - //! search time plus N*size() insertion time. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - void insert(InputIterator first, InputIterator last) - { m_flat_tree.insert_equal(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace(Args&&... args) - { return force_copy(m_flat_tree.emplace_equal(detail::forward_impl(args)...)); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant time if the value - //! is to be inserted before p) plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { - return force_copy(m_flat_tree.emplace_hint_equal - (force(hint), detail::forward_impl(args)...)); - } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return force_copy(m_flat_tree.emplace_equal()); } - - iterator emplace_hint(const_iterator hint) - { return force_copy(m_flat_tree.emplace_hint_equal(force(hint))); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - return force_copy(m_flat_tree.emplace_equal \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ - } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - return force_copy(m_flat_tree.emplace_hint_equal \ - (force(hint), \ - BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Linear to the elements with keys bigger than position - //! - //! Note: Invalidates elements with keys - //! not less than the erased element. - iterator erase(const_iterator position) - { return force_copy(m_flat_tree.erase(force(position))); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - size_type erase(const key_type& x) - { return m_flat_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: size()*N where N is the distance from first to last. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - iterator erase(const_iterator first, const_iterator last) - { return force_copy(m_flat_tree.erase(force(first), force(last))); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_flat_tree.clear(); } - - //! Effects: Tries to deallocate the excess of memory created - // with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { m_flat_tree.shrink_to_fit(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return force_copy(m_flat_tree.find(x)); } - - //! Returns: An const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return force(m_flat_tree.find(x)); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_flat_tree.count(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - {return force_copy(m_flat_tree.lower_bound(x)); } - - //! Returns: A const iterator pointing to the first element with key - //! not less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return force(m_flat_tree.lower_bound(x)); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - {return force_copy(m_flat_tree.upper_bound(x)); } - - //! Returns: A const iterator pointing to the first element with key - //! not less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return force(m_flat_tree.upper_bound(x)); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) - { return force_copy >(m_flat_tree.equal_range(x)); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return force_copy >(m_flat_tree.equal_range(x)); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return m_flat_tree.capacity(); } - - //! Effects: If n is less than or equal to capacity(), this call has no - //! effect. Otherwise, it is a request for allocation of additional memory. - //! If the request is successful, then capacity() is greater than or equal to - //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - //! - //! Note: If capacity() is less than "count", iterators and references to - //! to values might be invalidated. - void reserve(size_type count) - { m_flat_tree.reserve(count); } - - /// @cond - template - friend bool operator== (const flat_multimap& x, - const flat_multimap& y); - - template - friend bool operator< (const flat_multimap& x, - const flat_multimap& y); - /// @endcond -}; - -template -inline bool operator==(const flat_multimap& x, - const flat_multimap& y) - { return x.m_flat_tree == y.m_flat_tree; } - -template -inline bool operator<(const flat_multimap& x, - const flat_multimap& y) - { return x.m_flat_tree < y.m_flat_tree; } - -template -inline bool operator!=(const flat_multimap& x, - const flat_multimap& y) - { return !(x == y); } - -template -inline bool operator>(const flat_multimap& x, - const flat_multimap& y) - { return y < x; } - -template -inline bool operator<=(const flat_multimap& x, - const flat_multimap& y) - { return !(y < x); } - -template -inline bool operator>=(const flat_multimap& x, - const flat_multimap& y) - { return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(flat_multimap& x, - flat_multimap& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, - flat_multimap& y) - { x.get().swap(y); } - - -template -inline void swap(flat_multimap& x, - detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(flat_multimap&&x, - flat_multimap&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess { +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_FLAT_MAP_HPP */ +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP diff --git a/include/boost/interprocess/containers/flat_set.hpp b/include/boost/interprocess/containers/flat_set.hpp index 1e3c9bf..0c38930 100644 --- a/include/boost/interprocess/containers/flat_set.hpp +++ b/include/boost/interprocess/containers/flat_set.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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) // @@ -8,1237 +8,25 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_FLAT_SET_HPP -#define BOOST_INTERPROCESS_FLAT_SET_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP +#define BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include +#include -#include -#include -#include -#include -#include -#include -#include +namespace boost { +namespace interprocess { +using boost::interprocess_container::flat_set; +using boost::interprocess_container::flat_multiset; -namespace boost { namespace interprocess { - -/// @cond -// Forward declarations of operators < and ==, needed for friend declaration. - -template -class flat_set; - -template -inline bool operator==(const flat_set& x, - const flat_set& y); - -template -inline bool operator<(const flat_set& x, - const flat_set& y); -/// @endcond - -//! flat_set is a Sorted Associative Container that stores objects of type Key. -//! flat_set is a Simple Associative Container, meaning that its value type, -//! as well as its key type, is Key. It is also a Unique Associative Container, -//! meaning that no two elements are the same. -//! -//! flat_set is similar to std::set but it's implemented like an ordered vector. -//! This means that inserting a new element into a flat_set invalidates -//! previous iterators and references -//! -//! Erasing an element of a flat_set invalidates iterators and references -//! pointing to elements that come after (their keys are bigger) the erased element. -template -class flat_set -{ - /// @cond - private: - typedef detail::flat_tree, Pred, Alloc> tree_t; - tree_t m_flat_tree; // flat tree representing flat_set - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef typename tree_t::key_compare key_compare; - typedef typename tree_t::value_compare value_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty flat_map using the specified - //! comparison object and allocator. - //! - //! Complexity: Constant. - explicit flat_set(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) - {} - - //! Effects: Constructs an empty map using the specified comparison object and - //! allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - flat_set(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) - { m_flat_tree.insert_unique(first, last); } - - //! Effects: Copy constructs a map. - //! - //! Complexity: Linear in x.size(). - flat_set(const flat_set& x) - : m_flat_tree(x.m_flat_tree) {} - - //! Effects: Move constructs a map. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_set(detail::moved_object > mx) - : m_flat_tree(detail::move_impl(mx.get().m_flat_tree)) {} - #else - flat_set(flat_set && mx) - : m_flat_tree(detail::move_impl(mx.m_flat_tree)) {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - flat_set& operator=(const flat_set& x) - { m_flat_tree = x.m_flat_tree; return *this; } - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_set& operator=(detail::moved_object > mx) - { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } - - #else - flat_set& operator=(flat_set &&mx) - { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } - - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_flat_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return m_flat_tree.key_comp(); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return m_flat_tree.get_allocator(); } - - const stored_allocator_type &get_stored_allocator() const - { return m_flat_tree.get_stored_allocator(); } - - stored_allocator_type &get_stored_allocator() - { return m_flat_tree.get_stored_allocator(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_flat_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_flat_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return m_flat_tree.cbegin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_flat_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_flat_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return m_flat_tree.cend(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_flat_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_flat_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return m_flat_tree.crbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_flat_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_flat_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return m_flat_tree.crend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_flat_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_flat_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_flat_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(flat_set& x) - #else - void swap(flat_set &&x) - #endif - { m_flat_tree.swap(x.m_flat_tree); } - - //! Effects: Inserts x if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - std::pair insert(const value_type& x) - { return m_flat_tree.insert_unique(x); } - - //! Effects: Inserts a new value_type move constructed from the pair if and - //! only if there is no element in the container with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object x) - { return m_flat_tree.insert_unique(x); } - #else - std::pair insert(value_type && x) - { return m_flat_tree.insert_unique(detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container if and only if there is - //! no element in the container with key equivalent to the key of x. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const_iterator position, const value_type& x) - { return m_flat_tree.insert_unique(position, x); } - - //! Effects: Inserts an element move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object x) - { return m_flat_tree.insert_unique(position, x); } - #else - iterator insert(const_iterator position, value_type && x) - { return m_flat_tree.insert_unique(position, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) if and only - //! if there is no element with key equivalent to the key of that element. - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - //! search time plus N*size() insertion time. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - void insert(InputIterator first, InputIterator last) - { m_flat_tree.insert_unique(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace(Args&&... args) - { return m_flat_tree.emplace_unique(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container if and only if there is - //! no element in the container with key equivalent to the key of x. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_flat_tree.emplace_hint_unique(hint, detail::forward_impl(args)...); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return m_flat_tree.emplace_unique(); } - - iterator emplace_hint(const_iterator hint) - { return m_flat_tree.emplace_hint_unique(hint); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_flat_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_flat_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); }\ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Linear to the elements with keys bigger than position - //! - //! Note: Invalidates elements with keys - //! not less than the erased element. - iterator erase(const_iterator position) - { return m_flat_tree.erase(position); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - size_type erase(const key_type& x) - { return m_flat_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: size()*N where N is the distance from first to last. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - iterator erase(const_iterator first, const_iterator last) - { return m_flat_tree.erase(first, last); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_flat_tree.clear(); } - - //! Effects: Tries to deallocate the excess of memory created - // with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { m_flat_tree.shrink_to_fit(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_flat_tree.find(x); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic.s - const_iterator find(const key_type& x) const - { return m_flat_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_flat_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_flat_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_flat_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_flat_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_flat_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) - { return m_flat_tree.equal_range(x); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return m_flat_tree.capacity(); } - - //! Effects: If n is less than or equal to capacity(), this call has no - //! effect. Otherwise, it is a request for allocation of additional memory. - //! If the request is successful, then capacity() is greater than or equal to - //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - //! - //! Note: If capacity() is less than "count", iterators and references to - //! to values might be invalidated. - void reserve(size_type count) - { m_flat_tree.reserve(count); } - - /// @cond - template - friend bool operator== (const flat_set&, const flat_set&); - - template - friend bool operator< (const flat_set&, const flat_set&); - /// @endcond -}; - -template -inline bool operator==(const flat_set& x, - const flat_set& y) - { return x.m_flat_tree == y.m_flat_tree; } - -template -inline bool operator<(const flat_set& x, - const flat_set& y) - { return x.m_flat_tree < y.m_flat_tree; } - -template -inline bool operator!=(const flat_set& x, - const flat_set& y) - { return !(x == y); } - -template -inline bool operator>(const flat_set& x, - const flat_set& y) - { return y < x; } - -template -inline bool operator<=(const flat_set& x, - const flat_set& y) - { return !(y < x); } - -template -inline bool operator>=(const flat_set& x, - const flat_set& y) - { return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(flat_set& x, flat_set& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, flat_set& y) - { x.get().swap(y); } - -template -inline void swap(flat_set& x, detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(flat_set&&x, flat_set&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; - -// Forward declaration of operators < and ==, needed for friend declaration. - -template -class flat_multiset; - -template -inline bool operator==(const flat_multiset& x, - const flat_multiset& y); - -template -inline bool operator<(const flat_multiset& x, - const flat_multiset& y); -/// @endcond - -//! flat_multiset is a Sorted Associative Container that stores objects of type Key. -//! flat_multiset is a Simple Associative Container, meaning that its value type, -//! as well as its key type, is Key. -//! flat_Multiset can store multiple copies of the same key value. -//! -//! flat_multiset is similar to std::multiset but it's implemented like an ordered vector. -//! This means that inserting a new element into a flat_multiset invalidates -//! previous iterators and references -//! -//! Erasing an element of a flat_multiset invalidates iterators and references -//! pointing to elements that come after (their keys are equal or bigger) the erased element. -template -class flat_multiset -{ - /// @cond - private: - typedef detail::flat_tree, Pred, Alloc> tree_t; - tree_t m_flat_tree; // flat tree representing flat_multiset - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef typename tree_t::key_compare key_compare; - typedef typename tree_t::value_compare value_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - // allocation/deallocation - explicit flat_multiset(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) {} - - template - flat_multiset(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) - { m_flat_tree.insert_equal(first, last); } - - flat_multiset(const flat_multiset& x) - : m_flat_tree(x.m_flat_tree) {} - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_multiset(detail::moved_object > x) - : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) {} - #else - flat_multiset(flat_multiset && x) - : m_flat_tree(detail::move_impl(x.m_flat_tree)) {} - #endif - - flat_multiset& operator=(const flat_multiset& x) - { m_flat_tree = x.m_flat_tree; return *this; } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_multiset& operator=(detail::moved_object > mx) - { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } - #else - flat_multiset& operator=(flat_multiset && mx) - { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_flat_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return m_flat_tree.key_comp(); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return m_flat_tree.get_allocator(); } - - const stored_allocator_type &get_stored_allocator() const - { return m_flat_tree.get_stored_allocator(); } - - stored_allocator_type &get_stored_allocator() - { return m_flat_tree.get_stored_allocator(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_flat_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_flat_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return m_flat_tree.cbegin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_flat_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_flat_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return m_flat_tree.cend(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_flat_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_flat_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return m_flat_tree.crbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_flat_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_flat_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return m_flat_tree.crend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_flat_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_flat_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_flat_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(flat_multiset& x) - #else - void swap(flat_multiset &&x) - #endif - { m_flat_tree.swap(x.m_flat_tree); } - - //! Effects: Inserts x and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const value_type& x) - { return m_flat_tree.insert_equal(x); } - - //! Effects: Inserts a new value_type move constructed from x - //! and returns the iterator pointing to the newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(detail::moved_object x) - { return m_flat_tree.insert_equal(x); } - #else - iterator insert(value_type && x) - { return m_flat_tree.insert_equal(detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const_iterator position, const value_type& x) - { return m_flat_tree.insert_equal(position, x); } - - //! Effects: Inserts a new value move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object x) - { return m_flat_tree.insert_equal(position, x); } - #else - iterator insert(const_iterator position, value_type && x) - { return m_flat_tree.insert_equal(position, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) . - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - //! search time plus N*size() insertion time. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - void insert(InputIterator first, InputIterator last) - { m_flat_tree.insert_equal(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace(Args&&... args) - { return m_flat_tree.emplace_equal(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_flat_tree.emplace_hint_equal(hint, detail::forward_impl(args)...); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return m_flat_tree.emplace_equal(); } - - iterator emplace_hint(const_iterator hint) - { return m_flat_tree.emplace_hint_equal(hint); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_flat_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_flat_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Linear to the elements with keys bigger than position - //! - //! Note: Invalidates elements with keys - //! not less than the erased element. - iterator erase(const_iterator position) - { return m_flat_tree.erase(position); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - size_type erase(const key_type& x) - { return m_flat_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: size()*N where N is the distance from first to last. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - iterator erase(const_iterator first, const_iterator last) - { return m_flat_tree.erase(first, last); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_flat_tree.clear(); } - - //! Effects: Tries to deallocate the excess of memory created - // with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { m_flat_tree.shrink_to_fit(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_flat_tree.find(x); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic.s - const_iterator find(const key_type& x) const - { return m_flat_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_flat_tree.count(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_flat_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_flat_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_flat_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_flat_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_flat_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) - { return m_flat_tree.equal_range(x); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return m_flat_tree.capacity(); } - - //! Effects: If n is less than or equal to capacity(), this call has no - //! effect. Otherwise, it is a request for allocation of additional memory. - //! If the request is successful, then capacity() is greater than or equal to - //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - //! - //! Note: If capacity() is less than "count", iterators and references to - //! to values might be invalidated. - void reserve(size_type count) - { m_flat_tree.reserve(count); } - - /// @cond - template - friend bool operator== (const flat_multiset&, - const flat_multiset&); - template - friend bool operator< (const flat_multiset&, - const flat_multiset&); - /// @endcond -}; - -template -inline bool operator==(const flat_multiset& x, - const flat_multiset& y) - { return x.m_flat_tree == y.m_flat_tree; } - -template -inline bool operator<(const flat_multiset& x, - const flat_multiset& y) - { return x.m_flat_tree < y.m_flat_tree; } - -template -inline bool operator!=(const flat_multiset& x, - const flat_multiset& y) - { return !(x == y); } - -template -inline bool operator>(const flat_multiset& x, - const flat_multiset& y) - { return y < x; } - -template -inline bool operator<=(const flat_multiset& x, - const flat_multiset& y) - { return !(y < x); } - -template -inline bool operator>=(const flat_multiset& x, - const flat_multiset& y) -{ return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(flat_multiset& x, flat_multiset& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, flat_multiset& y) - { x.get().swap(y); } - -template -inline void swap(flat_multiset& x, detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(flat_multiset&&x, flat_multiset&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess { +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_FLAT_SET_HPP */ +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP diff --git a/include/boost/interprocess/containers/list.hpp b/include/boost/interprocess/containers/list.hpp index 9f17f5f..1eaf3f6 100644 --- a/include/boost/interprocess/containers/list.hpp +++ b/include/boost/interprocess/containers/list.hpp @@ -1,1469 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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. // ////////////////////////////////////////////////////////////////////////////// -// -// This file comes from SGI's stl_list.h file. Modified by Ion Gaztanaga 2004 -// Renaming, isolating and porting to generic algorithms. Pointer typedef -// set to allocator::pointer to allow placing it in shared memory. -// -/////////////////////////////////////////////////////////////////////////////// -/* - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifndef BOOST_INTERPROCESS_LIST_HPP_ -#define BOOST_INTERPROCESS_LIST_HPP_ +#ifndef BOOST_INTERPROCESS_CONTAINERS_LIST_HPP +#define BOOST_INTERPROCESS_CONTAINERS_LIST_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -//Preprocessor library to emulate perfect forwarding -#include -#endif - -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace interprocess { -/// @cond -namespace detail { - -template -struct list_hook -{ - typedef typename bi::make_list_base_hook - , bi::link_mode >::type type; -}; - -template -struct list_node - : public list_hook::type -{ - - #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - list_node() - : m_data() - {} - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - list_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - : m_data(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)) \ - {} \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #else //#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - template - list_node(Args &&...args) - : m_data(detail::forward_impl(args)...) - {} - #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - T m_data; -}; - -template -struct intrusive_list_type -{ - typedef typename A::value_type value_type; - typedef typename detail::pointer_to_other - ::type void_pointer; - typedef typename detail::list_node - node_type; - typedef typename bi::make_list - < node_type - , bi::base_hook::type> - , bi::constant_time_size - , bi::size_type - >::type container_type; - typedef container_type type ; -}; - -} //namespace detail { -/// @endcond - -//! A list is a doubly linked list. That is, it is a Sequence that supports both -//! forward and backward traversal, and (amortized) constant time insertion and -//! removal of elements at the beginning or the end, or in the middle. Lists have -//! the important property that insertion and splicing do not invalidate iterators -//! to list elements, and that even removal invalidates only the iterators that point -//! to the elements that are removed. The ordering of iterators may be changed -//! (that is, list::iterator might have a different predecessor or successor -//! after a list operation than it did before), but the iterators themselves will -//! not be invalidated or made to point to different elements unless that invalidation -//! or mutation is explicit. -template -class list - : protected detail::node_alloc_holder - ::type> -{ - /// @cond - typedef typename - detail::intrusive_list_type::type Icont; - typedef list ThisType; - typedef detail::node_alloc_holder AllocHolder; - typedef typename AllocHolder::NodePtr NodePtr; - typedef typename AllocHolder::NodeAlloc NodeAlloc; - typedef typename AllocHolder::ValAlloc ValAlloc; - typedef typename AllocHolder::Node Node; - typedef detail::allocator_destroyer Destroyer; - typedef typename AllocHolder::allocator_v1 allocator_v1; - typedef typename AllocHolder::allocator_v2 allocator_v2; - typedef typename AllocHolder::alloc_version alloc_version; - - class equal_to_value - { - typedef typename AllocHolder::value_type value_type; - const value_type &t_; - - public: - equal_to_value(const value_type &t) - : t_(t) - {} - - bool operator()(const value_type &t)const - { return t_ == t; } - }; - - template - struct ValueCompareToNodeCompare - : Pred - { - ValueCompareToNodeCompare(Pred pred) - : Pred(pred) - {} - - bool operator()(const Node &a, const Node &b) const - { return static_cast(*this)(a.m_data, b.m_data); } - - bool operator()(const Node &a) const - { return static_cast(*this)(a.m_data); } - }; - /// @endcond - - public: - //! The type of object, T, stored in the list - typedef T value_type; - //! Pointer to T - typedef typename A::pointer pointer; - //! Const pointer to T - typedef typename A::const_pointer const_pointer; - //! Reference to T - typedef typename A::reference reference; - //! Const reference to T - typedef typename A::const_reference const_reference; - //! An unsigned integral type - typedef typename A::size_type size_type; - //! A signed integral type - typedef typename A::difference_type difference_type; - //! The allocator type - typedef A allocator_type; - //! The stored allocator type - typedef NodeAlloc stored_allocator_type; - - /// @cond - private: - typedef difference_type list_difference_type; - typedef pointer list_pointer; - typedef const_pointer list_const_pointer; - typedef reference list_reference; - typedef const_reference list_const_reference; - /// @endcond - - public: - //! Const iterator used to iterate through a list. - class const_iterator - /// @cond - : public std::iterator - { - - protected: - typename Icont::iterator m_it; - explicit const_iterator(typename Icont::iterator it) : m_it(it){} - void prot_incr() { ++m_it; } - void prot_decr() { --m_it; } - - private: - typename Icont::iterator get() - { return this->m_it; } - - public: - friend class list; - typedef list_difference_type difference_type; - - //Constructors - const_iterator() - : m_it() - {} - - //Pointer like operators - const_reference operator*() const - { return m_it->m_data; } - - const_pointer operator->() const - { return const_pointer(&m_it->m_data); } - - //Increment / Decrement - const_iterator& operator++() - { prot_incr(); return *this; } - - const_iterator operator++(int) - { typename Icont::iterator tmp = m_it; ++*this; return const_iterator(tmp); } - - const_iterator& operator--() - { prot_decr(); return *this; } - - const_iterator operator--(int) - { typename Icont::iterator tmp = m_it; --*this; return const_iterator(tmp); } - - //Comparison operators - bool operator== (const const_iterator& r) const - { return m_it == r.m_it; } - - bool operator!= (const const_iterator& r) const - { return m_it != r.m_it; } - } - /// @endcond - ; - - //! Iterator used to iterate through a list - class iterator - /// @cond - : public const_iterator - { - - private: - explicit iterator(typename Icont::iterator it) - : const_iterator(it) - {} - - typename Icont::iterator get() - { return this->m_it; } - - public: - friend class list; - typedef list_pointer pointer; - typedef list_reference reference; - - //Constructors - iterator(){} - - //Pointer like operators - reference operator*() const { return this->m_it->m_data; } - pointer operator->() const { return pointer(&this->m_it->m_data); } - - //Increment / Decrement - iterator& operator++() - { this->prot_incr(); return *this; } - - iterator operator++(int) - { typename Icont::iterator tmp = this->m_it; ++*this; return iterator(tmp); } - - iterator& operator--() - { this->prot_decr(); return *this; } - - iterator operator--(int) - { iterator tmp = *this; --*this; return tmp; } - } - /// @endcond - ; - - //! Iterator used to iterate backwards through a list. - typedef std::reverse_iterator reverse_iterator; - //! Const iterator used to iterate backwards through a list. - typedef std::reverse_iterator const_reverse_iterator; - - //! Effects: Constructs a list taking the allocator as parameter. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - explicit list(const allocator_type &a = A()) - : AllocHolder(a) - {} - -// list(size_type n) -// : AllocHolder(detail::move_impl(allocator_type())) -// { this->resize(n); } - - //! Effects: Constructs a list that will use a copy of allocator a - //! and inserts n copies of value. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's default or copy constructor throws. - //! - //! Complexity: Linear to n. - list(size_type n, const T& value = T(), const A& a = A()) - : AllocHolder(a) - { this->insert(this->cbegin(), n, value); } - - //! Effects: Copy constructs a list. - //! - //! Postcondition: x == *this. - //! - //! Throws: If allocator_type's default constructor or copy constructor throws. - //! - //! Complexity: Linear to the elements x contains. - list(const list& x) - : AllocHolder(x) - { this->insert(this->cbegin(), x.begin(), x.end()); } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - list(detail::moved_object x) - : AllocHolder(detail::move_impl((AllocHolder&)x.get())) - {} - #else - list(list &&x) - : AllocHolder(detail::move_impl((AllocHolder&)x)) - {} - #endif - - //! Effects: Constructs a list that will use a copy of allocator a - //! and inserts a copy of the range [first, last) in the list. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's constructor taking an dereferenced InIt throws. - //! - //! Complexity: Linear to the range [first, last). - template - list(InpIt first, InpIt last, const A &a = A()) - : AllocHolder(a) - { this->insert(this->cbegin(), first, last); } - - //! Effects: Destroys the list. All stored values are destroyed - //! and used memory is deallocated. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements. - ~list() - {} //AllocHolder clears the list - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return allocator_type(this->node_alloc()); } - - const stored_allocator_type &get_stored_allocator() const - { return this->node_alloc(); } - - stored_allocator_type &get_stored_allocator() - { return this->node_alloc(); } - - //! Effects: Erases all the elements of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements in the list. - void clear() - { AllocHolder::clear(alloc_version()); } - - //! Effects: Returns an iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return iterator(this->icont().begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return this->cbegin(); } - - //! Effects: Returns an iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return iterator(this->icont().end()); } - - //! Effects: Returns a const_iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return this->cend(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return reverse_iterator(end()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return this->crbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return reverse_iterator(begin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return this->crend(); } - - //! Effects: Returns a const_iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return const_iterator(this->non_const_icont().begin()); } - - //! Effects: Returns a const_iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return const_iterator(this->non_const_icont().end()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return const_reverse_iterator(this->cend()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return const_reverse_iterator(this->cbegin()); } - - //! Effects: Returns true if the list contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return !this->size(); } - - //! Effects: Returns the number of the elements contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return this->icont().size(); } - - //! Effects: Returns the largest possible size of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return AllocHolder::max_size(); } - - //! Effects: Inserts a copy of t in the beginning of the list. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_front(const T& x) - { this->insert(this->cbegin(), x); } - - //! Effects: Constructs a new element in the beginning of the list - //! and moves the resources of t to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_front(detail::moved_object x) - { this->insert(this->cbegin(), x); } - #else - void push_front(T &&x) - { this->insert(this->cbegin(), detail::move_impl(x)); } - #endif - - //! Effects: Removes the last element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void push_back (const T& x) - { this->insert(this->cend(), x); } - - //! Effects: Removes the first element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_back (detail::moved_object x) - { this->insert(this->cend(), x); } - #else - void push_back (T &&x) - { this->insert(this->cend(), detail::move_impl(x)); } - #endif - - //! Effects: Removes the first element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void pop_front() - { this->erase(this->cbegin()); } - - //! Effects: Removes the last element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void pop_back() - { const_iterator tmp = this->cend(); this->erase(--tmp); } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference front() - { return *this->begin(); } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference front() const - { return *this->begin(); } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference back() - { return *(--this->end()); } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference back() const - { return *(--this->end()); } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size, const T& x) - { - const_iterator iend = this->cend(); - size_type len = this->size(); - - if(len > new_size){ - size_type to_erase = len - new_size; - while(to_erase--){ - --iend; - } - this->erase(iend, this->cend()); - } - else{ - this->priv_create_and_insert_nodes(iend, new_size - len, x); - } - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size) - { - const_iterator iend = this->end(); - size_type len = this->size(); - - if(len > new_size){ - size_type to_erase = len - new_size; - const_iterator ifirst; - if(to_erase < len/2u){ - ifirst = iend; - while(to_erase--){ - --ifirst; - } - } - else{ - ifirst = this->begin(); - size_type to_skip = len - to_erase; - while(to_skip--){ - ++ifirst; - } - } - this->erase(ifirst, iend); - } - else{ - this->priv_create_and_insert_nodes(this->cend(), new_size - len); - } - } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() - //! allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(ThisType& x) - #else - void swap(ThisType &&x) - #endif - { AllocHolder::swap(x); } - - //! Effects: Makes *this contain the same elements as x. - //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in x. - ThisType& operator=(const ThisType& x) - { - if (this != &x) { - this->assign(x.begin(), x.end()); - } - return *this; - } - - //! Effects: Move assignment. All mx's values are transferred to *this. - //! - //! Postcondition: x.empty(). *this contains a the elements x had - //! before the function. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - ThisType& operator=(detail::moved_object mx) - { - this->clear(); - this->swap(mx.get()); - return *this; - } - #else - ThisType& operator=(ThisType &&mx) - { - this->clear(); - this->swap(mx); - return *this; - } - #endif - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Inserts n copies of x before p. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void insert(const_iterator p, size_type n, const T& x) - { this->priv_create_and_insert_nodes(p, n, x); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [first, last) range before p. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws. - //! - //! Complexity: Linear to std::distance [first, last). - template - void insert(const_iterator p, InpIt first, InpIt last) - { - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_dispatch(p, first, last, Result()); - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of x before p. - //! - //! Throws: If memory allocation throws or x's copy constructor throws. - //! - //! Complexity: Amortized constant time. - iterator insert(const_iterator p, const T& x) - { - NodePtr tmp = AllocHolder::create_node(x); - return iterator(this->icont().insert(p.get(), *tmp)); - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a new element before p with mx's resources. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator p, detail::moved_object x) - { - NodePtr tmp = AllocHolder::create_node(x); - return iterator(this->icont().insert(p.get(), *tmp)); - } - #else - iterator insert(const_iterator p, T &&x) - { - NodePtr tmp = AllocHolder::create_node(detail::move_impl(x)); - return iterator(this->icont().insert(p.get(), *tmp)); - } - #endif - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the end of the list. - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - void emplace_back(Args&&... args) - { - this->emplace(this->cend(), detail::forward_impl(args)...); - } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the beginning of the list. - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - void emplace_front(Args&&... args) - { - this->emplace(this->cbegin(), detail::forward_impl(args)...); - } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... before p. - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - iterator emplace(const_iterator p, Args&&... args) - { - typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); - new ((void*)detail::get_pointer(d.get())) Node(detail::forward_impl(args)...); - NodePtr node = d.get(); - d.release(); - return iterator(this->icont().insert(p.get(), *node)); - } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //0 args - void emplace_back() - { this->emplace(this->cend()); } - - void emplace_front() - { this->emplace(this->cbegin()); } - - iterator emplace(const_iterator p) - { - typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); - new ((void*)detail::get_pointer(d.get())) Node(); - NodePtr node = d.get(); - d.release(); - return iterator(this->icont().insert(p.get(), *node)); - } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - void emplace_back(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - this->emplace(this->cend(), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - } \ - \ - template \ - void emplace_front(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { this->emplace(this->cbegin(), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _));} \ - \ - template \ - iterator emplace(const_iterator p, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); \ - new ((void*)detail::get_pointer(d.get())) \ - Node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - NodePtr node = d.get(); \ - d.release(); \ - return iterator(this->icont().insert(p.get(), *node)); \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Erases the element at p p. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - iterator erase(const_iterator p) - { return iterator(this->icont().erase_and_dispose(p.get(), Destroyer(this->node_alloc()))); } - - //! Requires: first and last must be valid iterator to elements in *this. - //! - //! Effects: Erases the elements pointed by [first, last). - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the distance between first and last. - iterator erase(const_iterator first, const_iterator last) - { return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); } - - //! Effects: Assigns the n copies of val to *this. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void assign(size_type n, const T& val) - { this->priv_fill_assign(n, val); } - - //! Effects: Assigns the the range [first, last) to *this. - //! - //! Throws: If memory allocation throws or - //! T's constructor from dereferencing InpIt throws. - //! - //! Complexity: Linear to n. - template - void assign(InpIt first, InpIt last) - { - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); - } - - //! Requires: p must point to an element contained - //! by the list. x != *this - //! - //! Effects: Transfers all the elements of list x to this list, before the - //! the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: Iterators of values obtained from list x now point to elements of - //! this list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(iterator p, detail::moved_object x) - { this->splice(p, x.get()); } - void splice(iterator p, ThisType& x) - #else - void splice(iterator p, ThisType&& x) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice(p.get(), x.icont()); - } - else{ - throw std::runtime_error("list::splice called with unequal allocators"); - } - } - - //! Requires: p must point to an element contained - //! by this list. i must point to an element contained in list x. - //! - //! Effects: Transfers the value pointed by i, from list x to this list, - //! before the the element pointed by p. No destructors or copy constructors are called. - //! If p == i or p == ++i, this function is a null operation. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object x, const_iterator i) - { this->splice(p, x.get(), i); } - void splice(const_iterator p, ThisType &x, const_iterator i) - #else - void splice(const_iterator p, ThisType &&x, const_iterator i) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice(p.get(), x.icont(), i.get()); - } - else{ - throw std::runtime_error("list::splice called with unequal allocators"); - } - } - - //! Requires: p must point to an element contained - //! by this list. first and last must point to elements contained in list x. - //! - //! Effects: Transfers the range pointed by first and last from list x to this list, - //! before the the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear to the number of elements transferred. - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object x, const_iterator first, const_iterator last) - { this->splice(p, x.get(), first, last); } - void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last) - #else - void splice(const_iterator p, ThisType &&x, const_iterator first, const_iterator last) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice(p.get(), x.icont(), first.get(), last.get()); - } - else{ - throw std::runtime_error("list::splice called with unequal allocators"); - } - } - - //! Requires: p must point to an element contained - //! by this list. first and last must point to elements contained in list x. - //! n == std::distance(first, last) - //! - //! Effects: Transfers the range pointed by first and last from list x to this list, - //! before the the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object x, const_iterator first, const_iterator last, size_type n) - { this->splice(p, x.get(), first, last, n); } - void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last, size_type n) - #else - void splice(const_iterator p, ThisType &&x, const_iterator first, const_iterator last, size_type n) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice(p.get(), x.icont(), first.get(), last.get(), n); - } - else{ - throw std::runtime_error("list::splice called with unequal allocators"); - } - } - - //! Effects: Reverses the order of elements in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time. - //! - //! Note: Iterators and references are not invalidated - void reverse() - { this->icont().reverse(); } - - //! Effects: Removes all the elements that compare equal to value. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear time. It performs exactly size() comparisons for equality. - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - void remove(const T& value) - { remove_if(equal_to_value(value)); } - - //! Effects: Removes all the elements for which a specified - //! predicate is satisfied. - //! - //! Throws: If pred throws. - //! - //! Complexity: Linear time. It performs exactly size() calls to the predicate. - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - template - void remove_if(Pred pred) - { - typedef ValueCompareToNodeCompare Predicate; - this->icont().remove_and_dispose_if(Predicate(pred), Destroyer(this->node_alloc())); - } - - //! Effects: Removes adjacent duplicate elements or adjacent - //! elements that are equal from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear time (size()-1 comparisons calls to pred()). - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - void unique() - { this->unique(value_equal()); } - - //! Effects: Removes adjacent duplicate elements or adjacent - //! elements that satisfy some binary predicate from the list. - //! - //! Throws: If pred throws. - //! - //! Complexity: Linear time (size()-1 comparisons equality comparisons). - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - template - void unique(BinaryPredicate binary_pred) - { - typedef ValueCompareToNodeCompare Predicate; - this->icont().unique_and_dispose(Predicate(binary_pred), Destroyer(this->node_alloc())); - } - - //! Requires: The lists x and *this must be distinct. - //! - //! Effects: This function removes all of x's elements and inserts them - //! in order into *this according to std::less. The merge is stable; - //! that is, if an element from *this is equivalent to one from x, then the element - //! from *this will precede the one from x. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time: it performs at most - //! size() + x.size() - 1 comparisons. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void merge(detail::moved_object > x) - { this->merge(x.get()); } - void merge(list& x) - #else - void merge(list&& x) - #endif - { this->merge(x, value_less()); } - - //! Requires: p must be a comparison function that induces a strict weak - //! ordering and both *this and x must be sorted according to that ordering - //! The lists x and *this must be distinct. - //! - //! Effects: This function removes all of x's elements and inserts them - //! in order into *this. The merge is stable; that is, if an element from *this is - //! equivalent to one from x, then the element from *this will precede the one from x. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time: it performs at most - //! size() + x.size() - 1 comparisons. - //! - //! Note: Iterators and references to *this are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - template - void merge(detail::moved_object > x, StrictWeakOrdering comp) - { this->merge(x.get(), comp); } - template - void merge(list& x, StrictWeakOrdering comp) - #else - template - void merge(list&& x, StrictWeakOrdering comp) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().merge(x.icont(), - ValueCompareToNodeCompare(comp)); - } - else{ - throw std::runtime_error("list::merge called with unequal allocators"); - } - } - - //! Effects: This function sorts the list *this according to std::less. - //! The sort is stable, that is, the relative order of equivalent elements is preserved. - //! - //! Throws: Nothing. - //! - //! Notes: Iterators and references are not invalidated. - //! - //! Complexity: The number of comparisons is approximately N log N, where N - //! is the list's size. - void sort() - { this->sort(value_less()); } - - //! Effects: This function sorts the list *this according to std::less. - //! The sort is stable, that is, the relative order of equivalent elements is preserved. - //! - //! Throws: Nothing. - //! - //! Notes: Iterators and references are not invalidated. - //! - //! Complexity: The number of comparisons is approximately N log N, where N - //! is the list's size. - template - void sort(StrictWeakOrdering comp) - { - // nothing if the list has length 0 or 1. - if (this->size() < 2) - return; - this->icont().sort(ValueCompareToNodeCompare(comp)); - } - - /// @cond - private: - - //Iterator range version - template - void priv_create_and_insert_nodes - (const_iterator pos, InpIterator beg, InpIterator end) - { - typedef typename std::iterator_traits::iterator_category ItCat; - priv_create_and_insert_nodes(pos, beg, end, alloc_version(), ItCat()); - } - - template - void priv_create_and_insert_nodes - (const_iterator pos, InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) - { - for (; beg != end; ++beg){ - this->icont().insert(pos.get(), *this->create_node_from_it(beg)); - } - } - - template - void priv_create_and_insert_nodes - (const_iterator pos, InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) - { //Just forward to the default one - priv_create_and_insert_nodes(pos, beg, end, allocator_v1(), std::input_iterator_tag()); - } - - class insertion_functor; - friend class insertion_functor; - - class insertion_functor - { - Icont &icont_; - typename Icont::const_iterator pos_; - - public: - insertion_functor(Icont &icont, typename Icont::const_iterator pos) - : icont_(icont), pos_(pos) - {} - - void operator()(Node &n) - { this->icont_.insert(pos_, n); } - }; - - - template - void priv_create_and_insert_nodes - (const_iterator pos, FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag) - { - if(beg != end){ - //Optimized allocation and construction - this->allocate_many_and_construct - (beg, std::distance(beg, end), insertion_functor(this->icont(), pos.get())); - } - } - - //Default constructed version - void priv_create_and_insert_nodes(const_iterator pos, size_type n) - { - typedef default_construct_iterator default_iterator; - this->priv_create_and_insert_nodes(pos, default_iterator(n), default_iterator()); - } - - //Copy constructed version - void priv_create_and_insert_nodes(const_iterator pos, size_type n, const T& x) - { - typedef constant_iterator cvalue_iterator; - this->priv_create_and_insert_nodes(pos, cvalue_iterator(x, n), cvalue_iterator()); - } - - //Dispatch to detect iterator range or integer overloads - template - void priv_insert_dispatch(const_iterator p, - InputIter first, InputIter last, - detail::false_) - { this->priv_create_and_insert_nodes(p, first, last); } - - template - void priv_insert_dispatch(const_iterator p, Integer n, Integer x, detail::true_) - { this->insert(p, (size_type)n, x); } - - void priv_fill_assign(size_type n, const T& val) - { - iterator i = this->begin(), iend = this->end(); - - for ( ; i != iend && n > 0; ++i, --n) - *i = val; - if (n > 0){ - this->priv_create_and_insert_nodes(this->cend(), n, val); - } - else{ - this->erase(i, cend()); - } - } - - template - void priv_assign_dispatch(Integer n, Integer val, detail::true_) - { this->priv_fill_assign((size_type) n, (T) val); } - - template - void priv_assign_dispatch(InputIter first2, InputIter last2, detail::false_) - { - iterator first1 = this->begin(); - iterator last1 = this->end(); - for ( ; first1 != last1 && first2 != last2; ++first1, ++first2) - *first1 = *first2; - if (first2 == last2) - this->erase(first1, last1); - else{ - this->priv_create_and_insert_nodes(last1, first2, last2); - } - } - - //Functors for member algorithm defaults - struct value_less - { - bool operator()(const value_type &a, const value_type &b) const - { return a < b; } - }; - - struct value_equal - { - bool operator()(const value_type &a, const value_type &b) const - { return a == b; } - }; - /// @endcond - -}; - -template -inline bool operator==(const list& x, const list& y) -{ - if(x.size() != y.size()){ - return false; - } - typedef typename list::const_iterator const_iterator; - const_iterator end1 = x.end(); - - const_iterator i1 = x.begin(); - const_iterator i2 = y.begin(); - while (i1 != end1 && *i1 == *i2) { - ++i1; - ++i2; - } - return i1 == end1; -} - -template -inline bool operator<(const list& x, - const list& y) -{ - return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); -} - -template -inline bool operator!=(const list& x, const list& y) -{ - return !(x == y); -} - -template -inline bool operator>(const list& x, const list& y) -{ - return y < x; -} - -template -inline bool operator<=(const list& x, const list& y) -{ - return !(y < x); -} - -template -inline bool operator>=(const list& x, const list& y) -{ - return !(x < y); -} - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(list& x, list& y) -{ - x.swap(y); -} - -template -inline void swap(detail::moved_object >& x, list y) -{ - x.get().swap(y); -} - -template -inline void swap(list& x, detail::moved_object > y) -{ - x.swap(y.get()); -} -#else -template -inline void swap(list &&x, list &&y) -{ - x.swap(y); -} - -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -/* -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -*/ -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::value }; -}; -/// @endcond +using boost::interprocess_container::list; } //namespace interprocess { } //namespace boost { #include -#endif // BOOST_INTERPROCESS_LIST_HPP_ +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_LIST_HPP + diff --git a/include/boost/interprocess/containers/map.hpp b/include/boost/interprocess/containers/map.hpp index 2d7f1a3..a5f0d41 100644 --- a/include/boost/interprocess/containers/map.hpp +++ b/include/boost/interprocess/containers/map.hpp @@ -1,1313 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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. // ////////////////////////////////////////////////////////////////////////////// -// -// This file comes from SGI's stl_map/stl_multimap files. Modified by Ion Gaztanaga. -// Renaming, isolating and porting to generic algorithms. Pointer typedef -// set to allocator::pointer to allow placing it in shared memory. -// -/////////////////////////////////////////////////////////////////////////////// -/* - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifndef BOOST_INTERPROCESS_MAP_HPP -#define BOOST_INTERPROCESS_MAP_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_MAP_HPP +#define BOOST_INTERPROCESS_CONTAINERS_MAP_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +namespace boost { +namespace interprocess { -namespace boost { namespace interprocess { +using boost::interprocess_container::map; +using boost::interprocess_container::multimap; -/// @cond -// Forward declarations of operators == and <, needed for friend declarations. -template -inline bool operator==(const map& x, - const map& y); - -template -inline bool operator<(const map& x, - const map& y); -/// @endcond - -//! A map is a kind of associative container that supports unique keys (contains at -//! most one of each key value) and provides for fast retrieval of values of another -//! type T based on the keys. The map class supports bidirectional iterators. -//! -//! A map satisfies all of the requirements of a container and of a reversible -//! container and of an associative container. For a -//! map the key_type is Key and the value_type is std::pair. -//! -//! Pred is the ordering function for Keys (e.g. std::less). -//! -//! Alloc is the allocator to allocate the value_types -//! (e.g. boost::interprocess:allocator< std::pair). -template -class map -{ - /// @cond - private: - typedef detail::rbtree, - detail::select1st< std::pair >, - Pred, - Alloc> tree_t; - tree_t m_tree; // red-black tree representing map - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef T mapped_type; - typedef Pred key_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - /// @cond - class value_compare_impl - : public Pred, - public std::binary_function - { - friend class map; - protected : - value_compare_impl(const Pred &c) : Pred(c) {} - public: - bool operator()(const value_type& x, const value_type& y) const { - return Pred::operator()(x.first, y.first); - } - }; - /// @endcond - typedef value_compare_impl value_compare; - - //! Effects: Constructs an empty map using the specified comparison object - //! and allocator. - //! - //! Complexity: Constant. - explicit map(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(comp, a) - {} - - //! Effects: Constructs an empty map using the specified comparison object and - //! allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - map(InputIterator first, InputIterator last, const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, true) - {} - - //! Effects: Copy constructs a map. - //! - //! Complexity: Linear in x.size(). - map(const map& x) - : m_tree(x.m_tree) - {} - - //! Effects: Move constructs a map. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - map(detail::moved_object > x) - : m_tree(detail::move_impl(x.get().m_tree)) - {} - #else - map(map &&x) - : m_tree(detail::move_impl(x.m_tree)) - {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - map& operator=(const map& x) - { m_tree = x.m_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - map& operator=(detail::moved_object > x) - { m_tree = detail::move_impl(x.get().m_tree); return *this; } - #else - map& operator=(map &&x) - { m_tree = detail::move_impl(x.m_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return value_compare(m_tree.key_comp()); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return m_tree.get_allocator(); } - - const stored_allocator_type &get_stored_allocator() const - { return m_tree.get_stored_allocator(); } - - stored_allocator_type &get_stored_allocator() - { return m_tree.get_stored_allocator(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_tree.begin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_tree.end(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_tree.rbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_tree.rend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_tree.max_size(); } - - //! Effects: If there is no key equivalent to x in the map, inserts - //! value_type(x, T()) into the map. - //! - //! Returns: A reference to the mapped_type corresponding to x in *this. - //! - //! Complexity: Logarithmic. - T& operator[](const key_type& k) - { - //we can optimize this - iterator i = lower_bound(k); - // i->first is greater than or equivalent to k. - if (i == end() || key_comp()(k, (*i).first)){ - value_type val(k, detail::move_impl(T())); - i = insert(i, detail::move_impl(val)); - } - return (*i).second; - } - - //! Effects: If there is no key equivalent to x in the map, inserts - //! value_type(detail::move_impl(x), T()) into the map (the key is move-constructed) - //! - //! Returns: A reference to the mapped_type corresponding to x in *this. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - T& operator[](detail::moved_object mk) - { - key_type &k = mk.get(); - //we can optimize this - iterator i = lower_bound(k); - // i->first is greater than or equivalent to k. - if (i == end() || key_comp()(k, (*i).first)){ - value_type val(k, detail::move_impl(T())); - i = insert(i, detail::move_impl(val)); - } - return (*i).second; - } - #else - T& operator[](key_type &&mk) - { - key_type &k = mk; - //we can optimize this - iterator i = lower_bound(k); - // i->first is greater than or equivalent to k. - if (i == end() || key_comp()(k, (*i).first)){ - value_type val(detail::move_impl(k), detail::move_impl(T())); - i = insert(i, detail::move_impl(val)); - } - return (*i).second; - } - #endif - - //! Returns: A reference to the element whose key is equivalent to x. - //! Throws: An exception object of type out_of_range if no such element is present. - //! Complexity: logarithmic. - T& at(const key_type& k) - { - iterator i = this->find(k); - if(i == this->end()){ - throw std::out_of_range("key not found"); - } - return i->second; - } - - //! Returns: A reference to the element whose key is equivalent to x. - //! Throws: An exception object of type out_of_range if no such element is present. - //! Complexity: logarithmic. - const T& at(const key_type& k) const - { - const_iterator i = this->find(k); - if(i == this->end()){ - throw std::out_of_range("key not found"); - } - return i->second; - } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(map& x) - #else - void swap(map &&x) - #endif - { m_tree.swap(x.m_tree); } - - //! Effects: Inserts x if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - std::pair insert(const value_type& x) - { return m_tree.insert_unique(x); } - - //! Effects: Inserts a new value_type created from the pair if and only if - //! there is no element in the container with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - std::pair insert(const std::pair& x) - { return m_tree.insert_unique(x); } - - //! Effects: Inserts a new value_type move constructed from the pair if and - //! only if there is no element in the container with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object > x) - { return m_tree.insert_unique(x); } - #else - std::pair insert(std::pair &&x) - { return m_tree.insert_unique(detail::move_impl(x)); } - #endif - - //! Effects: Move constructs a new value from x if and only if there is - //! no element in the container with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object x) - { return m_tree.insert_unique(x); } - #else - std::pair insert(value_type &&x) - { return m_tree.insert_unique(detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container if and only if there is - //! no element in the container with key equivalent to the key of x. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - iterator insert(iterator position, const value_type& x) - { return m_tree.insert_unique(position, x); } - - //! Effects: Move constructs a new value from x if and only if there is - //! no element in the container with key equivalent to the key of x. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(iterator position, detail::moved_object > x) - { return m_tree.insert_unique(position, x); } - #else - iterator insert(iterator position, std::pair &&x) - { return m_tree.insert_unique(position, detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - iterator insert(iterator position, const std::pair& x) - { return m_tree.insert_unique(position, x); } - - //! Effects: Inserts an element move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(iterator position, detail::moved_object x) - { return m_tree.insert_unique(position, x); } - #else - iterator insert(iterator position, value_type &&x) - { return m_tree.insert_unique(position, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) if and only - //! if there is no element with key equivalent to the key of that element. - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - template - void insert(InputIterator first, InputIterator last) - { m_tree.insert_unique(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container if and only if there is - //! no element in the container with an equivalent key. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace(Args&&... args) - { return m_tree.emplace_unique(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container if and only if there is - //! no element in the container with an equivalent key. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_tree.emplace_hint_unique(hint, detail::forward_impl(args)...); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return m_tree.emplace_unique(); } - - iterator emplace_hint(const_iterator hint) - { return m_tree.emplace_hint_unique(hint); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _));}\ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Amortized constant time - iterator erase(const_iterator position) - { return m_tree.erase(position); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: log(size()) + count(k) - size_type erase(const key_type& x) - { return m_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: log(size())+N where N is the distance from first to last. - iterator erase(const_iterator first, const_iterator last) - { return m_tree.erase(first, last); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_tree.clear(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_tree.find(x); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return m_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_tree.find(x) == m_tree.end() ? 0 : 1; } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) - { return m_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) const - { return m_tree.equal_range(x); } - - /// @cond - template - friend bool operator== (const map&, - const map&); - template - friend bool operator< (const map&, - const map&); - /// @endcond -}; - -template -inline bool operator==(const map& x, - const map& y) - { return x.m_tree == y.m_tree; } - -template -inline bool operator<(const map& x, - const map& y) - { return x.m_tree < y.m_tree; } - -template -inline bool operator!=(const map& x, - const map& y) - { return !(x == y); } - -template -inline bool operator>(const map& x, - const map& y) - { return y < x; } - -template -inline bool operator<=(const map& x, - const map& y) - { return !(y < x); } - -template -inline bool operator>=(const map& x, - const map& y) - { return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(map& x, map& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, map& y) - { x.get().swap(y); } - -template -inline void swap(map& x, detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(map&&x, map&&y) - { x.swap(y); } -#endif - - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -// Forward declaration of operators < and ==, needed for friend declaration. - -template -inline bool operator==(const multimap& x, - const multimap& y); - -template -inline bool operator<(const multimap& x, - const multimap& y); - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; -/// @endcond - -//! A multimap is a kind of associative container that supports equivalent keys -//! (possibly containing multiple copies of the same key value) and provides for -//! fast retrieval of values of another type T based on the keys. The multimap class -//! supports bidirectional iterators. -//! -//! A multimap satisfies all of the requirements of a container and of a reversible -//! container and of an associative container. For a -//! map the key_type is Key and the value_type is std::pair. -//! -//! Pred is the ordering function for Keys (e.g. std::less). -//! -//! Alloc is the allocator to allocate the value_types -//!(e.g. boost::interprocess:allocator< std::pair<const Key, T>). -template -class multimap -{ - /// @cond - private: - typedef detail::rbtree, - detail::select1st< std::pair >, - Pred, - Alloc> tree_t; - tree_t m_tree; // red-black tree representing map - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef T mapped_type; - typedef Pred key_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - /// @cond - class value_compare_impl - : public Pred, - public std::binary_function - { - friend class multimap; - protected : - value_compare_impl(const Pred &c) : Pred(c) {} - public: - bool operator()(const value_type& x, const value_type& y) const { - return Pred::operator()(x.first, y.first); - } - }; - /// @endcond - typedef value_compare_impl value_compare; - - //! Effects: Constructs an empty multimap using the specified comparison - //! object and allocator. - //! - //! Complexity: Constant. - explicit multimap(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(comp, a) - {} - - //! Effects: Constructs an empty multimap using the specified comparison object - //! and allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - multimap(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, false) - {} - - //! Effects: Copy constructs a multimap. - //! - //! Complexity: Linear in x.size(). - multimap(const multimap& x) - : m_tree(x.m_tree) - {} - - //! Effects: Move constructs a multimap. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - multimap(detail::moved_object > x) - : m_tree(detail::move_impl(x.get().m_tree)) - {} - #else - multimap(multimap && x) - : m_tree(detail::move_impl(x.m_tree)) - {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - multimap& - operator=(const multimap& x) - { m_tree = x.m_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - multimap& operator=(detail::moved_object > x) - { m_tree = detail::move_impl(x.get().m_tree); return *this; } - #else - multimap& operator=(multimap && x) - { m_tree = detail::move_impl(x.m_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return value_compare(m_tree.key_comp()); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return m_tree.get_allocator(); } - - const stored_allocator_type &get_stored_allocator() const - { return m_tree.get_stored_allocator(); } - - stored_allocator_type &get_stored_allocator() - { return m_tree.get_stored_allocator(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_tree.begin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_tree.end(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_tree.rbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_tree.rend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(multimap& x) - #else - void swap(multimap &&x) - #endif - { m_tree.swap(x.m_tree); } - - //! Effects: Inserts x and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic. - iterator insert(const value_type& x) - { return m_tree.insert_equal(x); } - - //! Effects: Inserts a new value constructed from x and returns - //! the iterator pointing to the newly inserted element. - //! - //! Complexity: Logarithmic. - iterator insert(const std::pair& x) - { return m_tree.insert_equal(x); } - - //! Effects: Inserts a new value move-constructed from x and returns - //! the iterator pointing to the newly inserted element. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(detail::moved_object > x) - { return m_tree.insert_equal(x); } - #else - iterator insert(std::pair && x) - { return m_tree.insert_equal(detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - iterator insert(iterator position, const value_type& x) - { return m_tree.insert_equal(position, x); } - - //! Effects: Inserts a new value constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - iterator insert(iterator position, const std::pair& x) - { return m_tree.insert_equal(position, x); } - - //! Effects: Inserts a new value move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(iterator position, detail::moved_object > x) - { return m_tree.insert_equal(position, x); } - #else - iterator insert(iterator position, std::pair && x) - { return m_tree.insert_equal(position, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) . - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - template - void insert(InputIterator first, InputIterator last) - { m_tree.insert_equal(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace(Args&&... args) - { return m_tree.emplace_equal(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_tree.emplace_hint_equal(hint, detail::forward_impl(args)...); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return m_tree.emplace_equal(); } - - iterator emplace_hint(const_iterator hint) - { return m_tree.emplace_hint_equal(hint); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); }\ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Amortized constant time - iterator erase(const_iterator position) - { return m_tree.erase(position); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: log(size()) + count(k) - size_type erase(const key_type& x) - { return m_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: log(size())+N where N is the distance from first to last. - iterator erase(const_iterator first, const_iterator last) - { return m_tree.erase(first, last); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_tree.clear(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_tree.find(x); } - - //! Returns: A const iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return m_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_tree.count(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - {return m_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) - { return m_tree.equal_range(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_tree.equal_range(x); } - - /// @cond - template - friend bool operator== (const multimap& x, - const multimap& y); - - template - friend bool operator< (const multimap& x, - const multimap& y); - /// @endcond -}; - -template -inline bool operator==(const multimap& x, - const multimap& y) -{ return x.m_tree == y.m_tree; } - -template -inline bool operator<(const multimap& x, - const multimap& y) -{ return x.m_tree < y.m_tree; } - -template -inline bool operator!=(const multimap& x, - const multimap& y) -{ return !(x == y); } - -template -inline bool operator>(const multimap& x, - const multimap& y) -{ return y < x; } - -template -inline bool operator<=(const multimap& x, - const multimap& y) -{ return !(y < x); } - -template -inline bool operator>=(const multimap& x, - const multimap& y) -{ return !(x < y); } - - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(multimap& x, multimap& y) -{ x.swap(y); } - -template -inline void swap(detail::moved_object > x, multimap& y) -{ x.get().swap(y); } - -template -inline void swap(multimap& x, detail::moved_object > y) -{ x.swap(y.get()); } -#else -template -inline void swap(multimap&&x, multimap&&y) -{ x.swap(y); } -#endif - -/// @cond -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess { +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_MAP_HPP */ - +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_MAP_HPP diff --git a/include/boost/interprocess/containers/pair.hpp b/include/boost/interprocess/containers/pair.hpp new file mode 100644 index 0000000..0510d1a --- /dev/null +++ b/include/boost/interprocess/containers/pair.hpp @@ -0,0 +1,32 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_PAIR_HPP +#define BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +using boost::interprocess_container::containers_detail::pair; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP + diff --git a/include/boost/interprocess/containers/set.hpp b/include/boost/interprocess/containers/set.hpp index 0908116..53d36c0 100644 --- a/include/boost/interprocess/containers/set.hpp +++ b/include/boost/interprocess/containers/set.hpp @@ -1,1186 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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. // ////////////////////////////////////////////////////////////////////////////// -// -// This file comes from SGI's stl_set/stl_multiset files. Modified by Ion Gaztanaga 2004. -// Renaming, isolating and porting to generic algorithms. Pointer typedef -// set to allocator::pointer to allow placing it in shared memory. -// -/////////////////////////////////////////////////////////////////////////////// -/* - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifndef BOOST_INTERPROCESS_SET_HPP -#define BOOST_INTERPROCESS_SET_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_SET_HPP +#define BOOST_INTERPROCESS_CONTAINERS_SET_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include -#include +#include -#include -#include -#include +namespace boost { +namespace interprocess { -#include -#include -#include -#include -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -#include -#endif +using boost::interprocess_container::set; +using boost::interprocess_container::multiset; -namespace boost { namespace interprocess { - -/// @cond -// Forward declarations of operators < and ==, needed for friend declaration. -template -inline bool operator==(const set& x, - const set& y); - -template -inline bool operator<(const set& x, - const set& y); -/// @endcond - -//! A set is a kind of associative container that supports unique keys (contains at -//! most one of each key value) and provides for fast retrieval of the keys themselves. -//! Class set supports bidirectional iterators. -//! -//! A set satisfies all of the requirements of a container and of a reversible container -//! , and of an associative container. A set also provides most operations described in -//! for unique keys. -template -class set -{ - /// @cond - private: - typedef detail::rbtree, Pred, Alloc> tree_t; - tree_t m_tree; // red-black tree representing set - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef Pred key_compare; - typedef Pred value_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty set using the specified comparison object - //! and allocator. - //! - //! Complexity: Constant. - explicit set(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(comp, a) - {} - - //! Effects: Constructs an empty set using the specified comparison object and - //! allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - set(InputIterator first, InputIterator last, const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, true) - {} - - //! Effects: Copy constructs a set. - //! - //! Complexity: Linear in x.size(). - set(const set& x) - : m_tree(x.m_tree) - {} - - //! Effects: Move constructs a set. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - set(detail::moved_object > x) - : m_tree(detail::move_impl(x.get().m_tree)) - {} - #else - set(set &&x) - : m_tree(detail::move_impl(x.m_tree)) - {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - set& operator=(const set& x) - { m_tree = x.m_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - set& operator=(detail::moved_object > x) - { m_tree = detail::move_impl(x.get().m_tree); return *this; } - #else - set& operator=(set &&x) - { m_tree = detail::move_impl(x.m_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return m_tree.get_allocator(); } - - const stored_allocator_type &get_stored_allocator() const - { return m_tree.get_stored_allocator(); } - - stored_allocator_type &get_stored_allocator() - { return m_tree.get_stored_allocator(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant - iterator begin() - { return m_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_tree.begin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_tree.end(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_tree.rbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_tree.rend(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return m_tree.cbegin(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return m_tree.cend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return m_tree.crbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return m_tree.crend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(set& x) - #else - void swap(set &&x) - #endif - { m_tree.swap(x.m_tree); } - - //! Effects: Inserts x if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - std::pair insert(const value_type& x) - { return m_tree.insert_unique(x); } - - //! Effects: Move constructs a new value from x if and only if there is - //! no element in the container with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object x) - { return m_tree.insert_unique(x); } - #else - std::pair insert(value_type &&x) - { return m_tree.insert_unique(detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container if and only if there is - //! no element in the container with key equivalent to the key of x. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - iterator insert(const_iterator p, const value_type& x) - { return m_tree.insert_unique(p, x); } - - //! Effects: Inserts an element move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator p, detail::moved_object x) - { return m_tree.insert_unique(p, x); } - #else - iterator insert(const_iterator p, value_type &&x) - { return m_tree.insert_unique(p, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) if and only - //! if there is no element with key equivalent to the key of that element. - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - template - void insert(InputIterator first, InputIterator last) - { m_tree.insert_unique(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... if and only if there is - //! no element in the container with equivalent value. - //! and returns the iterator pointing to the - //! newly inserted element. - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Logarithmic. - template - iterator emplace(Args&&... args) - { return m_tree.emplace_unique(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... if and only if there is - //! no element in the container with equivalent value. - //! p is a hint pointing to where the insert - //! should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_tree.emplace_hint_unique(hint, detail::forward_impl(args)...); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return m_tree.emplace_unique(); } - - iterator emplace_hint(const_iterator hint) - { return m_tree.emplace_hint_unique(hint); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _));}\ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by p. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Amortized constant time - iterator erase(const_iterator p) - { return m_tree.erase(p); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: log(size()) + count(k) - size_type erase(const key_type& x) - { return m_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: log(size())+N where N is the distance from first to last. - iterator erase(const_iterator first, const_iterator last) - { return m_tree.erase(first, last); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_tree.clear(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_tree.find(x); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return m_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_tree.find(x) == m_tree.end() ? 0 : 1; } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) - { return m_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_tree.equal_range(x); } - - /// @cond - template - friend bool operator== (const set&, const set&); - - template - friend bool operator< (const set&, const set&); - /// @endcond -}; - -template -inline bool operator==(const set& x, - const set& y) -{ return x.m_tree == y.m_tree; } - -template -inline bool operator<(const set& x, - const set& y) -{ return x.m_tree < y.m_tree; } - -template -inline bool operator!=(const set& x, - const set& y) -{ return !(x == y); } - -template -inline bool operator>(const set& x, - const set& y) -{ return y < x; } - -template -inline bool operator<=(const set& x, - const set& y) -{ return !(y < x); } - -template -inline bool operator>=(const set& x, - const set& y) -{ return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(set& x, set& y) -{ x.swap(y); } - -template -inline void swap(set& x, detail::moved_object >& y) -{ x.swap(y.get()); } - -template -inline void swap(detail::moved_object >& y, set& x) -{ y.swap(x.get()); } - -#else -template -inline void swap(set&&x, set&&y) -{ x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; - -// Forward declaration of operators < and ==, needed for friend declaration. - -template -inline bool operator==(const multiset& x, - const multiset& y); - -template -inline bool operator<(const multiset& x, - const multiset& y); -/// @endcond - -//! A multiset is a kind of associative container that supports equivalent keys -//! (possibly contains multiple copies of the same key value) and provides for -//! fast retrieval of the keys themselves. Class multiset supports bidirectional iterators. -//! -//! A multiset satisfies all of the requirements of a container and of a reversible -//! container, and of an associative container). multiset also provides most operations -//! described for duplicate keys. -template -class multiset -{ - /// @cond - private: - typedef detail::rbtree, Pred, Alloc> tree_t; - tree_t m_tree; // red-black tree representing multiset - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef Pred key_compare; - typedef Pred value_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty multiset using the specified comparison - //! object and allocator. - //! - //! Complexity: Constant. - explicit multiset(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(comp, a) - {} - - //! Effects: Constructs an empty multiset using the specified comparison object - //! and allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - multiset(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, false) - {} - - //! Effects: Copy constructs a multiset. - //! - //! Complexity: Linear in x.size(). - multiset(const multiset& x) - : m_tree(x.m_tree) - {} - - //! Effects: Move constructs a multiset. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - multiset(detail::moved_object > x) - : m_tree(detail::move_impl(x.get().m_tree)) - {} - #else - multiset(multiset &&x) - : m_tree(detail::move_impl(x.m_tree)) - {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - multiset& operator=(const multiset& x) - { m_tree = x.m_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - multiset& operator=(detail::moved_object > x) - { m_tree = detail::move_impl(x.get().m_tree); return *this; } - #else - multiset& operator=(multiset &&x) - { m_tree = detail::move_impl(x.m_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return m_tree.get_allocator(); } - - const stored_allocator_type &get_stored_allocator() const - { return m_tree.get_stored_allocator(); } - - stored_allocator_type &get_stored_allocator() - { return m_tree.get_stored_allocator(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_tree.begin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_tree.end(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_tree.rbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_tree.rend(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return m_tree.cbegin(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return m_tree.cend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return m_tree.crbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return m_tree.crend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(multiset& x) - #else - void swap(multiset &&x) - #endif - { m_tree.swap(x.m_tree); } - - //! Effects: Inserts x and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic. - iterator insert(const value_type& x) - { return m_tree.insert_equal(x); } - - //! Effects: Inserts a copy of x in the container. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(detail::moved_object x) - { return m_tree.insert_equal(x); } - #else - iterator insert(value_type && x) - { return m_tree.insert_equal(detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - iterator insert(const_iterator p, const value_type& x) - { return m_tree.insert_equal(p, x); } - - //! Effects: Inserts a value move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator p, detail::moved_object x) - { return m_tree.insert_equal(p, x); } - #else - iterator insert(const_iterator p, value_type && x) - { return m_tree.insert_equal(p, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) . - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - template - void insert(InputIterator first, InputIterator last) - { m_tree.insert_equal(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic. - template - iterator emplace(Args&&... args) - { return m_tree.emplace_equal(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_tree.emplace_hint_equal(hint, detail::forward_impl(args)...); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return m_tree.emplace_equal(); } - - iterator emplace_hint(const_iterator hint) - { return m_tree.emplace_hint_equal(hint); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); }\ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by p. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Amortized constant time - iterator erase(const_iterator p) - { return m_tree.erase(p); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: log(size()) + count(k) - size_type erase(const key_type& x) - { return m_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: log(size())+N where N is the distance from first to last. - iterator erase(const_iterator first, const_iterator last) - { return m_tree.erase(first, last); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_tree.clear(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_tree.find(x); } - - //! Returns: A const iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return m_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_tree.count(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) - { return m_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_tree.equal_range(x); } - - /// @cond - template - friend bool operator== (const multiset&, - const multiset&); - template - friend bool operator< (const multiset&, - const multiset&); - /// @endcond -}; - -template -inline bool operator==(const multiset& x, - const multiset& y) -{ return x.m_tree == y.m_tree; } - -template -inline bool operator<(const multiset& x, - const multiset& y) -{ return x.m_tree < y.m_tree; } - -template -inline bool operator!=(const multiset& x, - const multiset& y) -{ return !(x == y); } - -template -inline bool operator>(const multiset& x, - const multiset& y) -{ return y < x; } - -template -inline bool operator<=(const multiset& x, - const multiset& y) -{ return !(y < x); } - -template -inline bool operator>=(const multiset& x, - const multiset& y) -{ return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(multiset& x, multiset& y) -{ x.swap(y); } - -template -inline void swap(multiset& x, detail::moved_object >& y) -{ x.swap(y.get()); } - -template -inline void swap(detail::moved_object >& y, multiset& x) -{ y.swap(x.get()); } -#else -template -inline void swap(multiset&&x, multiset&&y) -{ x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess { +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_SET_HPP */ - +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_SET_HPP diff --git a/include/boost/interprocess/containers/slist.hpp b/include/boost/interprocess/containers/slist.hpp index 4b0728d..7a3cafd 100644 --- a/include/boost/interprocess/containers/slist.hpp +++ b/include/boost/interprocess/containers/slist.hpp @@ -1,1642 +1,31 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2004-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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. // ////////////////////////////////////////////////////////////////////////////// -// -// This file comes from SGI's stl_slist.h file. Modified by Ion Gaztanaga 2004-2008 -// Renaming, isolating and porting to generic algorithms. Pointer typedef -// set to allocator::pointer to allow placing it in shared memory. -// -/////////////////////////////////////////////////////////////////////////////// -/* - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifndef BOOST_INTERPROCESS_SLIST_HPP -#define BOOST_INTERPROCESS_SLIST_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP +#define BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include +namespace boost { +namespace interprocess { +using boost::interprocess_container::slist; -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -//Preprocessor library to emulate perfect forwarding -#include -#endif - -#include -#include -#include -#include -#include - -namespace boost{ namespace interprocess{ - -/// @cond - -namespace detail { - -template -struct slist_hook -{ - typedef typename bi::make_slist_base_hook - , bi::link_mode >::type type; -}; - -template -struct slist_node - : public slist_hook::type -{ - #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - slist_node() - : m_data() - {} - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - slist_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - : m_data(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)) \ - {} \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #else //#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - template - slist_node(Args &&...args) - : m_data(detail::forward_impl(args)...) - {} - #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - T m_data; -}; - -template -struct intrusive_slist_type -{ - typedef typename A::value_type value_type; - typedef typename detail::pointer_to_other - ::type void_pointer; - typedef typename detail::slist_node - node_type; - - typedef typename bi::make_slist - ::type> - ,bi::constant_time_size - ,bi::size_type - >::type container_type; - typedef container_type type ; -}; - -} //namespace detail { - -/// @endcond - -//! An slist is a singly linked list: a list where each element is linked to the next -//! element, but not to the previous element. That is, it is a Sequence that -//! supports forward but not backward traversal, and (amortized) constant time -//! insertion and removal of elements. Slists, like lists, have the important -//! property that insertion and splicing do not invalidate iterators to list elements, -//! and that even removal invalidates only the iterators that point to the elements -//! that are removed. The ordering of iterators may be changed (that is, -//! slist::iterator might have a different predecessor or successor after a list -//! operation than it did before), but the iterators themselves will not be invalidated -//! or made to point to different elements unless that invalidation or mutation is explicit. -//! -//! The main difference between slist and list is that list's iterators are bidirectional -//! iterators, while slist's iterators are forward iterators. This means that slist is -//! less versatile than list; frequently, however, bidirectional iterators are -//! unnecessary. You should usually use slist unless you actually need the extra -//! functionality of list, because singly linked lists are smaller and faster than double -//! linked lists. -//! -//! Important performance note: like every other Sequence, slist defines the member -//! functions insert and erase. Using these member functions carelessly, however, can -//! result in disastrously slow programs. The problem is that insert's first argument is -//! an iterator p, and that it inserts the new element(s) before p. This means that -//! insert must find the iterator just before p; this is a constant-time operation -//! for list, since list has bidirectional iterators, but for slist it must find that -//! iterator by traversing the list from the beginning up to p. In other words: -//! insert and erase are slow operations anywhere but near the beginning of the slist. -//! -//! Slist provides the member functions insert_after and erase_after, which are constant -//! time operations: you should always use insert_after and erase_after whenever -//! possible. If you find that insert_after and erase_after aren't adequate for your -//! needs, and that you often need to use insert and erase in the middle of the list, -//! then you should probably use list instead of slist. -template -class slist - : protected detail::node_alloc_holder - ::type> -{ - /// @cond - typedef typename - detail::intrusive_slist_type::type Icont; - typedef detail::node_alloc_holder AllocHolder; - typedef typename AllocHolder::NodePtr NodePtr; - typedef slist ThisType; - typedef typename AllocHolder::NodeAlloc NodeAlloc; - typedef typename AllocHolder::ValAlloc ValAlloc; - typedef typename AllocHolder::Node Node; - typedef detail::allocator_destroyer Destroyer; - typedef typename AllocHolder::allocator_v1 allocator_v1; - typedef typename AllocHolder::allocator_v2 allocator_v2; - typedef typename AllocHolder::alloc_version alloc_version; - - class equal_to_value - { - typedef typename AllocHolder::value_type value_type; - const value_type &t_; - - public: - equal_to_value(const value_type &t) - : t_(t) - {} - - bool operator()(const value_type &t)const - { return t_ == t; } - }; - - template - struct ValueCompareToNodeCompare - : Pred - { - ValueCompareToNodeCompare(Pred pred) - : Pred(pred) - {} - - bool operator()(const Node &a, const Node &b) const - { return static_cast(*this)(a.m_data, b.m_data); } - - bool operator()(const Node &a) const - { return static_cast(*this)(a.m_data); } - }; - /// @endcond - public: - //! The type of object, T, stored in the list - typedef T value_type; - //! Pointer to T - typedef typename A::pointer pointer; - //! Const pointer to T - typedef typename A::const_pointer const_pointer; - //! Reference to T - typedef typename A::reference reference; - //! Const reference to T - typedef typename A::const_reference const_reference; - //! An unsigned integral type - typedef typename A::size_type size_type; - //! A signed integral type - typedef typename A::difference_type difference_type; - //! The allocator type - typedef A allocator_type; - //! The stored allocator type - typedef NodeAlloc stored_allocator_type; - - /// @cond - private: - typedef difference_type list_difference_type; - typedef pointer list_pointer; - typedef const_pointer list_const_pointer; - typedef reference list_reference; - typedef const_reference list_const_reference; - /// @endcond - - public: - //! Const iterator used to iterate through a list. - class const_iterator - /// @cond - : public std::iterator - { - - protected: - typename Icont::iterator m_it; - explicit const_iterator(typename Icont::iterator it) : m_it(it){} - void prot_incr(){ ++m_it; } - - private: - typename Icont::iterator get() - { return this->m_it; } - - public: - friend class slist; - typedef list_difference_type difference_type; - - //Constructors - const_iterator() - : m_it() - {} - - //Pointer like operators - const_reference operator*() const - { return m_it->m_data; } - - const_pointer operator->() const - { return const_pointer(&m_it->m_data); } - - //Increment / Decrement - const_iterator& operator++() - { prot_incr(); return *this; } - - const_iterator operator++(int) - { typename Icont::iterator tmp = m_it; ++*this; return const_iterator(tmp); } - - //Comparison operators - bool operator== (const const_iterator& r) const - { return m_it == r.m_it; } - - bool operator!= (const const_iterator& r) const - { return m_it != r.m_it; } - } - /// @endcond - ; - - //! Iterator used to iterate through a list - class iterator - /// @cond - : public const_iterator - { - - private: - explicit iterator(typename Icont::iterator it) - : const_iterator(it) - {} - - typename Icont::iterator get() - { return this->m_it; } - - public: - friend class slist; - typedef list_pointer pointer; - typedef list_reference reference; - - //Constructors - iterator(){} - - //Pointer like operators - reference operator*() const { return this->m_it->m_data; } - pointer operator->() const { return pointer(&this->m_it->m_data); } - - //Increment / Decrement - iterator& operator++() - { this->prot_incr(); return *this; } - - iterator operator++(int) - { typename Icont::iterator tmp = this->m_it; ++*this; return iterator(tmp); } - } - /// @endcond - ; - - public: - //! Effects: Constructs a list taking the allocator as parameter. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - explicit slist(const allocator_type& a = allocator_type()) - : AllocHolder(a) - {} - -// explicit slist(size_type n) -// : AllocHolder(detail::move_impl(allocator_type())) -// { this->resize(n); } - - //! Effects: Constructs a list that will use a copy of allocator a - //! and inserts n copies of value. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's default or copy constructor throws. - //! - //! Complexity: Linear to n. - explicit slist(size_type n, const value_type& x = value_type(), - const allocator_type& a = allocator_type()) - : AllocHolder(a) - { this->priv_create_and_insert_nodes(this->before_begin(), n, x); } - - //! Effects: Constructs a list that will use a copy of allocator a - //! and inserts a copy of the range [first, last) in the list. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's constructor taking an dereferenced InIt throws. - //! - //! Complexity: Linear to the range [first, last). - template - slist(InpIt first, InpIt last, - const allocator_type& a = allocator_type()) - : AllocHolder(a) - { this->insert_after(this->before_begin(), first, last); } - - //! Effects: Copy constructs a list. - //! - //! Postcondition: x == *this. - //! - //! Throws: If allocator_type's default constructor or copy constructor throws. - //! - //! Complexity: Linear to the elements x contains. - slist(const slist& x) - : AllocHolder(x) - { this->insert_after(this->before_begin(), x.begin(), x.end()); } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - slist(detail::moved_object x) - : AllocHolder(detail::move_impl((AllocHolder&)x.get())) - {} - #else - slist(slist &&x) - : AllocHolder(detail::move_impl((AllocHolder&)x)) - {} - #endif - - //! Effects: Makes *this contain the same elements as x. - //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in x. - slist& operator= (const slist& x) - { - if (&x != this){ - this->assign(x.begin(), x.end()); - } - return *this; - } - - //! Effects: Makes *this contain the same elements as x. - //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in x. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - slist& operator= (detail::moved_object mx) - { - if (&mx.get() != this){ - this->clear(); - this->swap(mx.get()); - } - return *this; - } - #else - slist& operator= (slist && mx) - { - if (&mx != this){ - this->clear(); - this->swap(mx); - } - return *this; - } - #endif - - //! Effects: Destroys the list. All stored values are destroyed - //! and used memory is deallocated. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements. - ~slist() - {} //AllocHolder clears the slist - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return allocator_type(this->node_alloc()); } - - const stored_allocator_type &get_stored_allocator() const - { return this->node_alloc(); } - - stored_allocator_type &get_stored_allocator() - { return this->node_alloc(); } - - public: - - //! Effects: Assigns the n copies of val to *this. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void assign(size_type n, const T& val) - { this->priv_fill_assign(n, val); } - - //! Effects: Assigns the range [first, last) to *this. - //! - //! Throws: If memory allocation throws or - //! T's constructor from dereferencing InpIt throws. - //! - //! Complexity: Linear to n. - template - void assign(InpIt first, InpIt last) - { - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); - } - - //! Effects: Returns an iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return iterator(this->icont().begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return this->cbegin(); } - - //! Effects: Returns an iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return iterator(this->icont().end()); } - - //! Effects: Returns a const_iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return this->cend(); } - - //! Effects: Returns a non-dereferenceable iterator that, - //! when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator before_begin() - { return iterator(end()); } - - //! Effects: Returns a non-dereferenceable const_iterator - //! that, when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator before_begin() const - { return this->cbefore_begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return const_iterator(this->non_const_icont().begin()); } - - //! Effects: Returns a const_iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return const_iterator(this->non_const_icont().end()); } - - //! Effects: Returns a non-dereferenceable const_iterator - //! that, when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbefore_begin() const - { return const_iterator(end()); } - - //! Effects: Returns the number of the elements contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return this->icont().size(); } - - //! Effects: Returns the largest possible size of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return AllocHolder::max_size(); } - - //! Effects: Returns true if the list contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return !this->size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() - //! allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements on *this and x. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(slist& x) - #else - void swap(slist &&x) - #endif - { AllocHolder::swap(x); } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference front() - { return *this->begin(); } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference front() const - { return *this->begin(); } - - //! Effects: Inserts a copy of t in the beginning of the list. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_front(const value_type& x) - { this->icont().push_front(*this->create_node(x)); } - - //! Effects: Constructs a new element in the beginning of the list - //! and moves the resources of t to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_front(detail::moved_object x) - { this->icont().push_front(*this->create_node(x)); } - #else - void push_front(T && x) - { this->icont().push_front(*this->create_node(detail::move_impl(x))); } - #endif - - //! Effects: Removes the first element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void pop_front() - { this->icont().pop_front_and_dispose(Destroyer(this->node_alloc())); } - - //! Returns: The iterator to the element before i in the sequence. - //! Returns the end-iterator, if either i is the begin-iterator or the - //! sequence is empty. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements before i. - iterator previous(iterator p) - { return iterator(this->icont().previous(p.get())); } - - //! Returns: The const_iterator to the element before i in the sequence. - //! Returns the end-const_iterator, if either i is the begin-const_iterator or - //! the sequence is empty. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements before i. - const_iterator previous(const_iterator p) - { return const_iterator(this->icont().previous(p.get())); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Inserts a copy of the value after the p pointed - //! by prev_p. - //! - //! Returns: An iterator to the inserted element. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - //! - //! Note: Does not affect the validity of iterators and references of - //! previous values. - iterator insert_after(const_iterator prev_pos, const value_type& x) - { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(x))); } - - //! Requires: prev_pos must be a valid iterator of *this. - //! - //! Effects: Inserts a move constructed copy object from the value after the - //! p pointed by prev_pos. - //! - //! Returns: An iterator to the inserted element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - //! - //! Note: Does not affect the validity of iterators and references of - //! previous values. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert_after(const_iterator prev_pos, detail::moved_object x) - { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(x))); } - #else - iterator insert_after(const_iterator prev_pos, value_type && x) - { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(detail::move_impl(x)))); } - #endif - - //! Requires: prev_pos must be a valid iterator of *this. - //! - //! Effects: Inserts n copies of x after prev_pos. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - //! - //! Note: Does not affect the validity of iterators and references of - //! previous values. - void insert_after(const_iterator prev_pos, size_type n, const value_type& x) - { this->priv_create_and_insert_nodes(prev_pos, n, x); } - - //! Requires: prev_pos must be a valid iterator of *this. - //! - //! Effects: Inserts the range pointed by [first, last) - //! after the p prev_pos. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws. - //! - //! Complexity: Linear to the number of elements inserted. - //! - //! Note: Does not affect the validity of iterators and references of - //! previous values. - template - void insert_after(const_iterator prev_pos, InIter first, InIter last) - { - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_after_range_dispatch(prev_pos, first, last, Result()); - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of x before p. - //! - //! Throws: If memory allocation throws or x's copy constructor throws. - //! - //! Complexity: Linear to the elements before p. - iterator insert(const_iterator p, const value_type& x) - { return this->insert_after(previous(p), x); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a new element before p with mx's resources. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Linear to the elements before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator p, detail::moved_object x) - { return this->insert_after(previous(p), x); } - #else - iterator insert(const_iterator p, value_type && x) - { return this->insert_after(previous(p), detail::move_impl(x)); } - #endif - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Inserts n copies of x before p. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n plus linear to the elements before p. - void insert(const_iterator p, size_type n, const value_type& x) - { return this->insert_after(previous(p), n, x); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [first, last) range before p. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws. - //! - //! Complexity: Linear to std::distance [first, last) plus - //! linear to the elements before p. - template - void insert(const_iterator p, InIter first, InIter last) - { return this->insert_after(previous(p), first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the front of the list - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - template - void emplace_front(Args&&... args) - { this->emplace_after(this->cbefore_begin(), detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... before p - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Linear to the elements before p - template - iterator emplace(const_iterator p, Args&&... args) - { return this->emplace_after(this->previous(p), detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... after prev - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - iterator emplace_after(const_iterator prev, Args&&... args) - { - typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); - new ((void*)detail::get_pointer(d.get())) Node(detail::forward_impl(args)...); - NodePtr node = d.get(); - d.release(); - return iterator(this->icont().insert_after(prev.get(), *node)); - } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //0 args - void emplace_front() - { this->emplace_after(this->cbefore_begin()); } - - iterator emplace(const_iterator p) - { return this->emplace_after(this->previous(p)); } - - iterator emplace_after(const_iterator prev) - { - typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); - new ((void*)detail::get_pointer(d.get())) Node(); - NodePtr node = d.get(); - d.release(); - return iterator(this->icont().insert_after(prev.get(), *node)); - } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - void emplace_front(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - this->emplace \ - (this->cbegin(), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - } \ - \ - template \ - iterator emplace \ - (const_iterator p, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - return this->emplace_after \ - (this->previous(p), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - } \ - \ - template \ - iterator emplace_after \ - (const_iterator prev, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); \ - new ((void*)detail::get_pointer(d.get())) \ - Node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - NodePtr node = d.get(); \ - d.release(); \ - return iterator(this->icont().insert_after(prev.get(), *node)); \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element after the element pointed by prev_pos - //! of the list. - //! - //! Returns: the first element remaining beyond the removed elements, - //! or end() if no such element exists. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - //! - //! Note: Does not invalidate iterators or references to non erased elements. - iterator erase_after(const_iterator prev_pos) - { - return iterator(this->icont().erase_after_and_dispose(prev_pos.get(), Destroyer(this->node_alloc()))); - } - - //! Effects: Erases the range (before_first, last) from - //! the list. - //! - //! Returns: the first element remaining beyond the removed elements, - //! or end() if no such element exists. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of erased elements. - //! - //! Note: Does not invalidate iterators or references to non erased elements. - iterator erase_after(const_iterator before_first, const_iterator last) - { - return iterator(this->icont().erase_after_and_dispose(before_first.get(), last.get(), Destroyer(this->node_alloc()))); - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Erases the element at p p. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements before p. - iterator erase(const_iterator p) - { return iterator(this->erase_after(previous(p))); } - - //! Requires: first and last must be valid iterator to elements in *this. - //! - //! Effects: Erases the elements pointed by [first, last). - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the distance between first and last plus - //! linear to the elements before first. - iterator erase(const_iterator first, const_iterator last) - { return iterator(this->erase_after(previous(first), last)); } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size, const T& x) - { - typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next; - while (++(cur_next = cur) != end_n && new_size > 0){ - --new_size; - cur = cur_next; - } - if (cur_next != end_n) - this->erase_after(const_iterator(cur), const_iterator(end_n)); - else - this->insert_after(const_iterator(cur), new_size, x); - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size) - { - typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next; - size_type len = this->size(); - size_type left = new_size; - - while (++(cur_next = cur) != end_n && left > 0){ - --left; - cur = cur_next; - } - if (cur_next != end_n){ - this->erase_after(const_iterator(cur), const_iterator(end_n)); - } - else{ - this->priv_create_and_insert_nodes(const_iterator(cur), new_size - len); - } - } - - //! Effects: Erases all the elements of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements in the list. - void clear() - { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); } - - //! Requires: p must point to an element contained - //! by the list. x != *this - //! - //! Effects: Transfers all the elements of list x to this list, after the - //! the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear to the elements in x. - //! - //! Note: Iterators of values obtained from list x now point to elements of - //! this list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice_after(const_iterator prev_pos, detail::moved_object x) - { this->splice_after(prev_pos, x.get()); } - void splice_after(const_iterator prev_pos, slist& x) - #else - void splice_after(const_iterator prev_pos, slist&& x) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice_after(prev_pos.get(), x.icont()); - } - else{ - throw std::runtime_error("slist::splice called with unequal allocators"); - } - } - - //! Requires: prev_pos must be a valid iterator of this. - //! i must point to an element contained in list x. - //! - //! Effects: Transfers the value pointed by i, from list x to this list, - //! after the element pointed by prev_pos. - //! If prev_pos == prev or prev_pos == ++prev, this function is a null operation. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice_after(const_iterator prev_pos, detail::moved_object x, const_iterator prev) - { this->splice_after(prev_pos, x.get(), prev); } - void splice_after(const_iterator prev_pos, slist& x, const_iterator prev) - #else - void splice_after(const_iterator prev_pos, slist&& x, const_iterator prev) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice_after(prev_pos.get(), x.icont(), prev.get()); - } - else{ - throw std::runtime_error("slist::splice called with unequal allocators"); - } - } - - //! Requires: prev_pos must be a valid iterator of this. - //! before_first and before_last must be valid iterators of x. - //! prev_pos must not be contained in [before_first, before_last) range. - //! - //! Effects: Transfers the range [before_first + 1, before_last + 1) - //! from list x to this list, after the element pointed by prev_pos. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear to the number of transferred elements. - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice_after(const_iterator prev_pos, detail::moved_object x, - const_iterator before_first, const_iterator before_last) - { this->splice_after(prev_pos, x.get(), before_first, before_last); } - void splice_after(const_iterator prev_pos, slist& x, - const_iterator before_first, const_iterator before_last) - #else - void splice_after(const_iterator prev_pos, slist&& x, - const_iterator before_first, const_iterator before_last) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice_after - (prev_pos.get(), x.icont(), before_first.get(), before_last.get()); - } - else{ - throw std::runtime_error("slist::splice called with unequal allocators"); - } - } - - //! Requires: prev_pos must be a valid iterator of this. - //! before_first and before_last must be valid iterators of x. - //! prev_pos must not be contained in [before_first, before_last) range. - //! n == std::distance(before_first, before_last) - //! - //! Effects: Transfers the range [before_first + 1, before_last + 1) - //! from list x to this list, after the element pointed by prev_pos. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice_after(const_iterator prev_pos, detail::moved_object x, - const_iterator before_first, const_iterator before_last, - size_type n) - { this->splice_after(prev_pos, x.get(), before_first, before_last, n); } - void splice_after(const_iterator prev_pos, slist& x, - const_iterator before_first, const_iterator before_last, - size_type n) - #else - void splice_after(const_iterator prev_pos, slist&& x, - const_iterator before_first, const_iterator before_last, - size_type n) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice_after - (prev_pos.get(), x.icont(), before_first.get(), before_last.get(), n); - } - else{ - throw std::runtime_error("slist::splice called with unequal allocators"); - } - } - - //! Requires: p must point to an element contained - //! by the list. x != *this - //! - //! Effects: Transfers all the elements of list x to this list, before the - //! the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear in distance(begin(), p), and linear in x.size(). - //! - //! Note: Iterators of values obtained from list x now point to elements of - //! this list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object x) - { this->splice(p, x.get()); } - void splice(const_iterator p, ThisType& x) - #else - void splice(const_iterator p, ThisType&& x) - #endif - { this->splice_after(this->previous(p), x); } - - //! Requires: p must point to an element contained - //! by this list. i must point to an element contained in list x. - //! - //! Effects: Transfers the value pointed by i, from list x to this list, - //! before the the element pointed by p. No destructors or copy constructors are called. - //! If p == i or p == ++i, this function is a null operation. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear in distance(begin(), p), and in distance(x.begin(), i). - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object x, const_iterator i) - { this->splice(p, x.get(), i); } - void splice(const_iterator p, slist& x, const_iterator i) - #else - void splice(const_iterator p, slist&& x, const_iterator i) - #endif - { this->splice_after(previous(p), x, i); } - - //! Requires: p must point to an element contained - //! by this list. first and last must point to elements contained in list x. - //! - //! Effects: Transfers the range pointed by first and last from list x to this list, - //! before the the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear in distance(begin(), p), in distance(x.begin(), first), - //! and in distance(first, last). - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object x, const_iterator first, const_iterator last) - { this->splice(p, x.get(), first, last); } - void splice(const_iterator p, slist& x, const_iterator first, const_iterator last) - #else - void splice(const_iterator p, slist&& x, const_iterator first, const_iterator last) - #endif - { this->splice_after(previous(p), x, previous(first), previous(last)); } - - //! Effects: Reverses the order of elements in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time. - //! - //! Note: Iterators and references are not invalidated - void reverse() - { this->icont().reverse(); } - - //! Effects: Removes all the elements that compare equal to value. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear time. It performs exactly size() comparisons for equality. - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - void remove(const T& value) - { remove_if(equal_to_value(value)); } - - //! Effects: Removes all the elements for which a specified - //! predicate is satisfied. - //! - //! Throws: If pred throws. - //! - //! Complexity: Linear time. It performs exactly size() calls to the predicate. - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - template - void remove_if(Pred pred) - { - typedef ValueCompareToNodeCompare Predicate; - this->icont().remove_and_dispose_if(Predicate(pred), Destroyer(this->node_alloc())); - } - - //! Effects: Removes adjacent duplicate elements or adjacent - //! elements that are equal from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear time (size()-1 comparisons calls to pred()). - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - void unique() - { this->unique(value_equal()); } - - //! Effects: Removes adjacent duplicate elements or adjacent - //! elements that satisfy some binary predicate from the list. - //! - //! Throws: If pred throws. - //! - //! Complexity: Linear time (size()-1 comparisons equality comparisons). - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - template - void unique(Pred pred) - { - typedef ValueCompareToNodeCompare Predicate; - this->icont().unique_and_dispose(Predicate(pred), Destroyer(this->node_alloc())); - } - - //! Requires: The lists x and *this must be distinct. - //! - //! Effects: This function removes all of x's elements and inserts them - //! in order into *this according to std::less. The merge is stable; - //! that is, if an element from *this is equivalent to one from x, then the element - //! from *this will precede the one from x. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time: it performs at most - //! size() + x.size() - 1 comparisons. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void merge(detail::moved_object > x) - { this->merge(x.get()); } - void merge(slist& x) - #else - void merge(slist&& x) - #endif - { this->merge(x, value_less()); } - - //! Requires: p must be a comparison function that induces a strict weak - //! ordering and both *this and x must be sorted according to that ordering - //! The lists x and *this must be distinct. - //! - //! Effects: This function removes all of x's elements and inserts them - //! in order into *this. The merge is stable; that is, if an element from *this is - //! equivalent to one from x, then the element from *this will precede the one from x. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time: it performs at most - //! size() + x.size() - 1 comparisons. - //! - //! Note: Iterators and references to *this are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - template - void merge(detail::moved_object > x, StrictWeakOrdering comp) - { this->merge(x.get(), comp); } - template - void merge(slist& x, StrictWeakOrdering comp) - #else - template - void merge(slist&& x, StrictWeakOrdering comp) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().merge(x.icont(), - ValueCompareToNodeCompare(comp)); - } - else{ - throw std::runtime_error("list::merge called with unequal allocators"); - } - } - - //! Effects: This function sorts the list *this according to std::less. - //! The sort is stable, that is, the relative order of equivalent elements is preserved. - //! - //! Throws: Nothing. - //! - //! Notes: Iterators and references are not invalidated. - //! - //! Complexity: The number of comparisons is approximately N log N, where N - //! is the list's size. - void sort() - { this->sort(value_less()); } - - //! Effects: This function sorts the list *this according to std::less. - //! The sort is stable, that is, the relative order of equivalent elements is preserved. - //! - //! Throws: Nothing. - //! - //! Notes: Iterators and references are not invalidated. - //! - //! Complexity: The number of comparisons is approximately N log N, where N - //! is the list's size. - template - void sort(StrictWeakOrdering comp) - { - // nothing if the slist has length 0 or 1. - if (this->size() < 2) - return; - this->icont().sort(ValueCompareToNodeCompare(comp)); - } - - /// @cond - private: - - //Iterator range version - template - void priv_create_and_insert_nodes - (const_iterator prev, InpIterator beg, InpIterator end) - { - typedef typename std::iterator_traits::iterator_category ItCat; - priv_create_and_insert_nodes(prev, beg, end, alloc_version(), ItCat()); - } - - template - void priv_create_and_insert_nodes - (const_iterator prev, InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) - { - for (; beg != end; ++beg){ - this->icont().insert_after(prev.get(), *this->create_node_from_it(beg)); - ++prev; - } - } - - template - void priv_create_and_insert_nodes - (const_iterator prev, InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) - { //Just forward to the default one - priv_create_and_insert_nodes(prev, beg, end, allocator_v1(), std::input_iterator_tag()); - } - - class insertion_functor; - friend class insertion_functor; - - class insertion_functor - { - Icont &icont_; - typename Icont::const_iterator prev_; - - public: - insertion_functor(Icont &icont, typename Icont::const_iterator prev) - : icont_(icont), prev_(prev) - {} - - void operator()(Node &n) - { prev_ = this->icont_.insert_after(prev_, n); } - }; - - template - void priv_create_and_insert_nodes - (const_iterator prev, FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag) - { - //Optimized allocation and construction - this->allocate_many_and_construct - (beg, std::distance(beg, end), insertion_functor(this->icont(), prev.get())); - } - - //Default constructed version - void priv_create_and_insert_nodes(const_iterator prev, size_type n) - { - typedef default_construct_iterator default_iterator; - this->priv_create_and_insert_nodes(prev, default_iterator(n), default_iterator()); - } - - //Copy constructed version - void priv_create_and_insert_nodes(const_iterator prev, size_type n, const T& x) - { - typedef constant_iterator cvalue_iterator; - this->priv_create_and_insert_nodes(prev, cvalue_iterator(x, n), cvalue_iterator()); - } - - //Dispatch to detect iterator range or integer overloads - template - void priv_insert_dispatch(const_iterator prev, - InputIter first, InputIter last, - detail::false_) - { this->priv_create_and_insert_nodes(prev, first, last); } - - template - void priv_insert_dispatch(const_iterator prev, Integer n, Integer x, detail::true_) - { this->priv_create_and_insert_nodes(prev, n, x); } - - void priv_fill_assign(size_type n, const T& val) - { - iterator end_n(this->end()); - iterator prev(this->before_begin()); - iterator node(this->begin()); - for ( ; node != end_n && n > 0 ; --n){ - *node = val; - prev = node; - ++node; - } - if (n > 0) - this->priv_create_and_insert_nodes(prev, n, val); - else - this->erase_after(prev, end_n); - } - - template - void priv_assign_dispatch(Int n, Int val, detail::true_) - { this->priv_fill_assign((size_type) n, (T)val); } - - template - void priv_assign_dispatch(InpIt first, InpIt last, detail::false_) - { - iterator end_n(this->end()); - iterator prev(this->before_begin()); - iterator node(this->begin()); - while (node != end_n && first != last){ - *node = *first; - prev = node; - ++node; - ++first; - } - if (first != last) - this->priv_create_and_insert_nodes(prev, first, last); - else - this->erase_after(prev, end_n); - } - - template - void priv_insert_after_range_dispatch(const_iterator prev_pos, Int n, Int x, detail::true_) - { this->priv_create_and_insert_nodes(prev_pos, n, x); } - - template - void priv_insert_after_range_dispatch(const_iterator prev_pos, InIter first, InIter last, detail::false_) - { this->priv_create_and_insert_nodes(prev_pos, first, last); } - - //Functors for member algorithm defaults - struct value_less - { - bool operator()(const value_type &a, const value_type &b) const - { return a < b; } - }; - - struct value_equal - { - bool operator()(const value_type &a, const value_type &b) const - { return a == b; } - }; - - struct value_equal_to_this - { - explicit value_equal_to_this(const value_type &ref) - : m_ref(ref){} - - bool operator()(const value_type &val) const - { return m_ref == val; } - - const value_type &m_ref; - }; - /// @endcond -}; - -template -inline bool -operator==(const slist& x, const slist& y) -{ - if(x.size() != y.size()){ - return false; - } - typedef typename slist::const_iterator const_iterator; - const_iterator end1 = x.end(); - - const_iterator i1 = x.begin(); - const_iterator i2 = y.begin(); - while (i1 != end1 && *i1 == *i2){ - ++i1; - ++i2; - } - return i1 == end1; -} - -template -inline bool -operator<(const slist& sL1, const slist& sL2) -{ - return std::lexicographical_compare - (sL1.begin(), sL1.end(), sL2.begin(), sL2.end()); -} - -template -inline bool -operator!=(const slist& sL1, const slist& sL2) - { return !(sL1 == sL2); } - -template -inline bool -operator>(const slist& sL1, const slist& sL2) - { return sL2 < sL1; } - -template -inline bool -operator<=(const slist& sL1, const slist& sL2) - { return !(sL2 < sL1); } - -template -inline bool -operator>=(const slist& sL1, const slist& sL2) - { return !(sL1 < sL2); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(slist& x, slist& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, slist& y) - { x.get().swap(y); } - -template -inline void swap(slist& x, detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(slist&&x, slist&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -/* -template -struct is_movable > -{ - enum { value = true }; -}; -*/ -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost{ namespace interprocess{ - -// Specialization of insert_iterator so that insertions will be constant -// time rather than linear time. - -///@cond - -//Ummm, I don't like to define things in namespace std, but -//there is no other way -namespace std { - -template -class insert_iterator > -{ - protected: - typedef boost::interprocess::slist Container; - Container* container; - typename Container::iterator iter; - public: - typedef Container container_type; - typedef output_iterator_tag iterator_category; - typedef void value_type; - typedef void difference_type; - typedef void pointer; - typedef void reference; - - insert_iterator(Container& x, - typename Container::iterator i, - bool is_previous = false) - : container(&x), iter(is_previous ? i : x.previous(i)){ } - - insert_iterator& - operator=(const typename Container::value_type& value) - { - iter = container->insert_after(iter, value); - return *this; - } - insert_iterator& operator*(){ return *this; } - insert_iterator& operator++(){ return *this; } - insert_iterator& operator++(int){ return *this; } -}; - -} //namespace std; - -///@endcond +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_SLIST_HPP */ +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP diff --git a/include/boost/interprocess/containers/stable_vector.hpp b/include/boost/interprocess/containers/stable_vector.hpp new file mode 100644 index 0000000..d6c47a1 --- /dev/null +++ b/include/boost/interprocess/containers/stable_vector.hpp @@ -0,0 +1,31 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_STABLE_VECTOR_HPP +#define BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { + namespace interprocess { + + using boost::interprocess_container::stable_vector; + + } //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP diff --git a/include/boost/interprocess/containers/string.hpp b/include/boost/interprocess/containers/string.hpp index 4410423..ceacbce 100644 --- a/include/boost/interprocess/containers/string.hpp +++ b/include/boost/interprocess/containers/string.hpp @@ -1,2491 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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. // ////////////////////////////////////////////////////////////////////////////// -// -// This file comes from SGI's string file. Modified by Ion Gaztanaga 2004-2008 -// Renaming, isolating and porting to generic algorithms. Pointer typedef -// set to allocator::pointer to allow placing it in shared memory. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 1994 -// Hewlett-Packard Company -// -// Permission to use, copy, modify, distribute and sell this software -// and its documentation for any purpose is hereby granted without fee, -// provided that the above copyright notice appear in all copies and -// that both that copyright notice and this permission notice appear -// in supporting documentation. Hewlett-Packard Company makes no -// representations about the suitability of this software for any -// purpose. It is provided "as is" without express or implied warranty. -#ifndef BOOST_INTERPROCESS_STRING_HPP -#define BOOST_INTERPROCESS_STRING_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_STRING_HPP +#define BOOST_INTERPROCESS_CONTAINERS_STRING_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace interprocess { -namespace detail { -/// @cond -// ------------------------------------------------------------ -// Class basic_string_base. +using boost::interprocess_container::basic_string; +using boost::interprocess_container::string; -// basic_string_base is a helper class that makes it it easier to write -// an exception-safe version of basic_string. The constructor allocates, -// but does not initialize, a block of memory. The destructor -// deallocates, but does not destroy elements within, a block of -// memory. The destructor assumes that the memory either is the internal buffer, -// or else points to a block of memory that was allocated using _String_base's -// allocator and whose size is this->m_storage. -template -class basic_string_base -{ - basic_string_base(); - public: - typedef A allocator_type; - //! The stored allocator type - typedef allocator_type stored_allocator_type; - typedef typename A::pointer pointer; - typedef typename A::value_type value_type; - typedef typename A::size_type size_type; - - basic_string_base(const allocator_type& a) - : members_(a) - { init(); } - - basic_string_base(const allocator_type& a, std::size_t n) - : members_(a) - { - this->init(); - this->allocate_initial_block(n); - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) - basic_string_base(detail::moved_object > b) - : members_(b.get().members_) - { - init(); - this->swap(b.get()); - } - #else - basic_string_base(basic_string_base && b) - : members_(b.members_) - { - init(); - this->swap(b); - } - #endif - - ~basic_string_base() - { - this->deallocate_block(); - if(!this->is_short()){ - static_cast(static_cast(&this->members_.m_repr.r))->~long_t(); - } - } - - private: - - //This is the structure controlling a long string - struct long_t - { - size_type is_short : 1; - size_type length : (sizeof(size_type)*CHAR_BIT - 1); - size_type storage; - pointer start; - - long_t() - {} - - long_t(const long_t &other) - { - this->is_short = other.is_short; - length = other.length; - storage = other.storage; - start = other.start; - } - - long_t &operator =(const long_t &other) - { - this->is_short = other.is_short; - length = other.length; - storage = other.storage; - start = other.start; - return *this; - } - }; - - //This basic type should have the same alignment as long_t -//iG typedef typename type_with_alignment::value>::type -// long_alignment_type; - typedef void *long_alignment_type; - BOOST_STATIC_ASSERT((detail::alignment_of::value % - detail::alignment_of::value) == 0); - - - //This type is the first part of the structure controlling a short string - //The "data" member stores - struct short_header - { - unsigned char is_short : 1; - unsigned char length : (CHAR_BIT - 1); - }; - - //This type has the same alignment and size as long_t but it's POD - //so, unlike long_t, it can be placed in a union - struct long_raw_t - { - long_alignment_type a; - unsigned char b[sizeof(long_t) - sizeof(long_alignment_type)]; - }; - - protected: - static const size_type MinInternalBufferChars = 8; - static const size_type AlignmentOfValueType = - alignment_of::value; - static const size_type ShortDataOffset = - detail::ct_rounded_size::value; - static const size_type ZeroCostInternalBufferChars = - (sizeof(long_t) - ShortDataOffset)/sizeof(value_type); - static const size_type UnalignedFinalInternalBufferChars = - (ZeroCostInternalBufferChars > MinInternalBufferChars) ? - ZeroCostInternalBufferChars : MinInternalBufferChars; - - struct short_t - { - short_header h; - value_type data[UnalignedFinalInternalBufferChars]; - }; - - union repr_t - { - long_raw_t r; - short_t s; - - short_t &short_repr() const - { return *const_cast(&s); } - - long_t &long_repr() const - { return *static_cast(const_cast(static_cast(&r))); } - }; - - struct members_holder - : public A - { - members_holder(const A &a) - : A(a) - {} - - repr_t m_repr; - } members_; - - const A &alloc() const - { return members_; } - - A &alloc() - { return members_; } - - static const size_type InternalBufferChars = (sizeof(repr_t) - ShortDataOffset)/sizeof(value_type); - - private: - - static const size_type MinAllocation = InternalBufferChars*2; - - protected: - bool is_short() const - { return static_cast(this->members_.m_repr.s.h.is_short != 0); } - - void is_short(bool yes) - { - if(yes && !this->is_short()){ - static_cast(static_cast(&this->members_.m_repr.r))->~long_t(); - } - else{ - new(static_cast(&this->members_.m_repr.r))long_t(); - } - this->members_.m_repr.s.h.is_short = yes; - } - - private: - void init() - { - this->members_.m_repr.s.h.is_short = 1; - this->members_.m_repr.s.h.length = 0; - } - - protected: - - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant allocator_v2; - typedef detail::integral_constant::value> alloc_version; - - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, pointer reuse = 0) - { - if(this->is_short() && (command & (expand_fwd | expand_bwd)) ){ - reuse = pointer(0); - command &= ~(expand_fwd | expand_bwd); - } - return this->allocation_command - (command, limit_size, preferred_size, received_size, reuse, alloc_version()); - } - - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, - const pointer &reuse, - allocator_v1) - { - (void)limit_size; - (void)reuse; - if(!(command & allocate_new)) - return std::pair(pointer(0), 0); - received_size = preferred_size; - return std::make_pair(this->alloc().allocate(received_size), false); - } - - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, - pointer reuse, - allocator_v2) - { - return this->alloc().allocation_command(command, limit_size, preferred_size, - received_size, reuse); - } - - size_type next_capacity(size_type additional_objects) const - { return get_next_capacity(this->alloc().max_size(), this->priv_storage(), additional_objects); } - - void deallocate(pointer p, std::size_t n) - { - if (p && (n > InternalBufferChars)) - this->alloc().deallocate(p, n); - } - - void construct(pointer p, const value_type &value = value_type()) - { new((void*)detail::get_pointer(p)) value_type(value); } - - void destroy(pointer p, size_type n) - { - for(; n--; ++p) - detail::get_pointer(p)->~value_type(); - } - - void destroy(pointer p) - { detail::get_pointer(p)->~value_type(); } - - void allocate_initial_block(std::size_t n) - { - if (n <= this->max_size()) { - if(n > InternalBufferChars){ - size_type new_cap = this->next_capacity(n); - pointer p = this->allocation_command(allocate_new, n, new_cap, new_cap).first; - this->is_short(false); - this->priv_addr(p); - this->priv_size(0); - this->priv_storage(new_cap); - } - } - else - throw_length_error(); - } - - void deallocate_block() - { this->deallocate(this->priv_addr(), this->priv_storage()); } - - std::size_t max_size() const - { return this->alloc().max_size() - 1; } - - // Helper functions for exception handling. - void throw_length_error() const - { throw(std::length_error("basic_string")); } - - void throw_out_of_range() const - { throw(std::out_of_range("basic_string")); } - - protected: - size_type priv_capacity() const - { return this->priv_storage() - 1; } - - pointer priv_addr() const - { return this->is_short() ? pointer(&this->members_.m_repr.short_repr().data[0]) : this->members_.m_repr.long_repr().start; } - - void priv_addr(pointer addr) - { this->members_.m_repr.long_repr().start = addr; } - - size_type priv_storage() const - { return this->is_short() ? InternalBufferChars : this->members_.m_repr.long_repr().storage; } - - void priv_storage(size_type storage) - { - if(!this->is_short()) - this->members_.m_repr.long_repr().storage = storage; - } - - size_type priv_size() const - { return this->is_short() ? this->members_.m_repr.short_repr().h.length : this->members_.m_repr.long_repr().length; } - - void priv_size(size_type sz) - { - if(this->is_short()) - this->members_.m_repr.s.h.length = (unsigned char)sz; - else - this->members_.m_repr.long_repr().length = static_cast(sz); - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(basic_string_base& other) - #else - void swap(basic_string_base &&other) - #endif - { - if(this->is_short()){ - if(other.is_short()){ - std::swap(this->members_.m_repr, other.members_.m_repr); - } - else{ - repr_t copied(this->members_.m_repr); - this->members_.m_repr.long_repr() = other.members_.m_repr.long_repr(); - other.members_.m_repr = copied; - } - } - else{ - if(other.is_short()){ - repr_t copied(other.members_.m_repr); - other.members_.m_repr.long_repr() = this->members_.m_repr.long_repr(); - this->members_.m_repr = copied; - } - else{ - std::swap(this->members_.m_repr.long_repr(), other.members_.m_repr.long_repr()); - } - } - - allocator_type & this_al = this->alloc(), &other_al = other.alloc(); - if(this_al != other_al){ - detail::do_swap(this_al, other_al); - } - } -}; -/// @endcond - -} //namespace detail { - - -//! The basic_string class represents a Sequence of characters. It contains all the -//! usual operations of a Sequence, and, additionally, it contains standard string -//! operations such as search and concatenation. -//! -//! The basic_string class is parameterized by character type, and by that type's -//! Character Traits. -//! -//! This class has performance characteristics very much like vector<>, meaning, -//! for example, that it does not perform reference-count or copy-on-write, and that -//! concatenation of two strings is an O(N) operation. -//! -//! Some of basic_string's member functions use an unusual method of specifying positions -//! and ranges. In addition to the conventional method using iterators, many of -//! basic_string's member functions use a single value pos of type size_type to represent a -//! position (in which case the position is begin() + pos, and many of basic_string's -//! member functions use two values, pos and n, to represent a range. In that case pos is -//! the beginning of the range and n is its size. That is, the range is -//! [begin() + pos, begin() + pos + n). -//! -//! Note that the C++ standard does not specify the complexity of basic_string operations. -//! In this implementation, basic_string has performance characteristics very similar to -//! those of vector: access to a single character is O(1), while copy and concatenation -//! are O(N). -//! -//! In this implementation, begin(), -//! end(), rbegin(), rend(), operator[], c_str(), and data() do not invalidate iterators. -//! In this implementation, iterators are only invalidated by member functions that -//! explicitly change the string's contents. -template -class basic_string - : private detail::basic_string_base -{ - /// @cond - private: - typedef detail::basic_string_base base_t; - static const typename base_t::size_type InternalBufferChars = base_t::InternalBufferChars; - - protected: - // A helper class to use a char_traits as a function object. - - template - struct Eq_traits - : public std::binary_function - { - bool operator()(const typename Tr::char_type& x, - const typename Tr::char_type& y) const - { return Tr::eq(x, y); } - }; - - template - struct Not_within_traits - : public std::unary_function - { - typedef const typename Tr::char_type* Pointer; - const Pointer m_first; - const Pointer m_last; - - Not_within_traits(Pointer f, Pointer l) - : m_first(f), m_last(l) {} - - bool operator()(const typename Tr::char_type& x) const - { - return std::find_if(m_first, m_last, - std::bind1st(Eq_traits(), x)) == m_last; - } - }; - /// @endcond - - public: - //! The allocator type - typedef A allocator_type; - //! The stored allocator type - typedef allocator_type stored_allocator_type; - //! The type of object, CharT, stored in the string - typedef CharT value_type; - //! The second template parameter Traits - typedef Traits traits_type; - //! Pointer to CharT - typedef typename A::pointer pointer; - //! Const pointer to CharT - typedef typename A::const_pointer const_pointer; - //! Reference to CharT - typedef typename A::reference reference; - //! Const reference to CharT - typedef typename A::const_reference const_reference; - //! An unsigned integral type - typedef typename A::size_type size_type; - //! A signed integral type - typedef typename A::difference_type difference_type; - //! Iterator used to iterate through a string. It's a Random Access Iterator - typedef pointer iterator; - //! Const iterator used to iterate through a string. It's a Random Access Iterator - typedef const_pointer const_iterator; - //! Iterator used to iterate backwards through a string - typedef std::reverse_iterator reverse_iterator; - //! Const iterator used to iterate backwards through a string - typedef std::reverse_iterator const_reverse_iterator; - //! The largest possible value of type size_type. That is, size_type(-1). - static const size_type npos; - - /// @cond - private: - typedef constant_iterator cvalue_iterator; - /// @endcond - - public: // Constructor, destructor, assignment. - /// @cond - struct reserve_t {}; - /// @endcond - - basic_string(reserve_t, std::size_t n, - const allocator_type& a = allocator_type()) - : base_t(a, n + 1) - { this->priv_terminate_string(); } - - //! Effects: Constructs a basic_string taking the allocator as parameter. - //! - //! Throws: If allocator_type's copy constructor throws. - explicit basic_string(const allocator_type& a = allocator_type()) - : base_t(a, InternalBufferChars) - { this->priv_terminate_string(); } - - //! Effects: Copy constructs a basic_string. - //! - //! Postcondition: x == *this. - //! - //! Throws: If allocator_type's default constructor or copy constructor throws. - basic_string(const basic_string& s) - : base_t(s.alloc()) - { this->priv_range_initialize(s.begin(), s.end()); } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string(detail::moved_object s) - : base_t(detail::move_impl((base_t&)s.get())) - {} - #else - basic_string(basic_string && s) - : base_t(detail::move_impl((base_t&)s)) - {} - #endif - - //! Effects: Constructs a basic_string taking the allocator as parameter, - //! and is initialized by a specific number of characters of the s string. - basic_string(const basic_string& s, size_type pos, size_type n = npos, - const allocator_type& a = allocator_type()) - : base_t(a) - { - if (pos > s.size()) - this->throw_out_of_range(); - else - this->priv_range_initialize - (s.begin() + pos, s.begin() + pos + min_value(n, s.size() - pos)); - } - - //! Effects: Constructs a basic_string taking the allocator as parameter, - //! and is initialized by a specific number of characters of the s c-string. - basic_string(const CharT* s, size_type n, - const allocator_type& a = allocator_type()) - : base_t(a) - { this->priv_range_initialize(s, s + n); } - - //! Effects: Constructs a basic_string taking the allocator as parameter, - //! and is initialized by the null-terminated s c-string. - basic_string(const CharT* s, - const allocator_type& a = allocator_type()) - : base_t(a) - { this->priv_range_initialize(s, s + Traits::length(s)); } - - //! Effects: Constructs a basic_string taking the allocator as parameter, - //! and is initialized by n copies of c. - basic_string(size_type n, CharT c, - const allocator_type& a = allocator_type()) - : base_t(a) - { - this->priv_range_initialize(cvalue_iterator(c, n), - cvalue_iterator()); - } - - //! Effects: Constructs a basic_string taking the allocator as parameter, - //! and a range of iterators. - template - basic_string(InputIterator f, InputIterator l, - const allocator_type& a = allocator_type()) - : base_t(a) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_initialize_dispatch(f, l, Result()); - } - - //! Effects: Destroys the basic_string. All used memory is deallocated. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - ~basic_string() - {} - - //! Effects: Copy constructs a string. - //! - //! Postcondition: x == *this. - //! - //! Complexity: Linear to the elements x contains. - basic_string& operator=(const basic_string& s) - { - if (&s != this) - this->assign(s.begin(), s.end()); - return *this; - } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string& operator=(detail::moved_object ms) - { - basic_string &s = ms.get(); - if (&s != this){ - this->swap(s); - } - return *this; - } - #else - basic_string& operator=(basic_string && ms) - { - basic_string &s = ms; - if (&s != this){ - this->swap(s); - } - return *this; - } - #endif - - //! Effects: Assignment from a null-terminated c-string. - basic_string& operator=(const CharT* s) - { return this->assign(s, s + Traits::length(s)); } - - //! Effects: Assignment from character. - basic_string& operator=(CharT c) - { return this->assign(static_cast(1), c); } - - //! Effects: Returns an iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return this->priv_addr(); } - - //! Effects: Returns a const_iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return this->priv_addr(); } - - //! Effects: Returns an iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return this->priv_addr() + this->priv_size(); } - - //! Effects: Returns a const_iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return this->priv_addr() + this->priv_size(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return reverse_iterator(this->priv_addr() + this->priv_size()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return const_reverse_iterator(this->priv_addr() + this->priv_size()); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return reverse_iterator(this->priv_addr()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return const_reverse_iterator(this->priv_addr()); } - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return this->alloc(); } - - //! Effects: Returns the number of the elements contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return this->priv_size(); } - - //! Effects: Returns the number of the elements contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type length() const - { return this->size(); } - - //! Effects: Returns the largest possible size of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return base_t::max_size(); } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type n, CharT c) - { - if (n <= size()) - this->erase(this->begin() + n, this->end()); - else - this->append(n - this->size(), c); - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type n) - { resize(n, this->priv_null()); } - - //! Effects: If n is less than or equal to capacity(), this call has no - //! effect. Otherwise, it is a request for allocation of additional memory. - //! If the request is successful, then capacity() is greater than or equal to - //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - void reserve(size_type res_arg) - { - if (res_arg > this->max_size()) - this->throw_length_error(); - - if (this->capacity() < res_arg){ - size_type n = max_value(res_arg, this->size()) + 1; - size_type new_cap = this->next_capacity(n); - pointer new_start = this->allocation_command - (allocate_new, n, new_cap, new_cap).first; - size_type new_length = 0; - - new_length += priv_uninitialized_copy - (this->priv_addr(), this->priv_addr() + this->priv_size(), new_start); - this->priv_construct_null(new_start + new_length); - this->deallocate_block(); - this->is_short(false); - this->priv_addr(new_start); - this->priv_size(new_length); - this->priv_storage(new_cap); - } - } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return this->priv_capacity(); } - - //! Effects: Erases all the elements of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements in the vector. - void clear() - { - if (!empty()) { - Traits::assign(*this->priv_addr(), this->priv_null()); - this->priv_size(0); - } - } - - //! Effects: Returns true if the vector contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return !this->priv_size(); } - - //! Requires: size() < n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference operator[](size_type n) - { return *(this->priv_addr() + n); } - - //! Requires: size() < n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference operator[](size_type n) const - { return *(this->priv_addr() + n); } - - //! Requires: size() < n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - reference at(size_type n) { - if (n >= size()) - this->throw_out_of_range(); - return *(this->priv_addr() + n); - } - - //! Requires: size() < n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - const_reference at(size_type n) const { - if (n >= size()) - this->throw_out_of_range(); - return *(this->priv_addr() + n); - } - - //! Effects: Appends string s to *this. - basic_string& operator+=(const basic_string& s) - { return this->append(s); } - - //! Effects: Appends c-string s to *this. - basic_string& operator+=(const CharT* s) - { return this->append(s); } - - //! Effects: Appends character c to *this. - basic_string& operator+=(CharT c) - { this->push_back(c); return *this; } - - //! Effects: Appends string s to *this. - basic_string& append(const basic_string& s) - { return this->append(s.begin(), s.end()); } - - //! Effects: Appends the range [pos, pos + n) from string s to *this. - basic_string& append(const basic_string& s, size_type pos, size_type n) - { - if (pos > s.size()) - this->throw_out_of_range(); - return this->append(s.begin() + pos, - s.begin() + pos + min_value(n, s.size() - pos)); - } - - //! Effects: Appends the range [s, s + n) from c-string s to *this. - basic_string& append(const CharT* s, size_type n) - { return this->append(s, s + n); } - - //! Effects: Appends the c-string s to *this. - basic_string& append(const CharT* s) - { return this->append(s, s + Traits::length(s)); } - - //! Effects: Appends the n times the character c to *this. - basic_string& append(size_type n, CharT c) - { return this->append(cvalue_iterator(c, n), cvalue_iterator()); } - - //! Effects: Appends the range [first, last) *this. - template - basic_string& append(InputIter first, InputIter last) - { this->insert(this->end(), first, last); return *this; } - - //! Effects: Inserts a copy of c at the end of the vector. - void push_back(CharT c) - { - if (this->priv_size() < this->capacity()){ - this->priv_construct_null(this->priv_addr() + (this->priv_size() + 1)); - Traits::assign(this->priv_addr()[this->priv_size()], c); - this->priv_size(this->priv_size()+1); - } - else{ - //No enough memory, insert a new object at the end - this->append((size_type)1, c); - } - } - - //! Effects: Removes the last element from the vector. - void pop_back() - { - Traits::assign(this->priv_addr()[this->priv_size()-1], this->priv_null()); - this->priv_size(this->priv_size()-1);; - } - - //! Effects: Assigns the value s to *this. - basic_string& assign(const basic_string& s) - { return this->operator=(s); } - - //! Effects: Moves the resources from ms *this. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string& assign(detail::moved_object ms) - { return this->operator=(ms);} - #else - basic_string& assign(basic_string && ms) - { return this->operator=(ms);} - #endif - - //! Effects: Assigns the range [pos, pos + n) from s to *this. - basic_string& assign(const basic_string& s, - size_type pos, size_type n) { - if (pos > s.size()) - this->throw_out_of_range(); - return this->assign(s.begin() + pos, - s.begin() + pos + min_value(n, s.size() - pos)); - } - - //! Effects: Assigns the range [s, s + n) from s to *this. - basic_string& assign(const CharT* s, size_type n) - { return this->assign(s, s + n); } - - //! Effects: Assigns the c-string s to *this. - basic_string& assign(const CharT* s) - { return this->assign(s, s + Traits::length(s)); } - - //! Effects: Assigns the character c n-times to *this. - basic_string& assign(size_type n, CharT c) - { return this->assign(cvalue_iterator(c, n), cvalue_iterator()); } - - //! Effects: Assigns the range [first, last) to *this. - template - basic_string& assign(InputIter first, InputIter last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - return this->priv_assign_dispatch(first, last, Result()); - } - - //! Effects: Assigns the range [f, l) to *this. - basic_string& assign(const CharT* f, const CharT* l) - { - const std::ptrdiff_t n = l - f; - if (static_cast(n) <= size()) { - Traits::copy(detail::get_pointer(this->priv_addr()), f, n); - this->erase(this->priv_addr() + n, this->priv_addr() + this->priv_size()); - } - else { - Traits::copy(detail::get_pointer(this->priv_addr()), f, this->priv_size()); - this->append(f + this->priv_size(), l); - } - return *this; - } - - //! Effects: Inserts the string s before pos. - basic_string& insert(size_type pos, const basic_string& s) - { - if (pos > size()) - this->throw_out_of_range(); - if (this->size() > this->max_size() - s.size()) - this->throw_length_error(); - this->insert(this->priv_addr() + pos, s.begin(), s.end()); - return *this; - } - - //! Effects: Inserts the range [pos, pos + n) from string s before pos. - basic_string& insert(size_type pos, const basic_string& s, - size_type beg, size_type n) - { - if (pos > this->size() || beg > s.size()) - this->throw_out_of_range(); - size_type len = min_value(n, s.size() - beg); - if (this->size() > this->max_size() - len) - this->throw_length_error(); - const CharT *beg_ptr = detail::get_pointer(s.begin()) + beg; - const CharT *end_ptr = beg_ptr + len; - this->insert(this->priv_addr() + pos, beg_ptr, end_ptr); - return *this; - } - - //! Effects: Inserts the range [s, s + n) before pos. - basic_string& insert(size_type pos, const CharT* s, size_type n) - { - if (pos > this->size()) - this->throw_out_of_range(); - if (this->size() > this->max_size() - n) - this->throw_length_error(); - this->insert(this->priv_addr() + pos, s, s + n); - return *this; - } - - //! Effects: Inserts the c-string s before pos. - basic_string& insert(size_type pos, const CharT* s) - { - if (pos > size()) - this->throw_out_of_range(); - size_type len = Traits::length(s); - if (this->size() > this->max_size() - len) - this->throw_length_error(); - this->insert(this->priv_addr() + pos, s, s + len); - return *this; - } - - //! Effects: Inserts the character c n-times before pos. - basic_string& insert(size_type pos, size_type n, CharT c) - { - if (pos > this->size()) - this->throw_out_of_range(); - if (this->size() > this->max_size() - n) - this->throw_length_error(); - this->insert(this->priv_addr() + pos, n, c); - return *this; - } - - //! Effects: Inserts the character c before position. - iterator insert(iterator position, CharT c) - { - size_type new_offset = position - this->priv_addr() + 1; - this->insert(position, cvalue_iterator(c, 1), - cvalue_iterator()); - return this->priv_addr() + new_offset; - } - - //! Effects: Inserts the character c n-times before position. - void insert(iterator position, std::size_t n, CharT c) - { - this->insert(position, cvalue_iterator(c, n), - cvalue_iterator()); - } - - //! Effects: Inserts the range [first, last) before position. - template - void insert(iterator p, InputIter first, InputIter last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_dispatch(p, first, last, Result()); - } - - //! Effects: Inserts the range [pos, pos + n). - basic_string& erase(size_type pos = 0, size_type n = npos) - { - if (pos > size()) - this->throw_out_of_range(); - erase(this->priv_addr() + pos, this->priv_addr() + pos + min_value(n, size() - pos)); - return *this; - } - - //! Effects: Erases the character pointed by position. - iterator erase(iterator position) - { - // The move includes the terminating null. - Traits::move(detail::get_pointer(position), - detail::get_pointer(position + 1), - this->priv_size() - (position - this->priv_addr())); - this->priv_size(this->priv_size()-1); - return position; - } - - //! Effects: Erases the range [first, last). - iterator erase(iterator first, iterator last) - { - if (first != last) { // The move includes the terminating null. - size_type num_erased = last - first; - Traits::move(detail::get_pointer(first), - detail::get_pointer(last), - (this->priv_size() + 1)-(last - this->priv_addr())); - size_type new_length = this->priv_size() - num_erased; - this->priv_size(new_length); - } - return first; - } - - //! Effects: Replaces a substring of *this with the string s. - basic_string& replace(size_type pos, size_type n, - const basic_string& s) - { - if (pos > size()) - this->throw_out_of_range(); - const size_type len = min_value(n, size() - pos); - if (this->size() - len >= this->max_size() - s.size()) - this->throw_length_error(); - return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, - s.begin(), s.end()); - } - - //! Effects: Replaces a substring of *this with a substring of s. - basic_string& replace(size_type pos1, size_type n1, - const basic_string& s, - size_type pos2, size_type n2) - { - if (pos1 > size() || pos2 > s.size()) - this->throw_out_of_range(); - const size_type len1 = min_value(n1, size() - pos1); - const size_type len2 = min_value(n2, s.size() - pos2); - if (this->size() - len1 >= this->max_size() - len2) - this->throw_length_error(); - return this->replace(this->priv_addr() + pos1, this->priv_addr() + pos1 + len1, - s.priv_addr() + pos2, s.priv_addr() + pos2 + len2); - } - - //! Effects: Replaces a substring of *this with the first n1 characters of s. - basic_string& replace(size_type pos, size_type n1, - const CharT* s, size_type n2) - { - if (pos > size()) - this->throw_out_of_range(); - const size_type len = min_value(n1, size() - pos); - if (n2 > this->max_size() || size() - len >= this->max_size() - n2) - this->throw_length_error(); - return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, - s, s + n2); - } - - //! Effects: Replaces a substring of *this with a null-terminated character array. - basic_string& replace(size_type pos, size_type n1, - const CharT* s) - { - if (pos > size()) - this->throw_out_of_range(); - const size_type len = min_value(n1, size() - pos); - const size_type n2 = Traits::length(s); - if (n2 > this->max_size() || size() - len >= this->max_size() - n2) - this->throw_length_error(); - return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, - s, s + Traits::length(s)); - } - - //! Effects: Replaces a substring of *this with n1 copies of c. - basic_string& replace(size_type pos, size_type n1, - size_type n2, CharT c) - { - if (pos > size()) - this->throw_out_of_range(); - const size_type len = min_value(n1, size() - pos); - if (n2 > this->max_size() || size() - len >= this->max_size() - n2) - this->throw_length_error(); - return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, n2, c); - } - - //! Effects: Replaces a substring of *this with the string s. - basic_string& replace(iterator first, iterator last, - const basic_string& s) - { return this->replace(first, last, s.begin(), s.end()); } - - //! Effects: Replaces a substring of *this with the first n characters of s. - basic_string& replace(iterator first, iterator last, - const CharT* s, size_type n) - { return this->replace(first, last, s, s + n); } - - //! Effects: Replaces a substring of *this with a null-terminated character array. - basic_string& replace(iterator first, iterator last, - const CharT* s) - { return this->replace(first, last, s, s + Traits::length(s)); } - - //! Effects: Replaces a substring of *this with n copies of c. - basic_string& replace(iterator first, iterator last, - size_type n, CharT c) - { - const size_type len = static_cast(last - first); - if (len >= n) { - Traits::assign(detail::get_pointer(first), n, c); - erase(first + n, last); - } - else { - Traits::assign(detail::get_pointer(first), len, c); - insert(last, n - len, c); - } - return *this; - } - - //! Effects: Replaces a substring of *this with the range [f, l) - template - basic_string& replace(iterator first, iterator last, - InputIter f, InputIter l) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - return this->priv_replace_dispatch(first, last, f, l, Result()); - } - - //! Effects: Copies a substring of *this to a buffer. - size_type copy(CharT* s, size_type n, size_type pos = 0) const - { - if (pos > size()) - this->throw_out_of_range(); - const size_type len = min_value(n, size() - pos); - Traits::copy(s, detail::get_pointer(this->priv_addr() + pos), len); - return len; - } - - //! Effects: Swaps the contents of two strings. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(basic_string& x) - #else - void swap(basic_string &&x) - #endif - { base_t::swap(x); } - - //! Returns: Returns a pointer to a null-terminated array of characters - //! representing the string's contents. For any string s it is guaranteed - //! that the first s.size() characters in the array pointed to by s.c_str() - //! are equal to the character in s, and that s.c_str()[s.size()] is a null - //! character. Note, however, that it not necessarily the first null character. - //! Characters within a string are permitted to be null. - const CharT* c_str() const - { return detail::get_pointer(this->priv_addr()); } - - //! Returns: Returns a pointer to an array of characters, not necessarily - //! null-terminated, representing the string's contents. data() is permitted, - //! but not required, to be identical to c_str(). The first size() characters - //! of that array are guaranteed to be identical to the characters in *this. - //! The return value of data() is never a null pointer, even if size() is zero. - const CharT* data() const - { return detail::get_pointer(this->priv_addr()); } - - //! Effects: Searches for s as a substring of *this, beginning at - //! character pos of *this. - size_type find(const basic_string& s, size_type pos = 0) const - { return find(s.c_str(), pos, s.size()); } - - //! Effects: Searches for a null-terminated character array as a - //! substring of *this, beginning at character pos of *this. - size_type find(const CharT* s, size_type pos = 0) const - { return find(s, pos, Traits::length(s)); } - - //! Effects: Searches for the first n characters of s as a substring - //! of *this, beginning at character pos of *this. - size_type find(const CharT* s, size_type pos, size_type n) const - { - if (pos + n > size()) - return npos; - else { - pointer finish = this->priv_addr() + this->priv_size(); - const const_iterator result = - std::search(detail::get_pointer(this->priv_addr() + pos), - detail::get_pointer(finish), - s, s + n, Eq_traits()); - return result != finish ? result - begin() : npos; - } - } - - //! Effects: Searches for the character c, beginning at character - //! position pos. - size_type find(CharT c, size_type pos = 0) const - { - if (pos >= size()) - return npos; - else { - pointer finish = this->priv_addr() + this->priv_size(); - const const_iterator result = - std::find_if(this->priv_addr() + pos, finish, - std::bind2nd(Eq_traits(), c)); - return result != finish ? result - begin() : npos; - } - } - - //! Effects: Searches backward for s as a substring of *this, - //! beginning at character position min(pos, size()) - size_type rfind(const basic_string& s, size_type pos = npos) const - { return rfind(s.c_str(), pos, s.size()); } - - //! Effects: Searches backward for a null-terminated character array - //! as a substring of *this, beginning at character min(pos, size()) - size_type rfind(const CharT* s, size_type pos = npos) const - { return rfind(s, pos, Traits::length(s)); } - - //! Effects: Searches backward for the first n characters of s as a - //! substring of *this, beginning at character position min(pos, size()). - size_type rfind(const CharT* s, size_type pos, size_type n) const - { - const std::size_t len = size(); - - if (n > len) - return npos; - else if (n == 0) - return min_value(len, pos); - else { - const const_iterator last = begin() + min_value(len - n, pos) + n; - const const_iterator result = find_end(begin(), last, - s, s + n, - Eq_traits()); - return result != last ? result - begin() : npos; - } - } - - //! Effects: Searches backward for a null-terminated character array - //! as a substring of *this, beginning at character min(pos, size()). - size_type rfind(CharT c, size_type pos = npos) const - { - const size_type len = size(); - - if (len < 1) - return npos; - else { - const const_iterator last = begin() + min_value(len - 1, pos) + 1; - const_reverse_iterator rresult = - std::find_if(const_reverse_iterator(last), rend(), - std::bind2nd(Eq_traits(), c)); - return rresult != rend() ? (rresult.base() - 1) - begin() : npos; - } - } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is equal to any character within s. - size_type find_first_of(const basic_string& s, size_type pos = 0) const - { return find_first_of(s.c_str(), pos, s.size()); } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is equal to any character within s. - size_type find_first_of(const CharT* s, size_type pos = 0) const - { return find_first_of(s, pos, Traits::length(s)); } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is equal to any character within the first n characters of s. - size_type find_first_of(const CharT* s, size_type pos, - size_type n) const - { - if (pos >= size()) - return npos; - else { - pointer finish = this->priv_addr() + this->priv_size(); - const_iterator result = std::find_first_of(this->priv_addr() + pos, finish, - s, s + n, - Eq_traits()); - return result != finish ? result - begin() : npos; - } - } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is equal to c. - size_type find_first_of(CharT c, size_type pos = 0) const - { return find(c, pos); } - - //! Effects: Searches backward within *this, beginning at min(pos, size()), - //! for the first character that is equal to any character within s. - size_type find_last_of(const basic_string& s, - size_type pos = npos) const - { return find_last_of(s.c_str(), pos, s.size()); } - - //! Effects: Searches backward *this, beginning at min(pos, size()), for - //! the first character that is equal to any character within s. - size_type find_last_of(const CharT* s, size_type pos = npos) const - { return find_last_of(s, pos, Traits::length(s)); } - - //! Effects: Searches backward within *this, beginning at min(pos, size()), - //! for the first character that is equal to any character within the first n - //! characters of s. - size_type find_last_of(const CharT* s, size_type pos, size_type n) const - { - const size_type len = size(); - - if (len < 1) - return npos; - else { - const const_iterator last = this->priv_addr() + min_value(len - 1, pos) + 1; - const const_reverse_iterator rresult = - std::find_first_of(const_reverse_iterator(last), rend(), - s, s + n, - Eq_traits()); - return rresult != rend() ? (rresult.base() - 1) - this->priv_addr() : npos; - } - } - - //! Effects: Searches backward *this, beginning at min(pos, size()), for - //! the first character that is equal to c. - size_type find_last_of(CharT c, size_type pos = npos) const - { return rfind(c, pos); } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is not equal to any character within s. - size_type find_first_not_of(const basic_string& s, - size_type pos = 0) const - { return find_first_not_of(s.c_str(), pos, s.size()); } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is not equal to any character within s. - size_type find_first_not_of(const CharT* s, size_type pos = 0) const - { return find_first_not_of(s, pos, Traits::length(s)); } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is not equal to any character within the first n - //! characters of s. - size_type find_first_not_of(const CharT* s, size_type pos, - size_type n) const - { - if (pos > size()) - return npos; - else { - pointer finish = this->priv_addr() + this->priv_size(); - const_iterator result = std::find_if(this->priv_addr() + pos, finish, - Not_within_traits(s, s + n)); - return result != finish ? result - this->priv_addr() : npos; - } - } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is not equal to c. - size_type find_first_not_of(CharT c, size_type pos = 0) const - { - if (pos > size()) - return npos; - else { - pointer finish = this->priv_addr() + this->priv_size(); - const_iterator result - = std::find_if(this->priv_addr() + pos, finish, - std::not1(std::bind2nd(Eq_traits(), c))); - return result != finish ? result - begin() : npos; - } - } - - //! Effects: Searches backward within *this, beginning at min(pos, size()), - //! for the first character that is not equal to any character within s. - size_type find_last_not_of(const basic_string& s, - size_type pos = npos) const - { return find_last_not_of(s.c_str(), pos, s.size()); } - - //! Effects: Searches backward *this, beginning at min(pos, size()), - //! for the first character that is not equal to any character within s. - size_type find_last_not_of(const CharT* s, size_type pos = npos) const - { return find_last_not_of(s, pos, Traits::length(s)); } - - //! Effects: Searches backward within *this, beginning at min(pos, size()), - //! for the first character that is not equal to any character within the first - //! n characters of s. - size_type find_last_not_of(const CharT* s, size_type pos, size_type n) const - { - const size_type len = size(); - - if (len < 1) - return npos; - else { - const const_iterator last = begin() + min_value(len - 1, pos) + 1; - const const_reverse_iterator rresult = - std::find_if(const_reverse_iterator(last), rend(), - Not_within_traits(s, s + n)); - return rresult != rend() ? (rresult.base() - 1) - begin() : npos; - } - } - - //! Effects: Searches backward *this, beginning at min(pos, size()), - //! for the first character that is not equal to c. - size_type find_last_not_of(CharT c, size_type pos = npos) const - { - const size_type len = size(); - - if (len < 1) - return npos; - else { - const const_iterator last = begin() + min_value(len - 1, pos) + 1; - const_reverse_iterator rresult = - std::find_if(const_reverse_iterator(last), rend(), - std::not1(std::bind2nd(Eq_traits(), c))); - return rresult != rend() ? (rresult.base() - 1) - begin() : npos; - } - } - - //! Effects: Returns a substring of *this. - basic_string substr(size_type pos = 0, size_type n = npos) const - { - if (pos > size()) - this->throw_out_of_range(); - return basic_string(this->priv_addr() + pos, - this->priv_addr() + pos + min_value(n, size() - pos), this->alloc()); - } - - //! Effects: Three-way lexicographical comparison of s and *this. - int compare(const basic_string& s) const - { return s_compare(this->priv_addr(), this->priv_addr() + this->priv_size(), s.priv_addr(), s.priv_addr() + s.priv_size()); } - - //! Effects: Three-way lexicographical comparison of s and a substring - //! of *this. - int compare(size_type pos1, size_type n1, const basic_string& s) const - { - if (pos1 > size()) - this->throw_out_of_range(); - return s_compare(this->priv_addr() + pos1, - this->priv_addr() + pos1 + min_value(n1, size() - pos1), - s.priv_addr(), s.priv_addr() + s.priv_size()); - } - - //! Effects: Three-way lexicographical comparison of a substring of s - //! and a substring of *this. - int compare(size_type pos1, size_type n1, - const basic_string& s, - size_type pos2, size_type n2) const { - if (pos1 > size() || pos2 > s.size()) - this->throw_out_of_range(); - return s_compare(this->priv_addr() + pos1, - this->priv_addr() + pos1 + min_value(n1, size() - pos1), - s.priv_addr() + pos2, - s.priv_addr() + pos2 + min_value(n2, size() - pos2)); - } - - //! Effects: Three-way lexicographical comparison of s and *this. - int compare(const CharT* s) const - { return s_compare(this->priv_addr(), this->priv_addr() + this->priv_size(), s, s + Traits::length(s)); } - - - //! Effects: Three-way lexicographical comparison of the first - //! min(len, traits::length(s) characters of s and a substring of *this. - int compare(size_type pos1, size_type n1, const CharT* s, - size_type n2 = npos) const - { - if (pos1 > size()) - this->throw_out_of_range(); - return s_compare(this->priv_addr() + pos1, - this->priv_addr() + pos1 + min_value(n1, size() - pos1), - s, s + n2); - } - - /// @cond - private: - static int s_compare(const_pointer f1, const_pointer l1, - const_pointer f2, const_pointer l2) - { - const std::ptrdiff_t n1 = l1 - f1; - const std::ptrdiff_t n2 = l2 - f2; - const int cmp = Traits::compare(detail::get_pointer(f1), - detail::get_pointer(f2), - min_value(n1, n2)); - return cmp != 0 ? cmp : (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0)); - } - - void priv_construct_null(pointer p) - { this->construct(p, 0); } - - static CharT priv_null() - { return (CharT) 0; } - - // Helper functions used by constructors. It is a severe error for - // any of them to be called anywhere except from within constructors. - void priv_terminate_string() - { this->priv_construct_null(this->priv_addr() + this->priv_size()); } - - template - void priv_range_initialize(InputIter f, InputIter l, - std::input_iterator_tag) - { - this->allocate_initial_block(InternalBufferChars); - this->priv_construct_null(this->priv_addr() + this->priv_size()); - this->append(f, l); - } - - template - void priv_range_initialize(ForwardIter f, ForwardIter l, - std::forward_iterator_tag) - { - difference_type n = std::distance(f, l); - this->allocate_initial_block(max_value(n+1, InternalBufferChars)); - priv_uninitialized_copy(f, l, this->priv_addr()); - this->priv_size(n); - this->priv_terminate_string(); - } - - template - void priv_range_initialize(InputIter f, InputIter l) - { - typedef typename std::iterator_traits::iterator_category Category; - this->priv_range_initialize(f, l, Category()); - } - - template - void priv_initialize_dispatch(Integer n, Integer x, detail::true_) - { - this->allocate_initial_block(max_value(n+1, InternalBufferChars)); - priv_uninitialized_fill_n(this->priv_addr(), n, x); - this->priv_size(n); - this->priv_terminate_string(); - } - - template - void priv_initialize_dispatch(InputIter f, InputIter l, detail::false_) - { this->priv_range_initialize(f, l); } - - template inline - void priv_uninitialized_fill_n(FwdIt first, Count count, const CharT val) - { - //Save initial position - FwdIt init = first; - - BOOST_TRY{ - //Construct objects - for (; count--; ++first){ - this->construct(first, val); - } - } - BOOST_CATCH(...){ - //Call destructors - for (; init != first; ++init){ - this->destroy(init); - } - BOOST_RETHROW - } - BOOST_CATCH_END - } - - template inline - size_type priv_uninitialized_copy(InpIt first, InpIt last, FwdIt dest) - { - //Save initial destination position - FwdIt dest_init = dest; - size_type constructed = 0; - - BOOST_TRY{ - //Try to build objects - for (; first != last; ++dest, ++first, ++constructed){ - this->construct(dest, *first); - } - } - BOOST_CATCH(...){ - //Call destructors - for (; constructed--; ++dest_init){ - this->destroy(dest_init); - } - BOOST_RETHROW - } - BOOST_CATCH_END - return (constructed); - } - - template - basic_string& priv_assign_dispatch(Integer n, Integer x, detail::true_) - { return this->assign((size_type) n, (CharT) x); } - - template - basic_string& priv_assign_dispatch(InputIter f, InputIter l, - detail::false_) - { - size_type cur = 0; - CharT *ptr = detail::get_pointer(this->priv_addr()); - while (f != l && cur != this->priv_size()) { - Traits::assign(*ptr, *f); - ++f; - ++cur; - ++ptr; - } - if (f == l) - this->erase(this->priv_addr() + cur, this->priv_addr() + this->priv_size()); - else - this->append(f, l); - return *this; - } - - template - void priv_insert(iterator p, InputIter first, InputIter last, std::input_iterator_tag) - { - for ( ; first != last; ++first, ++p) { - p = this->insert(p, *first); - } - } - - template - void priv_insert(iterator position, ForwardIter first, - ForwardIter last, std::forward_iterator_tag) - { - if (first != last) { - size_type n = std::distance(first, last); - size_type remaining = this->capacity() - this->priv_size(); - const size_type old_size = this->size(); - pointer old_start = this->priv_addr(); - bool enough_capacity = false; - std::pair allocation_ret; - size_type new_cap = 0; - - //Check if we have enough capacity - if (remaining >= n){ - enough_capacity = true; - } - else { - //Otherwise expand current buffer or allocate new storage - new_cap = this->next_capacity(n); - allocation_ret = this->allocation_command - (allocate_new | expand_fwd | expand_bwd, old_size + n + 1, - new_cap, new_cap, old_start); - - //Check forward expansion - if(old_start == allocation_ret.first){ - enough_capacity = true; - this->priv_storage(new_cap); - } - } - - //Reuse same buffer - if(enough_capacity){ - const size_type elems_after = - this->priv_size() - (position - this->priv_addr()); - size_type old_length = this->priv_size(); - if (elems_after >= n) { - pointer pointer_past_last = this->priv_addr() + this->priv_size() + 1; - priv_uninitialized_copy(this->priv_addr() + (this->priv_size() - n + 1), - pointer_past_last, pointer_past_last); - - this->priv_size(this->priv_size()+n); - Traits::move(detail::get_pointer(position + n), - detail::get_pointer(position), - (elems_after - n) + 1); - this->priv_copy(first, last, position); - } - else { - ForwardIter mid = first; - std::advance(mid, elems_after + 1); - - priv_uninitialized_copy(mid, last, this->priv_addr() + this->priv_size() + 1); - this->priv_size(this->priv_size() + (n - elems_after)); - priv_uninitialized_copy - (position, this->priv_addr() + old_length + 1, - this->priv_addr() + this->priv_size()); - this->priv_size(this->priv_size() + elems_after); - this->priv_copy(first, mid, position); - } - } - else{ - pointer new_start = allocation_ret.first; - if(!allocation_ret.second){ - //Copy data to new buffer - size_type new_length = 0; - //This can't throw, since characters are POD - new_length += priv_uninitialized_copy - (this->priv_addr(), position, new_start); - new_length += priv_uninitialized_copy - (first, last, new_start + new_length); - new_length += priv_uninitialized_copy - (position, this->priv_addr() + this->priv_size(), - new_start + new_length); - this->priv_construct_null(new_start + new_length); - - this->deallocate_block(); - this->is_short(false); - this->priv_addr(new_start); - this->priv_size(new_length); - this->priv_storage(new_cap); - } - else{ - //value_type is POD, so backwards expansion is much easier - //than with vector - value_type *oldbuf = detail::get_pointer(old_start); - value_type *newbuf = detail::get_pointer(new_start); - value_type *pos = detail::get_pointer(position); - size_type before = pos - oldbuf; - - //First move old data - Traits::move(newbuf, oldbuf, before); - Traits::move(newbuf + before + n, pos, old_size - before); - //Now initialize the new data - priv_uninitialized_copy(first, last, new_start + before); - this->priv_construct_null(new_start + (old_size + n)); - this->is_short(false); - this->priv_addr(new_start); - this->priv_size(old_size + n); - this->priv_storage(new_cap); - } - } - } - } - - template - void priv_insert_dispatch(iterator p, Integer n, Integer x, - detail::true_) - { insert(p, (size_type) n, (CharT) x); } - - template - void priv_insert_dispatch(iterator p, InputIter first, InputIter last, - detail::false_) - { - typedef typename std::iterator_traits::iterator_category Category; - priv_insert(p, first, last, Category()); - } - - template - void priv_copy(InputIterator first, InputIterator last, iterator result) - { - for ( ; first != last; ++first, ++result) - Traits::assign(*result, *first); - } - - void priv_copy(const CharT* first, const CharT* last, CharT* result) - { Traits::copy(result, first, last - first); } - - template - basic_string& priv_replace_dispatch(iterator first, iterator last, - Integer n, Integer x, - detail::true_) - { return this->replace(first, last, (size_type) n, (CharT) x); } - - template - basic_string& priv_replace_dispatch(iterator first, iterator last, - InputIter f, InputIter l, - detail::false_) - { - typedef typename std::iterator_traits::iterator_category Category; - return this->priv_replace(first, last, f, l, Category()); - } - - - template - basic_string& priv_replace(iterator first, iterator last, - InputIter f, InputIter l, std::input_iterator_tag) - { - for ( ; first != last && f != l; ++first, ++f) - Traits::assign(*first, *f); - - if (f == l) - this->erase(first, last); - else - this->insert(last, f, l); - return *this; - } - - template - basic_string& priv_replace(iterator first, iterator last, - ForwardIter f, ForwardIter l, - std::forward_iterator_tag) - { - difference_type n = std::distance(f, l); - const difference_type len = last - first; - if (len >= n) { - this->priv_copy(f, l, first); - this->erase(first + n, last); - } - else { - ForwardIter m = f; - std::advance(m, len); - this->priv_copy(f, m, first); - this->insert(last, m, l); - } - return *this; - } - /// @endcond -}; - -template -const typename basic_string::size_type -basic_string::npos - = (typename basic_string::size_type) -1; - -// ------------------------------------------------------------ -// Non-member functions. - -// Operator+ - -template -inline basic_string -operator+(const basic_string& x, - const basic_string& y) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - str_t result(reserve, x.size() + y.size(), x.alloc()); - result.append(x); - result.append(y); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(detail::moved_object > mx, - const basic_string& y) -{ - mx.get() += y; - return mx; -} -#else -template -basic_string && -operator+(basic_string && mx, - const basic_string& y) -{ - mx += y; - return detail::move_impl(mx); -} -#endif - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(const basic_string& x, - detail::moved_object > my) -{ - typedef typename basic_string::size_type size_type; - return my.get().replace(size_type(0), size_type(0), x); -} -#else -template -inline basic_string && -operator+(const basic_string& x, - basic_string && my) -{ - typedef typename basic_string::size_type size_type; - return my.replace(size_type(0), size_type(0), x); -} -#endif - -template -inline basic_string -operator+(const CharT* s, const basic_string& y) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - const std::size_t n = Traits::length(s); - str_t result(reserve, n + y.size()); - result.append(s, s + n); - result.append(y); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(const CharT* s, - detail::moved_object > my) -{ - typedef typename basic_string::size_type size_type; - return my.get().replace(size_type(0), size_type(0), s); -} -#else -template -inline basic_string && -operator+(const CharT* s, - basic_string && my) -{ - typedef typename basic_string::size_type size_type; - return detail::move_impl(my.get().replace(size_type(0), size_type(0), s)); -} -#endif - -template -inline basic_string -operator+(CharT c, const basic_string& y) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - str_t result(reserve, 1 + y.size()); - result.push_back(c); - result.append(y); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(CharT c, - detail::moved_object > my) -{ - typedef typename basic_string::size_type size_type; - return my.get().replace(size_type(0), size_type(0), &c, &c + 1); -} -#else -template -inline basic_string && -operator+(CharT c, - basic_string && my) -{ - typedef typename basic_string::size_type size_type; - return my.replace(size_type(0), size_type(0), &c, &c + 1); -} -#endif - -template -inline basic_string -operator+(const basic_string& x, const CharT* s) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - const std::size_t n = Traits::length(s); - str_t result(reserve, x.size() + n, x.alloc()); - result.append(x); - result.append(s, s + n); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(detail::moved_object > mx, - const CharT* s) -{ - mx.get() += s; - return mx; -} -#else -template -basic_string && -operator+(basic_string && mx, - const CharT* s) -{ - mx += s; - return detail::move_impl(mx); -} -#endif - -template -inline basic_string -operator+(const basic_string& x, const CharT c) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - str_t result(reserve, x.size() + 1, x.alloc()); - result.append(x); - result.push_back(c); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(detail::moved_object > mx, - const CharT c) -{ - mx.get() += c; - return mx; -} -#else -template -basic_string && -operator+(basic_string && mx, const CharT c) -{ - mx += c; - return detail::move_impl(mx); -} -#endif - -// Operator== and operator!= - -template -inline bool -operator==(const basic_string& x, - const basic_string& y) -{ - return x.size() == y.size() && - Traits::compare(x.data(), y.data(), x.size()) == 0; -} - -template -inline bool -operator==(const CharT* s, const basic_string& y) -{ - std::size_t n = Traits::length(s); - return n == y.size() && Traits::compare(s, y.data(), n) == 0; -} - -template -inline bool -operator==(const basic_string& x, const CharT* s) -{ - std::size_t n = Traits::length(s); - return x.size() == n && Traits::compare(x.data(), s, n) == 0; -} - -template -inline bool -operator!=(const basic_string& x, - const basic_string& y) - { return !(x == y); } - -template -inline bool -operator!=(const CharT* s, const basic_string& y) - { return !(s == y); } - -template -inline bool -operator!=(const basic_string& x, const CharT* s) - { return !(x == s); } - - -// Operator< (and also >, <=, and >=). - -template -inline bool -operator<(const basic_string& x, - const basic_string& y) -{ - return x.compare(y) < 0; -// return basic_string -// ::s_compare(x.begin(), x.end(), y.begin(), y.end()) < 0; -} - -template -inline bool -operator<(const CharT* s, const basic_string& y) -{ - return y.compare(s) > 0; -// std::size_t n = Traits::length(s); -// return basic_string -// ::s_compare(s, s + n, y.begin(), y.end()) < 0; -} - -template -inline bool -operator<(const basic_string& x, - const CharT* s) -{ - return x.compare(s) < 0; -// std::size_t n = Traits::length(s); -// return basic_string -// ::s_compare(x.begin(), x.end(), s, s + n) < 0; -} - -template -inline bool -operator>(const basic_string& x, - const basic_string& y) { - return y < x; -} - -template -inline bool -operator>(const CharT* s, const basic_string& y) { - return y < s; -} - -template -inline bool -operator>(const basic_string& x, const CharT* s) -{ - return s < x; -} - -template -inline bool -operator<=(const basic_string& x, - const basic_string& y) -{ - return !(y < x); -} - -template -inline bool -operator<=(const CharT* s, const basic_string& y) - { return !(y < s); } - -template -inline bool -operator<=(const basic_string& x, const CharT* s) - { return !(s < x); } - -template -inline bool -operator>=(const basic_string& x, - const basic_string& y) - { return !(x < y); } - -template -inline bool -operator>=(const CharT* s, const basic_string& y) - { return !(s < y); } - -template -inline bool -operator>=(const basic_string& x, const CharT* s) - { return !(x < s); } - -// Swap. -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline void swap(basic_string& x, basic_string& y) -{ x.swap(y); } - -template -inline void swap(detail::moved_object > mx, basic_string& y) -{ mx.get().swap(y); } - -template -inline void swap(basic_string& x, detail::moved_object > my) -{ x.swap(my.get()); } -#else -template -inline void swap(basic_string && x, basic_string &&y) -{ x.swap(y); } -#endif - -/// @cond -// I/O. -namespace detail { - -template -inline bool -interprocess_string_fill(std::basic_ostream& os, - std::basic_streambuf* buf, - std::size_t n) -{ - CharT f = os.fill(); - std::size_t i; - bool ok = true; - - for (i = 0; i < n; i++) - ok = ok && !Traits::eq_int_type(buf->sputc(f), Traits::eof()); - return ok; -} - -} //namespace detail { -/// @endcond - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - const basic_string& s) - #else - const basic_string&&s) - #endif -{ - typename std::basic_ostream::sentry sentry(os); - bool ok = false; - - if (sentry) { - ok = true; - std::size_t n = s.size(); - std::size_t pad_len = 0; - const bool left = (os.flags() & std::ios::left) != 0; - const std::size_t w = os.width(0); - std::basic_streambuf* buf = os.rdbuf(); - - if (w != 0 && n < w) - pad_len = w - n; - - if (!left) - ok = detail::interprocess_string_fill(os, buf, pad_len); - - ok = ok && - buf->sputn(s.data(), std::streamsize(n)) == std::streamsize(n); - - if (left) - ok = ok && detail::interprocess_string_fill(os, buf, pad_len); - } - - if (!ok) - os.setstate(std::ios_base::failbit); - - return os; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -std::basic_ostream& -operator<<(std::basic_ostream& os, - detail::moved_object > ms) -{ return os << ms.get(); } -#endif - - -template -std::basic_istream& -operator>>(std::basic_istream& is, - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string& s) - #else - basic_string&&s) - #endif -{ - typename std::basic_istream::sentry sentry(is); - - if (sentry) { - std::basic_streambuf* buf = is.rdbuf(); - const std::ctype& ctype = std::use_facet >(is.getloc()); - - s.clear(); - std::size_t n = is.width(0); - if (n == 0) - n = static_cast(-1); - else - s.reserve(n); - - while (n-- > 0) { - typename Traits::int_type c1 = buf->sbumpc(); - - if (Traits::eq_int_type(c1, Traits::eof())) { - is.setstate(std::ios_base::eofbit); - break; - } - else { - CharT c = Traits::to_char_type(c1); - - if (ctype.is(std::ctype::space, c)) { - if (Traits::eq_int_type(buf->sputbackc(c), Traits::eof())) - is.setstate(std::ios_base::failbit); - break; - } - else - s.push_back(c); - } - } - - // If we have read no characters, then set failbit. - if (s.size() == 0) - is.setstate(std::ios_base::failbit); - } - else - is.setstate(std::ios_base::failbit); - - return is; -} - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -std::basic_istream& -operator>>(std::basic_istream& is, - detail::moved_object > ms) -{ return is >> ms.get(); } -#endif - -template -std::basic_istream& -getline(std::istream& is, - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string& s, - #else - basic_string&&s, - #endif - CharT delim) -{ - std::size_t nread = 0; - typename std::basic_istream::sentry sentry(is, true); - if (sentry) { - std::basic_streambuf* buf = is.rdbuf(); - s.clear(); - - int c1; - while (nread < s.max_size()) { - int c1 = buf->sbumpc(); - if (Traits::eq_int_type(c1, Traits::eof())) { - is.setstate(std::ios_base::eofbit); - break; - } - else { - ++nread; - CharT c = Traits::to_char_type(c1); - if (!Traits::eq(c, delim)) - s.push_back(c); - else - break; // Character is extracted but not appended. - } - } - } - if (nread == 0 || nread >= s.max_size()) - is.setstate(std::ios_base::failbit); - - return is; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -std::basic_istream& -getline(std::istream& is, - detail::moved_object > ms, - CharT delim) -{ return getline(is, ms.get(), delim); } -#endif - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline std::basic_istream& -getline(std::basic_istream& is, - basic_string& s) -{ - return getline(is, s, '\n'); -} - -template -std::basic_istream& -getline(std::istream& is, - detail::moved_object > ms) -{ return getline(is, ms.get()); } -#else -template -std::basic_istream& -getline(std::istream& is, - basic_string && ms) -{ return getline(is, ms); } -#endif - -template -inline std::size_t hash_value(basic_string, A> const& v) -{ - return hash_range(v.begin(), v.end()); -} - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess +} //namespace interprocess { +} //namespace boost { #include -#endif // BOOST_INTERPROCESS_STRING_HPP +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_STRING_HPP diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp index 680bb82..d6f31c2 100644 --- a/include/boost/interprocess/containers/vector.hpp +++ b/include/boost/interprocess/containers/vector.hpp @@ -1,1998 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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. // ////////////////////////////////////////////////////////////////////////////// -// -// This file comes from SGI's stl_vector.h file. Modified by Ion Gaztanaga. -// Renaming, isolating and porting to generic algorithms. Pointer typedef -// set to allocator::pointer to allow placing it in shared memory. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 1994 -// Hewlett-Packard Company -// -// Permission to use, copy, modify, distribute and sell this software -// and its documentation for any purpose is hereby granted without fee, -// provided that the above copyright notice appear in all copies and -// that both that copyright notice and this permission notice appear -// in supporting documentation. Hewlett-Packard Company makes no -// representations about the suitability of this software for any -// purpose. It is provided "as is" without express or implied warranty. -// -// -// Copyright (c) 1996 -// Silicon Graphics Computer Systems, Inc. -// -// Permission to use, copy, modify, distribute and sell this software -// and its documentation for any purpose is hereby granted without fee, -// provided that the above copyright notice appear in all copies and -// that both that copyright notice and this permission notice appear -// in supporting documentation. Silicon Graphics makes no -// representations about the suitability of this software for any -// purpose. It is provided "as is" without express or implied warranty. -#ifndef BOOST_INTERPROCESS_VECTOR_HPP -#define BOOST_INTERPROCESS_VECTOR_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP +#define BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace interprocess { -/// @cond - -namespace detail { - -//! Const vector_iterator used to iterate through a vector. -template -class vector_const_iterator - : public std::iterator::value_type - ,typename std::iterator_traits::difference_type - ,typename pointer_to_other - ::value_type - >::type - ,const typename std::iterator_traits::value_type &> -{ - public: - typedef const typename std::iterator_traits::value_type value_type; - typedef typename std::iterator_traits::difference_type difference_type; - typedef typename pointer_to_other::type pointer; - typedef value_type& reference; - - /// @cond - protected: - Pointer m_ptr; - - public: - Pointer get_ptr() const { return m_ptr; } - explicit vector_const_iterator(Pointer ptr) : m_ptr(ptr){} - /// @endcond - - public: - - //Constructors - vector_const_iterator() : m_ptr(0){} - - //Pointer like operators - reference operator*() const - { return *m_ptr; } - - const value_type * operator->() const - { return detail::get_pointer(m_ptr); } - - reference operator[](difference_type off) const - { return m_ptr[off]; } - - //Increment / Decrement - vector_const_iterator& operator++() - { ++m_ptr; return *this; } - - vector_const_iterator operator++(int) - { Pointer tmp = m_ptr; ++*this; return vector_const_iterator(tmp); } - - vector_const_iterator& operator--() - { --m_ptr; return *this; } - - vector_const_iterator operator--(int) - { Pointer tmp = m_ptr; --*this; return vector_const_iterator(tmp); } - - //Arithmetic - vector_const_iterator& operator+=(difference_type off) - { m_ptr += off; return *this; } - - vector_const_iterator operator+(difference_type off) const - { return vector_const_iterator(m_ptr+off); } - - friend vector_const_iterator operator+(difference_type off, const vector_const_iterator& right) - { return vector_const_iterator(off + right.m_ptr); } - - vector_const_iterator& operator-=(difference_type off) - { m_ptr -= off; return *this; } - - vector_const_iterator operator-(difference_type off) const - { return vector_const_iterator(m_ptr-off); } - - difference_type operator-(const vector_const_iterator& right) const - { return m_ptr - right.m_ptr; } - - //Comparison operators - bool operator== (const vector_const_iterator& r) const - { return m_ptr == r.m_ptr; } - - bool operator!= (const vector_const_iterator& r) const - { return m_ptr != r.m_ptr; } - - bool operator< (const vector_const_iterator& r) const - { return m_ptr < r.m_ptr; } - - bool operator<= (const vector_const_iterator& r) const - { return m_ptr <= r.m_ptr; } - - bool operator> (const vector_const_iterator& r) const - { return m_ptr > r.m_ptr; } - - bool operator>= (const vector_const_iterator& r) const - { return m_ptr >= r.m_ptr; } -}; - -//! Iterator used to iterate through a vector -template -class vector_iterator - : public vector_const_iterator -{ - public: - explicit vector_iterator(Pointer ptr) - : vector_const_iterator(ptr) - {} - - public: - typedef typename std::iterator_traits::value_type value_type; - typedef typename vector_const_iterator::difference_type difference_type; - typedef Pointer pointer; - typedef value_type& reference; - - //Constructors - vector_iterator() - {} - - //Pointer like operators - reference operator*() const - { return *this->m_ptr; } - - value_type* operator->() const - { return detail::get_pointer(this->m_ptr); } - - reference operator[](difference_type off) const - { return this->m_ptr[off]; } - - //Increment / Decrement - vector_iterator& operator++() - { ++this->m_ptr; return *this; } - - vector_iterator operator++(int) - { pointer tmp = this->m_ptr; ++*this; return vector_iterator(tmp); } - - vector_iterator& operator--() - { --this->m_ptr; return *this; } - - vector_iterator operator--(int) - { vector_iterator tmp = *this; --*this; return vector_iterator(tmp); } - - // Arithmetic - vector_iterator& operator+=(difference_type off) - { this->m_ptr += off; return *this; } - - vector_iterator operator+(difference_type off) const - { return vector_iterator(this->m_ptr+off); } - - friend vector_iterator operator+(difference_type off, const vector_iterator& right) - { return vector_iterator(off + right.m_ptr); } - - vector_iterator& operator-=(difference_type off) - { this->m_ptr -= off; return *this; } - - vector_iterator operator-(difference_type off) const - { return vector_iterator(this->m_ptr-off); } - - difference_type operator-(const vector_const_iterator& right) const - { return static_cast&>(*this) - right; } -}; - -template -struct vector_value_traits -{ - typedef T value_type; - typedef A allocator_type; - static const bool trivial_dctr = boost::has_trivial_destructor::value; - static const bool trivial_dctr_after_move = - has_trivial_destructor_after_move::value || trivial_dctr; - static const bool trivial_copy = has_trivial_copy::value; - static const bool nothrow_copy = has_nothrow_copy::value; - static const bool trivial_assign = has_trivial_assign::value; - static const bool nothrow_assign = has_nothrow_assign::value; - - //This is the anti-exception array destructor - //to deallocate values already constructed - typedef typename detail::if_c - - ,detail::scoped_destructor_n - >::type OldArrayDestructor; - //This is the anti-exception array destructor - //to destroy objects created with copy construction - typedef typename detail::if_c - - ,detail::scoped_destructor_n - >::type UCopiedArrayDestructor; - //This is the anti-exception array deallocator - typedef typename detail::if_c - - ,detail::scoped_array_deallocator - >::type UCopiedArrayDeallocator; - - //This is the optimized move iterator for copy constructors - //so that std::copy and similar can use memcpy - typedef typename detail::if_c - ::value - #endif - ,const T* - ,detail::move_iterator - >::type copy_move_it; - - //This is the optimized move iterator for assignments - //so that std::uninitialized_copy and similar can use memcpy - typedef typename detail::if_c - ::value - #endif - ,const T* - ,detail::move_iterator - >::type assign_move_it; -}; - -//!This struct deallocates and allocated memory -template -struct vector_alloc_holder -{ - typedef typename A::pointer pointer; - typedef typename A::size_type size_type; - typedef typename A::value_type value_type; - typedef vector_value_traits value_traits; - - //Constructor, does not throw - vector_alloc_holder(const A &a) - : members_(a) - {} - - //Constructor, does not throw - vector_alloc_holder(const vector_alloc_holder &h) - : members_(h.alloc()) - {} - - //Destructor - ~vector_alloc_holder() - { - this->prot_destroy_all(); - this->prot_deallocate(); - } - - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant allocator_v2; - typedef detail::integral_constant::value> alloc_version; - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, const pointer &reuse = 0) - { - return allocation_command(command, limit_size, preferred_size, - received_size, reuse, alloc_version()); - } - - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, - const pointer &reuse, - allocator_v1) - { - (void)limit_size; - (void)reuse; - if(!(command & allocate_new)) - return std::pair(pointer(0), 0); - received_size = preferred_size; - return std::make_pair(this->alloc().allocate(received_size), false); - } - - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, - const pointer &reuse, - allocator_v2) - { - return this->alloc().allocation_command - (command, limit_size, preferred_size, received_size, reuse); - } - - size_type next_capacity(size_type additional_objects) const - { return get_next_capacity(this->alloc().max_size(), this->members_.m_capacity, additional_objects); } - - struct members_holder - : public A - { - private: - members_holder(const members_holder&); - - public: - members_holder(const A &alloc) - : A(alloc), m_start(0), m_size(0), m_capacity(0) - {} - - pointer m_start; - size_type m_size; - size_type m_capacity; - } members_; - - protected: - void prot_deallocate() - { - if(!this->members_.m_capacity) return; - this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); - this->members_.m_start = 0; - this->members_.m_size = 0; - this->members_.m_capacity = 0; - } - - void destroy(value_type* p) - { - if(!value_traits::trivial_dctr) - detail::get_pointer(p)->~value_type(); - } - - void destroy_n(value_type* p, size_type n) - { - if(!value_traits::trivial_dctr) - for(; n--; ++p) p->~value_type(); - } - - void prot_destroy_all() - { - this->destroy_n(detail::get_pointer(this->members_.m_start), this->members_.m_size); - this->members_.m_size = 0; - } - - A &alloc() - { return members_; } - - const A &alloc() const - { return members_; } -}; - -} //namespace detail { -/// @endcond - -//! A vector is a sequence that supports random access to elements, constant -//! time insertion and removal of elements at the end, and linear time insertion -//! and removal of elements at the beginning or in the middle. The number of -//! elements in a vector may vary dynamically; memory management is automatic. -//! boost::interprocess::vector is similar to std::vector but it's compatible -//! with shared memory and memory mapped files. -template -class vector : private detail::vector_alloc_holder -{ - /// @cond - typedef vector self_t; - typedef detail::vector_alloc_holder base_t; - /// @endcond - public: - //! The type of object, T, stored in the vector - typedef T value_type; - //! Pointer to T - typedef typename A::pointer pointer; - //! Const pointer to T - typedef typename A::const_pointer const_pointer; - //! Reference to T - typedef typename A::reference reference; - //! Const reference to T - typedef typename A::const_reference const_reference; - //! An unsigned integral type - typedef typename A::size_type size_type; - //! A signed integral type - typedef typename A::difference_type difference_type; - //! The allocator type - typedef A allocator_type; - //! The random access iterator - typedef detail::vector_iterator iterator; - //! The random access const_iterator - typedef detail::vector_const_iterator const_iterator; - - //! Iterator used to iterate backwards through a vector. - typedef std::reverse_iterator - reverse_iterator; - //! Const iterator used to iterate backwards through a vector. - typedef std::reverse_iterator - const_reverse_iterator; - //! The stored allocator type - typedef allocator_type stored_allocator_type; - - /// @cond - private: - typedef detail::advanced_insert_aux_int advanced_insert_aux_int_t; - typedef detail::vector_value_traits value_traits; - - typedef typename base_t::allocator_v1 allocator_v1; - typedef typename base_t::allocator_v2 allocator_v2; - typedef typename base_t::alloc_version alloc_version; - - typedef constant_iterator cvalue_iterator; - typedef repeat_iterator repeat_it; - typedef detail::move_iterator repeat_move_it; - /// @endcond - - public: - - //! Effects: Constructs a vector taking the allocator as parameter. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - explicit vector(const A& a = A()) - : base_t(a) - {} - - //! Effects: Constructs a vector that will use a copy of allocator a - //! and inserts n copies of value. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's default or copy constructor throws. - //! - //! Complexity: Linear to n. - vector(size_type n, const T& value = T(), - const allocator_type& a = allocator_type()) - : base_t(a) - { this->insert(this->cend(), n, value); } - - //! Effects: Copy constructs a vector. - //! - //! Postcondition: x == *this. - //! - //! Complexity: Linear to the elements x contains. - vector(const vector& x) - : base_t((base_t&)x) - { *this = x; } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - vector(detail::moved_object > mx) - : base_t(mx.get()) - { this->swap(mx.get()); } - #else - vector(vector && mx) - : base_t(detail::move_impl(mx)) - { this->swap(mx); } - #endif - - //! Effects: Constructs a vector that will use a copy of allocator a - //! and inserts a copy of the range [first, last) in the vector. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's constructor taking an dereferenced InIt throws. - //! - //! Complexity: Linear to the range [first, last). - template - vector(InIt first, InIt last, const allocator_type& a = allocator_type()) - : base_t(a) - { this->assign(first, last); } - - //! Effects: Destroys the vector. All stored values are destroyed - //! and used memory is deallocated. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements. - ~vector() - {} //vector_alloc_holder clears the data - - //! Effects: Returns an iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return iterator(this->members_.m_start); } - - //! Effects: Returns a const_iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return const_iterator(this->members_.m_start); } - - //! Effects: Returns an iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return iterator(this->members_.m_start + this->members_.m_size); } - - //! Effects: Returns a const_iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return this->cend(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return reverse_iterator(this->end()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin()const - { return this->crbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return reverse_iterator(this->begin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return this->crend(); } - - //! Effects: Returns a const_iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return const_iterator(this->members_.m_start); } - - //! Effects: Returns a const_iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return const_iterator(this->members_.m_start + this->members_.m_size); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin()const - { return const_reverse_iterator(this->end());} - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return const_reverse_iterator(this->begin()); } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference front() - { return *this->members_.m_start; } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference front() const - { return *this->members_.m_start; } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference back() - { return this->members_.m_start[this->members_.m_size - 1]; } - - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference back() const - { return this->members_.m_start[this->members_.m_size - 1]; } - - //! Returns: A pointer such that [data(),data() + size()) is a valid range. - //! For a non-empty vector, data() == &front(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - pointer data() - { return this->members_.m_start; } - - //! Returns: A pointer such that [data(),data() + size()) is a valid range. - //! For a non-empty vector, data() == &front(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_pointer data() const - { return this->members_.m_start; } - - //! Effects: Returns the number of the elements contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return this->members_.m_size; } - - //! Effects: Returns the largest possible size of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return this->alloc().max_size(); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return this->members_.m_capacity; } - - //! Effects: Returns true if the vector contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return !this->members_.m_size; } - - //! Requires: size() < n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference operator[](size_type n) - { return this->members_.m_start[n]; } - - //! Requires: size() < n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference operator[](size_type n) const - { return this->members_.m_start[n]; } - - //! Requires: size() < n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - reference at(size_type n) - { this->priv_check_range(n); return this->members_.m_start[n]; } - - //! Requires: size() < n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - const_reference at(size_type n) const - { this->priv_check_range(n); return this->members_.m_start[n]; } - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return this->alloc(); } - - const stored_allocator_type &get_stored_allocator() const - { return this->alloc(); } - - stored_allocator_type &get_stored_allocator() - { return this->alloc(); } - - //! Effects: If n is less than or equal to capacity(), this call has no - //! effect. Otherwise, it is a request for allocation of additional memory. - //! If the request is successful, then capacity() is greater than or equal to - //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - void reserve(size_type new_cap) - { - if (this->capacity() < new_cap){ - //There is not enough memory, allocate a new - //buffer or expand the old one. - bool same_buffer_start; - size_type real_cap = 0; - std::pair ret = - this->allocation_command - (allocate_new | expand_fwd | expand_bwd, - new_cap, new_cap, real_cap, this->members_.m_start); - - //Check for forward expansion - same_buffer_start = ret.second && this->members_.m_start == ret.first; - if(same_buffer_start){ - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - ++this->num_expand_fwd; - #endif - this->members_.m_capacity = real_cap; - } - //If there is no forward expansion, move objects - else{ - //We will reuse insert code, so create a dummy input iterator - typename value_traits::copy_move_it dummy_it(detail::get_pointer(this->members_.m_start)); - detail::advanced_insert_aux_proxy - proxy(dummy_it, dummy_it); - //Backwards (and possibly forward) expansion - if(ret.second){ - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - ++this->num_expand_bwd; - #endif - this->priv_range_insert_expand_backwards - ( detail::get_pointer(ret.first) - , real_cap - , detail::get_pointer(this->members_.m_start) - , 0 - , proxy); - } - //New buffer - else{ - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - ++this->num_alloc; - #endif - this->priv_range_insert_new_allocation - ( detail::get_pointer(ret.first) - , real_cap - , detail::get_pointer(this->members_.m_start) - , 0 - , proxy); - } - } - } - } - - //! Effects: Makes *this contain the same elements as x. - //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in x. - vector& operator=(const vector& x) - { - if (&x != this){ - this->assign(x.members_.m_start, x.members_.m_start + x.members_.m_size); - } - return *this; - } - - //! Effects: Move assignment. All mx's values are transferred to *this. - //! - //! Postcondition: x.empty(). *this contains a the elements x had - //! before the function. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - vector& operator=(detail::moved_object > mx) - { - vector &x = mx.get(); - #else - vector& operator=(vector && x) - { - #endif - if (&x != this){ - this->swap(x); - x.clear(); - } - return *this; - } - - //! Effects: Assigns the n copies of val to *this. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void assign(size_type n, const value_type& val) - { this->assign(cvalue_iterator(val, n), cvalue_iterator()); } - - //! Effects: Assigns the the range [first, last) to *this. - //! - //! Throws: If memory allocation throws or - //! T's constructor from dereferencing InpIt throws. - //! - //! Complexity: Linear to n. - template - void assign(InIt first, InIt last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); - } - - //! Effects: Inserts a copy of x at the end of the vector. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_back(const T& x) - { - if (this->members_.m_size < this->members_.m_capacity){ - //There is more memory, just construct a new object at the end - new((void*)(detail::get_pointer(this->members_.m_start) + this->members_.m_size))value_type(x); - ++this->members_.m_size; - } - else{ - this->insert(this->cend(), x); - } - } - - //! Effects: Constructs a new element in the end of the vector - //! and moves the resources of mx to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_back(detail::moved_object mx) - { - value_type &x = mx.get(); - #else - void push_back(T && x) - { - #endif - if (this->members_.m_size < this->members_.m_capacity){ - //There is more memory, just construct a new object at the end - new((void*)detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(detail::move_impl(x)); - ++this->members_.m_size; - } - else{ - this->insert(this->cend(), detail::move_impl(x)); - } - } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the end of the vector. - //! - //! Throws: If memory allocation throws or the in-place constructor throws. - //! - //! Complexity: Amortized constant time. - template - void emplace_back(Args &&...args) - { - T* back_pos = detail::get_pointer(this->members_.m_start) + this->members_.m_size; - if (this->members_.m_size < this->members_.m_capacity){ - //There is more memory, just construct a new object at the end - new((void*)(back_pos))value_type(detail::forward_impl(args)...); - ++this->members_.m_size; - } - else{ - detail::advanced_insert_aux_emplace proxy - (detail::forward_impl(args)...); - priv_range_insert(back_pos, 1, proxy); - } - } - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... before position - //! - //! Throws: If memory allocation throws or the in-place constructor throws. - //! - //! Complexity: If position is end(), amortized constant time - //! Linear time otherwise. - template - iterator emplace(const_iterator position, Args && ...args) - { - //Just call more general insert(pos, size, value) and return iterator - size_type pos_n = position - cbegin(); - detail::advanced_insert_aux_emplace proxy - (detail::forward_impl(args)...); - priv_range_insert(position.get_ptr(), 1, proxy); - return iterator(this->members_.m_start + pos_n); - } - - #else - - void emplace_back() - { - T* back_pos = detail::get_pointer(this->members_.m_start) + this->members_.m_size; - if (this->members_.m_size < this->members_.m_capacity){ - //There is more memory, just construct a new object at the end - new((void*)(back_pos))value_type(); - ++this->members_.m_size; - } - else{ - detail::advanced_insert_aux_emplace proxy; - priv_range_insert(back_pos, 1, proxy); - } - } - - iterator emplace(const_iterator position) - { - size_type pos_n = position - cbegin(); - detail::advanced_insert_aux_emplace proxy; - priv_range_insert(detail::get_pointer(position.get_ptr()), 1, proxy); - return iterator(this->members_.m_start + pos_n); - } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - void emplace_back(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - T* back_pos = detail::get_pointer(this->members_.m_start) + this->members_.m_size; \ - if (this->members_.m_size < this->members_.m_capacity){ \ - new((void*)(back_pos))value_type \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - ++this->members_.m_size; \ - } \ - else{ \ - detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ - \ - proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_range_insert(back_pos, 1, proxy); \ - } \ - } \ - \ - template \ - iterator emplace(const_iterator pos, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - size_type pos_n = pos - cbegin(); \ - detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ - \ - proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_range_insert(detail::get_pointer(pos.get_ptr()), 1, proxy); \ - return iterator(this->members_.m_start + pos_n); \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() - //! allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(vector& x) - #else - void swap(vector &&x) - #endif - { - allocator_type &this_al = this->alloc(), &other_al = x.alloc(); - //Just swap internals - detail::do_swap(this->members_.m_start, x.members_.m_start); - detail::do_swap(this->members_.m_size, x.members_.m_size); - detail::do_swap(this->members_.m_capacity, x.members_.m_capacity); - - if (this_al != other_al){ - detail::do_swap(this_al, other_al); - } - } - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Insert a copy of x before position. - //! - //! Throws: If memory allocation throws or x's copy constructor throws. - //! - //! Complexity: If position is end(), amortized constant time - //! Linear time otherwise. - iterator insert(const_iterator position, const T& x) - { - //Just call more general insert(pos, size, value) and return iterator - size_type pos_n = position - cbegin(); - this->insert(position, (size_type)1, x); - return iterator(this->members_.m_start + pos_n); - } - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Insert a new element before position with mx's resources. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: If position is end(), amortized constant time - //! Linear time otherwise. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object mx) - { - value_type &x = mx.get(); - #else - iterator insert(const_iterator position, T &&x) - { - #endif - //Just call more general insert(pos, size, value) and return iterator - size_type pos_n = position - cbegin(); - this->insert(position - ,repeat_move_it(repeat_it(x, 1)) - ,repeat_move_it(repeat_it())); - return iterator(this->members_.m_start + pos_n); - } - - //! Requires: pos must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [first, last) range before pos. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws or T's copy constructor throws. - //! - //! Complexity: Linear to std::distance [first, last). - template - void insert(const_iterator pos, InIt first, InIt last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_dispatch(pos, first, last, Result()); - } - - //! Requires: pos must be a valid iterator of *this. - //! - //! Effects: Insert n copies of x before pos. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void insert(const_iterator p, size_type n, const T& x) - { this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); } - - //! Effects: Removes the last element from the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant time. - void pop_back() - { - //Destroy last element - --this->members_.m_size; - this->destroy(detail::get_pointer(this->members_.m_start) + this->members_.m_size); - } - - //! Effects: Erases the element at position pos. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the elements between pos and the - //! last element. Constant if pos is the first or the last element. - iterator erase(const_iterator position) - { - T *pos = detail::get_pointer(position.get_ptr()); - T *beg = detail::get_pointer(this->members_.m_start); - typedef typename value_traits::assign_move_it assign_move_it; - std::copy(assign_move_it(pos + 1), assign_move_it(beg + this->members_.m_size), pos); - --this->members_.m_size; - //Destroy last element - base_t::destroy(detail::get_pointer(this->members_.m_start) + this->members_.m_size); - return iterator(position.get_ptr()); - } - - //! Effects: Erases the elements pointed by [first, last). - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the distance between first and last. - iterator erase(const_iterator first, const_iterator last) - { - typedef typename value_traits::assign_move_it assign_move_it; - if (first != last){ // worth doing, copy down over hole - T* end_pos = detail::get_pointer(this->members_.m_start) + this->members_.m_size; - T* ptr = detail::get_pointer(std::copy - (assign_move_it(detail::get_pointer(last.get_ptr())) - ,assign_move_it(end_pos) - ,detail::get_pointer(first.get_ptr()) - )); - size_type destroyed = (end_pos - ptr); - this->destroy_n(ptr, destroyed); - this->members_.m_size -= destroyed; - } - return iterator(first.get_ptr()); - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size, const T& x) - { - pointer finish = this->members_.m_start + this->members_.m_size; - if (new_size < size()){ - //Destroy last elements - this->erase(const_iterator(this->members_.m_start + new_size), this->end()); - } - else{ - //Insert new elements at the end - this->insert(const_iterator(finish), new_size - this->size(), x); - } - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size) - { - if (new_size < this->size()){ - //Destroy last elements - this->erase(const_iterator(this->members_.m_start + new_size), this->end()); - } - else{ - size_type n = new_size - this->size(); - this->reserve(new_size); - detail::default_construct_aux_proxy proxy(n); - priv_range_insert(this->cend().get_ptr(), n, proxy); - } - } - - //! Effects: Erases all the elements of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements in the vector. - void clear() - { this->prot_destroy_all(); } - - /// @cond - - //! Effects: Tries to deallocate the excess of memory created - //! with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { priv_shrink_to_fit(alloc_version()); } - - private: - void priv_shrink_to_fit(allocator_v1) - { - if(this->members_.m_capacity){ - if(!size()){ - this->prot_deallocate(); - } - else{ - //This would not work with stateful allocators - vector(*this).swap(*this); - } - } - } - - void priv_shrink_to_fit(allocator_v2) - { - if(this->members_.m_capacity){ - if(!size()){ - this->prot_deallocate(); - } - else{ - size_type received_size; - if(this->alloc().allocation_command - ( shrink_in_place | nothrow_allocation - , this->capacity(), this->size() - , received_size, this->members_.m_start).first){ - this->members_.m_capacity = received_size; - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - ++this->num_shrink; - #endif - } - } - } - } - - template - void priv_range_insert(pointer pos, FwdIt first, FwdIt last, std::forward_iterator_tag) - { - if(first != last){ - const size_type n = std::distance(first, last); - detail::advanced_insert_aux_proxy proxy(first, last); - priv_range_insert(pos, n, proxy); - } - } - - void priv_range_insert(pointer pos, const size_type n, advanced_insert_aux_int_t &interf) - { - //Check if we have enough memory or try to expand current memory - size_type remaining = this->members_.m_capacity - this->members_.m_size; - bool same_buffer_start; - std::pair ret; - size_type real_cap = this->members_.m_capacity; - - //Check if we already have room - if (n <= remaining){ - same_buffer_start = true; - } - else{ - //There is not enough memory, allocate a new - //buffer or expand the old one. - size_type new_cap = this->next_capacity(n); - ret = this->allocation_command - (allocate_new | expand_fwd | expand_bwd, - this->members_.m_size + n, new_cap, real_cap, this->members_.m_start); - - //Check for forward expansion - same_buffer_start = ret.second && this->members_.m_start == ret.first; - if(same_buffer_start){ - this->members_.m_capacity = real_cap; - } - } - - //If we had room or we have expanded forward - if (same_buffer_start){ - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - ++this->num_expand_fwd; - #endif - this->priv_range_insert_expand_forward - (detail::get_pointer(pos), n, interf); - } - //Backwards (and possibly forward) expansion - else if(ret.second){ - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - ++this->num_expand_bwd; - #endif - this->priv_range_insert_expand_backwards - ( detail::get_pointer(ret.first) - , real_cap - , detail::get_pointer(pos) - , n - , interf); - } - //New buffer - else{ - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - ++this->num_alloc; - #endif - this->priv_range_insert_new_allocation - ( detail::get_pointer(ret.first) - , real_cap - , detail::get_pointer(pos) - , n - , interf); - } - } - - void priv_range_insert_expand_forward(T* pos, size_type n, advanced_insert_aux_int_t &interf) - { - typedef typename value_traits::copy_move_it copy_move_it; - typedef typename value_traits::assign_move_it assign_move_it; - //There is enough memory - T* old_finish = detail::get_pointer(this->members_.m_start) + this->members_.m_size; - const size_type elems_after = old_finish - pos; - - if (elems_after > n){ - //New elements can be just copied. - //Move to uninitialized memory last objects - std::uninitialized_copy(copy_move_it(old_finish - n), copy_move_it(old_finish), old_finish); - this->members_.m_size += n; - //Copy previous to last objects to the initialized end - std::copy_backward(assign_move_it(pos), assign_move_it(old_finish - n), old_finish); - //Insert new objects in the pos - interf.copy_all_to(pos); - } - else { - //The new elements don't fit in the [pos, end()) range. Copy - //to the beginning of the unallocated zone the last new elements. - interf.uninitialized_copy_some_and_update(old_finish, elems_after, false); - this->members_.m_size += n - elems_after; - //Copy old [pos, end()) elements to the uninitialized memory - std::uninitialized_copy - ( copy_move_it(pos), copy_move_it(old_finish) - , detail::get_pointer(this->members_.m_start) + this->members_.m_size); - this->members_.m_size += elems_after; - //Copy first new elements in pos - interf.copy_all_to(pos); - } - } - - void priv_range_insert_new_allocation - (T* new_start, size_type new_cap, T* pos, size_type n, advanced_insert_aux_int_t &interf) - { - typedef typename value_traits::copy_move_it copy_move_it; - T* new_finish = new_start; - T *old_finish; - //Anti-exception rollbacks - typename value_traits::UCopiedArrayDeallocator scoped_alloc(new_start, this->alloc(), new_cap); - typename value_traits::UCopiedArrayDestructor constructed_values_destroyer(new_start, 0u); - - //Initialize with [begin(), pos) old buffer - //the start of the new buffer - new_finish = std::uninitialized_copy - ( copy_move_it(detail::get_pointer(this->members_.m_start)) - , copy_move_it(pos) - , old_finish = new_finish); - constructed_values_destroyer.increment_size(new_finish - old_finish); - //Initialize new objects, starting from previous point - interf.uninitialized_copy_all_to(old_finish = new_finish); - new_finish += n; - constructed_values_destroyer.increment_size(new_finish - old_finish); - //Initialize from the rest of the old buffer, - //starting from previous point - new_finish = std::uninitialized_copy - ( copy_move_it(pos) - , copy_move_it(detail::get_pointer(this->members_.m_start) + this->members_.m_size) - , new_finish); - - //All construction successful, disable rollbacks - constructed_values_destroyer.release(); - scoped_alloc.release(); - //Destroy and deallocate old elements - //If there is allocated memory, destroy and deallocate - if(this->members_.m_start != 0){ - if(!value_traits::trivial_dctr_after_move) - this->destroy_n(detail::get_pointer(this->members_.m_start), this->members_.m_size); - this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); - } - this->members_.m_start = new_start; - this->members_.m_size = new_finish - new_start; - this->members_.m_capacity = new_cap; - } - - void priv_range_insert_expand_backwards - (T* new_start, size_type new_capacity, - T* pos, const size_type n, advanced_insert_aux_int_t &interf) - { - typedef typename value_traits::copy_move_it copy_move_it; - typedef typename value_traits::assign_move_it assign_move_it; - - //Backup old data - T* old_start = detail::get_pointer(this->members_.m_start); - T* old_finish = old_start + this->members_.m_size; - size_type old_size = this->members_.m_size; - - //We can have 8 possibilities: - const size_type elemsbefore = (size_type)(pos - old_start); - const size_type s_before = (size_type)(old_start - new_start); - - //Update the vector buffer information to a safe state - this->members_.m_start = new_start; - this->members_.m_capacity = new_capacity; - this->members_.m_size = 0; - - //If anything goes wrong, this object will destroy - //all the old objects to fulfill previous vector state - typename value_traits::OldArrayDestructor old_values_destroyer(old_start, old_size); - //Check if s_before is big enough to hold the beginning of old data + new data - if(difference_type(s_before) >= difference_type(elemsbefore + n)){ - //Copy first old values before pos, after that the new objects - std::uninitialized_copy(copy_move_it(old_start), copy_move_it(pos), new_start); - this->members_.m_size = elemsbefore; - interf.uninitialized_copy_all_to(new_start + elemsbefore); - this->members_.m_size += n; - //Check if s_before is so big that even copying the old data + new data - //there is a gap between the new data and the old data - if(s_before >= (old_size + n)){ - //Old situation: - // _________________________________________________________ - //| raw_mem | old_begin | old_end | - //| __________________________________|___________|_________| - // - //New situation: - // _________________________________________________________ - //| old_begin | new | old_end | raw_mem | - //|___________|__________|_________|________________________| - // - //Now initialize the rest of memory with the last old values - std::uninitialized_copy - (copy_move_it(pos), copy_move_it(old_finish), new_start + elemsbefore + n); - //All new elements correctly constructed, avoid new element destruction - this->members_.m_size = old_size + n; - //Old values destroyed automatically with "old_values_destroyer" - //when "old_values_destroyer" goes out of scope unless the have trivial - //destructor after move. - if(value_traits::trivial_dctr_after_move) - old_values_destroyer.release(); - } - //s_before is so big that divides old_end - else{ - //Old situation: - // __________________________________________________ - //| raw_mem | old_begin | old_end | - //| ___________________________|___________|_________| - // - //New situation: - // __________________________________________________ - //| old_begin | new | old_end | raw_mem | - //|___________|__________|_________|_________________| - // - //Now initialize the rest of memory with the last old values - //All new elements correctly constructed, avoid new element destruction - size_type raw_gap = s_before - (elemsbefore + n); - //Now initialize the rest of s_before memory with the - //first of elements after new values - std::uninitialized_copy - (copy_move_it(pos), copy_move_it(pos + raw_gap), new_start + elemsbefore + n); - //Update size since we have a contiguous buffer - this->members_.m_size = old_size + s_before; - //All new elements correctly constructed, avoid old element destruction - old_values_destroyer.release(); - //Now copy remaining last objects in the old buffer begin - T *to_destroy = std::copy(assign_move_it(pos + raw_gap), assign_move_it(old_finish), old_start); - //Now destroy redundant elements except if they were moved and - //they have trivial destructor after move - size_type n_destroy = old_finish - to_destroy; - if(!value_traits::trivial_dctr_after_move) - this->destroy_n(to_destroy, n_destroy); - this->members_.m_size -= n_destroy; - } - } - else{ - //Check if we have to do the insertion in two phases - //since maybe s_before is not big enough and - //the buffer was expanded both sides - // - //Old situation: - // _________________________________________________ - //| raw_mem | old_begin + old_end | raw_mem | - //|_________|_____________________|_________________| - // - //New situation with do_after: - // _________________________________________________ - //| old_begin + new + old_end | raw_mem | - //|___________________________________|_____________| - // - //New without do_after: - // _________________________________________________ - //| old_begin + new + old_end | raw_mem | - //|____________________________|____________________| - // - bool do_after = n > s_before; - - //Now we can have two situations: the raw_mem of the - //beginning divides the old_begin, or the new elements: - if (s_before <= elemsbefore) { - //The raw memory divides the old_begin group: - // - //If we need two phase construction (do_after) - //new group is divided in new = new_beg + new_end groups - //In this phase only new_beg will be inserted - // - //Old situation: - // _________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|_________|___________|_________|_________________| - // - //New situation with do_after(1): - //This is not definitive situation, the second phase - //will include - // _________________________________________________ - //| old_begin | new_beg | old_end | raw_mem | - //|___________|_________|_________|_________________| - // - //New situation without do_after: - // _________________________________________________ - //| old_begin | new | old_end | raw_mem | - //|___________|_____|_________|_____________________| - // - //Copy the first part of old_begin to raw_mem - T *start_n = old_start + difference_type(s_before); - std::uninitialized_copy(copy_move_it(old_start), copy_move_it(start_n), new_start); - //The buffer is all constructed until old_end, - //release destroyer and update size - old_values_destroyer.release(); - this->members_.m_size = old_size + s_before; - //Now copy the second part of old_begin overwriting himself - T* next = std::copy(assign_move_it(start_n), assign_move_it(pos), old_start); - if(do_after){ - //Now copy the new_beg elements - interf.copy_some_and_update(next, s_before, true); - } - else{ - //Now copy the all the new elements - interf.copy_all_to(next); - T* move_start = next + n; - //Now displace old_end elements - T* move_end = std::copy(assign_move_it(pos), assign_move_it(old_finish), move_start); - //Destroy remaining moved elements from old_end except if - //they have trivial destructor after being moved - difference_type n_destroy = s_before - n; - if(!value_traits::trivial_dctr_after_move) - this->destroy_n(move_end, n_destroy); - this->members_.m_size -= n_destroy; - } - } - else { - //If we have to expand both sides, - //we will play if the first new values so - //calculate the upper bound of new values - - //The raw memory divides the new elements - // - //If we need two phase construction (do_after) - //new group is divided in new = new_beg + new_end groups - //In this phase only new_beg will be inserted - // - //Old situation: - // _______________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|_______________|___________|_________|_________________| - // - //New situation with do_after(): - // ____________________________________________________ - //| old_begin | new_beg | old_end | raw_mem | - //|___________|_______________|_________|______________| - // - //New situation without do_after: - // ______________________________________________________ - //| old_begin | new | old_end | raw_mem | - //|___________|_____|_________|__________________________| - // - //First copy whole old_begin and part of new to raw_mem - std::uninitialized_copy(copy_move_it(old_start), copy_move_it(pos), new_start); - this->members_.m_size = elemsbefore; - - const size_type mid_n = difference_type(s_before) - elemsbefore; - interf.uninitialized_copy_some_and_update(new_start + elemsbefore, mid_n, true); - this->members_.m_size = old_size + s_before; - //The buffer is all constructed until old_end, - //release destroyer and update size - old_values_destroyer.release(); - - if(do_after){ - //Copy new_beg part - interf.copy_some_and_update(old_start, s_before - mid_n, true); - } - else{ - //Copy all new elements - interf.copy_all_to(old_start); - T* move_start = old_start + (n-mid_n); - //Displace old_end - T* move_end = std::copy(copy_move_it(pos), copy_move_it(old_finish), move_start); - //Destroy remaining moved elements from old_end except if they - //have trivial destructor after being moved - difference_type n_destroy = s_before - n; - if(!value_traits::trivial_dctr_after_move) - this->destroy_n(move_end, n_destroy); - this->members_.m_size -= n_destroy; - } - } - - //This is only executed if two phase construction is needed - //This can be executed without exception handling since we - //have to just copy and append in raw memory and - //old_values_destroyer has been released in phase 1. - if(do_after){ - //The raw memory divides the new elements - // - //Old situation: - // ______________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|______________|___________|____________|______________| - // - //New situation with do_after(1): - // _______________________________________________________ - //| old_begin + new_beg | new_end |old_end | raw_mem | - //|__________________________|_________|________|_________| - // - //New situation with do_after(2): - // ______________________________________________________ - //| old_begin + new | old_end |raw | - //|_______________________________________|_________|____| - // - const size_type n_after = n - s_before; - const difference_type elemsafter = old_size - elemsbefore; - - //We can have two situations: - if (elemsafter > difference_type(n_after)){ - //The raw_mem from end will divide displaced old_end - // - //Old situation: - // ______________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|______________|___________|____________|______________| - // - //New situation with do_after(1): - // _______________________________________________________ - //| old_begin + new_beg | new_end |old_end | raw_mem | - //|__________________________|_________|________|_________| - // - //First copy the part of old_end raw_mem - T* finish_n = old_finish - difference_type(n_after); - std::uninitialized_copy - (copy_move_it(finish_n), copy_move_it(old_finish), old_finish); - this->members_.m_size += n_after; - //Displace the rest of old_end to the new position - std::copy_backward(assign_move_it(pos), assign_move_it(finish_n), old_finish); - //Now overwrite with new_end - //The new_end part is [first + (n - n_after), last) - interf.copy_all_to(pos); - } - else { - //The raw_mem from end will divide new_end part - // - //Old situation: - // _____________________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|______________|___________|____________|_____________________| - // - //New situation with do_after(2): - // _____________________________________________________________ - //| old_begin + new_beg | new_end |old_end | raw_mem | - //|__________________________|_______________|________|_________| - // - size_type mid_last_dist = n_after - elemsafter; - //First initialize data in raw memory - //The new_end part is [first + (n - n_after), last) - interf.uninitialized_copy_some_and_update(old_finish, elemsafter, false); - this->members_.m_size += mid_last_dist; - std::uninitialized_copy(copy_move_it(pos), copy_move_it(old_finish), old_finish + mid_last_dist); - this->members_.m_size += n_after - mid_last_dist; - //Now copy the part of new_end over constructed elements - interf.copy_all_to(pos); - } - } - } - } - - template - void priv_range_insert(const_iterator pos, InIt first, InIt last, std::input_iterator_tag) - { - for(;first != last; ++first){ - this->insert(pos, detail::move_impl(value_type(*first))); - } - } - - template - void priv_assign_aux(InIt first, InIt last, std::input_iterator_tag) - { - //Overwrite all elements we can from [first, last) - iterator cur = begin(); - for ( ; first != last && cur != end(); ++cur, ++first){ - *cur = *first; - } - - if (first == last){ - //There are no more elements in the sequence, erase remaining - this->erase(cur, cend()); - } - else{ - //There are more elements in the range, insert the remaining ones - this->insert(this->cend(), first, last); - } - } - - template - void priv_assign_aux(FwdIt first, FwdIt last, - std::forward_iterator_tag) - { - size_type n = std::distance(first, last); - //Check if we have enough memory or try to expand current memory - size_type remaining = this->members_.m_capacity - this->members_.m_size; - bool same_buffer_start; - std::pair ret; - size_type real_cap = this->members_.m_capacity; - - if (n <= remaining){ - same_buffer_start = true; - } - else{ - //There is not enough memory, allocate a new buffer - size_type new_cap = this->next_capacity(n); - ret = this->allocation_command - (allocate_new | expand_fwd | expand_bwd, - this->size() + n, new_cap, real_cap, this->members_.m_start); - same_buffer_start = ret.second && this->members_.m_start == ret.first; - if(same_buffer_start){ - this->members_.m_capacity = real_cap; - } - } - - if(same_buffer_start){ - T *start = detail::get_pointer(this->members_.m_start); - if (this->size() >= n){ - //There is memory, but there are more old elements than new ones - //Overwrite old elements with new ones - std::copy(first, last, start); - //Destroy remaining old elements - this->destroy_n(start + n, this->members_.m_size - n); - this->members_.m_size = n; - } - else{ - //There is memory, but there are less old elements than new ones - //First overwrite some old elements with new ones - FwdIt mid = first; - std::advance(mid, this->size()); - T *end = std::copy(first, mid, start); - //Initialize the remaining new elements in the uninitialized memory - std::uninitialized_copy(mid, last, end); - this->members_.m_size = n; - } - } - else if(!ret.second){ - typename value_traits::UCopiedArrayDeallocator scoped_alloc(ret.first, this->alloc(), real_cap); - std::uninitialized_copy(first, last, detail::get_pointer(ret.first)); - scoped_alloc.release(); - //Destroy and deallocate old buffer - if(this->members_.m_start != 0){ - this->destroy_n(detail::get_pointer(this->members_.m_start), this->members_.m_size); - this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); - } - this->members_.m_start = ret.first; - this->members_.m_size = n; - this->members_.m_capacity = real_cap; - } - else{ - //Backwards expansion - //If anything goes wrong, this object will destroy old objects - T *old_start = detail::get_pointer(this->members_.m_start); - size_type old_size = this->members_.m_size; - typename value_traits::OldArrayDestructor old_values_destroyer(old_start, old_size); - //If something goes wrong size will be 0 - //but holding the whole buffer - this->members_.m_size = 0; - this->members_.m_start = ret.first; - this->members_.m_capacity = real_cap; - - //Backup old buffer data - size_type old_offset = old_start - detail::get_pointer(ret.first); - size_type first_count = min_value(n, old_offset); - - FwdIt mid = first; - std::advance(mid, first_count); - std::uninitialized_copy(first, mid, detail::get_pointer(ret.first)); - - if(old_offset > n){ - //All old elements will be destroyed by "old_values_destroyer" - this->members_.m_size = n; - } - else{ - //We have constructed objects from the new begin until - //the old end so release the rollback destruction - old_values_destroyer.release(); - this->members_.m_start = ret.first; - this->members_.m_size = first_count + old_size; - //Now overwrite the old values - size_type second_count = min_value(old_size, n - first_count); - FwdIt mid2 = mid; - std::advance(mid2, second_count); - std::copy(mid, mid2, old_start); - - //Check if we still have to append elements in the - //uninitialized end - if(second_count == old_size){ - std::copy(mid2, last, old_start + old_size); - } - else{ - //We have to destroy some old values - this->destroy_n - (old_start + second_count, old_size - second_count); - this->members_.m_size = n; - } - this->members_.m_size = n; - } - } - } - - template - void priv_assign_dispatch(Integer n, Integer val, detail::true_) - { this->assign((size_type) n, (T) val); } - - template - void priv_assign_dispatch(InIt first, InIt last, detail::false_) - { - //Dispatch depending on integer/iterator - typedef typename - std::iterator_traits::iterator_category ItCat; - this->priv_assign_aux(first, last, ItCat()); - } - - template - void priv_insert_dispatch(const_iterator pos, Integer n, Integer val, detail::true_) - { this->insert(pos, (size_type)n, (T)val); } - - template - void priv_insert_dispatch(const_iterator pos, InIt first, - InIt last, detail::false_) - { - //Dispatch depending on integer/iterator - typedef typename - std::iterator_traits::iterator_category ItCat; - this->priv_range_insert(pos.get_ptr(), first, last, ItCat()); - } - - void priv_check_range(size_type n) const - { - //If n is out of range, throw an out_of_range exception - if (n >= size()) - throw std::out_of_range("vector::at"); - } - - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - public: - unsigned int num_expand_fwd; - unsigned int num_expand_bwd; - unsigned int num_shrink; - unsigned int num_alloc; - void reset_alloc_stats() - { num_expand_fwd = num_expand_bwd = num_alloc = 0, num_shrink = 0; } - #endif - /// @endcond -}; - -template -inline bool -operator==(const vector& x, const vector& y) -{ - //Check first size and each element if needed - return x.size() == y.size() && - std::equal(x.begin(), x.end(), y.begin()); -} - -template -inline bool -operator!=(const vector& x, const vector& y) -{ - //Check first size and each element if needed - return x.size() != y.size() || - !std::equal(x.begin(), x.end(), y.begin()); -} - -template -inline bool -operator<(const vector& x, const vector& y) -{ - return std::lexicographical_compare(x.begin(), x.end(), - y.begin(), y.end()); -} - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(vector& x, vector& y) -{ x.swap(y); } - -template -inline void swap(detail::moved_object > x, vector& y) -{ x.get().swap(y); } - -template -inline void swap(vector &x, detail::moved_object > y) -{ x.swap(y.get()); } -#else -template -inline void swap(vector&&x, vector&&y) -{ x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::value }; -}; -/// @endcond +using boost::interprocess_container::vector; } //namespace interprocess { } //namespace boost { #include -#endif // #ifndef BOOST_INTERPROCESS_VECTOR_HPP +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP diff --git a/include/boost/interprocess/containers/version_type.hpp b/include/boost/interprocess/containers/version_type.hpp new file mode 100644 index 0000000..06e7419 --- /dev/null +++ b/include/boost/interprocess/containers/version_type.hpp @@ -0,0 +1,33 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_VERSION_TYPE_HPP +#define BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +using boost::interprocess_container::containers_detail::version_type; +using boost::interprocess_container::containers_detail::version; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP + diff --git a/include/boost/interprocess/detail/atomic.hpp b/include/boost/interprocess/detail/atomic.hpp index 094bc0c..b8a8086 100644 --- a/include/boost/interprocess/detail/atomic.hpp +++ b/include/boost/interprocess/detail/atomic.hpp @@ -48,7 +48,7 @@ inline boost::uint32_t atomic_cas32 } //namespace interprocess{ } //namespace boost{ -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) #include diff --git a/include/boost/interprocess/detail/file_wrapper.hpp b/include/boost/interprocess/detail/file_wrapper.hpp index 22f92e9..091a14f 100644 --- a/include/boost/interprocess/detail/file_wrapper.hpp +++ b/include/boost/interprocess/detail/file_wrapper.hpp @@ -24,7 +24,12 @@ namespace detail{ class file_wrapper { + /// @cond + file_wrapper(file_wrapper&); + file_wrapper & operator=(file_wrapper&); + /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(file_wrapper) //!Default constructor. //!Represents an empty file_wrapper. @@ -49,34 +54,18 @@ class file_wrapper //!Moves the ownership of "moved"'s file to *this. //!After the call, "moved" does not represent any file. //!Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - file_wrapper - (detail::moved_object moved) - { this->swap(moved.get()); } - #else - file_wrapper(file_wrapper &&moved) + file_wrapper(BOOST_INTERPROCESS_RV_REF(file_wrapper) moved) { this->swap(moved); } - #endif //!Moves the ownership of "moved"'s file to *this. //!After the call, "moved" does not represent any file. //!Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - file_wrapper &operator= - (detail::moved_object moved) + file_wrapper &operator=(BOOST_INTERPROCESS_RV_REF(file_wrapper) moved) { - file_wrapper tmp(moved); + file_wrapper tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } - #else - file_wrapper &operator=(file_wrapper &&moved) - { - file_wrapper tmp(detail::move_impl(moved)); - this->swap(tmp); - return *this; - } - #endif //!Swaps to file_wrappers. //!Does not throw diff --git a/include/boost/interprocess/detail/managed_memory_impl.hpp b/include/boost/interprocess/detail/managed_memory_impl.hpp index ab0744c..72645e2 100644 --- a/include/boost/interprocess/detail/managed_memory_impl.hpp +++ b/include/boost/interprocess/detail/managed_memory_impl.hpp @@ -98,7 +98,7 @@ class basic_managed_memory_impl segment_manager::char_ptr_holder_t char_ptr_holder_t; //Experimental. Don't use. - typedef typename segment_manager::multiallocation_iterator multiallocation_iterator; + typedef typename segment_manager::multiallocation_chain multiallocation_chain; /// @endcond @@ -291,7 +291,7 @@ class basic_managed_memory_impl template std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0) { @@ -310,21 +310,25 @@ class basic_managed_memory_impl //Experimental. Don't use. //!Allocates n_elements of elem_size bytes. - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements) + multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements) { return mp_header->allocate_many(elem_bytes, num_elements); } //!Allocates n_elements, each one of elem_sizes[i] bytes. - multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements) + multiallocation_chain allocate_many(const std::size_t *elem_sizes, std::size_t n_elements) { return mp_header->allocate_many(elem_sizes, n_elements); } //!Allocates n_elements of elem_size bytes. - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements, std::nothrow_t nothrow) + multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements, std::nothrow_t nothrow) { return mp_header->allocate_many(elem_bytes, num_elements, nothrow); } //!Allocates n_elements, each one of elem_sizes[i] bytes. - multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::nothrow_t nothrow) + multiallocation_chain allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::nothrow_t nothrow) { return mp_header->allocate_many(elem_sizes, n_elements, nothrow); } + //!Allocates n_elements, each one of elem_sizes[i] bytes. + void deallocate_many(multiallocation_chain chain) + { return mp_header->deallocate_many(boost::interprocess::move(chain)); } + /// @endcond //!Marks previously allocated memory as free. Never throws. diff --git a/include/boost/interprocess/detail/managed_multi_shared_memory.hpp b/include/boost/interprocess/detail/managed_multi_shared_memory.hpp index 3a3b0c9..948e865 100644 --- a/include/boost/interprocess/detail/managed_multi_shared_memory.hpp +++ b/include/boost/interprocess/detail/managed_multi_shared_memory.hpp @@ -315,21 +315,21 @@ class basic_managed_multi_shared_memory case create_open_func::DoCreate: { managed_impl shm(create_only, name, size, read_write, addr, func); - mshm = detail::move_impl(shm); + mshm = boost::interprocess::move(shm); } break; case create_open_func::DoOpen: { managed_impl shm(open_only, name,read_write, addr, func); - mshm = detail::move_impl(shm); + mshm = boost::interprocess::move(shm); } break; case create_open_func::DoOpenOrCreate: { managed_impl shm(open_or_create, name, size, read_write, addr, func); - mshm = detail::move_impl(shm); + mshm = boost::interprocess::move(shm); } break; @@ -339,7 +339,7 @@ class basic_managed_multi_shared_memory } //This can throw. - m_shmem_list.push_back(detail::move_impl(mshm)); + m_shmem_list.push_back(boost::interprocess::move(mshm)); return true; } BOOST_CATCH(const std::bad_alloc&){ diff --git a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp index caa7741..d71ec1b 100644 --- a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp +++ b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp @@ -37,8 +37,8 @@ template class managed_open_or_create_impl { //Non-copyable - managed_open_or_create_impl(const managed_open_or_create_impl &); - managed_open_or_create_impl &operator=(const managed_open_or_create_impl &); + managed_open_or_create_impl(managed_open_or_create_impl &); + managed_open_or_create_impl &operator=(managed_open_or_create_impl &); enum { @@ -49,6 +49,7 @@ class managed_open_or_create_impl }; public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(managed_open_or_create_impl) static const std::size_t ManagedOpenOrCreateUserOffset = @@ -154,34 +155,16 @@ class managed_open_or_create_impl , construct_func); } - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - managed_open_or_create_impl(detail::moved_object moved) - { this->swap(moved.get()); } - #else - managed_open_or_create_impl(managed_open_or_create_impl &&moved) + managed_open_or_create_impl(BOOST_INTERPROCESS_RV_REF(managed_open_or_create_impl) moved) { this->swap(moved); } - #endif - //!Move assignment. If *this owns a memory mapped region, it will be - //!destroyed and it will take ownership of "other"'s memory mapped region. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - managed_open_or_create_impl &operator=(detail::moved_object moved) + managed_open_or_create_impl &operator=(BOOST_INTERPROCESS_RV_REF(managed_open_or_create_impl) moved) { - managed_open_or_create_impl tmp(moved); + managed_open_or_create_impl tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } - #else - managed_open_or_create_impl &operator=(managed_open_or_create_impl &&moved) - { - managed_open_or_create_impl tmp(detail::move_impl(moved)); - this->swap(tmp); - return *this; - } - #endif - ~managed_open_or_create_impl() {} @@ -437,20 +420,6 @@ inline void swap(managed_open_or_create_impl &x } //namespace detail { - -///@cond - -//!Trait class to detect if a type is -//!movable -template - -struct is_movable > -{ - enum { value = true }; -}; - -///@endcond - } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/detail/move.hpp b/include/boost/interprocess/detail/move.hpp index ca5c0e2..9ecd69f 100644 --- a/include/boost/interprocess/detail/move.hpp +++ b/include/boost/interprocess/detail/move.hpp @@ -1,175 +1,747 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006. 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) +// (C) Copyright David Abrahams, Vicente Botet, Ion Gaztanaga 2009. +// 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. +// See http://www.boost.org/libs/move for documentation. // ////////////////////////////////////////////////////////////////////////////// +// +// Parts of this file come from Adobe's Move library: +// +// Copyright 2005-2007 Adobe Systems Incorporated +// Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt +// or a copy at http://stlab.adobe.com/licenses.html) +// +////////////////////////////////////////////////////////////////////////////// + +//! \file #ifndef BOOST_INTERPROCESS_MOVE_HPP #define BOOST_INTERPROCESS_MOVE_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif - -#include -#include -#include -#include - -//!\file -//!Describes a function and a type to emulate move semantics. +#include +#include //copy, copy_backward +#include //uninitialized_copy +#include //std::iterator +#include +#include +#include namespace boost { namespace interprocess { +namespace move_detail { -//!Trait class to detect if a type is -//!movable template -struct is_movable +struct identity { - enum { value = false }; + typedef T type; }; +template +class is_convertible +{ + typedef char true_t; + class false_t { char dummy[2]; }; + static true_t dispatch(U); + static false_t dispatch(...); + static T trigger(); + public: + enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) }; +}; + +} //namespace move_detail { } //namespace interprocess { } //namespace boost { -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - -#include -#include +#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_MOVE_DOXYGEN_INVOKED) namespace boost { namespace interprocess { -namespace detail { -//!An object that represents a -//!moved object. -template -struct moved_object -{ - moved_object(const T &obj) - : m_obj(const_cast(&obj)) - {} - - T &get() const - { return *m_obj; } - - private: - T *m_obj; -}; - -// Metafunction that, given movable T, provides move_source, else T&. -template -struct move_type +////////////////////////////////////////////////////////////////////////////// +// +// struct rv +// +////////////////////////////////////////////////////////////////////////////// +template +class rv : public T { - public: // metafunction result - typedef typename if_, moved_object, T&>::type type; -}; - -template -class move_return -{ - typedef moved_object moved_type; - private: - mutable T m_moved; - + rv(); + ~rv(); + rv(rv const&); + void operator=(rv const&); public: - typedef T type; - - move_return(const T& returned) - : m_moved(moved_object(returned)) - {} - - move_return(const move_return& operand) - : m_moved(const_cast(operand)) - {} - - operator moved_type() const - { return moved_type(m_moved); } + //T &get() { return *this; } }; -template -struct return_type +////////////////////////////////////////////////////////////////////////////// +// +// move_detail::is_rv +// +////////////////////////////////////////////////////////////////////////////// + +namespace move_detail { + +template +struct is_rv { - public: // metafunction result - - typedef typename if_, move_return, T>::type type; + static const bool value = false; }; -} //namespace detail { -} //namespace interprocess { -} //namespace boost { +template +struct is_rv< rv > +{ + static const bool value = true; +}; -namespace boost { -namespace interprocess { +} //namespace move_detail { -namespace detail{ +////////////////////////////////////////////////////////////////////////////// +// +// is_movable +// +////////////////////////////////////////////////////////////////////////////// +template +class is_movable +{ + public: + static const bool value = move_detail::is_convertible&>::value; +}; -//!A function that converts an object to a moved object so that -//!it can match a function taking a detail::moved_object object. -template -typename detail::move_type::type move_impl(const Object &object) -{ - typedef typename detail::move_type::type type; - return type(object); +template +class is_movable< rv > +{ + public: + static const bool value = false; +}; + +////////////////////////////////////////////////////////////////////////////// +// +// move() +// +////////////////////////////////////////////////////////////////////////////// +template +typename boost::disable_if, T&>::type move(T& x) +{ + return x; } template -inline const T& forward_impl(const T &t) -{ return t; } +typename enable_if, rv&>::type move(T& x) +{ + return reinterpret_cast& >(x); +} template -inline T& forward_impl(T &t) -{ return t; } +typename enable_if, rv&>::type move(const rv& x) +{ + return const_cast& >(x); +} + +////////////////////////////////////////////////////////////////////////////// +// +// forward() +// +////////////////////////////////////////////////////////////////////////////// template -inline detail::moved_object forward_impl(detail::moved_object &t) -{ return t; } +typename enable_if, T &>::type + forward(const typename move_detail::identity::type &x) +{ + return const_cast(x); +} -} //namespace detail { +/* +template +typename enable_if, T &>::type +forward(typename move_detail::identity::type &x) +{ + return x; +} -//!A function that converts an object to a moved object so that -//!it can match a function taking a detail::moved_object object. -template -typename detail::move_type::type move(const Object &object) -{ return detail::move_impl(object); } +template +typename disable_if, T &>::type + forward(typename move_detail::identity::type &x) +{ + return x; +} +*/ +template +typename disable_if, const T &>::type + forward(const typename move_detail::identity::type &x) +{ + return x; +} +////////////////////////////////////////////////////////////////////////////// +// +// BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION +// +////////////////////////////////////////////////////////////////////////////// +#define BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(TYPE)\ + operator boost::interprocess::rv&() \ + { return reinterpret_cast& >(*this); }\ +// + + +#define BOOST_INTERPROCESS_RV_REF(TYPE)\ + boost::interprocess::rv< TYPE >& \ +// + +#define BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(TYPE, ARG1, ARG2)\ + boost::interprocess::rv< TYPE >& \ +// + +#define BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(TYPE, ARG1, ARG2, ARG3)\ + boost::interprocess::rv< TYPE >& \ +// + +#define BOOST_INTERPROCESS_FWD_REF(TYPE)\ + const TYPE & \ +// } //namespace interprocess { -} //namespace boost { +} //namespace boost -#else //#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#else //BOOST_HAS_RVALUE_REFS -#include +#include namespace boost { namespace interprocess { -namespace detail { +////////////////////////////////////////////////////////////////////////////// +// +// is_movable +// +////////////////////////////////////////////////////////////////////////////// -template -inline typename detail::remove_reference::type&& move_impl(T&& t) +//! For compilers with rvalue references, this traits class returns true +//! if T && is convertible to T. +//! +//! For other compilers returns true if T is convertible to boost::interprocess::rv& +template +class is_movable +{ + public: + static const bool value = move_detail::is_convertible::value; +}; + +////////////////////////////////////////////////////////////////////////////// +// +// move +// +////////////////////////////////////////////////////////////////////////////// + + +#if defined(BOOST_MOVE_DOXYGEN_INVOKED) +//! This function provides a way to convert a reference into a rvalue reference +//! in compilers with rvalue reference. For other compilers converts T & into +//! boost::interprocess::rv & so that move emulation is activated. +template inline +rvalue_reference move (input_reference); +#else +template inline +typename remove_reference::type&& move(T&& t) { return t; } +#endif -template -inline T&& forward_impl(typename detail::identity::type&& t) +////////////////////////////////////////////////////////////////////////////// +// +// forward +// +////////////////////////////////////////////////////////////////////////////// + + +#if defined(BOOST_MOVE_DOXYGEN_INVOKED) +//! This function provides limited form of forwarding that is usually enough for +//! in-place construction and avoids the exponential overloading necessary for +//! perfect forwarding in C++03. +//! +//! For compilers with rvalue references this function provides perfect forwarding. +//! +//! Otherwise: +//! * If input_reference binds to const boost::interprocess::rv & then it output_reference is +//! boost::rev & +//! +//! * Else, input_reference is equal to output_reference is equal to input_reference. +template inline output_reference forward(input_reference); +#else +template inline +T&& forward (typename move_detail::identity::type&& t) { return t; } +#endif -} //namespace detail { +////////////////////////////////////////////////////////////////////////////// +// +// BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION +// +////////////////////////////////////////////////////////////////////////////// -template -inline typename detail::remove_reference::type&& move(T&& t) -{ return t; } +//! This macro expands to nothing for compilers with rvalue references. +//! Otherwise expands to: +//! \code +//! operator boost::interprocess::rv&() +//! { return static_cast& >(*this); } +//! \endcode +#define BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(TYPE)\ +// + +#define BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(TYPE, ARG1, ARG2)\ + TYPE && \ +// + +#define BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(TYPE, ARG1, ARG2, ARG3)\ + TYPE && \ +// + +//! This macro expands to T&& for compilers with rvalue references. +//! Otherwise expands to boost::interprocess::rv &. +#define BOOST_INTERPROCESS_RV_REF(TYPE)\ + TYPE && \ +// + +//! This macro expands to T&& for compilers with rvalue references. +//! Otherwise expands to const T &. +#define BOOST_INTERPROCESS_FWD_REF(TYPE)\ + TYPE && \ +// } //namespace interprocess { } //namespace boost { -#endif //#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#endif //BOOST_HAS_RVALUE_REFS -#include +namespace boost { +namespace interprocess { -#endif //#ifndef BOOST_INTERPROCESS_MOVE_HPP +////////////////////////////////////////////////////////////////////////////// +// +// move_iterator +// +////////////////////////////////////////////////////////////////////////////// + +//! Class template move_iterator is an iterator adaptor with the same behavior +//! as the underlying iterator except that its dereference operator implicitly +//! converts the value returned by the underlying iterator's dereference operator +//! to an rvalue reference. Some generic algorithms can be called with move +//! iterators to replace copying with moving. +template +class move_iterator +{ + public: + typedef It iterator_type; + typedef typename std::iterator_traits::value_type value_type; + #if defined(BOOST_HAS_RVALUE_REFS) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + typedef value_type && reference; + #else + typedef typename boost::mpl::if_ + < boost::interprocess::is_movable + , boost::interprocess::rv& + , value_type & >::type reference; + #endif + typedef typename std::iterator_traits::pointer pointer; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename std::iterator_traits::iterator_category iterator_category; + + move_iterator() + {} + + explicit move_iterator(It i) + : m_it(i) + {} + + template + move_iterator(const move_iterator& u) + : m_it(u.base()) + {} + + iterator_type base() const + { return m_it; } + + reference operator*() const + { + #if defined(BOOST_HAS_RVALUE_REFS) + return *m_it; + #else + return boost::interprocess::move(*m_it); + #endif + } + + pointer operator->() const + { return m_it; } + + move_iterator& operator++() + { ++m_it; return *this; } + + move_iterator operator++(int) + { move_iterator tmp(*this); ++(*this); return tmp; } + + move_iterator& operator--() + { --m_it; return *this; } + + move_iterator operator--(int) + { move_iterator tmp(*this); --(*this); return tmp; } + + move_iterator operator+ (difference_type n) const + { return move_iterator(m_it + n); } + + move_iterator& operator+=(difference_type n) + { m_it += n; return *this; } + + move_iterator operator- (difference_type n) const + { return move_iterator(m_it - n); } + + move_iterator& operator-=(difference_type n) + { m_it -= n; return *this; } + + reference operator[](difference_type n) const + { + #if defined(BOOST_HAS_RVALUE_REFS) + return m_it[n]; + #else + return boost::interprocess::move(m_it[n]); + #endif + } + + friend bool operator==(const move_iterator& x, const move_iterator& y) + { return x.base() == y.base(); } + + friend bool operator!=(const move_iterator& x, const move_iterator& y) + { return x.base() != y.base(); } + + friend bool operator< (const move_iterator& x, const move_iterator& y) + { return x.base() < y.base(); } + + friend bool operator<=(const move_iterator& x, const move_iterator& y) + { return x.base() <= y.base(); } + + friend bool operator> (const move_iterator& x, const move_iterator& y) + { return x.base() > y.base(); } + + friend bool operator>=(const move_iterator& x, const move_iterator& y) + { return x.base() >= y.base(); } + + friend difference_type operator-(const move_iterator& x, const move_iterator& y) + { return x.base() - y.base(); } + + friend move_iterator operator+(difference_type n, const move_iterator& x) + { return move_iterator(x.base() + n); } + + private: + It m_it; +}; + + +//is_move_iterator +namespace move_detail { + +template +struct is_move_iterator +{ + static const bool value = false; +}; + +template +struct is_move_iterator< ::boost::interprocess::move_iterator > +{ + static const bool value = true; +}; + +} //namespace move_detail { + +////////////////////////////////////////////////////////////////////////////// +// +// move_iterator +// +////////////////////////////////////////////////////////////////////////////// + +//! +//! Returns: move_iterator(i). +template +move_iterator make_move_iterator(const It &it) +{ return move_iterator(it); } + +////////////////////////////////////////////////////////////////////////////// +// +// back_move_insert_iterator +// +////////////////////////////////////////////////////////////////////////////// + + +//! A move insert iterator that move constructs elements at the +//! back of a container +template // C models Container +class back_move_insert_iterator + : public std::iterator +{ + C* container_m; + + public: + typedef C container_type; + + explicit back_move_insert_iterator(C& x) : container_m(&x) { } + + back_move_insert_iterator& operator=(typename C::reference x) + { container_m->push_back(boost::interprocess::move(x)); return *this; } + + back_move_insert_iterator& operator*() { return *this; } + back_move_insert_iterator& operator++() { return *this; } + back_move_insert_iterator& operator++(int) { return *this; } +}; + +//! +//! Returns: back_move_insert_iterator(x). +template // C models Container +inline back_move_insert_iterator back_move_inserter(C& x) +{ + return back_move_insert_iterator(x); +} + +////////////////////////////////////////////////////////////////////////////// +// +// front_move_insert_iterator +// +////////////////////////////////////////////////////////////////////////////// + +//! A move insert iterator that move constructs elements int the +//! front of a container +template // C models Container +class front_move_insert_iterator + : public std::iterator +{ + C* container_m; + +public: + typedef C container_type; + + explicit front_move_insert_iterator(C& x) : container_m(&x) { } + + front_move_insert_iterator& operator=(typename C::reference x) + { container_m->push_front(boost::interprocess::move(x)); return *this; } + + front_move_insert_iterator& operator*() { return *this; } + front_move_insert_iterator& operator++() { return *this; } + front_move_insert_iterator& operator++(int) { return *this; } +}; + +//! +//! Returns: front_move_insert_iterator(x). +template // C models Container +inline front_move_insert_iterator front_move_inserter(C& x) +{ + return front_move_insert_iterator(x); +} + +////////////////////////////////////////////////////////////////////////////// +// +// insert_move_iterator +// +////////////////////////////////////////////////////////////////////////////// +template // C models Container +class move_insert_iterator + : public std::iterator +{ + C* container_m; + typename C::iterator pos_; + + public: + typedef C container_type; + + explicit move_insert_iterator(C& x, typename C::iterator pos) + : container_m(&x), pos_(pos) + {} + + move_insert_iterator& operator=(typename C::reference x) + { + pos_ = container_m->insert(pos_, boost::interprocess::move(x)); + ++pos_; + return *this; + } + + move_insert_iterator& operator*() { return *this; } + move_insert_iterator& operator++() { return *this; } + move_insert_iterator& operator++(int) { return *this; } +}; + +//! +//! Returns: move_insert_iterator(x, it). +template // C models Container +inline move_insert_iterator move_inserter(C& x, typename C::iterator it) +{ + return move_insert_iterator(x, it); +} + +////////////////////////////////////////////////////////////////////////////// +// +// move +// +////////////////////////////////////////////////////////////////////////////// + + +//! Effects: Moves elements in the range [first,last) into the range [result,result + (last - +//! first)) starting from first and proceeding to last. For each non-negative integer n < (last-first), +//! performs *(result + n) = boost::interprocess::move (*(first + n)). +//! +//! Effects: result + (last - first). +//! +//! Requires: result shall not be in the range [first,last). +//! +//! Complexity: Exactly last - first move assignments. +template // O models OutputIterator +O move(I f, I l, O result) +{ + while (f != l) { + *result = boost::interprocess::move(*f); + ++f; ++result; + } + return result; +} + +////////////////////////////////////////////////////////////////////////////// +// +// move_backward +// +////////////////////////////////////////////////////////////////////////////// + +//! Effects: Moves elements in the range [first,last) into the range +//! [result - (last-first),result) starting from last - 1 and proceeding to +//! first. For each positive integer n <= (last - first), +//! performs *(result - n) = boost::interprocess::move(*(last - n)). +//! +//! Requires: result shall not be in the range [first,last). +//! +//! Returns: result - (last - first). +//! +//! Complexity: Exactly last - first assignments. +template // O models BidirectionalIterator +O move_backward(I f, I l, O result) +{ + while (f != l) { + --l; --result; + *result = boost::interprocess::move(*l); + } + return result; +} + +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_move +// +////////////////////////////////////////////////////////////////////////////// + +//! Effects: +//! \code +//! for (; first != last; ++result, ++first) +//! new (static_cast(&*result)) +//! typename iterator_traits::value_type(boost::interprocess::move(*first)); +//! \endcode +//! +//! Returns: result +template + // F models ForwardIterator +F uninitialized_move(I f, I l, F r + /// @cond + ,typename enable_if::value_type> >::type* = 0 + /// @endcond + ) +{ + typedef typename std::iterator_traits::value_type input_value_type; + while (f != l) { + ::new(static_cast(&*r)) input_value_type(boost::interprocess::move(*f)); + ++f; ++r; + } + return r; +} + +/// @cond + +template + // F models ForwardIterator +F uninitialized_move(I f, I l, F r, + typename disable_if::value_type> >::type* = 0) +{ + return std::uninitialized_copy(f, l, r); +} + +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_copy_or_move +// +////////////////////////////////////////////////////////////////////////////// + +namespace move_detail { + +template + // F models ForwardIterator +F uninitialized_move_move_iterator(I f, I l, F r, + typename enable_if< is_movable >::type* = 0) +{ + return boost::interprocess::uninitialized_move(f, l, r); +} + +template + // F models ForwardIterator +F uninitialized_move_move_iterator(I f, I l, F r, + typename disable_if< is_movable >::type* = 0) +{ + return std::uninitialized_copy(f.base(), l.base(), r); +} + +} //namespace move_detail { + +template + // F models ForwardIterator +F uninitialized_copy_or_move(I f, I l, F r, + typename enable_if< move_detail::is_move_iterator >::type* = 0) +{ + return boost::interprocess::move_detail::uninitialized_move_move_iterator(f, l, r); +} + +/// @endcond + +//! Effects: +//! \code +//! for (; first != last; ++result, ++first) +//! new (static_cast(&*result)) +//! typename iterator_traits::value_type(*first); +//! \endcode +//! +//! Returns: result +//! +//! Note: This function is provided because +//! std::uninitialized_copy from some STL implementations +//! is not compatible with move_iterator +template + // F models ForwardIterator +F uninitialized_copy_or_move(I f, I l, F r + /// @cond + ,typename disable_if< move_detail::is_move_iterator >::type* = 0 + /// @endcond + ) +{ + return std::uninitialized_copy(f, l, r); +} + +///has_trivial_destructor_after_move<> == true_type +///specialization for optimizations +template +struct has_trivial_destructor_after_move + : public boost::has_trivial_destructor +{}; + +} //namespace interprocess { +} //namespace boost { + +#endif //#ifndef BOOST_INTERPROCESS_MOVE_HPP diff --git a/include/boost/interprocess/detail/move_iterator.hpp b/include/boost/interprocess/detail/move_iterator.hpp deleted file mode 100644 index 4c9f282..0000000 --- a/include/boost/interprocess/detail/move_iterator.hpp +++ /dev/null @@ -1,138 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006. 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_MOVE_ITERATOR_HPP_INCLUDED -#define BOOST_INTERPROCESS_MOVE_ITERATOR_HPP_INCLUDED - -#include -#include - -namespace boost{ -namespace interprocess{ -namespace detail{ - -template -class move_iterator -{ - public: - typedef It iterator_type; - typedef typename std::iterator_traits::value_type value_type; - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - typedef typename move_type::type reference; - #else - typedef value_type && reference; - #endif - typedef typename std::iterator_traits::pointer pointer; - typedef typename std::iterator_traits::difference_type difference_type; - typedef typename std::iterator_traits::iterator_category iterator_category; - - move_iterator() - {} - - explicit move_iterator(It i) - : m_it(i) - {} - - template - move_iterator(const move_iterator& u) - : m_it(u.base()) - {} - - const iterator_type &base() const - { return m_it; } - - iterator_type &base() - { return m_it; } - - reference operator*() const - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - { return detail::move_impl(*m_it); } - #else - { return *m_it; } - #endif - - pointer operator->() const - { return m_it; } - - move_iterator& operator++() - { ++m_it; return *this; } - - move_iterator operator++(int) - { move_iterator tmp(*this); ++(*this); return tmp; } - - move_iterator& operator--() - { --m_it; return *this; } - - move_iterator operator--(int) - { move_iterator tmp(*this); --(*this); return tmp; } - - move_iterator operator+ (difference_type n) const - { return move_iterator(m_it + n); } - - move_iterator& operator+=(difference_type n) - { m_it += n; return *this; } - - move_iterator operator- (difference_type n) const - { return move_iterator(m_it - n); } - - move_iterator& operator-=(difference_type n) - { m_it -= n; return *this; } - - reference operator[](difference_type n) const - { return detail::move_impl(m_it[n]); } - - private: - It m_it; -}; - -template inline -bool operator==(const move_iterator& x, const move_iterator& y) -{ return x.base() == y.base(); } - -template inline -bool operator!=(const move_iterator& x, const move_iterator& y) -{ return x.base() != y.base(); } - -template inline -bool operator< (const move_iterator& x, const move_iterator& y) -{ return x.base() < y.base(); } - -template inline -bool operator<=(const move_iterator& x, const move_iterator& y) -{ return x.base() <= y.base(); } - -template inline -bool operator> (const move_iterator& x, const move_iterator& y) -{ return x.base() > y.base(); } - -template inline -bool operator>=(const move_iterator& x, const move_iterator& y) -{ return x.base() >= y.base(); } - -template inline -typename move_iterator::difference_type - operator-(const move_iterator& x, const move_iterator& y) -{ return x.base() - y.base(); } - -template inline -move_iterator - operator+(typename move_iterator::difference_type n - ,const move_iterator& x) -{ return move_iterator(x.base() + n); } - -template -move_iterator make_move_iterator(const It &it) -{ return move_iterator(it); } - -} //namespace detail{ -} //namespace interprocess{ -} //namespace boost{ - -#endif //#ifndef BOOST_INTERPROCESS_MOVE_ITERATOR_HPP_INCLUDED diff --git a/include/boost/interprocess/detail/mpl.hpp b/include/boost/interprocess/detail/mpl.hpp index dfdd38c..364a54d 100644 --- a/include/boost/interprocess/detail/mpl.hpp +++ b/include/boost/interprocess/detail/mpl.hpp @@ -59,6 +59,9 @@ struct enable_if_c {}; template struct enable_if : public enable_if_c {}; +template +struct disable_if : public enable_if_c {}; + template class is_convertible { @@ -105,7 +108,8 @@ template struct select1st // : public std::unary_function { - const typename Pair::first_type& operator()(const Pair& x) const + template + const typename Pair::first_type& operator()(const OtherPair& x) const { return x.first; } const typename Pair::first_type& operator()(const typename Pair::first_type& x) const diff --git a/include/boost/interprocess/detail/named_proxy.hpp b/include/boost/interprocess/detail/named_proxy.hpp index b4df4da..b16cf1d 100644 --- a/include/boost/interprocess/detail/named_proxy.hpp +++ b/include/boost/interprocess/detail/named_proxy.hpp @@ -72,11 +72,11 @@ struct CtorNArg : public placement_destroy private: template void construct(void *mem, detail::true_, const index_tuple&) - { new((void*)mem)T(*detail::forward_impl(get(args_))...); } + { new((void*)mem)T(*boost::interprocess::forward(get(args_))...); } template void construct(void *mem, detail::false_, const index_tuple&) - { new((void*)mem)T(detail::forward_impl(get(args_))...); } + { new((void*)mem)T(boost::interprocess::forward(get(args_))...); } template void do_increment(detail::true_, const index_tuple&) @@ -120,7 +120,7 @@ class named_proxy template T *operator()(Args &&...args) const { - CtorNArg ctor_obj(detail::forward_impl(args)...); + CtorNArg ctor_obj(boost::interprocess::forward(args)...); return mp_mngr->template generic_construct(mp_name, m_num, m_find, m_dothrow, ctor_obj); } @@ -211,7 +211,7 @@ struct Ctor0Arg : public placement_destroy //be able to bind temporaries. After that we will un-const them. //This cast is ugly but it is necessary until "perfect forwarding" //is achieved in C++0x. Meanwhile, if we want to be able to -//bind rvalues with non-const references, we have to be ugly +//bind lvalues with non-const references, we have to be ugly #define BOOST_PP_LOCAL_MACRO(n) \ template \ struct BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \ diff --git a/include/boost/interprocess/detail/os_file_functions.hpp b/include/boost/interprocess/detail/os_file_functions.hpp index 83f8c7e..78bbe96 100644 --- a/include/boost/interprocess/detail/os_file_functions.hpp +++ b/include/boost/interprocess/detail/os_file_functions.hpp @@ -13,9 +13,9 @@ #include #include -//#include +#include -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include #else # ifdef BOOST_HAS_UNISTD_H @@ -35,11 +35,11 @@ namespace boost { namespace interprocess { -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) typedef void * file_handle_t; typedef long long offset_t; -typedef struct{ +typedef struct mapping_handle_impl_t{ void * handle; bool is_shm; } mapping_handle_t; @@ -65,6 +65,14 @@ inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd) return ret; } +inline mapping_handle_t mapping_handle_from_shm_handle(file_handle_t hnd) +{ + mapping_handle_t ret; + ret.handle = hnd; + ret.is_shm = true; + return ret; +} + inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd) { return hnd.handle; } @@ -99,10 +107,7 @@ inline file_handle_t open_existing_file } inline bool delete_file(const char *name) -{ return winapi::delete_file(name); } - -inline bool delete_file_on_reboot_if_possible(const char *filename) -{ return winapi::move_file_ex(filename, 0, winapi::movefile_delay_until_reboot); } +{ return winapi::unlink_file(name); } inline bool truncate_file (file_handle_t hnd, std::size_t size) { @@ -191,16 +196,89 @@ inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) return (acquired = true); } - - inline bool release_file_lock_sharable(file_handle_t hnd) { return release_file_lock(hnd); } -#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +inline bool delete_subdirectories_recursive + (const std::string &refcstrRootDirectory, const char *dont_delete_this, unsigned int count) +{ + bool bSubdirectory = false; // Flag, indicating whether + // subdirectories have been found + void * hFile; // Handle to directory + std::string strFilePath; // Filepath + std::string strPattern; // Pattern + winapi::win32_find_data_t FileInformation; // File information + + //Find all files and directories + strPattern = refcstrRootDirectory + "\\*.*"; + hFile = winapi::find_first_file(strPattern.c_str(), &FileInformation); + if(hFile != winapi::invalid_handle_value){ + do{ + //If it's not "." or ".." or the pointed root_level dont_delete_this erase it + if(FileInformation.cFileName[0] != '.' && + !(dont_delete_this && count == 0 && std::strcmp(dont_delete_this, FileInformation.cFileName) == 0)){ + strFilePath.erase(); + strFilePath = refcstrRootDirectory + "\\" + FileInformation.cFileName; + + //If it's a directory, go recursive + if(FileInformation.dwFileAttributes & winapi::file_attribute_directory){ + // Delete subdirectory + if(!delete_subdirectories_recursive(strFilePath, dont_delete_this, count+1)) + return false; + } + //If it's a file, just delete it + else{ + // Set file attributes + //if(::SetFileAttributes(strFilePath.c_str(), winapi::file_attribute_normal) == 0) + //return winapi::get_last_error(); + // Delete file + if(winapi::delete_file(strFilePath.c_str()) == 0) + return false; + } + } + //Go to the next file + } while(winapi::find_next_file(hFile, &FileInformation) == 1); + + // Close handle + winapi::find_close(hFile); + + //See if the loop has ended with an error or just because we've traversed all the files + if(winapi::get_last_error() != winapi::error_no_more_files){ + return false; + } + else + { + //Erase empty subdirectories or original refcstrRootDirectory + if(!bSubdirectory && count) + { + // Set directory attributes + //if(::SetFileAttributes(refcstrRootDirectory.c_str(), FILE_ATTRIBUTE_NORMAL) == 0) + //return ::GetLastError(); + // Delete directory + if(winapi::remove_directory(refcstrRootDirectory.c_str()) == 0) + return false; + } + } + } + return true; +} + +//This function erases all the subdirectories of a directory except the one pointed by "dont_delete_this" +inline bool delete_subdirectories(const std::string &refcstrRootDirectory, const char *dont_delete_this) +{ + return delete_subdirectories_recursive(refcstrRootDirectory, dont_delete_this, 0u); +} + +#else //#if (defined BOOST_INTERPROCESS_WINDOWS) typedef int file_handle_t; typedef off_t offset_t; -typedef file_handle_t mapping_handle_t; + +typedef struct mapping_handle_impl_t +{ + file_handle_t handle; + bool is_xsi; +} mapping_handle_t; typedef enum { read_only = O_RDONLY , read_write = O_RDWR @@ -216,10 +294,15 @@ typedef enum { file_begin = SEEK_SET namespace detail{ inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd) -{ return hnd; } +{ + mapping_handle_t ret; + ret.handle = hnd; + ret.is_xsi = false; + return ret; +} inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd) -{ return hnd; } +{ return hnd.handle; } inline bool create_directory(const char *path) { return ::mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0; } @@ -263,12 +346,6 @@ inline file_handle_t open_existing_file inline bool delete_file(const char *name) { return ::unlink(name) == 0; } - -inline bool delete_file_on_reboot_if_possible(const char *) -{ //Function not implemented in POSIX functions - return false; -} - inline bool truncate_file (file_handle_t hnd, std::size_t size) { return 0 == ::ftruncate(hnd, size); } @@ -365,7 +442,7 @@ inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) inline bool release_file_lock_sharable(file_handle_t hnd) { return release_file_lock(hnd); } -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) } //namespace detail{ } //namespace interprocess { diff --git a/include/boost/interprocess/detail/os_thread_functions.hpp b/include/boost/interprocess/detail/os_thread_functions.hpp index eee090e..4d2e3dd 100644 --- a/include/boost/interprocess/detail/os_thread_functions.hpp +++ b/include/boost/interprocess/detail/os_thread_functions.hpp @@ -14,7 +14,7 @@ #include #include -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include #else # ifdef BOOST_HAS_UNISTD_H @@ -30,7 +30,7 @@ namespace boost { namespace interprocess { namespace detail{ -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) typedef unsigned long OS_process_id_t; typedef unsigned long OS_thread_id_t; @@ -40,6 +40,9 @@ typedef OS_thread_id_t OS_systemwide_thread_id_t; inline OS_process_id_t get_current_process_id() { return winapi::get_current_process_id(); } +inline OS_process_id_t get_invalid_process_id() +{ return OS_process_id_t(0); } + //thread inline OS_thread_id_t get_current_thread_id() { return winapi::get_current_thread_id(); } @@ -59,6 +62,12 @@ inline OS_systemwide_thread_id_t get_current_systemwide_thread_id() return get_current_thread_id(); } +inline void systemwide_thread_id_copy + (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to) +{ + to = from; +} + inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2) { return equal_thread_id(id1, id2); @@ -69,24 +78,56 @@ inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id() return get_invalid_thread_id(); } -#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#else //#if (defined BOOST_INTERPROCESS_WINDOWS) typedef pthread_t OS_thread_id_t; typedef pid_t OS_process_id_t; struct OS_systemwide_thread_id_t { + OS_systemwide_thread_id_t() + : pid(), tid() + {} + OS_systemwide_thread_id_t(pid_t p, pthread_t t) : pid(p), tid(t) {} + + OS_systemwide_thread_id_t(const OS_systemwide_thread_id_t &x) + : pid(x.pid), tid(x.tid) + {} + + OS_systemwide_thread_id_t(const volatile OS_systemwide_thread_id_t &x) + : pid(x.pid), tid(x.tid) + {} + + OS_systemwide_thread_id_t & operator=(const OS_systemwide_thread_id_t &x) + { pid = x.pid; tid = x.tid; return *this; } + + OS_systemwide_thread_id_t & operator=(const volatile OS_systemwide_thread_id_t &x) + { pid = x.pid; tid = x.tid; return *this; } + + void operator=(const OS_systemwide_thread_id_t &x) volatile + { pid = x.pid; tid = x.tid; } + pid_t pid; pthread_t tid; }; +inline void systemwide_thread_id_copy + (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to) +{ + to.pid = from.pid; + to.tid = from.tid; +} + //process inline OS_process_id_t get_current_process_id() { return ::getpid(); } +inline OS_process_id_t get_invalid_process_id() +{ return pid_t(0); } + //thread inline OS_thread_id_t get_current_thread_id() { return ::pthread_self(); } @@ -116,10 +157,10 @@ inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, con inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id() { - return OS_systemwide_thread_id_t(pid_t(0), get_invalid_thread_id()); + return OS_systemwide_thread_id_t(get_invalid_process_id(), get_invalid_thread_id()); } -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) } //namespace detail{ } //namespace interprocess { diff --git a/include/boost/interprocess/detail/preprocessor.hpp b/include/boost/interprocess/detail/preprocessor.hpp index 45afb67..b7cb8fd 100644 --- a/include/boost/interprocess/detail/preprocessor.hpp +++ b/include/boost/interprocess/detail/preprocessor.hpp @@ -36,7 +36,7 @@ //This cast is ugly but it is necessary until "perfect forwarding" //is achieved in C++0x. Meanwhile, if we want to be able to //bind rvalues with non-const references, we have to be ugly -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#ifdef BOOST_HAS_RVALUE_REFS #define BOOST_INTERPROCESS_PP_PARAM_LIST(z, n, data) \ BOOST_PP_CAT(P, n) && BOOST_PP_CAT(p, n) \ //! @@ -46,7 +46,7 @@ //! #endif -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#ifdef BOOST_HAS_RVALUE_REFS #define BOOST_INTERPROCESS_PARAM(U, u) \ U && u \ //! @@ -56,7 +56,7 @@ //! #endif -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#ifdef BOOST_HAS_RVALUE_REFS #define BOOST_INTERPROCESS_AUX_PARAM_INIT(z, n, data) \ BOOST_PP_CAT(m_p, n) (BOOST_PP_CAT(p, n)) \ //! @@ -70,7 +70,7 @@ BOOST_PP_CAT(++m_p, n) \ //! -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#ifdef BOOST_HAS_RVALUE_REFS #define BOOST_INTERPROCESS_AUX_PARAM_DEFINE(z, n, data) \ BOOST_PP_CAT(P, n) && BOOST_PP_CAT(m_p, n); \ //! @@ -80,25 +80,13 @@ //! #endif -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - #define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \ - detail::forward_impl< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \ - //! -#else - #define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \ - BOOST_PP_CAT(p, n) \ - //! -#endif +#define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \ +boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \ +//! -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - #define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \ - detail::forward_impl< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \ - //! -#else - #define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \ - BOOST_PP_CAT(m_p, n) \ - //! -#endif +#define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \ +boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \ +//! #define BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD(z, n, data) \ BOOST_PP_CAT(*m_p, n) \ diff --git a/include/boost/interprocess/detail/segment_manager_helper.hpp b/include/boost/interprocess/detail/segment_manager_helper.hpp index ffbe9fb..0301dfe 100644 --- a/include/boost/interprocess/detail/segment_manager_helper.hpp +++ b/include/boost/interprocess/detail/segment_manager_helper.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -27,6 +29,8 @@ #include //char_traits #include //std::nothrow #include //std::pair +#include //assert +#include //unary_function #ifndef BOOST_NO_EXCEPTIONS #include #endif @@ -75,7 +79,7 @@ struct block_header block_header(std::size_t value_bytes ,std::size_t value_alignment - ,std::size_t allocation_type + ,std::size_t alloc_type ,std::size_t sizeof_char ,std::size_t num_char ) @@ -83,7 +87,7 @@ struct block_header , m_num_char(num_char) , m_value_alignment(value_alignment) , m_alloc_type_sizeof_char - ( ((unsigned char)allocation_type << 5u) | + ( ((unsigned char)alloc_type << 5u) | ((unsigned char)sizeof_char & 0x1F) ) {}; @@ -94,7 +98,7 @@ struct block_header std::size_t total_size() const { - if(allocation_type() != anonymous_type){ + if(alloc_type() != anonymous_type){ return name_offset() + (m_num_char+1)*sizeof_char(); } else{ @@ -114,7 +118,7 @@ struct block_header + total_size(); } - std::size_t allocation_type() const + std::size_t alloc_type() const { return (m_alloc_type_sizeof_char >> 5u)&(unsigned char)0x7; } std::size_t sizeof_char() const @@ -252,6 +256,7 @@ struct char_if_void typedef instance_t anonymous_instance_t; typedef instance_t unique_instance_t; + template struct intrusive_value_type_impl : public Hook @@ -325,7 +330,7 @@ class char_ptr_holder template struct index_key { - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_char_ptr_t; typedef CharT char_type; @@ -471,6 +476,26 @@ struct segment_manager_iterator_transform } //namespace detail { +//These pointers are the ones the user will use to +//indicate previous allocation types +static const detail::anonymous_instance_t * anonymous_instance = 0; +static const detail::unique_instance_t * unique_instance = 0; + +namespace detail_really_deep_namespace { + +//Otherwise, gcc issues a warning of previously defined +//anonymous_instance and unique_instance +struct dummy +{ + dummy() + { + (void)anonymous_instance; + (void)unique_instance; + } +}; + +} //detail_really_deep_namespace + }} //namespace boost { namespace interprocess #include diff --git a/include/boost/interprocess/detail/tmp_dir_helpers.hpp b/include/boost/interprocess/detail/tmp_dir_helpers.hpp index 34db635..2c0ccc5 100644 --- a/include/boost/interprocess/detail/tmp_dir_helpers.hpp +++ b/include/boost/interprocess/detail/tmp_dir_helpers.hpp @@ -18,10 +18,87 @@ #include #include +#if (defined BOOST_INTERPROCESS_WINDOWS) +# include +#endif + namespace boost { namespace interprocess { namespace detail { +#if (defined BOOST_INTERPROCESS_WINDOWS) + +inline void tmp_filename(const char *filename, std::string &tmp_name) +{ + const char *tmp_dir = get_temporary_path(); + if(!tmp_dir){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + tmp_name = tmp_dir; + + //Remove final null. + tmp_name += "/boost_interprocess/"; + + char bootstamp[winapi::BootstampLength*2+1]; + std::size_t bootstamp_length = winapi::BootstampLength*2; + winapi::get_boot_time_str(bootstamp, bootstamp_length); + bootstamp[winapi::BootstampLength*2] = 0; + tmp_name += bootstamp; + tmp_name += '/'; + tmp_name += filename; +} + +inline void create_tmp_dir_and_get_filename(const char *filename, std::string &tmp_name) +{ + //First get the temp directory + const char *tmp_path = get_temporary_path(); + if(!tmp_path){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + + //Create Boost.Interprocess dir + tmp_name = tmp_path; + tmp_name += "/boost_interprocess"; + + //If fails, check that it's because already exists + if(!create_directory(tmp_name.c_str())){ + error_info info(system_error_code()); + if(info.get_error_code() != already_exists_error){ + throw interprocess_exception(info); + } + } + + //Obtain bootstamp string + char bootstamp[winapi::BootstampLength*2+1]; + std::size_t bootstamp_length = winapi::BootstampLength*2; + winapi::get_boot_time_str(bootstamp, bootstamp_length); + bootstamp[winapi::BootstampLength*2] = 0; + + //Create a new subdirectory with the bootstamp + std::string root_tmp_name = tmp_name; + tmp_name += '/'; + tmp_name += bootstamp; + + //If fails, check that it's because already exists + if(!create_directory(tmp_name.c_str())){ + error_info info(system_error_code()); + if(info.get_error_code() != already_exists_error){ + throw interprocess_exception(info); + } + } + + //Now erase all old directories created in the previous boot sessions + delete_subdirectories(root_tmp_name, bootstamp); + + //Add filename + tmp_name += '/'; + tmp_name += filename; +} + +#else //POSIX SYSTEMS + inline void tmp_filename(const char *filename, std::string &tmp_name) { const char *tmp_dir = get_temporary_path(); @@ -61,6 +138,8 @@ inline void create_tmp_dir_and_get_filename(const char *filename, std::string &t tmp_name += filename; } +#endif + inline void add_leading_slash(const char *name, std::string &new_name) { if(name[0] != '/'){ diff --git a/include/boost/interprocess/detail/transform_iterator.hpp b/include/boost/interprocess/detail/transform_iterator.hpp new file mode 100644 index 0000000..eb081c2 --- /dev/null +++ b/include/boost/interprocess/detail/transform_iterator.hpp @@ -0,0 +1,180 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// 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_TRANSFORM_ITERATORS_HPP +#define BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include + +#include +#include + +namespace boost { +namespace interprocess { + +template +struct operator_arrow_proxy +{ + operator_arrow_proxy(const PseudoReference &px) + : m_value(px) + {} + + PseudoReference* operator->() const { return &m_value; } + // This function is needed for MWCW and BCC, which won't call operator-> + // again automatically per 13.3.1.2 para 8 +// operator T*() const { return &m_value; } + mutable PseudoReference m_value; +}; + +template +struct operator_arrow_proxy +{ + operator_arrow_proxy(T &px) + : m_value(px) + {} + + T* operator->() const { return &m_value; } + // This function is needed for MWCW and BCC, which won't call operator-> + // again automatically per 13.3.1.2 para 8 +// operator T*() const { return &m_value; } + mutable T &m_value; +}; + +template +class transform_iterator + : public UnaryFunction + , public std::iterator + < typename Iterator::iterator_category + , typename detail::remove_reference::type + , typename Iterator::difference_type + , operator_arrow_proxy + , typename UnaryFunction::result_type> +{ + public: + explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction()) + : UnaryFunction(f), m_it(it) + {} + + explicit transform_iterator() + : UnaryFunction(), m_it() + {} + + //Constructors + transform_iterator& operator++() + { increment(); return *this; } + + transform_iterator operator++(int) + { + transform_iterator result (*this); + increment(); + return result; + } + + friend bool operator== (const transform_iterator& i, const transform_iterator& i2) + { return i.equal(i2); } + + friend bool operator!= (const transform_iterator& i, const transform_iterator& i2) + { return !(i == i2); } + +/* + friend bool operator> (const transform_iterator& i, const transform_iterator& i2) + { return i2 < i; } + + friend bool operator<= (const transform_iterator& i, const transform_iterator& i2) + { return !(i > i2); } + + friend bool operator>= (const transform_iterator& i, const transform_iterator& i2) + { return !(i < i2); } +*/ + friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + transform_iterator& operator+=(typename Iterator::difference_type off) + { this->advance(off); return *this; } + + transform_iterator operator+(typename Iterator::difference_type off) const + { + transform_iterator other(*this); + other.advance(off); + return other; + } + + friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right) + { return right + off; } + + transform_iterator& operator-=(typename Iterator::difference_type off) + { this->advance(-off); return *this; } + + transform_iterator operator-(typename Iterator::difference_type off) const + { return *this + (-off); } + + typename UnaryFunction::result_type operator*() const + { return dereference(); } + + operator_arrow_proxy + operator->() const + { return operator_arrow_proxy(dereference()); } + + Iterator & base() + { return m_it; } + + const Iterator & base() const + { return m_it; } + + private: + Iterator m_it; + + void increment() + { ++m_it; } + + void decrement() + { --m_it; } + + bool equal(const transform_iterator &other) const + { return m_it == other.m_it; } + + bool less(const transform_iterator &other) const + { return other.m_it < m_it; } + + typename UnaryFunction::result_type dereference() const + { return UnaryFunction::operator()(*m_it); } + + void advance(typename Iterator::difference_type n) + { std::advance(m_it, n); } + + typename Iterator::difference_type distance_to(const transform_iterator &other)const + { return std::distance(other.m_it, m_it); } +}; + +template +transform_iterator +make_transform_iterator(Iterator it, UnaryFunc fun) +{ + return transform_iterator(it, fun); +} + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP + diff --git a/include/boost/interprocess/detail/type_traits.hpp b/include/boost/interprocess/detail/type_traits.hpp index 44066b7..d4ee029 100644 --- a/include/boost/interprocess/detail/type_traits.hpp +++ b/include/boost/interprocess/detail/type_traits.hpp @@ -120,13 +120,13 @@ struct add_reference template<> struct add_reference { - typedef nat& type; + typedef nat &type; }; template<> struct add_reference { - typedef const nat& type; + typedef const nat &type; }; template diff --git a/include/boost/interprocess/detail/utilities.hpp b/include/boost/interprocess/detail/utilities.hpp index a96215e..166cf2e 100644 --- a/include/boost/interprocess/detail/utilities.hpp +++ b/include/boost/interprocess/detail/utilities.hpp @@ -26,11 +26,10 @@ #include #include #include -#include -#include -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -#include -#endif +#include +#include +#include +#include #include #include @@ -70,321 +69,6 @@ inline void do_swap(T& x, T& y) swap(x, y); } -//!A deleter for scoped_ptr that deallocates the memory -//!allocated for an object using a STL allocator. -template -struct scoped_ptr_dealloc_functor -{ - typedef typename Allocator::pointer pointer; - typedef detail::integral_constant::value> alloc_version; - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant allocator_v2; - - private: - void priv_deallocate(const typename Allocator::pointer &p, allocator_v1) - { m_alloc.deallocate(p, 1); } - - void priv_deallocate(const typename Allocator::pointer &p, allocator_v2) - { m_alloc.deallocate_one(p); } - - public: - Allocator& m_alloc; - - scoped_ptr_dealloc_functor(Allocator& a) - : m_alloc(a) {} - - void operator()(pointer ptr) - { if (ptr) priv_deallocate(ptr, alloc_version()); } -}; - -//!A deleter for scoped_ptr that deallocates the memory -//!allocated for an object using a STL allocator. -template -struct scoped_deallocator -{ - typedef typename Allocator::pointer pointer; - typedef detail::integral_constant::value> alloc_version; - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant allocator_v2; - - private: - void priv_deallocate(allocator_v1) - { m_alloc.deallocate(m_ptr, 1); } - - void priv_deallocate(allocator_v2) - { m_alloc.deallocate_one(m_ptr); } - - scoped_deallocator(const scoped_deallocator &); - scoped_deallocator& operator=(const scoped_deallocator &); - - public: - pointer m_ptr; - Allocator& m_alloc; - - scoped_deallocator(pointer p, Allocator& a) - : m_ptr(p), m_alloc(a) {} - - ~scoped_deallocator() - { if (m_ptr)priv_deallocate(alloc_version()); } - - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - scoped_deallocator(scoped_deallocator &&o) - : m_ptr(o.m_ptr), m_alloc(o.m_alloc) - { - #else - scoped_deallocator(moved_object mo) - : m_ptr(mo.get().m_ptr), m_alloc(mo.get().m_alloc) - { - scoped_deallocator &o = mo.get(); - #endif - o.release(); - } - - pointer get() const - { return m_ptr; } - - void release() - { m_ptr = 0; } -}; - -} //namespace detail { - -template -struct is_movable > -{ - static const bool value = true; -}; - -namespace detail { - -//!A deleter for scoped_ptr that deallocates the memory -//!allocated for an array of objects using a STL allocator. -template -struct scoped_array_deallocator -{ - typedef typename Allocator::pointer pointer; - typedef typename Allocator::size_type size_type; - - scoped_array_deallocator(pointer p, Allocator& a, size_type length) - : m_ptr(p), m_alloc(a), m_length(length) {} - - ~scoped_array_deallocator() - { if (m_ptr) m_alloc.deallocate(m_ptr, m_length); } - - void release() - { m_ptr = 0; } - - private: - pointer m_ptr; - Allocator& m_alloc; - size_type m_length; -}; - -template -struct null_scoped_array_deallocator -{ - typedef typename Allocator::pointer pointer; - typedef typename Allocator::size_type size_type; - - null_scoped_array_deallocator(pointer, Allocator&, size_type) - {} - - void release() - {} -}; - -//!A deleter for scoped_ptr that destroys -//!an object using a STL allocator. -template -struct scoped_destructor_n -{ - typedef typename Allocator::pointer pointer; - typedef typename Allocator::value_type value_type; - typedef typename Allocator::size_type size_type; - - pointer m_p; - size_type m_n; - - scoped_destructor_n(pointer p, size_type n) - : m_p(p), m_n(n) - {} - - void release() - { m_p = 0; } - - void increment_size(size_type inc) - { m_n += inc; } - - ~scoped_destructor_n() - { - if(!m_p) return; - value_type *raw_ptr = detail::get_pointer(m_p); - for(std::size_t i = 0; i < m_n; ++i, ++raw_ptr) - raw_ptr->~value_type(); - } -}; - -//!A deleter for scoped_ptr that destroys -//!an object using a STL allocator. -template -struct null_scoped_destructor_n -{ - typedef typename Allocator::pointer pointer; - typedef typename Allocator::size_type size_type; - - null_scoped_destructor_n(pointer, size_type) - {} - - void increment_size(size_type) - {} - - void release() - {} -}; - -template -class allocator_destroyer -{ - typedef typename A::value_type value_type; - typedef detail::integral_constant::value> alloc_version; - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant allocator_v2; - - private: - A & a_; - - private: - void priv_deallocate(const typename A::pointer &p, allocator_v1) - { a_.deallocate(p, 1); } - - void priv_deallocate(const typename A::pointer &p, allocator_v2) - { a_.deallocate_one(p); } - - public: - allocator_destroyer(A &a) - : a_(a) - {} - - void operator()(const typename A::pointer &p) - { - detail::get_pointer(p)->~value_type(); - priv_deallocate(p, alloc_version()); - } -}; - -template -class allocator_destroyer_and_chain_builder -{ - typedef typename A::value_type value_type; - typedef typename A::multiallocation_iterator multiallocation_iterator; - typedef typename A::multiallocation_chain multiallocation_chain; - - A & a_; - multiallocation_chain &c_; - - public: - allocator_destroyer_and_chain_builder(A &a, multiallocation_chain &c) - : a_(a), c_(c) - {} - - void operator()(const typename A::pointer &p) - { - value_type *vp = detail::get_pointer(p); - vp->~value_type(); - c_.push_back(vp); - } -}; - -template -class allocator_multialloc_chain_node_deallocator -{ - typedef typename A::value_type value_type; - typedef typename A::multiallocation_iterator multiallocation_iterator; - typedef typename A::multiallocation_chain multiallocation_chain; - typedef allocator_destroyer_and_chain_builder chain_builder; - - A & a_; - multiallocation_chain c_; - - public: - allocator_multialloc_chain_node_deallocator(A &a) - : a_(a), c_() - {} - - chain_builder get_chain_builder() - { return chain_builder(a_, c_); } - - ~allocator_multialloc_chain_node_deallocator() - { - multiallocation_iterator it(c_.get_it()); - if(it != multiallocation_iterator()) - a_.deallocate_individual(it); - } -}; - -template -class allocator_multialloc_chain_array_deallocator -{ - typedef typename A::value_type value_type; - typedef typename A::multiallocation_iterator multiallocation_iterator; - typedef typename A::multiallocation_chain multiallocation_chain; - typedef allocator_destroyer_and_chain_builder chain_builder; - - A & a_; - multiallocation_chain c_; - - public: - allocator_multialloc_chain_array_deallocator(A &a) - : a_(a), c_() - {} - - chain_builder get_chain_builder() - { return chain_builder(a_, c_); } - - ~allocator_multialloc_chain_array_deallocator() - { - multiallocation_iterator it(c_.get_it()); - if(it != multiallocation_iterator()) - a_.deallocate_many(it); - } -}; - -//!A class used for exception-safe multi-allocation + construction. -template -struct multiallocation_destroy_dealloc -{ - typedef typename Allocator::multiallocation_iterator multiallocation_iterator; - typedef typename Allocator::value_type value_type; - - multiallocation_iterator m_itbeg; - Allocator& m_alloc; - - multiallocation_destroy_dealloc(multiallocation_iterator itbeg, Allocator& a) - : m_itbeg(itbeg), m_alloc(a) {} - - ~multiallocation_destroy_dealloc() - { - multiallocation_iterator endit; - while(m_itbeg != endit){ - detail::get_pointer(&*m_itbeg)->~value_type(); - m_alloc.deallocate(&*m_itbeg, 1); - ++m_itbeg; - } - } - - void next() - { ++m_itbeg; } - - void release() - { m_itbeg = multiallocation_iterator(); } -}; - //Rounds "orig_size" by excess to round_to bytes inline std::size_t get_rounded_size(std::size_t orig_size, std::size_t round_to) { @@ -415,18 +99,6 @@ struct ct_rounded_size enum { value = ((OrigSize-1)/RoundTo+1)*RoundTo }; }; -template -struct ct_min -{ - enum { value = (Value1 < Value2)? Value1 : Value2 }; -}; - -template -struct ct_max -{ - enum { value = (Value1 > Value2)? Value1 : Value2 }; -}; - // Gennaro Prota wrote this. Thanks! template struct ct_max_pow2_less @@ -443,38 +115,6 @@ struct ct_max_pow2_less<0, 0> static const std::size_t value = 0; }; -//!Obtains a generic pointer of the same type that -//!can point to other pointed type: Ptr -> Ptr -template -struct pointer_to_other; - -template class Sp> -struct pointer_to_other< Sp, U > -{ - typedef Sp type; -}; - -template class Sp> -struct pointer_to_other< Sp, U > -{ - typedef Sp type; -}; - -template class Sp> -struct pointer_to_other< Sp, U > -{ - typedef Sp type; -}; - -template -struct pointer_to_other< T*, U > -{ - typedef U* type; -}; - } //namespace detail { //!Trait class to detect if an index is a node @@ -486,7 +126,6 @@ struct is_node_index enum { value = false }; }; - //!Trait class to detect if an index is an intrusive //!index. This will embed the derivation hook in each //!allocation header, to provide memory for the intrusive @@ -497,334 +136,6 @@ struct is_intrusive_index enum { value = false }; }; -template -SizeType - get_next_capacity(const SizeType max_size - ,const SizeType capacity - ,const SizeType n) -{ -// if (n > max_size - capacity) -// throw std::length_error("get_next_capacity"); - - const SizeType m3 = max_size/3; - - if (capacity < m3) - return capacity + max_value(3*(capacity+1)/5, n); - - if (capacity < m3*2) - return capacity + max_value((capacity+1)/2, n); - - return max_size; -} - -namespace detail { - -template -struct pair -{ - typedef T1 first_type; - typedef T2 second_type; - - T1 first; - T2 second; - - //std::pair compatibility - template - pair(const std::pair& p) - : first(p.first), second(p.second) - {} - - //To resolve ambiguity with the variadic constructor of 1 argument - //and the previous constructor - pair(std::pair& x) - : first(x.first), second(x.second) - {} - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - pair(detail::moved_object > p) - : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) - {} - #else - template - pair(std::pair && p) - : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) - {} - #endif - - pair() - : first(), second() - {} - - pair(const pair& x) - : first(x.first), second(x.second) - {} - - //To resolve ambiguity with the variadic constructor of 1 argument - //and the copy constructor - pair(pair& x) - : first(x.first), second(x.second) - {} - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - pair(detail::moved_object > p) - : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) - {} - #else - pair(pair && p) - : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) - {} - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - pair(detail::moved_object > p) - : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) - {} - #else - template - pair(pair && p) - : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) - {} - #endif - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - template - pair(U &&u, Args &&... args) - : first(detail::forward_impl(u)) - , second(detail::forward_impl(args)...) - {} - - #else - - template - pair(BOOST_INTERPROCESS_PARAM(U, u)) - : first(detail::forward_impl(u)) - {} - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - pair(BOOST_INTERPROCESS_PARAM(U, u) \ - ,BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - : first(detail::forward_impl(u)) \ - , second(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)) \ - {} \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - pair& operator=(detail::moved_object > p) - { - first = detail::move_impl(p.get().first); - second = detail::move_impl(p.get().second); - return *this; - } - #else - pair& operator=(pair &&p) - { - first = detail::move_impl(p.first); - second = detail::move_impl(p.second); - return *this; - } - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - pair& operator=(detail::moved_object > p) - { - first = detail::move_impl(p.get().first); - second = detail::move_impl(p.get().second); - return *this; - } - #else - pair& operator=(std::pair &&p) - { - first = detail::move_impl(p.first); - second = detail::move_impl(p.second); - return *this; - } - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - pair& operator=(detail::moved_object > p) - { - first = detail::move_impl(p.get().first); - second = detail::move_impl(p.get().second); - return *this; - } - #else - template - pair& operator=(std::pair &&p) - { - first = detail::move_impl(p.first); - second = detail::move_impl(p.second); - return *this; - } - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(detail::moved_object p) - { std::swap(*this, p.get()); } - - void swap(pair& p) - { std::swap(*this, p); } - - #else - void swap(pair &&p) - { std::swap(*this, p); } - #endif -}; - -template -inline bool operator==(const pair& x, const pair& y) -{ return static_cast(x.first == y.first && x.second == y.second); } - -template -inline bool operator< (const pair& x, const pair& y) -{ return static_cast(x.first < y.first || - (!(y.first < x.first) && x.second < y.second)); } - -template -inline bool operator!=(const pair& x, const pair& y) -{ return static_cast(!(x == y)); } - -template -inline bool operator> (const pair& x, const pair& y) -{ return y < x; } - -template -inline bool operator>=(const pair& x, const pair& y) -{ return static_cast(!(x < y)); } - -template -inline bool operator<=(const pair& x, const pair& y) -{ return static_cast(!(y < x)); } - -template -inline pair make_pair(T1 x, T2 y) -{ return pair(x, y); } - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline void swap(detail::moved_object > &x, pair y) -{ - swap(x.get().first, y.first); - swap(x.get().second, y.second); -} - -template -inline void swap(pair& x, detail::moved_object > y) -{ - swap(x.first, y.get().first); - swap(x.second, y.get().second); -} - -template -inline void swap(pair& x, pair& y) -{ - swap(x.first, y.first); - swap(x.second, y.second); -} - -#else -template -inline void swap(pair&&x, pair&&y) -{ - swap(x.first, y.first); - swap(x.second, y.second); -} -#endif - -template -struct cast_functor -{ - typedef typename detail::add_reference::type result_type; - result_type operator()(char &ptr) const - { return *static_cast(static_cast(&ptr)); } -}; - -template -class multiallocation_chain_adaptor -{ - private: - MultiallocChain chain_; - - multiallocation_chain_adaptor - (const multiallocation_chain_adaptor &); - multiallocation_chain_adaptor &operator= - (const multiallocation_chain_adaptor &); - - public: - typedef transform_iterator - < typename MultiallocChain:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - - multiallocation_chain_adaptor() - : chain_() - {} - - void push_back(T *mem) - { chain_.push_back(mem); } - - void push_front(T *mem) - { chain_.push_front(mem); } - - void swap(multiallocation_chain_adaptor &other_chain) - { chain_.swap(other_chain.chain_); } - - void splice_back(multiallocation_chain_adaptor &other_chain) - { chain_.splice_back(other_chain.chain_); } - - T *pop_front() - { return static_cast(chain_.pop_front()); } - - bool empty() const - { return chain_.empty(); } - - multiallocation_iterator get_it() const - { return multiallocation_iterator(chain_.get_it()); } - - std::size_t size() const - { return chain_.size(); } -}; - -template -struct value_init -{ - value_init() - : m_t() - {} - - T m_t; -}; - -} //namespace detail { - -//!The pair is movable if any of its members is movable -template -struct is_movable > -{ - enum { value = is_movable::value || is_movable::value }; -}; - -//!The pair is movable if any of its members is movable -template -struct is_movable > -{ - enum { value = is_movable::value || is_movable::value }; -}; - -///has_trivial_destructor_after_move<> == true_type -///specialization for optimizations -template -struct has_trivial_destructor_after_move - : public boost::has_trivial_destructor -{}; - template T* addressof(T& v) { @@ -850,36 +161,6 @@ class value_eraser bool m_erase; }; -template -struct sizeof_value -{ - static const std::size_t value = sizeof(T); -}; - -template <> -struct sizeof_value -{ - static const std::size_t value = sizeof(void*); -}; - -template <> -struct sizeof_value -{ - static const std::size_t value = sizeof(void*); -}; - -template <> -struct sizeof_value -{ - static const std::size_t value = sizeof(void*); -}; - -template <> -struct sizeof_value -{ - static const std::size_t value = sizeof(void*); -}; - } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/detail/win32_api.hpp b/include/boost/interprocess/detail/win32_api.hpp index fa26ee9..cfe0afc 100644 --- a/include/boost/interprocess/detail/win32_api.hpp +++ b/include/boost/interprocess/detail/win32_api.hpp @@ -14,13 +14,15 @@ #include #include #include +#include +#include #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once # pragma comment( lib, "advapi32.lib" ) #endif -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include # include #else @@ -37,6 +39,7 @@ namespace winapi { static const unsigned long infinite_time = 0xFFFFFFFF; static const unsigned long error_already_exists = 183L; static const unsigned long error_file_not_found = 2u; +static const unsigned long error_no_more_files = 18u; static const unsigned long semaphore_all_access = (0x000F0000L)|(0x00100000L)|0x3; static const unsigned long mutex_all_access = (0x000F0000L)|(0x00100000L)|0x0001; @@ -62,6 +65,15 @@ static const unsigned long file_map_copy = section_query; static const unsigned long file_map_write = section_map_write; static const unsigned long file_map_read = section_map_read; static const unsigned long file_map_all_access = section_all_access; +static const unsigned long delete_access = 0x00010000L; +static const unsigned long file_flag_backup_semantics = 0x02000000; +static const long file_flag_delete_on_close = 0x04000000; + +//Native API constants +static const unsigned long file_open_for_backup_intent = 0x00004000; +static const int file_share_valid_flags = 0x00000007; +static const long file_delete_on_close = 0x00001000L; +static const long obj_case_insensitive = 0x00000040L; static const unsigned long movefile_copy_allowed = 0x02; static const unsigned long movefile_delay_until_reboot = 0x04; @@ -74,6 +86,15 @@ static const unsigned long file_share_read = 0x00000001; static const unsigned long file_share_write = 0x00000002; static const unsigned long file_share_delete = 0x00000004; +static const unsigned long file_attribute_readonly = 0x00000001; +static const unsigned long file_attribute_hidden = 0x00000002; +static const unsigned long file_attribute_system = 0x00000004; +static const unsigned long file_attribute_directory = 0x00000010; +static const unsigned long file_attribute_archive = 0x00000020; +static const unsigned long file_attribute_device = 0x00000040; +static const unsigned long file_attribute_normal = 0x00000080; +static const unsigned long file_attribute_temporary = 0x00000100; + static const unsigned long generic_read = 0x80000000L; static const unsigned long generic_write = 0x40000000L; @@ -109,8 +130,6 @@ static const unsigned long open_existing = 3; static const unsigned long open_always = 4; static const unsigned long truncate_existing = 5; -static const unsigned long file_attribute_temporary = 0x00000100; - static const unsigned long file_begin = 0; static const unsigned long file_current = 1; static const unsigned long file_end = 2; @@ -120,6 +139,13 @@ static const unsigned long lockfile_exclusive_lock = 2; static const unsigned long error_lock_violation = 33; static const unsigned long security_descriptor_revision = 1; +//Own defines +static const long SystemTimeOfDayInfoLength = 48; +static const long BootAndSystemstampLength = 16; +static const long BootstampLength = 8; +static const unsigned long MaxPath = 260; + + } //namespace winapi { } //namespace interprocess { } //namespace boost { @@ -151,6 +177,20 @@ struct interprocess_filetime unsigned long dwHighDateTime; }; +struct win32_find_data_t +{ + unsigned long dwFileAttributes; + interprocess_filetime ftCreationTime; + interprocess_filetime ftLastAccessTime; + interprocess_filetime ftLastWriteTime; + unsigned long nFileSizeHigh; + unsigned long nFileSizeLow; + unsigned long dwReserved0; + unsigned long dwReserved1; + char cFileName[MaxPath]; + char cAlternateFileName[14]; +}; + struct interprocess_security_attributes { unsigned long nLength; @@ -208,6 +248,126 @@ typedef struct _interprocess_security_descriptor interprocess_acl *Dacl; } interprocess_security_descriptor; +enum file_information_class_t { + file_directory_information = 1, + file_full_directory_information, + file_both_directory_information, + file_basic_information, + file_standard_information, + file_internal_information, + file_ea_information, + file_access_information, + file_name_information, + file_rename_information, + file_link_information, + file_names_information, + file_disposition_information, + file_position_information, + file_full_ea_information, + file_mode_information, + file_alignment_information, + file_all_information, + file_allocation_information, + file_end_of_file_information, + file_alternate_name_information, + file_stream_information, + file_pipe_information, + file_pipe_local_information, + file_pipe_remote_information, + file_mailslot_query_information, + file_mailslot_set_information, + file_compression_information, + file_copy_on_write_information, + file_completion_information, + file_move_cluster_information, + file_quota_information, + file_reparse_point_information, + file_network_open_information, + file_object_id_information, + file_tracking_information, + file_ole_directory_information, + file_content_index_information, + file_inherit_content_index_information, + file_ole_information, + file_maximum_information +}; + +struct file_name_information_t { + unsigned long FileNameLength; + wchar_t FileName[1]; +}; + +struct file_rename_information_t { + int Replace; + void *RootDir; + unsigned long FileNameLength; + wchar_t FileName[1]; +}; + +struct unicode_string_t { + unsigned short Length; + unsigned short MaximumLength; + wchar_t *Buffer; +}; + +struct object_attributes_t { + unsigned long Length; + void * RootDirectory; + unicode_string_t *ObjectName; + unsigned long Attributes; + void *SecurityDescriptor; + void *SecurityQualityOfService; +}; + +struct io_status_block_t { + union { + long Status; + void *Pointer; + }; + + unsigned long *Information; +}; + +union system_timeofday_information +{ + struct data_t + { + __int64 liKeBootTime; + __int64 liKeSystemTime; + __int64 liExpTimeZoneBias; + unsigned long uCurrentTimeZoneId; + unsigned long dwReserved; + } data; + unsigned char Reserved1[SystemTimeOfDayInfoLength]; +}; + +enum system_information_class { + system_basic_information = 0, + system_performance_information = 2, + system_time_of_day_information = 3, + system_process_information = 5, + system_processor_performance_information = 8, + system_interrupt_information = 23, + system_exception_information = 33, + system_registry_quota_information = 37, + system_lookaside_information = 45 +}; + +enum object_information_class +{ + object_basic_information, + object_name_information, + object_type_information, + object_all_information, + object_data_information +}; + +struct object_name_information_t +{ + unicode_string_t Name; + wchar_t NameBuffer[1]; +}; + //Some windows API declarations extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId(); extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(); @@ -220,6 +380,9 @@ extern "C" __declspec(dllimport) int __stdcall DuplicateHandle , void *hTargetProcessHandle, void **lpTargetHandle , unsigned long dwDesiredAccess, int bInheritHandle , unsigned long dwOptions); +extern "C" __declspec(dllimport) void *__stdcall FindFirstFileA(const char *lpFileName, win32_find_data_t *lpFindFileData); +extern "C" __declspec(dllimport) int __stdcall FindNextFileA(void *hFindFile, win32_find_data_t *lpFindFileData); +extern "C" __declspec(dllimport) int __stdcall FindClose(void *hFindFile); extern "C" __declspec(dllimport) void __stdcall GetSystemTimeAsFileTime(interprocess_filetime*); extern "C" __declspec(dllimport) int __stdcall FileTimeToLocalFileTime(const interprocess_filetime *in, const interprocess_filetime *out); extern "C" __declspec(dllimport) void * __stdcall CreateMutexA(interprocess_security_attributes*, int, const char *); @@ -245,6 +408,7 @@ extern "C" __declspec(dllimport) unsigned long __stdcall FormatMessageA std::va_list *Arguments); extern "C" __declspec(dllimport) void *__stdcall LocalFree (void *); extern "C" __declspec(dllimport) int __stdcall CreateDirectoryA(const char *, interprocess_security_attributes*); +extern "C" __declspec(dllimport) int __stdcall RemoveDirectoryA(const char *lpPathName); extern "C" __declspec(dllimport) int __stdcall GetTempPathA(unsigned long length, char *buffer); extern "C" __declspec(dllimport) int __stdcall CreateDirectory(const char *, interprocess_security_attributes*); extern "C" __declspec(dllimport) int __stdcall SetFileValidData(void *, __int64 size); @@ -257,6 +421,25 @@ extern "C" __declspec(dllimport) int __stdcall UnlockFileEx(void *hnd, unsigned extern "C" __declspec(dllimport) int __stdcall WriteFile(void *hnd, const void *buffer, unsigned long bytes_to_write, unsigned long *bytes_written, interprocess_overlapped* overlapped); extern "C" __declspec(dllimport) int __stdcall InitializeSecurityDescriptor(interprocess_security_descriptor *pSecurityDescriptor, unsigned long dwRevision); extern "C" __declspec(dllimport) int __stdcall SetSecurityDescriptorDacl(interprocess_security_descriptor *pSecurityDescriptor, int bDaclPresent, interprocess_acl *pDacl, int bDaclDefaulted); +extern "C" __declspec(dllimport) void *__stdcall LoadLibraryA(const char *); +extern "C" __declspec(dllimport) int __stdcall FreeLibrary(void *); +extern "C" __declspec(dllimport) void *__stdcall GetProcAddress(void *, const char*); +extern "C" __declspec(dllimport) void *__stdcall GetModuleHandleA(const char*); + +//API function typedefs +//Pointer to functions +typedef long (__stdcall *NtDeleteFile_t)(object_attributes_t *ObjectAttributes); +typedef long (__stdcall *NtSetInformationFile_t)(void *FileHandle, io_status_block_t *IoStatusBlock, void *FileInformation, unsigned long Length, int FileInformationClass ); +typedef long (__stdcall *NtQueryInformationFile_t)(void *,io_status_block_t *,void *, long, int); +typedef long (__stdcall *NtOpenFile_t)(void*,unsigned long ,object_attributes_t*,io_status_block_t*,unsigned long,unsigned long); +typedef long (__stdcall *NtClose_t) (void*); +typedef long (__stdcall *RtlCreateUnicodeStringFromAsciiz_t)(unicode_string_t *, const char *); +typedef void (__stdcall *RtlFreeUnicodeString_t)(unicode_string_t *); +typedef void (__stdcall *RtlInitUnicodeString_t)( unicode_string_t *, const wchar_t * ); +typedef long (__stdcall *RtlAppendUnicodeToString_t)(unicode_string_t *Destination, const wchar_t *Source); +typedef long (__stdcall * NtQuerySystemInformation_t)(int, void*, unsigned long, unsigned long *); +typedef long (__stdcall * NtQueryObject_t)(void*, object_information_class, void *, unsigned long, unsigned long *); +typedef unsigned long (__stdcall * GetMappedFileName_t)(void *, void *, wchar_t *, unsigned long); } //namespace winapi { } //namespace interprocess { @@ -298,6 +481,15 @@ static inline unsigned long get_current_process_id() static inline unsigned int close_handle(void* handle) { return CloseHandle(handle); } +static inline void * find_first_file(const char *lpFileName, win32_find_data_t *lpFindFileData) +{ return FindFirstFileA(lpFileName, lpFindFileData); } + +static inline bool find_next_file(void *hFindFile, win32_find_data_t *lpFindFileData) +{ return FindNextFileA(hFindFile, lpFindFileData) != 0; } + +static inline bool find_close(void *handle) +{ return FindClose(handle) != 0; } + static inline bool duplicate_current_process_handle (void *hSourceHandle, void **lpTargetHandle) { @@ -384,6 +576,9 @@ static inline bool get_file_size(void *handle, __int64 &size) static inline bool create_directory(const char *name, interprocess_security_attributes* security) { return 0 != CreateDirectoryA(name, security); } +static inline bool remove_directory(const char *lpPathName) +{ return 0 != RemoveDirectoryA(lpPathName); } + static inline unsigned long get_temp_path(unsigned long length, char *buffer) { return GetTempPathA(length, buffer); } @@ -417,6 +612,274 @@ static inline long interlocked_exchange_add(long volatile* addend, long value) static inline long interlocked_exchange(long volatile* addend, long value) { return BOOST_INTERLOCKED_EXCHANGE(const_cast(addend), value); } +//Forward functions +static inline void *load_library(const char *name) +{ return LoadLibraryA(name); } + +static inline bool free_library(void *module) +{ return 0 != FreeLibrary(module); } + +static inline void *get_proc_address(void *module, const char *name) +{ return GetProcAddress(module, name); } + +static inline void *get_current_process() +{ return GetCurrentProcess(); } + +static inline void *get_module_handle(const char *name) +{ return GetModuleHandleA(name); } + +static inline void initialize_object_attributes +( object_attributes_t *pobject_attr, unicode_string_t *name + , unsigned long attr, void *rootdir, void *security_descr) + +{ + pobject_attr->Length = sizeof(object_attributes_t); + pobject_attr->RootDirectory = rootdir; + pobject_attr->Attributes = attr; + pobject_attr->ObjectName = name; + pobject_attr->SecurityDescriptor = security_descr; + pobject_attr->SecurityQualityOfService = 0; +} + +static inline void rtl_init_empty_unicode_string(unicode_string_t *ucStr, wchar_t *buf, unsigned short bufSize) +{ + ucStr->Buffer = buf; + ucStr->Length = 0; + ucStr->MaximumLength = bufSize; +} + +//Complex winapi based functions... + +//pszFilename must have room for at least MaxPath+1 characters +static inline bool get_file_name_from_handle_function + (void * hFile, wchar_t *pszFilename, std::size_t length, std::size_t &out_length) +{ + if(length <= MaxPath){ + return false; + } + + void *hiPSAPI = load_library("PSAPI.DLL"); + if (0 == hiPSAPI) + return 0; + + class library_unloader + { + void *lib_; + + public: + library_unloader(void *module) : lib_(module){} + ~library_unloader(){ free_library(lib_); } + } unloader(hiPSAPI); + + // Pointer to function getMappedFileName() in PSAPI.DLL + GetMappedFileName_t pfGMFN = + (GetMappedFileName_t)get_proc_address(hiPSAPI, "GetMappedFileNameW"); + if (! pfGMFN){ + return 0; // Failed: unexpected error + } + + bool bSuccess = false; + + // Create a file mapping object. + void * hFileMap = create_file_mapping(hFile, page_readonly, 0, 1, 0); + if(hFileMap) + { + // Create a file mapping to get the file name. + void* pMem = map_view_of_file_ex(hFileMap, file_map_read, 0, 0, 1, 0); + + if (pMem){ + out_length = pfGMFN(get_current_process(), pMem, pszFilename, MaxPath); + if(out_length){ + bSuccess = true; + } + unmap_view_of_file(pMem); + } + close_handle(hFileMap); + } + + return(bSuccess); +} + +static inline bool get_system_time_of_day_information(system_timeofday_information &info) +{ + NtQuerySystemInformation_t pNtQuerySystemInformation = (NtQuerySystemInformation_t) + get_proc_address(get_module_handle("ntdll.dll"), "NtQuerySystemInformation"); + unsigned long res; + long status = pNtQuerySystemInformation(system_time_of_day_information, &info, sizeof(info), &res); + if(status){ + return false; + } + return true; +} + +static inline bool get_boot_time(unsigned char (&bootstamp) [BootstampLength]) +{ + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + return false; + } + std::memcpy(&bootstamp[0], &info.Reserved1, sizeof(bootstamp)); + return true; +} + +static inline bool get_boot_and_system_time(unsigned char (&bootsystemstamp) [BootAndSystemstampLength]) +{ + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + return false; + } + std::memcpy(&bootsystemstamp[0], &info.Reserved1, sizeof(bootsystemstamp)); + return true; +} + +static inline bool get_boot_time_str(char *bootstamp_str, std::size_t &s) //will write BootstampLength chars +{ + if(s < (BootstampLength*2)) + return false; + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + return false; + } + const char Characters [] = + { '0', '1', '2', '3', '4', '5', '6', '7' + , '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + std::size_t char_counter = 0; + for(std::size_t i = 0; i != static_cast(BootstampLength); ++i){ + bootstamp_str[char_counter++] = Characters[(info.Reserved1[i]&0xF0)>>4]; + bootstamp_str[char_counter++] = Characters[(info.Reserved1[i]&0x0F)]; + } + s = BootstampLength*2; + return true; +} + +static inline bool get_boot_and_system_time_wstr(wchar_t *bootsystemstamp, std::size_t &s) //will write BootAndSystemstampLength chars +{ + if(s < (BootAndSystemstampLength*2)) + return false; + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + return false; + } + const wchar_t Characters [] = + { L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7' + , L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F' }; + std::size_t char_counter = 0; + for(std::size_t i = 0; i != static_cast(BootAndSystemstampLength); ++i){ + bootsystemstamp[char_counter++] = Characters[(info.Reserved1[i]&0xF0)>>4]; + bootsystemstamp[char_counter++] = Characters[(info.Reserved1[i]&0x0F)]; + } + s = BootAndSystemstampLength*2; + return true; +} + +static inline bool unlink_file(const char *filename) +{ + try{ + NtSetInformationFile_t pNtSetInformationFile = + (NtSetInformationFile_t)get_proc_address(get_module_handle("ntdll.dll"), "NtSetInformationFile"); + if(!pNtSetInformationFile){ + return false; + } + + NtQueryObject_t pNtQueryObject = + (NtQueryObject_t)get_proc_address(get_module_handle("ntdll.dll"), "NtQueryObject"); + + //First step: Obtain a handle to the file using Win32 rules. This resolves relative paths + void *fh = create_file(filename, generic_read | delete_access, open_existing, + file_flag_backup_semantics | file_flag_delete_on_close); + if(fh == invalid_handle_value){ + return false; + } + + class handle_closer + { + void *handle_; + public: + handle_closer(void *handle) : handle_(handle){} + ~handle_closer(){ close_handle(handle_); } + } handle_closer(fh); + + const std::size_t CharArraySize = 32767; //Max name length + + union mem_t + { + object_name_information_t name; + struct ren_t + { + file_rename_information_t info; + wchar_t buf[CharArraySize]; + } ren; + }; + + class auto_ptr + { + public: + explicit auto_ptr(mem_t *ptr) : ptr_(ptr){} + ~auto_ptr(){ delete ptr_; } + mem_t *get() const{ return (ptr_); } + mem_t *operator->() const{ return this->get(); } + private: + mem_t *ptr_; + } pmem(new mem_t); + + file_rename_information_t *pfri = (file_rename_information_t*)&pmem->ren.info; + const std::size_t RenMaxNumChars = + ((char*)pmem.get() - (char*)&pmem->ren.info.FileName[0])/sizeof(wchar_t); + + //Obtain file name + unsigned long size; + if(pNtQueryObject(fh, object_name_information, pmem.get(), sizeof(mem_t), &size)){ + return false; + } + + //Copy filename to the rename member + std::memmove(pmem->ren.info.FileName, pmem->name.Name.Buffer, pmem->name.Name.Length); + std::size_t filename_string_length = pmem->name.Name.Length/sizeof(wchar_t); + + //Second step: obtain the complete native-nt filename + //if(!get_file_name_from_handle_function(fh, pfri->FileName, RenMaxNumChars, filename_string_length)){ + //return 0; + //} + + //Add trailing mark + if((RenMaxNumChars-filename_string_length) < (SystemTimeOfDayInfoLength*2)){ + return false; + } + + //Search '\\' character to replace it + for(std::size_t i = filename_string_length; i != 0; --filename_string_length){ + if(pmem->ren.info.FileName[--i] == L'\\') + break; + } + + //Add random number + std::size_t s = RenMaxNumChars - filename_string_length; + if(!get_boot_and_system_time_wstr(&pfri->FileName[filename_string_length], s)){ + return false; + } + filename_string_length += s; + + //Fill rename information (FileNameLength is in bytes) + pfri->FileNameLength = static_cast(sizeof(wchar_t)*(filename_string_length)); + pfri->Replace = 1; + pfri->RootDir = 0; + + //Final step: change the name of the in-use file: + io_status_block_t io; + if(0 != pNtSetInformationFile(fh, &io, pfri, sizeof(mem_t::ren_t), file_rename_information)){ + return false; + } + return true; + } + catch(...){ + return false; + } +} + } //namespace winapi } //namespace interprocess } //namespace boost diff --git a/include/boost/interprocess/detail/workaround.hpp b/include/boost/interprocess/detail/workaround.hpp index 9e4f3fa..80168c7 100644 --- a/include/boost/interprocess/detail/workaround.hpp +++ b/include/boost/interprocess/detail/workaround.hpp @@ -8,40 +8,46 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_PTR_WRKRND_HPP -#define BOOST_INTERPROCESS_PTR_WRKRND_HPP +#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP +#define BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP #include -#undef BOOST_DISABLE_WIN32 +#if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) -#if !(defined BOOST_WINDOWS) || (defined BOOST_DISABLE_WIN32) +#define BOOST_INTERPROCESS_WINDOWS + +/* +#if !defined(_MSC_EXTENSIONS) +#error "Turn on Microsoft language extensions (_MSC_EXTENSIONS) to be able to call Windows API functions" +#endif +*/ + +#endif + +#if !(defined BOOST_INTERPROCESS_WINDOWS) #include - #if defined(_POSIX_THREAD_PROCESS_SHARED) - # if !((_XOPEN_VERSION >= 600) && (_POSIX_THREAD_PROCESS_SHARED - 0 <= 0)) + #if ((_POSIX_THREAD_PROCESS_SHARED - 0) > 0) //Cygwin defines _POSIX_THREAD_PROCESS_SHARED but does not implement it. //Mac Os X >= Leopard defines _POSIX_THREAD_PROCESS_SHARED but does not seems to work. # if !defined(__CYGWIN__) && !defined(__APPLE__) # define BOOST_INTERPROCESS_POSIX_PROCESS_SHARED # endif - # endif - #endif - - #if defined(_POSIX_BARRIERS) - # if !((_XOPEN_VERSION >= 600) && (_POSIX_BARRIERS - 0 <= 0)) + #endif + + #if ((_POSIX_BARRIERS - 0) > 0) # define BOOST_INTERPROCESS_POSIX_BARRIERS # endif - #endif - #if defined(_POSIX_SEMAPHORES) - # if !((_XOPEN_VERSION >= 600) && (_POSIX_SEMAPHORES - 0 <= 0)) - # define BOOST_INTERPROCESS_POSIX_SEMAPHORES + #if ((_POSIX_SEMAPHORES - 0) > 0) + # define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES # if defined(__CYGWIN__) #define BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK # endif - # endif + #elif defined(__APPLE__) + # define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES #endif #if ((defined _V6_ILP32_OFFBIG) &&(_V6_ILP32_OFFBIG - 0 > 0)) ||\ @@ -56,40 +62,41 @@ #else #endif - #if defined(_POSIX_SHARED_MEMORY_OBJECTS) - # if !((_XOPEN_VERSION >= 600) && (_POSIX_SHARED_MEMORY_OBJECTS - 0 <= 0)) + #if ((_POSIX_SHARED_MEMORY_OBJECTS - 0) > 0) # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS - # endif #else + //VMS and MACOS don't define it but the have shm_open/close interface # if defined(__vms) # if __CRTL_VER >= 70200000 # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS # endif + # define BOOST_INTERPROCESS_SYSTEM_V_SHARED_MEMORY_OBJECTS + //Mac OS has some non-conformant features like names limited to SHM_NAME_MAX + //# elif defined (__APPLE__) + //# define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS # endif #endif - #if defined(_POSIX_TIMEOUTS) - # if !((_XOPEN_VERSION >= 600) && (_POSIX_TIMEOUTS - 0 <= 0)) + #if ((_POSIX_TIMEOUTS - 0) > 0) # define BOOST_INTERPROCESS_POSIX_TIMEOUTS - # endif #endif + //Some systems have filesystem-based resources, so the + //portable "/shmname" format does not work due to permission issues + //For those systems we need to form a path to a temporary directory: + // hp-ux tru64 vms freebsd + #if defined(__hpux) || defined(__osf__) || defined(__vms) || defined(__FreeBSD__) + #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_RESOURCES + #endif + #ifdef BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS - //Some systems have filesystem-based shared memory, so the - //portable "/shmname" format does not work due to permission issues - //For those systems we need to form a path to a temporary directory: - // hp-ux tru64 vms - #if defined(__hpux) || defined(__osf__) || defined(__vms) + #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_RESOURCES) #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY #endif #endif - #ifdef BOOST_INTERPROCESS_POSIX_SEMAPHORES - //Some systems have filesystem-based shared memory, so the - //portable "/semname" format does not work due to permission issues - //For those systems we need to form a path to a temporary directory: - // hp-ux tru64 vms - #if defined(__hpux) || defined(__osf__) || defined(__vms) + #ifdef BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES + #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_RESOURCES) #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES #endif #endif @@ -100,34 +107,20 @@ #endif -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2) -// C++0x features are only enabled when -std=c++0x or -std=gnu++0x are -// passed on the command line, which in turn defines -// __GXX_EXPERIMENTAL_CXX0X__. Note: __GXX_EXPERIMENTAL_CPP0X__ is -// defined by some very early development versions of GCC 4.3; we will -// remove this part of the check in the near future. -# if defined(__GXX_EXPERIMENTAL_CPP0X__) || defined(__GXX_EXPERIMENTAL_CXX0X__) -# define BOOST_INTERPROCESS_RVALUE_REFERENCE -# define BOOST_INTERPROCESS_VARIADIC_TEMPLATES -# if defined(__GLIBCPP__) || defined(__GLIBCXX__) -# define BOOST_INTERPROCESS_RVALUE_PAIR -# endif -# endif -#endif - -#if defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && defined(BOOST_INTERPROCESS_VARIADIC_TEMPLATES) +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)\ + && !defined(BOOST_INTERPROCESS_DISABLE_VARIADIC_TMPL) #define BOOST_INTERPROCESS_PERFECT_FORWARDING #endif //Now declare some Boost.Interprocess features depending on the implementation -#if defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) +#if defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) #define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES #endif -#if defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) +#if defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) #define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES #define BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES @@ -136,4 +129,4 @@ #include -#endif //#ifndef BOOST_INTERPROCESS_PTR_WRKRND_HPP +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP diff --git a/include/boost/interprocess/errors.hpp b/include/boost/interprocess/errors.hpp index 8c17c2c..cdd4208 100644 --- a/include/boost/interprocess/errors.hpp +++ b/include/boost/interprocess/errors.hpp @@ -33,7 +33,7 @@ #include #include -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include #else # ifdef BOOST_HAS_UNISTD_H @@ -42,7 +42,7 @@ # else //ifdef BOOST_HAS_UNISTD_H # error Unknown platform # endif //ifdef BOOST_HAS_UNISTD_H -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) //!\file //!Describes the error numbering of interprocess classes @@ -52,7 +52,7 @@ namespace interprocess { /// @cond static inline int system_error_code() // artifact of POSIX and WINDOWS error reporting { - #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #if (defined BOOST_INTERPROCESS_WINDOWS) return winapi::get_last_error(); #else return errno; // GCC 3.1 won't accept ::errno @@ -60,7 +60,7 @@ static inline int system_error_code() // artifact of POSIX and WINDOWS error rep } -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) inline void fill_system_message(int sys_err_code, std::string &str) { void *lpMsgBuf; @@ -110,7 +110,9 @@ enum error_code_t sem_error, mode_error, size_error, - corrupted_error + corrupted_error, + not_such_file_or_directory, + invalid_argument }; typedef int native_error_t; @@ -124,7 +126,7 @@ struct ec_xlate static const ec_xlate ec_table[] = { - #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #if (defined BOOST_INTERPROCESS_WINDOWS) { /*ERROR_ACCESS_DENIED*/5L, security_error }, { /*ERROR_INVALID_ACCESS*/12L, security_error }, { /*ERROR_SHARING_VIOLATION*/32L, security_error }, @@ -156,7 +158,7 @@ static const ec_xlate ec_table[] = { /*ERROR_OUTOFMEMORY*/14L, out_of_memory_error }, { /*ERROR_NOT_ENOUGH_MEMORY*/8L, out_of_memory_error }, { /*ERROR_TOO_MANY_OPEN_FILES*/4L, out_of_resource_error } - #else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #else //#if (defined BOOST_INTERPROCESS_WINDOWS) { EACCES, security_error }, { EROFS, read_only_error }, { EIO, io_error }, @@ -171,8 +173,10 @@ static const ec_xlate ec_table[] = { EISDIR, is_directory_error }, { ENOSPC, out_of_space_error }, { ENOMEM, out_of_memory_error }, - { EMFILE, out_of_resource_error } - #endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + { EMFILE, out_of_resource_error }, + { ENOENT, not_such_file_or_directory }, + { EINVAL, invalid_argument } + #endif //#if (defined BOOST_INTERPROCESS_WINDOWS) }; static inline error_code_t lookup_error(native_error_t err) diff --git a/include/boost/interprocess/file_mapping.hpp b/include/boost/interprocess/file_mapping.hpp index 37391e2..6dbefb4 100644 --- a/include/boost/interprocess/file_mapping.hpp +++ b/include/boost/interprocess/file_mapping.hpp @@ -21,8 +21,6 @@ #include #include #include //std::string -#include //std::remove -#include //!\file //!Describes file_mapping and mapped region classes @@ -30,31 +28,19 @@ namespace boost { namespace interprocess { -///@cond - -class file_mapping; - -//!Trait class to detect if a type is -//!movable -template<> -struct is_movable -{ - enum { value = true }; -}; - -///@endcond - //!A class that wraps a file-mapping that can be used to //!create mapped regions from the mapped files class file_mapping { /// @cond //Non-copyable and non-assignable - file_mapping(const file_mapping &); - file_mapping &operator=(const file_mapping &); + file_mapping(file_mapping &); + file_mapping &operator=(file_mapping &); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(file_mapping) + //!Constructs an empty file mapping. //!Does not throw file_mapping(); @@ -68,41 +54,23 @@ class file_mapping //!Moves the ownership of "moved"'s file mapping object to *this. //!After the call, "moved" does not represent any file mapping object. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - file_mapping(detail::moved_object moved) - : m_handle(file_handle_t(detail::invalid_file())) - { this->swap(moved.get()); } - #else - file_mapping(file_mapping &&moved) + file_mapping(BOOST_INTERPROCESS_RV_REF(file_mapping) moved) : m_handle(file_handle_t(detail::invalid_file())) { this->swap(moved); } - #endif //!Moves the ownership of "moved"'s file mapping to *this. //!After the call, "moved" does not represent any file mapping. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - file_mapping &operator=(detail::moved_object m_other) - { - file_mapping &moved = m_other.get(); - #else - file_mapping &operator=(file_mapping &&moved) - { - #endif - file_mapping tmp(detail::move_impl(moved)); + file_mapping &operator=(BOOST_INTERPROCESS_RV_REF(file_mapping) moved) + { + file_mapping tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } //!Swaps to file_mappings. //!Does not throw. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(file_mapping &other); - #else - void swap(file_mapping &&other); - #endif //!Returns access mode //!used in the constructor @@ -120,6 +88,12 @@ class file_mapping //!used in the constructor. const char *get_name() const; + //!Removes the file named "filename" even if it's been memory mapped. + //!Returns true on success. + //!The function might fail in some operating systems if the file is + //!being used other processes and no deletion permission was shared. + static bool remove(const char *filename); + /// @cond private: //!Closes a previously opened file mapping. Never throws. @@ -140,11 +114,7 @@ inline file_mapping::~file_mapping() inline const char *file_mapping::get_name() const { return m_filename.c_str(); } -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) inline void file_mapping::swap(file_mapping &other) -#else -inline void file_mapping::swap(file_mapping &&other) -#endif { std::swap(m_handle, other.m_handle); std::swap(m_mode, other.m_mode); @@ -179,6 +149,9 @@ inline file_mapping::file_mapping m_mode = mode; } +inline bool file_mapping::remove(const char *filename) +{ return detail::delete_file(filename); } + ///@cond inline void file_mapping::priv_close() @@ -192,7 +165,7 @@ inline void file_mapping::priv_close() ///@endcond //!A class that stores the name of a file -//!and call std::remove(name) in its destructor +//!and tries to remove it in its destructor //!Useful to remove temporary files in the presence //!of exceptions class remove_file_on_destroy @@ -204,7 +177,7 @@ class remove_file_on_destroy {} ~remove_file_on_destroy() - { std::remove(m_name); } + { detail::delete_file(m_name); } }; } //namespace interprocess { diff --git a/include/boost/interprocess/indexes/iunordered_set_index.hpp b/include/boost/interprocess/indexes/iunordered_set_index.hpp index 1b059a3..522ab4a 100644 --- a/include/boost/interprocess/indexes/iunordered_set_index.hpp +++ b/include/boost/interprocess/indexes/iunordered_set_index.hpp @@ -176,7 +176,7 @@ class iunordered_set_index return old_size; std::size_t received_size; if(!alloc.allocation_command - (try_shrink_in_place | nothrow_allocation, old_size, new_size, received_size, buckets).first){ + (boost::interprocess::try_shrink_in_place | boost::interprocess::nothrow_allocation, old_size, new_size, received_size, buckets).first){ return old_size; } @@ -188,7 +188,7 @@ class iunordered_set_index } bucket_ptr shunk_p = alloc.allocation_command - (shrink_in_place | nothrow_allocation, received_size, received_size, received_size, buckets).first; + (boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, received_size, received_size, received_size, buckets).first; BOOST_ASSERT(buckets == shunk_p); bucket_ptr buckets_init = buckets + received_size; @@ -205,7 +205,7 @@ class iunordered_set_index std::size_t received_size; std::pair ret = alloc.allocation_command - (expand_fwd | allocate_new, new_num, new_num, received_size, old_buckets); + (boost::interprocess::expand_fwd | boost::interprocess::allocate_new, new_num, new_num, received_size, old_buckets); if(ret.first == old_buckets){ bucket_ptr buckets_init = old_buckets + old_num; for(std::size_t i = 0; i < (new_num - old_num); ++i){ diff --git a/include/boost/interprocess/interprocess_fwd.hpp b/include/boost/interprocess/interprocess_fwd.hpp index aca3960..575a2a9 100644 --- a/include/boost/interprocess/interprocess_fwd.hpp +++ b/include/boost/interprocess/interprocess_fwd.hpp @@ -11,12 +11,12 @@ #ifndef BOOST_INTERPROCESS_FWD_HPP #define BOOST_INTERPROCESS_FWD_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined (_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -//#include -//#include +#include +#include #include @@ -61,9 +61,9 @@ namespace boost { namespace interprocess { class shared_memory_object; -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if defined (BOOST_INTERPROCESS_WINDOWS) class windows_shared_memory; -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) ////////////////////////////////////////////////////////////////////////////// // mapped file/mapped region/mapped_file @@ -113,6 +113,9 @@ class scoped_lock; template class sharable_lock; +template +class upgradable_lock; + ////////////////////////////////////////////////////////////////////////////// // STL compatible allocators ////////////////////////////////////////////////////////////////////////////// @@ -230,7 +233,7 @@ wmanaged_shared_memory; // Windows shared memory managed memory classes ////////////////////////////////////////////////////////////////////////////// -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if defined (BOOST_INTERPROCESS_WINDOWS) template wmanaged_windows_shared_memory; -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#else + +template class IndexType> +class basic_managed_xsi_shared_memory; + +typedef basic_managed_xsi_shared_memory + + ,iset_index> +managed_xsi_shared_memory; + +typedef basic_managed_xsi_shared_memory + + ,iset_index> +wmanaged_xsi_shared_memory; + +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) ////////////////////////////////////////////////////////////////////////////// // Fixed address shared memory @@ -382,98 +404,12 @@ class weak_ptr; class message_queue; -////////////////////////////////////////////////////////////////////////////// -// Containers -////////////////////////////////////////////////////////////////////////////// - -//vector class -template > -class vector; - -//vector class -template > -class deque; - -//list class -template > -class list; - -//slist class -template > -class slist; - -//set class -template - ,class Alloc = std::allocator > -class set; - -//multiset class -template - ,class Alloc = std::allocator > -class multiset; - -//map class -template - ,class Alloc = std::allocator > > -class map; - -//multimap class -template - ,class Alloc = std::allocator > > -class multimap; - -//flat_set class -template - ,class Alloc = std::allocator > -class flat_set; - -//flat_multiset class -template - ,class Alloc = std::allocator > -class flat_multiset; - -//flat_map class -template - ,class Alloc = std::allocator > > -class flat_map; - -//flat_multimap class -template - ,class Alloc = std::allocator > > -class flat_multimap; - -//basic_string class -template - ,class Alloc = std::allocator > -class basic_string; - -//string class -typedef basic_string - - ,std::allocator > -string; - }} //namespace boost { namespace interprocess { -//#include +////////////////////////////////////////////////////////////////////////////// +// CONTAINERS +////////////////////////////////////////////////////////////////////////////// + +#include #endif //#ifndef BOOST_INTERPROCESS_FWD_HPP - diff --git a/include/boost/interprocess/managed_external_buffer.hpp b/include/boost/interprocess/managed_external_buffer.hpp index 88550f6..30b822a 100644 --- a/include/boost/interprocess/managed_external_buffer.hpp +++ b/include/boost/interprocess/managed_external_buffer.hpp @@ -43,9 +43,12 @@ class basic_managed_external_buffer /// @cond typedef detail::basic_managed_memory_impl base_t; + basic_managed_external_buffer(basic_managed_external_buffer&); + basic_managed_external_buffer & operator=(basic_managed_external_buffer&); /// @endcond - + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_managed_external_buffer) //!Default constructor. Does nothing. //!Useful in combination with move semantics @@ -75,25 +78,15 @@ class basic_managed_external_buffer } //!Moves the ownership of "moved"'s managed memory to *this. Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_external_buffer(detail::moved_object mother) + basic_managed_external_buffer(BOOST_INTERPROCESS_RV_REF(basic_managed_external_buffer) moved) { - basic_managed_external_buffer &moved = mother.get(); - #else - basic_managed_external_buffer(basic_managed_external_buffer &&moved) - { - #endif this->swap(moved); } //!Moves the ownership of "moved"'s managed memory to *this. Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_external_buffer &operator=(detail::moved_object moved) - #else - basic_managed_external_buffer &operator=(basic_managed_external_buffer &&moved) - #endif + basic_managed_external_buffer &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_external_buffer) moved) { - basic_managed_external_buffer tmp(detail::move_impl(moved)); + basic_managed_external_buffer tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -103,36 +96,10 @@ class basic_managed_external_buffer //!Swaps the ownership of the managed heap memories managed by *this and other. //!Never throws. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(basic_managed_external_buffer &other) - #else - void swap(basic_managed_external_buffer &&other) - #endif { base_t::swap(other); } }; -///@cond - -//!Trait class to detect if a type is -//!movable -template - < - class CharType, - class AllocationAlgorithm, - template class IndexType - > -struct is_movable -> -{ - static const bool value = true; -}; - -///@endcond - - } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/managed_heap_memory.hpp b/include/boost/interprocess/managed_heap_memory.hpp index 87a5452..5bc4509 100644 --- a/include/boost/interprocess/managed_heap_memory.hpp +++ b/include/boost/interprocess/managed_heap_memory.hpp @@ -46,9 +46,12 @@ class basic_managed_heap_memory typedef detail::basic_managed_memory_impl base_t; + basic_managed_heap_memory(basic_managed_heap_memory&); + basic_managed_heap_memory & operator=(basic_managed_heap_memory&); /// @endcond public: //functions + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_managed_heap_memory) //!Default constructor. Does nothing. //!Useful in combination with move semantics @@ -71,26 +74,13 @@ class basic_managed_heap_memory } //!Moves the ownership of "moved"'s managed memory to *this. Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_heap_memory - (detail::moved_object mother) - { - basic_managed_heap_memory &moved = mother.get(); - #else - basic_managed_heap_memory(basic_managed_heap_memory &&moved) - { - #endif - this->swap(moved); - } + basic_managed_heap_memory(BOOST_INTERPROCESS_RV_REF(basic_managed_heap_memory) moved) + { this->swap(moved); } //!Moves the ownership of "moved"'s managed memory to *this. Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_heap_memory &operator=(detail::moved_object moved) - #else - basic_managed_heap_memory &operator=(basic_managed_heap_memory &&moved) - #endif + basic_managed_heap_memory &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_heap_memory) moved) { - basic_managed_heap_memory tmp(detail::move_impl(moved)); + basic_managed_heap_memory tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -125,13 +115,7 @@ class basic_managed_heap_memory //!Swaps the ownership of the managed heap memories managed by *this and other. //!Never throws. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(basic_managed_heap_memory &other) - #else - void swap(basic_managed_heap_memory &&other) - #endif { base_t::swap(other); m_heapmem.swap(other.m_heapmem); @@ -150,27 +134,8 @@ class basic_managed_heap_memory /// @endcond }; -///@cond - -//!Trait class to detect if a type is -//!movable -template - < - class CharType, - class AllocationAlgorithm, - template class IndexType - > -struct is_movable -> -{ - static const bool value = true; -}; - -///@endcond } //namespace interprocess { - } //namespace boost { #include diff --git a/include/boost/interprocess/managed_mapped_file.hpp b/include/boost/interprocess/managed_mapped_file.hpp index dee8488..065c424 100644 --- a/include/boost/interprocess/managed_mapped_file.hpp +++ b/include/boost/interprocess/managed_mapped_file.hpp @@ -47,6 +47,8 @@ class basic_managed_mapped_file ::ManagedOpenOrCreateUserOffset> base_t; typedef detail::file_wrapper device_type; + basic_managed_mapped_file(basic_managed_mapped_file&); + basic_managed_mapped_file & operator=(basic_managed_mapped_file&); private: @@ -61,6 +63,7 @@ class basic_managed_mapped_file /// @endcond public: //functions + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_managed_mapped_file) //!Creates mapped file and creates and places the segment manager. //!This can throw. @@ -118,27 +121,16 @@ class basic_managed_mapped_file //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_mapped_file - (detail::moved_object mother) + basic_managed_mapped_file(BOOST_INTERPROCESS_RV_REF(basic_managed_mapped_file) moved) { - basic_managed_mapped_file &moved = mother.get(); - #else - basic_managed_mapped_file(basic_managed_mapped_file &&moved) - { - #endif this->swap(moved); } //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_mapped_file &operator=(detail::moved_object moved) - #else - basic_managed_mapped_file &operator=(basic_managed_mapped_file &&moved) - #endif + basic_managed_mapped_file &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_mapped_file) moved) { - basic_managed_mapped_file tmp(detail::move_impl(moved)); + basic_managed_mapped_file tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -154,14 +146,7 @@ class basic_managed_mapped_file //!Swaps the ownership of the managed mapped memories managed by *this and other. //!Never throws. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } - void swap(basic_managed_mapped_file &other) - #else - void swap(basic_managed_mapped_file &&other) - #endif { base_t::swap(other); m_mfile.swap(other.m_mfile); @@ -214,27 +199,7 @@ class basic_managed_mapped_file /// @endcond }; -///@cond - -//!Trait class to detect if a type is -//!movable -template - < - class CharType, - class AllocationAlgorithm, - template class IndexType - > -struct is_movable -> -{ - static const bool value = true; -}; - -///@endcond - } //namespace interprocess { - } //namespace boost { #include diff --git a/include/boost/interprocess/managed_shared_memory.hpp b/include/boost/interprocess/managed_shared_memory.hpp index a726e06..990585e 100644 --- a/include/boost/interprocess/managed_shared_memory.hpp +++ b/include/boost/interprocess/managed_shared_memory.hpp @@ -60,9 +60,12 @@ class basic_managed_shared_memory private: typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; + basic_managed_shared_memory(basic_managed_shared_memory&); + basic_managed_shared_memory & operator=(basic_managed_shared_memory&); /// @endcond public: //functions + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_managed_shared_memory) //!Destroys *this and indicates that the calling process is finished using //!the resource. The destructor function will deallocate @@ -134,14 +137,8 @@ class basic_managed_shared_memory //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_shared_memory(detail::moved_object mother) + basic_managed_shared_memory(BOOST_INTERPROCESS_RV_REF(basic_managed_shared_memory) moved) { - basic_managed_shared_memory &moved = mother.get(); - #else - basic_managed_shared_memory(basic_managed_shared_memory &&moved) - { - #endif basic_managed_shared_memory tmp; this->swap(moved); tmp.swap(moved); @@ -149,26 +146,16 @@ class basic_managed_shared_memory //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_shared_memory &operator=(detail::moved_object moved) - #else - basic_managed_shared_memory &operator=(basic_managed_shared_memory &&moved) - #endif + basic_managed_shared_memory &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_shared_memory) moved) { - basic_managed_shared_memory tmp(detail::move_impl(moved)); + basic_managed_shared_memory tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } //!Swaps the ownership of the managed shared memories managed by *this and other. //!Never throws. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(basic_managed_shared_memory &other) - #else - void swap(basic_managed_shared_memory &&other) - #endif { base_t::swap(other); base2_t::swap(other); @@ -179,20 +166,20 @@ class basic_managed_shared_memory //! //!This function is not synchronized so no other thread or process should //!be reading or writing the file - static bool grow(const char *filename, std::size_t extra_bytes) + static bool grow(const char *shmname, std::size_t extra_bytes) { return base_t::template grow - (filename, extra_bytes); + (shmname, extra_bytes); } //!Tries to resize the managed shared memory to minimized the size of the file. //! //!This function is not synchronized so no other thread or process should //!be reading or writing the file - static bool shrink_to_fit(const char *filename) + static bool shrink_to_fit(const char *shmname) { return base_t::template shrink_to_fit - (filename); + (shmname); } /// @cond @@ -214,25 +201,6 @@ class basic_managed_shared_memory /// @endcond }; -///@cond - -//!Trait class to detect if a type is -//!movable -template - < - class CharType, - class AllocationAlgorithm, - template class IndexType - > -struct is_movable -> -{ - static const bool value = true; -}; - -///@endcond - } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/managed_windows_shared_memory.hpp b/include/boost/interprocess/managed_windows_shared_memory.hpp index a0e9a92..144352b 100644 --- a/include/boost/interprocess/managed_windows_shared_memory.hpp +++ b/include/boost/interprocess/managed_windows_shared_memory.hpp @@ -60,9 +60,13 @@ class basic_managed_windows_shared_memory private: typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; + basic_managed_windows_shared_memory(basic_managed_windows_shared_memory&); + basic_managed_windows_shared_memory & operator=(basic_managed_windows_shared_memory&); + /// @endcond public: //functions + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_managed_windows_shared_memory) //!Default constructor. Does nothing. //!Useful in combination with move semantics @@ -121,24 +125,15 @@ class basic_managed_windows_shared_memory //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) basic_managed_windows_shared_memory - (detail::moved_object moved) - { this->swap(moved.get()); } - #else - basic_managed_windows_shared_memory(basic_managed_windows_shared_memory &&moved) + (BOOST_INTERPROCESS_RV_REF(basic_managed_windows_shared_memory) moved) { this->swap(moved); } - #endif //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_windows_shared_memory &operator=(detail::moved_object moved) - #else - basic_managed_windows_shared_memory &operator=(basic_managed_windows_shared_memory &&moved) - #endif + basic_managed_windows_shared_memory &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_windows_shared_memory) moved) { - basic_managed_windows_shared_memory tmp(detail::move_impl(moved)); + basic_managed_windows_shared_memory tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -153,19 +148,14 @@ class basic_managed_windows_shared_memory //!Swaps the ownership of the managed mapped memories managed by *this and other. //!Never throws. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(basic_managed_windows_shared_memory &other) - #else - void swap(basic_managed_windows_shared_memory &&other) - #endif { base_t::swap(other); m_wshm.swap(other.m_wshm); } /// @cond + //!Tries to find a previous named allocation address. Returns a memory //!buffer and the object count. If not found returned pointer is 0. //!Never throws. @@ -185,25 +175,6 @@ class basic_managed_windows_shared_memory /// @endcond }; -///@cond - -//!Trait class to detect if a type is -//!movable -template - < - class CharType, - class AllocationAlgorithm, - template class IndexType - > -struct is_movable -> -{ - static const bool value = true; -}; - -///@endcond - } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/mapped_region.hpp b/include/boost/interprocess/mapped_region.hpp index 115b25d..f571272 100644 --- a/include/boost/interprocess/mapped_region.hpp +++ b/include/boost/interprocess/mapped_region.hpp @@ -22,7 +22,7 @@ #include #include -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include #else # ifdef BOOST_HAS_UNISTD_H @@ -31,11 +31,13 @@ # include # include # include +# include +# include # else # error Unknown platform # endif -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) //!\file //!Describes memory_mappable and mapped region classes @@ -55,11 +57,12 @@ class mapped_region { /// @cond //Non-copyable - mapped_region(const mapped_region &); - mapped_region &operator=(const mapped_region &); + mapped_region(mapped_region &); + mapped_region &operator=(mapped_region &); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(mapped_region) //!Creates a mapping region of the mapped memory "mapping", starting in //!offset "offset", and the mapping's size will be "size". The mapping @@ -78,11 +81,7 @@ class mapped_region //!Move constructor. *this will be constructed taking ownership of "other"'s //!region and "other" will be left in default constructor state. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - mapped_region(detail::moved_object other); - #else - mapped_region(mapped_region &&other); - #endif + mapped_region(BOOST_INTERPROCESS_RV_REF(mapped_region) other); //!Destroys the mapped region. //!Does not throw @@ -90,11 +89,7 @@ class mapped_region //!Move assignment. If *this owns a memory mapped region, it will be //!destroyed and it will take ownership of "other"'s memory mapped region. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - mapped_region &operator=(detail::moved_object other); - #else - mapped_region &operator=(mapped_region &&other); - #endif + mapped_region &operator=(BOOST_INTERPROCESS_RV_REF(mapped_region) other); //!Returns the size of the mapping. Note for windows users: If //!windows_shared_memory is mapped using 0 as the size, it returns 0 @@ -119,13 +114,7 @@ class mapped_region //!Swaps the mapped_region with another //!mapped region - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(mapped_region &other); - #else - void swap(mapped_region &&other); - #endif //!Returns the size of the page. This size is the minimum memory that //!will be used by the system when mapping a memory mappable source. @@ -148,8 +137,10 @@ class mapped_region offset_t m_offset; offset_t m_extra_offset; mode_t m_mode; - #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) - file_handle_t m_file_mapping_hnd; + #if (defined BOOST_INTERPROCESS_WINDOWS) + file_handle_t m_file_mapping_hnd; + #else + bool m_is_xsi; #endif friend class detail::interprocess_tester; @@ -163,14 +154,9 @@ class mapped_region inline void swap(mapped_region &x, mapped_region &y) { x.swap(y); } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -inline mapped_region &mapped_region::operator=(detail::moved_object moved) +inline mapped_region &mapped_region::operator=(BOOST_INTERPROCESS_RV_REF(mapped_region) moved) { -#else -inline mapped_region &mapped_region::operator=(mapped_region &&moved) -{ -#endif - mapped_region tmp(detail::move_impl(moved)); + mapped_region tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -190,28 +176,19 @@ inline mode_t mapped_region::get_mode() const inline void* mapped_region::get_address() const { return m_base; } -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) inline mapped_region::mapped_region() : m_base(0), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only) , m_file_mapping_hnd(detail::invalid_file()) {} -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -inline mapped_region::mapped_region(detail::moved_object other) - : m_base(0), m_size(0), m_offset(0) - , m_extra_offset(0) - , m_mode(read_only) - , m_file_mapping_hnd(detail::invalid_file()) -{ this->swap(other.get()); } -#else -inline mapped_region::mapped_region(mapped_region &&other) +inline mapped_region::mapped_region(BOOST_INTERPROCESS_RV_REF(mapped_region) other) : m_base(0), m_size(0), m_offset(0) , m_extra_offset(0) , m_mode(read_only) , m_file_mapping_hnd(detail::invalid_file()) { this->swap(other); } -#endif template inline std::size_t mapped_region::page_size_holder::get_page_size() @@ -264,7 +241,9 @@ inline mapped_region::mapped_region //Update mapping size if the user does not specify it if(size == 0){ __int64 total_size; - if(!winapi::get_file_size(detail::file_handle_from_mapping_handle(mapping.get_mapping_handle()), total_size)){ + if(!winapi::get_file_size + (detail::file_handle_from_mapping_handle + (mapping.get_mapping_handle()), total_size)){ error_info err(winapi::get_last_error()); throw interprocess_exception(err); } @@ -382,11 +361,10 @@ inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbyte inline void mapped_region::priv_close() { if(m_base){ - this->flush(); winapi::unmap_view_of_file(static_cast(m_base) - m_extra_offset); m_base = 0; } - #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #if (defined BOOST_INTERPROCESS_WINDOWS) if(m_file_mapping_hnd != detail::invalid_file()){ winapi::close_handle(m_file_mapping_hnd); m_file_mapping_hnd = detail::invalid_file(); @@ -397,22 +375,15 @@ inline void mapped_region::priv_close() inline void mapped_region::dont_close_on_destruction() {} -#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#else //#if (defined BOOST_INTERPROCESS_WINDOWS) inline mapped_region::mapped_region() - : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only), m_is_xsi(false) {} -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -inline mapped_region::mapped_region(detail::moved_object other) - : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only) -{ this->swap(other.get()); } -#else -inline mapped_region::mapped_region(mapped_region &&other) - : m_base(MAP_FAILED), m_size(0), m_offset(0), m_mode(read_only) - , m_extra_offset(0) +inline mapped_region::mapped_region(BOOST_INTERPROCESS_RV_REF(mapped_region) other) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only), m_is_xsi(false) { this->swap(other); } -#endif template inline std::size_t mapped_region::page_size_holder::get_page_size() @@ -425,13 +396,55 @@ inline mapped_region::mapped_region offset_t offset, std::size_t size, const void *address) - : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(mode) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(mode), m_is_xsi(false) { + mapping_handle_t map_hnd = mapping.get_mapping_handle(); + + if(map_hnd.is_xsi){ + //Get the size + ::shmid_ds xsi_ds; + int ret = ::shmctl(map_hnd.handle, IPC_STAT, &xsi_ds); + if(ret == -1){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } + //Compare sizess + if(size == 0){ + size = (std::size_t)xsi_ds.shm_segsz; + } + else if(size != (std::size_t)xsi_ds.shm_segsz){ + error_info err(size_error); + throw interprocess_exception(err); + } + //Calculate flag + int flag = 0; + if(m_mode == read_only){ + flag |= SHM_RDONLY; + } + else if(m_mode != read_write){ + error_info err(mode_error); + throw interprocess_exception(err); + } + //Attach memory + void *base = ::shmat(map_hnd.handle, (void*)address, flag); + if(base == (void*)-1){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } + //Update members + m_base = base; + m_offset = offset; + m_size = size; + m_mode = mode; + m_extra_offset = 0; + m_is_xsi = true; + + return; + } + if(size == 0){ -// offset_t filesize = lseek64 offset_t filesize = lseek - (mapping.get_mapping_handle(), offset, SEEK_END); - + (map_hnd.handle, offset, SEEK_END); if(filesize == -1 ){ error_info err(system_error_code()); throw interprocess_exception(err); @@ -440,12 +453,13 @@ inline mapped_region::mapped_region error_info err(size_error); throw interprocess_exception(err); } + filesize -= offset; - size = (size_t)filesize; + if((offset_t)size != filesize){ error_info err(size_error); - throw interprocess_exception(err); + throw interprocess_exception(err); } } @@ -459,7 +473,7 @@ inline mapped_region::mapped_region prot |= PROT_READ; flags |= MAP_SHARED; break; - + case read_write: prot |= (PROT_WRITE | PROT_READ); flags |= MAP_SHARED; @@ -469,7 +483,7 @@ inline mapped_region::mapped_region prot |= (PROT_WRITE | PROT_READ); flags |= MAP_PRIVATE; break; - + default: { error_info err(mode_error); @@ -496,7 +510,7 @@ inline mapped_region::mapped_region , static_cast(m_extra_offset + m_size) , prot , flags - , mapping.get_mapping_handle() + , mapping.get_mapping_handle().handle , offset - m_extra_offset); //Check if mapping was successful @@ -537,7 +551,12 @@ inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbyte inline void mapped_region::priv_close() { if(m_base != MAP_FAILED){ - this->flush(); + if(m_is_xsi){ + int ret = ::shmdt(m_base); + assert(ret == 0); + (void)ret; + return; + } munmap(static_cast(m_base) - m_extra_offset, m_size + m_extra_offset); m_base = MAP_FAILED; } @@ -546,7 +565,7 @@ inline void mapped_region::priv_close() inline void mapped_region::dont_close_on_destruction() { m_base = MAP_FAILED; } -#endif //##if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //##if (defined BOOST_INTERPROCESS_WINDOWS) template const std::size_t mapped_region::page_size_holder::PageSize @@ -560,19 +579,17 @@ inline std::size_t mapped_region::get_page_size() return page_size_holder<0>::PageSize; } -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) inline void mapped_region::swap(mapped_region &other) -#else -inline void mapped_region::swap(mapped_region &&other) -#endif { detail::do_swap(this->m_base, other.m_base); detail::do_swap(this->m_size, other.m_size); detail::do_swap(this->m_offset, other.m_offset); detail::do_swap(this->m_extra_offset, other.m_extra_offset); - detail::do_swap(this->m_mode, other.m_mode); - #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + detail::do_swap(this->m_mode, other.m_mode); + #if (defined BOOST_INTERPROCESS_WINDOWS) detail::do_swap(this->m_file_mapping_hnd, other.m_file_mapping_hnd); + #else + detail::do_swap(this->m_is_xsi, other.m_is_xsi); #endif } @@ -583,13 +600,6 @@ struct null_mapped_region_function { return true; } }; -//!Trait class to detect if a type is -//!movable -template<> -struct is_movable -{ - enum { value = true }; -}; /// @endcond } //namespace interprocess { diff --git a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp index 2cdc2ce..dec5300 100644 --- a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp +++ b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -19,14 +19,17 @@ #include #include -#include +#include #include #include -#include #include #include +#include #include #include +#include +#include +#include //!\file //!Implements common operations for memory algorithms. @@ -36,206 +39,527 @@ namespace interprocess { namespace detail { template -struct multi_allocation_next +class basic_multiallocation_slist { - typedef typename detail:: - pointer_to_other::type - multi_allocation_next_ptr; - - multi_allocation_next(multi_allocation_next_ptr n) - : next_(n) - {} - multi_allocation_next_ptr next_; -}; - -//!This iterator is returned by "allocate_many" functions so that -//!the user can access the multiple buffers allocated in a single call -template -class basic_multiallocation_iterator - : public std::iterator -{ - void unspecified_bool_type_func() const {} - typedef void (basic_multiallocation_iterator::*unspecified_bool_type)() const; - typedef typename detail:: - pointer_to_other - >::type - multi_allocation_next_ptr; - public: - typedef char value_type; - typedef value_type & reference; - typedef value_type * pointer; - - basic_multiallocation_iterator() - : next_alloc_(0) - {} - - basic_multiallocation_iterator(multi_allocation_next_ptr next) - : next_alloc_(next) - {} - - basic_multiallocation_iterator &operator=(const basic_multiallocation_iterator &other) - { next_alloc_ = other.next_alloc_; return *this; } - - public: - basic_multiallocation_iterator& operator++() - { next_alloc_.next_ = detail::get_pointer(next_alloc_.next_->next_); return *this; } - - basic_multiallocation_iterator operator++(int) - { - basic_multiallocation_iterator result(next_alloc_.next_); - ++*this; - return result; - } - - bool operator== (const basic_multiallocation_iterator& other) const - { return next_alloc_.next_ == other.next_alloc_.next_; } - - bool operator!= (const basic_multiallocation_iterator& other) const - { return !operator== (other); } - - reference operator*() const - { return *reinterpret_cast(detail::get_pointer(next_alloc_.next_)); } - - operator unspecified_bool_type() const - { return next_alloc_.next_? &basic_multiallocation_iterator::unspecified_bool_type_func : 0; } - - pointer operator->() const - { return &(*(*this)); } - - static basic_multiallocation_iterator create_simple_range(void *mem) - { - basic_multiallocation_iterator it; - typedef multi_allocation_next next_impl_t; - next_impl_t * tmp_mem = static_cast(mem); - it = basic_multiallocation_iterator(tmp_mem); - tmp_mem->next_ = 0; - return it; - } - - multi_allocation_next &get_multi_allocation_next() - { return *next_alloc_.next_; } + typedef VoidPointer void_pointer; private: - multi_allocation_next next_alloc_; -}; + static VoidPointer &priv_get_ref(const VoidPointer &p) + { return *static_cast(detail::get_pointer(p)); } -template -class basic_multiallocation_chain -{ - private: - basic_multiallocation_iterator it_; - VoidPointer last_mem_; - std::size_t num_mem_; - - basic_multiallocation_chain(const basic_multiallocation_chain &); - basic_multiallocation_chain &operator=(const basic_multiallocation_chain &); + basic_multiallocation_slist(basic_multiallocation_slist &); + basic_multiallocation_slist &operator=(basic_multiallocation_slist &); public: - typedef basic_multiallocation_iterator multiallocation_iterator; + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_slist) - basic_multiallocation_chain() - : it_(0), last_mem_(0), num_mem_(0) - {} - - void reset() + //!This iterator is returned by "allocate_many" functions so that + //!the user can access the multiple buffers allocated in a single call + class iterator + : public std::iterator { - this->it_ = multiallocation_iterator(); - this->last_mem_ = 0; - this->num_mem_ = 0; - } + friend class basic_multiallocation_slist; + void unspecified_bool_type_func() const {} + typedef void (iterator::*unspecified_bool_type)() const; - void push_back(void *mem) - { - typedef multi_allocation_next next_impl_t; - next_impl_t * tmp_mem = static_cast(mem); + iterator(void_pointer node_range) + : next_node_(node_range) + {} + + public: + typedef char value_type; + typedef value_type & reference; + typedef value_type * pointer; + + iterator() + : next_node_(0) + {} + + iterator &operator=(const iterator &other) + { next_node_ = other.next_node_; return *this; } + + public: + iterator& operator++() + { + next_node_ = *static_cast(detail::get_pointer(next_node_)); + return *this; + } - if(!this->last_mem_){ - this->it_ = basic_multiallocation_iterator(tmp_mem); + iterator operator++(int) + { + iterator result(*this); + ++*this; + return result; } - else{ - static_cast(detail::get_pointer(this->last_mem_))->next_ = tmp_mem; - } - tmp_mem->next_ = 0; - this->last_mem_ = tmp_mem; - ++num_mem_; - } - void push_front(void *mem) + bool operator== (const iterator& other) const + { return next_node_ == other.next_node_; } + + bool operator!= (const iterator& other) const + { return !operator== (other); } + + reference operator*() const + { return *static_cast(detail::get_pointer(next_node_)); } + + operator unspecified_bool_type() const + { return next_node_? &iterator::unspecified_bool_type_func : 0; } + + pointer operator->() const + { return &(*(*this)); } + + private: + void_pointer next_node_; + }; + + private: + iterator it_; + + public: + basic_multiallocation_slist() + : it_(iterator()) + {} + + basic_multiallocation_slist(void_pointer p) + : it_(p ? iterator_to(p) : iterator()) + {} + + basic_multiallocation_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_slist) other) + : it_(iterator()) + { this->swap(other); } + + basic_multiallocation_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_slist) other) { - typedef multi_allocation_next next_impl_t; - next_impl_t * tmp_mem = static_cast(mem); - ++num_mem_; - - if(!this->last_mem_){ - this->it_ = basic_multiallocation_iterator(tmp_mem); - tmp_mem->next_ = 0; - this->last_mem_ = tmp_mem; - } - else{ - next_impl_t * old_first = &this->it_.get_multi_allocation_next(); - tmp_mem->next_ = old_first; - this->it_ = basic_multiallocation_iterator(tmp_mem); - } - } - - void swap(basic_multiallocation_chain &other_chain) - { - std::swap(this->it_, other_chain.it_); - std::swap(this->last_mem_, other_chain.last_mem_); - std::swap(this->num_mem_, other_chain.num_mem_); - } - - void splice_back(basic_multiallocation_chain &other_chain) - { - typedef multi_allocation_next next_impl_t; - multiallocation_iterator end_it; - multiallocation_iterator other_it = other_chain.get_it(); - multiallocation_iterator this_it = this->get_it(); - if(end_it == other_it){ - return; - } - else if(end_it == this_it){ - this->swap(other_chain); - } - else{ - static_cast(detail::get_pointer(this->last_mem_))->next_ - = &other_chain.it_.get_multi_allocation_next(); - this->last_mem_ = other_chain.last_mem_; - this->num_mem_ += other_chain.num_mem_; - } - } - - void *pop_front() - { - multiallocation_iterator itend; - if(this->it_ == itend){ - this->last_mem_= 0; - this->num_mem_ = 0; - return 0; - } - else{ - void *addr = &*it_; - ++it_; - --num_mem_; - if(!num_mem_){ - this->last_mem_ = 0; - this->it_ = multiallocation_iterator(); - } - return addr; - } + basic_multiallocation_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; } bool empty() const - { return !num_mem_; } + { return !it_; } - multiallocation_iterator get_it() const - { return it_; } + iterator before_begin() const + { return iterator(void_pointer(const_cast(static_cast(&it_.next_node_)))); } - std::size_t size() const - { return num_mem_; } + iterator begin() const + { return it_; } + + iterator end() const + { return iterator(); } + + void clear() + { this->it_.next_node_ = void_pointer(0); } + + iterator insert_after(iterator it, void_pointer m) + { + priv_get_ref(m) = priv_get_ref(it.next_node_); + priv_get_ref(it.next_node_) = m; + return iterator(m); + } + + void push_front(void_pointer m) + { + priv_get_ref(m) = this->it_.next_node_; + this->it_.next_node_ = m; + } + + void pop_front() + { ++it_; } + + void *front() const + { return detail::get_pointer(it_.next_node_); } + + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { + if (after_this != before_begin && after_this != before_end && before_begin != before_end) { + void_pointer next_b = priv_get_ref(before_begin.next_node_); + void_pointer next_e = priv_get_ref(before_end.next_node_); + void_pointer next_p = priv_get_ref(after_this.next_node_); + priv_get_ref(before_begin.next_node_) = next_e; + priv_get_ref(before_end.next_node_) = next_p; + priv_get_ref(after_this.next_node_) = next_b; + } + } + + void swap(basic_multiallocation_slist &other_chain) + { + std::swap(this->it_, other_chain.it_); + } + + static iterator iterator_to(void_pointer p) + { return iterator(p); } + + void_pointer extract_data() + { + void_pointer ret = empty() ? void_pointer(0) : void_pointer(&*it_); + it_ = iterator(); + return ret; + } }; +template +class basic_multiallocation_cached_slist +{ + private: + basic_multiallocation_slist slist_; + typename basic_multiallocation_slist::iterator last_; + + basic_multiallocation_cached_slist(basic_multiallocation_cached_slist &); + basic_multiallocation_cached_slist &operator=(basic_multiallocation_cached_slist &); + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_cached_slist) + + typedef typename basic_multiallocation_slist::void_pointer void_pointer; + typedef typename basic_multiallocation_slist::iterator iterator; + + basic_multiallocation_cached_slist() + : slist_(), last_(slist_.before_begin()) + {} +/* + basic_multiallocation_cached_slist(iterator first_node) + : slist_(first_node), last_(slist_.before_begin()) + { + iterator end; + while(first_node != end){ + ++last_; + } + }*/ + + basic_multiallocation_cached_slist(void_pointer p1, void_pointer p2) + : slist_(p1), last_(p2 ? iterator_to(p2) : slist_.before_begin()) + {} + + basic_multiallocation_cached_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_slist) other) + : slist_(), last_(slist_.before_begin()) + { this->swap(other); } + + basic_multiallocation_cached_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_slist) other) + { + basic_multiallocation_cached_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + bool empty() const + { return slist_.empty(); } + + iterator before_begin() const + { return slist_.before_begin(); } + + iterator begin() const + { return slist_.begin(); } + + iterator end() const + { return slist_.end(); } + + iterator last() const + { return last_; } + + void clear() + { + slist_.clear(); + last_ = slist_.before_begin(); + } + + iterator insert_after(iterator it, void_pointer m) + { + slist_.insert_after(it, m); + if(it == last_){ + last_ = slist_.iterator_to(m); + } + return iterator_to(m); + } + + void push_front(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void push_back(void_pointer m) + { this->insert_after(last_, m); } + + void pop_front() + { + if(last_ == slist_.begin()){ + last_ = slist_.before_begin(); + } + slist_.pop_front(); + } + + void *front() const + { return slist_.front(); } + + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { + if(before_begin == before_end) + return; + if(after_this == last_){ + last_ = before_end; + } + slist_.splice_after(after_this, before_begin, before_end); + } + + void swap(basic_multiallocation_cached_slist &x) + { + slist_.swap(x.slist_); + using std::swap; + swap(last_, x.last_); + if(last_ == x.before_begin()){ + last_ = this->before_begin(); + } + if(x.last_ == this->before_begin()){ + x.last_ = x.before_begin(); + } + } + + static iterator iterator_to(void_pointer p) + { return basic_multiallocation_slist::iterator_to(p); } + + std::pair extract_data() + { + if(this->empty()){ + return std::pair(void_pointer(0), void_pointer(0)); + } + else{ + void_pointer p1 = slist_.extract_data(); + void_pointer p2 = void_pointer(&*last_); + last_ = iterator(); + return std::pair(p1, p2); + } + } +}; + +template +class basic_multiallocation_cached_counted_slist +{ + private: + MultiallocatorCachedSlist cached_slist_; + std::size_t size_; + + basic_multiallocation_cached_counted_slist(basic_multiallocation_cached_counted_slist &); + basic_multiallocation_cached_counted_slist &operator=(basic_multiallocation_cached_counted_slist &); + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_cached_counted_slist) + + typedef typename MultiallocatorCachedSlist::void_pointer void_pointer; + typedef typename MultiallocatorCachedSlist::iterator iterator; + + basic_multiallocation_cached_counted_slist() + : cached_slist_(), size_(0) + {} + + basic_multiallocation_cached_counted_slist(void_pointer p1, void_pointer p2, std::size_t n) + : cached_slist_(p1, p2), size_(n) + {} + + basic_multiallocation_cached_counted_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_counted_slist) other) + : cached_slist_(), size_(0) + { this->swap(other); } + + basic_multiallocation_cached_counted_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_counted_slist) other) + { + basic_multiallocation_cached_counted_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + basic_multiallocation_cached_counted_slist (MultiallocatorCachedSlist mem, std::size_t n) + : cached_slist_(boost::interprocess::move(mem)), size_(n) + {} + + bool empty() const + { return cached_slist_.empty(); } + + std::size_t size() const + { return size_; } + + iterator before_begin() const + { return cached_slist_.before_begin(); } + + iterator begin() const + { return cached_slist_.begin(); } + + iterator end() const + { return cached_slist_.end(); } + + iterator last() const + { return cached_slist_.last(); } + + void clear() + { + cached_slist_.clear(); + size_ = 0; + } + + iterator insert_after(iterator it, void_pointer m) + { + iterator ret = cached_slist_.insert_after(it, m); + ++size_; + return ret; + } + + void push_front(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void push_back(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void pop_front() + { + cached_slist_.pop_front(); + --size_; + } + + void *front() const + { return cached_slist_.front(); } + + void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x, iterator before_begin, iterator before_end) + { + std::size_t n = static_cast(std::distance(before_begin, before_end)); + this->splice_after(after_this, x, before_begin, before_end, n); + } + + void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x, iterator before_begin, iterator before_end, std::size_t n) + { + cached_slist_.splice_after(after_this, before_begin, before_end); + size_ += n; + x.size_ -= n; + } + + void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x) + { + cached_slist_.splice_after(after_this, x.before_begin(), x.last()); + size_ += x.size_; + x.size_ = 0; + } + + void swap(basic_multiallocation_cached_counted_slist &x) + { + cached_slist_.swap(x.cached_slist_); + using std::swap; + swap(size_, x.size_); + } + + static iterator iterator_to(void_pointer p) + { return MultiallocatorCachedSlist::iterator_to(p); } + + std::pair extract_data() + { + size_ = 0; + return cached_slist_.extract_data(); + } +}; + +template +struct cast_functor +{ + typedef typename detail::add_reference::type result_type; + result_type operator()(char &ptr) const + { return *static_cast(static_cast(&ptr)); } +}; + + +template +class transform_multiallocation_chain +{ +private: + + MultiallocationChain holder_; + typedef typename MultiallocationChain::void_pointer void_pointer; + typedef typename boost::pointer_to_other + ::type pointer; + + transform_multiallocation_chain(transform_multiallocation_chain &); + transform_multiallocation_chain &operator=(transform_multiallocation_chain &); + + static pointer cast(void_pointer p) + { + return pointer(static_cast(detail::get_pointer(p))); + } + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(transform_multiallocation_chain) + + typedef transform_iterator + < typename MultiallocationChain::iterator + , detail::cast_functor > iterator; + + transform_multiallocation_chain(void_pointer p1, void_pointer p2, std::size_t n) + : holder_(p1, p2, n) + {} + + transform_multiallocation_chain() + : holder_() + {} + + transform_multiallocation_chain(BOOST_INTERPROCESS_RV_REF(transform_multiallocation_chain) other) + : holder_() + { this->swap(other); } + + transform_multiallocation_chain(BOOST_INTERPROCESS_RV_REF(MultiallocationChain) other) + : holder_(boost::interprocess::move(other)) + {} + + transform_multiallocation_chain& operator=(BOOST_INTERPROCESS_RV_REF(transform_multiallocation_chain) other) + { + transform_multiallocation_chain tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + void push_front(pointer mem) + { holder_.push_front(mem); } + + void swap(transform_multiallocation_chain &other_chain) + { holder_.swap(other_chain.holder_); } + /* + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { holder_.splice_after(after_this.base(), before_begin.base(), before_end.base()); } + */ + void splice_after(iterator after_this, transform_multiallocation_chain &x, iterator before_begin, iterator before_end, std::size_t n) + { holder_.splice_after(after_this.base(), x.holder_, before_begin.base(), before_end.base(), n); } + + void pop_front() + { holder_.pop_front(); } + + pointer front() const + { return cast(holder_.front()); } + + bool empty() const + { return holder_.empty(); } + + iterator before_begin() const + { return iterator(holder_.before_begin()); } + + iterator begin() const + { return iterator(holder_.begin()); } + + iterator end() const + { return iterator(holder_.end()); } + + iterator last() const + { return iterator(holder_.last()); } + + std::size_t size() const + { return holder_.size(); } + + void clear() + { holder_.clear(); } + + iterator insert_after(iterator it, pointer m) + { return iterator(holder_.insert_after(it.base(), m)); } + + static iterator iterator_to(pointer p) + { return iterator(MultiallocationChain::iterator_to(p)); } + + std::pair extract_data() + { return holder_.extract_data(); } + + MultiallocationChain extract_multiallocation_chain() + { + return MultiallocationChain(boost::interprocess::move(holder_)); + } +}; //!This class implements several allocation functions shared by different algorithms //!(aligned allocation, multiple allocation...). @@ -245,19 +569,16 @@ class memory_algorithm_common public: typedef typename MemoryAlgorithm::void_pointer void_pointer; typedef typename MemoryAlgorithm::block_ctrl block_ctrl; - typedef typename MemoryAlgorithm::multiallocation_iterator multiallocation_iterator; - typedef multi_allocation_next multi_allocation_next_t; - typedef typename multi_allocation_next_t:: - multi_allocation_next_ptr multi_allocation_next_ptr; + typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; typedef memory_algorithm_common this_type; - static const std::size_t Alignment = MemoryAlgorithm::Alignment; - static const std::size_t MinBlockUnits = MemoryAlgorithm::MinBlockUnits; - static const std::size_t AllocatedCtrlBytes = MemoryAlgorithm::AllocatedCtrlBytes; - static const std::size_t AllocatedCtrlUnits = MemoryAlgorithm::AllocatedCtrlUnits; - static const std::size_t BlockCtrlBytes = MemoryAlgorithm::BlockCtrlBytes; - static const std::size_t BlockCtrlUnits = MemoryAlgorithm::BlockCtrlUnits; - static const std::size_t UsableByPreviousChunk = MemoryAlgorithm::UsableByPreviousChunk; + static const std::size_t Alignment = MemoryAlgorithm::Alignment; + static const std::size_t MinBlockUnits = MemoryAlgorithm::MinBlockUnits; + static const std::size_t AllocatedCtrlBytes = MemoryAlgorithm::AllocatedCtrlBytes; + static const std::size_t AllocatedCtrlUnits = MemoryAlgorithm::AllocatedCtrlUnits; + static const std::size_t BlockCtrlBytes = MemoryAlgorithm::BlockCtrlBytes; + static const std::size_t BlockCtrlUnits = MemoryAlgorithm::BlockCtrlUnits; + static const std::size_t UsableByPreviousChunk = MemoryAlgorithm::UsableByPreviousChunk; static void assert_alignment(const void *ptr) { assert_alignment((std::size_t)ptr); } @@ -280,12 +601,17 @@ class memory_algorithm_common static std::size_t multiple_of_units(std::size_t size) { return detail::get_rounded_size(size, Alignment); } - static multiallocation_iterator allocate_many + static multiallocation_chain allocate_many (MemoryAlgorithm *memory_algo, std::size_t elem_bytes, std::size_t n_elements) { return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0); } + static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain chain) + { + return this_type::priv_deallocate_many(memory_algo, boost::interprocess::move(chain)); + } + static bool calculate_lcm_and_needs_backwards_lcmed (std::size_t backwards_multiple, std::size_t received_size, std::size_t size_to_achieve, std::size_t &lcm_out, std::size_t &needs_backwards_lcmed_out) @@ -381,7 +707,7 @@ class memory_algorithm_common return true; } - static multiallocation_iterator allocate_many + static multiallocation_chain allocate_many ( MemoryAlgorithm *memory_algo , const std::size_t *elem_sizes , std::size_t n_elements @@ -403,7 +729,8 @@ class memory_algorithm_common std::size_t real_size; if(alignment <= Alignment){ - return memory_algo->priv_allocate(allocate_new, nbytes, nbytes, real_size).first; + return memory_algo->priv_allocate + (boost::interprocess::allocate_new, nbytes, nbytes, real_size).first; } if(nbytes > UsableByPreviousChunk) @@ -428,7 +755,8 @@ class memory_algorithm_common ); //Now allocate the buffer - void *buffer = memory_algo->priv_allocate(allocate_new, request, request, real_size).first; + void *buffer = memory_algo->priv_allocate + (boost::interprocess::allocate_new, request, request, real_size).first; if(!buffer){ return 0; } @@ -608,7 +936,7 @@ class memory_algorithm_common } private: - static multiallocation_iterator priv_allocate_many + static multiallocation_chain priv_allocate_many ( MemoryAlgorithm *memory_algo , const std::size_t *elem_sizes , std::size_t n_elements @@ -620,7 +948,7 @@ class memory_algorithm_common //Calculate the total size of all requests std::size_t total_request_units = 0; std::size_t elem_units = 0; - const std::size_t ptr_size_units = memory_algo->priv_get_total_units(sizeof(multi_allocation_next_ptr)); + const std::size_t ptr_size_units = memory_algo->priv_get_total_units(sizeof(void_pointer)); if(!sizeof_element){ elem_units = memory_algo->priv_get_total_units(*elem_sizes); elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units; @@ -634,7 +962,8 @@ class memory_algorithm_common } } - multi_allocation_next_ptr first = 0, previous = 0; + multiallocation_chain chain; + std::size_t low_idx = 0; while(low_idx < n_elements){ std::size_t total_bytes = total_request_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; @@ -645,7 +974,7 @@ class memory_algorithm_common std::size_t received_size; std::pair ret = memory_algo->priv_allocate - (allocate_new, min_allocation, total_bytes, received_size, 0); + (boost::interprocess::allocate_new, min_allocation, total_bytes, received_size, 0); if(!ret.first){ break; } @@ -710,33 +1039,28 @@ class memory_algorithm_common block_address += new_block->m_size*Alignment; total_used_units += new_block->m_size; //Check we have enough room to overwrite the intrusive pointer - assert((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(multi_allocation_next_t)); - multi_allocation_next_ptr p = new(memory_algo->priv_get_user_buffer(new_block))multi_allocation_next_t(0); - - if(!first){ - first = p; - } - else{ - previous->next_ = p; - } - previous = p; + assert((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(void_pointer)); + void_pointer p = new(memory_algo->priv_get_user_buffer(new_block))void_pointer(0); + chain.push_back(p); ++low_idx; //prev_block = new_block; } //Sanity check BOOST_ASSERT(total_used_units == received_units); } - + if(low_idx != n_elements){ - while(first){ - multi_allocation_next_ptr prev = first; - first = first->next_; - memory_algo->priv_deallocate(detail::get_pointer(prev)); - } - return multiallocation_iterator(); + priv_deallocate_many(memory_algo, boost::interprocess::move(chain)); } - else{ - return multiallocation_iterator(first); + return boost::interprocess::move(chain); + } + + static void priv_deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain chain) + { + while(!chain.empty()){ + void *addr = detail::get_pointer(chain.front()); + chain.pop_front(); + memory_algo->priv_deallocate(addr); } } }; diff --git a/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp index b196faf..80c6209 100644 --- a/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp +++ b/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp @@ -18,8 +18,10 @@ #include #include +#include + #include -#include +#include #include #include #include @@ -67,7 +69,7 @@ class simple_seq_fit_impl private: struct block_ctrl; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type block_ctrl_ptr; /*!Block control structure*/ @@ -149,7 +151,7 @@ class simple_seq_fit_impl void clear_free_memory(); std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, void *reuse_ptr = 0, std::size_t backwards_multiple = 1); @@ -169,7 +171,7 @@ class simple_seq_fit_impl private: /*!Real allocation algorithm with min allocation option*/ - std::pair priv_allocate(allocation_type command + std::pair priv_allocate(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -188,7 +190,7 @@ class simple_seq_fit_impl ,std::size_t &received_size); /*!Real expand to both sides implementation*/ - void* priv_expand_both_sides(allocation_type command + void* priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -375,7 +377,7 @@ inline void* simple_seq_fit_impl:: boost::interprocess::scoped_lock guard(m_header); //----------------------- std::size_t ignore; - return priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + return priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; } template @@ -390,7 +392,7 @@ inline void* simple_seq_fit_impl:: template inline std::pair simple_seq_fit_impl:: - allocation_command (allocation_type command, std::size_t min_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t min_size, std::size_t preferred_size,std::size_t &received_size, void *reuse_ptr, std::size_t backwards_multiple) { @@ -398,7 +400,7 @@ inline std::pair simple_seq_fit_impl:: boost::interprocess::scoped_lock guard(m_header); //----------------------- (void)backwards_multiple; - command &= ~expand_bwd; + command &= ~boost::interprocess::expand_bwd; if(!command) return std::pair(0, false); return priv_allocate(command, min_size, preferred_size, received_size, reuse_ptr); @@ -426,7 +428,7 @@ inline void* simple_seq_fit_impl:: //Multisegment pointer. Let's try first the normal allocation //since it's faster. std::size_t ignore; - void *addr = this->priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + void *addr = this->priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; if(!addr){ //If this fails we will try the allocation through the segment //creator. @@ -447,7 +449,7 @@ inline void* simple_seq_fit_impl:: p_services->create_new_segment(MinBlockSize > nbytes ? MinBlockSize : nbytes); if(ret.first){ priv_add_segment(ret.first, ret.second); - addr = this->priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + addr = this->priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; } } return addr; @@ -455,7 +457,7 @@ inline void* simple_seq_fit_impl:: template void* simple_seq_fit_impl:: - priv_expand_both_sides(allocation_type command + priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -471,14 +473,14 @@ void* simple_seq_fit_impl:: return reuse_ptr; } - if(command & expand_fwd){ + if(command & boost::interprocess::expand_fwd){ if(priv_expand(reuse_ptr, min_size, preferred_size, received_size)) return reuse_ptr; } else{ received_size = this->size(reuse_ptr); } - if(command & expand_bwd){ + if(command & boost::interprocess::expand_bwd){ std::size_t extra_forward = !received_size ? 0 : received_size + BlockCtrlBytes; prev_block_t prev_pair = priv_prev_block_if_free(reuse); block_ctrl *prev = prev_pair.second; @@ -534,13 +536,13 @@ void* simple_seq_fit_impl:: template std::pair simple_seq_fit_impl:: - priv_allocate(allocation_type command + priv_allocate(boost::interprocess::allocation_type command ,std::size_t limit_size ,std::size_t preferred_size ,std::size_t &received_size ,void *reuse_ptr) { - if(command & shrink_in_place){ + if(command & boost::interprocess::shrink_in_place){ bool success = this->priv_shrink(reuse_ptr, limit_size, preferred_size, received_size); return std::pair ((success ? reuse_ptr : 0), true); @@ -565,14 +567,14 @@ std::pair simple_seq_fit_impl:: //Expand in place //reuse_ptr, limit_size, preferred_size, received_size // - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ void *ret = priv_expand_both_sides (command, limit_size, preferred_size, received_size, reuse_ptr, true); if(ret) return return_type(ret, true); } - if(command & allocate_new){ + if(command & boost::interprocess::allocate_new){ received_size = 0; while(block != root){ //Update biggest block pointers @@ -600,7 +602,7 @@ std::pair simple_seq_fit_impl:: } } //Now try to expand both sides with min size - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ return return_type(priv_expand_both_sides (command, limit_size, preferred_size, received_size, reuse_ptr, false), true); } @@ -809,12 +811,12 @@ inline void* simple_seq_fit_impl:: std::size_t ignore; if(alignment <= Alignment){ - return priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + return priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; } std::size_t request = nbytes + alignment + MinBlockSize*Alignment - BlockCtrlBytes; - void *buffer = priv_allocate(allocate_new, request, request, ignore).first; + void *buffer = priv_allocate(boost::interprocess::allocate_new, request, request, ignore).first; if(!buffer) return 0; else if ((((std::size_t)(buffer)) % alignment) == 0) diff --git a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp index bd0773a..19ed89d 100644 --- a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp +++ b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp @@ -18,8 +18,10 @@ #include #include +#include + #include -#include +#include #include #include #include @@ -61,15 +63,13 @@ class simple_seq_fit_impl typedef MutexFamily mutex_family; //!Pointer type to be used with the rest of the Interprocess framework typedef VoidPointer void_pointer; - - typedef detail::basic_multiallocation_iterator - multiallocation_iterator; - typedef detail::basic_multiallocation_chain - multiallocation_chain; + typedef detail::basic_multiallocation_cached_slist multialloc_cached; + typedef detail::basic_multiallocation_cached_counted_slist + multiallocation_chain; private: class block_ctrl; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type block_ctrl_ptr; class block_ctrl; @@ -109,7 +109,6 @@ class simple_seq_fit_impl std::size_t m_extra_hdr_bytes; } m_header; - friend class detail::basic_multiallocation_iterator; friend class detail::memory_algorithm_common; typedef detail::memory_algorithm_common algo_impl_t; @@ -134,13 +133,27 @@ class simple_seq_fit_impl /// @cond //!Multiple element allocation, same size - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements); + multiallocation_chain + allocate_many(std::size_t elem_bytes, std::size_t num_elements) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return algo_impl_t::allocate_many(this, elem_bytes, num_elements); + } //!Multiple element allocation, different size - multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element); + multiallocation_chain + allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element); + } //!Multiple element deallocation - void deallocate_many(multiallocation_iterator it); + void deallocate_many(multiallocation_chain chain); /// @endcond @@ -171,12 +184,12 @@ class simple_seq_fit_impl template std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0); std::pair - raw_allocation_command (allocation_type command, std::size_t limit_size, + raw_allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, void *reuse_ptr = 0, std::size_t sizeof_object = 1); @@ -196,13 +209,13 @@ class simple_seq_fit_impl static block_ctrl *priv_get_block(const void *ptr); //!Real allocation algorithm with min allocation option - std::pair priv_allocate(allocation_type command + std::pair priv_allocate(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size ,void *reuse_ptr = 0); - std::pair priv_allocation_command(allocation_type command + std::pair priv_allocation_command(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -233,7 +246,7 @@ class simple_seq_fit_impl ,std::size_t &received_size); //!Real expand to both sides implementation - void* priv_expand_both_sides(allocation_type command + void* priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -386,7 +399,7 @@ void simple_seq_fit_impl::shrink_to_fit() if(!m_header.m_allocated){ assert(prev == root); std::size_t ignore; - unique_block = priv_allocate(allocate_new, 0, 0, ignore).first; + unique_block = priv_allocate(boost::interprocess::allocate_new, 0, 0, ignore).first; if(!unique_block) return; last = detail::get_pointer(m_header.m_root.m_next); @@ -547,7 +560,7 @@ inline void* simple_seq_fit_impl:: boost::interprocess::scoped_lock guard(m_header); //----------------------- std::size_t ignore; - return priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + return priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; } template @@ -564,7 +577,7 @@ inline void* simple_seq_fit_impl:: template template inline std::pair simple_seq_fit_impl:: - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr) { @@ -577,13 +590,13 @@ inline std::pair simple_seq_fit_impl:: template inline std::pair simple_seq_fit_impl:: - raw_allocation_command (allocation_type command, std::size_t limit_objects, + raw_allocation_command (boost::interprocess::allocation_type command, std::size_t limit_objects, std::size_t preferred_objects,std::size_t &received_objects, void *reuse_ptr, std::size_t sizeof_object) { if(!sizeof_object) return std::pair(static_cast(0), 0); - if(command & try_shrink_in_place){ + if(command & boost::interprocess::try_shrink_in_place){ bool success = algo_impl_t::try_shrink ( this, reuse_ptr, limit_objects*sizeof_object , preferred_objects*sizeof_object, received_objects); @@ -596,11 +609,11 @@ inline std::pair simple_seq_fit_impl:: template inline std::pair simple_seq_fit_impl:: - priv_allocation_command (allocation_type command, std::size_t limit_size, + priv_allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size, std::size_t &received_size, void *reuse_ptr, std::size_t sizeof_object) { - command &= ~expand_bwd; + command &= ~boost::interprocess::expand_bwd; if(!command) return std::pair(static_cast(0), false); std::pair ret; @@ -634,7 +647,7 @@ inline std::size_t simple_seq_fit_impl:: template void* simple_seq_fit_impl:: - priv_expand_both_sides(allocation_type command + priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -650,14 +663,14 @@ void* simple_seq_fit_impl:: return reuse_ptr; } - if(command & expand_fwd){ + if(command & boost::interprocess::expand_fwd){ if(priv_expand(reuse_ptr, min_size, preferred_size, received_size)) return reuse_ptr; } else{ received_size = this->size(reuse_ptr); } - if(command & expand_bwd){ + if(command & boost::interprocess::expand_bwd){ std::size_t extra_forward = !received_size ? 0 : received_size + BlockCtrlBytes; prev_block_t prev_pair = priv_prev_block_if_free(reuse); block_ctrl *prev = prev_pair.second; @@ -711,43 +724,20 @@ void* simple_seq_fit_impl:: return 0; } -template -inline typename simple_seq_fit_impl::multiallocation_iterator - simple_seq_fit_impl:: - allocate_many(std::size_t elem_bytes, std::size_t num_elements) -{ - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return algo_impl_t:: - allocate_many(this, elem_bytes, num_elements); -} - template inline void simple_seq_fit_impl:: - deallocate_many(typename simple_seq_fit_impl::multiallocation_iterator it) + deallocate_many(typename simple_seq_fit_impl::multiallocation_chain chain) { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - while(it){ - void *addr = &*it; - ++it; + while(!chain.empty()){ + void *addr = chain.front(); + chain.pop_front(); this->priv_deallocate(addr); } } -template -inline typename simple_seq_fit_impl::multiallocation_iterator - simple_seq_fit_impl:: - allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element) -{ - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element); -} - template inline std::size_t simple_seq_fit_impl:: priv_get_total_units(std::size_t userbytes) @@ -759,13 +749,13 @@ inline std::size_t simple_seq_fit_impl:: template std::pair simple_seq_fit_impl:: - priv_allocate(allocation_type command + priv_allocate(boost::interprocess::allocation_type command ,std::size_t limit_size ,std::size_t preferred_size ,std::size_t &received_size ,void *reuse_ptr) { - if(command & shrink_in_place){ + if(command & boost::interprocess::shrink_in_place){ bool success = algo_impl_t::shrink(this, reuse_ptr, limit_size, preferred_size, received_size); return std::pair ((success ? reuse_ptr : 0), true); @@ -790,7 +780,7 @@ std::pair simple_seq_fit_impl:: //Expand in place //reuse_ptr, limit_size, preferred_size, received_size // - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ void *ret = priv_expand_both_sides (command, limit_size, preferred_size, received_size, reuse_ptr, true); if(ret){ @@ -799,7 +789,7 @@ std::pair simple_seq_fit_impl:: } } - if(command & allocate_new){ + if(command & boost::interprocess::allocate_new){ received_size = 0; while(block != root){ //Update biggest block pointers @@ -835,7 +825,7 @@ std::pair simple_seq_fit_impl:: } } //Now try to expand both sides with min size - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ return_type ret (priv_expand_both_sides (command, limit_size, preferred_size, received_size, reuse_ptr, false), true); algo_impl_t::assert_alignment(ret.first); diff --git a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp index 5379139..d4299b3 100644 --- a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp +++ b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -18,9 +18,11 @@ #include #include +#include + #include #include -#include +#include #include #include #include @@ -40,15 +42,7 @@ #include #include -//#define BOOST_INTERPROCESS_RBTREE_BEST_FIT_USE_SPLAY - -#ifndef BOOST_INTERPROCESS_RBTREE_BEST_FIT_USE_SPLAY #include -#else -//#include -//#include -#include -#endif //!\file //!Describes a best-fit algorithm based in an intrusive red-black tree used to allocate @@ -75,35 +69,26 @@ class rbtree_best_fit typedef MutexFamily mutex_family; //!Pointer type to be used with the rest of the Interprocess framework typedef VoidPointer void_pointer; - typedef detail::basic_multiallocation_iterator - multiallocation_iterator; - typedef detail::basic_multiallocation_chain - multiallocation_chain; + //typedef detail::basic_multiallocation_cached_counted_slist multiallocation_chain; + + typedef detail::basic_multiallocation_cached_slist multialloc_cached; + typedef detail::basic_multiallocation_cached_counted_slist + multiallocation_chain; /// @cond private: struct block_ctrl; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type block_ctrl_ptr; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type char_ptr; -#ifndef BOOST_INTERPROCESS_RBTREE_BEST_FIT_USE_SPLAY typedef typename bi::make_set_base_hook -#else -// typedef typename bi::make_splay_set_base_hook -// typedef typename bi::make_avl_set_base_hook - typedef typename bi::make_sg_set_base_hook -#endif < bi::void_pointer , bi::optimize_size , bi::link_mode >::type TreeHook; - typedef detail::multi_allocation_next multi_allocation_next_t; - typedef typename multi_allocation_next_t:: - multi_allocation_next_ptr multi_allocation_next_ptr; - struct SizeHolder { //!This block's memory size (including block_ctrl @@ -138,13 +123,7 @@ class rbtree_best_fit //!Shared interprocess_mutex to protect memory allocate/deallocate typedef typename MutexFamily::mutex_type interprocess_mutex; -#ifndef BOOST_INTERPROCESS_RBTREE_BEST_FIT_USE_SPLAY typedef typename bi::make_multiset -#else - //typedef typename bi::make_splay_multiset - //typedef typename bi::make_avl_multiset - typedef typename bi::make_sg_multiset -#endif >::type Imultiset; typedef typename Imultiset::iterator imultiset_iterator; @@ -163,7 +142,6 @@ class rbtree_best_fit std::size_t m_size; } m_header; - friend class detail::basic_multiallocation_iterator; friend class detail::memory_algorithm_common; typedef detail::memory_algorithm_common algo_impl_t; @@ -192,13 +170,27 @@ class rbtree_best_fit //Experimental. Dont' use //!Multiple element allocation, same size - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements); + multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements) + { + + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return algo_impl_t::allocate_many(this, elem_bytes, num_elements); + } //!Multiple element allocation, different size - multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element); + multiallocation_chain allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element) + { + + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element); + } //!Multiple element allocation, different size - void deallocate_many(multiallocation_iterator it); + void deallocate_many(multiallocation_chain chain); /// @endcond @@ -231,12 +223,12 @@ class rbtree_best_fit template std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0); std::pair - raw_allocation_command (allocation_type command, std::size_t limit_object, + raw_allocation_command (boost::interprocess::allocation_type command, std::size_t limit_object, std::size_t preferred_object,std::size_t &received_object, void *reuse_ptr = 0, std::size_t sizeof_object = 1); @@ -252,13 +244,13 @@ class rbtree_best_fit static std::size_t priv_first_block_offset(const void *this_ptr, std::size_t extra_hdr_bytes); std::pair - priv_allocation_command(allocation_type command, std::size_t limit_size, + priv_allocation_command(boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, void *reuse_ptr, std::size_t sizeof_object); //!Real allocation algorithm with min allocation option - std::pair priv_allocate(allocation_type command + std::pair priv_allocate(boost::interprocess::allocation_type command ,std::size_t limit_size ,std::size_t preferred_size ,std::size_t &received_size @@ -281,7 +273,7 @@ class rbtree_best_fit ,std::size_t &received_size); //!Real expand to both sides implementation - void* priv_expand_both_sides(allocation_type command + void* priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -463,7 +455,7 @@ void rbtree_best_fit::shrink_to_fit() block_ctrl *last_block; if(priv_next_block(first_block) == old_end_block){ std::size_t ignore; - unique_buffer = priv_allocate(allocate_new, 0, 0, ignore).first; + unique_buffer = priv_allocate(boost::interprocess::allocate_new, 0, 0, ignore).first; if(!unique_buffer) return; algo_impl_t::assert_alignment(unique_buffer); @@ -631,7 +623,7 @@ inline void* rbtree_best_fit:: boost::interprocess::scoped_lock guard(m_header); //----------------------- std::size_t ignore; - void * ret = priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + void * ret = priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; return ret; } @@ -648,7 +640,7 @@ inline void* rbtree_best_fit:: template template inline std::pair rbtree_best_fit:: - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr) { @@ -661,13 +653,13 @@ inline std::pair rbtree_best_fit inline std::pair rbtree_best_fit:: - raw_allocation_command (allocation_type command, std::size_t limit_objects, + raw_allocation_command (boost::interprocess::allocation_type command, std::size_t limit_objects, std::size_t preferred_objects,std::size_t &received_objects, void *reuse_ptr, std::size_t sizeof_object) { if(!sizeof_object) return std::pair(static_cast(0), 0); - if(command & try_shrink_in_place){ + if(command & boost::interprocess::try_shrink_in_place){ bool success = algo_impl_t::try_shrink ( this, reuse_ptr, limit_objects*sizeof_object , preferred_objects*sizeof_object, received_objects); @@ -681,7 +673,7 @@ inline std::pair rbtree_best_fit inline std::pair rbtree_best_fit:: - priv_allocation_command (allocation_type command, std::size_t limit_size, + priv_allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, void *reuse_ptr, std::size_t sizeof_object) { @@ -732,7 +724,7 @@ inline void rbtree_best_fit::zero_free_m template void* rbtree_best_fit:: - priv_expand_both_sides(allocation_type command + priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -741,7 +733,7 @@ void* rbtree_best_fit:: ,std::size_t backwards_multiple) { algo_impl_t::assert_alignment(reuse_ptr); - if(command & expand_fwd){ + if(command & boost::interprocess::expand_fwd){ if(priv_expand(reuse_ptr, min_size, preferred_size, received_size)) return reuse_ptr; } @@ -756,7 +748,7 @@ void* rbtree_best_fit:: BOOST_ASSERT(0 == (preferred_size % backwards_multiple)); } - if(command & expand_bwd){ + if(command & boost::interprocess::expand_bwd){ //Obtain the real size of the block block_ctrl *reuse = priv_get_block(reuse_ptr); @@ -791,7 +783,7 @@ void* rbtree_best_fit:: //Check if previous block has enough size if(std::size_t(prev_block->m_size*Alignment) >= needs_backwards_aligned){ //Now take all next space. This will succeed - if(command & expand_fwd){ + if(command & boost::interprocess::expand_fwd){ std::size_t received_size2; if(!priv_expand(reuse_ptr, received_size, received_size, received_size2)){ assert(0); @@ -873,45 +865,19 @@ void* rbtree_best_fit:: return 0; } -template -inline typename rbtree_best_fit::multiallocation_iterator - rbtree_best_fit:: - allocate_many(std::size_t elem_bytes, std::size_t num_elements) -{ - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return algo_impl_t::allocate_many(this, elem_bytes, num_elements); -} - template inline void rbtree_best_fit:: - deallocate_many(typename rbtree_best_fit::multiallocation_iterator it) + deallocate_many(typename rbtree_best_fit::multiallocation_chain chain) { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - while(it){ - void *addr = &*it; - ++it; - this->priv_deallocate(addr); - } -} - -template -inline typename rbtree_best_fit::multiallocation_iterator - rbtree_best_fit:: - allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element) -{ - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element); + algo_impl_t::deallocate_many(this, boost::interprocess::move(chain)); } template std::pair rbtree_best_fit:: - priv_allocate(allocation_type command + priv_allocate(boost::interprocess::allocation_type command ,std::size_t limit_size ,std::size_t preferred_size ,std::size_t &received_size @@ -919,9 +885,9 @@ std::pair rbtree_best_fit: ,std::size_t backwards_multiple) { //Remove me. Forbid backwards allocation - //command &= (~expand_bwd); + //command &= (~boost::interprocess::expand_bwd); - if(command & shrink_in_place){ + if(command & boost::interprocess::shrink_in_place){ bool success = algo_impl_t::shrink(this, reuse_ptr, limit_size, preferred_size, received_size); return std::pair ((success ? reuse_ptr : 0), true); @@ -940,14 +906,14 @@ std::pair rbtree_best_fit: std::size_t limit_units = priv_get_total_units(limit_size); //Expand in place - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ void *ret = priv_expand_both_sides (command, limit_size, preferred_size, received_size, reuse_ptr, true, backwards_multiple); if(ret) return return_type(ret, true); } - if(command & allocate_new){ + if(command & boost::interprocess::allocate_new){ size_block_ctrl_compare comp; imultiset_iterator it(m_header.m_imultiset.lower_bound(preferred_units, comp)); @@ -965,7 +931,7 @@ std::pair rbtree_best_fit: //Now try to expand both sides with min size - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ return return_type(priv_expand_both_sides (command, limit_size, preferred_size, received_size, reuse_ptr, false, backwards_multiple), true); } diff --git a/include/boost/interprocess/offset_ptr.hpp b/include/boost/interprocess/offset_ptr.hpp index e89ef76..c1ae9f4 100644 --- a/include/boost/interprocess/offset_ptr.hpp +++ b/include/boost/interprocess/offset_ptr.hpp @@ -162,7 +162,11 @@ class offset_ptr //!Dereferencing operator, if it is a null offset_ptr behavior //! is undefined. Never throws. reference operator* () const - { return *(this->get()); } + { + pointer p = this->get(); + reference r = *p; + return r; + } //!Indexing operator. //!Never throws. diff --git a/include/boost/interprocess/segment_manager.hpp b/include/boost/interprocess/segment_manager.hpp index a9836f6..972e08c 100644 --- a/include/boost/interprocess/segment_manager.hpp +++ b/include/boost/interprocess/segment_manager.hpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include @@ -72,8 +72,7 @@ class segment_manager_base /// @cond //Experimental. Don't use - typedef typename MemoryAlgorithm::multiallocation_iterator multiallocation_iterator; - typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; + typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; /// @endcond @@ -123,38 +122,40 @@ class segment_manager_base //Experimental. Dont' use. //!Allocates n_elements of //!elem_size bytes. Throws bad_alloc on failure. - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements) + multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements) { - multiallocation_iterator ret = MemoryAlgorithm::allocate_many(elem_bytes, num_elements); - if(!ret) throw bad_alloc(); - return ret; + multiallocation_chain mem(MemoryAlgorithm::allocate_many(elem_bytes, num_elements)); + if(mem.empty()) throw bad_alloc(); + return boost::interprocess::move(mem); } //!Allocates n_elements, each one of //!element_lenghts[i]*sizeof_element bytes. Throws bad_alloc on failure. - multiallocation_iterator allocate_many + multiallocation_chain allocate_many (const std::size_t *element_lenghts, std::size_t n_elements, std::size_t sizeof_element = 1) { - multiallocation_iterator ret = MemoryAlgorithm::allocate_many(element_lenghts, n_elements, sizeof_element); - if(!ret) throw bad_alloc(); - return ret; + multiallocation_chain mem(MemoryAlgorithm::allocate_many(element_lenghts, n_elements, sizeof_element)); + if(mem.empty()) throw bad_alloc(); + return boost::interprocess::move(mem); } //!Allocates n_elements of //!elem_size bytes. Returns a default constructed iterator on failure. - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements, std::nothrow_t) + multiallocation_chain allocate_many + (std::size_t elem_bytes, std::size_t num_elements, std::nothrow_t) { return MemoryAlgorithm::allocate_many(elem_bytes, num_elements); } //!Allocates n_elements, each one of //!element_lenghts[i]*sizeof_element bytes. //!Returns a default constructed iterator on failure. - multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element, std::nothrow_t) + multiallocation_chain allocate_many + (const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element, std::nothrow_t) { return MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element); } //!Deallocates elements pointed by the //!multiallocation iterator range. - void deallocate_many(multiallocation_iterator it) - { MemoryAlgorithm::deallocate_many(it); } + void deallocate_many(multiallocation_chain chain) + { MemoryAlgorithm::deallocate_many(boost::interprocess::move(chain)); } /// @endcond @@ -185,27 +186,27 @@ class segment_manager_base template std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0) { std::pair ret = MemoryAlgorithm::allocation_command - ( command | nothrow_allocation, limit_size, preferred_size, received_size + ( command | boost::interprocess::nothrow_allocation, limit_size, preferred_size, received_size , reuse_ptr); - if(!(command & nothrow_allocation) && !ret.first) + if(!(command & boost::interprocess::nothrow_allocation) && !ret.first) throw bad_alloc(); return ret; } std::pair - raw_allocation_command (allocation_type command, std::size_t limit_objects, + raw_allocation_command (boost::interprocess::allocation_type command, std::size_t limit_objects, std::size_t preferred_objects,std::size_t &received_objects, void *reuse_ptr = 0, std::size_t sizeof_object = 1) { std::pair ret = MemoryAlgorithm::raw_allocation_command - ( command | nothrow_allocation, limit_objects, preferred_objects, received_objects + ( command | boost::interprocess::nothrow_allocation, limit_objects, preferred_objects, received_objects , reuse_ptr, sizeof_object); - if(!(command & nothrow_allocation) && !ret.first) + if(!(command & boost::interprocess::nothrow_allocation) && !ret.first) throw bad_alloc(); return ret; } @@ -297,7 +298,7 @@ class segment_manager_base //scoped_lock guard(m_header); //------------------------------- - if(ctrl_data->allocation_type() != anonymous_type){ + if(ctrl_data->alloc_type() != anonymous_type){ //This is not an anonymous object, the pointer is wrong! assert(0); } @@ -311,11 +312,6 @@ class segment_manager_base /// @endcond }; -//These pointers are the ones the user will use to -//indicate previous allocation types -static const detail::anonymous_instance_t * anonymous_instance = 0; -static const detail::unique_instance_t * unique_instance = 0; - //!This object is placed in the beginning of memory segment and //!implements the allocation (named or anonymous) of portions //!of the segment. This object contains two indexes that @@ -351,7 +347,6 @@ class segment_manager typedef MemoryAlgorithm memory_algorithm; typedef typename Base::void_pointer void_pointer; typedef CharType char_type; - typedef typename Base::multiallocation_iterator multiallocation_iterator; typedef segment_manager_base segment_manager_base_type; @@ -672,6 +667,7 @@ class segment_manager typename deleter::type get_deleter() { return typename deleter::type(this); } + /// @cond //!Generic named/anonymous new function. Offers all the possibilities, @@ -753,7 +749,7 @@ class segment_manager void priv_destroy_ptr(const void *ptr, detail::in_place_interface &dtor) { block_header_t *ctrl_data = block_header_t::block_header_from_value(ptr, dtor.size, dtor.alignment); - switch(ctrl_data->allocation_type()){ + switch(ctrl_data->alloc_type()){ case anonymous_type: this->prot_anonymous_destroy(ptr, dtor); break; @@ -779,7 +775,7 @@ class segment_manager //!functions. Does not throw static const CharType *priv_get_instance_name(block_header_t *ctrl_data) { - allocation_type type = ctrl_data->allocation_type(); + boost::interprocess::allocation_type type = ctrl_data->alloc_type(); if(type != named_type){ assert((type == anonymous_type && ctrl_data->m_num_char == 0) || (type == unique_type && ctrl_data->m_num_char != 0) ); @@ -805,8 +801,8 @@ class segment_manager static instance_type priv_get_instance_type(block_header_t *ctrl_data) { //Get header - assert((instance_type)ctrl_data->allocation_type() < max_allocation_type); - return (instance_type)ctrl_data->allocation_type(); + assert((instance_type)ctrl_data->alloc_type() < max_allocation_type); + return (instance_type)ctrl_data->alloc_type(); } static std::size_t priv_get_reserved_bytes() @@ -1311,18 +1307,13 @@ class segment_manager typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex; - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - scoped_lock - #else - detail::move_return > - #endif - priv_get_lock(bool use_lock) + scoped_lock priv_get_lock(bool use_lock) { scoped_lock local(m_header, defer_lock); if(use_lock){ local.lock(); } - return local; + return scoped_lock(boost::interprocess::move(local)); } //!This struct includes needed data and derives from @@ -1338,6 +1329,7 @@ class segment_manager , m_unique_index(restricted_segment_mngr) {} } m_header; + /// @endcond }; diff --git a/include/boost/interprocess/shared_memory_object.hpp b/include/boost/interprocess/shared_memory_object.hpp index f84c0c7..b1a9b34 100644 --- a/include/boost/interprocess/shared_memory_object.hpp +++ b/include/boost/interprocess/shared_memory_object.hpp @@ -22,10 +22,11 @@ #include #include #include -#include //std::remove #include -#ifdef BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS +#if defined(BOOST_INTERPROCESS_SYSTEM_V_SHARED_MEMORY_OBJECTS) +# include //System V shared memory... +#elif defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) # include //O_CREAT, O_*... # include //shm_xxx # include //ftruncate, close @@ -46,11 +47,12 @@ class shared_memory_object { /// @cond //Non-copyable and non-assignable - shared_memory_object(const shared_memory_object &); - shared_memory_object &operator=(const shared_memory_object &); + shared_memory_object(shared_memory_object &); + shared_memory_object &operator=(shared_memory_object &); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(shared_memory_object) //!Default constructor. Represents an empty shared_memory_object. shared_memory_object(); @@ -74,44 +76,22 @@ class shared_memory_object //!Moves the ownership of "moved"'s shared memory object to *this. //!After the call, "moved" does not represent any shared memory object. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - shared_memory_object(detail::moved_object moved) - : m_handle(file_handle_t(detail::invalid_file())) - { this->swap(moved.get()); } - #else - shared_memory_object(shared_memory_object &&moved) + shared_memory_object(BOOST_INTERPROCESS_RV_REF(shared_memory_object) moved) : m_handle(file_handle_t(detail::invalid_file())) { this->swap(moved); } - #endif //!Moves the ownership of "moved"'s shared memory to *this. //!After the call, "moved" does not represent any shared memory. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - shared_memory_object &operator= - (detail::moved_object moved) + shared_memory_object &operator=(BOOST_INTERPROCESS_RV_REF(shared_memory_object) moved) { - shared_memory_object tmp(moved); + shared_memory_object tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } - #else - shared_memory_object &operator=(shared_memory_object &&moved) - { - shared_memory_object tmp(detail::move_impl(moved)); - this->swap(tmp); - return *this; - } - #endif //!Swaps the shared_memory_objects. Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } - void swap(shared_memory_object &other); - #else - void swap(shared_memory_object &&other); - #endif + void swap(shared_memory_object &moved); //!Erases a shared memory object from the system. //!Returns false on error. Never throws @@ -173,11 +153,7 @@ inline const char *shared_memory_object::get_name() const inline bool shared_memory_object::get_size(offset_t &size) const { return detail::get_file_size((file_handle_t)m_handle, size); } -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) inline void shared_memory_object::swap(shared_memory_object &other) -#else -inline void shared_memory_object::swap(shared_memory_object &&other) -#endif { std::swap(m_handle, other.m_handle); std::swap(m_mode, other.m_mode); @@ -185,7 +161,9 @@ inline void shared_memory_object::swap(shared_memory_object &&other) } inline mapping_handle_t shared_memory_object::get_mapping_handle() const -{ return detail::mapping_handle_from_file_handle(m_handle); } +{ + return detail::mapping_handle_from_file_handle(m_handle); +} inline mode_t shared_memory_object::get_mode() const { return m_mode; } @@ -229,7 +207,6 @@ inline bool shared_memory_object::priv_open_or_create throw interprocess_exception(err); } - //detail::delete_file_on_reboot_if_possible(shmfile.c_str()); m_mode = mode; return true; } @@ -240,7 +217,7 @@ inline bool shared_memory_object::remove(const char *filename) //Make sure a temporary path is created for shared memory std::string shmfile; detail::tmp_filename(filename, shmfile); - return std::remove(shmfile.c_str()) == 0; + return detail::delete_file(shmfile.c_str()) == 0; } catch(...){ return false; @@ -355,14 +332,6 @@ inline void shared_memory_object::priv_close() #endif -//!Trait class to detect if a type is -//!movable -template<> -struct is_movable -{ - enum { value = true }; -}; - ///@endcond //!A class that stores the name of a shared memory diff --git a/include/boost/interprocess/smart_ptr/deleter.hpp b/include/boost/interprocess/smart_ptr/deleter.hpp index 5909808..c223e4f 100644 --- a/include/boost/interprocess/smart_ptr/deleter.hpp +++ b/include/boost/interprocess/smart_ptr/deleter.hpp @@ -20,6 +20,7 @@ #include #include #include +#include //!\file //!Describes the functor to delete objects from the segment. @@ -35,11 +36,11 @@ template class deleter { public: - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; private: - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type segment_manager_pointer; segment_manager_pointer mp_mngr; diff --git a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp index 8e4db51..39a64da 100644 --- a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp +++ b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -41,20 +42,20 @@ template class shared_count { public: - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; private: typedef sp_counted_impl_pd counted_impl; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type counted_impl_ptr; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type counted_base_ptr; typedef typename VoidAllocator::template rebind ::other counted_impl_allocator; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_deleter_pointer; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_allocator_pointer; pointer m_px; @@ -212,14 +213,14 @@ template class weak_count { public: - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; private: typedef sp_counted_impl_pd counted_impl; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type counted_impl_ptr; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type counted_base_ptr; pointer m_px; diff --git a/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp b/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp index 23c4e67..9d799fa 100644 --- a/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp +++ b/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace boost { @@ -33,6 +34,34 @@ namespace interprocess { namespace detail { +//!A deleter for scoped_ptr that deallocates the memory +//!allocated for an object using a STL allocator. +template +struct scoped_ptr_dealloc_functor +{ + typedef typename Allocator::pointer pointer; + typedef detail::integral_constant::value> alloc_version; + typedef detail::integral_constant allocator_v1; + typedef detail::integral_constant allocator_v2; + + private: + void priv_deallocate(const typename Allocator::pointer &p, allocator_v1) + { m_alloc.deallocate(p, 1); } + + void priv_deallocate(const typename Allocator::pointer &p, allocator_v2) + { m_alloc.deallocate_one(p); } + + public: + Allocator& m_alloc; + + scoped_ptr_dealloc_functor(Allocator& a) + : m_alloc(a) {} + + void operator()(pointer ptr) + { if (ptr) priv_deallocate(ptr, alloc_version()); } +}; + template class sp_counted_impl_pd : public sp_counted_base @@ -50,10 +79,10 @@ class sp_counted_impl_pd sp_counted_impl_pd( sp_counted_impl_pd const & ); sp_counted_impl_pd & operator= ( sp_counted_impl_pd const & ); - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_deleter_pointer; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_allocator_pointer; typedef typename D::pointer pointer; @@ -73,7 +102,7 @@ class sp_counted_impl_pd { return const_allocator_pointer(&static_cast(*this)); } void dispose() // nothrow - { static_cast(*this)(m_ptr); } + { static_cast(*this)(m_ptr); } void destroy() // nothrow { @@ -83,9 +112,8 @@ class sp_counted_impl_pd BOOST_ASSERT(a_copy == *this); this_pointer this_ptr (this); //Do it now! - scoped_ptr > - deallocator(this_ptr, a_copy); + scoped_ptr< this_type, scoped_ptr_dealloc_functor > + deleter(this_ptr, a_copy); typedef typename this_allocator::value_type value_type; detail::get_pointer(this_ptr)->~value_type(); } diff --git a/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp b/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp index 5ebac3c..86df285 100644 --- a/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp @@ -22,6 +22,7 @@ #include #include +#include #include // for std::less #include // for std::basic_ostream @@ -49,7 +50,7 @@ class intrusive_ptr { public: //!Provides the type of the internal stored pointer. - typedef typename detail::pointer_to_other::type pointer; + typedef typename boost::pointer_to_other::type pointer; //!Provides the type of the stored pointer. typedef T element_type; diff --git a/include/boost/interprocess/smart_ptr/scoped_ptr.hpp b/include/boost/interprocess/smart_ptr/scoped_ptr.hpp index a21ba60..74fe1d6 100644 --- a/include/boost/interprocess/smart_ptr/scoped_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/scoped_ptr.hpp @@ -19,6 +19,7 @@ #include #include #include +#include //!\file //!Describes the smart pointer scoped_ptr @@ -54,7 +55,7 @@ class scoped_ptr typedef typename detail::pointer_type::type pointer; //!Provides the type of the internal stored pointer -// typedef typename detail::pointer_to_other +// typedef typename boost::pointer_to_other // ::type pointer; //!Constructs a scoped_ptr, storing a copy of p(which can be 0) and d. diff --git a/include/boost/interprocess/smart_ptr/shared_ptr.hpp b/include/boost/interprocess/smart_ptr/shared_ptr.hpp index ddf6f7d..5d650e2 100644 --- a/include/boost/interprocess/smart_ptr/shared_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/shared_ptr.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include // for std::swap #include // for std::less @@ -96,18 +97,20 @@ class shared_ptr typedef T element_type; typedef T value_type; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; typedef typename detail::add_reference ::type reference; typedef typename detail::add_reference ::type const_reference; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_deleter_pointer; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_allocator_pointer; public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(shared_ptr) + //!Constructs an empty shared_ptr. //!Use_count() == 0 && get()== 0. shared_ptr() @@ -122,7 +125,7 @@ class shared_ptr { //Check that the pointer passed is of the same type that //the pointer the allocator defines or it's a raw pointer - typedef typename detail::pointer_to_other::type ParameterPointer; + typedef typename boost::pointer_to_other::type ParameterPointer; BOOST_STATIC_ASSERT((detail::is_same::value) || (detail::is_pointer::value)); detail::sp_enable_shared_from_this( m_pn, detail::get_pointer(p), detail::get_pointer(p) ); @@ -153,15 +156,9 @@ class shared_ptr //!Move-Constructs a shared_ptr that takes ownership of other resource and //!other is put in default-constructed state. //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - explicit shared_ptr(detail::moved_object other) - : m_pn() - { this->swap(other.get()); } - #else - explicit shared_ptr(shared_ptr &&other) + explicit shared_ptr(BOOST_INTERPROCESS_RV_REF(shared_ptr) other) : m_pn() { this->swap(other); } - #endif /// @cond template @@ -198,19 +195,11 @@ class shared_ptr //!Move-assignment. Equivalent to shared_ptr(other).swap(*this). //!Never throws - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - shared_ptr & operator=(detail::moved_object other) // never throws + shared_ptr & operator=(BOOST_INTERPROCESS_RV_REF(shared_ptr) other) // never throws { this_type(other).swap(*this); return *this; } - #else - shared_ptr & operator=(shared_ptr &&other) // never throws - { - this_type(other).swap(*this); - return *this; - } - #endif //!This is equivalent to: //!this_type().swap(*this); @@ -226,7 +215,7 @@ class shared_ptr { //Check that the pointer passed is of the same type that //the pointer the allocator defines or it's a raw pointer - typedef typename detail::pointer_to_other::type ParameterPointer; + typedef typename boost::pointer_to_other::type ParameterPointer; BOOST_STATIC_ASSERT((detail::is_same::value) || (detail::is_pointer::value)); this_type(p, a, d).swap(*this); @@ -371,26 +360,6 @@ inline typename managed_shared_ptr::type ); } - -/* -// get_deleter (experimental) -template -typename detail::pointer_to_other, Deleter>::type - get_deleter(shared_ptr const & p) -{ return static_cast(p._internal_get_deleter(typeid(Deleter))); } -*/ - -/// @cond - -//!This class has move constructor -template -struct is_movable > -{ - enum { value = true }; -}; - -/// @endcond - } // namespace interprocess /// @cond diff --git a/include/boost/interprocess/smart_ptr/unique_ptr.hpp b/include/boost/interprocess/smart_ptr/unique_ptr.hpp index 064af09..36a7507 100644 --- a/include/boost/interprocess/smart_ptr/unique_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/unique_ptr.hpp @@ -88,6 +88,8 @@ class unique_ptr /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(unique_ptr) + typedef T element_type; typedef D deleter_type; typedef typename detail::pointer_type::type pointer; @@ -142,7 +144,7 @@ class unique_ptr //! //!After the construction, u no longer owns a pointer. //![ Note: The deleter constructor can be implemented with - //!std::detail::forward_impl. -end note ] + //! boost::interprocess::forward. -end note ] //! //!Postconditions: get() == value u.get() had before the construction. //!get_deleter() returns a reference to the internally stored deleter which @@ -150,15 +152,9 @@ class unique_ptr //!deleter() and u.get_deleter() both reference the same lvalue deleter. //! //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - unique_ptr(detail::moved_object u) - : ptr_(u.get().release(), detail::move_impl(u.get().get_deleter())) + unique_ptr(BOOST_INTERPROCESS_RV_REF(unique_ptr) u) + : ptr_(u.release(), boost::interprocess::forward(u.get_deleter())) {} - #else - unique_ptr(unique_ptr &&u) - : ptr_(u.release(), detail::forward_impl(u.get_deleter())) - {} - #endif //!Requires: If D is not a reference type, construction of the deleter //!D from an rvalue of type E must be well formed @@ -179,9 +175,8 @@ class unique_ptr //!was constructed from u.get_deleter(). //! //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template - unique_ptr(detail::moved_object > u, + unique_ptr(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(unique_ptr, U, E) u, typename detail::enable_if_c< detail::is_convertible::pointer, pointer>::value && detail::is_convertible::value && @@ -192,24 +187,8 @@ class unique_ptr , nat >::type = nat()) - : ptr_(const_cast&>(u.get()).release(), detail::move_impl(u.get().get_deleter())) + : ptr_(const_cast&>(u).release(), boost::interprocess::move(u.get_deleter())) {} - #else - template - unique_ptr(unique_ptr && u, - typename detail::enable_if_c< - detail::is_convertible::pointer, pointer>::value && - detail::is_convertible::value && - ( - !detail::is_reference::value || - detail::is_same::value - ) - , - nat - >::type = nat()) - : ptr_(const_cast&>(u).release(), detail::forward_impl(u.get_deleter())) - {} - #endif //!Effects: If get() == 0 there are no effects. Otherwise get_deleter()(get()). //! @@ -230,21 +209,12 @@ class unique_ptr //!Returns: *this. //! //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - unique_ptr& operator=(detail::moved_object u) - { - reset(u.get().release()); - ptr_.second() = detail::move_impl(u.get().get_deleter()); - return *this; - } - #else - unique_ptr& operator=(unique_ptr && u) + unique_ptr& operator=(BOOST_INTERPROCESS_RV_REF(unique_ptr) u) { reset(u.release()); - ptr_.second() = detail::move_impl(u.get_deleter()); + ptr_.second() = boost::interprocess::move(u.get_deleter()); return *this; } - #endif //!Requires: Assignment of the deleter D from an rvalue D must not //!throw an exception. U* must be implicitly convertible to T*. @@ -261,21 +231,12 @@ class unique_ptr //! //!Throws: nothing. template - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - unique_ptr& operator=(detail::moved_object > mu) - { - reset(mu.get().release()); - ptr_.second() = detail::move_impl(mu.get().get_deleter()); - return *this; - } - #else - unique_ptr& operator=(unique_ptr && u) + unique_ptr& operator=(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(unique_ptr, U, E) u) { reset(u.release()); - ptr_.second() = detail::move_impl(u.get_deleter()); + ptr_.second() = boost::interprocess::move(u.get_deleter()); return *this; } - #endif //!Assigns from the literal 0 or NULL. //! @@ -359,23 +320,14 @@ class unique_ptr //!Effects: The stored pointers of this and u are exchanged. //! The stored deleters are swapped (unqualified). //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) void swap(unique_ptr& u) { ptr_.swap(u.ptr_); } - void swap(detail::moved_object mu) - { ptr_.swap(mu.get().ptr_); } - #else - void swap(unique_ptr&&u) - { ptr_.swap(u.ptr_); } - #endif - /// @cond private: boost::compressed_pair ptr_; - //This private constructor avoids moving from non-const lvalues - unique_ptr(const unique_ptr&); + unique_ptr(unique_ptr&); template unique_ptr(unique_ptr&); template unique_ptr(U&, typename detail::unique_ptr_error::type = 0); @@ -570,16 +522,6 @@ template inline bool operator>=(const unique_ptr& x, const unique_ptr& y) { return x.get() >= y.get(); } -/// @cond - -//!This class has move constructor -template -struct is_movable > -{ - enum { value = true }; -}; -/// @endcond - //!Returns the type of a unique pointer //!of type T with boost::interprocess::deleter deleter @@ -597,20 +539,11 @@ struct managed_unique_ptr //!with boost::interproces::deleter from a pointer //!of type T that has been allocated in the passed managed segment template -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -inline typename detail::return_type - ::type - >::type -#else -typename managed_unique_ptr::type -#endif +inline typename managed_unique_ptr::type make_managed_unique_ptr(T *constructed_object, ManagedMemory &managed_memory) { - typename managed_unique_ptr::type to_return - ( constructed_object - , managed_memory.template get_deleter() - ); - return to_return; + return typename managed_unique_ptr::type + (constructed_object, managed_memory.template get_deleter()); } } //namespace interprocess{ diff --git a/include/boost/interprocess/smart_ptr/weak_ptr.hpp b/include/boost/interprocess/smart_ptr/weak_ptr.hpp index d69e4fe..4019f47 100644 --- a/include/boost/interprocess/smart_ptr/weak_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/weak_ptr.hpp @@ -22,6 +22,7 @@ #include #include #include +#include //!\file //!Describes the smart pointer weak_ptr. @@ -53,7 +54,7 @@ class weak_ptr private: // Borland 5.5.1 specific workarounds typedef weak_ptr this_type; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; typedef typename detail::add_reference ::type reference; diff --git a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp index b40e3c7..32b236f 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp @@ -94,11 +94,11 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, InternalLock lock; if(tout_enabled){ InternalLock dummy(m_enter_mut, abs_time); - lock = detail::move_impl(dummy); + lock = boost::interprocess::move(dummy); } else{ InternalLock dummy(m_enter_mut); - lock = detail::move_impl(dummy); + lock = boost::interprocess::move(dummy); } if(!lock) @@ -161,15 +161,18 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, InternalLock lock; if(tout_enabled){ InternalLock dummy(m_check_mut, abs_time); - lock = detail::move_impl(dummy); + lock = boost::interprocess::move(dummy); } else{ InternalLock dummy(m_check_mut); - lock = detail::move_impl(dummy); + lock = boost::interprocess::move(dummy); } - if(!lock) - return false; + if(!lock){ + timed_out = true; + unlock_enter_mut = true; + break; + } //--------------------------------------------------------------- boost::uint32_t result = detail::atomic_cas32 (const_cast(&m_command), SLEEP, NOTIFY_ONE); diff --git a/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp index c659e20..c6bc907 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp @@ -39,8 +39,11 @@ inline interprocess_recursive_mutex::~interprocess_recursive_mutex(){} inline void interprocess_recursive_mutex::lock() { - detail::OS_systemwide_thread_id_t th_id = detail::get_current_systemwide_thread_id(); - if(detail::equal_systemwide_thread_id(th_id, m_nOwner)){ + typedef detail::OS_systemwide_thread_id_t handle_t; + const handle_t thr_id(detail::get_current_systemwide_thread_id()); + handle_t old_id; + detail::systemwide_thread_id_copy(m_nOwner, old_id); + if(detail::equal_systemwide_thread_id(thr_id , old_id)){ if((unsigned int)(m_nLockCount+1) == 0){ //Overflow, throw an exception throw interprocess_exception(); @@ -49,15 +52,18 @@ inline void interprocess_recursive_mutex::lock() } else{ m_mutex.lock(); - m_nOwner = th_id; + detail::systemwide_thread_id_copy(thr_id, m_nOwner); m_nLockCount = 1; } } inline bool interprocess_recursive_mutex::try_lock() { - detail::OS_systemwide_thread_id_t th_id = detail::get_current_systemwide_thread_id(); - if(detail::equal_systemwide_thread_id(th_id, m_nOwner)) { // we own it + typedef detail::OS_systemwide_thread_id_t handle_t; + handle_t thr_id(detail::get_current_systemwide_thread_id()); + handle_t old_id; + detail::systemwide_thread_id_copy(m_nOwner, old_id); + if(detail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it if((unsigned int)(m_nLockCount+1) == 0){ //Overflow, throw an exception throw interprocess_exception(); @@ -66,7 +72,7 @@ inline bool interprocess_recursive_mutex::try_lock() return true; } if(m_mutex.try_lock()){ - m_nOwner = th_id; + detail::systemwide_thread_id_copy(thr_id, m_nOwner); m_nLockCount = 1; return true; } @@ -75,12 +81,15 @@ inline bool interprocess_recursive_mutex::try_lock() inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) { + typedef detail::OS_systemwide_thread_id_t handle_t; if(abs_time == boost::posix_time::pos_infin){ this->lock(); return true; } - detail::OS_systemwide_thread_id_t th_id = detail::get_current_systemwide_thread_id(); - if(detail::equal_systemwide_thread_id(th_id, m_nOwner)) { // we own it + const handle_t thr_id(detail::get_current_systemwide_thread_id()); + handle_t old_id; + detail::systemwide_thread_id_copy(m_nOwner, old_id); + if(detail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it if((unsigned int)(m_nLockCount+1) == 0){ //Overflow, throw an exception throw interprocess_exception(); @@ -89,7 +98,7 @@ inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::pt return true; } if(m_mutex.timed_lock(abs_time)){ - m_nOwner = th_id; + detail::systemwide_thread_id_copy(thr_id, m_nOwner); m_nLockCount = 1; return true; } @@ -98,10 +107,16 @@ inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::pt inline void interprocess_recursive_mutex::unlock() { - assert(detail::equal_systemwide_thread_id(detail::get_current_systemwide_thread_id(), m_nOwner)); + typedef detail::OS_systemwide_thread_id_t handle_t; + handle_t old_id; + detail::systemwide_thread_id_copy(m_nOwner, old_id); + const handle_t thr_id(detail::get_current_systemwide_thread_id()); + (void)old_id; + assert(detail::equal_systemwide_thread_id(thr_id, old_id)); --m_nLockCount; if(!m_nLockCount){ - m_nOwner = detail::get_invalid_systemwide_thread_id(); + const handle_t new_id(detail::get_invalid_systemwide_thread_id()); + detail::systemwide_thread_id_copy(new_id, m_nOwner); m_mutex.unlock(); } } diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp index 517770f..d0f329d 100644 --- a/include/boost/interprocess/sync/file_lock.hpp +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -29,19 +29,6 @@ namespace boost { namespace interprocess { -///@cond - -class file_lock; - -//!Trait class to detect if a type is -//!movable -template<> -struct is_movable -{ - enum { value = true }; -}; - -///@endcond //!A file lock, is a mutual exclusion utility similar to a mutex using a //!file. A file lock has sharable and exclusive locking capabilities and @@ -56,6 +43,7 @@ class file_lock file_lock &operator=(const file_lock &); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(file_lock) //!Constructs an empty file mapping. //!Does not throw @@ -70,28 +58,16 @@ class file_lock //!Moves the ownership of "moved"'s file mapping object to *this. //!After the call, "moved" does not represent any file mapping object. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - file_lock(detail::moved_object moved) - : m_file_hnd(file_handle_t(detail::invalid_file())) - { this->swap(moved.get()); } - #else - file_lock(file_lock &&moved) + file_lock(BOOST_INTERPROCESS_RV_REF(file_lock) moved) : m_file_hnd(file_handle_t(detail::invalid_file())) { this->swap(moved); } - #endif //!Moves the ownership of "moved"'s file mapping to *this. //!After the call, "moved" does not represent any file mapping. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - file_lock &operator=(detail::moved_object m_other) + file_lock &operator=(BOOST_INTERPROCESS_RV_REF(file_lock) moved) { - file_lock &moved = m_other.get(); - #else - file_lock &operator=(file_lock &&moved) - { - #endif - file_lock tmp(detail::move_impl(moved)); + file_lock tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -101,16 +77,10 @@ class file_lock //!Swaps two file_locks. //!Does not throw. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(file_lock &other) - #else - void swap(file_lock &&other) - #endif { file_handle_t tmp = m_file_hnd; - other.m_file_hnd = other.m_file_hnd; + m_file_hnd = other.m_file_hnd; other.m_file_hnd = tmp; } diff --git a/include/boost/interprocess/sync/interprocess_barrier.hpp b/include/boost/interprocess/sync/interprocess_barrier.hpp index 6ba5a66..3133668 100644 --- a/include/boost/interprocess/sync/interprocess_barrier.hpp +++ b/include/boost/interprocess/sync/interprocess_barrier.hpp @@ -26,6 +26,8 @@ #ifndef BOOST_INTERPROCESS_BARRIER_HPP #define BOOST_INTERPROCESS_BARRIER_HPP +/// @cond + #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif @@ -48,6 +50,8 @@ # include +/// @endcond + namespace boost { namespace interprocess { diff --git a/include/boost/interprocess/sync/interprocess_condition.hpp b/include/boost/interprocess/sync/interprocess_condition.hpp index 5c4a123..73b9e67 100644 --- a/include/boost/interprocess/sync/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/interprocess_condition.hpp @@ -15,6 +15,8 @@ # pragma once #endif +/// @cond + #include #include @@ -38,6 +40,8 @@ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION #endif +/// @endcond + //!\file //!Describes process-shared variables interprocess_condition class diff --git a/include/boost/interprocess/sync/interprocess_mutex.hpp b/include/boost/interprocess/sync/interprocess_mutex.hpp index 5717725..8d7192b 100644 --- a/include/boost/interprocess/sync/interprocess_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_mutex.hpp @@ -27,6 +27,8 @@ #ifndef BOOST_INTERPROCESS_MUTEX_HPP #define BOOST_INTERPROCESS_MUTEX_HPP +/// @cond + #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif @@ -48,6 +50,8 @@ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION #endif +/// @endcond + //!\file //!Describes a mutex class that can be placed in memory shared by //!several processes. @@ -110,7 +114,7 @@ class interprocess_mutex volatile boost::uint32_t m_s; #elif defined(BOOST_INTERPROCESS_USE_POSIX) pthread_mutex_t m_mut; - #endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #endif //#if (defined BOOST_INTERPROCESS_WINDOWS) /// @endcond }; diff --git a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp index 13c0eb0..96369cc 100644 --- a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp @@ -27,6 +27,8 @@ #ifndef BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP #define BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP +/// @cond + #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif @@ -50,6 +52,8 @@ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION #endif +/// @endcond + //!\file //!Describes interprocess_recursive_mutex and shared_recursive_try_mutex classes @@ -106,10 +110,10 @@ class interprocess_recursive_mutex #if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION) interprocess_mutex m_mutex; unsigned int m_nLockCount; - detail::OS_systemwide_thread_id_t m_nOwner; + volatile detail::OS_systemwide_thread_id_t m_nOwner; #else //#if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION) pthread_mutex_t m_mut; - #endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #endif //#if (defined BOOST_INTERPROCESS_WINDOWS) /// @endcond }; diff --git a/include/boost/interprocess/sync/interprocess_semaphore.hpp b/include/boost/interprocess/sync/interprocess_semaphore.hpp index b10eb89..0fe15ad 100644 --- a/include/boost/interprocess/sync/interprocess_semaphore.hpp +++ b/include/boost/interprocess/sync/interprocess_semaphore.hpp @@ -11,6 +11,8 @@ #ifndef BOOST_INTERPROCESS_SEMAPHORE_HPP #define BOOST_INTERPROCESS_SEMAPHORE_HPP +/// @cond + #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif @@ -22,7 +24,7 @@ #include #if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \ - (defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES)) + (defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES)) #include //O_CREAT, O_*... #include //close #include //std::string @@ -39,6 +41,8 @@ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION #endif +/// @endcond + //!\file //!Describes a interprocess_semaphore class for inter-process synchronization diff --git a/include/boost/interprocess/sync/named_condition.hpp b/include/boost/interprocess/sync/named_condition.hpp index 38ce368..96047ca 100644 --- a/include/boost/interprocess/sync/named_condition.hpp +++ b/include/boost/interprocess/sync/named_condition.hpp @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include #include @@ -24,6 +26,7 @@ #include #include #include +#include #if defined BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES #include #include @@ -85,7 +88,7 @@ class named_condition //!If there are no waiting threads, notify_all() has no effect. void notify_all(); - //!Releases the lock on the interprocess_mutex object associated with lock, blocks + //!Releases the lock on the named_mutex object associated with lock, blocks //!the current thread of execution until readied by a call to //!this->notify_one() or this->notify_all(), and then reacquires the lock. template @@ -96,7 +99,7 @@ class named_condition template void wait(L& lock, Pr pred); - //!Releases the lock on the interprocess_mutex object associated with lock, blocks + //!Releases the lock on the named_mutex object associated with lock, blocks //!the current thread of execution until readied by a call to //!this->notify_one() or this->notify_all(), or until time abs_time is reached, //!and then reacquires the lock. @@ -148,7 +151,10 @@ class named_condition template void do_wait(Lock& lock) - { + { + //named_condition only works with named_mutex + BOOST_STATIC_ASSERT((detail::is_convertible::value == true)); + //lock internal before unlocking external to avoid race with a notifier scoped_lock internal_lock(*this->mutex()); lock_inverter inverted_lock(lock); @@ -163,6 +169,8 @@ class named_condition template bool do_timed_wait(Lock& lock, const boost::posix_time::ptime &abs_time) { + //named_condition only works with named_mutex + BOOST_STATIC_ASSERT((detail::is_convertible::value == true)); //lock internal before unlocking external to avoid race with a notifier scoped_lock internal_lock(*this->mutex(), abs_time); if(!internal_lock) return false; diff --git a/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp index 67b6998..f76212f 100644 --- a/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp +++ b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp @@ -20,7 +20,7 @@ #include #ifdef SEM_FAILED -#define BOOST_INTERPROCESS_POSIX_SEM_FAILED SEM_FAILED +#define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast(SEM_FAILED)) #else #define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast(-1)) #endif diff --git a/include/boost/interprocess/sync/scoped_lock.hpp b/include/boost/interprocess/sync/scoped_lock.hpp index 2bdfa3e..8dd1e57 100644 --- a/include/boost/interprocess/sync/scoped_lock.hpp +++ b/include/boost/interprocess/sync/scoped_lock.hpp @@ -22,8 +22,11 @@ #include #include +#include #include #include +#include +#include #include #include @@ -33,11 +36,6 @@ namespace boost { namespace interprocess { -template -class sharable_lock; - -template -class upgradable_lock; //!scoped_lock is meant to carry out the tasks for locking, unlocking, try-locking //!and timed-locking (recursive or not) for the Mutex. The Mutex need not supply all @@ -55,11 +53,13 @@ class scoped_lock /// @cond private: typedef scoped_lock this_type; - scoped_lock(scoped_lock const&); - scoped_lock& operator= (scoped_lock const&); + scoped_lock(scoped_lock&); + scoped_lock& operator= (scoped_lock&); typedef bool this_type::*unspecified_bool_type; /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(scoped_lock) + typedef Mutex mutex_type; //!Effects: Default constructs a scoped_lock. @@ -122,18 +122,12 @@ class scoped_lock //! to thisscoped_lock with no blocking. If the scop scoped_lock does not //! own the mutex, then neither will this scoped_lock. Only a moved //! scoped_lock's will match this signature. An non-moved scoped_lock - //! can be moved with the expression: "detail::move_impl(lock);". This + //! can be moved with the expression: "boost::interprocess::move(lock);". This //! constructor does not alter the state of the mutex, only potentially //! who owns it. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > scop) - : mp_mutex(0), m_locked(scop.get().owns()) - { mp_mutex = scop.get().release(); } - #else - scoped_lock(scoped_lock &&scop) + scoped_lock(BOOST_INTERPROCESS_RV_REF(scoped_lock) scop) : mp_mutex(0), m_locked(scop.owns()) { mp_mutex = scop.release(); } - #endif //!Effects: If upgr.owns() then calls unlock_upgradable_and_lock() on the //! referenced mutex. upgr.release() is called. @@ -144,22 +138,12 @@ class scoped_lock //! unlocking upgr. If upgr is unlocked, then this scoped_lock will be //! unlocked as well. Only a moved upgradable_lock's will match this //! signature. An non-moved upgradable_lock can be moved with - //! the expression: "detail::move_impl(lock);" This constructor may block if + //! the expression: "boost::interprocess::move(lock);" This constructor may block if //! other threads hold a sharable_lock on this mutex (sharable_lock's can //! share ownership with an upgradable_lock). - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > upgr) - : mp_mutex(0), m_locked(false) - { - upgradable_lock &u_lock = upgr.get(); - if(u_lock.owns()){ - u_lock.mutex()->unlock_upgradable_and_lock(); - m_locked = true; - } - mp_mutex = u_lock.release(); - } - #else - scoped_lock(upgradable_lock &&upgr) + template + explicit scoped_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -169,7 +153,6 @@ class scoped_lock } mp_mutex = u_lock.release(); } - #endif //!Effects: If upgr.owns() then calls try_unlock_upgradable_and_lock() on the //!referenced mutex: @@ -185,25 +168,10 @@ class scoped_lock //! "read lock" to a "write lock". If the "read lock" isn't held in the //! first place, the mutex merely changes type to an unlocked "write lock". //! If the "read lock" is held, then mutex transfer occurs only if it can - //! do so in a non-blocking manner.*/ - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > upgr - ,try_to_lock_type) - : mp_mutex(0), m_locked(false) - { - upgradable_lock &u_lock = upgr.get(); - if(u_lock.owns()){ - if((m_locked = u_lock.mutex()->try_unlock_upgradable_and_lock()) == true){ - mp_mutex = u_lock.release(); - } - } - else{ - u_lock.release(); - } - } - #else - scoped_lock(upgradable_lock &&upgr - ,try_to_lock_type) + //! do so in a non-blocking manner. + template + scoped_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr, try_to_lock_type + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -216,7 +184,6 @@ class scoped_lock u_lock.release(); } } - #endif //!Effects: If upgr.owns() then calls timed_unlock_upgradable_and_lock(abs_time) //! on the referenced mutex: @@ -232,24 +199,9 @@ class scoped_lock //! "write lock". If the "read lock" isn't held in the first place, the mutex //! merely changes type to an unlocked "write lock". If the "read lock" is held, //! then mutex transfer occurs only if it can do so in a non-blocking manner. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > upgr - ,boost::posix_time::ptime &abs_time) - : mp_mutex(0), m_locked(false) - { - upgradable_lock &u_lock = upgr.get(); - if(u_lock.owns()){ - if((m_locked = u_lock.mutex()->timed_unlock_upgradable_and_lock(abs_time)) == true){ - mp_mutex = u_lock.release(); - } - } - else{ - u_lock.release(); - } - } - #else - scoped_lock(upgradable_lock &&upgr - ,boost::posix_time::ptime &abs_time) + template + scoped_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr, boost::posix_time::ptime &abs_time + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -262,7 +214,6 @@ class scoped_lock u_lock.release(); } } - #endif //!Effects: If shar.owns() then calls try_unlock_sharable_and_lock() on the //!referenced mutex. @@ -279,24 +230,9 @@ class scoped_lock //! first place, the mutex merely changes type to an unlocked "write lock". //! If the "read lock" is held, then mutex transfer occurs only if it can //! do so in a non-blocking manner. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > shar - ,try_to_lock_type) - : mp_mutex(0), m_locked(false) - { - sharable_lock &s_lock = shar.get(); - if(s_lock.owns()){ - if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock()) == true){ - mp_mutex = s_lock.release(); - } - } - else{ - s_lock.release(); - } - } - #else - scoped_lock(sharable_lock &&shar - ,try_to_lock_type) + template + scoped_lock(BOOST_INTERPROCESS_RV_REF(sharable_lock) shar, try_to_lock_type + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { sharable_lock &s_lock = shar; @@ -309,7 +245,6 @@ class scoped_lock s_lock.release(); } } - #endif //!Effects: if (owns()) mp_mutex->unlock(). //!Notes: The destructor behavior ensures that the mutex lock is not leaked.*/ @@ -325,17 +260,7 @@ class scoped_lock //! the same mutex before the assignment. In this case, this will own the //! mutex after the assignment (and scop will not), but the mutex's lock //! count will be decremented by one. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock &operator=(detail::moved_object scop) - { - if(this->owns()) - this->unlock(); - m_locked = scop.get().owns(); - mp_mutex = scop.get().release(); - return *this; - } - #else - scoped_lock &operator=(scoped_lock &&scop) + scoped_lock &operator=(BOOST_INTERPROCESS_RV_REF(scoped_lock) scop) { if(this->owns()) this->unlock(); @@ -343,7 +268,6 @@ class scoped_lock mp_mutex = scop.release(); return *this; } - #endif //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() //! exception. Calls lock() on the referenced mutex. @@ -429,19 +353,11 @@ class scoped_lock //!Effects: Swaps state with moved lock. //!Throws: Nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object > other) - { - std::swap(mp_mutex, other.get().mp_mutex); - std::swap(m_locked, other.get().m_locked); - } - #else - void swap(scoped_lock &&other) + void swap( scoped_lock &other) { std::swap(mp_mutex, other.mp_mutex); std::swap(m_locked, other.m_locked); } - #endif /// @cond private: @@ -450,16 +366,6 @@ class scoped_lock /// @endcond }; -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -/// @endcond - } // namespace interprocess } // namespace boost diff --git a/include/boost/interprocess/sync/sharable_lock.hpp b/include/boost/interprocess/sync/sharable_lock.hpp index ea97864..b7baf04 100644 --- a/include/boost/interprocess/sync/sharable_lock.hpp +++ b/include/boost/interprocess/sync/sharable_lock.hpp @@ -22,10 +22,12 @@ #include #include +#include #include #include +#include +#include #include -//Ig#include #include //!\file @@ -35,11 +37,6 @@ namespace boost { namespace interprocess { -template -class scoped_lock; - -template -class upgradable_lock; //!sharable_lock is meant to carry out the tasks for sharable-locking //!(such as read-locking), unlocking, try-sharable-locking and timed-sharable-locking @@ -57,13 +54,14 @@ class sharable_lock /// @cond private: typedef sharable_lock this_type; - sharable_lock(sharable_lock const&); - explicit sharable_lock(scoped_lock const&); + sharable_lock(sharable_lock&); + explicit sharable_lock(scoped_lock&); typedef bool this_type::*unspecified_bool_type; - sharable_lock& operator=(sharable_lock const&); - sharable_lock& operator=(scoped_lock const&); + sharable_lock& operator=(sharable_lock&); + sharable_lock& operator=(scoped_lock&); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(sharable_lock) //!Effects: Default constructs a sharable_lock. //!Postconditions: owns() == false and mutex() == 0. @@ -127,17 +125,11 @@ class sharable_lock //! sharable_lock with no blocking. If the upgr sharable_lock does not own the mutex, then //! neither will this sharable_lock. Only a moved sharable_lock's will match this //! signature. An non-moved sharable_lock can be moved with the expression: - //! "detail::move_impl(lock);". This constructor does not alter the state of the mutex, + //! "boost::interprocess::move(lock);". This constructor does not alter the state of the mutex, //! only potentially who owns it. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - sharable_lock(detail::moved_object > upgr) - : mp_mutex(0), m_locked(upgr.get().owns()) - { mp_mutex = upgr.get().release(); } - #else - sharable_lock(sharable_lock &&upgr) + sharable_lock(BOOST_INTERPROCESS_RV_REF(sharable_lock) upgr) : mp_mutex(0), m_locked(upgr.owns()) { mp_mutex = upgr.release(); } - #endif //!Effects: If upgr.owns() then calls unlock_upgradable_and_lock_sharable() on the //! referenced mutex. @@ -147,20 +139,10 @@ class sharable_lock //!Notes: If upgr is locked, this constructor will lock this sharable_lock while //! unlocking upgr. Only a moved sharable_lock's will match this //! signature. An non-moved upgradable_lock can be moved with the expression: - //! "detail::move_impl(lock);".*/ - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - sharable_lock(detail::moved_object > upgr) - : mp_mutex(0), m_locked(false) - { - upgradable_lock &u_lock = upgr.get(); - if(u_lock.owns()){ - u_lock.mutex()->unlock_upgradable_and_lock_sharable(); - m_locked = true; - } - mp_mutex = u_lock.release(); - } - #else - sharable_lock(upgradable_lock &&upgr) + //! "boost::interprocess::move(lock);".*/ + template + sharable_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -170,7 +152,6 @@ class sharable_lock } mp_mutex = u_lock.release(); } - #endif //!Effects: If scop.owns() then calls unlock_and_lock_sharable() on the //! referenced mutex. @@ -181,20 +162,10 @@ class sharable_lock //! to a sharable-ownership of this sharable_lock. //! Only a moved scoped_lock's will match this //! signature. An non-moved scoped_lock can be moved with the expression: - //! "detail::move_impl(lock);".*/ - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - sharable_lock(detail::moved_object > scop) - : mp_mutex(0), m_locked(false) - { - scoped_lock &e_lock = scop.get(); - if(e_lock.owns()){ - e_lock.mutex()->unlock_and_lock_sharable(); - m_locked = true; - } - mp_mutex = e_lock.release(); - } - #else - sharable_lock(scoped_lock &&scop) + //! "boost::interprocess::move(lock);". + template + sharable_lock(BOOST_INTERPROCESS_RV_REF(scoped_lock) scop + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { scoped_lock &e_lock = scop; @@ -204,7 +175,6 @@ class sharable_lock } mp_mutex = e_lock.release(); } - #endif //!Effects: if (owns()) mp_mutex->unlock_sharable(). //!Notes: The destructor behavior ensures that the mutex lock is not leaked. @@ -221,17 +191,7 @@ class sharable_lock //!Notes: With a recursive mutex it is possible that both this and upgr own the mutex //! before the assignment. In this case, this will own the mutex after the assignment //! (and upgr will not), but the mutex's lock count will be decremented by one. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - sharable_lock &operator=(detail::moved_object > upgr) - { - if(this->owns()) - this->unlock(); - m_locked = upgr.get().owns(); - mp_mutex = upgr.get().release(); - return *this; - } - #else - sharable_lock &operator=(sharable_lock &&upgr) + sharable_lock &operator=(BOOST_INTERPROCESS_RV_REF(sharable_lock) upgr) { if(this->owns()) this->unlock(); @@ -239,7 +199,6 @@ class sharable_lock mp_mutex = upgr.release(); return *this; } - #endif //!Effects: If mutex() == 0 or already locked, throws a lock_exception() //! exception. Calls lock_sharable() on the referenced mutex. @@ -328,19 +287,11 @@ class sharable_lock //!Effects: Swaps state with moved lock. //!Throws: Nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object > other) - { - std::swap(mp_mutex, other.get().mp_mutex); - std::swap(m_locked, other.get().m_locked); - } - #else - void swap(sharable_lock &&other) + void swap(sharable_lock &other) { std::swap(mp_mutex, other.mp_mutex); std::swap(m_locked, other.m_locked); } - #endif /// @cond private: @@ -349,16 +300,6 @@ class sharable_lock /// @endcond }; -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -/// @endcond - } // namespace interprocess } // namespace boost diff --git a/include/boost/interprocess/sync/upgradable_lock.hpp b/include/boost/interprocess/sync/upgradable_lock.hpp index 386187d..fe3744b 100644 --- a/include/boost/interprocess/sync/upgradable_lock.hpp +++ b/include/boost/interprocess/sync/upgradable_lock.hpp @@ -22,7 +22,11 @@ #include #include +#include #include +#include +#include + #include #include #include @@ -34,12 +38,6 @@ namespace boost { namespace interprocess { -template -class scoped_lock; - -template -class sharable_lock; - //!upgradable_lock is meant to carry out the tasks for read-locking, unlocking, //!try-read-locking and timed-read-locking (recursive or not) for the Mutex. //!Additionally the upgradable_lock can transfer ownership to a scoped_lock @@ -57,13 +55,14 @@ class upgradable_lock /// @cond private: typedef upgradable_lock this_type; - upgradable_lock(upgradable_lock const&); - explicit upgradable_lock(scoped_lock const&); + upgradable_lock(upgradable_lock&); + explicit upgradable_lock(scoped_lock&); typedef bool this_type::*unspecified_bool_type; - upgradable_lock& operator=(upgradable_lock const&); - upgradable_lock& operator=(scoped_lock const&); + upgradable_lock& operator=(upgradable_lock&); + upgradable_lock& operator=(scoped_lock&); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(upgradable_lock) //!Effects: Default constructs a upgradable_lock. //!Postconditions: owns() == false and mutex() == 0. @@ -121,17 +120,11 @@ class upgradable_lock //! while unlocking upgr. If upgr is unlocked, then this upgradable_lock will //! be unlocked as well. Only a moved upgradable_lock's will match this //! signature. An non-moved upgradable_lock can be moved with the - //! expression: "detail::move_impl(lock);". This constructor does not alter the + //! expression: "boost::interprocess::move(lock);". This constructor does not alter the //! state of the mutex, only potentially who owns it. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - upgradable_lock(detail::moved_object > upgr) - : mp_mutex(0), m_locked(upgr.get().owns()) - { mp_mutex = upgr.get().release(); } - #else - upgradable_lock(upgradable_lock &&upgr) + upgradable_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr) : mp_mutex(0), m_locked(upgr.owns()) { mp_mutex = upgr.release(); } - #endif //!Effects: If scop.owns(), m_.unlock_and_lock_upgradable(). //!Postconditions: mutex() == the value scop.mutex() had before the construction. @@ -141,20 +134,10 @@ class upgradable_lock //! to an upgradable-ownership of this upgradable_lock. //! Only a moved sharable_lock's will match this //! signature. An non-moved sharable_lock can be moved with the - //! expression: "detail::move_impl(lock);". - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - upgradable_lock(detail::moved_object > scop) - : mp_mutex(0), m_locked(false) - { - scoped_lock &u_lock = scop.get(); - if(u_lock.owns()){ - u_lock.mutex()->unlock_and_lock_upgradable(); - m_locked = true; - } - mp_mutex = u_lock.release(); - } - #else - upgradable_lock(scoped_lock &&scop) + //! expression: "boost::interprocess::move(lock);". + template + upgradable_lock(BOOST_INTERPROCESS_RV_REF(scoped_lock) scop + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { scoped_lock &u_lock = scop; @@ -164,7 +147,6 @@ class upgradable_lock } mp_mutex = u_lock.release(); } - #endif //!Effects: If shar.owns() then calls try_unlock_sharable_and_lock_upgradable() //! on the referenced mutex. @@ -181,24 +163,9 @@ class upgradable_lock //! in the first place, the mutex merely changes type to an unlocked //! "upgradable lock". If the "read lock" is held, then mutex transfer //! occurs only if it can do so in a non-blocking manner. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - upgradable_lock( detail::moved_object > shar - , try_to_lock_type) - : mp_mutex(0), m_locked(false) - { - sharable_lock &s_lock = shar.get(); - if(s_lock.owns()){ - if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock_upgradable()) == true){ - mp_mutex = s_lock.release(); - } - } - else{ - s_lock.release(); - } - } - #else - upgradable_lock( sharable_lock &&shar - , try_to_lock_type) + template + upgradable_lock( BOOST_INTERPROCESS_RV_REF(sharable_lock) shar, try_to_lock_type + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { sharable_lock &s_lock = shar; @@ -211,7 +178,6 @@ class upgradable_lock s_lock.release(); } } - #endif //!Effects: if (owns()) m_->unlock_upgradable(). //!Notes: The destructor behavior ensures that the mutex lock is not leaked. @@ -229,17 +195,7 @@ class upgradable_lock //! mutex before the assignment. In this case, this will own the mutex //! after the assignment (and upgr will not), but the mutex's upgradable lock //! count will be decremented by one. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - upgradable_lock &operator=(detail::moved_object > upgr) - { - if(this->owns()) - this->unlock(); - m_locked = upgr.get().owns(); - mp_mutex = upgr.get().release(); - return *this; - } - #else - upgradable_lock &operator=(upgradable_lock &&upgr) + upgradable_lock &operator=(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr) { if(this->owns()) this->unlock(); @@ -247,7 +203,6 @@ class upgradable_lock mp_mutex = upgr.release(); return *this; } - #endif //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() //! exception. Calls lock_upgradable() on the referenced mutex. @@ -336,19 +291,11 @@ class upgradable_lock //!Effects: Swaps state with moved lock. //!Throws: Nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object > other) - { - std::swap(mp_mutex, other.get().mp_mutex); - std::swap(m_locked, other.get().m_locked); - } - #else - void swap(upgradable_lock &&other) + void swap(upgradable_lock &other) { std::swap(mp_mutex, other.mp_mutex); std::swap(m_locked, other.m_locked); } - #endif /// @cond private: @@ -357,16 +304,6 @@ class upgradable_lock /// @endcond }; -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -/// @endcond - } // namespace interprocess } // namespace boost diff --git a/include/boost/interprocess/windows_shared_memory.hpp b/include/boost/interprocess/windows_shared_memory.hpp index cd82e01..8b86710 100644 --- a/include/boost/interprocess/windows_shared_memory.hpp +++ b/include/boost/interprocess/windows_shared_memory.hpp @@ -15,7 +15,7 @@ #include #include -#if !defined(BOOST_WINDOWS) || defined(BOOST_DISABLE_WIN32) +#if !defined(BOOST_INTERPROCESS_WINDOWS) #error "This header can only be used in Windows operating systems" #endif @@ -51,11 +51,12 @@ class windows_shared_memory { /// @cond //Non-copyable and non-assignable - windows_shared_memory(const windows_shared_memory &); - windows_shared_memory &operator=(const windows_shared_memory &); + windows_shared_memory(windows_shared_memory &); + windows_shared_memory &operator=(windows_shared_memory &); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(windows_shared_memory) //!Default constructor. //!Represents an empty windows_shared_memory. @@ -81,26 +82,15 @@ class windows_shared_memory //!Moves the ownership of "moved"'s shared memory object to *this. //!After the call, "moved" does not represent any shared memory object. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - windows_shared_memory - (detail::moved_object moved) - { this->swap(moved.get()); } - #else - windows_shared_memory(windows_shared_memory &&moved) + windows_shared_memory(BOOST_INTERPROCESS_RV_REF(windows_shared_memory) moved) { this->swap(moved); } - #endif //!Moves the ownership of "moved"'s shared memory to *this. //!After the call, "moved" does not represent any shared memory. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - windows_shared_memory &operator= - (detail::moved_object moved) - #else - windows_shared_memory &operator=(windows_shared_memory &&moved) - #endif + windows_shared_memory &operator=(BOOST_INTERPROCESS_RV_REF(windows_shared_memory) moved) { - windows_shared_memory tmp(detail::move_impl(moved)); + windows_shared_memory tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -232,14 +222,6 @@ inline void windows_shared_memory::priv_close() } } -//!Trait class to detect if a type is -//!movable -template<> -struct is_movable -{ - static const bool value = true; -}; - ///@endcond } //namespace interprocess {