diff options
Diffstat (limited to 'boost/container/detail')
40 files changed, 5641 insertions, 2018 deletions
diff --git a/boost/container/detail/adaptive_node_pool.hpp b/boost/container/detail/adaptive_node_pool.hpp new file mode 100644 index 0000000000..4e7375412b --- /dev/null +++ b/boost/container/detail/adaptive_node_pool.hpp @@ -0,0 +1,162 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_ADAPTIVE_NODE_POOL_HPP +#define BOOST_CONTAINER_DETAIL_ADAPTIVE_NODE_POOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> + +#include <boost/intrusive/set.hpp> +#include <boost/aligned_storage.hpp> +#include <boost/container/detail/alloc_lib_auto_link.hpp> +#include <boost/container/detail/multiallocation_chain.hpp> +#include <boost/container/detail/pool_common_alloc.hpp> +#include <boost/container/detail/mutex.hpp> +#include <boost/container/detail/adaptive_node_pool_impl.hpp> +#include <boost/container/detail/multiallocation_chain.hpp> +#include <cstddef> +#include <cmath> +#include <cassert> + + +namespace boost { +namespace container { +namespace container_detail { + +template<bool AlignOnly> +struct select_private_adaptive_node_pool_impl +{ + typedef boost::container::container_detail:: + private_adaptive_node_pool_impl + < fake_segment_manager + , unsigned(AlignOnly)*::boost::container::adaptive_pool_flag::align_only + | ::boost::container::adaptive_pool_flag::size_ordered | ::boost::container::adaptive_pool_flag::address_ordered + > type; +}; + +//!Pooled memory allocator using an smart adaptive pool. Includes +//!a reference count but the class does not delete itself, this is +//!responsibility of user classes. Node size (NodeSize) and the number of +//!nodes allocated per block (NodesPerBlock) are known at compile time. +template< std::size_t NodeSize + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks + , std::size_t OverheadPercent + > +class private_adaptive_node_pool + : public select_private_adaptive_node_pool_impl<(OverheadPercent == 0)>::type +{ + typedef typename select_private_adaptive_node_pool_impl<OverheadPercent == 0>::type base_t; + //Non-copyable + private_adaptive_node_pool(const private_adaptive_node_pool &); + private_adaptive_node_pool &operator=(const private_adaptive_node_pool &); + + public: + typedef typename base_t::multiallocation_chain multiallocation_chain; + static const std::size_t nodes_per_block = NodesPerBlock; + + //!Constructor. Never throws + private_adaptive_node_pool() + : base_t(0 + , NodeSize + , NodesPerBlock + , MaxFreeBlocks + , (unsigned char)OverheadPercent) + {} +}; + +//!Pooled memory allocator using adaptive pool. Includes +//!a reference count but the class does not delete itself, this is +//!responsibility of user classes. Node size (NodeSize) and the number of +//!nodes allocated per block (NodesPerBlock) are known at compile time +template< std::size_t NodeSize + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks + , std::size_t OverheadPercent + > +class shared_adaptive_node_pool + : public private_adaptive_node_pool + <NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent> +{ + private: + typedef private_adaptive_node_pool + <NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent> private_node_allocator_t; + public: + typedef typename private_node_allocator_t::multiallocation_chain multiallocation_chain; + + //!Constructor. Never throws + shared_adaptive_node_pool() + : private_node_allocator_t(){} + + //!Destructor. Deallocates all allocated blocks. Never throws + ~shared_adaptive_node_pool() + {} + + //!Allocates array of count elements. Can throw std::bad_alloc + void *allocate_node() + { + //----------------------- + scoped_lock<default_mutex> guard(mutex_); + //----------------------- + return private_node_allocator_t::allocate_node(); + } + + //!Deallocates an array pointed by ptr. Never throws + void deallocate_node(void *ptr) + { + //----------------------- + scoped_lock<default_mutex> guard(mutex_); + //----------------------- + private_node_allocator_t::deallocate_node(ptr); + } + + //!Allocates a singly linked list of n nodes ending in null pointer. + //!can throw std::bad_alloc + void allocate_nodes(const std::size_t n, multiallocation_chain &chain) + { + //----------------------- + scoped_lock<default_mutex> guard(mutex_); + //----------------------- + return private_node_allocator_t::allocate_nodes(n, chain); + } + + void deallocate_nodes(multiallocation_chain &chain) + { + //----------------------- + scoped_lock<default_mutex> guard(mutex_); + //----------------------- + private_node_allocator_t::deallocate_nodes(chain); + } + + //!Deallocates all the free blocks of memory. Never throws + void deallocate_free_blocks() + { + //----------------------- + scoped_lock<default_mutex> guard(mutex_); + //----------------------- + private_node_allocator_t::deallocate_free_blocks(); + } + + private: + default_mutex mutex_; +}; + +} //namespace container_detail { +} //namespace container { +} //namespace boost { + +#include <boost/container/detail/config_end.hpp> + +#endif //#ifndef BOOST_CONTAINER_DETAIL_ADAPTIVE_NODE_POOL_HPP diff --git a/boost/container/detail/adaptive_node_pool_impl.hpp b/boost/container/detail/adaptive_node_pool_impl.hpp index afba6b5f1b..dc1a7f102e 100644 --- a/boost/container/detail/adaptive_node_pool_impl.hpp +++ b/boost/container/detail/adaptive_node_pool_impl.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,26 +11,40 @@ #ifndef BOOST_CONTAINER_DETAIL_ADAPTIVE_NODE_POOL_IMPL_HPP #define BOOST_CONTAINER_DETAIL_ADAPTIVE_NODE_POOL_IMPL_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" -#include <boost/container/container_fwd.hpp> +#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> + +#include <boost/container/container_fwd.hpp> #include <boost/container/detail/utilities.hpp> #include <boost/intrusive/pointer_traits.hpp> #include <boost/intrusive/set.hpp> +#include <boost/intrusive/list.hpp> #include <boost/intrusive/slist.hpp> #include <boost/container/detail/type_traits.hpp> #include <boost/container/detail/math_functions.hpp> #include <boost/container/detail/mpl.hpp> #include <boost/container/detail/pool_common.hpp> +#include <boost/container/throw_exception.hpp> #include <boost/assert.hpp> +#include <boost/core/no_exceptions_support.hpp> #include <cstddef> namespace boost { namespace container { + +namespace adaptive_pool_flag { + +static const unsigned int none = 0u; +static const unsigned int align_only = 1u << 0u; +static const unsigned int size_ordered = 1u << 1u; +static const unsigned int address_ordered = 1u << 2u; + +} //namespace adaptive_pool_flag{ + namespace container_detail { template<class size_type> @@ -42,42 +56,160 @@ struct hdr_offset_holder_t size_type hdr_offset; }; +template<class SizeType, unsigned int Flags> +struct less_func; + +template<class SizeType> +struct less_func<SizeType, adaptive_pool_flag::none> +{ + static bool less(SizeType, SizeType, const void *, const void *) + { return true; } +}; + +template<class SizeType> +struct less_func<SizeType, adaptive_pool_flag::size_ordered> +{ + static bool less(SizeType ls, SizeType rs, const void *, const void *) + { return ls < rs; } +}; + +template<class SizeType> +struct less_func<SizeType, adaptive_pool_flag::address_ordered> +{ + static bool less(SizeType, SizeType, const void *la, const void *ra) + { return &la < &ra; } +}; + +template<class SizeType> +struct less_func<SizeType, adaptive_pool_flag::size_ordered | adaptive_pool_flag::address_ordered> +{ + static bool less(SizeType ls, SizeType rs, const void *la, const void *ra) + { return (ls < rs) || ((ls == rs) && (la < ra)); } +}; + +template<class VoidPointer, class SizeType, bool ordered> +struct block_container_traits +{ + typedef typename bi::make_set_base_hook + < bi::void_pointer<VoidPointer> + , bi::optimize_size<true> + , bi::link_mode<bi::normal_link> >::type hook_t; + + template<class T> + struct container + { + typedef typename bi::make_multiset + <T, bi::base_hook<hook_t>, bi::size_type<SizeType> >::type type; + }; + + template<class Container> + static void reinsert_was_used(Container &container, typename Container::reference v, bool) + { + typedef typename Container::const_iterator const_block_iterator; + const const_block_iterator this_block + (Container::s_iterator_to(const_cast<typename Container::const_reference>(v))); + const_block_iterator next_block(this_block); + if(++next_block != container.cend()){ + if(this_block->free_nodes.size() > next_block->free_nodes.size()){ + container.erase(this_block); + container.insert(v); + } + } + } + + template<class Container> + static void insert_was_empty(Container &container, typename Container::value_type &v, bool) + { + container.insert(v); + } + + template<class Container> + static void erase_first(Container &container) + { + container.erase(container.cbegin()); + } + + template<class Container> + static void erase_last(Container &container) + { + container.erase(--container.cend()); + } +}; + template<class VoidPointer, class SizeType> +struct block_container_traits<VoidPointer, SizeType, false> +{ + typedef typename bi::make_list_base_hook + < bi::void_pointer<VoidPointer> + , bi::link_mode<bi::normal_link> >::type hook_t; + + template<class T> + struct container + { + typedef typename bi::make_list + <T, bi::base_hook<hook_t>, bi::size_type<SizeType>, bi::constant_time_size<false> >::type type; + }; + + template<class Container> + static void reinsert_was_used(Container &container, typename Container::value_type &v, bool is_full) + { + if(is_full){ + container.erase(Container::s_iterator_to(v)); + container.push_back(v); + } + } + + template<class Container> + static void insert_was_empty(Container &container, typename Container::value_type &v, bool is_full) + { + if(is_full){ + container.push_back(v); + } + else{ + container.push_front(v); + } + } + + template<class Container> + static void erase_first(Container &container) + { + container.pop_front(); + } + + template<class Container> + static void erase_last(Container &container) + { + container.pop_back(); + } +}; + +template<class MultiallocationChain, class VoidPointer, class SizeType, unsigned int Flags> struct adaptive_pool_types { typedef VoidPointer void_pointer; - typedef typename bi::make_set_base_hook - < bi::void_pointer<void_pointer> - , bi::optimize_size<true> - , bi::constant_time_size<false> - , bi::link_mode<bi::normal_link> >::type multiset_hook_t; - + static const bool ordered = (Flags & (adaptive_pool_flag::size_ordered | adaptive_pool_flag::address_ordered)) != 0; + typedef block_container_traits<VoidPointer, SizeType, ordered> block_container_traits_t; + typedef typename block_container_traits_t::hook_t hook_t; typedef hdr_offset_holder_t<SizeType> hdr_offset_holder; + static const unsigned int order_flags = Flags & (adaptive_pool_flag::size_ordered | adaptive_pool_flag::address_ordered); + typedef MultiallocationChain free_nodes_t; struct block_info_t - : - public hdr_offset_holder, - public multiset_hook_t + : public hdr_offset_holder, + public hook_t { - typedef typename node_slist<void_pointer>::node_slist_t free_nodes_t; //An intrusive list of free node from this block free_nodes_t free_nodes; friend bool operator <(const block_info_t &l, const block_info_t &r) { -// { return l.free_nodes.size() < r.free_nodes.size(); } - //Let's order blocks first by free nodes and then by address - //so that highest address fully free blocks are deallocated. - //This improves returning memory to the OS (trimming). - const bool is_less = l.free_nodes.size() < r.free_nodes.size(); - const bool is_equal = l.free_nodes.size() == r.free_nodes.size(); - return is_less || (is_equal && (&l < &r)); + return less_func<SizeType, order_flags>:: + less(l.free_nodes.size(), r.free_nodes.size(), &l , &r); } friend bool operator ==(const block_info_t &l, const block_info_t &r) { return &l == &r; } }; - typedef typename bi::make_multiset - <block_info_t, bi::base_hook<multiset_hook_t> >::type block_multiset_t; + typedef typename block_container_traits_t:: template container<block_info_t>::type block_container_t; }; template<class size_type> @@ -113,9 +245,9 @@ inline void calculate_num_subblocks , size_type &num_subblocks, size_type &real_num_node, size_type overhead_percent , size_type hdr_size, size_type hdr_offset_size, size_type payload_per_allocation) { + const size_type hdr_subblock_elements = (alignment - hdr_size - payload_per_allocation)/real_node_size; size_type elements_per_subblock = (alignment - hdr_offset_size)/real_node_size; size_type possible_num_subblock = (elements_per_block - 1)/elements_per_subblock + 1; - size_type hdr_subblock_elements = (alignment - hdr_size - payload_per_allocation)/real_node_size; while(((possible_num_subblock-1)*elements_per_subblock + hdr_subblock_elements) < elements_per_block){ ++possible_num_subblock; } @@ -135,7 +267,7 @@ inline void calculate_num_subblocks real_num_node = (possible_num_subblock-1)*elements_per_subblock + hdr_subblock_elements; } -template<class SegmentManagerBase, bool AlignOnly = false> +template<class SegmentManagerBase, unsigned int Flags> class private_adaptive_node_pool_impl { //Non-copyable @@ -147,27 +279,42 @@ class private_adaptive_node_pool_impl typedef typename SegmentManagerBase::void_pointer void_pointer; static const typename SegmentManagerBase:: size_type PayloadPerAllocation = SegmentManagerBase::PayloadPerAllocation; + //Flags + //align_only + static const bool AlignOnly = (Flags & adaptive_pool_flag::align_only) != 0; typedef bool_<AlignOnly> IsAlignOnly; typedef true_ AlignOnlyTrue; typedef false_ AlignOnlyFalse; + //size_ordered + static const bool SizeOrdered = (Flags & adaptive_pool_flag::size_ordered) != 0; + typedef bool_<SizeOrdered> IsSizeOrdered; + typedef true_ SizeOrderedTrue; + typedef false_ SizeOrderedFalse; + //address_ordered + static const bool AddressOrdered = (Flags & adaptive_pool_flag::address_ordered) != 0; + typedef bool_<AddressOrdered> IsAddressOrdered; + typedef true_ AddressOrderedTrue; + typedef false_ AddressOrderedFalse; public: - typedef typename node_slist<void_pointer>::node_t node_t; - typedef typename node_slist<void_pointer>::node_slist_t free_nodes_t; - typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain; - typedef typename SegmentManagerBase::size_type size_type; + typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain; + typedef typename SegmentManagerBase::size_type size_type; private: - typedef typename adaptive_pool_types<void_pointer, size_type>::block_info_t block_info_t; - typedef typename adaptive_pool_types<void_pointer, size_type>::block_multiset_t block_multiset_t; - typedef typename block_multiset_t::iterator block_iterator; - typedef typename adaptive_pool_types<void_pointer, size_type>::hdr_offset_holder hdr_offset_holder; - - static const size_type MaxAlign = alignment_of<node_t>::value; + typedef adaptive_pool_types + <multiallocation_chain, void_pointer, size_type, Flags> adaptive_pool_types_t; + typedef typename adaptive_pool_types_t::free_nodes_t free_nodes_t; + typedef typename adaptive_pool_types_t::block_info_t block_info_t; + typedef typename adaptive_pool_types_t::block_container_t block_container_t; + typedef typename adaptive_pool_types_t::block_container_traits_t block_container_traits_t; + typedef typename block_container_t::iterator block_iterator; + typedef typename block_container_t::const_iterator const_block_iterator; + typedef typename adaptive_pool_types_t::hdr_offset_holder hdr_offset_holder; + + static const size_type MaxAlign = alignment_of<void_pointer>::value; static const size_type HdrSize = ((sizeof(block_info_t)-1)/MaxAlign+1)*MaxAlign; static const size_type HdrOffsetSize = ((sizeof(hdr_offset_holder)-1)/MaxAlign+1)*MaxAlign; - public: //!Segment manager typedef typedef SegmentManagerBase segment_manager_base_type; @@ -181,7 +328,7 @@ class private_adaptive_node_pool_impl , unsigned char overhead_percent ) : m_max_free_blocks(max_free_blocks) - , m_real_node_size(lcm(node_size, size_type(alignment_of<node_t>::value))) + , m_real_node_size(lcm(node_size, size_type(alignment_of<void_pointer>::value))) //Round the size to a power of two value. //This is the total memory size (including payload) that we want to //allocate from the general-purpose allocator @@ -195,7 +342,7 @@ class private_adaptive_node_pool_impl , m_real_num_node(AlignOnly ? (m_real_block_alignment - PayloadPerAllocation - HdrSize)/m_real_node_size : 0) //General purpose allocator , mp_segment_mngr_base(segment_mngr_base) - , m_block_multiset() + , m_block_container() , m_totally_free_blocks(0) { if(!AlignOnly){ @@ -214,7 +361,7 @@ class private_adaptive_node_pool_impl //!Destructor. Deallocates all allocated blocks. Never throws ~private_adaptive_node_pool_impl() - { priv_clear(); } + { this->priv_clear(); } size_type get_real_num_node() const { return m_real_num_node; } @@ -226,84 +373,157 @@ class private_adaptive_node_pool_impl //!Allocates array of count elements. Can throw void *allocate_node() { - priv_invariants(); + this->priv_invariants(); //If there are no free nodes we allocate a new block - if (m_block_multiset.empty()){ - priv_alloc_block(1); + if(!m_block_container.empty()){ + //We take the first free node the multiset can't be empty + free_nodes_t &free_nodes = m_block_container.begin()->free_nodes; + BOOST_ASSERT(!free_nodes.empty()); + const size_type free_nodes_count = free_nodes.size(); + void *first_node = container_detail::to_raw_pointer(free_nodes.pop_front()); + if(free_nodes.empty()){ + block_container_traits_t::erase_first(m_block_container); + } + m_totally_free_blocks -= static_cast<size_type>(free_nodes_count == m_real_num_node); + this->priv_invariants(); + return first_node; + } + else{ + multiallocation_chain chain; + this->priv_append_from_new_blocks(1, chain, IsAlignOnly()); + return container_detail::to_raw_pointer(chain.pop_front()); } - //We take the first free node the multiset can't be empty - return priv_take_first_node(); } //!Deallocates an array pointed by ptr. Never throws void deallocate_node(void *pElem) { - multiallocation_chain chain; - chain.push_front(void_pointer(pElem)); - this->priv_reinsert_nodes_in_block(chain, 1); - //Update free block count< - if(m_totally_free_blocks > m_max_free_blocks){ - this->priv_deallocate_free_blocks(m_max_free_blocks); - } - priv_invariants(); + this->priv_invariants(); + block_info_t &block_info = *this->priv_block_from_node(pElem); + BOOST_ASSERT(block_info.free_nodes.size() < m_real_num_node); + + //We put the node at the beginning of the free node list + block_info.free_nodes.push_back(void_pointer(pElem)); + + //The loop reinserts all blocks except the last one + this->priv_reinsert_block(block_info, block_info.free_nodes.size() == 1); + this->priv_deallocate_free_blocks(m_max_free_blocks); + this->priv_invariants(); } //!Allocates n nodes. //!Can throw - multiallocation_chain allocate_nodes(const size_type n) + void allocate_nodes(const size_type n, multiallocation_chain &chain) { - multiallocation_chain chain; size_type i = 0; - try{ - priv_invariants(); + BOOST_TRY{ + this->priv_invariants(); while(i != n){ //If there are no free nodes we allocate all needed blocks - if (m_block_multiset.empty()){ - priv_alloc_block(((n - i) - 1)/m_real_num_node + 1); + if (m_block_container.empty()){ + this->priv_append_from_new_blocks(n - i, chain, IsAlignOnly()); + BOOST_ASSERT(m_block_container.empty() || (++m_block_container.cbegin() == m_block_container.cend())); + BOOST_ASSERT(chain.size() == n); + break; } - free_nodes_t &free_nodes = m_block_multiset.begin()->free_nodes; + free_nodes_t &free_nodes = m_block_container.begin()->free_nodes; const size_type free_nodes_count_before = free_nodes.size(); - if(free_nodes_count_before == m_real_num_node){ - --m_totally_free_blocks; - } - const size_type num_elems = ((n-i) < free_nodes_count_before) ? (n-i) : free_nodes_count_before; - for(size_type j = 0; j != num_elems; ++j){ - void *new_node = &free_nodes.front(); - free_nodes.pop_front(); - chain.push_back(new_node); + m_totally_free_blocks -= static_cast<size_type>(free_nodes_count_before == m_real_num_node); + const size_type num_left = n-i; + const size_type num_elems = (num_left < free_nodes_count_before) ? num_left : free_nodes_count_before; + typedef typename free_nodes_t::iterator free_nodes_iterator; + + if(num_left < free_nodes_count_before){ + const free_nodes_iterator it_bbeg(free_nodes.before_begin()); + free_nodes_iterator it_bend(it_bbeg); + for(size_type j = 0; j != num_elems; ++j){ + ++it_bend; + } + free_nodes_iterator it_end = it_bend; ++it_end; + free_nodes_iterator it_beg = it_bbeg; ++it_beg; + free_nodes.erase_after(it_bbeg, it_end, num_elems); + chain.incorporate_after(chain.last(), &*it_beg, &*it_bend, num_elems); + //chain.splice_after(chain.last(), free_nodes, it_bbeg, it_bend, num_elems); + BOOST_ASSERT(!free_nodes.empty()); } - - if(free_nodes.empty()){ - m_block_multiset.erase(m_block_multiset.begin()); + else{ + const free_nodes_iterator it_beg(free_nodes.begin()), it_bend(free_nodes.last()); + free_nodes.clear(); + chain.incorporate_after(chain.last(), &*it_beg, &*it_bend, num_elems); + block_container_traits_t::erase_first(m_block_container); } i += num_elems; } } - catch(...){ - this->deallocate_nodes(boost::move(chain)); - throw; + BOOST_CATCH(...){ + this->deallocate_nodes(chain); + BOOST_RETHROW } - priv_invariants(); - return boost::move(chain); + BOOST_CATCH_END + this->priv_invariants(); } //!Deallocates a linked list of nodes. Never throws - void deallocate_nodes(multiallocation_chain nodes) + void deallocate_nodes(multiallocation_chain &nodes) { - this->priv_reinsert_nodes_in_block(nodes, nodes.size()); - if(m_totally_free_blocks > m_max_free_blocks){ + this->priv_invariants(); + //To take advantage of node locality, wait until two + //nodes belong to different blocks. Only then reinsert + //the block of the first node in the block tree. + //Cache of the previous block + block_info_t *prev_block_info = 0; + + //If block was empty before this call, it's not already + //inserted in the block tree. + bool prev_block_was_empty = false; + typedef typename free_nodes_t::iterator free_nodes_iterator; + { + const free_nodes_iterator itbb(nodes.before_begin()), ite(nodes.end()); + free_nodes_iterator itf(nodes.begin()), itbf(itbb); + size_type splice_node_count = size_type(-1); + while(itf != ite){ + void *pElem = container_detail::to_raw_pointer(container_detail::iterator_to_pointer(itf)); + block_info_t &block_info = *this->priv_block_from_node(pElem); + BOOST_ASSERT(block_info.free_nodes.size() < m_real_num_node); + ++splice_node_count; + + //If block change is detected calculate the cached block position in the tree + if(&block_info != prev_block_info){ + if(prev_block_info){ //Make sure we skip the initial "dummy" cache + free_nodes_iterator it(itbb); ++it; + nodes.erase_after(itbb, itf, splice_node_count); + prev_block_info->free_nodes.incorporate_after(prev_block_info->free_nodes.last(), &*it, &*itbf, splice_node_count); + this->priv_reinsert_block(*prev_block_info, prev_block_was_empty); + splice_node_count = 0; + } + //Update cache with new data + prev_block_was_empty = block_info.free_nodes.empty(); + prev_block_info = &block_info; + } + itbf = itf; + ++itf; + } + } + if(prev_block_info){ + //The loop reinserts all blocks except the last one + const free_nodes_iterator itfirst(nodes.begin()), itlast(nodes.last()); + const size_type splice_node_count = nodes.size(); + nodes.clear(); + prev_block_info->free_nodes.incorporate_after(prev_block_info->free_nodes.last(), &*itfirst, &*itlast, splice_node_count); + this->priv_reinsert_block(*prev_block_info, prev_block_was_empty); + this->priv_invariants(); this->priv_deallocate_free_blocks(m_max_free_blocks); } } void deallocate_free_blocks() - { this->priv_deallocate_free_blocks(0); } + { this->priv_deallocate_free_blocks(0); } size_type num_free_nodes() { - typedef typename block_multiset_t::const_iterator citerator; + typedef typename block_container_t::const_iterator citerator; size_type count = 0; - citerator it (m_block_multiset.begin()), itend(m_block_multiset.end()); + citerator it (m_block_container.begin()), itend(m_block_container.end()); for(; it != itend; ++it){ count += it->free_nodes.size(); } @@ -318,7 +538,7 @@ class private_adaptive_node_pool_impl BOOST_ASSERT(m_real_num_node == other.m_real_num_node); std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base); std::swap(m_totally_free_blocks, other.m_totally_free_blocks); - m_block_multiset.swap(other.m_block_multiset); + m_block_container.swap(other.m_block_container); } //Deprecated, use deallocate_free_blocks @@ -326,84 +546,54 @@ class private_adaptive_node_pool_impl { this->priv_deallocate_free_blocks(0); } private: + void priv_deallocate_free_blocks(size_type max_free_blocks) + { //Trampoline function to ease inlining + if(m_totally_free_blocks > max_free_blocks){ + this->priv_deallocate_free_blocks_impl(max_free_blocks); + } + } + + void priv_deallocate_free_blocks_impl(size_type max_free_blocks) { - priv_invariants(); + this->priv_invariants(); //Now check if we've reached the free nodes limit //and check if we have free blocks. If so, deallocate as much //as we can to stay below the limit - for( block_iterator itend = m_block_multiset.end() - ; m_totally_free_blocks > max_free_blocks - ; --m_totally_free_blocks - ){ - BOOST_ASSERT(!m_block_multiset.empty()); - block_iterator it = itend; + multiallocation_chain chain; + { + const const_block_iterator itend = m_block_container.cend(); + const_block_iterator it = itend; --it; - BOOST_ASSERT(it->free_nodes.size() == m_real_num_node); - m_block_multiset.erase_and_dispose(it, block_destroyer(this)); - } - } - - void priv_reinsert_nodes_in_block(multiallocation_chain &chain, size_type n) - { - block_iterator block_it(m_block_multiset.end()); - while(n--){ - void *pElem = container_detail::to_raw_pointer(chain.front()); - chain.pop_front(); - priv_invariants(); - block_info_t *block_info = this->priv_block_from_node(pElem); - BOOST_ASSERT(block_info->free_nodes.size() < m_real_num_node); - //We put the node at the beginning of the free node list - node_t * to_deallocate = static_cast<node_t*>(pElem); - block_info->free_nodes.push_front(*to_deallocate); - - block_iterator this_block(block_multiset_t::s_iterator_to(*block_info)); - block_iterator next_block(this_block); - ++next_block; - - //Cache the free nodes from the block - size_type this_block_free_nodes = this_block->free_nodes.size(); - - if(this_block_free_nodes == 1){ - m_block_multiset.insert(m_block_multiset.begin(), *block_info); + size_type totally_free_blocks = m_totally_free_blocks; + + for( ; totally_free_blocks > max_free_blocks; --totally_free_blocks){ + BOOST_ASSERT(it->free_nodes.size() == m_real_num_node); + void *addr = priv_first_subblock_from_block(const_cast<block_info_t*>(&*it)); + --it; + block_container_traits_t::erase_last(m_block_container); + chain.push_front(void_pointer(addr)); } - else{ - block_iterator next_block(this_block); - ++next_block; - if(next_block != block_it){ - size_type next_free_nodes = next_block->free_nodes.size(); - if(this_block_free_nodes > next_free_nodes){ - //Now move the block to the new position - m_block_multiset.erase(this_block); - m_block_multiset.insert(*block_info); - } - } - } - //Update free block count - if(this_block_free_nodes == m_real_num_node){ - ++m_totally_free_blocks; - } - priv_invariants(); + BOOST_ASSERT((m_totally_free_blocks - max_free_blocks) == chain.size()); + m_totally_free_blocks = max_free_blocks; } + this->mp_segment_mngr_base->deallocate_many(chain); } - node_t *priv_take_first_node() + void priv_reinsert_block(block_info_t &prev_block_info, const bool prev_block_was_empty) { - BOOST_ASSERT(m_block_multiset.begin() != m_block_multiset.end()); - //We take the first free node the multiset can't be empty - free_nodes_t &free_nodes = m_block_multiset.begin()->free_nodes; - node_t *first_node = &free_nodes.front(); - const size_type free_nodes_count = free_nodes.size(); - BOOST_ASSERT(0 != free_nodes_count); - free_nodes.pop_front(); - if(free_nodes_count == 1){ - m_block_multiset.erase(m_block_multiset.begin()); + //Cache the free nodes from the block + const size_type this_block_free_nodes = prev_block_info.free_nodes.size(); + const bool is_full = this_block_free_nodes == m_real_num_node; + + //Update free block count + m_totally_free_blocks += static_cast<size_type>(is_full); + if(prev_block_was_empty){ + block_container_traits_t::insert_was_empty(m_block_container, prev_block_info, is_full); } - else if(free_nodes_count == m_real_num_node){ - --m_totally_free_blocks; + else{ + block_container_traits_t::reinsert_was_used(m_block_container, prev_block_info, is_full); } - priv_invariants(); - return first_node; } class block_destroyer; @@ -412,33 +602,31 @@ class private_adaptive_node_pool_impl class block_destroyer { public: - block_destroyer(const this_type *impl) - : mp_impl(impl) + block_destroyer(const this_type *impl, multiallocation_chain &chain) + : mp_impl(impl), m_chain(chain) {} - void operator()(typename block_multiset_t::pointer to_deallocate) + void operator()(typename block_container_t::pointer to_deallocate) { return this->do_destroy(to_deallocate, IsAlignOnly()); } private: - void do_destroy(typename block_multiset_t::pointer to_deallocate, AlignOnlyTrue) + void do_destroy(typename block_container_t::pointer to_deallocate, AlignOnlyTrue) { - size_type free_nodes = to_deallocate->free_nodes.size(); - (void)free_nodes; - BOOST_ASSERT(free_nodes == mp_impl->m_real_num_node); - mp_impl->mp_segment_mngr_base->deallocate(to_deallocate); + BOOST_ASSERT(to_deallocate->free_nodes.size() == mp_impl->m_real_num_node); + m_chain.push_back(to_deallocate); } - void do_destroy(typename block_multiset_t::pointer to_deallocate, AlignOnlyFalse) + void do_destroy(typename block_container_t::pointer to_deallocate, AlignOnlyFalse) { - size_type free_nodes = to_deallocate->free_nodes.size(); - (void)free_nodes; - BOOST_ASSERT(free_nodes == mp_impl->m_real_num_node); + BOOST_ASSERT(to_deallocate->free_nodes.size() == mp_impl->m_real_num_node); BOOST_ASSERT(0 == to_deallocate->hdr_offset); - hdr_offset_holder *hdr_off_holder = mp_impl->priv_first_subblock_from_block(container_detail::to_raw_pointer(to_deallocate)); - mp_impl->mp_segment_mngr_base->deallocate(hdr_off_holder); + hdr_offset_holder *hdr_off_holder = + mp_impl->priv_first_subblock_from_block(container_detail::to_raw_pointer(to_deallocate)); + m_chain.push_back(hdr_off_holder); } const this_type *mp_impl; + multiallocation_chain &m_chain; }; //This macro will activate invariant checking. Slow, but helpful for debugging the code. @@ -447,44 +635,45 @@ class private_adaptive_node_pool_impl #ifdef BOOST_CONTAINER_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS #undef BOOST_CONTAINER_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS { - //We iterate through the block tree to free the memory - block_iterator it(m_block_multiset.begin()), - itend(m_block_multiset.end()), to_deallocate; - if(it != itend){ - for(++it; it != itend; ++it){ - block_iterator prev(it); - --prev; - size_type sp = prev->free_nodes.size(), - si = it->free_nodes.size(); - BOOST_ASSERT(sp <= si); - (void)sp; (void)si; + const const_block_iterator itend(m_block_container.end()); + + { //We iterate through the block tree to free the memory + const_block_iterator it(m_block_container.begin()); + + if(it != itend){ + for(++it; it != itend; ++it){ + const_block_iterator prev(it); + --prev; + BOOST_ASSERT(*prev < *it); + (void)prev; (void)it; + } } } - //Check that the total free nodes are correct - it = m_block_multiset.begin(); - itend = m_block_multiset.end(); - size_type total_free_nodes = 0; - for(; it != itend; ++it){ - total_free_nodes += it->free_nodes.size(); + { //Check that the total free nodes are correct + const_block_iterator it(m_block_container.cbegin()); + size_type total_free_nodes = 0; + for(; it != itend; ++it){ + total_free_nodes += it->free_nodes.size(); + } + BOOST_ASSERT(total_free_nodes >= m_totally_free_blocks*m_real_num_node); } - BOOST_ASSERT(total_free_nodes >= m_totally_free_blocks*m_real_num_node); - - //Check that the total totally free blocks are correct - it = m_block_multiset.begin(); - itend = m_block_multiset.end(); - total_free = 0; - for(; it != itend; ++it){ - total_free += it->free_nodes.size() == m_real_num_node; + { //Check that the total totally free blocks are correct + BOOST_ASSERT(m_block_container.size() >= m_totally_free_blocks); + const_block_iterator it = m_block_container.cend(); + size_type total_free_blocks = m_totally_free_blocks; + while(total_free_blocks--){ + BOOST_ASSERT((--it)->free_nodes.size() == m_real_num_node); + } } - BOOST_ASSERT(total_free >= m_totally_free_blocks); if(!AlignOnly){ //Check that header offsets are correct - it = m_block_multiset.begin(); + const_block_iterator it = m_block_container.begin(); for(; it != itend; ++it){ - hdr_offset_holder *hdr_off_holder = priv_first_subblock_from_block(&*it); + hdr_offset_holder *hdr_off_holder = this->priv_first_subblock_from_block(const_cast<block_info_t *>(&*it)); for(size_type i = 0, max = m_num_subblocks; i < max; ++i){ - BOOST_ASSERT(hdr_off_holder->hdr_offset == size_type(reinterpret_cast<char*>(&*it)- reinterpret_cast<char*>(hdr_off_holder))); + const size_type offset = reinterpret_cast<char*>(const_cast<block_info_t *>(&*it)) - reinterpret_cast<char*>(hdr_off_holder); + BOOST_ASSERT(hdr_off_holder->hdr_offset == offset); BOOST_ASSERT(0 == ((size_type)hdr_off_holder & (m_real_block_alignment - 1))); BOOST_ASSERT(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1))); hdr_off_holder = reinterpret_cast<hdr_offset_holder *>(reinterpret_cast<char*>(hdr_off_holder) + m_real_block_alignment); @@ -500,19 +689,21 @@ class private_adaptive_node_pool_impl void priv_clear() { #ifndef NDEBUG - block_iterator it = m_block_multiset.begin(); - block_iterator itend = m_block_multiset.end(); - size_type num_free_nodes = 0; + block_iterator it = m_block_container.begin(); + block_iterator itend = m_block_container.end(); + size_type n_free_nodes = 0; for(; it != itend; ++it){ //Check for memory leak BOOST_ASSERT(it->free_nodes.size() == m_real_num_node); - ++num_free_nodes; + ++n_free_nodes; } - BOOST_ASSERT(num_free_nodes == m_totally_free_blocks); + BOOST_ASSERT(n_free_nodes == m_totally_free_blocks); #endif //Check for memory leaks - priv_invariants(); - m_block_multiset.clear_and_dispose(block_destroyer(this)); + this->priv_invariants(); + multiallocation_chain chain; + m_block_container.clear_and_dispose(block_destroyer(this, chain)); + this->mp_segment_mngr_base->deallocate_many(chain); m_totally_free_blocks = 0; } @@ -534,93 +725,129 @@ class private_adaptive_node_pool_impl } block_info_t *priv_block_from_node(void *node) const - { return priv_block_from_node(node, IsAlignOnly()); } + { return this->priv_block_from_node(node, IsAlignOnly()); } hdr_offset_holder *priv_first_subblock_from_block(block_info_t *block) const + { return this->priv_first_subblock_from_block(block, IsAlignOnly()); } + + hdr_offset_holder *priv_first_subblock_from_block(block_info_t *block, AlignOnlyFalse) const { - hdr_offset_holder *hdr_off_holder = reinterpret_cast<hdr_offset_holder*> + hdr_offset_holder *const hdr_off_holder = reinterpret_cast<hdr_offset_holder*> (reinterpret_cast<char*>(block) - (m_num_subblocks-1)*m_real_block_alignment); BOOST_ASSERT(hdr_off_holder->hdr_offset == size_type(reinterpret_cast<char*>(block) - reinterpret_cast<char*>(hdr_off_holder))); - BOOST_ASSERT(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1))); + BOOST_ASSERT(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1))); BOOST_ASSERT(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1))); return hdr_off_holder; } + hdr_offset_holder *priv_first_subblock_from_block(block_info_t *block, AlignOnlyTrue) const + { + return reinterpret_cast<hdr_offset_holder*>(block); + } + + void priv_dispatch_block_chain_or_free + ( multiallocation_chain &chain, block_info_t &c_info, size_type num_node + , char *mem_address, size_type total_elements, bool insert_block_if_free) + { + BOOST_ASSERT(chain.size() <= total_elements); + //First add all possible nodes to the chain + const size_type left = total_elements - chain.size(); + const size_type max_chain = (num_node < left) ? num_node : left; + mem_address = static_cast<char *>(container_detail::to_raw_pointer + (chain.incorporate_after(chain.last(), void_pointer(mem_address), m_real_node_size, max_chain))); + //Now store remaining nodes in the free list + if(const size_type max_free = num_node - max_chain){ + free_nodes_t & free_nodes = c_info.free_nodes; + free_nodes.incorporate_after(free_nodes.last(), void_pointer(mem_address), m_real_node_size, max_free); + if(insert_block_if_free){ + m_block_container.push_front(c_info); + } + } + } + //!Allocates a several blocks of nodes. Can throw - void priv_alloc_block(size_type n, AlignOnlyTrue) + void priv_append_from_new_blocks(size_type min_elements, multiallocation_chain &chain, AlignOnlyTrue) { - size_type real_block_size = m_real_block_alignment - PayloadPerAllocation; + BOOST_ASSERT(m_block_container.empty()); + BOOST_ASSERT(min_elements > 0); + const size_type n = (min_elements - 1)/m_real_num_node + 1; + const size_type real_block_size = m_real_block_alignment - PayloadPerAllocation; + const size_type total_elements = chain.size() + min_elements; for(size_type i = 0; i != n; ++i){ //We allocate a new NodeBlock and put it the last //element of the tree char *mem_address = static_cast<char*> (mp_segment_mngr_base->allocate_aligned(real_block_size, m_real_block_alignment)); - if(!mem_address) throw std::bad_alloc(); - ++m_totally_free_blocks; - block_info_t *c_info = new(mem_address)block_info_t(); - m_block_multiset.insert(m_block_multiset.end(), *c_info); - + if(!mem_address){ + //In case of error, free memory deallocating all nodes (the new ones allocated + //in this function plus previously stored nodes in chain). + this->deallocate_nodes(chain); + throw_bad_alloc(); + } + block_info_t &c_info = *new(mem_address)block_info_t(); mem_address += HdrSize; - //We initialize all Nodes in Node Block to insert - //them in the free Node list - typename free_nodes_t::iterator prev_insert_pos = c_info->free_nodes.before_begin(); - for(size_type i = 0; i < m_real_num_node; ++i){ - prev_insert_pos = c_info->free_nodes.insert_after(prev_insert_pos, *(node_t*)mem_address); - mem_address += m_real_node_size; + if(i != (n-1)){ + chain.incorporate_after(chain.last(), void_pointer(mem_address), m_real_node_size, m_real_num_node); + } + else{ + this->priv_dispatch_block_chain_or_free(chain, c_info, m_real_num_node, mem_address, total_elements, true); } } } - void priv_alloc_block(size_type n, AlignOnlyFalse) + void priv_append_from_new_blocks(size_type min_elements, multiallocation_chain &chain, AlignOnlyFalse) { - size_type real_block_size = m_real_block_alignment*m_num_subblocks - PayloadPerAllocation; - size_type elements_per_subblock = (m_real_block_alignment - HdrOffsetSize)/m_real_node_size; - size_type hdr_subblock_elements = (m_real_block_alignment - HdrSize - PayloadPerAllocation)/m_real_node_size; + BOOST_ASSERT(m_block_container.empty()); + BOOST_ASSERT(min_elements > 0); + const size_type n = (min_elements - 1)/m_real_num_node + 1; + const size_type real_block_size = m_real_block_alignment*m_num_subblocks - PayloadPerAllocation; + const size_type elements_per_subblock = (m_real_block_alignment - HdrOffsetSize)/m_real_node_size; + const size_type hdr_subblock_elements = (m_real_block_alignment - HdrSize - PayloadPerAllocation)/m_real_node_size; + const size_type total_elements = chain.size() + min_elements; for(size_type i = 0; i != n; ++i){ //We allocate a new NodeBlock and put it the last //element of the tree char *mem_address = static_cast<char*> (mp_segment_mngr_base->allocate_aligned(real_block_size, m_real_block_alignment)); - if(!mem_address) throw std::bad_alloc(); - ++m_totally_free_blocks; - + if(!mem_address){ + //In case of error, free memory deallocating all nodes (the new ones allocated + //in this function plus previously stored nodes in chain). + this->deallocate_nodes(chain); + throw_bad_alloc(); + } //First initialize header information on the last subblock char *hdr_addr = mem_address + m_real_block_alignment*(m_num_subblocks-1); - block_info_t *c_info = new(hdr_addr)block_info_t(); + block_info_t &c_info = *new(hdr_addr)block_info_t(); //Some structural checks - BOOST_ASSERT(static_cast<void*>(&static_cast<hdr_offset_holder*>(c_info)->hdr_offset) == - static_cast<void*>(c_info)); - typename free_nodes_t::iterator prev_insert_pos = c_info->free_nodes.before_begin(); - for( size_type subblock = 0, maxsubblock = m_num_subblocks - 1 - ; subblock < maxsubblock - ; ++subblock, mem_address += m_real_block_alignment){ - //Initialize header offset mark - new(mem_address) hdr_offset_holder(size_type(hdr_addr - mem_address)); - char *pNode = mem_address + HdrOffsetSize; - for(size_type i = 0; i < elements_per_subblock; ++i){ - prev_insert_pos = c_info->free_nodes.insert_after(prev_insert_pos, *new (pNode) node_t); - pNode += m_real_node_size; + BOOST_ASSERT(static_cast<void*>(&static_cast<hdr_offset_holder&>(c_info).hdr_offset) == + static_cast<void*>(&c_info)); (void)c_info; + if(i != (n-1)){ + for( size_type subblock = 0, maxsubblock = m_num_subblocks - 1 + ; subblock < maxsubblock + ; ++subblock, mem_address += m_real_block_alignment){ + //Initialize header offset mark + new(mem_address) hdr_offset_holder(size_type(hdr_addr - mem_address)); + chain.incorporate_after + (chain.last(), void_pointer(mem_address + HdrOffsetSize), m_real_node_size, elements_per_subblock); } + chain.incorporate_after(chain.last(), void_pointer(hdr_addr + HdrSize), m_real_node_size, hdr_subblock_elements); } - { - char *pNode = hdr_addr + HdrSize; - //We initialize all Nodes in Node Block to insert - //them in the free Node list - for(size_type i = 0; i < hdr_subblock_elements; ++i){ - prev_insert_pos = c_info->free_nodes.insert_after(prev_insert_pos, *new (pNode) node_t); - pNode += m_real_node_size; + else{ + for( size_type subblock = 0, maxsubblock = m_num_subblocks - 1 + ; subblock < maxsubblock + ; ++subblock, mem_address += m_real_block_alignment){ + //Initialize header offset mark + new(mem_address) hdr_offset_holder(size_type(hdr_addr - mem_address)); + this->priv_dispatch_block_chain_or_free + (chain, c_info, elements_per_subblock, mem_address + HdrOffsetSize, total_elements, false); } + this->priv_dispatch_block_chain_or_free + (chain, c_info, hdr_subblock_elements, hdr_addr + HdrSize, total_elements, true); } - //Insert the block after the free node list is full - m_block_multiset.insert(m_block_multiset.end(), *c_info); } } - //!Allocates a block of nodes. Can throw std::bad_alloc - void priv_alloc_block(size_type n) - { return priv_alloc_block(n, IsAlignOnly()); } - private: typedef typename boost::intrusive::pointer_traits <void_pointer>::template rebind_pointer<segment_manager_base_type>::type segment_mngr_base_ptr_t; @@ -634,9 +861,9 @@ class private_adaptive_node_pool_impl //This is the real number of nodes per block //const size_type m_real_num_node; - segment_mngr_base_ptr_t mp_segment_mngr_base; //Segment manager - block_multiset_t m_block_multiset; //Intrusive block list - size_type m_totally_free_blocks; //Free blocks + segment_mngr_base_ptr_t mp_segment_mngr_base; //Segment manager + block_container_t m_block_container; //Intrusive block list + size_type m_totally_free_blocks; //Free blocks }; } //namespace container_detail { diff --git a/boost/container/detail/advanced_insert_int.hpp b/boost/container/detail/advanced_insert_int.hpp index a97af282e0..a35279dcf7 100644 --- a/boost/container/detail/advanced_insert_int.hpp +++ b/boost/container/detail/advanced_insert_int.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,170 +11,198 @@ #ifndef BOOST_CONTAINER_ADVANCED_INSERT_INT_HPP #define BOOST_CONTAINER_ADVANCED_INSERT_INT_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" +#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> + #include <boost/container/allocator_traits.hpp> #include <boost/container/detail/destroyers.hpp> #include <boost/aligned_storage.hpp> -#include <boost/move/move.hpp> +#include <boost/move/utility_core.hpp> +#include <boost/container/detail/mpl.hpp> +#include <boost/container/detail/utilities.hpp> +#include <boost/container/detail/type_traits.hpp> +#include <boost/container/detail/iterators.hpp> #include <iterator> //std::iterator_traits #include <boost/assert.hpp> +#include <boost/core/no_exceptions_support.hpp> namespace boost { namespace container { namespace container_detail { -//This class will be interface for operations dependent on FwdIt types used advanced_insert_aux_impl -template<class Iterator> -struct advanced_insert_aux_int +template<class A, class FwdIt, class Iterator> +struct move_insert_range_proxy { - typedef typename std::iterator_traits<Iterator>::difference_type difference_type; - virtual void copy_remaining_to(Iterator p) = 0; - virtual void uninitialized_copy_remaining_to(Iterator p) = 0; - virtual void uninitialized_copy_some_and_update(Iterator pos, difference_type division_count, bool first) = 0; - virtual void copy_some_and_update(Iterator pos, difference_type division_count, bool first) = 0; - virtual ~advanced_insert_aux_int() {} + typedef typename allocator_traits<A>::size_type size_type; + typedef typename allocator_traits<A>::value_type value_type; + + explicit move_insert_range_proxy(FwdIt first) + : first_(first) + {} + + void uninitialized_copy_n_and_update(A &a, Iterator p, size_type n) + { + this->first_ = ::boost::container::uninitialized_move_alloc_n_source + (a, this->first_, n, p); + } + + void copy_n_and_update(A &, Iterator p, size_type n) + { + this->first_ = ::boost::container::move_n_source(this->first_, n, p); + } + + FwdIt first_; }; -//This class template will adapt each FwIt types to advanced_insert_aux_int + template<class A, class FwdIt, class Iterator> -struct advanced_insert_aux_proxy - : public advanced_insert_aux_int<Iterator> +struct insert_range_proxy { typedef typename allocator_traits<A>::size_type size_type; typedef typename allocator_traits<A>::value_type value_type; - typedef typename advanced_insert_aux_int<Iterator>::difference_type difference_type; - - advanced_insert_aux_proxy(A& a, FwdIt first, FwdIt last) - : a_(a), first_(first), last_(last) - {} - virtual ~advanced_insert_aux_proxy() + explicit insert_range_proxy(FwdIt first) + : first_(first) {} - virtual void copy_remaining_to(Iterator p) - { ::boost::copy_or_move(this->first_, this->last_, p); } - - virtual void uninitialized_copy_remaining_to(Iterator p) - { ::boost::container::uninitialized_copy_or_move_alloc(this->a_, this->first_, this->last_, p); } + void uninitialized_copy_n_and_update(A &a, Iterator p, size_type n) + { + this->first_ = ::boost::container::uninitialized_copy_alloc_n_source(a, this->first_, n, p); + } - virtual void uninitialized_copy_some_and_update(Iterator pos, difference_type division_count, bool first_n) + void copy_n_and_update(A &, Iterator p, size_type n) { - FwdIt mid = this->first_; - std::advance(mid, division_count); - if(first_n){ - ::boost::container::uninitialized_copy_or_move_alloc(this->a_, this->first_, mid, pos); - this->first_ = mid; - } - else{ - ::boost::container::uninitialized_copy_or_move_alloc(this->a_, mid, this->last_, pos); - this->last_ = mid; - } + this->first_ = ::boost::container::copy_n_source(this->first_, n, p); } - virtual void copy_some_and_update(Iterator pos, difference_type division_count, bool first_n) + FwdIt first_; +}; + + +template<class A, class Iterator> +struct insert_n_copies_proxy +{ + typedef typename allocator_traits<A>::size_type size_type; + typedef typename allocator_traits<A>::value_type value_type; + + explicit insert_n_copies_proxy(const value_type &v) + : v_(v) + {} + + void uninitialized_copy_n_and_update(A &a, Iterator p, size_type n) const + { boost::container::uninitialized_fill_alloc_n(a, v_, n, p); } + + void copy_n_and_update(A &, Iterator p, size_type n) const { - FwdIt mid = this->first_; - std::advance(mid, division_count); - if(first_n){ - ::boost::copy_or_move(this->first_, mid, pos); - this->first_ = mid; - } - else{ - ::boost::copy_or_move(mid, this->last_, pos); - this->last_ = mid; + for (; 0 < n; --n, ++p){ + *p = v_; } } - A &a_; - FwdIt first_, last_; + + const value_type &v_; }; -//This class template will adapt default construction insertions to advanced_insert_aux_int template<class A, class Iterator> -struct default_construct_aux_proxy - : public advanced_insert_aux_int<Iterator> +struct insert_value_initialized_n_proxy { typedef ::boost::container::allocator_traits<A> alloc_traits; typedef typename allocator_traits<A>::size_type size_type; typedef typename allocator_traits<A>::value_type value_type; - typedef typename advanced_insert_aux_int<Iterator>::difference_type difference_type; - default_construct_aux_proxy(A &a, size_type count) - : a_(a), count_(count) - {} + void uninitialized_copy_n_and_update(A &a, Iterator p, size_type n) const + { boost::container::uninitialized_value_init_alloc_n(a, n, p); } + + void copy_n_and_update(A &, Iterator, size_type) const + { BOOST_ASSERT(false); } +}; - virtual ~default_construct_aux_proxy() +template<class A, class Iterator> +struct insert_default_initialized_n_proxy +{ + typedef ::boost::container::allocator_traits<A> alloc_traits; + typedef typename allocator_traits<A>::size_type size_type; + typedef typename allocator_traits<A>::value_type value_type; + + void uninitialized_copy_n_and_update(A &a, Iterator p, size_type n) const + { boost::container::uninitialized_default_init_alloc_n(a, n, p); } + + void copy_n_and_update(A &, Iterator, size_type) const + { BOOST_ASSERT(false); } +}; + +template<class A, class Iterator> +struct insert_copy_proxy +{ + typedef boost::container::allocator_traits<A> alloc_traits; + typedef typename alloc_traits::size_type size_type; + typedef typename alloc_traits::value_type value_type; + + explicit insert_copy_proxy(const value_type &v) + : v_(v) {} - virtual void copy_remaining_to(Iterator) - { //This should never be called with any count - BOOST_ASSERT(this->count_ == 0); + void uninitialized_copy_n_and_update(A &a, Iterator p, size_type n) const + { + BOOST_ASSERT(n == 1); (void)n; + alloc_traits::construct( a, iterator_to_raw_pointer(p), v_); } - virtual void uninitialized_copy_remaining_to(Iterator p) - { this->priv_uninitialized_copy(p, this->count_); } - - virtual void uninitialized_copy_some_and_update(Iterator pos, difference_type division_count, bool first_n) + void copy_n_and_update(A &, Iterator p, size_type n) const { - size_type new_count; - if(first_n){ - new_count = division_count; - } - else{ - BOOST_ASSERT(difference_type(this->count_)>= division_count); - new_count = this->count_ - division_count; - } - this->priv_uninitialized_copy(pos, new_count); + BOOST_ASSERT(n == 1); (void)n; + *p =v_; } - virtual void copy_some_and_update(Iterator , difference_type division_count, bool first_n) + const value_type &v_; +}; + + +template<class A, class Iterator> +struct insert_move_proxy +{ + typedef boost::container::allocator_traits<A> alloc_traits; + typedef typename alloc_traits::size_type size_type; + typedef typename alloc_traits::value_type value_type; + + explicit insert_move_proxy(value_type &v) + : v_(v) + {} + + void uninitialized_copy_n_and_update(A &a, Iterator p, size_type n) const { - BOOST_ASSERT(this->count_ == 0); - size_type new_count; - if(first_n){ - new_count = division_count; - } - else{ - BOOST_ASSERT(difference_type(this->count_)>= division_count); - new_count = this->count_ - division_count; - } - //This function should never called with a count different to zero - BOOST_ASSERT(new_count == 0); - (void)new_count; + BOOST_ASSERT(n == 1); (void)n; + alloc_traits::construct( a, iterator_to_raw_pointer(p), ::boost::move(v_) ); } - private: - void priv_uninitialized_copy(Iterator p, const size_type n) + void copy_n_and_update(A &, Iterator p, size_type n) const { - BOOST_ASSERT(n <= this->count_); - Iterator orig_p = p; - size_type i = 0; - try{ - for(; i < n; ++i, ++p){ - alloc_traits::construct(this->a_, container_detail::to_raw_pointer(&*p)); - } - } - catch(...){ - while(i--){ - alloc_traits::destroy(this->a_, container_detail::to_raw_pointer(&*orig_p++)); - } - throw; - } - this->count_ -= n; + BOOST_ASSERT(n == 1); (void)n; + *p = ::boost::move(v_); } - A &a_; - size_type count_; + + value_type &v_; }; +template<class It, class A> +insert_move_proxy<A, It> get_insert_value_proxy(BOOST_RV_REF(typename std::iterator_traits<It>::value_type) v) +{ + return insert_move_proxy<A, It>(v); +} + +template<class It, class A> +insert_copy_proxy<A, It> get_insert_value_proxy(const typename std::iterator_traits<It>::value_type &v) +{ + return insert_copy_proxy<A, It>(v); +} + }}} //namespace boost { namespace container { namespace container_detail { #ifdef BOOST_CONTAINER_PERFECT_FORWARDING #include <boost/container/detail/variadic_templates_tools.hpp> -#include <boost/container/detail/stored_ref.hpp> -#include <boost/move/move.hpp> +#include <boost/move/utility_core.hpp> #include <typeinfo> //#include <iostream> //For debugging purposes @@ -182,143 +210,117 @@ namespace boost { namespace container { namespace container_detail { - -//This class template will adapt emplace construction insertions of movable types -//to advanced_insert_aux_int template<class A, class Iterator, class ...Args> -struct advanced_insert_aux_non_movable_emplace - : public advanced_insert_aux_int<Iterator> +struct insert_non_movable_emplace_proxy { - typedef boost::container::allocator_traits<A> alloc_traits; - typedef typename allocator_traits<A>::size_type size_type; - typedef typename allocator_traits<A>::value_type value_type; - typedef typename advanced_insert_aux_int<Iterator>::difference_type difference_type; - typedef typename build_number_seq<sizeof...(Args)>::type index_tuple_t; + typedef boost::container::allocator_traits<A> alloc_traits; + typedef typename alloc_traits::size_type size_type; + typedef typename alloc_traits::value_type value_type; - explicit advanced_insert_aux_non_movable_emplace(A &a, Args&&... args) - : a_(a) - , args_(args...) - , used_(false) - {} + typedef typename build_number_seq<sizeof...(Args)>::type index_tuple_t; - ~advanced_insert_aux_non_movable_emplace() + explicit insert_non_movable_emplace_proxy(Args&&... args) + : args_(args...) {} - virtual void copy_remaining_to(Iterator) - //This code can't be called since value_type is not movable or copyable - { BOOST_ASSERT(false); } - - virtual void uninitialized_copy_remaining_to(Iterator p) - { this->priv_uninitialized_copy_remaining_to(index_tuple_t(), p); } - - virtual void uninitialized_copy_some_and_update(Iterator p, difference_type division_count, bool first_n) - { this->priv_uninitialized_copy_some_and_update(index_tuple_t(), p, division_count, first_n); } - - virtual void copy_some_and_update(Iterator, difference_type, bool ) - //This code can't be called since value_type is not movable or copyable - { BOOST_ASSERT(false); } + void uninitialized_copy_n_and_update(A &a, Iterator p, size_type n) + { this->priv_uninitialized_copy_some_and_update(a, index_tuple_t(), p, n); } private: template<int ...IdxPack> - void priv_uninitialized_copy_some_and_update(const index_tuple<IdxPack...>&, Iterator p, difference_type division_count, bool first_n) + void priv_uninitialized_copy_some_and_update(A &a, const index_tuple<IdxPack...>&, Iterator p, size_type n) { - BOOST_ASSERT(division_count <=1); - if((first_n && division_count == 1) || (!first_n && division_count == 0)){ - if(!this->used_){ - alloc_traits::construct( this->a_ - , container_detail::to_raw_pointer(&*p) - , ::boost::container::container_detail:: - stored_ref<Args>::forward(get<IdxPack>(this->args_))... - ); - this->used_ = true; - } - } - } - - template<int ...IdxPack> - void priv_uninitialized_copy_remaining_to(const index_tuple<IdxPack...>&, Iterator p) - { - if(!this->used_){ - alloc_traits::construct( this->a_ - , container_detail::to_raw_pointer(&*p) - , ::boost::container::container_detail:: - stored_ref<Args>::forward(get<IdxPack>(this->args_))... - ); - this->used_ = true; - } + BOOST_ASSERT(n == 1); (void)n; + alloc_traits::construct( a, iterator_to_raw_pointer(p), ::boost::forward<Args>(get<IdxPack>(this->args_))... ); } protected: - A &a_; tuple<Args&...> args_; - bool used_; }; -//This class template will adapt emplace construction insertions of movable types -//to advanced_insert_aux_int template<class A, class Iterator, class ...Args> -struct advanced_insert_aux_emplace - : public advanced_insert_aux_non_movable_emplace<A, Iterator, Args...> +struct insert_emplace_proxy + : public insert_non_movable_emplace_proxy<A, Iterator, Args...> { - typedef advanced_insert_aux_non_movable_emplace<A, Iterator, Args...> base_t; - typedef boost::container::allocator_traits<A> alloc_traits; - typedef typename base_t::value_type value_type; - typedef typename base_t::difference_type difference_type; - typedef typename base_t::index_tuple_t index_tuple_t; - - explicit advanced_insert_aux_emplace(A &a, Args&&... args) - : base_t(a, ::boost::forward<Args>(args)...) + typedef insert_non_movable_emplace_proxy<A, Iterator, Args...> base_t; + typedef boost::container::allocator_traits<A> alloc_traits; + typedef typename base_t::value_type value_type; + typedef typename base_t::size_type size_type; + typedef typename base_t::index_tuple_t index_tuple_t; + + explicit insert_emplace_proxy(Args&&... args) + : base_t(::boost::forward<Args>(args)...) {} - ~advanced_insert_aux_emplace() - {} - - //Override only needed functions - virtual void copy_remaining_to(Iterator p) - { this->priv_copy_remaining_to(index_tuple_t(), p); } - - virtual void copy_some_and_update(Iterator p, difference_type division_count, bool first_n) - { this->priv_copy_some_and_update(index_tuple_t(), p, division_count, first_n); } + void copy_n_and_update(A &a, Iterator p, size_type n) + { this->priv_copy_some_and_update(a, index_tuple_t(), p, n); } private: + template<int ...IdxPack> - void priv_copy_remaining_to(const index_tuple<IdxPack...>&, Iterator p) + void priv_copy_some_and_update(A &a, const index_tuple<IdxPack...>&, Iterator p, size_type n) { - if(!this->used_){ - aligned_storage<sizeof(value_type), alignment_of<value_type>::value> v; - value_type *vp = static_cast<value_type *>(static_cast<void *>(&v)); - alloc_traits::construct(this->a_, vp, - ::boost::container::container_detail::stored_ref<Args>::forward(get<IdxPack>(this->args_))...); - scoped_destructor<A> d(this->a_, vp); + BOOST_ASSERT(n ==1); (void)n; + aligned_storage<sizeof(value_type), alignment_of<value_type>::value> v; + value_type *vp = static_cast<value_type *>(static_cast<void *>(&v)); + alloc_traits::construct(a, vp, + ::boost::forward<Args>(get<IdxPack>(this->args_))...); + BOOST_TRY{ *p = ::boost::move(*vp); - d.release(); - this->used_ = true; } - } - - template<int ...IdxPack> - void priv_copy_some_and_update(const index_tuple<IdxPack...>&, Iterator p, difference_type division_count, bool first_n) - { - BOOST_ASSERT(division_count <=1); - if((first_n && division_count == 1) || (!first_n && division_count == 0)){ - if(!this->used_){ - aligned_storage<sizeof(value_type), alignment_of<value_type>::value> v; - value_type *vp = static_cast<value_type *>(static_cast<void *>(&v)); - alloc_traits::construct(this->a_, vp, - ::boost::container::container_detail::stored_ref<Args>::forward(get<IdxPack>(this->args_))...); - try { - *p = ::boost::move(*vp); - } catch (...) { - alloc_traits::destroy(this->a_, vp); - throw; - } - alloc_traits::destroy(this->a_, vp); - this->used_ = true; - } + BOOST_CATCH(...){ + alloc_traits::destroy(a, vp); + BOOST_RETHROW } + BOOST_CATCH_END + alloc_traits::destroy(a, vp); } }; +//Specializations to avoid an unneeded temporary when emplacing from a single argument o type value_type +template<class A, class Iterator> +struct insert_emplace_proxy<A, Iterator, typename boost::container::allocator_traits<A>::value_type> + : public insert_move_proxy<A, Iterator> +{ + explicit insert_emplace_proxy(typename boost::container::allocator_traits<A>::value_type &&v) + : insert_move_proxy<A, Iterator>(v) + {} +}; + +//We use "add_const" here as adding "const" only confuses MSVC12(and maybe later) provoking +//compiler error C2752 (“more than one partial specialization matches”). +//Any problem is solvable with an extra layer of indirection? ;-) +template<class A, class Iterator> +struct insert_emplace_proxy<A, Iterator + , typename boost::container::container_detail::add_const<typename boost::container::allocator_traits<A>::value_type>::type + > + : public insert_copy_proxy<A, Iterator> +{ + explicit insert_emplace_proxy(const typename boost::container::allocator_traits<A>::value_type &v) + : insert_copy_proxy<A, Iterator>(v) + {} +}; + +template<class A, class Iterator> +struct insert_emplace_proxy<A, Iterator, typename boost::container::allocator_traits<A>::value_type &> + : public insert_copy_proxy<A, Iterator> +{ + explicit insert_emplace_proxy(const typename boost::container::allocator_traits<A>::value_type &v) + : insert_copy_proxy<A, Iterator>(v) + {} +}; + +template<class A, class Iterator> +struct insert_emplace_proxy<A, Iterator + , typename boost::container::container_detail::add_const<typename boost::container::allocator_traits<A>::value_type>::type & + > + : public insert_copy_proxy<A, Iterator> +{ + explicit insert_emplace_proxy(const typename boost::container::allocator_traits<A>::value_type &v) + : insert_copy_proxy<A, Iterator>(v) + {} +}; + }}} //namespace boost { namespace container { namespace container_detail { #else //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING @@ -330,118 +332,142 @@ namespace boost { namespace container { namespace container_detail { -#define BOOST_PP_LOCAL_MACRO(n) \ -template<class A, class Iterator BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) > \ -struct BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_non_movable_emplace, n), arg) \ - : public advanced_insert_aux_int<Iterator> \ +#define BOOST_PP_LOCAL_MACRO(N) \ +template<class A, class Iterator BOOST_PP_ENUM_TRAILING_PARAMS(N, class P) > \ +struct BOOST_PP_CAT(insert_non_movable_emplace_proxy_arg, N) \ { \ typedef boost::container::allocator_traits<A> alloc_traits; \ - typedef typename allocator_traits<A>::size_type size_type; \ - typedef typename allocator_traits<A>::value_type value_type; \ - typedef typename advanced_insert_aux_int<Iterator>::difference_type \ - difference_type; \ + typedef typename alloc_traits::size_type size_type; \ + typedef typename alloc_traits::value_type value_type; \ \ - BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_non_movable_emplace, n), arg) \ - ( A &a BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _) ) \ - : a_(a) \ - , used_(false) \ - BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_INIT, _) \ - {} \ + explicit BOOST_PP_CAT(insert_non_movable_emplace_proxy_arg, N) \ + ( BOOST_PP_ENUM(N, BOOST_CONTAINER_PP_PARAM_LIST, _) ) \ + BOOST_PP_EXPR_IF(N, :) BOOST_PP_ENUM(N, BOOST_CONTAINER_PP_PARAM_INIT, _) \ + {} \ \ - virtual void copy_remaining_to(Iterator) \ - { BOOST_ASSERT(false); } \ - \ - virtual void uninitialized_copy_remaining_to(Iterator p) \ + void uninitialized_copy_n_and_update(A &a, Iterator p, size_type n) \ { \ - if(!this->used_){ \ - alloc_traits::construct \ - ( this->a_ \ - , container_detail::to_raw_pointer(&*p) \ - BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_MEMBER_FORWARD, _) \ - ); \ - this->used_ = true; \ - } \ + BOOST_ASSERT(n == 1); (void)n; \ + alloc_traits::construct \ + ( a, iterator_to_raw_pointer(p) \ + BOOST_PP_ENUM_TRAILING(N, BOOST_CONTAINER_PP_MEMBER_FORWARD, _) \ + ); \ } \ \ - virtual void uninitialized_copy_some_and_update \ - (Iterator p, difference_type division_count, bool first_n) \ - { \ - BOOST_ASSERT(division_count <=1); \ - if((first_n && division_count == 1) || (!first_n && division_count == 0)){ \ - if(!this->used_){ \ - alloc_traits::construct \ - ( this->a_ \ - , container_detail::to_raw_pointer(&*p) \ - BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_MEMBER_FORWARD, _) \ - ); \ - this->used_ = true; \ - } \ - } \ - } \ - \ - virtual void copy_some_and_update(Iterator, difference_type, bool) \ + void copy_n_and_update(A &, Iterator, size_type) \ { BOOST_ASSERT(false); } \ \ - A &a_; \ - bool used_; \ - BOOST_PP_REPEAT(n, BOOST_CONTAINER_PP_PARAM_DEFINE, _) \ + protected: \ + BOOST_PP_REPEAT(N, BOOST_CONTAINER_PP_PARAM_DEFINE, _) \ }; \ \ -template<class A, class Iterator BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) > \ -struct BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ - : BOOST_PP_CAT(BOOST_PP_CAT( \ - advanced_insert_aux_non_movable_emplace, n), arg) \ - < A, Iterator BOOST_PP_ENUM_TRAILING_PARAMS(n, P) > \ +template<class A, class Iterator BOOST_PP_ENUM_TRAILING_PARAMS(N, class P) > \ +struct BOOST_PP_CAT(insert_emplace_proxy_arg, N) \ + : BOOST_PP_CAT(insert_non_movable_emplace_proxy_arg, N) \ + < A, Iterator BOOST_PP_ENUM_TRAILING_PARAMS(N, P) > \ { \ - typedef BOOST_PP_CAT(BOOST_PP_CAT( \ - advanced_insert_aux_non_movable_emplace, n), arg) \ - <A, Iterator BOOST_PP_ENUM_TRAILING_PARAMS(n, P) > base_t; \ + typedef BOOST_PP_CAT(insert_non_movable_emplace_proxy_arg, N) \ + <A, Iterator BOOST_PP_ENUM_TRAILING_PARAMS(N, P) > base_t; \ typedef typename base_t::value_type value_type; \ - typedef typename base_t::difference_type difference_type; \ + typedef typename base_t::size_type size_type; \ typedef boost::container::allocator_traits<A> alloc_traits; \ \ - BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ - ( A &a BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _) ) \ - : base_t(a BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ) \ - {} \ + explicit BOOST_PP_CAT(insert_emplace_proxy_arg, N) \ + ( BOOST_PP_ENUM(N, BOOST_CONTAINER_PP_PARAM_LIST, _) ) \ + : base_t(BOOST_PP_ENUM(N, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ) \ + {} \ \ - virtual void copy_remaining_to(Iterator p) \ + void copy_n_and_update(A &a, Iterator p, size_type n) \ { \ - if(!this->used_){ \ - aligned_storage<sizeof(value_type), alignment_of<value_type>::value> v; \ - value_type *vp = static_cast<value_type *>(static_cast<void *>(&v)); \ - alloc_traits::construct(this->a_, vp \ - BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_MEMBER_FORWARD, _)); \ - scoped_destructor<A> d(this->a_, vp); \ - *p = ::boost::move(*vp); \ - d.release(); \ - this->used_ = true; \ + BOOST_ASSERT(n == 1); (void)n; \ + aligned_storage<sizeof(value_type), alignment_of<value_type>::value> v; \ + value_type *vp = static_cast<value_type *>(static_cast<void *>(&v)); \ + alloc_traits::construct(a, vp \ + BOOST_PP_ENUM_TRAILING(N, BOOST_CONTAINER_PP_MEMBER_FORWARD, _)); \ + BOOST_TRY{ \ + *p = ::boost::move(*vp); \ } \ - } \ - \ - virtual void copy_some_and_update \ - (Iterator p, difference_type division_count, bool first_n) \ - { \ - BOOST_ASSERT(division_count <=1); \ - if((first_n && division_count == 1) || (!first_n && division_count == 0)){ \ - if(!this->used_){ \ - aligned_storage<sizeof(value_type), alignment_of<value_type>::value> v; \ - value_type *vp = static_cast<value_type *>(static_cast<void *>(&v)); \ - alloc_traits::construct(this->a_, vp \ - BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_MEMBER_FORWARD, _)); \ - scoped_destructor<A> d(this->a_, vp); \ - *p = ::boost::move(*vp); \ - d.release(); \ - this->used_ = true; \ - } \ + BOOST_CATCH(...){ \ + alloc_traits::destroy(a, vp); \ + BOOST_RETHROW \ } \ + BOOST_CATCH_END \ + alloc_traits::destroy(a, vp); \ } \ }; \ //! - #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + +//Specializations to avoid an unneeded temporary when emplacing from a single argument o type value_type +template<class A, class Iterator> +struct insert_emplace_proxy_arg1<A, Iterator, ::boost::rv<typename boost::container::allocator_traits<A>::value_type> > + : public insert_move_proxy<A, Iterator> +{ + explicit insert_emplace_proxy_arg1(typename boost::container::allocator_traits<A>::value_type &v) + : insert_move_proxy<A, Iterator>(v) + {} +}; + +template<class A, class Iterator> +struct insert_emplace_proxy_arg1<A, Iterator, typename boost::container::allocator_traits<A>::value_type> + : public insert_copy_proxy<A, Iterator> +{ + explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits<A>::value_type &v) + : insert_copy_proxy<A, Iterator>(v) + {} +}; + +#else //e.g. MSVC10 & MSVC11 + +//Specializations to avoid an unneeded temporary when emplacing from a single argument o type value_type +template<class A, class Iterator> +struct insert_emplace_proxy_arg1<A, Iterator, typename boost::container::allocator_traits<A>::value_type> + : public insert_move_proxy<A, Iterator> +{ + explicit insert_emplace_proxy_arg1(typename boost::container::allocator_traits<A>::value_type &&v) + : insert_move_proxy<A, Iterator>(v) + {} +}; + +//We use "add_const" here as adding "const" only confuses MSVC10&11 provoking +//compiler error C2752 (“more than one partial specialization matches”). +//Any problem is solvable with an extra layer of indirection? ;-) +template<class A, class Iterator> +struct insert_emplace_proxy_arg1<A, Iterator + , typename boost::container::container_detail::add_const<typename boost::container::allocator_traits<A>::value_type>::type + > + : public insert_copy_proxy<A, Iterator> +{ + explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits<A>::value_type &v) + : insert_copy_proxy<A, Iterator>(v) + {} +}; + +template<class A, class Iterator> +struct insert_emplace_proxy_arg1<A, Iterator, typename boost::container::allocator_traits<A>::value_type &> + : public insert_copy_proxy<A, Iterator> +{ + explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits<A>::value_type &v) + : insert_copy_proxy<A, Iterator>(v) + {} +}; + +template<class A, class Iterator> +struct insert_emplace_proxy_arg1<A, Iterator + , typename boost::container::container_detail::add_const<typename boost::container::allocator_traits<A>::value_type>::type & + > + : public insert_copy_proxy<A, Iterator> +{ + explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits<A>::value_type &v) + : insert_copy_proxy<A, Iterator>(v) + {} +}; + +#endif + }}} //namespace boost { namespace container { namespace container_detail { #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING diff --git a/boost/container/detail/algorithms.hpp b/boost/container/detail/algorithms.hpp index dc09575b24..af15f65737 100644 --- a/boost/container/detail/algorithms.hpp +++ b/boost/container/detail/algorithms.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. +// (C) Copyright Ion Gaztanaga 2005-2013. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -13,38 +13,40 @@ #ifndef BOOST_CONTAINER_DETAIL_ALGORITHMS_HPP #define BOOST_CONTAINER_DETAIL_ALGORITHMS_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" +#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> - -#include <boost/type_traits/has_trivial_copy.hpp> -#include <boost/type_traits/has_trivial_assign.hpp> -#include <boost/detail/no_exceptions_support.hpp> - -#include <boost/container/detail/type_traits.hpp> -#include <boost/container/detail/mpl.hpp> +#include <boost/container/allocator_traits.hpp> #include <boost/container/detail/iterators.hpp> - -#include <cstring> - namespace boost { namespace container { template<class A, class T, class InpIt> inline void construct_in_place(A &a, T* dest, InpIt source) { boost::container::allocator_traits<A>::construct(a, dest, *source); } -//#endif template<class A, class T, class U, class D> -inline void construct_in_place(A &a, T *dest, default_construct_iterator<U, D>) +inline void construct_in_place(A &a, T *dest, value_init_construct_iterator<U, D>) { boost::container::allocator_traits<A>::construct(a, dest); } +template <class T, class Difference> +class default_init_construct_iterator; + +template<class A, class T, class U, class D> +inline void construct_in_place(A &a, T *dest, default_init_construct_iterator<U, D>) +{ + boost::container::allocator_traits<A>::construct(a, dest, default_init); +} + +template <class T, class EmplaceFunctor, class Difference> +class emplace_iterator; + template<class A, class T, class U, class EF, class D> inline void construct_in_place(A &a, T *dest, emplace_iterator<U, EF, D> ei) { diff --git a/boost/container/detail/alloc_lib.h b/boost/container/detail/alloc_lib.h new file mode 100644 index 0000000000..4802d9d814 --- /dev/null +++ b/boost/container/detail/alloc_lib.h @@ -0,0 +1,326 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_ALLOC_LIB_EXT_H +#define BOOST_CONTAINER_ALLOC_LIB_EXT_H + +#include <stddef.h> + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable : 4127) + +/* + we need to import/export our code only if the user has specifically + asked for it by defining either BOOST_ALL_DYN_LINK if they want all boost + libraries to be dynamically linked, or BOOST_CONTAINER_DYN_LINK + if they want just this one to be dynamically liked: +*/ +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTAINER_DYN_LINK) + +/* export if this is our own source, otherwise import: */ +#ifdef BOOST_CONTAINER_SOURCE +# define BOOST_CONTAINER_DECL __declspec(dllexport) +#else +# define BOOST_CONTAINER_DECL __declspec(dllimport) +#endif /* BOOST_CONTAINER_SOURCE */ +#endif /* DYN_LINK */ +#endif /* _MSC_VER */ + +/* if BOOST_CONTAINER_DECL isn't defined yet define it now: */ +#ifndef BOOST_CONTAINER_DECL +#define BOOST_CONTAINER_DECL +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*!An forward iterator to traverse the elements of a memory chain container.*/ +typedef struct multialloc_node_impl +{ + struct multialloc_node_impl *next_node_ptr; +} boost_cont_memchain_node; + + +/*!An forward iterator to traverse the elements of a memory chain container.*/ +typedef struct multialloc_it_impl +{ + boost_cont_memchain_node *node_ptr; +} boost_cont_memchain_it; + +/*!Memory chain: A container holding memory portions allocated by boost_cont_multialloc_nodes + and boost_cont_multialloc_arrays functions.*/ +typedef struct boost_cont_memchain_impl +{ + size_t num_mem; + boost_cont_memchain_node root_node; + boost_cont_memchain_node *last_node_ptr; +} boost_cont_memchain; + +/*!Advances the iterator one position so that it points to the next element in the memory chain*/ +#define BOOST_CONTAINER_MEMIT_NEXT(IT) (IT.node_ptr = IT.node_ptr->next_node_ptr) + +/*!Returns the address of the memory chain currently pointed by the iterator*/ +#define BOOST_CONTAINER_MEMIT_ADDR(IT) ((void*)IT.node_ptr) + +/*!Initializer for an iterator pointing to the position before the first element*/ +#define BOOST_CONTAINER_MEMCHAIN_BEFORE_BEGIN_IT(PMEMCHAIN) { &((PMEMCHAIN)->root_node) } + +/*!Initializer for an iterator pointing to the first element*/ +#define BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(PMEMCHAIN) {(PMEMCHAIN)->root_node.next_node_ptr } + +/*!Initializer for an iterator pointing to the last element*/ +#define BOOST_CONTAINER_MEMCHAIN_LAST_IT(PMEMCHAIN) {(PMEMCHAIN)->last_node_ptr } + +/*!Initializer for an iterator pointing to one past the last element (end iterator)*/ +#define BOOST_CONTAINER_MEMCHAIN_END_IT(PMEMCHAIN) {(boost_cont_memchain_node *)0 } + +/*!True if IT is the end iterator, false otherwise*/ +#define BOOST_CONTAINER_MEMCHAIN_IS_END_IT(PMEMCHAIN, IT) (!(IT).node_ptr) + +/*!The address of the first memory portion hold by the memory chain*/ +#define BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(PMEMCHAIN)((void*)((PMEMCHAIN)->root_node.next_node_ptr)) + +/*!The address of the last memory portion hold by the memory chain*/ +#define BOOST_CONTAINER_MEMCHAIN_LASTMEM(PMEMCHAIN) ((void*)((PMEMCHAIN)->last_node_ptr)) + +/*!The number of memory portions hold by the memory chain*/ +#define BOOST_CONTAINER_MEMCHAIN_SIZE(PMEMCHAIN) ((PMEMCHAIN)->num_mem) + +/*!Initializes the memory chain from the first memory portion, the last memory + portion and number of portions obtained from another memory chain*/ +#define BOOST_CONTAINER_MEMCHAIN_INIT_FROM(PMEMCHAIN, FIRST, LAST, NUM)\ + (PMEMCHAIN)->last_node_ptr = (boost_cont_memchain_node *)(LAST), \ + (PMEMCHAIN)->root_node.next_node_ptr = (boost_cont_memchain_node *)(FIRST), \ + (PMEMCHAIN)->num_mem = (NUM);\ +/**/ + +/*!Default initializes a memory chain. Postconditions: begin iterator is end iterator, + the number of portions is zero.*/ +#define BOOST_CONTAINER_MEMCHAIN_INIT(PMEMCHAIN)\ + ((PMEMCHAIN)->root_node.next_node_ptr = 0, (PMEMCHAIN)->last_node_ptr = &((PMEMCHAIN)->root_node), (PMEMCHAIN)->num_mem = 0)\ +/**/ + +/*!True if the memory chain is empty (holds no memory portions*/ +#define BOOST_CONTAINER_MEMCHAIN_EMPTY(PMEMCHAIN)\ + ((PMEMCHAIN)->num_mem == 0)\ +/**/ + +/*!Inserts a new memory portions in the front of the chain*/ +#define BOOST_CONTAINER_MEMCHAIN_PUSH_BACK(PMEMCHAIN, MEM)\ + do{\ + boost_cont_memchain *____chain____ = (PMEMCHAIN);\ + boost_cont_memchain_node *____tmp_mem____ = (boost_cont_memchain_node *)(MEM);\ + ____chain____->last_node_ptr->next_node_ptr = ____tmp_mem____;\ + ____tmp_mem____->next_node_ptr = 0;\ + ____chain____->last_node_ptr = ____tmp_mem____;\ + ++____chain____->num_mem;\ + }while(0)\ +/**/ + +/*!Inserts a new memory portions in the back of the chain*/ +#define BOOST_CONTAINER_MEMCHAIN_PUSH_FRONT(PMEMCHAIN, MEM)\ + do{\ + boost_cont_memchain *____chain____ = (PMEMCHAIN);\ + boost_cont_memchain_node *____tmp_mem____ = (boost_cont_memchain_node *)(MEM);\ + boost_cont_memchain *____root____ = &((PMEMCHAIN)->root_node);\ + if(!____chain____->root_node.next_node_ptr){\ + ____chain____->last_node_ptr = ____tmp_mem____;\ + }\ + boost_cont_memchain_node *____old_first____ = ____root____->next_node_ptr;\ + ____tmp_mem____->next_node_ptr = ____old_first____;\ + ____root____->next_node_ptr = ____tmp_mem____;\ + ++____chain____->num_mem;\ + }while(0)\ +/**/ + +/*!Erases the memory portion after the portion pointed by BEFORE_IT from the memory chain*/ +/*!Precondition: BEFORE_IT must be a valid iterator of the memory chain and it can't be the end iterator*/ +#define BOOST_CONTAINER_MEMCHAIN_ERASE_AFTER(PMEMCHAIN, BEFORE_IT)\ + do{\ + boost_cont_memchain *____chain____ = (PMEMCHAIN);\ + boost_cont_memchain_node *____prev_node____ = (BEFORE_IT).node_ptr;\ + boost_cont_memchain_node *____erase_node____ = ____prev_node____->next_node_ptr;\ + if(____chain____->last_node_ptr == ____erase_node____){\ + ____chain____->last_node_ptr = &____chain____->root_node;\ + }\ + ____prev_node____->next_node_ptr = ____erase_node____->next_node_ptr;\ + --____chain____->num_mem;\ + }while(0)\ +/**/ + +/*!Erases the first portion from the memory chain. + Precondition: the memory chain must not be empty*/ +#define BOOST_CONTAINER_MEMCHAIN_POP_FRONT(PMEMCHAIN)\ + do{\ + boost_cont_memchain *____chain____ = (PMEMCHAIN);\ + boost_cont_memchain_node *____prev_node____ = &____chain____->root_node;\ + boost_cont_memchain_node *____erase_node____ = ____prev_node____->next_node_ptr;\ + if(____chain____->last_node_ptr == ____erase_node____){\ + ____chain____->last_node_ptr = &____chain____->root_node;\ + }\ + ____prev_node____->next_node_ptr = ____erase_node____->next_node_ptr;\ + --____chain____->num_mem;\ + }while(0)\ +/**/ + +/*!Joins two memory chains inserting the portions of the second chain at the back of the first chain*/ +/* +#define BOOST_CONTAINER_MEMCHAIN_SPLICE_BACK(PMEMCHAIN, PMEMCHAIN2)\ + do{\ + boost_cont_memchain *____chain____ = (PMEMCHAIN);\ + boost_cont_memchain *____chain2____ = (PMEMCHAIN2);\ + if(!____chain2____->root_node.next_node_ptr){\ + break;\ + }\ + else if(!____chain____->first_mem){\ + ____chain____->first_mem = ____chain2____->first_mem;\ + ____chain____->last_node_ptr = ____chain2____->last_node_ptr;\ + ____chain____->num_mem = ____chain2____->num_mem;\ + BOOST_CONTAINER_MEMCHAIN_INIT(*____chain2____);\ + }\ + else{\ + ____chain____->last_node_ptr->next_node_ptr = ____chain2____->first_mem;\ + ____chain____->last_node_ptr = ____chain2____->last_node_ptr;\ + ____chain____->num_mem += ____chain2____->num_mem;\ + }\ + }while(0)\*/ +/**/ + +/*!Joins two memory chains inserting the portions of the second chain at the back of the first chain*/ +#define BOOST_CONTAINER_MEMCHAIN_INCORPORATE_AFTER(PMEMCHAIN, BEFORE_IT, FIRST, BEFORELAST, NUM)\ + do{\ + boost_cont_memchain *____chain____ = (PMEMCHAIN);\ + boost_cont_memchain_node *____pnode____ = (BEFORE_IT).node_ptr;\ + boost_cont_memchain_node *____next____ = ____pnode____->next_node_ptr;\ + boost_cont_memchain_node *____first____ = (boost_cont_memchain_node *)(FIRST);\ + boost_cont_memchain_node *____blast____ = (boost_cont_memchain_node *)(BEFORELAST);\ + size_t ____num____ = (NUM);\ + if(!____num____){\ + break;\ + }\ + if(____pnode____ == ____chain____->last_node_ptr){\ + ____chain____->last_node_ptr = ____blast____;\ + }\ + ____pnode____->next_node_ptr = ____first____;\ + ____blast____->next_node_ptr = ____next____;\ + ____chain____->num_mem += ____num____;\ + }while(0)\ +/**/ + +BOOST_CONTAINER_DECL size_t boost_cont_size(const void *p); + +BOOST_CONTAINER_DECL void* boost_cont_malloc(size_t bytes); + +BOOST_CONTAINER_DECL void boost_cont_free(void* mem); + +BOOST_CONTAINER_DECL void* boost_cont_memalign(size_t bytes, size_t alignment); + +/*!Indicates the all elements allocated by boost_cont_multialloc_nodes or boost_cont_multialloc_arrays + must be contiguous.*/ +#define DL_MULTIALLOC_ALL_CONTIGUOUS ((size_t)(-1)) + +/*!Indicates the number of contiguous elements allocated by boost_cont_multialloc_nodes or boost_cont_multialloc_arrays + should be selected by those functions.*/ +#define DL_MULTIALLOC_DEFAULT_CONTIGUOUS ((size_t)(0)) + +BOOST_CONTAINER_DECL int boost_cont_multialloc_nodes + (size_t n_elements, size_t elem_size, size_t contiguous_elements, boost_cont_memchain *pchain); + +BOOST_CONTAINER_DECL int boost_cont_multialloc_arrays + (size_t n_elements, const size_t *sizes, size_t sizeof_element, size_t contiguous_elements, boost_cont_memchain *pchain); + +BOOST_CONTAINER_DECL void boost_cont_multidealloc(boost_cont_memchain *pchain); + +BOOST_CONTAINER_DECL size_t boost_cont_footprint(); + +BOOST_CONTAINER_DECL size_t boost_cont_allocated_memory(); + +BOOST_CONTAINER_DECL size_t boost_cont_chunksize(const void *p); + +BOOST_CONTAINER_DECL int boost_cont_all_deallocated(); + +typedef struct boost_cont_malloc_stats_impl +{ + size_t max_system_bytes; + size_t system_bytes; + size_t in_use_bytes; +} boost_cont_malloc_stats_t; + +BOOST_CONTAINER_DECL boost_cont_malloc_stats_t boost_cont_malloc_stats(); + +BOOST_CONTAINER_DECL size_t boost_cont_in_use_memory(); + +BOOST_CONTAINER_DECL int boost_cont_trim(size_t pad); + +BOOST_CONTAINER_DECL int boost_cont_mallopt + (int parameter_number, int parameter_value); + +BOOST_CONTAINER_DECL int boost_cont_grow + (void* oldmem, size_t minbytes, size_t maxbytes, size_t *received); + +BOOST_CONTAINER_DECL int boost_cont_shrink + (void* oldmem, size_t minbytes, size_t maxbytes, size_t *received, int do_commit); + +BOOST_CONTAINER_DECL void* boost_cont_alloc + (size_t minbytes, size_t preferred_bytes, size_t *received_bytes); + +BOOST_CONTAINER_DECL int boost_cont_malloc_check(); + +typedef unsigned int allocation_type; + +enum +{ + // constants for allocation commands + BOOST_CONTAINER_ALLOCATE_NEW = 0X01, + BOOST_CONTAINER_EXPAND_FWD = 0X02, + BOOST_CONTAINER_EXPAND_BWD = 0X04, + BOOST_CONTAINER_SHRINK_IN_PLACE = 0X08, + BOOST_CONTAINER_NOTHROW_ALLOCATION = 0X10, +// BOOST_CONTAINER_ZERO_MEMORY = 0X20, + BOOST_CONTAINER_TRY_SHRINK_IN_PLACE = 0X40, + BOOST_CONTAINER_EXPAND_BOTH = BOOST_CONTAINER_EXPAND_FWD | BOOST_CONTAINER_EXPAND_BWD, + BOOST_CONTAINER_EXPAND_OR_NEW = BOOST_CONTAINER_ALLOCATE_NEW | BOOST_CONTAINER_EXPAND_BOTH +}; + +//#define BOOST_CONTAINERDLMALLOC__FOOTERS +#ifndef BOOST_CONTAINERDLMALLOC__FOOTERS +enum { BOOST_CONTAINER_ALLOCATION_PAYLOAD = sizeof(size_t) }; +#else +enum { BOOST_CONTAINER_ALLOCATION_PAYLOAD = sizeof(size_t)*2 }; +#endif + +typedef struct boost_cont_command_ret_impl +{ + void *first; + int second; +}boost_cont_command_ret_t; + +BOOST_CONTAINER_DECL boost_cont_command_ret_t boost_cont_allocation_command + ( allocation_type command + , size_t sizeof_object + , size_t limit_objects + , size_t preferred_objects + , size_t *received_objects + , void *reuse_ptr + ); + +BOOST_CONTAINER_DECL int boost_cont_mallopt(int param_number, int value); + +#ifdef __cplusplus +} //extern "C" { +#endif + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + + +#endif //#define BOOST_CONTAINERDLMALLOC__EXT_H diff --git a/boost/container/detail/alloc_lib_auto_link.hpp b/boost/container/detail/alloc_lib_auto_link.hpp new file mode 100644 index 0000000000..e0a01b6086 --- /dev/null +++ b/boost/container/detail/alloc_lib_auto_link.hpp @@ -0,0 +1,20 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_DETAIL_BOOST_CONT_EXT_AUTO_LINK_HPP +#define BOOST_CONTAINER_DETAIL_BOOST_CONT_EXT_AUTO_LINK_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +#include <boost/container/detail/auto_link.hpp> +#include <boost/container/detail/alloc_lib.h> + +#endif //#ifndef BOOST_CONTAINER_DETAIL_BOOST_CONT_EXT_AUTO_LINK_HPP diff --git a/boost/container/detail/allocation_type.hpp b/boost/container/detail/allocation_type.hpp index 1ebf20ed70..65d543ad50 100644 --- a/boost/container/detail/allocation_type.hpp +++ b/boost/container/detail/allocation_type.hpp @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,19 +11,19 @@ #ifndef BOOST_CONTAINER_ALLOCATION_TYPE_HPP #define BOOST_CONTAINER_ALLOCATION_TYPE_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" +#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> namespace boost { namespace container { -/// @cond +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED enum allocation_type_v -{ +{ // constants for allocation commands allocate_new_v = 0x01, expand_fwd_v = 0x02, @@ -37,7 +37,7 @@ enum allocation_type_v }; typedef int allocation_type; -/// @endcond +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED static const allocation_type allocate_new = (allocation_type)allocate_new_v; static const allocation_type expand_fwd = (allocation_type)expand_fwd_v; static const allocation_type expand_bwd = (allocation_type)expand_bwd_v; diff --git a/boost/container/detail/allocator_version_traits.hpp b/boost/container/detail/allocator_version_traits.hpp new file mode 100644 index 0000000000..18bb2ac613 --- /dev/null +++ b/boost/container/detail/allocator_version_traits.hpp @@ -0,0 +1,168 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_ALLOCATOR_VERSION_TRAITS_HPP +#define BOOST_CONTAINER_DETAIL_ALLOCATOR_VERSION_TRAITS_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> + +#include <boost/container/allocator_traits.hpp> //allocator_traits +#include <boost/container/throw_exception.hpp> +#include <boost/container/detail/multiallocation_chain.hpp> //multiallocation_chain +#include <boost/container/detail/version_type.hpp> //version_type +#include <boost/container/detail/allocation_type.hpp> //allocation_type +#include <boost/container/detail/mpl.hpp> //integral_constant +#include <boost/intrusive/pointer_traits.hpp> //pointer_traits +#include <utility> //pair +#include <boost/core/no_exceptions_support.hpp> //BOOST_TRY + +namespace boost { +namespace container { +namespace container_detail { + +template<class Allocator, unsigned Version = boost::container::container_detail::version<Allocator>::value> +struct allocator_version_traits +{ + typedef ::boost::container::container_detail::integral_constant + <unsigned, Version> alloc_version; + + typedef typename Allocator::multiallocation_chain multiallocation_chain; + + typedef typename boost::container::allocator_traits<Allocator>::pointer pointer; + typedef typename boost::container::allocator_traits<Allocator>::size_type size_type; + + //Node allocation interface + static pointer allocate_one(Allocator &a) + { return a.allocate_one(); } + + static void deallocate_one(Allocator &a, const pointer &p) + { a.deallocate_one(p); } + + static void allocate_individual(Allocator &a, size_type n, multiallocation_chain &m) + { return a.allocate_individual(n, m); } + + static void deallocate_individual(Allocator &a, multiallocation_chain &holder) + { a.deallocate_individual(holder); } + + static std::pair<pointer, bool> + allocation_command(Allocator &a, allocation_type command, + size_type limit_size, size_type preferred_size, + size_type &received_size, const pointer &reuse) + { + return a.allocation_command + (command, limit_size, preferred_size, received_size, reuse); + } +}; + +template<class Allocator> +struct allocator_version_traits<Allocator, 1> +{ + typedef ::boost::container::container_detail::integral_constant + <unsigned, 1> alloc_version; + + typedef typename boost::container::allocator_traits<Allocator>::pointer pointer; + typedef typename boost::container::allocator_traits<Allocator>::size_type size_type; + typedef typename boost::container::allocator_traits<Allocator>::value_type value_type; + + typedef typename boost::intrusive::pointer_traits<pointer>:: + template rebind_pointer<void>::type void_ptr; + typedef container_detail::basic_multiallocation_chain + <void_ptr> multialloc_cached_counted; + typedef boost::container::container_detail:: + transform_multiallocation_chain + < multialloc_cached_counted, value_type> multiallocation_chain; + + //Node allocation interface + static pointer allocate_one(Allocator &a) + { return a.allocate(1); } + + static void deallocate_one(Allocator &a, const pointer &p) + { a.deallocate(p, 1); } + + static void deallocate_individual(Allocator &a, multiallocation_chain &holder) + { + size_type n = holder.size(); + typename multiallocation_chain::iterator it = holder.begin(); + while(n--){ + pointer p = boost::intrusive::pointer_traits<pointer>::pointer_to(*it); + ++it; + a.deallocate(p, 1); + } + } + + struct allocate_individual_rollback + { + allocate_individual_rollback(Allocator &a, multiallocation_chain &chain) + : mr_a(a), mp_chain(&chain) + {} + + ~allocate_individual_rollback() + { + if(mp_chain) + allocator_version_traits::deallocate_individual(mr_a, *mp_chain); + } + + void release() + { + mp_chain = 0; + } + + Allocator &mr_a; + multiallocation_chain * mp_chain; + }; + + static void allocate_individual(Allocator &a, size_type n, multiallocation_chain &m) + { + allocate_individual_rollback rollback(a, m); + while(n--){ + m.push_front(a.allocate(1)); + } + rollback.release(); + } + + static std::pair<pointer, bool> + allocation_command(Allocator &a, allocation_type command, + size_type, size_type preferred_size, + size_type &received_size, const pointer &) + { + std::pair<pointer, bool> ret(pointer(), false); + if(!(command & allocate_new)){ + if(!(command & nothrow_allocation)){ + throw_logic_error("version 1 allocator without allocate_new flag"); + } + } + else{ + received_size = preferred_size; + BOOST_TRY{ + ret.first = a.allocate(received_size); + } + BOOST_CATCH(...){ + if(!(command & nothrow_allocation)){ + BOOST_RETHROW + } + } + BOOST_CATCH_END + } + return ret; + } +}; + +} //namespace container_detail { +} //namespace container { +} //namespace boost { + +#include <boost/container/detail/config_end.hpp> + +#endif // ! defined(BOOST_CONTAINER_DETAIL_ALLOCATOR_VERSION_TRAITS_HPP) diff --git a/boost/container/detail/auto_link.hpp b/boost/container/detail/auto_link.hpp new file mode 100644 index 0000000000..2e4733363d --- /dev/null +++ b/boost/container/detail/auto_link.hpp @@ -0,0 +1,38 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_DETAIL_AUTO_LINK_HPP_INCLUDED +#define BOOST_CONTAINER_DETAIL_AUTO_LINK_HPP_INCLUDED + +#if defined(_MSC_VER) +# pragma once +#endif + +// +// Automatically link to the correct build variant where possible. +// +#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_CONTAINER_NO_LIB) && !defined(BOOST_CONTAINER_SOURCE) +// +// Set the name of our library, this will get undef'ed by auto_link.hpp +// once it's done with it: +// +#define BOOST_LIB_NAME boost_container +// +// If we're importing code from a dll, then tell auto_link.hpp about it: +// +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTAINER_DYN_LINK) +# define BOOST_DYN_LINK +#endif +// +// And include the header that does the work: +// +#include <boost/config/auto_link.hpp> +#endif // auto-linking disabled + +#endif //#ifndef BOOST_CONTAINER_DETAIL_AUTO_LINK_HPP_INCLUDED diff --git a/boost/container/detail/config_begin.hpp b/boost/container/detail/config_begin.hpp index 83c2cfe40c..ca9dd59682 100644 --- a/boost/container/detail/config_begin.hpp +++ b/boost/container/detail/config_begin.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -9,15 +9,13 @@ ////////////////////////////////////////////////////////////////////////////// #ifndef BOOST_CONTAINER_CONTAINER_DETAIL_CONFIG_INCLUDED #define BOOST_CONTAINER_CONTAINER_DETAIL_CONFIG_INCLUDED +#ifndef BOOST_CONFIG_HPP #include <boost/config.hpp> +#endif #endif //BOOST_CONTAINER_CONTAINER_DETAIL_CONFIG_INCLUDED #ifdef BOOST_MSVC - #ifndef _CRT_SECURE_NO_DEPRECATE - #define BOOST_CONTAINER_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 @@ -46,4 +44,5 @@ #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 #pragma warning (disable : 4584) // X is already a base-class of Y + #pragma warning (disable : 4510) // default constructor could not be generated #endif //BOOST_MSVC diff --git a/boost/container/detail/config_end.hpp b/boost/container/detail/config_end.hpp index 34513718cc..f93c8f6f79 100644 --- a/boost/container/detail/config_end.hpp +++ b/boost/container/detail/config_end.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -9,9 +9,5 @@ ////////////////////////////////////////////////////////////////////////////// #if defined BOOST_MSVC #pragma warning (pop) - #ifdef BOOST_CONTAINER_DETAIL_CRT_SECURE_NO_DEPRECATE - #undef BOOST_CONTAINER_DETAIL_CRT_SECURE_NO_DEPRECATE - #undef _CRT_SECURE_NO_DEPRECATE - #endif #endif diff --git a/boost/container/detail/destroyers.hpp b/boost/container/detail/destroyers.hpp index d1b118cdcc..ea9b617437 100644 --- a/boost/container/detail/destroyers.hpp +++ b/boost/container/detail/destroyers.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. +// (C) Copyright Ion Gaztanaga 2005-2013. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -13,12 +13,13 @@ #ifndef BOOST_CONTAINER_DESTROYERS_HPP #define BOOST_CONTAINER_DESTROYERS_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" +#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> + #include <boost/container/detail/version_type.hpp> #include <boost/container/detail/utilities.hpp> #include <boost/container/allocator_traits.hpp> @@ -28,6 +29,74 @@ namespace container { namespace container_detail { //!A deleter for scoped_ptr that deallocates the memory +//!allocated for an object using a STL allocator. +template <class A> +struct scoped_deallocator +{ + typedef allocator_traits<A> allocator_traits_type; + typedef typename allocator_traits_type::pointer pointer; + typedef container_detail::integral_constant<unsigned, + boost::container::container_detail:: + version<A>::value> alloc_version; + typedef container_detail::integral_constant<unsigned, 1> allocator_v1; + typedef container_detail::integral_constant<unsigned, 2> 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); } + + BOOST_MOVABLE_BUT_NOT_COPYABLE(scoped_deallocator) + + public: + + pointer m_ptr; + A& m_alloc; + + scoped_deallocator(pointer p, A& a) + : m_ptr(p), m_alloc(a) + {} + + ~scoped_deallocator() + { if (m_ptr)priv_deallocate(alloc_version()); } + + scoped_deallocator(BOOST_RV_REF(scoped_deallocator) o) + : m_ptr(o.m_ptr), m_alloc(o.m_alloc) + { o.release(); } + + pointer get() const + { return m_ptr; } + + void set(const pointer &p) + { m_ptr = p; } + + void release() + { m_ptr = 0; } +}; + +template <class Allocator> +struct null_scoped_deallocator +{ + typedef boost::container::allocator_traits<Allocator> AllocTraits; + typedef typename AllocTraits::pointer pointer; + typedef typename AllocTraits::size_type size_type; + + null_scoped_deallocator(pointer, Allocator&, size_type) + {} + + void release() + {} + + pointer get() const + { return pointer(); } + + void set(const pointer &) + {} +}; + +//!A deleter for scoped_ptr that deallocates the memory //!allocated for an array of objects using a STL allocator. template <class Allocator> struct scoped_array_deallocator @@ -126,13 +195,17 @@ struct scoped_destructor_n void increment_size_backwards(size_type inc) { m_n += inc; m_p -= inc; } - + + void shrink_forward(size_type inc) + { m_n -= inc; m_p += inc; } + ~scoped_destructor_n() { if(!m_p) return; value_type *raw_ptr = container_detail::to_raw_pointer(m_p); - for(size_type i = 0; i < m_n; ++i, ++raw_ptr) - AllocTraits::destroy(m_a, raw_ptr); + while(m_n--){ + AllocTraits::destroy(m_a, raw_ptr++); + } } private: @@ -159,6 +232,9 @@ struct null_scoped_destructor_n void increment_size_backwards(size_type) {} + void shrink_forward(size_type) + {} + void release() {} }; @@ -183,6 +259,11 @@ class scoped_destructor void release() { pv_ = 0; } + + void set(value_type *ptr) { pv_ = ptr; } + + value_type *get() const { return pv_; } + private: value_type *pv_; A &a_; @@ -239,10 +320,56 @@ class allocator_destroyer void operator()(const pointer &p) { AllocTraits::destroy(a_, container_detail::to_raw_pointer(p)); - priv_deallocate(p, alloc_version()); + this->priv_deallocate(p, alloc_version()); } }; +template <class A> +class allocator_destroyer_and_chain_builder +{ + typedef allocator_traits<A> allocator_traits_type; + typedef typename allocator_traits_type::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) + { + allocator_traits<A>::destroy(a_, container_detail::to_raw_pointer(p)); + c_.push_back(p); + } +}; + +template <class A> +class allocator_multialloc_chain_node_deallocator +{ + typedef allocator_traits<A> allocator_traits_type; + typedef typename allocator_traits_type::value_type value_type; + typedef typename A::multiallocation_chain multiallocation_chain; + typedef allocator_destroyer_and_chain_builder<A> 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() + { + a_.deallocate_individual(c_); + } +}; } //namespace container_detail { } //namespace container { diff --git a/boost/container/detail/flat_tree.hpp b/boost/container/detail/flat_tree.hpp index 23be0bfd13..a6f7568b43 100644 --- a/boost/container/detail/flat_tree.hpp +++ b/boost/container/detail/flat_tree.hpp @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,11 +11,11 @@ #ifndef BOOST_CONTAINER_FLAT_TREE_HPP #define BOOST_CONTAINER_FLAT_TREE_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" +#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> #include <boost/container/container_fwd.hpp> @@ -25,7 +25,7 @@ #include <utility> #include <boost/type_traits/has_trivial_destructor.hpp> -#include <boost/move/move.hpp> +#include <boost/move/utility_core.hpp> #include <boost/container/detail/utilities.hpp> #include <boost/container/detail/pair.hpp> @@ -33,7 +33,11 @@ #include <boost/container/detail/value_init.hpp> #include <boost/container/detail/destroyers.hpp> #include <boost/container/allocator_traits.hpp> +#ifdef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER +#include <boost/intrusive/pointer_traits.hpp> +#endif #include <boost/aligned_storage.hpp> +#include <boost/move/make_unique.hpp> namespace boost { @@ -48,7 +52,7 @@ class flat_tree_value_compare typedef Value first_argument_type; typedef Value second_argument_type; typedef bool return_type; - public: + public: flat_tree_value_compare() : Compare() {} @@ -65,7 +69,7 @@ class flat_tree_value_compare const Compare &get_comp() const { return *this; } - + Compare &get_comp() { return *this; } }; @@ -73,12 +77,23 @@ class flat_tree_value_compare template<class Pointer> struct get_flat_tree_iterators { - typedef typename container_detail:: - vector_iterator<Pointer> iterator; - typedef typename container_detail:: - vector_const_iterator<Pointer> const_iterator; - typedef std::reverse_iterator<iterator> reverse_iterator; - typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + #ifdef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + typedef Pointer iterator; + typedef typename boost::intrusive:: + pointer_traits<Pointer>::element_type iterator_element_type; + typedef typename boost::intrusive:: + pointer_traits<Pointer>:: template + rebind_pointer<const iterator_element_type>::type const_iterator; + #else //BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + typedef typename boost::container::container_detail:: + vec_iterator<Pointer, false> iterator; + typedef typename boost::container::container_detail:: + vec_iterator<Pointer, true > const_iterator; + #endif //BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + typedef boost::container::container_detail:: + reverse_iterator<iterator> reverse_iterator; + typedef boost::container::container_detail:: + reverse_iterator<const_iterator> const_reverse_iterator; }; template <class Key, class Value, class KeyOfValue, @@ -103,7 +118,7 @@ class flat_tree : value_compare(), m_vect() {} - Data(const Data &d) + explicit Data(const Data &d) : value_compare(static_cast<const value_compare&>(d)), m_vect(d.m_vect) {} @@ -119,15 +134,18 @@ class flat_tree : value_compare(boost::move(static_cast<value_compare&>(d))), m_vect(boost::move(d.m_vect), a) {} - Data(const Compare &comp) + explicit Data(const Compare &comp) : value_compare(comp), m_vect() {} - Data(const Compare &comp, - const allocator_t &alloc) + Data(const Compare &comp, const allocator_t &alloc) : value_compare(comp), m_vect(alloc) {} + explicit Data(const allocator_t &alloc) + : value_compare(), m_vect(alloc) + {} + Data& operator=(BOOST_COPY_ASSIGN_REF(Data) d) { this->value_compare::operator=(d); @@ -145,7 +163,7 @@ class flat_tree void swap(Data &d) { value_compare& mycomp = *this, & othercomp = d; - container_detail::do_swap(mycomp, othercomp); + boost::container::swap_dispatch(mycomp, othercomp); this->m_vect.swap(d.m_vect); } @@ -191,6 +209,10 @@ class flat_tree : m_data(comp, a) { } + explicit flat_tree(const allocator_type& a) + : m_data(a) + { } + flat_tree(const flat_tree& x) : m_data(x.m_data) { } @@ -214,8 +236,31 @@ class flat_tree : m_data(comp, a) { this->m_data.m_vect.insert(this->m_data.m_vect.end(), first, last); } + template <class InputIterator> + flat_tree( bool unique_insertion + , InputIterator first, InputIterator last + , const Compare& comp = Compare() + , const allocator_type& a = allocator_type()) + : m_data(comp, a) + { + //Use cend() as hint to achieve linear time for + //ordered ranges as required by the standard + //for the constructor + //Call end() every iteration as reallocation might have invalidated iterators + if(unique_insertion){ + for ( ; first != last; ++first){ + this->insert_unique(this->cend(), *first); + } + } + else{ + for ( ; first != last; ++first){ + this->insert_equal(this->cend(), *first); + } + } + } + ~flat_tree() - { } + {} flat_tree& operator=(BOOST_COPY_ASSIGN_REF(flat_tree) x) { m_data = x.m_data; return *this; } @@ -223,11 +268,14 @@ class flat_tree flat_tree& operator=(BOOST_RV_REF(flat_tree) mx) { m_data = boost::move(mx.m_data); return *this; } - public: + public: // accessors: Compare key_comp() const { return this->m_data.get_comp(); } + value_compare value_comp() const + { return this->m_data; } + allocator_type get_allocator() const { return this->m_data.m_vect.get_allocator(); } @@ -289,21 +337,21 @@ class flat_tree // insert/erase std::pair<iterator,bool> insert_unique(const value_type& val) { + std::pair<iterator,bool> ret; insert_commit_data data; - std::pair<iterator,bool> ret = priv_insert_unique_prepare(val, data); - if(ret.second){ - ret.first = priv_insert_commit(data, val); - } + ret.second = this->priv_insert_unique_prepare(val, data); + ret.first = ret.second ? this->priv_insert_commit(data, val) + : iterator(vector_iterator_get_ptr(data.position)); return ret; } std::pair<iterator,bool> insert_unique(BOOST_RV_REF(value_type) val) { + std::pair<iterator,bool> ret; insert_commit_data data; - std::pair<iterator,bool> ret = priv_insert_unique_prepare(val, data); - if(ret.second){ - ret.first = priv_insert_commit(data, boost::move(val)); - } + ret.second = this->priv_insert_unique_prepare(val, data); + ret.first = ret.second ? this->priv_insert_commit(data, boost::move(val)) + : iterator(vector_iterator_get_ptr(data.position)); return ret; } @@ -323,69 +371,134 @@ class flat_tree iterator insert_unique(const_iterator pos, const value_type& val) { + std::pair<iterator,bool> ret; insert_commit_data data; - std::pair<iterator,bool> ret = priv_insert_unique_prepare(pos, val, data); - if(ret.second){ - ret.first = priv_insert_commit(data, val); - } - return ret.first; + return this->priv_insert_unique_prepare(pos, val, data) + ? this->priv_insert_commit(data, val) + : iterator(vector_iterator_get_ptr(data.position)); } - iterator insert_unique(const_iterator pos, BOOST_RV_REF(value_type) mval) + iterator insert_unique(const_iterator pos, BOOST_RV_REF(value_type) val) { + std::pair<iterator,bool> ret; insert_commit_data data; - std::pair<iterator,bool> ret = priv_insert_unique_prepare(pos, mval, data); - if(ret.second){ - ret.first = priv_insert_commit(data, boost::move(mval)); - } - return ret.first; + return this->priv_insert_unique_prepare(pos, val, data) + ? this->priv_insert_commit(data, boost::move(val)) + : iterator(vector_iterator_get_ptr(data.position)); } iterator insert_equal(const_iterator pos, const value_type& val) { insert_commit_data data; this->priv_insert_equal_prepare(pos, val, data); - return priv_insert_commit(data, val); + return this->priv_insert_commit(data, val); } iterator insert_equal(const_iterator pos, BOOST_RV_REF(value_type) mval) { insert_commit_data data; this->priv_insert_equal_prepare(pos, mval, data); - return priv_insert_commit(data, boost::move(mval)); + return this->priv_insert_commit(data, boost::move(mval)); } template <class InIt> void insert_unique(InIt first, InIt last) { - for ( ; first != last; ++first) + for ( ; first != last; ++first){ this->insert_unique(*first); + } } template <class InIt> - void insert_equal(InIt first, InIt last) + void insert_equal(InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator<InIt>::value + >::type * = 0 + #endif + ) + { this->priv_insert_equal_loop(first, last); } + + template <class InIt> + void insert_equal(InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_input_iterator<InIt>::value + >::type * = 0 + #endif + ) { - typedef typename - std::iterator_traits<InIt>::iterator_category ItCat; - this->priv_insert_equal(first, last, ItCat()); + const size_type len = static_cast<size_type>(std::distance(first, last)); + this->reserve(this->size()+len); + this->priv_insert_equal_loop(first, last); } + //Ordered + template <class InIt> - void insert_equal(ordered_range_t, InIt first, InIt last) + void insert_equal(ordered_range_t, InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator<InIt>::value + >::type * = 0 + #endif + ) + { this->priv_insert_equal_loop_ordered(first, last); } + + template <class FwdIt> + void insert_equal(ordered_range_t, FwdIt first, FwdIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_input_iterator<FwdIt>::value && + container_detail::is_forward_iterator<FwdIt>::value + >::type * = 0 + #endif + ) { - typedef typename - std::iterator_traits<InIt>::iterator_category ItCat; - this->priv_insert_equal(ordered_range_t(), first, last, ItCat()); + const size_type len = static_cast<size_type>(std::distance(first, last)); + this->reserve(this->size()+len); + this->priv_insert_equal_loop_ordered(first, last); } + template <class BidirIt> + void insert_equal(ordered_range_t, BidirIt first, BidirIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_input_iterator<BidirIt>::value && + !container_detail::is_forward_iterator<BidirIt>::value + >::type * = 0 + #endif + ) + { this->priv_insert_ordered_range(false, first, last); } + template <class InIt> - void insert_unique(ordered_unique_range_t, InIt first, InIt last) - { - typedef typename - std::iterator_traits<InIt>::iterator_category ItCat; - this->priv_insert_unique(ordered_unique_range_t(), first, last, ItCat()); + void insert_unique(ordered_unique_range_t, InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator<InIt>::value || + container_detail::is_forward_iterator<InIt>::value + >::type * = 0 + #endif + ) + { + const_iterator pos(this->cend()); + for ( ; first != last; ++first){ + pos = this->insert_unique(pos, *first); + ++pos; + } } + template <class BidirIt> + void insert_unique(ordered_unique_range_t, BidirIt first, BidirIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !(container_detail::is_input_iterator<BidirIt>::value || + container_detail::is_forward_iterator<BidirIt>::value) + >::type * = 0 + #endif + ) + { this->priv_insert_ordered_range(true, first, last); } + #ifdef BOOST_CONTAINER_PERFECT_FORWARDING template <class... Args> @@ -396,13 +509,7 @@ class flat_tree stored_allocator_type &a = this->get_stored_allocator(); stored_allocator_traits::construct(a, &val, ::boost::forward<Args>(args)... ); value_destructor<stored_allocator_type> d(a, val); - insert_commit_data data; - std::pair<iterator,bool> ret = - priv_insert_unique_prepare(val, data); - if(ret.second){ - ret.first = priv_insert_commit(data, boost::move(val)); - } - return ret; + return this->insert_unique(::boost::move(val)); } template <class... Args> @@ -413,12 +520,7 @@ class flat_tree stored_allocator_type &a = this->get_stored_allocator(); stored_allocator_traits::construct(a, &val, ::boost::forward<Args>(args)... ); value_destructor<stored_allocator_type> d(a, val); - insert_commit_data data; - std::pair<iterator,bool> ret = priv_insert_unique_prepare(hint, val, data); - if(ret.second){ - ret.first = priv_insert_commit(data, boost::move(val)); - } - return ret.first; + return this->insert_unique(hint, ::boost::move(val)); } template <class... Args> @@ -429,9 +531,7 @@ class flat_tree stored_allocator_type &a = this->get_stored_allocator(); stored_allocator_traits::construct(a, &val, ::boost::forward<Args>(args)... ); value_destructor<stored_allocator_type> d(a, val); - iterator i = this->upper_bound(KeyOfValue()(val)); - i = this->m_data.m_vect.insert(i, boost::move(val)); - return i; + return this->insert_equal(::boost::move(val)); } template <class... Args> @@ -442,10 +542,7 @@ class flat_tree stored_allocator_type &a = this->get_stored_allocator(); stored_allocator_traits::construct(a, &val, ::boost::forward<Args>(args)... ); value_destructor<stored_allocator_type> d(a, val); - insert_commit_data data; - this->priv_insert_equal_prepare(hint, val, data); - iterator i = priv_insert_commit(data, boost::move(val)); - return i; + return this->insert_equal(hint, ::boost::move(val)); } #else //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING @@ -461,12 +558,7 @@ class flat_tree stored_allocator_traits::construct(a, &val \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \ value_destructor<stored_allocator_type> d(a, val); \ - insert_commit_data data; \ - std::pair<iterator,bool> ret = priv_insert_unique_prepare(val, data); \ - if(ret.second){ \ - ret.first = priv_insert_commit(data, boost::move(val)); \ - } \ - return ret; \ + return this->insert_unique(::boost::move(val)); \ } \ \ BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ @@ -478,13 +570,8 @@ class flat_tree stored_allocator_type &a = this->get_stored_allocator(); \ stored_allocator_traits::construct(a, &val \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \ - value_destructor<stored_allocator_type> d(a, val); \ - insert_commit_data data; \ - std::pair<iterator,bool> ret = priv_insert_unique_prepare(hint, val, data); \ - if(ret.second){ \ - ret.first = priv_insert_commit(data, boost::move(val)); \ - } \ - return ret.first; \ + value_destructor<stored_allocator_type> d(a, val); \ + return this->insert_unique(hint, ::boost::move(val)); \ } \ \ BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ @@ -496,9 +583,7 @@ class flat_tree stored_allocator_traits::construct(a, &val \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \ value_destructor<stored_allocator_type> d(a, val); \ - iterator i = this->upper_bound(KeyOfValue()(val)); \ - i = this->m_data.m_vect.insert(i, boost::move(val)); \ - return i; \ + return this->insert_equal(::boost::move(val)); \ } \ \ BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ @@ -511,12 +596,8 @@ class flat_tree stored_allocator_traits::construct(a, &val \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \ value_destructor<stored_allocator_type> d(a, val); \ - insert_commit_data data; \ - this->priv_insert_equal_prepare(hint, val, data); \ - iterator i = priv_insert_commit(data, boost::move(val)); \ - return i; \ + return this->insert_equal(hint, ::boost::move(val)); \ } \ - //! #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() @@ -554,26 +635,26 @@ class flat_tree // set operations: iterator find(const key_type& k) { - const Compare &key_comp = this->m_data.get_comp(); iterator i = this->lower_bound(k); - - if (i != this->end() && key_comp(k, KeyOfValue()(*i))){ - i = this->end(); + iterator end_it = this->end(); + if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){ + i = end_it; } return i; } const_iterator find(const key_type& k) const { - const Compare &key_comp = this->m_data.get_comp(); const_iterator i = this->lower_bound(k); - if (i != this->end() && key_comp(k, KeyOfValue()(*i))){ - i = this->end(); + const_iterator end_it = this->cend(); + if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){ + i = end_it; } return i; } + // set operations: size_type count(const key_type& k) const { std::pair<const_iterator, const_iterator> p = this->equal_range(k); @@ -585,25 +666,57 @@ class flat_tree { return this->priv_lower_bound(this->begin(), this->end(), k); } const_iterator lower_bound(const key_type& k) const - { return this->priv_lower_bound(this->begin(), this->end(), k); } + { return this->priv_lower_bound(this->cbegin(), this->cend(), k); } iterator upper_bound(const key_type& k) { return this->priv_upper_bound(this->begin(), this->end(), k); } const_iterator upper_bound(const key_type& k) const - { return this->priv_upper_bound(this->begin(), this->end(), k); } + { return this->priv_upper_bound(this->cbegin(), this->cend(), k); } std::pair<iterator,iterator> equal_range(const key_type& k) { return this->priv_equal_range(this->begin(), this->end(), k); } std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const - { return this->priv_equal_range(this->begin(), this->end(), k); } + { return this->priv_equal_range(this->cbegin(), this->cend(), k); } + + std::pair<iterator, iterator> lower_bound_range(const key_type& k) + { return this->priv_lower_bound_range(this->begin(), this->end(), k); } + + std::pair<const_iterator, const_iterator> lower_bound_range(const key_type& k) const + { return this->priv_lower_bound_range(this->cbegin(), this->cend(), k); } - size_type capacity() const + size_type capacity() const { return this->m_data.m_vect.capacity(); } - void reserve(size_type count) - { this->m_data.m_vect.reserve(count); } + void reserve(size_type cnt) + { this->m_data.m_vect.reserve(cnt); } + + friend bool operator==(const flat_tree& x, const flat_tree& y) + { + return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); + } + + friend bool operator<(const flat_tree& x, const flat_tree& y) + { + return std::lexicographical_compare(x.begin(), x.end(), + y.begin(), y.end()); + } + + friend bool operator!=(const flat_tree& x, const flat_tree& y) + { return !(x == y); } + + friend bool operator>(const flat_tree& x, const flat_tree& y) + { return y < x; } + + friend bool operator<=(const flat_tree& x, const flat_tree& y) + { return !(y < x); } + + friend bool operator>=(const flat_tree& x, const flat_tree& y) + { return !(x < y); } + + friend void swap(flat_tree& x, flat_tree& y) + { x.swap(y); } private: struct insert_commit_data @@ -624,10 +737,10 @@ class flat_tree // insert val before upper_bound(val) // else // insert val before lower_bound(val) - const value_compare &value_comp = this->m_data; + const value_compare &val_cmp = this->m_data; - if(pos == this->cend() || !value_comp(*pos, val)){ - if (pos == this->cbegin() || !value_comp(val, pos[-1])){ + if(pos == this->cend() || !val_cmp(*pos, val)){ + if (pos == this->cbegin() || !val_cmp(val, pos[-1])){ data.position = pos; } else{ @@ -641,21 +754,19 @@ class flat_tree } } - std::pair<iterator,bool> priv_insert_unique_prepare - (const_iterator beg, const_iterator end, const value_type& val, insert_commit_data &commit_data) + bool priv_insert_unique_prepare + (const_iterator b, const_iterator e, const value_type& val, insert_commit_data &commit_data) { - const value_compare &value_comp = this->m_data; - commit_data.position = this->priv_lower_bound(beg, end, KeyOfValue()(val)); - return std::pair<iterator,bool> - ( *reinterpret_cast<iterator*>(&commit_data.position) - , commit_data.position == end || value_comp(val, *commit_data.position)); + const value_compare &val_cmp = this->m_data; + commit_data.position = this->priv_lower_bound(b, e, KeyOfValue()(val)); + return commit_data.position == e || val_cmp(val, *commit_data.position); } - std::pair<iterator,bool> priv_insert_unique_prepare + bool priv_insert_unique_prepare (const value_type& val, insert_commit_data &commit_data) - { return priv_insert_unique_prepare(this->begin(), this->end(), val, commit_data); } + { return this->priv_insert_unique_prepare(this->cbegin(), this->cend(), val, commit_data); } - std::pair<iterator,bool> priv_insert_unique_prepare + bool priv_insert_unique_prepare (const_iterator pos, const value_type& val, insert_commit_data &commit_data) { //N1780. Props to Howard Hinnant! @@ -669,37 +780,32 @@ class flat_tree // insert val after pos //else // insert val before lower_bound(val) - const value_compare &value_comp = this->m_data; - - if(pos == this->cend() || value_comp(val, *pos)){ - if(pos != this->cbegin() && !value_comp(val, pos[-1])){ - if(value_comp(pos[-1], val)){ - commit_data.position = pos; - return std::pair<iterator,bool>(*reinterpret_cast<iterator*>(&pos), true); - } - else{ - return std::pair<iterator,bool>(*reinterpret_cast<iterator*>(&pos), false); - } + const value_compare &val_cmp = this->m_data; + const const_iterator cend_it = this->cend(); + if(pos == cend_it || val_cmp(val, *pos)){ //Check if val should go before end + const const_iterator cbeg = this->cbegin(); + commit_data.position = pos; + if(pos == cbeg){ //If container is empty then insert it in the beginning + return true; + } + const_iterator prev(pos); + --prev; + if(val_cmp(*prev, val)){ //If previous element was less, then it should go between prev and pos + return true; + } + else if(!val_cmp(val, *prev)){ //If previous was equal then insertion should fail + commit_data.position = prev; + return false; + } + else{ //Previous was bigger so insertion hint was pointless, dispatch to hintless insertion + //but reduce the search between beg and prev as prev is bigger than val + return this->priv_insert_unique_prepare(cbeg, prev, val, commit_data); } - return this->priv_insert_unique_prepare(this->cbegin(), pos, val, commit_data); } - - // Works, but increases code complexity - //Next check - //else if (value_comp(*pos, val) && !value_comp(pos[1], val)){ - // if(value_comp(val, pos[1])){ - // commit_data.position = pos+1; - // return std::pair<iterator,bool>(pos+1, true); - // } - // else{ - // return std::pair<iterator,bool>(pos+1, false); - // } - //} else{ - //[... pos ... val ... ] //The hint is before the insertion position, so insert it - //in the remaining range - return this->priv_insert_unique_prepare(pos, this->end(), val, commit_data); + //in the remaining range [pos, end) + return this->priv_insert_unique_prepare(pos, cend_it, val, commit_data); } } @@ -713,50 +819,50 @@ class flat_tree } template <class RanIt> - RanIt priv_lower_bound(RanIt first, RanIt last, + RanIt priv_lower_bound(RanIt first, const RanIt last, const key_type & key) const { - const Compare &key_comp = this->m_data.get_comp(); + const Compare &key_cmp = this->m_data.get_comp(); KeyOfValue key_extract; - difference_type len = last - first, half; + size_type len = static_cast<size_type>(last - first); RanIt middle; - while (len > 0) { - half = len >> 1; + while (len) { + size_type step = len >> 1; middle = first; - middle += half; + middle += step; - if (key_comp(key_extract(*middle), key)) { - ++middle; - first = middle; - len = len - half - 1; + if (key_cmp(key_extract(*middle), key)) { + first = ++middle; + len -= step + 1; + } + else{ + len = step; } - else - len = half; } return first; } template <class RanIt> - RanIt priv_upper_bound(RanIt first, RanIt last, + RanIt priv_upper_bound(RanIt first, const RanIt last, const key_type & key) const { - const Compare &key_comp = this->m_data.get_comp(); + const Compare &key_cmp = this->m_data.get_comp(); KeyOfValue key_extract; - difference_type len = last - first, half; + size_type len = static_cast<size_type>(last - first); RanIt middle; - while (len > 0) { - half = len >> 1; + while (len) { + size_type step = len >> 1; middle = first; - middle += half; + middle += step; - if (key_comp(key, key_extract(*middle))) { - len = half; + if (key_cmp(key, key_extract(*middle))) { + len = step; } else{ first = ++middle; - len = len - half - 1; + len -= step + 1; } } return first; @@ -766,189 +872,135 @@ class flat_tree std::pair<RanIt, RanIt> priv_equal_range(RanIt first, RanIt last, const key_type& key) const { - const Compare &key_comp = this->m_data.get_comp(); + const Compare &key_cmp = this->m_data.get_comp(); KeyOfValue key_extract; - difference_type len = last - first, half; - RanIt middle, left, right; + size_type len = static_cast<size_type>(last - first); + RanIt middle; - while (len > 0) { - half = len >> 1; + while (len) { + size_type step = len >> 1; middle = first; - middle += half; + middle += step; - if (key_comp(key_extract(*middle), key)){ - first = middle; - ++first; - len = len - half - 1; + if (key_cmp(key_extract(*middle), key)){ + first = ++middle; + len -= step + 1; } - else if (key_comp(key, key_extract(*middle))){ - len = half; + else if (key_cmp(key, key_extract(*middle))){ + len = step; } else { - left = this->priv_lower_bound(first, middle, key); - first += len; - right = this->priv_upper_bound(++middle, first, key); - return std::pair<RanIt, RanIt>(left, right); + //Middle is equal to key + last = first; + last += len; + return std::pair<RanIt, RanIt> + ( this->priv_lower_bound(first, middle, key) + , this->priv_upper_bound(++middle, last, key)); } } return std::pair<RanIt, RanIt>(first, first); } - template <class BidirIt> - void priv_insert_equal(ordered_range_t, BidirIt first, BidirIt last, std::bidirectional_iterator_tag) + template<class RanIt> + std::pair<RanIt, RanIt> priv_lower_bound_range(RanIt first, RanIt last, const key_type& k) const { - size_type len = static_cast<size_type>(std::distance(first, last)); - const size_type BurstSize = 16; - size_type positions[BurstSize]; + const Compare &key_cmp = this->m_data.get_comp(); + KeyOfValue key_extract; + RanIt lb(this->priv_lower_bound(first, last, k)), ub(lb); + if(lb != last && static_cast<difference_type>(!key_cmp(k, key_extract(*lb)))){ + ++ub; + } + return std::pair<RanIt, RanIt>(lb, ub); + } - //Prereserve all memory so that iterators are not invalidated - this->reserve(this->size()+len); - const const_iterator beg(this->cbegin()); - const_iterator pos(beg); - //Loop in burst sizes - while(len){ - const size_type burst = len < BurstSize ? len : BurstSize; - const const_iterator cend(this->cend()); - len -= burst; - for(size_type i = 0; i != burst; ++i){ - //Get the insertion position for each key - pos = const_cast<const flat_tree&>(*this).priv_upper_bound(pos, cend, KeyOfValue()(*first)); - positions[i] = static_cast<size_type>(pos - beg); - ++first; - } - //Insert all in a single step in the precalculated positions - this->m_data.m_vect.insert_ordered_at(burst, positions + burst, first); - //Next search position updated - pos += burst; + template<class InIt> + void priv_insert_equal_loop(InIt first, InIt last) + { + for ( ; first != last; ++first){ + this->insert_equal(*first); + } + } + + template<class InIt> + void priv_insert_equal_loop_ordered(InIt first, InIt last) + { + const_iterator pos(this->cend()); + for ( ; first != last; ++first){ + //If ordered, then try hint version + //to achieve constant-time complexity per insertion + pos = this->insert_equal(pos, *first); + ++pos; } } template <class BidirIt> - void priv_insert_unique(ordered_unique_range_t, BidirIt first, BidirIt last, std::bidirectional_iterator_tag) + void priv_insert_ordered_range(const bool unique_values, BidirIt first, BidirIt last) { size_type len = static_cast<size_type>(std::distance(first, last)); - const size_type BurstSize = 16; - size_type positions[BurstSize]; - size_type skips[BurstSize]; - //Prereserve all memory so that iterators are not invalidated this->reserve(this->size()+len); - const const_iterator beg(this->cbegin()); - const_iterator pos(beg); - const value_compare &value_comp = this->m_data; + //Auxiliary data for insertion positions. + const size_type BurstSize = len; + const ::boost::movelib::unique_ptr<size_type[]> positions = + ::boost::movelib::make_unique_definit<size_type[]>(BurstSize); + + const const_iterator b(this->cbegin()); + const const_iterator ce(this->cend()); + const_iterator pos(b); + const value_compare &val_cmp = this->m_data; //Loop in burst sizes - while(len){ - skips[0u] = 0u; + bool back_insert = false; + while(len && !back_insert){ const size_type burst = len < BurstSize ? len : BurstSize; size_type unique_burst = 0u; - const const_iterator cend(this->cend()); - while(unique_burst < burst && len > 0){ - //Get the insertion position for each key - const value_type & val = *first++; - --len; - pos = const_cast<const flat_tree&>(*this).priv_lower_bound(pos, cend, KeyOfValue()(val)); + size_type checked = 0; + for(; checked != burst; ++checked){ + //Get the insertion position for each key, use std::iterator_traits<BidirIt>::value_type + //because it can be different from container::value_type + //(e.g. conversion between std::pair<A, B> -> boost::container::pair<A, B> + const typename std::iterator_traits<BidirIt>::value_type & val = *first; + pos = const_cast<const flat_tree&>(*this).priv_lower_bound(pos, ce, KeyOfValue()(val)); //Check if already present - if(pos != cend && !value_comp(*pos, val)){ - ++skips[unique_burst]; - continue; + if (pos != ce){ + ++first; + --len; + positions[checked] = (unique_values && !val_cmp(val, *pos)) ? + size_type(-1) : (++unique_burst, static_cast<size_type>(pos - b)); } - - //If not present, calculate position - positions[unique_burst] = static_cast<size_type>(pos - beg); - if(++unique_burst < burst) - skips[unique_burst] = 0u; + else{ //this element and the remaining should be back inserted + back_insert = true; + break; + } + } + if(unique_burst){ + //Insert all in a single step in the precalculated positions + this->m_data.m_vect.insert_ordered_at(unique_burst, positions.get() + checked, first); + //Next search position updated, iterator still valid because we've preserved the vector + pos += unique_burst; } - //Insert all in a single step in the precalculated positions - this->m_data.m_vect.insert_ordered_at(unique_burst, positions + unique_burst, skips + unique_burst, first); - //Next search position updated - pos += unique_burst; } - } -/* - template <class FwdIt> - void priv_insert_equal_forward(ordered_range_t, FwdIt first, FwdIt last, std::forward_iterator_tag) - { this->priv_insert_equal(first, last, std::forward_iterator_tag()); } -*/ - template <class InIt> - void priv_insert_equal(ordered_range_t, InIt first, InIt last, std::input_iterator_tag) - { this->priv_insert_equal(first, last, std::input_iterator_tag()); } - - template <class InIt> - void priv_insert_unique(ordered_unique_range_t, InIt first, InIt last, std::input_iterator_tag) - { this->priv_insert_unique(first, last, std::input_iterator_tag()); } -/* - template <class FwdIt> - void priv_insert_equal_forward(FwdIt first, FwdIt last, std::forward_iterator_tag) - { - const size_type len = static_cast<size_type>(std::distance(first, last)); - this->reserve(this->size()+len); - this->priv_insert_equal(first, last, std::input_iterator_tag()); - } -*/ - template <class InIt> - void priv_insert_equal(InIt first, InIt last, std::input_iterator_tag) - { - for ( ; first != last; ++first) - this->insert_equal(*first); + //The remaining range should be back inserted + if(unique_values){ + while(len--){ + BidirIt next(first); + ++next; + if(next == last || val_cmp(*first, *next)){ + const bool room = this->m_data.m_vect.stable_emplace_back(*first); + (void)room; + BOOST_ASSERT(room); + } + first = next; + } + BOOST_ASSERT(first == last); + } + else{ + BOOST_ASSERT(size_type(std::distance(first, last)) == len); + if(len) + this->m_data.m_vect.insert(this->m_data.m_vect.cend(), len, first, last); + } } }; -template <class Key, class Value, class KeyOfValue, - class Compare, class A> -inline bool -operator==(const flat_tree<Key,Value,KeyOfValue,Compare,A>& x, - const flat_tree<Key,Value,KeyOfValue,Compare,A>& y) -{ - return x.size() == y.size() && - std::equal(x.begin(), x.end(), y.begin()); -} - -template <class Key, class Value, class KeyOfValue, - class Compare, class A> -inline bool -operator<(const flat_tree<Key,Value,KeyOfValue,Compare,A>& x, - const flat_tree<Key,Value,KeyOfValue,Compare,A>& y) -{ - return std::lexicographical_compare(x.begin(), x.end(), - y.begin(), y.end()); -} - -template <class Key, class Value, class KeyOfValue, - class Compare, class A> -inline bool -operator!=(const flat_tree<Key,Value,KeyOfValue,Compare,A>& x, - const flat_tree<Key,Value,KeyOfValue,Compare,A>& y) - { return !(x == y); } - -template <class Key, class Value, class KeyOfValue, - class Compare, class A> -inline bool -operator>(const flat_tree<Key,Value,KeyOfValue,Compare,A>& x, - const flat_tree<Key,Value,KeyOfValue,Compare,A>& y) - { return y < x; } - -template <class Key, class Value, class KeyOfValue, - class Compare, class A> -inline bool -operator<=(const flat_tree<Key,Value,KeyOfValue,Compare,A>& x, - const flat_tree<Key,Value,KeyOfValue,Compare,A>& y) - { return !(y < x); } - -template <class Key, class Value, class KeyOfValue, - class Compare, class A> -inline bool -operator>=(const flat_tree<Key,Value,KeyOfValue,Compare,A>& x, - const flat_tree<Key,Value,KeyOfValue,Compare,A>& y) - { return !(x < y); } - - -template <class Key, class Value, class KeyOfValue, - class Compare, class A> -inline void -swap(flat_tree<Key,Value,KeyOfValue,Compare,A>& x, - flat_tree<Key,Value,KeyOfValue,Compare,A>& y) - { x.swap(y); } - } //namespace container_detail { } //namespace container { @@ -959,7 +1011,7 @@ template <class K, class V, class KOV, class C, class A> struct has_trivial_destructor_after_move<boost::container::container_detail::flat_tree<K, V, KOV, C, A> > { - static const bool value = has_trivial_destructor<A>::value && has_trivial_destructor<C>::value; + static const bool value = has_trivial_destructor_after_move<A>::value && has_trivial_destructor_after_move<C>::value; }; */ } //namespace boost { diff --git a/boost/container/detail/function_detector.hpp b/boost/container/detail/function_detector.hpp index 5a5f6fd77d..242eb41352 100644 --- a/boost/container/detail/function_detector.hpp +++ b/boost/container/detail/function_detector.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2009-2012. +// (C) Copyright Ion Gaztanaga 2009-2013. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -22,6 +22,10 @@ #ifndef BOOST_CONTAINER_DETAIL_FUNCTION_DETECTOR_HPP #define BOOST_CONTAINER_DETAIL_FUNCTION_DETECTOR_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include <boost/container/detail/config_begin.hpp> namespace boost { diff --git a/boost/container/detail/hash_table.hpp b/boost/container/detail/hash_table.hpp new file mode 100644 index 0000000000..da7bb536e4 --- /dev/null +++ b/boost/container/detail/hash_table.hpp @@ -0,0 +1,383 @@ +/* +template <class Value, unsigned int Options = 0, class Hash = hash<Value>, class Pred = equal_to<Value>, + class Alloc = allocator<Value> > +class hash_set +{ +public: + // types + typedef Value key_type; + typedef key_type value_type; + typedef Hash hasher; + typedef Pred key_equal; + typedef Alloc allocator_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef typename allocator_traits<allocator_type>::pointer pointer; + typedef typename allocator_traits<allocator_type>::const_pointer const_pointer; + typedef typename allocator_traits<allocator_type>::size_type size_type; + typedef typename allocator_traits<allocator_type>::difference_type difference_type; + + typedef /unspecified/ iterator; + typedef /unspecified/ const_iterator; + typedef /unspecified/ local_iterator; + typedef /unspecified/ const_local_iterator; + + hash_set() + noexcept( + is_nothrow_default_constructible<hasher>::value && + is_nothrow_default_constructible<key_equal>::value && + is_nothrow_default_constructible<allocator_type>::value); + explicit hash_set(size_type n, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template <class InputIterator> + hash_set(InputIterator f, InputIterator l, + size_type n = 0, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + explicit hash_set(const allocator_type&); + hash_set(const hash_set&); + hash_set(const hash_set&, const Allocator&); + hash_set(hash_set&&) + noexcept( + is_nothrow_move_constructible<hasher>::value && + is_nothrow_move_constructible<key_equal>::value && + is_nothrow_move_constructible<allocator_type>::value); + hash_set(hash_set&&, const Allocator&); + hash_set(initializer_list<value_type>, size_type n = 0, + const hasher& hf = hasher(), const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + ~hash_set(); + hash_set& operator=(const hash_set&); + hash_set& operator=(hash_set&&) + noexcept( + allocator_type::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<allocator_type>::value && + is_nothrow_move_assignable<hasher>::value && + is_nothrow_move_assignable<key_equal>::value); + hash_set& operator=(initializer_list<value_type>); + + allocator_type get_allocator() const noexcept; + + bool empty() const noexcept; + size_type size() const noexcept; + size_type max_size() const noexcept; + + iterator begin() noexcept; + iterator end() noexcept; + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + template <class... Args> + pair<iterator, bool> emplace(Args&&... args); + template <class... Args> + iterator emplace_hint(const_iterator position, Args&&... args); + pair<iterator, bool> insert(const value_type& obj); + pair<iterator, bool> insert(value_type&& obj); + iterator insert(const_iterator hint, const value_type& obj); + iterator insert(const_iterator hint, value_type&& obj); + template <class InputIterator> + void insert(InputIterator first, InputIterator last); + void insert(initializer_list<value_type>); + + iterator erase(const_iterator position); + size_type erase(const key_type& k); + iterator erase(const_iterator first, const_iterator last); + void clear() noexcept; + + void swap(hash_set&) + noexcept( + (!allocator_type::propagate_on_container_swap::value || + __is_nothrow_swappable<allocator_type>::value) && + __is_nothrow_swappable<hasher>::value && + __is_nothrow_swappable<key_equal>::value); + + hasher hash_function() const; + key_equal key_eq() const; + + iterator find(const key_type& k); + const_iterator find(const key_type& k) const; + size_type count(const key_type& k) const; + pair<iterator, iterator> equal_range(const key_type& k); + pair<const_iterator, const_iterator> equal_range(const key_type& k) const; + + size_type bucket_count() const noexcept; + size_type max_bucket_count() const noexcept; + + size_type bucket_size(size_type n) const; + size_type bucket(const key_type& k) const; + + local_iterator begin(size_type n); + local_iterator end(size_type n); + const_local_iterator begin(size_type n) const; + const_local_iterator end(size_type n) const; + const_local_iterator cbegin(size_type n) const; + const_local_iterator cend(size_type n) const; + + float load_factor() const noexcept; + float max_load_factor() const noexcept; + void max_load_factor(float z); + void rehash(size_type n); + void reserve(size_type n); +}; + +template <class Key, class T, unsigned int Options = 0, class Hash = hash<Key>, class Pred = equal_to<Key>, + class Alloc = allocator<pair<const Key, T> > > +class hash_map +{ +public: + // types + typedef Key key_type; + typedef T mapped_type; + typedef Hash hasher; + typedef Pred key_equal; + typedef Alloc allocator_type; + typedef pair<const key_type, mapped_type> value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef typename allocator_traits<allocator_type>::pointer pointer; + typedef typename allocator_traits<allocator_type>::const_pointer const_pointer; + typedef typename allocator_traits<allocator_type>::size_type size_type; + typedef typename allocator_traits<allocator_type>::difference_type difference_type; + + typedef /unspecified/ iterator; + typedef /unspecified/ const_iterator; + typedef /unspecified/ local_iterator; + typedef /unspecified/ const_local_iterator; + + hash_map() + noexcept( + is_nothrow_default_constructible<hasher>::value && + is_nothrow_default_constructible<key_equal>::value && + is_nothrow_default_constructible<allocator_type>::value); + explicit hash_map(size_type n, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template <class InputIterator> + hash_map(InputIterator f, InputIterator l, + size_type n = 0, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + explicit hash_map(const allocator_type&); + hash_map(const hash_map&); + hash_map(const hash_map&, const Allocator&); + hash_map(hash_map&&) + noexcept( + is_nothrow_move_constructible<hasher>::value && + is_nothrow_move_constructible<key_equal>::value && + is_nothrow_move_constructible<allocator_type>::value); + hash_map(hash_map&&, const Allocator&); + hash_map(initializer_list<value_type>, size_type n = 0, + const hasher& hf = hasher(), const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + ~hash_map(); + hash_map& operator=(const hash_map&); + hash_map& operator=(hash_map&&) + noexcept( + allocator_type::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<allocator_type>::value && + is_nothrow_move_assignable<hasher>::value && + is_nothrow_move_assignable<key_equal>::value); + hash_map& operator=(initializer_list<value_type>); + + allocator_type get_allocator() const noexcept; + + bool empty() const noexcept; + size_type size() const noexcept; + size_type max_size() const noexcept; + + iterator begin() noexcept; + iterator end() noexcept; + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + template <class... Args> + pair<iterator, bool> emplace(Args&&... args); + template <class... Args> + iterator emplace_hint(const_iterator position, Args&&... args); + pair<iterator, bool> insert(const value_type& obj); + template <class P> + pair<iterator, bool> insert(P&& obj); + iterator insert(const_iterator hint, const value_type& obj); + template <class P> + iterator insert(const_iterator hint, P&& obj); + template <class InputIterator> + void insert(InputIterator first, InputIterator last); + void insert(initializer_list<value_type>); + + iterator erase(const_iterator position); + size_type erase(const key_type& k); + iterator erase(const_iterator first, const_iterator last); + void clear() noexcept; + + void swap(hash_map&) + noexcept( + (!allocator_type::propagate_on_container_swap::value || + __is_nothrow_swappable<allocator_type>::value) && + __is_nothrow_swappable<hasher>::value && + __is_nothrow_swappable<key_equal>::value); + + hasher hash_function() const; + key_equal key_eq() const; + + iterator find(const key_type& k); + const_iterator find(const key_type& k) const; + size_type count(const key_type& k) const; + pair<iterator, iterator> equal_range(const key_type& k); + pair<const_iterator, const_iterator> equal_range(const key_type& k) const; + + mapped_type& operator[](const key_type& k); + mapped_type& operator[](key_type&& k); + + mapped_type& at(const key_type& k); + const mapped_type& at(const key_type& k) const; + + size_type bucket_count() const noexcept; + size_type max_bucket_count() const noexcept; + + size_type bucket_size(size_type n) const; + size_type bucket(const key_type& k) const; + + local_iterator begin(size_type n); + local_iterator end(size_type n); + const_local_iterator begin(size_type n) const; + const_local_iterator end(size_type n) const; + const_local_iterator cbegin(size_type n) const; + const_local_iterator cend(size_type n) const; + + float load_factor() const noexcept; + float max_load_factor() const noexcept; + void max_load_factor(float z); + void rehash(size_type n); + void reserve(size_type n); +}; + +*/ + +template <class Key, class Value, class KeyOfValue, unsigned int Options = 0, class Hash = hash<Key>, class Pred = equal_to<Key>, + class Alloc = allocator<Value> > +class hash_table +{ +public: + // types + typedef Value key_type; + typedef key_type value_type; + typedef Hash hasher; + typedef Pred key_equal; + typedef Alloc allocator_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef typename allocator_traits<allocator_type>::pointer pointer; + typedef typename allocator_traits<allocator_type>::const_pointer const_pointer; + typedef typename allocator_traits<allocator_type>::size_type size_type; + typedef typename allocator_traits<allocator_type>::difference_type difference_type; + + typedef /unspecified/ iterator; + typedef /unspecified/ const_iterator; + typedef /unspecified/ local_iterator; + typedef /unspecified/ const_local_iterator; + + hash_set() + noexcept( + is_nothrow_default_constructible<hasher>::value && + is_nothrow_default_constructible<key_equal>::value && + is_nothrow_default_constructible<allocator_type>::value); + explicit hash_set(size_type n, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template <class InputIterator> + hash_set(InputIterator f, InputIterator l, + size_type n = 0, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + explicit hash_set(const allocator_type&); + hash_set(const hash_set&); + hash_set(const hash_set&, const Allocator&); + hash_set(hash_set&&) + noexcept( + is_nothrow_move_constructible<hasher>::value && + is_nothrow_move_constructible<key_equal>::value && + is_nothrow_move_constructible<allocator_type>::value); + hash_set(hash_set&&, const Allocator&); + hash_set(initializer_list<value_type>, size_type n = 0, + const hasher& hf = hasher(), const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + ~hash_set(); + hash_set& operator=(const hash_set&); + hash_set& operator=(hash_set&&) + noexcept( + allocator_type::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<allocator_type>::value && + is_nothrow_move_assignable<hasher>::value && + is_nothrow_move_assignable<key_equal>::value); + hash_set& operator=(initializer_list<value_type>); + + allocator_type get_allocator() const noexcept; + + bool empty() const noexcept; + size_type size() const noexcept; + size_type max_size() const noexcept; + + iterator begin() noexcept; + iterator end() noexcept; + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + template <class... Args> + pair<iterator, bool> emplace(Args&&... args); + template <class... Args> + iterator emplace_hint(const_iterator position, Args&&... args); + pair<iterator, bool> insert(const value_type& obj); + pair<iterator, bool> insert(value_type&& obj); + iterator insert(const_iterator hint, const value_type& obj); + iterator insert(const_iterator hint, value_type&& obj); + template <class InputIterator> + void insert(InputIterator first, InputIterator last); + void insert(initializer_list<value_type>); + + iterator erase(const_iterator position); + size_type erase(const key_type& k); + iterator erase(const_iterator first, const_iterator last); + void clear() noexcept; + + void swap(hash_set&) + noexcept( + (!allocator_type::propagate_on_container_swap::value || + __is_nothrow_swappable<allocator_type>::value) && + __is_nothrow_swappable<hasher>::value && + __is_nothrow_swappable<key_equal>::value); + + hasher hash_function() const; + key_equal key_eq() const; + + iterator find(const key_type& k); + const_iterator find(const key_type& k) const; + size_type count(const key_type& k) const; + pair<iterator, iterator> equal_range(const key_type& k); + pair<const_iterator, const_iterator> equal_range(const key_type& k) const; + + size_type bucket_count() const noexcept; + size_type max_bucket_count() const noexcept; + + size_type bucket_size(size_type n) const; + size_type bucket(const key_type& k) const; + + local_iterator begin(size_type n); + local_iterator end(size_type n); + const_local_iterator begin(size_type n) const; + const_local_iterator end(size_type n) const; + const_local_iterator cbegin(size_type n) const; + const_local_iterator cend(size_type n) const; + + float load_factor() const noexcept; + float max_load_factor() const noexcept; + void max_load_factor(float z); + void rehash(size_type n); + void reserve(size_type n); +}; diff --git a/boost/container/detail/iterators.hpp b/boost/container/detail/iterators.hpp index 374b55c836..0dabd3c73e 100644 --- a/boost/container/detail/iterators.hpp +++ b/boost/container/detail/iterators.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. +// (C) Copyright Ion Gaztanaga 2005-2013. // (C) Copyright Gennaro Prota 2003 - 2004. // // Distributed under the Boost Software License, Version 1.0. @@ -14,18 +14,20 @@ #ifndef BOOST_CONTAINER_DETAIL_ITERATORS_HPP #define BOOST_CONTAINER_DETAIL_ITERATORS_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" +#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> -#include <boost/move/move.hpp> #include <boost/container/allocator_traits.hpp> +#include <boost/container/detail/type_traits.hpp> +#include <boost/static_assert.hpp> +#include <boost/move/utility_core.hpp> +#include <boost/intrusive/detail/reverse_iterator.hpp> #ifdef BOOST_CONTAINER_PERFECT_FORWARDING #include <boost/container/detail/variadic_templates_tools.hpp> -#include <boost/container/detail/stored_ref.hpp> #else #include <boost/container/detail/preprocessor.hpp> #endif @@ -52,7 +54,7 @@ class constant_iterator constant_iterator& operator++() { increment(); return *this; } - + constant_iterator operator++(int) { constant_iterator result (*this); @@ -62,7 +64,7 @@ class constant_iterator constant_iterator& operator--() { decrement(); return *this; } - + constant_iterator operator--(int) { constant_iterator result (*this); @@ -114,7 +116,7 @@ class constant_iterator const T& operator*() const { return dereference(); } - const T& operator[] (Difference n) const + const T& operator[] (Difference ) const { return dereference(); } const T* operator->() const @@ -146,90 +148,199 @@ class constant_iterator { return m_num - other.m_num; } }; -template <class T, class Difference = std::ptrdiff_t> -class default_construct_iterator +template <class T, class Difference> +class value_init_construct_iterator : public std::iterator <std::random_access_iterator_tag, T, Difference, const T*, const T &> { - typedef default_construct_iterator<T, Difference> this_type; + typedef value_init_construct_iterator<T, Difference> this_type; public: - explicit default_construct_iterator(Difference range_size) + explicit value_init_construct_iterator(Difference range_size) : m_num(range_size){} //Constructors - default_construct_iterator() + value_init_construct_iterator() : m_num(0){} - default_construct_iterator& operator++() + value_init_construct_iterator& operator++() { increment(); return *this; } - - default_construct_iterator operator++(int) + + value_init_construct_iterator operator++(int) { - default_construct_iterator result (*this); + value_init_construct_iterator result (*this); increment(); return result; } - default_construct_iterator& operator--() + value_init_construct_iterator& operator--() { decrement(); return *this; } - - default_construct_iterator operator--(int) + + value_init_construct_iterator operator--(int) { - default_construct_iterator result (*this); + value_init_construct_iterator result (*this); decrement(); return result; } - friend bool operator== (const default_construct_iterator& i, const default_construct_iterator& i2) + friend bool operator== (const value_init_construct_iterator& i, const value_init_construct_iterator& i2) { return i.equal(i2); } - friend bool operator!= (const default_construct_iterator& i, const default_construct_iterator& i2) + friend bool operator!= (const value_init_construct_iterator& i, const value_init_construct_iterator& i2) { return !(i == i2); } - friend bool operator< (const default_construct_iterator& i, const default_construct_iterator& i2) + friend bool operator< (const value_init_construct_iterator& i, const value_init_construct_iterator& i2) { return i.less(i2); } - friend bool operator> (const default_construct_iterator& i, const default_construct_iterator& i2) + friend bool operator> (const value_init_construct_iterator& i, const value_init_construct_iterator& i2) { return i2 < i; } - friend bool operator<= (const default_construct_iterator& i, const default_construct_iterator& i2) + friend bool operator<= (const value_init_construct_iterator& i, const value_init_construct_iterator& i2) { return !(i > i2); } - friend bool operator>= (const default_construct_iterator& i, const default_construct_iterator& i2) + friend bool operator>= (const value_init_construct_iterator& i, const value_init_construct_iterator& i2) { return !(i < i2); } - friend Difference operator- (const default_construct_iterator& i, const default_construct_iterator& i2) + friend Difference operator- (const value_init_construct_iterator& i, const value_init_construct_iterator& i2) { return i2.distance_to(i); } //Arithmetic - default_construct_iterator& operator+=(Difference off) + value_init_construct_iterator& operator+=(Difference off) { this->advance(off); return *this; } - default_construct_iterator operator+(Difference off) const + value_init_construct_iterator operator+(Difference off) const { - default_construct_iterator other(*this); + value_init_construct_iterator other(*this); other.advance(off); return other; } - friend default_construct_iterator operator+(Difference off, const default_construct_iterator& right) + friend value_init_construct_iterator operator+(Difference off, const value_init_construct_iterator& right) { return right + off; } - default_construct_iterator& operator-=(Difference off) + value_init_construct_iterator& operator-=(Difference off) { this->advance(-off); return *this; } - default_construct_iterator operator-(Difference off) const + value_init_construct_iterator operator-(Difference off) const { return *this + (-off); } - const T& operator*() const - { return dereference(); } + //This pseudo-iterator's dereference operations have no sense since value is not + //constructed until ::boost::container::construct_in_place is called. + //So comment them to catch bad uses + //const T& operator*() const; + //const T& operator[](difference_type) const; + //const T* operator->() const; - const T* operator->() const - { return &(dereference()); } + private: + Difference m_num; - const T& operator[] (Difference n) const - { return dereference(); } + 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 + { + static T dummy; + return dummy; + } + + void advance(Difference n) + { m_num -= n; } + + Difference distance_to(const this_type &other)const + { return m_num - other.m_num; } +}; + +template <class T, class Difference> +class default_init_construct_iterator + : public std::iterator + <std::random_access_iterator_tag, T, Difference, const T*, const T &> +{ + typedef default_init_construct_iterator<T, Difference> this_type; + + public: + explicit default_init_construct_iterator(Difference range_size) + : m_num(range_size){} + + //Constructors + default_init_construct_iterator() + : m_num(0){} + + default_init_construct_iterator& operator++() + { increment(); return *this; } + + default_init_construct_iterator operator++(int) + { + default_init_construct_iterator result (*this); + increment(); + return result; + } + + default_init_construct_iterator& operator--() + { decrement(); return *this; } + + default_init_construct_iterator operator--(int) + { + default_init_construct_iterator result (*this); + decrement(); + return result; + } + + friend bool operator== (const default_init_construct_iterator& i, const default_init_construct_iterator& i2) + { return i.equal(i2); } + + friend bool operator!= (const default_init_construct_iterator& i, const default_init_construct_iterator& i2) + { return !(i == i2); } + + friend bool operator< (const default_init_construct_iterator& i, const default_init_construct_iterator& i2) + { return i.less(i2); } + + friend bool operator> (const default_init_construct_iterator& i, const default_init_construct_iterator& i2) + { return i2 < i; } + + friend bool operator<= (const default_init_construct_iterator& i, const default_init_construct_iterator& i2) + { return !(i > i2); } + + friend bool operator>= (const default_init_construct_iterator& i, const default_init_construct_iterator& i2) + { return !(i < i2); } + + friend Difference operator- (const default_init_construct_iterator& i, const default_init_construct_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + default_init_construct_iterator& operator+=(Difference off) + { this->advance(off); return *this; } + + default_init_construct_iterator operator+(Difference off) const + { + default_init_construct_iterator other(*this); + other.advance(off); + return other; + } + + friend default_init_construct_iterator operator+(Difference off, const default_init_construct_iterator& right) + { return right + off; } + + default_init_construct_iterator& operator-=(Difference off) + { this->advance(-off); return *this; } + + default_init_construct_iterator operator-(Difference off) const + { return *this + (-off); } + + //This pseudo-iterator's dereference operations have no sense since value is not + //constructed until ::boost::container::construct_in_place is called. + //So comment them to catch bad uses + //const T& operator*() const; + //const T& operator[](difference_type) const; + //const T* operator->() const; private: Difference m_num; @@ -259,6 +370,7 @@ class default_construct_iterator { return m_num - other.m_num; } }; + template <class T, class Difference = std::ptrdiff_t> class repeat_iterator : public std::iterator @@ -275,7 +387,7 @@ class repeat_iterator this_type& operator++() { increment(); return *this; } - + this_type operator++(int) { this_type result (*this); @@ -285,7 +397,7 @@ class repeat_iterator this_type& operator--() { increment(); return *this; } - + this_type operator--(int) { this_type result (*this); @@ -337,7 +449,7 @@ class repeat_iterator T& operator*() const { return dereference(); } - T& operator[] (Difference n) const + T& operator[] (Difference ) const { return dereference(); } T *operator->() const @@ -386,7 +498,7 @@ class emplace_iterator this_type& operator++() { increment(); return *this; } - + this_type operator++(int) { this_type result (*this); @@ -396,7 +508,7 @@ class emplace_iterator this_type& operator--() { decrement(); return *this; } - + this_type operator--(int) { this_type result (*this); @@ -445,14 +557,12 @@ class emplace_iterator this_type operator-(difference_type off) const { return *this + (-off); } - const T& operator*() const - { return dereference(); } - - const T& operator[](difference_type) const - { return dereference(); } - - const T* operator->() const - { return &(dereference()); } + //This pseudo-iterator's dereference operations have no sense since value is not + //constructed until ::boost::container::construct_in_place is called. + //So comment them to catch bad uses + //const T& operator*() const; + //const T& operator[](difference_type) const; + //const T* operator->() const; template<class A> void construct_in_place(A &a, T* ptr) @@ -506,8 +616,7 @@ struct emplace_functor void inplace_impl(A &a, T* ptr, const container_detail::index_tuple<IdxPack...>&) { allocator_traits<A>::construct - (a, ptr, container_detail::stored_ref<Args>::forward - (container_detail::get<IdxPack>(args_))...); + (a, ptr, ::boost::forward<Args>(container_detail::get<IdxPack>(args_))...); } container_detail::tuple<Args&...> args_; @@ -539,10 +648,174 @@ struct emplace_functor #endif +namespace container_detail { + +template<class T> +struct has_iterator_category +{ + template <typename X> + static char test(int, typename X::iterator_category*); + + template <typename X> + static int test(int, ...); + + static const bool value = (1 == sizeof(test<T>(0, 0))); +}; + + +template<class T, bool = has_iterator_category<T>::value > +struct is_input_iterator +{ + static const bool value = is_same<typename T::iterator_category, std::input_iterator_tag>::value; +}; + +template<class T> +struct is_input_iterator<T, false> +{ + static const bool value = false; +}; + +template<class T, bool = has_iterator_category<T>::value > +struct is_forward_iterator +{ + static const bool value = is_same<typename T::iterator_category, std::forward_iterator_tag>::value; +}; + +template<class T> +struct is_forward_iterator<T, false> +{ + static const bool value = false; +}; + +template<class T, bool = has_iterator_category<T>::value > +struct is_bidirectional_iterator +{ + static const bool value = is_same<typename T::iterator_category, std::bidirectional_iterator_tag>::value; +}; + +template<class T> +struct is_bidirectional_iterator<T, false> +{ + static const bool value = false; +}; + +template<class IINodeType> +struct iiterator_node_value_type { + typedef typename IINodeType::value_type type; +}; + +template<class IIterator> +struct iiterator_types +{ + typedef typename IIterator::value_type it_value_type; + typedef typename iiterator_node_value_type<it_value_type>::type value_type; + typedef typename std::iterator_traits<IIterator>::pointer it_pointer; + typedef typename std::iterator_traits<IIterator>::difference_type difference_type; + typedef typename ::boost::intrusive::pointer_traits<it_pointer>:: + template rebind_pointer<value_type>::type pointer; + typedef typename ::boost::intrusive::pointer_traits<it_pointer>:: + template rebind_pointer<const value_type>::type const_pointer; + typedef typename ::boost::intrusive:: + pointer_traits<pointer>::reference reference; + typedef typename ::boost::intrusive:: + pointer_traits<const_pointer>::reference const_reference; + typedef typename IIterator::iterator_category iterator_category; +}; + +template<class IIterator, bool IsConst> +struct std_iterator +{ + typedef typename std::iterator + < typename iiterator_types<IIterator>::iterator_category + , typename iiterator_types<IIterator>::value_type + , typename iiterator_types<IIterator>::difference_type + , typename iiterator_types<IIterator>::const_pointer + , typename iiterator_types<IIterator>::const_reference> type; +}; + +template<class IIterator> +struct std_iterator<IIterator, false> +{ + typedef typename std::iterator + < typename iiterator_types<IIterator>::iterator_category + , typename iiterator_types<IIterator>::value_type + , typename iiterator_types<IIterator>::difference_type + , typename iiterator_types<IIterator>::pointer + , typename iiterator_types<IIterator>::reference> type; +}; + +template<class IIterator, bool IsConst> +class iterator +{ + typedef typename std_iterator<IIterator, IsConst>::type types_t; + + public: + typedef typename types_t::pointer pointer; + typedef typename types_t::reference reference; + typedef typename types_t::difference_type difference_type; + typedef typename types_t::iterator_category iterator_category; + typedef typename types_t::value_type value_type; + + iterator() + {} + + explicit iterator(IIterator iit) BOOST_CONTAINER_NOEXCEPT + : m_iit(iit) + {} + + iterator(iterator<IIterator, false> const& other) BOOST_CONTAINER_NOEXCEPT + : m_iit(other.get()) + {} + + iterator& operator++() BOOST_CONTAINER_NOEXCEPT + { ++this->m_iit; return *this; } + + iterator operator++(int) BOOST_CONTAINER_NOEXCEPT + { + iterator result (*this); + ++this->m_iit; + return result; + } + + iterator& operator--() BOOST_CONTAINER_NOEXCEPT + { + //If the iterator is not a bidirectional iterator, operator-- should not exist + BOOST_STATIC_ASSERT((is_bidirectional_iterator<iterator>::value)); + --this->m_iit; return *this; + } + + iterator operator--(int) BOOST_CONTAINER_NOEXCEPT + { + iterator result (*this); + --this->m_iit; + return result; + } + + friend bool operator== (const iterator& l, const iterator& r) BOOST_CONTAINER_NOEXCEPT + { return l.m_iit == r.m_iit; } + + friend bool operator!= (const iterator& l, const iterator& r) BOOST_CONTAINER_NOEXCEPT + { return !(l == r); } + + reference operator*() const BOOST_CONTAINER_NOEXCEPT + { return (*this->m_iit).get_data(); } + + pointer operator->() const BOOST_CONTAINER_NOEXCEPT + { return ::boost::intrusive::pointer_traits<pointer>::pointer_to(this->operator*()); } + + const IIterator &get() const BOOST_CONTAINER_NOEXCEPT + { return this->m_iit; } + + private: + IIterator m_iit; +}; + +using ::boost::intrusive::detail::reverse_iterator; + +} //namespace container_detail { } //namespace container { } //namespace boost { #include <boost/container/detail/config_end.hpp> #endif //#ifndef BOOST_CONTAINER_DETAIL_ITERATORS_HPP - diff --git a/boost/container/detail/math_functions.hpp b/boost/container/detail/math_functions.hpp index fe8386be69..6853b9c59f 100644 --- a/boost/container/detail/math_functions.hpp +++ b/boost/container/detail/math_functions.hpp @@ -1,7 +1,7 @@ ////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Stephen Cleary 2000. -// (C) Copyright Ion Gaztanaga 2007-2012. +// (C) Copyright Ion Gaztanaga 2007-2013. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -16,7 +16,13 @@ #ifndef BOOST_CONTAINER_DETAIL_MATH_FUNCTIONS_HPP #define BOOST_CONTAINER_DETAIL_MATH_FUNCTIONS_HPP -#include "config_begin.hpp" +#if defined(_MSC_VER) +# pragma once +#endif + +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> + #include <climits> #include <boost/static_assert.hpp> @@ -94,7 +100,7 @@ inline std::size_t floor_log2 (std::size_t x) std::size_t n = x; std::size_t log2 = 0; - + for(std::size_t shift = Bits >> 1; shift; shift >>= 1){ std::size_t tmp = n >> shift; if (tmp) diff --git a/boost/container/detail/memory_util.hpp b/boost/container/detail/memory_util.hpp index c00172c60c..7f055cb55b 100644 --- a/boost/container/detail/memory_util.hpp +++ b/boost/container/detail/memory_util.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2011-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,26 +11,28 @@ #ifndef BOOST_CONTAINER_ALLOCATOR_MEMORY_UTIL_HPP #define BOOST_CONTAINER_ALLOCATOR_MEMORY_UTIL_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif #include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> + #include <boost/container/detail/preprocessor.hpp> +#include <boost/intrusive/detail/mpl.hpp> #include <boost/intrusive/detail/has_member_function_callable_with.hpp> #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME allocate #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEGIN namespace boost { namespace container { namespace container_detail { #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} -#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, 2, <boost/intrusive/detail/has_member_function_callable_with.hpp>)) +#define BOOST_PP_ITERATION_PARAMS_1 (3, (2, 2, <boost/intrusive/detail/has_member_function_callable_with.hpp>)) #include BOOST_PP_ITERATE() #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME destroy #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEGIN namespace boost { namespace container { namespace container_detail { #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} -#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, 3, <boost/intrusive/detail/has_member_function_callable_with.hpp>)) +#define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 1, <boost/intrusive/detail/has_member_function_callable_with.hpp>)) #include BOOST_PP_ITERATE() #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME max_size @@ -48,14 +50,23 @@ #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME construct #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEGIN namespace boost { namespace container { namespace container_detail { #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} -#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS+1, <boost/intrusive/detail/has_member_function_callable_with.hpp>)) +#ifdef BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_SINGLE_ITERATION +# define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 1, <boost/intrusive/detail/has_member_function_callable_with.hpp>)) +#else +# define BOOST_PP_ITERATION_PARAMS_1 (3, (1, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS+1, <boost/intrusive/detail/has_member_function_callable_with.hpp>)) +#endif +#include BOOST_PP_ITERATE() + +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME swap +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEGIN namespace boost { namespace container { namespace container_detail { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 1, <boost/intrusive/detail/has_member_function_callable_with.hpp>)) #include BOOST_PP_ITERATE() namespace boost { namespace container { namespace container_detail { - BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(pointer) BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(const_pointer) BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(reference) @@ -67,6 +78,8 @@ BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(propagate_on_container_copy_assig BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment) BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(propagate_on_container_swap) BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(difference_type) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(value_compare) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(wrapped_value_compare) } //namespace container_detail { } //namespace container { diff --git a/boost/container/detail/mpl.hpp b/boost/container/detail/mpl.hpp index 74a1ce0e67..ceac52a371 100644 --- a/boost/container/detail/mpl.hpp +++ b/boost/container/detail/mpl.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. +// (C) Copyright Ion Gaztanaga 2005-2013. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -13,10 +13,13 @@ #ifndef BOOST_CONTAINER_CONTAINER_DETAIL_MPL_HPP #define BOOST_CONTAINER_CONTAINER_DETAIL_MPL_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> + #include <cstddef> namespace boost { @@ -66,18 +69,32 @@ struct disable_if : public enable_if_c<!Cond::value, T> {}; template <bool B, class T = void> struct disable_if_c : public enable_if_c<!B, T> {}; +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + +template <class T, class U> +struct is_convertible +{ + static const bool value = __is_convertible_to(T, U); +}; + +#else + template <class T, class U> class is_convertible { typedef char true_t; class false_t { char dummy[2]; }; - static true_t dispatch(U); + //use any_conversion as first parameter since in MSVC + //overaligned types can't go through ellipsis static false_t dispatch(...); - static T trigger(); + static true_t dispatch(U); + static T &trigger(); public: - enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) }; + static const bool value = sizeof(dispatch(trigger())) == sizeof(true_t); }; +#endif + template< bool C , typename T1 @@ -110,8 +127,10 @@ struct if_ template <class Pair> struct select1st -// : public std::unary_function<Pair, typename Pair::first_type> { + typedef Pair argument_type; + typedef typename Pair::first_type result_type; + template<class OtherPair> const typename Pair::first_type& operator()(const OtherPair& x) const { return x.first; } @@ -123,8 +142,10 @@ struct select1st // identity is an extension: it is not part of the standard. template <class T> struct identity -// : public std::unary_function<T,T> { + typedef T argument_type; + typedef T result_type; + typedef T type; const T& operator()(const T& x) const { return x; } @@ -156,5 +177,7 @@ template <> struct unvoid<const void> { struct type { }; }; } //namespace container { } //namespace boost { +#include <boost/container/detail/config_end.hpp> + #endif //#ifndef BOOST_CONTAINER_CONTAINER_DETAIL_MPL_HPP diff --git a/boost/container/detail/multiallocation_chain.hpp b/boost/container/detail/multiallocation_chain.hpp index c9952535eb..96f6202671 100644 --- a/boost/container/detail/multiallocation_chain.hpp +++ b/boost/container/detail/multiallocation_chain.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,7 +11,13 @@ #ifndef BOOST_CONTAINER_DETAIL_MULTIALLOCATION_CHAIN_HPP #define BOOST_CONTAINER_DETAIL_MULTIALLOCATION_CHAIN_HPP -#include "config_begin.hpp" +#if defined(_MSC_VER) +# pragma once +#endif + +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> + #include <boost/container/container_fwd.hpp> #include <boost/container/detail/utilities.hpp> #include <boost/container/detail/type_traits.hpp> @@ -19,7 +25,7 @@ #include <boost/intrusive/slist.hpp> #include <boost/intrusive/pointer_traits.hpp> #include <boost/type_traits/make_unsigned.hpp> -#include <boost/move/move.hpp> +#include <boost/move/utility_core.hpp> namespace boost { namespace container { @@ -45,30 +51,43 @@ class basic_multiallocation_chain > slist_impl_t; slist_impl_t slist_impl_; - static node & to_node(VoidPointer p) - { return *static_cast<node*>(static_cast<void*>(container_detail::to_raw_pointer(p))); } + typedef typename boost::intrusive::pointer_traits + <VoidPointer>::template rebind_pointer<node>::type node_ptr; + typedef typename boost::intrusive:: + pointer_traits<node_ptr> node_ptr_traits; + + static node & to_node(const VoidPointer &p) + { return *static_cast<node*>(static_cast<void*>(container_detail::to_raw_pointer(p))); } + + static VoidPointer from_node(node &n) + { return node_ptr_traits::pointer_to(n); } + + static node_ptr to_node_ptr(const VoidPointer &p) + { return node_ptr_traits::static_cast_from(p); } BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_multiallocation_chain) public: - - typedef VoidPointer void_pointer; - typedef typename slist_impl_t::iterator iterator; - typedef typename slist_impl_t::size_type size_type; + typedef VoidPointer void_pointer; + typedef typename slist_impl_t::iterator iterator; + typedef typename slist_impl_t::size_type size_type; basic_multiallocation_chain() : slist_impl_() {} + basic_multiallocation_chain(const void_pointer &b, const void_pointer &before_e, size_type n) + : slist_impl_(to_node_ptr(b), to_node_ptr(before_e), n) + {} + basic_multiallocation_chain(BOOST_RV_REF(basic_multiallocation_chain) other) - : slist_impl_() - { slist_impl_.swap(other.slist_impl_); } + : slist_impl_(::boost::move(other.slist_impl_)) + {} basic_multiallocation_chain& operator=(BOOST_RV_REF(basic_multiallocation_chain) other) { - basic_multiallocation_chain tmp(boost::move(other)); - this->swap(tmp); + slist_impl_ = ::boost::move(other.slist_impl_); return *this; } @@ -96,37 +115,52 @@ class basic_multiallocation_chain iterator insert_after(iterator it, void_pointer m) { return slist_impl_.insert_after(it, to_node(m)); } - void push_front(void_pointer m) - { return slist_impl_.push_front(to_node(m)); } + void push_front(const void_pointer &m) + { return slist_impl_.push_front(to_node(m)); } - void push_back(void_pointer m) + void push_back(const void_pointer &m) { return slist_impl_.push_back(to_node(m)); } - void pop_front() - { return slist_impl_.pop_front(); } - - void *front() - { return &*slist_impl_.begin(); } - - void splice_after(iterator after_this, basic_multiallocation_chain &x, iterator before_begin, iterator before_end) - { slist_impl_.splice_after(after_this, x.slist_impl_, before_begin, before_end); } + void_pointer pop_front() + { + node & n = slist_impl_.front(); + void_pointer ret = from_node(n); + slist_impl_.pop_front(); + return ret; + } - void splice_after(iterator after_this, basic_multiallocation_chain &x, iterator before_begin, iterator before_end, size_type n) - { slist_impl_.splice_after(after_this, x.slist_impl_, before_begin, before_end, n); } + void splice_after(iterator after_this, basic_multiallocation_chain &x, iterator before_b, iterator before_e, size_type n) + { slist_impl_.splice_after(after_this, x.slist_impl_, before_b, before_e, n); } void splice_after(iterator after_this, basic_multiallocation_chain &x) { slist_impl_.splice_after(after_this, x.slist_impl_); } - void incorporate_after(iterator after_this, void_pointer begin , iterator before_end) - { slist_impl_.incorporate_after(after_this, &to_node(begin), &to_node(before_end)); } + void erase_after(iterator before_b, iterator e, size_type n) + { slist_impl_.erase_after(before_b, e, n); } - void incorporate_after(iterator after_this, void_pointer begin, void_pointer before_end, size_type n) - { slist_impl_.incorporate_after(after_this, &to_node(begin), &to_node(before_end), n); } + void_pointer incorporate_after(iterator after_this, const void_pointer &b, size_type unit_bytes, size_type num_units) + { + typedef typename boost::intrusive::pointer_traits<char_ptr> char_pointer_traits; + char_ptr elem = char_pointer_traits::static_cast_from(b); + if(num_units){ + char_ptr prev_elem = elem; + elem += unit_bytes; + for(size_type i = 0; i != num_units-1; ++i, elem += unit_bytes){ + ::new (container_detail::to_raw_pointer(prev_elem)) void_pointer(elem); + prev_elem = elem; + } + slist_impl_.incorporate_after(after_this, to_node_ptr(b), to_node_ptr(prev_elem), num_units); + } + return elem; + } + + void incorporate_after(iterator after_this, void_pointer b, void_pointer before_e, size_type n) + { slist_impl_.incorporate_after(after_this, to_node_ptr(b), to_node_ptr(before_e), n); } void swap(basic_multiallocation_chain &x) { slist_impl_.swap(x.slist_impl_); } - static iterator iterator_to(void_pointer p) + static iterator iterator_to(const void_pointer &p) { return slist_impl_t::s_iterator_to(to_node(p)); } std::pair<void_pointer, void_pointer> extract_data() @@ -150,72 +184,75 @@ struct cast_functor template<class MultiallocationChain, class T> class transform_multiallocation_chain + : public MultiallocationChain { private: BOOST_MOVABLE_BUT_NOT_COPYABLE(transform_multiallocation_chain) + //transform_multiallocation_chain(const transform_multiallocation_chain &); + //transform_multiallocation_chain & operator=(const transform_multiallocation_chain &); - MultiallocationChain holder_; typedef typename MultiallocationChain::void_pointer void_pointer; typedef typename boost::intrusive::pointer_traits - <void_pointer>::template rebind_pointer<T>::type pointer; + <void_pointer> void_pointer_traits; + typedef typename void_pointer_traits::template + rebind_pointer<T>::type pointer; + typedef typename boost::intrusive::pointer_traits + <pointer> pointer_traits; - static pointer cast(void_pointer p) - { - return pointer(static_cast<T*>(container_detail::to_raw_pointer(p))); - } + static pointer cast(const void_pointer &p) + { return pointer_traits::static_cast_from(p); } public: typedef transform_iterator < typename MultiallocationChain::iterator - , container_detail::cast_functor <T> > iterator; - typedef typename MultiallocationChain::size_type size_type; + , container_detail::cast_functor <T> > iterator; + typedef typename MultiallocationChain::size_type size_type; transform_multiallocation_chain() - : holder_() + : MultiallocationChain() {} transform_multiallocation_chain(BOOST_RV_REF(transform_multiallocation_chain) other) - : holder_() - { this->swap(other); } + : MultiallocationChain(::boost::move(static_cast<MultiallocationChain&>(other))) + {} transform_multiallocation_chain(BOOST_RV_REF(MultiallocationChain) other) - : holder_(boost::move(other)) + : MultiallocationChain(::boost::move(static_cast<MultiallocationChain&>(other))) {} transform_multiallocation_chain& operator=(BOOST_RV_REF(transform_multiallocation_chain) other) { - transform_multiallocation_chain tmp(boost::move(other)); - this->swap(tmp); - return *this; + return static_cast<MultiallocationChain&> + (this->MultiallocationChain::operator=(::boost::move(static_cast<MultiallocationChain&>(other)))); } - - void push_front(pointer mem) +/* + void push_front(const pointer &mem) { holder_.push_front(mem); } + void push_back(const pointer &mem) + { return holder_.push_back(mem); } + void swap(transform_multiallocation_chain &other_chain) { holder_.swap(other_chain.holder_); } - void splice_after(iterator after_this, transform_multiallocation_chain &x, iterator before_begin, iterator before_end, size_type n) - { holder_.splice_after(after_this.base(), x.holder_, before_begin.base(), before_end.base(), n); } - - void incorporate_after(iterator after_this, void_pointer begin, void_pointer before_end, size_type n) - { holder_.incorporate_after(after_this.base(), begin, before_end, n); } - - void pop_front() - { holder_.pop_front(); } - - pointer front() - { return cast(holder_.front()); } + void splice_after(iterator after_this, transform_multiallocation_chain &x, iterator before_b, iterator before_e, size_type n) + { holder_.splice_after(after_this.base(), x.holder_, before_b.base(), before_e.base(), n); } + void incorporate_after(iterator after_this, pointer b, pointer before_e, size_type n) + { holder_.incorporate_after(after_this.base(), b, before_e, n); } +*/ + pointer pop_front() + { return cast(this->MultiallocationChain::pop_front()); } +/* bool empty() const { return holder_.empty(); } iterator before_begin() { return iterator(holder_.before_begin()); } - +*/ iterator begin() - { return iterator(holder_.begin()); } - + { return iterator(this->MultiallocationChain::begin()); } +/* iterator end() { return iterator(holder_.end()); } @@ -227,20 +264,21 @@ class transform_multiallocation_chain void clear() { holder_.clear(); } - +*/ iterator insert_after(iterator it, pointer m) - { return iterator(holder_.insert_after(it.base(), m)); } + { return iterator(this->MultiallocationChain::insert_after(it.base(), m)); } - static iterator iterator_to(pointer p) + static iterator iterator_to(const pointer &p) { return iterator(MultiallocationChain::iterator_to(p)); } - std::pair<void_pointer, void_pointer> extract_data() - { return holder_.extract_data(); } - - MultiallocationChain extract_multiallocation_chain() + std::pair<pointer, pointer> extract_data() { - return MultiallocationChain(boost::move(holder_)); + std::pair<void_pointer, void_pointer> data(this->MultiallocationChain::extract_data()); + return std::pair<pointer, pointer>(cast(data.first), cast(data.second)); } +/* + MultiallocationChain &extract_multiallocation_chain() + { return holder_; }*/ }; }}} diff --git a/boost/container/detail/mutex.hpp b/boost/container/detail/mutex.hpp new file mode 100644 index 0000000000..c53afa1f42 --- /dev/null +++ b/boost/container/detail/mutex.hpp @@ -0,0 +1,284 @@ +// Copyright (C) 2000 Stephen Cleary +// +// 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 for updates, documentation, and revision history. + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_MUTEX_HPP +#define BOOST_CONTAINER_MUTEX_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +//#define BOOST_CONTAINER_NO_MT +//#define BOOST_CONTAINER_NO_SPINLOCKS + +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> + +// Extremely Light-Weight wrapper classes for OS thread synchronization + +#define BOOST_MUTEX_HELPER_NONE 0 +#define BOOST_MUTEX_HELPER_WIN32 1 +#define BOOST_MUTEX_HELPER_PTHREAD 2 +#define BOOST_MUTEX_HELPER_SPINLOCKS 3 + +#if !defined(BOOST_HAS_THREADS) && !defined(BOOST_NO_MT) +# define BOOST_NO_MT +#endif + +#if defined(BOOST_NO_MT) || defined(BOOST_CONTAINER_NO_MT) + // No multithreading -> make locks into no-ops + #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_NONE +#else + //Taken from dlmalloc + #if !defined(BOOST_CONTAINER_NO_SPINLOCKS) && \ + ((defined(__GNUC__) && \ + ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) || \ + defined(__i386__) || defined(__x86_64__))) || \ + (defined(_MSC_VER) && _MSC_VER>=1310)) + #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_SPINLOCKS + #endif + + #if defined(BOOST_WINDOWS) + #include <windows.h> + #ifndef BOOST_MUTEX_HELPER + #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_WIN32 + #endif + #elif defined(BOOST_HAS_UNISTD_H) + #include <unistd.h> + #if !defined(BOOST_MUTEX_HELPER) && (defined(_POSIX_THREADS) || defined(BOOST_HAS_PTHREADS)) + #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_PTHREAD + #endif + #endif +#endif + +#ifndef BOOST_MUTEX_HELPER + #error Unable to determine platform mutex type; #define BOOST_NO_MT to assume single-threaded +#endif + +#if BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_NONE + //... +#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_SPINLOCKS + #if defined(_MSC_VER) + #ifndef _M_AMD64 + /* These are already defined on AMD64 builds */ + #ifdef __cplusplus + extern "C" { + #endif /* __cplusplus */ + long __cdecl _InterlockedCompareExchange(long volatile *Dest, long Exchange, long Comp); + long __cdecl _InterlockedExchange(long volatile *Target, long Value); + #ifdef __cplusplus + } + #endif /* __cplusplus */ + #endif /* _M_AMD64 */ + #pragma intrinsic (_InterlockedCompareExchange) + #pragma intrinsic (_InterlockedExchange) + #define interlockedcompareexchange _InterlockedCompareExchange + #define interlockedexchange _InterlockedExchange + #elif defined(WIN32) && defined(__GNUC__) + #define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b) + #define interlockedexchange __sync_lock_test_and_set + #endif /* Win32 */ + + /* First, define CAS_LOCK and CLEAR_LOCK on ints */ + /* Note CAS_LOCK defined to return 0 on success */ + + #if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) + #define BOOST_CONTAINER_CAS_LOCK(sl) __sync_lock_test_and_set(sl, 1) + #define BOOST_CONTAINER_CLEAR_LOCK(sl) __sync_lock_release(sl) + + #elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) + /* Custom spin locks for older gcc on x86 */ + static FORCEINLINE int boost_container_x86_cas_lock(int *sl) { + int ret; + int val = 1; + int cmp = 0; + __asm__ __volatile__ ("lock; cmpxchgl %1, %2" + : "=a" (ret) + : "r" (val), "m" (*(sl)), "0"(cmp) + : "memory", "cc"); + return ret; + } + + static FORCEINLINE void boost_container_x86_clear_lock(int* sl) { + assert(*sl != 0); + int prev = 0; + int ret; + __asm__ __volatile__ ("lock; xchgl %0, %1" + : "=r" (ret) + : "m" (*(sl)), "0"(prev) + : "memory"); + } + + #define BOOST_CONTAINER_CAS_LOCK(sl) boost_container_x86_cas_lock(sl) + #define BOOST_CONTAINER_CLEAR_LOCK(sl) boost_container_x86_clear_lock(sl) + + #else /* Win32 MSC */ + #define BOOST_CONTAINER_CAS_LOCK(sl) interlockedexchange((long volatile*)sl, (long)1) + #define BOOST_CONTAINER_CLEAR_LOCK(sl) interlockedexchange((long volatile*)sl, (long)0) + #endif + + /* How to yield for a spin lock */ + #define SPINS_PER_YIELD 63 + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #define SLEEP_EX_DURATION 50 /* delay for yield/sleep */ + #define SPIN_LOCK_YIELD SleepEx(SLEEP_EX_DURATION, FALSE) + #elif defined (__SVR4) && defined (__sun) /* solaris */ + #include <thread.h> + #define SPIN_LOCK_YIELD thr_yield(); + #elif !defined(LACKS_SCHED_H) + #include <sched.h> + #define SPIN_LOCK_YIELD sched_yield(); + #else + #define SPIN_LOCK_YIELD + #endif /* ... yield ... */ + + #define BOOST_CONTAINER_SPINS_PER_YIELD 63 + inline int boost_interprocess_spin_acquire_lock(int *sl) { + int spins = 0; + while (*(volatile int *)sl != 0 || + BOOST_CONTAINER_CAS_LOCK(sl)) { + if ((++spins & BOOST_CONTAINER_SPINS_PER_YIELD) == 0) { + SPIN_LOCK_YIELD; + } + } + return 0; + } + #define BOOST_CONTAINER_MLOCK_T int + #define BOOST_CONTAINER_TRY_LOCK(sl) !BOOST_CONTAINER_CAS_LOCK(sl) + #define BOOST_CONTAINER_RELEASE_LOCK(sl) BOOST_CONTAINER_CLEAR_LOCK(sl) + #define BOOST_CONTAINER_ACQUIRE_LOCK(sl) (BOOST_CONTAINER_CAS_LOCK(sl)? boost_interprocess_spin_acquire_lock(sl) : 0) + #define BOOST_CONTAINER_INITIAL_LOCK(sl) (*sl = 0) + #define BOOST_CONTAINER_DESTROY_LOCK(sl) (0) +#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_WIN32 + // +#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_PTHREAD + #include <pthread.h> +#endif + +namespace boost { +namespace container { +namespace container_detail { + +#if BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_NONE + class null_mutex + { + private: + null_mutex(const null_mutex &); + void operator=(const null_mutex &); + + public: + null_mutex() { } + + static void lock() { } + static void unlock() { } + }; + + typedef null_mutex default_mutex; +#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_SPINLOCKS + + class spin_mutex + { + private: + BOOST_CONTAINER_MLOCK_T sl; + spin_mutex(const spin_mutex &); + void operator=(const spin_mutex &); + + public: + spin_mutex() { BOOST_CONTAINER_INITIAL_LOCK(&sl); } + + void lock() { BOOST_CONTAINER_ACQUIRE_LOCK(&sl); } + void unlock() { BOOST_CONTAINER_RELEASE_LOCK(&sl); } + }; + typedef spin_mutex default_mutex; +#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_WIN32 + class mutex + { + private: + CRITICAL_SECTION mtx; + + mutex(const mutex &); + void operator=(const mutex &); + + public: + mutex() + { InitializeCriticalSection(&mtx); } + + ~mutex() + { DeleteCriticalSection(&mtx); } + + void lock() + { EnterCriticalSection(&mtx); } + + void unlock() + { LeaveCriticalSection(&mtx); } + }; + + typedef mutex default_mutex; +#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_PTHREAD + class mutex + { + private: + pthread_mutex_t mtx; + + mutex(const mutex &); + void operator=(const mutex &); + + public: + mutex() + { pthread_mutex_init(&mtx, 0); } + + ~mutex() + { pthread_mutex_destroy(&mtx); } + + void lock() + { pthread_mutex_lock(&mtx); } + + void unlock() + { pthread_mutex_unlock(&mtx); } + }; + + typedef mutex default_mutex; +#endif + +template<class Mutex> +class scoped_lock +{ + public: + scoped_lock(Mutex &m) + : m_(m) + { m_.lock(); } + ~scoped_lock() + { m_.unlock(); } + + private: + Mutex &m_; +}; + +} // namespace container_detail +} // namespace container +} // namespace boost + +#undef BOOST_MUTEX_HELPER_WIN32 +#undef BOOST_MUTEX_HELPER_PTHREAD +#undef BOOST_MUTEX_HELPER_NONE +#undef BOOST_MUTEX_HELPER +#undef BOOST_MUTEX_HELPER_SPINLOCKS + +#include <boost/container/detail/config_end.hpp> + +#endif diff --git a/boost/container/detail/node_alloc_holder.hpp b/boost/container/detail/node_alloc_holder.hpp index 9797f1fbd5..250c559765 100644 --- a/boost/container/detail/node_alloc_holder.hpp +++ b/boost/container/detail/node_alloc_holder.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,163 +11,89 @@ #ifndef BOOST_CONTAINER_DETAIL_NODE_ALLOC_HPP_ #define BOOST_CONTAINER_DETAIL_NODE_ALLOC_HPP_ -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" +#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> #include <utility> #include <functional> -#include <boost/move/move.hpp> +#include <boost/move/utility_core.hpp> #include <boost/intrusive/options.hpp> #include <boost/container/detail/version_type.hpp> #include <boost/container/detail/type_traits.hpp> #include <boost/container/detail/utilities.hpp> #include <boost/container/allocator_traits.hpp> +#include <boost/container/detail/allocator_version_traits.hpp> #include <boost/container/detail/mpl.hpp> #include <boost/container/detail/destroyers.hpp> +#include <boost/container/detail/memory_util.hpp> +#include <boost/container/detail/placement_new.hpp> +#include <boost/core/no_exceptions_support.hpp> #ifndef BOOST_CONTAINER_PERFECT_FORWARDING #include <boost/container/detail/preprocessor.hpp> #endif #include <boost/container/detail/algorithms.hpp> -#include <new> + namespace boost { namespace container { namespace container_detail { -//!A deleter for scoped_ptr that deallocates the memory -//!allocated for an object using a STL allocator. -template <class A> -struct scoped_deallocator -{ - typedef allocator_traits<A> allocator_traits_type; - typedef typename allocator_traits_type::pointer pointer; - typedef container_detail::integral_constant<unsigned, - boost::container::container_detail:: - version<A>::value> alloc_version; - typedef container_detail::integral_constant<unsigned, 1> allocator_v1; - typedef container_detail::integral_constant<unsigned, 2> 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); } - - BOOST_MOVABLE_BUT_NOT_COPYABLE(scoped_deallocator) - - public: - - pointer m_ptr; - A& m_alloc; - - scoped_deallocator(pointer p, A& a) - : m_ptr(p), m_alloc(a) - {} - - ~scoped_deallocator() - { if (m_ptr)priv_deallocate(alloc_version()); } - - scoped_deallocator(BOOST_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 A> -class allocator_destroyer_and_chain_builder -{ - typedef allocator_traits<A> allocator_traits_type; - typedef typename allocator_traits_type::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) - { - allocator_traits<A>::destroy(a_, container_detail::to_raw_pointer(p)); - c_.push_front(p); - } -}; - -template <class A> -class allocator_multialloc_chain_node_deallocator -{ - typedef allocator_traits<A> allocator_traits_type; - typedef typename allocator_traits_type::value_type value_type; - typedef typename A::multiallocation_chain multiallocation_chain; - typedef allocator_destroyer_and_chain_builder<A> 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::move(c_)); - } -}; - template<class ValueCompare, class Node> struct node_compare : private ValueCompare { - typedef typename ValueCompare::key_type key_type; - typedef typename ValueCompare::value_type value_type; - typedef typename ValueCompare::key_of_value key_of_value; + typedef ValueCompare wrapped_value_compare; + typedef typename wrapped_value_compare::key_type key_type; + typedef typename wrapped_value_compare::value_type value_type; + typedef typename wrapped_value_compare::key_of_value key_of_value; + + explicit node_compare(const wrapped_value_compare &pred) + : wrapped_value_compare(pred) + {} - node_compare(const ValueCompare &pred) - : ValueCompare(pred) + node_compare() + : wrapped_value_compare() {} - ValueCompare &value_comp() - { return static_cast<ValueCompare &>(*this); } + wrapped_value_compare &value_comp() + { return static_cast<wrapped_value_compare &>(*this); } - ValueCompare &value_comp() const - { return static_cast<const ValueCompare &>(*this); } + wrapped_value_compare &value_comp() const + { return static_cast<const wrapped_value_compare &>(*this); } bool operator()(const Node &a, const Node &b) const - { return ValueCompare::operator()(a.get_data(), b.get_data()); } + { return wrapped_value_compare::operator()(a.get_data(), b.get_data()); } }; -template<class A, class ICont, class Pred = container_detail::nat> +template<class A, class ICont> struct node_alloc_holder { + //If the intrusive container is an associative container, obtain the predicate, which will + //be of type node_compare<>. If not an associative container value_compare will be a "nat" type. + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, ICont, + value_compare, container_detail::nat) intrusive_value_compare; + //In that case obtain the value predicate from the node predicate via wrapped_value_compare + //if intrusive_value_compare is node_compare<>, nat otherwise + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, ICont, + wrapped_value_compare, container_detail::nat) value_compare; + typedef allocator_traits<A> allocator_traits_type; - typedef node_alloc_holder<A, ICont> self_t; typedef typename allocator_traits_type::value_type value_type; + typedef ICont intrusive_container; typedef typename ICont::value_type Node; typedef typename allocator_traits_type::template portable_rebind_alloc<Node>::type NodeAlloc; typedef allocator_traits<NodeAlloc> node_allocator_traits_type; + typedef container_detail::allocator_version_traits<NodeAlloc> node_allocator_version_traits_type; typedef A ValAlloc; typedef typename node_allocator_traits_type::pointer NodePtr; typedef container_detail::scoped_deallocator<NodeAlloc> Deallocator; @@ -182,6 +108,7 @@ struct node_alloc_holder typedef typename ICont::const_iterator icont_citerator; typedef allocator_destroyer<NodeAlloc> Destroyer; typedef allocator_traits<NodeAlloc> NodeAllocTraits; + typedef allocator_version_traits<NodeAlloc> AllocVersionTraits; private: BOOST_COPYABLE_AND_MOVABLE(node_alloc_holder) @@ -206,25 +133,25 @@ struct node_alloc_holder { this->icont().swap(x.icont()); } //Constructors for associative containers - explicit node_alloc_holder(const ValAlloc &a, const Pred &c) + explicit node_alloc_holder(const ValAlloc &a, const value_compare &c) : members_(a, c) {} - explicit node_alloc_holder(const node_alloc_holder &x, const Pred &c) + explicit node_alloc_holder(const node_alloc_holder &x, const value_compare &c) : members_(NodeAllocTraits::select_on_container_copy_construction(x.node_alloc()), c) {} - explicit node_alloc_holder(const Pred &c) + explicit node_alloc_holder(const value_compare &c) : members_(c) {} //helpers for move assignments - explicit node_alloc_holder(BOOST_RV_REF(node_alloc_holder) x, const Pred &c) + explicit node_alloc_holder(BOOST_RV_REF(node_alloc_holder) x, const value_compare &c) : members_(boost::move(x.node_alloc()), c) { this->icont().swap(x.icont()); } void copy_assign_alloc(const node_alloc_holder &x) - { + { container_detail::bool_<allocator_traits_type::propagate_on_container_copy_assignment::value> flag; container_detail::assign_alloc( static_cast<NodeAlloc &>(this->members_) , static_cast<const NodeAlloc &>(x.members_), flag); @@ -244,22 +171,10 @@ struct node_alloc_holder { return allocator_traits_type::max_size(this->node_alloc()); } NodePtr allocate_one() - { return this->allocate_one(alloc_version()); } - - NodePtr allocate_one(allocator_v1) - { return this->node_alloc().allocate(1); } - - NodePtr allocate_one(allocator_v2) - { return this->node_alloc().allocate_one(); } + { return AllocVersionTraits::allocate_one(this->node_alloc()); } void deallocate_one(const NodePtr &p) - { return this->deallocate_one(p, alloc_version()); } - - void deallocate_one(const NodePtr &p, allocator_v1) - { this->node_alloc().deallocate(p, 1); } - - void deallocate_one(const NodePtr &p, allocator_v2) - { this->node_alloc().deallocate_one(p); } + { AllocVersionTraits::deallocate_one(this->node_alloc(), p); } #ifdef BOOST_CONTAINER_PERFECT_FORWARDING @@ -274,7 +189,7 @@ struct node_alloc_holder node_deallocator.release(); //This does not throw typedef typename Node::hook_type hook_type; - ::new(static_cast<hook_type*>(container_detail::to_raw_pointer(p))) hook_type; + ::new(static_cast<hook_type*>(container_detail::to_raw_pointer(p)), boost_container_new_t()) hook_type; return (p); } @@ -292,7 +207,7 @@ struct node_alloc_holder BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ node_deallocator.release(); \ typedef typename Node::hook_type hook_type; \ - ::new(static_cast<hook_type*>(container_detail::to_raw_pointer(p))) hook_type; \ + ::new(static_cast<hook_type*>(container_detail::to_raw_pointer(p)), boost_container_new_t()) hook_type; \ return (p); \ } \ //! @@ -310,7 +225,7 @@ struct node_alloc_holder node_deallocator.release(); //This does not throw typedef typename Node::hook_type hook_type; - ::new(static_cast<hook_type*>(container_detail::to_raw_pointer(p))) hook_type; + ::new(static_cast<hook_type*>(container_detail::to_raw_pointer(p)), boost_container_new_t()) hook_type; return (p); } @@ -328,41 +243,49 @@ struct node_alloc_holder } template<class FwdIterator, class Inserter> - FwdIterator allocate_many_and_construct + void allocate_many_and_construct (FwdIterator beg, difference_type n, Inserter inserter) { if(n){ - typedef typename NodeAlloc::multiallocation_chain multiallocation_chain; + typedef typename node_allocator_version_traits_type::multiallocation_chain multiallocation_chain; //Try to allocate memory in a single block - multiallocation_chain mem(this->node_alloc().allocate_individual(n)); - int constructed = 0; + typedef typename multiallocation_chain::iterator multialloc_iterator; + multiallocation_chain mem; + NodeAlloc &nalloc = this->node_alloc(); + node_allocator_version_traits_type::allocate_individual(nalloc, n, mem); + multialloc_iterator itbeg(mem.begin()), itlast(mem.last()); + mem.clear(); Node *p = 0; BOOST_TRY{ - for(difference_type i = 0; i < n; ++i, ++beg, --constructed){ - p = container_detail::to_raw_pointer(mem.front()); - mem.pop_front(); + Deallocator node_deallocator(NodePtr(), nalloc); + container_detail::scoped_destructor<NodeAlloc> sdestructor(nalloc, 0); + while(n--){ + p = container_detail::to_raw_pointer(iterator_to_pointer(itbeg)); + node_deallocator.set(p); + ++itbeg; //This can throw - constructed = 0; - boost::container::construct_in_place(this->node_alloc(), container_detail::addressof(p->m_data), beg); - ++constructed; + boost::container::construct_in_place(nalloc, container_detail::addressof(p->m_data), beg); + sdestructor.set(p); + ++beg; //This does not throw typedef typename Node::hook_type hook_type; - ::new(static_cast<hook_type*>(container_detail::to_raw_pointer(p))) hook_type; - //This can throw in some containers (predicate might throw) + ::new(static_cast<hook_type*>(p), boost_container_new_t()) hook_type; + //This can throw in some containers (predicate might throw). + //(sdestructor will destruct the node and node_deallocator will deallocate it in case of exception) inserter(*p); + sdestructor.set(0); } + sdestructor.release(); + node_deallocator.release(); } BOOST_CATCH(...){ - if(constructed){ - allocator_traits<NodeAlloc>::destroy(this->node_alloc(), container_detail::to_raw_pointer(p)); - } - this->node_alloc().deallocate_individual(boost::move(mem)); + mem.incorporate_after(mem.last(), &*itbeg, &*itlast, n); + node_allocator_version_traits_type::deallocate_individual(this->node_alloc(), mem); BOOST_RETHROW } BOOST_CATCH_END } - return beg; } void clear(allocator_v1) @@ -375,7 +298,7 @@ struct node_alloc_holder this->icont().clear_and_dispose(builder); //BOOST_STATIC_ASSERT((::boost::has_move_emulation_enabled<typename NodeAlloc::multiallocation_chain>::value == true)); if(!chain.empty()) - this->node_alloc().deallocate_individual(boost::move(chain)); + this->node_alloc().deallocate_individual(chain); } icont_iterator erase_range(const icont_iterator &first, const icont_iterator &last, allocator_v1) @@ -383,8 +306,13 @@ struct node_alloc_holder icont_iterator erase_range(const icont_iterator &first, const icont_iterator &last, allocator_v2) { - allocator_multialloc_chain_node_deallocator<NodeAlloc> chain_holder(this->node_alloc()); - return this->icont().erase_and_dispose(first, last, chain_holder.get_chain_builder()); + typedef typename NodeAlloc::multiallocation_chain multiallocation_chain; + NodeAlloc & nalloc = this->node_alloc(); + multiallocation_chain chain; + allocator_destroyer_and_chain_builder<NodeAlloc> chain_builder(nalloc, chain); + icont_iterator ret_it = this->icont().erase_and_dispose(first, last, chain_builder); + nalloc.deallocate_individual(chain); + return ret_it; } template<class Key, class Comparator> @@ -430,12 +358,12 @@ struct node_alloc_holder {} template<class ConvertibleToAlloc> - members_holder(BOOST_FWD_REF(ConvertibleToAlloc) c2alloc, const Pred &c) + members_holder(BOOST_FWD_REF(ConvertibleToAlloc) c2alloc, const value_compare &c) : NodeAlloc(boost::forward<ConvertibleToAlloc>(c2alloc)) , m_icont(typename ICont::value_compare(c)) {} - explicit members_holder(const Pred &c) + explicit members_holder(const value_compare &c) : NodeAlloc() , m_icont(typename ICont::value_compare(c)) {} diff --git a/boost/container/detail/node_pool.hpp b/boost/container/detail/node_pool.hpp new file mode 100644 index 0000000000..60d826675a --- /dev/null +++ b/boost/container/detail/node_pool.hpp @@ -0,0 +1,156 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_NODE_POOL_HPP +#define BOOST_CONTAINER_DETAIL_NODE_POOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> + +#include <boost/container/detail/mutex.hpp> +#include <boost/container/detail/pool_common_alloc.hpp> +#include <boost/container/detail/node_pool_impl.hpp> +#include <boost/container/detail/mutex.hpp> +#include <boost/intrusive/slist.hpp> +#include <boost/move/utility_core.hpp> +#include <cstddef> +#include <functional> //std::unary_function +#include <algorithm> //std::swap +#include <cassert> + +namespace boost { +namespace container { +namespace container_detail { + +//!Pooled memory allocator using single segregated storage. Includes +//!a reference count but the class does not delete itself, this is +//!responsibility of user classes. Node size (NodeSize) and the number of +//!nodes allocated per block (NodesPerBlock) are known at compile time +template< std::size_t NodeSize, std::size_t NodesPerBlock > +class private_node_pool + //Inherit from the implementation to avoid template bloat + : public boost::container::container_detail:: + private_node_pool_impl<fake_segment_manager> +{ + typedef boost::container::container_detail:: + private_node_pool_impl<fake_segment_manager> base_t; + //Non-copyable + private_node_pool(const private_node_pool &); + private_node_pool &operator=(const private_node_pool &); + + public: + typedef typename base_t::multiallocation_chain multiallocation_chain; + static const std::size_t nodes_per_block = NodesPerBlock; + + //!Constructor from a segment manager. Never throws + private_node_pool() + : base_t(0, NodeSize, NodesPerBlock) + {} + +}; + +template< std::size_t NodeSize + , std::size_t NodesPerBlock + > +class shared_node_pool + : public private_node_pool<NodeSize, NodesPerBlock> +{ + private: + typedef private_node_pool<NodeSize, NodesPerBlock> private_node_allocator_t; + + public: + typedef typename private_node_allocator_t::free_nodes_t free_nodes_t; + typedef typename private_node_allocator_t::multiallocation_chain multiallocation_chain; + + //!Constructor from a segment manager. Never throws + shared_node_pool() + : private_node_allocator_t(){} + + //!Destructor. Deallocates all allocated blocks. Never throws + ~shared_node_pool() + {} + + //!Allocates array of count elements. Can throw std::bad_alloc + void *allocate_node() + { + //----------------------- + scoped_lock<default_mutex> guard(mutex_); + //----------------------- + return private_node_allocator_t::allocate_node(); + } + + //!Deallocates an array pointed by ptr. Never throws + void deallocate_node(void *ptr) + { + //----------------------- + scoped_lock<default_mutex> guard(mutex_); + //----------------------- + private_node_allocator_t::deallocate_node(ptr); + } + + //!Allocates a singly linked list of n nodes ending in null pointer. + //!can throw std::bad_alloc + void allocate_nodes(const std::size_t n, multiallocation_chain &chain) + { + //----------------------- + scoped_lock<default_mutex> guard(mutex_); + //----------------------- + return private_node_allocator_t::allocate_nodes(n, chain); + } + + void deallocate_nodes(multiallocation_chain &chain) + { + //----------------------- + scoped_lock<default_mutex> guard(mutex_); + //----------------------- + private_node_allocator_t::deallocate_nodes(chain); + } + + //!Deallocates all the free blocks of memory. Never throws + void deallocate_free_blocks() + { + //----------------------- + scoped_lock<default_mutex> guard(mutex_); + //----------------------- + private_node_allocator_t::deallocate_free_blocks(); + } + + //!Deallocates all blocks. Never throws + void purge_blocks() + { + //----------------------- + scoped_lock<default_mutex> guard(mutex_); + //----------------------- + private_node_allocator_t::purge_blocks(); + } + + std::size_t num_free_nodes() + { + //----------------------- + scoped_lock<default_mutex> guard(mutex_); + //----------------------- + return private_node_allocator_t::num_free_nodes(); + } + + private: + default_mutex mutex_; +}; + +} //namespace container_detail { +} //namespace container { +} //namespace boost { + +#include <boost/container/detail/config_end.hpp> + +#endif //#ifndef BOOST_CONTAINER_DETAIL_NODE_POOL_HPP diff --git a/boost/container/detail/node_pool_impl.hpp b/boost/container/detail/node_pool_impl.hpp index 63c1278238..2450e5103e 100644 --- a/boost/container/detail/node_pool_impl.hpp +++ b/boost/container/detail/node_pool_impl.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,13 +11,14 @@ #ifndef BOOST_CONTAINER_DETAIL_NODE_POOL_IMPL_HPP #define BOOST_CONTAINER_DETAIL_NODE_POOL_IMPL_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" -#include <boost/container/container_fwd.hpp> +#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> + +#include <boost/container/container_fwd.hpp> #include <boost/container/detail/utilities.hpp> #include <boost/intrusive/pointer_traits.hpp> #include <boost/intrusive/set.hpp> @@ -26,9 +27,9 @@ #include <boost/container/detail/math_functions.hpp> #include <boost/container/detail/mpl.hpp> #include <boost/container/detail/pool_common.hpp> +#include <boost/core/no_exceptions_support.hpp> #include <boost/assert.hpp> #include <cstddef> -#include <functional> //std::unary_function namespace boost { namespace container { @@ -85,19 +86,19 @@ class private_node_pool_impl { return container_detail::to_raw_pointer(mp_segment_mngr_base); } void *allocate_node() - { return priv_alloc_node(); } - + { return this->priv_alloc_node(); } + //!Deallocates an array pointed by ptr. Never throws void deallocate_node(void *ptr) - { priv_dealloc_node(ptr); } + { this->priv_dealloc_node(ptr); } //!Allocates a singly linked list of n nodes ending in null pointer. - multiallocation_chain allocate_nodes(const size_type n) + void allocate_nodes(const size_type n, multiallocation_chain &chain) { //Preallocate all needed blocks to fulfill the request size_type cur_nodes = m_freelist.size(); if(cur_nodes < n){ - priv_alloc_block(((n - cur_nodes) - 1)/m_nodes_per_block + 1); + this->priv_alloc_block(((n - cur_nodes) - 1)/m_nodes_per_block + 1); } //We just iterate the needed nodes to get the last we'll erase @@ -118,20 +119,18 @@ class private_node_pool_impl //Now take the last erased node and just splice it in the end //of the intrusive list that will be traversed by the multialloc iterator. - multiallocation_chain chain; chain.incorporate_after(chain.before_begin(), &*first_node, &*last_node, n); m_allocated += n; - return boost::move(chain); } - void deallocate_nodes(multiallocation_chain chain) + void deallocate_nodes(multiallocation_chain &chain) { typedef typename multiallocation_chain::iterator iterator; iterator it(chain.begin()), itend(chain.end()); while(it != itend){ void *pElem = &*it; ++it; - priv_dealloc_node(pElem); + this->priv_dealloc_node(pElem); } } @@ -208,8 +207,6 @@ class private_node_pool_impl BOOST_ASSERT(m_allocated==0); size_type blocksize = get_rounded_size (m_real_node_size*m_nodes_per_block, (size_type)alignment_of<node_t>::value); - typename blockslist_t::iterator - it(m_blocklist.begin()), itend(m_blocklist.end()), aux; //We iterate though the NodeBlock list to free the memory while(!m_blocklist.empty()){ @@ -238,7 +235,7 @@ class private_node_pool_impl push_in_list(free_nodes_t &l, typename free_nodes_t::iterator &it) : slist_(l), last_it_(it) {} - + void operator()(typename free_nodes_t::pointer p) const { slist_.push_front(*p); @@ -253,12 +250,14 @@ class private_node_pool_impl }; struct is_between - : std::unary_function<typename free_nodes_t::value_type, bool> { + typedef typename free_nodes_t::value_type argument_type; + typedef bool result_type; + is_between(const void *addr, std::size_t size) : beg_(static_cast<const char *>(addr)), end_(beg_+size) {} - + bool operator()(typename free_nodes_t::const_reference v) const { return (beg_ <= reinterpret_cast<const char *>(&v) && @@ -275,7 +274,7 @@ class private_node_pool_impl { //If there are no free nodes we allocate a new block if (m_freelist.empty()) - priv_alloc_block(); + this->priv_alloc_block(1); //We take the first free node node_t *n = (node_t*)&m_freelist.front(); m_freelist.pop_front(); @@ -295,14 +294,13 @@ class private_node_pool_impl } //!Allocates several blocks of nodes. Can throw - void priv_alloc_block(size_type num_blocks = 1) + void priv_alloc_block(size_type num_blocks) { - if(!num_blocks) - return; + BOOST_ASSERT(num_blocks > 0); size_type blocksize = get_rounded_size(m_real_node_size*m_nodes_per_block, (size_type)alignment_of<node_t>::value); - try{ + BOOST_TRY{ for(size_type i = 0; i != num_blocks; ++i){ //We allocate a new NodeBlock and put it as first //element in the free Node list @@ -313,15 +311,16 @@ class private_node_pool_impl //We initialize all Nodes in Node Block to insert //them in the free Node list - for(size_type i = 0; i < m_nodes_per_block; ++i, pNode += m_real_node_size){ + for(size_type j = 0; j < m_nodes_per_block; ++j, pNode += m_real_node_size){ m_freelist.push_front(*new (pNode) node_t); } } } - catch(...){ + BOOST_CATCH(...){ //to-do: if possible, an efficient way to deallocate allocated blocks - throw; + BOOST_RETHROW } + BOOST_CATCH_END } //!Deprecated, use deallocate_free_blocks @@ -335,13 +334,13 @@ class private_node_pool_impl private: //!Returns a reference to the block hook placed in the end of the block static node_t & get_block_hook (void *block, size_type blocksize) - { - return *reinterpret_cast<node_t*>(reinterpret_cast<char*>(block) + blocksize); + { + return *reinterpret_cast<node_t*>(reinterpret_cast<char*>(block) + blocksize); } //!Returns the starting address of the block reference to the block hook placed in the end of the block void *get_block_from_hook (node_t *hook, size_type blocksize) - { + { return (reinterpret_cast<char*>(hook) - blocksize); } diff --git a/boost/container/detail/pair.hpp b/boost/container/detail/pair.hpp index 2a20ed13ec..b7ad84c80e 100644 --- a/boost/container/detail/pair.hpp +++ b/boost/container/detail/pair.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. +// (C) Copyright Ion Gaztanaga 2005-2013. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -13,11 +13,11 @@ #ifndef BOOST_CONTAINER_CONTAINER_DETAIL_PAIR_HPP #define BOOST_CONTAINER_CONTAINER_DETAIL_PAIR_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" +#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> #include <boost/container/detail/mpl.hpp> @@ -26,9 +26,10 @@ #include <boost/container/detail/type_traits.hpp> #include <utility> //std::pair +#include <algorithm> //std::swap + +#include <boost/move/utility_core.hpp> -#include <boost/move/move.hpp> -#include <boost/type_traits/is_class.hpp> #ifndef BOOST_CONTAINER_PERFECT_FORWARDING #include <boost/container/detail/preprocessor.hpp> @@ -329,22 +330,42 @@ struct is_enum< ::boost::container::container_detail::pair<T, U> > static const bool value = false; }; +template <class T> +struct is_class; + //This specialization is needed to avoid instantiation of pair in //is_class, and allow recursive maps. template <class T1, class T2> struct is_class< ::boost::container::container_detail::pair<T1, T2> > - : public ::boost::true_type -{}; +{ + static const bool value = true; +}; -#ifdef BOOST_NO_RVALUE_REFERENCES +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES template<class T1, class T2> struct has_move_emulation_enabled< ::boost::container::container_detail::pair<T1, T2> > - : ::boost::true_type -{}; +{ + static const bool value = true; +}; #endif +namespace move_detail{ + +template<class T> +struct is_class_or_union; + +template <class T1, class T2> +struct is_class_or_union< ::boost::container::container_detail::pair<T1, T2> > +//This specialization is needed to avoid instantiation of pair in +//is_class, and allow recursive maps. +{ + static const bool value = true; +}; + + +} //namespace move_detail{ } //namespace boost { diff --git a/boost/container/detail/placement_new.hpp b/boost/container/detail/placement_new.hpp new file mode 100644 index 0000000000..2489d8a45e --- /dev/null +++ b/boost/container/detail/placement_new.hpp @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-2014. 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_CONTAINER_DETAIL_PLACEMENT_NEW_HPP +#define BOOST_CONTAINER_DETAIL_PLACEMENT_NEW_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +struct boost_container_new_t{}; + +//avoid including <new> +inline void *operator new(std::size_t, void *p, boost_container_new_t) +{ return p; } + +inline void operator delete(void *, void *, boost_container_new_t) +{} + +#endif //BOOST_CONTAINER_DETAIL_PLACEMENT_NEW_HPP diff --git a/boost/container/detail/pool_common.hpp b/boost/container/detail/pool_common.hpp index 500b9124d5..11fb6c2e50 100644 --- a/boost/container/detail/pool_common.hpp +++ b/boost/container/detail/pool_common.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -8,16 +8,17 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_CONTAINER_DETAIL_NODE_POOL_COMMON_HPP -#define BOOST_CONTAINER_DETAIL_NODE_POOL_COMMON_HPP +#ifndef BOOST_CONTAINER_DETAIL_POOL_COMMON_HPP +#define BOOST_CONTAINER_DETAIL_POOL_COMMON_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> + #include <boost/intrusive/slist.hpp> -#include <new> namespace boost { namespace container { @@ -34,7 +35,7 @@ struct node_slist typedef slist_hook_t node_t; typedef typename bi::make_slist - <node_t, bi::linear<true>, bi::base_hook<slist_hook_t> >::type node_slist_t; + <node_t, bi::linear<true>, bi::cache_last<true>, bi::base_hook<slist_hook_t> >::type node_slist_t; }; template<class T> diff --git a/boost/container/detail/pool_common_alloc.hpp b/boost/container/detail/pool_common_alloc.hpp new file mode 100644 index 0000000000..dfae7efd13 --- /dev/null +++ b/boost/container/detail/pool_common_alloc.hpp @@ -0,0 +1,98 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_POOL_COMMON_ALLOC_HPP +#define BOOST_CONTAINER_DETAIL_POOL_COMMON_ALLOC_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> +#include <boost/container/throw_exception.hpp> + +#include <boost/intrusive/slist.hpp> +#include <boost/container/detail/pool_common.hpp> +#include <boost/container/detail/alloc_lib.h> +#include <cstddef> + +namespace boost{ +namespace container{ +namespace container_detail{ + +struct node_slist_helper + : public boost::container::container_detail::node_slist<void*> +{}; + +struct fake_segment_manager +{ + typedef void * void_pointer; + static const std::size_t PayloadPerAllocation = BOOST_CONTAINER_ALLOCATION_PAYLOAD; + + typedef boost::container::container_detail:: + basic_multiallocation_chain<void*> multiallocation_chain; + static void deallocate(void_pointer p) + { boost_cont_free(p); } + + static void deallocate_many(multiallocation_chain &chain) + { + std::size_t size = chain.size(); + std::pair<void*, void*> ptrs = chain.extract_data(); + boost_cont_memchain dlchain; + BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&dlchain, ptrs.first, ptrs.second, size); + boost_cont_multidealloc(&dlchain); + } + + typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + + static void *allocate_aligned(std::size_t nbytes, std::size_t alignment) + { + void *ret = boost_cont_memalign(nbytes, alignment); + if(!ret) + boost::container::throw_bad_alloc(); + return ret; + } + + static void *allocate(std::size_t nbytes) + { + void *ret = boost_cont_malloc(nbytes); + if(!ret) + boost::container::throw_bad_alloc(); + return ret; + } +}; + +} //namespace boost{ +} //namespace container{ +} //namespace container_detail{ + +namespace boost { +namespace container { +namespace container_detail { + +template<class T> +struct is_stateless_segment_manager; + +template<> +struct is_stateless_segment_manager + <boost::container::container_detail::fake_segment_manager> +{ + static const bool value = true; +}; + +} //namespace container_detail { +} //namespace container { +} //namespace boost { + +#include <boost/container/detail/config_end.hpp> + +#endif //BOOST_CONTAINER_DETAIL_POOL_COMMON_ALLOC_HPP diff --git a/boost/container/detail/preprocessor.hpp b/boost/container/detail/preprocessor.hpp index 1818094be1..838eff2ca1 100644 --- a/boost/container/detail/preprocessor.hpp +++ b/boost/container/detail/preprocessor.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,17 +11,13 @@ #ifndef BOOST_CONTAINER_DETAIL_PREPROCESSOR_HPP #define BOOST_CONTAINER_DETAIL_PREPROCESSOR_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif #include <boost/container/detail/config_begin.hpp> - -#ifndef BOOST_NO_RVALUE_REFERENCES -#include <boost/container/detail/stored_ref.hpp> -#endif //#ifndef BOOST_NO_RVALUE_REFERENCES - #include <boost/container/detail/workaround.hpp> +#include <boost/move/utility_core.hpp> #ifdef BOOST_CONTAINER_PERFECT_FORWARDING //#error "This file is not needed when perfect forwarding is available" @@ -36,10 +32,7 @@ #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum_trailing_params.hpp> #include <boost/preprocessor/repetition/enum_trailing.hpp> -#include <boost/preprocessor/repetition/enum_shifted_params.hpp> -#include <boost/preprocessor/repetition/enum_shifted.hpp> #include <boost/preprocessor/repetition/repeat.hpp> -#include <boost/preprocessor/logical/not.hpp> #include <boost/preprocessor/arithmetic/sub.hpp> #include <boost/preprocessor/arithmetic/add.hpp> #include <boost/preprocessor/iteration/iterate.hpp> @@ -52,7 +45,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 -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #define BOOST_CONTAINER_PP_PARAM_LIST(z, n, data) \ BOOST_PP_CAT(P, n) && BOOST_PP_CAT(p, n) \ //! @@ -60,13 +53,13 @@ #define BOOST_CONTAINER_PP_PARAM_LIST(z, n, data) \ const BOOST_PP_CAT(P, n) & BOOST_PP_CAT(p, n) \ //! -#endif //#ifndef BOOST_NO_RVALUE_REFERENCES +#endif //#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #define BOOST_CONTAINER_PP_CONST_REF_PARAM_LIST_Q(z, n, Data) \ const BOOST_PP_CAT(Q, n) & BOOST_PP_CAT(q, n) \ //! -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #define BOOST_CONTAINER_PP_PARAM(U, u) \ U && u \ //! @@ -74,36 +67,87 @@ const BOOST_PP_CAT(Q, n) & BOOST_PP_CAT(q, n) \ #define BOOST_CONTAINER_PP_PARAM(U, u) \ const U & u \ //! -#endif //#ifndef BOOST_NO_RVALUE_REFERENCES - -#ifndef BOOST_NO_RVALUE_REFERENCES - - #if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) +#endif //#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - #define BOOST_CONTAINER_PP_PARAM_INIT(z, n, data) \ - BOOST_PP_CAT(m_p, n) (static_cast<BOOST_PP_CAT(P, n)>( BOOST_PP_CAT(p, n) )) \ - - #else //#if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #define BOOST_CONTAINER_PP_PARAM_INIT(z, n, data) \ BOOST_PP_CAT(m_p, n) (::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) )) \ //! - #endif //BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - -#else //BOOST_NO_RVALUE_REFERENCES +#else //BOOST_NO_CXX11_RVALUE_REFERENCES #define BOOST_CONTAINER_PP_PARAM_INIT(z, n, data) \ BOOST_PP_CAT(m_p, n) (const_cast<BOOST_PP_CAT(P, n) &>(BOOST_PP_CAT(p, n))) \ //! -#endif //#ifndef BOOST_NO_RVALUE_REFERENCES +#endif //#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) + namespace boost { + namespace container { + namespace container_detail { + template<class T> + struct ref_holder; + + template<class T> + struct ref_holder<T &> + { + explicit ref_holder(T &t) + : t_(t) + {} + T &t_; + T & get() { return t_; } + }; + + template<class T> + struct ref_holder<const T> + { + explicit ref_holder(const T &t) + : t_(t) + {} + const T &t_; + const T & get() { return t_; } + }; + + template<class T> + struct ref_holder<const T &&> + { + explicit ref_holder(const T &t) + : t_(t) + {} + const T &t_; + const T & get() { return t_; } + }; + + template<class T> + struct ref_holder + { + explicit ref_holder(T &&t) + : t_(t) + {} + T &t_; + T && get() { return ::boost::move(t_); } + }; + + template<class T> + struct ref_holder<T &&> + { + explicit ref_holder(T &&t) + : t_(t) + {} + T &t_; + T && get() { return ::boost::move(t_); } + }; + + } //namespace container_detail { + } //namespace container { + } //namespace boost { + #define BOOST_CONTAINER_PP_PARAM_DEFINE(z, n, data) \ - BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \ + ::boost::container::container_detail::ref_holder<BOOST_PP_CAT(P, n)> BOOST_PP_CAT(m_p, n); \ //! #else //BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG @@ -114,26 +158,25 @@ const BOOST_PP_CAT(Q, n) & BOOST_PP_CAT(q, n) \ #endif //defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) -#else //BOOST_NO_RVALUE_REFERENCES +#else //BOOST_NO_CXX11_RVALUE_REFERENCES #define BOOST_CONTAINER_PP_PARAM_DEFINE(z, n, data) \ BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \ //! -#endif //#ifndef BOOST_NO_RVALUE_REFERENCES +#endif //#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES -#if !defined(BOOST_NO_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) - #define BOOST_CONTAINER_PP_MEMBER_FORWARD(z, n, data) \ - ::boost::container::container_detail::stored_ref< BOOST_PP_CAT(P, n) >::forward( BOOST_PP_CAT(this->m_p, n) ) \ + #define BOOST_CONTAINER_PP_MEMBER_FORWARD(z, n, data) BOOST_PP_CAT(this->m_p, n).get() \ //! -#else //!defined(BOOST_NO_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) +#else //!defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) #define BOOST_CONTAINER_PP_MEMBER_FORWARD(z, n, data) \ ::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(this->m_p, n) ) \ //! -#endif //!defined(BOOST_NO_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) +#endif //!defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) #define BOOST_CONTAINER_PP_PARAM_INC(z, n, data) \ BOOST_PP_CAT(++this->m_p, n) \ diff --git a/boost/container/detail/singleton.hpp b/boost/container/detail/singleton.hpp new file mode 100644 index 0000000000..a2372c3a96 --- /dev/null +++ b/boost/container/detail/singleton.hpp @@ -0,0 +1,117 @@ +// Copyright (C) 2000 Stephen Cleary +// Copyright (C) 2008 Ion Gaztanaga +// +// 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 for updates, documentation, and revision history. +// +// This file is a modified file from Boost.Pool + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_SINGLETON_DETAIL_HPP +#define BOOST_CONTAINER_DETAIL_SINGLETON_DETAIL_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> + +// +// The following helper classes are placeholders for a generic "singleton" +// class. The classes below support usage of singletons, including use in +// program startup/shutdown code, AS LONG AS there is only one thread +// running before main() begins, and only one thread running after main() +// exits. +// +// This class is also limited in that it can only provide singleton usage for +// classes with default constructors. +// + +// The design of this class is somewhat twisted, but can be followed by the +// calling inheritance. Let us assume that there is some user code that +// calls "singleton_default<T>::instance()". The following (convoluted) +// sequence ensures that the same function will be called before main(): +// instance() contains a call to create_object.do_nothing() +// Thus, object_creator is implicitly instantiated, and create_object +// must exist. +// Since create_object is a static member, its constructor must be +// called before main(). +// The constructor contains a call to instance(), thus ensuring that +// instance() will be called before main(). +// The first time instance() is called (i.e., before main()) is the +// latest point in program execution where the object of type T +// can be created. +// Thus, any call to instance() will auto-magically result in a call to +// instance() before main(), unless already present. +// Furthermore, since the instance() function contains the object, instead +// of the singleton_default class containing a static instance of the +// object, that object is guaranteed to be constructed (at the latest) in +// the first call to instance(). This permits calls to instance() from +// static code, even if that code is called before the file-scope objects +// in this file have been initialized. + +namespace boost { +namespace container { +namespace container_detail { + +// T must be: no-throw default constructible and no-throw destructible +template <typename T> +struct singleton_default +{ + private: + struct object_creator + { + // This constructor does nothing more than ensure that instance() + // is called before main() begins, thus creating the static + // T object before multithreading race issues can come up. + object_creator() { singleton_default<T>::instance(); } + inline void do_nothing() const { } + }; + static object_creator create_object; + + singleton_default(); + + public: + typedef T object_type; + + // If, at any point (in user code), singleton_default<T>::instance() + // is called, then the following function is instantiated. + static object_type & instance() + { + // This is the object that we return a reference to. + // It is guaranteed to be created before main() begins because of + // the next line. + static object_type obj; + + // The following line does nothing else than force the instantiation + // of singleton_default<T>::create_object, whose constructor is + // called before main() begins. + create_object.do_nothing(); + + return obj; + } +}; +template <typename T> +typename singleton_default<T>::object_creator +singleton_default<T>::create_object; + +} // namespace container_detail +} // namespace container +} // namespace boost + +#include <boost/container/detail/config_end.hpp> + +#endif //BOOST_CONTAINER_DETAIL_SINGLETON_DETAIL_HPP diff --git a/boost/container/detail/std_fwd.hpp b/boost/container/detail/std_fwd.hpp new file mode 100644 index 0000000000..a2edeccff1 --- /dev/null +++ b/boost/container/detail/std_fwd.hpp @@ -0,0 +1,59 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-2014. 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_CONTAINER_DETAIL_STD_FWD_HPP +#define BOOST_CONTAINER_DETAIL_STD_FWD_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +////////////////////////////////////////////////////////////////////////////// +// Standard predeclarations +////////////////////////////////////////////////////////////////////////////// + +#if defined(__clang__) && defined(_LIBCPP_VERSION) + #define BOOST_CONTAINER_CLANG_INLINE_STD_NS + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wc++11-extensions" + #define BOOST_CONTAINER_STD_NS_BEG _LIBCPP_BEGIN_NAMESPACE_STD + #define BOOST_CONTAINER_STD_NS_END _LIBCPP_END_NAMESPACE_STD +#else + #define BOOST_CONTAINER_STD_NS_BEG namespace std{ + #define BOOST_CONTAINER_STD_NS_END } +#endif + +BOOST_CONTAINER_STD_NS_BEG + +template<class T> +class allocator; + +template<class T> +struct less; + +template<class T1, class T2> +struct pair; + +template<class T> +struct char_traits; + +struct input_iterator_tag; +struct forward_iterator_tag; +struct bidirectional_iterator_tag; +struct random_access_iterator_tag; + +BOOST_CONTAINER_STD_NS_END + +#ifdef BOOST_CONTAINER_CLANG_INLINE_STD_NS + #pragma GCC diagnostic pop + #undef BOOST_CONTAINER_CLANG_INLINE_STD_NS +#endif //BOOST_CONTAINER_CLANG_INLINE_STD_NS + +#endif //#ifndef BOOST_CONTAINER_DETAIL_STD_FWD_HPP diff --git a/boost/container/detail/stored_ref.hpp b/boost/container/detail/stored_ref.hpp deleted file mode 100644 index 80fda89615..0000000000 --- a/boost/container/detail/stored_ref.hpp +++ /dev/null @@ -1,92 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2008-2012. 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_CONTAINER_DETAIL_STORED_REF_HPP -#define BOOST_CONTAINER_DETAIL_STORED_REF_HPP - -#include "config_begin.hpp" -#include <boost/container/detail/workaround.hpp> - -#ifndef BOOST_NO_RVALUE_REFERENCES - -namespace boost{ -namespace container{ -namespace container_detail{ - -template<class T> -struct stored_ref -{ - - static T && forward(T &t) - #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - { return t; } - #else - { return boost::move(t); } - #endif -}; - -template<class T> -struct stored_ref<const T> -{ - static const T && forward(const T &t) - #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - { return t; } - #else - { return static_cast<const T&&>(t); } - #endif -}; - -template<class T> -struct stored_ref<T&&> -{ - static T && forward(T &t) - #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - { return t; } - #else - { return boost::move(t); } - #endif -}; - -template<class T> -struct stored_ref<const T&&> -{ - static const T && forward(const T &t) - #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - { return t; } - #else - { return static_cast<const T &&>(t); } - #endif -}; - -template<class T> -struct stored_ref<const T&> -{ - static const T & forward(const T &t) - { return t; } -}; - -template<class T> -struct stored_ref<T&> -{ - static T & forward(T &t) - { return t; } -}; - -} //namespace container_detail{ -} //namespace container{ -} //namespace boost{ - -#else -#error "This header can be included only for compiler with rvalue references" -#endif //BOOST_NO_RVALUE_REFERENCES - -#include <boost/container/detail/config_end.hpp> - -#endif //BOOST_CONTAINER_DETAIL_STORED_REF_HPP diff --git a/boost/container/detail/transform_iterator.hpp b/boost/container/detail/transform_iterator.hpp index 98f5c04d60..c4e746c389 100644 --- a/boost/container/detail/transform_iterator.hpp +++ b/boost/container/detail/transform_iterator.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. +// (C) Copyright Ion Gaztanaga 2005-2013. // (C) Copyright Gennaro Prota 2003 - 2004. // // Distributed under the Boost Software License, Version 1.0. @@ -14,12 +14,13 @@ #ifndef BOOST_CONTAINER_DETAIL_TRANSFORM_ITERATORS_HPP #define BOOST_CONTAINER_DETAIL_TRANSFORM_ITERATORS_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" +#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> + #include <boost/container/detail/type_traits.hpp> #include <iterator> @@ -33,10 +34,10 @@ struct operator_arrow_proxy : m_value(px) {} + typedef PseudoReference element_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; }; @@ -47,10 +48,10 @@ struct operator_arrow_proxy<T&> : m_value(px) {} + typedef T element_type; + T* operator->() const { return const_cast<T*>(&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; } + T &m_value; }; diff --git a/boost/container/detail/tree.hpp b/boost/container/detail/tree.hpp index 3ab1536204..e59bca0887 100644 --- a/boost/container/detail/tree.hpp +++ b/boost/container/detail/tree.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,23 +11,35 @@ #ifndef BOOST_CONTAINER_TREE_HPP #define BOOST_CONTAINER_TREE_HPP -#include "config_begin.hpp" +#if defined(_MSC_VER) +# pragma once +#endif + +#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> #include <boost/container/container_fwd.hpp> -#include <boost/move/move.hpp> -#include <boost/intrusive/pointer_traits.hpp> -#include <boost/type_traits/has_trivial_destructor.hpp> -#include <boost/detail/no_exceptions_support.hpp> -#include <boost/intrusive/rbtree.hpp> - #include <boost/container/detail/utilities.hpp> +#include <boost/container/detail/iterators.hpp> #include <boost/container/detail/algorithms.hpp> #include <boost/container/detail/node_alloc_holder.hpp> #include <boost/container/detail/destroyers.hpp> #include <boost/container/detail/pair.hpp> #include <boost/container/detail/type_traits.hpp> #include <boost/container/allocator_traits.hpp> +#include <boost/container/options.hpp> + +// +#include <boost/intrusive/pointer_traits.hpp> +#include <boost/intrusive/rbtree.hpp> +#include <boost/intrusive/avltree.hpp> +#include <boost/intrusive/splaytree.hpp> +#include <boost/intrusive/sgtree.hpp> +// +#include <boost/move/utility_core.hpp> +#include <boost/type_traits/has_trivial_destructor.hpp> +#include <boost/core/no_exceptions_support.hpp> +// #ifndef BOOST_CONTAINER_PERFECT_FORWARDING #include <boost/container/detail/preprocessor.hpp> #endif @@ -41,7 +53,7 @@ namespace container { namespace container_detail { template<class Key, class Value, class KeyCompare, class KeyOfValue> -struct value_compare_impl +struct tree_value_compare : public KeyCompare { typedef Value value_type; @@ -49,8 +61,12 @@ struct value_compare_impl typedef KeyOfValue key_of_value; typedef Key key_type; - value_compare_impl(const key_compare &kcomp) - : key_compare(kcomp) + explicit tree_value_compare(const key_compare &kcomp) + : KeyCompare(kcomp) + {} + + tree_value_compare() + : KeyCompare() {} const key_compare &key_comp() const @@ -80,47 +96,78 @@ struct value_compare_impl { return key_compare::operator()(this->key_forward(key1), this->key_forward(key2)); } }; -template<class VoidPointer> -struct rbtree_hook +template<class VoidPointer, boost::container::tree_type_enum tree_type_value, bool OptimizeSize> +struct intrusive_tree_hook; + +template<class VoidPointer, bool OptimizeSize> +struct intrusive_tree_hook<VoidPointer, boost::container::red_black_tree, OptimizeSize> { typedef typename container_detail::bi::make_set_base_hook < container_detail::bi::void_pointer<VoidPointer> , container_detail::bi::link_mode<container_detail::bi::normal_link> - , container_detail::bi::optimize_size<true> + , container_detail::bi::optimize_size<OptimizeSize> + >::type type; +}; + +template<class VoidPointer, bool OptimizeSize> +struct intrusive_tree_hook<VoidPointer, boost::container::avl_tree, OptimizeSize> +{ + typedef typename container_detail::bi::make_avl_set_base_hook + < container_detail::bi::void_pointer<VoidPointer> + , container_detail::bi::link_mode<container_detail::bi::normal_link> + , container_detail::bi::optimize_size<OptimizeSize> + >::type type; +}; + +template<class VoidPointer, bool OptimizeSize> +struct intrusive_tree_hook<VoidPointer, boost::container::scapegoat_tree, OptimizeSize> +{ + typedef typename container_detail::bi::make_bs_set_base_hook + < container_detail::bi::void_pointer<VoidPointer> + , container_detail::bi::link_mode<container_detail::bi::normal_link> + >::type type; +}; + +template<class VoidPointer, bool OptimizeSize> +struct intrusive_tree_hook<VoidPointer, boost::container::splay_tree, OptimizeSize> +{ + typedef typename container_detail::bi::make_bs_set_base_hook + < container_detail::bi::void_pointer<VoidPointer> + , container_detail::bi::link_mode<container_detail::bi::normal_link> >::type type; }; //This trait is used to type-pun std::pair because in C++03 //compilers std::pair is useless for C++11 features template<class T> -struct rbtree_internal_data_type +struct tree_internal_data_type { typedef T type; }; template<class T1, class T2> -struct rbtree_internal_data_type< std::pair<T1, T2> > +struct tree_internal_data_type< std::pair<T1, T2> > { typedef pair<T1, T2> type; }; - //The node to be store in the tree -template <class T, class VoidPointer> -struct rbtree_node - : public rbtree_hook<VoidPointer>::type +template <class T, class VoidPointer, boost::container::tree_type_enum tree_type_value, bool OptimizeSize> +struct tree_node + : public intrusive_tree_hook<VoidPointer, tree_type_value, OptimizeSize>::type { private: - //BOOST_COPYABLE_AND_MOVABLE(rbtree_node) - rbtree_node(); + //BOOST_COPYABLE_AND_MOVABLE(tree_node) + tree_node(); public: - typedef typename rbtree_hook<VoidPointer>::type hook_type; - + typedef typename intrusive_tree_hook + <VoidPointer, tree_type_value, OptimizeSize>::type hook_type; typedef T value_type; - typedef typename rbtree_internal_data_type<T>::type internal_type; + typedef typename tree_internal_data_type<T>::type internal_type; - typedef rbtree_node<T, VoidPointer> node_type; + typedef tree_node< T, VoidPointer + , tree_type_value, OptimizeSize> node_type; T &get_data() { @@ -173,56 +220,261 @@ struct rbtree_node { m_data = ::boost::move(v); } }; +template <class T, class VoidPointer, boost::container::tree_type_enum tree_type_value, bool OptimizeSize> +struct iiterator_node_value_type< tree_node<T, VoidPointer, tree_type_value, OptimizeSize> > { + typedef T type; +}; + +template<class Node, class Icont> +class insert_equal_end_hint_functor +{ + Icont &icont_; + + public: + insert_equal_end_hint_functor(Icont &icont) + : icont_(icont) + {} + + void operator()(Node &n) + { this->icont_.insert_equal(this->icont_.cend(), n); } +}; + +template<class Node, class Icont> +class push_back_functor +{ + Icont &icont_; + + public: + push_back_functor(Icont &icont) + : icont_(icont) + {} + + void operator()(Node &n) + { this->icont_.push_back(n); } +}; + }//namespace container_detail { namespace container_detail { -template<class A, class ValueCompare> -struct intrusive_rbtree_type +template< class NodeType, class NodeCompareType + , class SizeType, class HookType + , boost::container::tree_type_enum tree_type_value> +struct intrusive_tree_dispatch; + +template<class NodeType, class NodeCompareType, class SizeType, class HookType> +struct intrusive_tree_dispatch + <NodeType, NodeCompareType, SizeType, HookType, boost::container::red_black_tree> { + typedef typename container_detail::bi::make_rbtree + <NodeType + ,container_detail::bi::compare<NodeCompareType> + ,container_detail::bi::base_hook<HookType> + ,container_detail::bi::constant_time_size<true> + ,container_detail::bi::size_type<SizeType> + >::type type; +}; + +template<class NodeType, class NodeCompareType, class SizeType, class HookType> +struct intrusive_tree_dispatch + <NodeType, NodeCompareType, SizeType, HookType, boost::container::avl_tree> +{ + typedef typename container_detail::bi::make_avltree + <NodeType + ,container_detail::bi::compare<NodeCompareType> + ,container_detail::bi::base_hook<HookType> + ,container_detail::bi::constant_time_size<true> + ,container_detail::bi::size_type<SizeType> + >::type type; +}; + +template<class NodeType, class NodeCompareType, class SizeType, class HookType> +struct intrusive_tree_dispatch + <NodeType, NodeCompareType, SizeType, HookType, boost::container::scapegoat_tree> +{ + typedef typename container_detail::bi::make_sgtree + <NodeType + ,container_detail::bi::compare<NodeCompareType> + ,container_detail::bi::base_hook<HookType> + ,container_detail::bi::floating_point<true> + ,container_detail::bi::size_type<SizeType> + >::type type; +}; + +template<class NodeType, class NodeCompareType, class SizeType, class HookType> +struct intrusive_tree_dispatch + <NodeType, NodeCompareType, SizeType, HookType, boost::container::splay_tree> +{ + typedef typename container_detail::bi::make_splaytree + <NodeType + ,container_detail::bi::compare<NodeCompareType> + ,container_detail::bi::base_hook<HookType> + ,container_detail::bi::constant_time_size<true> + ,container_detail::bi::size_type<SizeType> + >::type type; +}; + +template<class A, class ValueCompare, boost::container::tree_type_enum tree_type_value, bool OptimizeSize> +struct intrusive_tree_type +{ + private: typedef typename boost::container:: allocator_traits<A>::value_type value_type; typedef typename boost::container:: allocator_traits<A>::void_pointer void_pointer; typedef typename boost::container:: allocator_traits<A>::size_type size_type; - typedef typename container_detail::rbtree_node - <value_type, void_pointer> node_type; + typedef typename container_detail::tree_node + < value_type, void_pointer + , tree_type_value, OptimizeSize> node_type; typedef node_compare<ValueCompare, node_type> node_compare_type; - typedef typename container_detail::bi::make_rbtree - <node_type - ,container_detail::bi::compare<node_compare_type> - ,container_detail::bi::base_hook<typename rbtree_hook<void_pointer>::type> - ,container_detail::bi::constant_time_size<true> - ,container_detail::bi::size_type<size_type> - >::type container_type; - typedef container_type type ; + //Deducing the hook type from node_type (e.g. node_type::hook_type) would + //provoke an early instantiation of node_type that could ruin recursive + //tree definitions, so retype the complete type to avoid any problem. + typedef typename intrusive_tree_hook + <void_pointer, tree_type_value + , OptimizeSize>::type hook_type; + public: + typedef typename intrusive_tree_dispatch + < node_type, node_compare_type + , size_type, hook_type + , tree_type_value>::type type; +}; + +//Trait to detect manually rebalanceable tree types +template<boost::container::tree_type_enum tree_type_value> +struct is_manually_balanceable +{ static const bool value = true; }; + +template<> struct is_manually_balanceable<red_black_tree> +{ static const bool value = false; }; + +template<> struct is_manually_balanceable<avl_tree> +{ static const bool value = false; }; + +//Proxy traits to implement different operations depending on the +//is_manually_balanceable<>::value +template< boost::container::tree_type_enum tree_type_value + , bool IsManuallyRebalanceable = is_manually_balanceable<tree_type_value>::value> +struct intrusive_tree_proxy +{ + template<class Icont> + static void rebalance(Icont &) {} +}; + +template<boost::container::tree_type_enum tree_type_value> +struct intrusive_tree_proxy<tree_type_value, true> +{ + template<class Icont> + static void rebalance(Icont &c) + { c.rebalance(); } }; } //namespace container_detail { namespace container_detail { +//This functor will be used with Intrusive clone functions to obtain +//already allocated nodes from a intrusive container instead of +//allocating new ones. When the intrusive container runs out of nodes +//the node holder is used instead. +template<class AllocHolder, bool DoMove> +class RecyclingCloner +{ + typedef typename AllocHolder::intrusive_container intrusive_container; + typedef typename AllocHolder::Node node_type; + typedef typename AllocHolder::NodePtr node_ptr_type; + + public: + RecyclingCloner(AllocHolder &holder, intrusive_container &itree) + : m_holder(holder), m_icont(itree) + {} + + static void do_assign(node_ptr_type &p, const node_type &other, bool_<true>) + { p->do_assign(other.m_data); } + + static void do_assign(node_ptr_type &p, const node_type &other, bool_<false>) + { p->do_move_assign(const_cast<node_type &>(other).m_data); } + + node_ptr_type operator()(const node_type &other) const + { + if(node_ptr_type p = m_icont.unlink_leftmost_without_rebalance()){ + //First recycle a node (this can't throw) + BOOST_TRY{ + //This can throw + this->do_assign(p, other, bool_<DoMove>()); + return p; + } + BOOST_CATCH(...){ + //If there is an exception destroy the whole source + m_holder.destroy_node(p); + while((p = m_icont.unlink_leftmost_without_rebalance())){ + m_holder.destroy_node(p); + } + BOOST_RETHROW + } + BOOST_CATCH_END + } + else{ + return m_holder.create_node(other.m_data); + } + } + + AllocHolder &m_holder; + intrusive_container &m_icont; +}; + +template<class KeyValueCompare, class Node> +//where KeyValueCompare is tree_value_compare<Key, Value, KeyCompare, KeyOfValue> +struct key_node_compare + : private KeyValueCompare +{ + explicit key_node_compare(const KeyValueCompare &comp) + : KeyValueCompare(comp) + {} + + template<class T> + struct is_node + { + static const bool value = is_same<T, Node>::value; + }; + + template<class T> + typename enable_if_c<is_node<T>::value, const typename KeyValueCompare::value_type &>::type + key_forward(const T &node) const + { return node.get_data(); } + + template<class T> + typename enable_if_c<!is_node<T>::value, const T &>::type + key_forward(const T &key) const + { return key; } + + template<class KeyType, class KeyType2> + bool operator()(const KeyType &key1, const KeyType2 &key2) const + { return KeyValueCompare::operator()(this->key_forward(key1), this->key_forward(key2)); } +}; + template <class Key, class Value, class KeyOfValue, - class KeyCompare, class A> -class rbtree + class KeyCompare, class A, + class Options = tree_assoc_defaults> +class tree : protected container_detail::node_alloc_holder < A - , typename container_detail::intrusive_rbtree_type - <A, value_compare_impl<Key, Value, KeyCompare, KeyOfValue> - >::type - , KeyCompare + , typename container_detail::intrusive_tree_type + < A, tree_value_compare<Key, Value, KeyCompare, KeyOfValue> //ValComp + , Options::tree_type, Options::optimize_size>::type > { - typedef typename container_detail::intrusive_rbtree_type - < A, value_compare_impl - <Key, Value, KeyCompare, KeyOfValue> - >::type Icont; - typedef container_detail::node_alloc_holder - <A, Icont, KeyCompare> AllocHolder; + typedef tree_value_compare + <Key, Value, KeyCompare, KeyOfValue> ValComp; + typedef typename container_detail::intrusive_tree_type + < A, ValComp, Options::tree_type + , Options::optimize_size>::type Icont; + typedef container_detail::node_alloc_holder + <A, Icont> AllocHolder; typedef typename AllocHolder::NodePtr NodePtr; - typedef rbtree < Key, Value, KeyOfValue - , KeyCompare, A> ThisType; + typedef tree < Key, Value, KeyOfValue + , KeyCompare, A, Options> ThisType; typedef typename AllocHolder::NodeAlloc NodeAlloc; typedef typename AllocHolder::ValAlloc ValAlloc; typedef typename AllocHolder::Node Node; @@ -232,82 +484,9 @@ class rbtree typedef typename AllocHolder::allocator_v1 allocator_v1; typedef typename AllocHolder::allocator_v2 allocator_v2; typedef typename AllocHolder::alloc_version alloc_version; + typedef intrusive_tree_proxy<Options::tree_type> intrusive_tree_proxy_t; - class RecyclingCloner; - friend class RecyclingCloner; - - class RecyclingCloner - { - public: - RecyclingCloner(AllocHolder &holder, Icont &irbtree) - : m_holder(holder), m_icont(irbtree) - {} - - NodePtr operator()(const Node &other) const - { - if(NodePtr p = m_icont.unlink_leftmost_without_rebalance()){ - //First recycle a node (this can't throw) - try{ - //This can throw - p->do_assign(other.m_data); - return p; - } - catch(...){ - //If there is an exception destroy the whole source - m_holder.destroy_node(p); - while((p = m_icont.unlink_leftmost_without_rebalance())){ - m_holder.destroy_node(p); - } - throw; - } - } - else{ - return m_holder.create_node(other.m_data); - } - } - - AllocHolder &m_holder; - Icont &m_icont; - }; - - class RecyclingMoveCloner; - friend class RecyclingMoveCloner; - - class RecyclingMoveCloner - { - public: - RecyclingMoveCloner(AllocHolder &holder, Icont &irbtree) - : m_holder(holder), m_icont(irbtree) - {} - - NodePtr operator()(const Node &other) const - { - if(NodePtr p = m_icont.unlink_leftmost_without_rebalance()){ - //First recycle a node (this can't throw) - try{ - //This can throw - p->do_move_assign(const_cast<Node &>(other).m_data); - return p; - } - catch(...){ - //If there is an exception destroy the whole source - m_holder.destroy_node(p); - while((p = m_icont.unlink_leftmost_without_rebalance())){ - m_holder.destroy_node(p); - } - throw; - } - } - else{ - return m_holder.create_node(other.m_data); - } - } - - AllocHolder &m_holder; - Icont &m_icont; - }; - - BOOST_COPYABLE_AND_MOVABLE(rbtree) + BOOST_COPYABLE_AND_MOVABLE(tree) public: @@ -315,8 +494,7 @@ class rbtree typedef Value value_type; typedef A allocator_type; typedef KeyCompare key_compare; - typedef value_compare_impl< Key, Value - , KeyCompare, KeyOfValue> value_compare; + typedef ValComp value_compare; typedef typename boost::container:: allocator_traits<A>::pointer pointer; typedef typename boost::container:: @@ -329,190 +507,147 @@ class rbtree allocator_traits<A>::size_type size_type; typedef typename boost::container:: allocator_traits<A>::difference_type difference_type; - typedef difference_type rbtree_difference_type; - typedef pointer rbtree_pointer; - typedef const_pointer rbtree_const_pointer; - typedef reference rbtree_reference; - typedef const_reference rbtree_const_reference; + typedef difference_type tree_difference_type; + typedef pointer tree_pointer; + typedef const_pointer tree_const_pointer; + typedef reference tree_reference; + typedef const_reference tree_const_reference; typedef NodeAlloc stored_allocator_type; private: - template<class KeyValueCompare> - struct key_node_compare - : private KeyValueCompare - { - key_node_compare(const KeyValueCompare &comp) - : KeyValueCompare(comp) - {} - - template<class T> - struct is_node - { - static const bool value = is_same<T, Node>::value; - }; - - template<class T> - typename enable_if_c<is_node<T>::value, const value_type &>::type - key_forward(const T &node) const - { return node.get_data(); } - - template<class T> - typename enable_if_c<!is_node<T>::value, const T &>::type - key_forward(const T &key) const - { return key; } - - template<class KeyType, class KeyType2> - bool operator()(const KeyType &key1, const KeyType2 &key2) const - { return KeyValueCompare::operator()(this->key_forward(key1), this->key_forward(key2)); } - }; - - typedef key_node_compare<value_compare> KeyNodeCompare; + typedef key_node_compare<value_compare, Node> KeyNodeCompare; public: - //rbtree const_iterator - class const_iterator - : public std::iterator - < std::bidirectional_iterator_tag - , value_type , rbtree_difference_type - , rbtree_const_pointer , rbtree_const_reference> - { - protected: - typedef typename Icont::iterator iiterator; - iiterator m_it; - explicit const_iterator(iiterator it) : m_it(it){} - void prot_incr() { ++m_it; } - void prot_decr() { --m_it; } - - private: - iiterator get() - { return this->m_it; } - - public: - friend class rbtree <Key, Value, KeyOfValue, KeyCompare, A>; - typedef rbtree_difference_type difference_type; + typedef container_detail::iterator<iiterator, false> iterator; + typedef container_detail::iterator<iiterator, true > const_iterator; + typedef container_detail::reverse_iterator<iterator> reverse_iterator; + typedef container_detail::reverse_iterator<const_iterator> const_reverse_iterator; - //Constructors - const_iterator() - : m_it() - {} - - //Pointer like operators - const_reference operator*() const - { return m_it->get_data(); } - - const_pointer operator->() const - { return const_pointer(&m_it->get_data()); } - - //Increment / Decrement - const_iterator& operator++() - { prot_incr(); return *this; } - - const_iterator operator++(int) - { iiterator tmp = m_it; ++*this; return const_iterator(tmp); } - - const_iterator& operator--() - { prot_decr(); return *this; } - - const_iterator operator--(int) - { iiterator tmp = m_it; --*this; return const_iterator(tmp); } + tree() + : AllocHolder(ValComp(key_compare())) + {} - //Comparison operators - bool operator== (const const_iterator& r) const - { return m_it == r.m_it; } + explicit tree(const key_compare& comp, const allocator_type& a = allocator_type()) + : AllocHolder(a, ValComp(comp)) + {} - bool operator!= (const const_iterator& r) const - { return m_it != r.m_it; } - }; + explicit tree(const allocator_type& a) + : AllocHolder(a) + {} - //rbtree iterator - class iterator : public const_iterator + template <class InputIterator> + tree(bool unique_insertion, InputIterator first, InputIterator last, const key_compare& comp, + const allocator_type& a + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator<InputIterator>::value + || container_detail::is_same<alloc_version, allocator_v1>::value + >::type * = 0 + #endif + ) + : AllocHolder(a, value_compare(comp)) { - private: - explicit iterator(iiterator it) - : const_iterator(it) - {} - - iiterator get() - { return this->m_it; } - - public: - friend class rbtree <Key, Value, KeyOfValue, KeyCompare, A>; - typedef rbtree_pointer pointer; - typedef rbtree_reference reference; - - //Constructors - iterator(){} - - //Pointer like operators - reference operator*() const - { return this->m_it->get_data(); } - pointer operator->() const - { return boost::intrusive::pointer_traits<pointer>::pointer_to(this->m_it->get_data()); } - - //Increment / Decrement - iterator& operator++() - { this->prot_incr(); return *this; } - - iterator operator++(int) - { iiterator tmp = this->m_it; ++*this; return iterator(tmp); } - - iterator& operator--() - { this->prot_decr(); return *this; } - - iterator operator--(int) - { iterator tmp = *this; --*this; return tmp; } - }; - - typedef std::reverse_iterator<iterator> reverse_iterator; - typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - - rbtree() - : AllocHolder(key_compare()) - {} + //Use cend() as hint to achieve linear time for + //ordered ranges as required by the standard + //for the constructor + const const_iterator end_it(this->cend()); + if(unique_insertion){ + for ( ; first != last; ++first){ + this->insert_unique(end_it, *first); + } + } + else{ + for ( ; first != last; ++first){ + this->insert_equal(end_it, *first); + } + } + } - rbtree(const key_compare& comp, const allocator_type& a = allocator_type()) - : AllocHolder(a, comp) - {} + template <class InputIterator> + tree(bool unique_insertion, InputIterator first, InputIterator last, const key_compare& comp, + const allocator_type& a + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !(container_detail::is_input_iterator<InputIterator>::value + || container_detail::is_same<alloc_version, allocator_v1>::value) + >::type * = 0 + #endif + ) + : AllocHolder(a, value_compare(comp)) + { + if(unique_insertion){ + //Use cend() as hint to achieve linear time for + //ordered ranges as required by the standard + //for the constructor + const const_iterator end_it(this->cend()); + for ( ; first != last; ++first){ + this->insert_unique(end_it, *first); + } + } + else{ + //Optimized allocation and construction + this->allocate_many_and_construct + ( first, std::distance(first, last) + , insert_equal_end_hint_functor<Node, Icont>(this->icont())); + } + } template <class InputIterator> - rbtree(InputIterator first, InputIterator last, const key_compare& comp, - const allocator_type& a, bool unique_insertion) - : AllocHolder(a, comp) + tree( ordered_range_t, InputIterator first, InputIterator last + , const key_compare& comp = key_compare(), const allocator_type& a = allocator_type() + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator<InputIterator>::value + || container_detail::is_same<alloc_version, allocator_v1>::value + >::type * = 0 + #endif + ) + : AllocHolder(a, value_compare(comp)) { - typedef typename std::iterator_traits<InputIterator>::iterator_category ItCat; - priv_create_and_insert_nodes(first, last, unique_insertion, alloc_version(), ItCat()); + for ( ; first != last; ++first){ + this->push_back_impl(*first); + } } template <class InputIterator> - rbtree( ordered_range_t, InputIterator first, InputIterator last - , const key_compare& comp = key_compare(), const allocator_type& a = allocator_type()) - : AllocHolder(a, comp) + tree( ordered_range_t, InputIterator first, InputIterator last + , const key_compare& comp = key_compare(), const allocator_type& a = allocator_type() + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !(container_detail::is_input_iterator<InputIterator>::value + || container_detail::is_same<alloc_version, allocator_v1>::value) + >::type * = 0 + #endif + ) + : AllocHolder(a, value_compare(comp)) { - typedef typename std::iterator_traits<InputIterator>::iterator_category ItCat; - priv_create_and_insert_ordered_nodes(first, last, alloc_version(), ItCat()); + //Optimized allocation and construction + this->allocate_many_and_construct + ( first, std::distance(first, last) + , container_detail::push_back_functor<Node, Icont>(this->icont())); } - rbtree(const rbtree& x) - : AllocHolder(x, x.key_comp()) + tree(const tree& x) + : AllocHolder(x, x.value_comp()) { this->icont().clone_from (x.icont(), typename AllocHolder::cloner(*this), Destroyer(this->node_alloc())); } - rbtree(BOOST_RV_REF(rbtree) x) - : AllocHolder(::boost::move(static_cast<AllocHolder&>(x)), x.key_comp()) + tree(BOOST_RV_REF(tree) x) + : AllocHolder(::boost::move(static_cast<AllocHolder&>(x)), x.value_comp()) {} - rbtree(const rbtree& x, const allocator_type &a) - : AllocHolder(a, x.key_comp()) + tree(const tree& x, const allocator_type &a) + : AllocHolder(a, x.value_comp()) { this->icont().clone_from (x.icont(), typename AllocHolder::cloner(*this), Destroyer(this->node_alloc())); } - rbtree(BOOST_RV_REF(rbtree) x, const allocator_type &a) - : AllocHolder(a, x.key_comp()) + tree(BOOST_RV_REF(tree) x, const allocator_type &a) + : AllocHolder(a, x.value_comp()) { if(this->node_alloc() == x.node_alloc()){ this->icont().swap(x.icont()); @@ -523,10 +658,10 @@ class rbtree } } - ~rbtree() + ~tree() {} //AllocHolder clears the tree - rbtree& operator=(BOOST_COPY_ASSIGN_REF(rbtree) x) + tree& operator=(BOOST_COPY_ASSIGN_REF(tree) x) { if (&x != this){ NodeAlloc &this_alloc = this->get_stored_allocator(); @@ -545,7 +680,7 @@ class rbtree //Now recreate the source tree reusing nodes stored by other_tree this->icont().clone_from (x.icont() - , RecyclingCloner(*this, other_tree) + , RecyclingCloner<AllocHolder, false>(*this, other_tree) , Destroyer(this->node_alloc())); //If there are remaining nodes, destroy them @@ -557,43 +692,47 @@ class rbtree return *this; } - rbtree& operator=(BOOST_RV_REF(rbtree) x) + tree& operator=(BOOST_RV_REF(tree) x) { - if (&x != this){ - NodeAlloc &this_alloc = this->node_alloc(); - NodeAlloc &x_alloc = x.node_alloc(); - //If allocators are equal we can just swap pointers - if(this_alloc == x_alloc){ - //Destroy and swap pointers - this->clear(); - this->icont() = ::boost::move(x.icont()); - //Move allocator if needed - this->AllocHolder::move_assign_alloc(x); - } - //If unequal allocators, then do a one by one move - else{ - //Transfer all the nodes to a temporary tree - //If anything goes wrong, all the nodes will be destroyed - //automatically - Icont other_tree(::boost::move(this->icont())); - - //Now recreate the source tree reusing nodes stored by other_tree - this->icont().clone_from - (x.icont() - , RecyclingMoveCloner(*this, other_tree) - , Destroyer(this->node_alloc())); - - //If there are remaining nodes, destroy them - NodePtr p; - while((p = other_tree.unlink_leftmost_without_rebalance())){ - AllocHolder::destroy_node(p); - } + BOOST_ASSERT(this != &x); + NodeAlloc &this_alloc = this->node_alloc(); + NodeAlloc &x_alloc = x.node_alloc(); + const bool propagate_alloc = allocator_traits<NodeAlloc>:: + propagate_on_container_move_assignment::value; + const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; + //Resources can be transferred if both allocators are + //going to be equal after this function (either propagated or already equal) + if(propagate_alloc || allocators_equal){ + //Destroy + this->clear(); + //Move allocator if needed + this->AllocHolder::move_assign_alloc(x); + //Obtain resources + this->icont() = boost::move(x.icont()); + } + //Else do a one by one move + else{ + //Transfer all the nodes to a temporary tree + //If anything goes wrong, all the nodes will be destroyed + //automatically + Icont other_tree(::boost::move(this->icont())); + + //Now recreate the source tree reusing nodes stored by other_tree + this->icont().clone_from + (x.icont() + , RecyclingCloner<AllocHolder, true>(*this, other_tree) + , Destroyer(this->node_alloc())); + + //If there are remaining nodes, destroy them + NodePtr p; + while((p = other_tree.unlink_leftmost_without_rebalance())){ + AllocHolder::destroy_node(p); } } return *this; } - public: + public: // accessors: value_compare value_comp() const { return this->icont().value_comp().value_comp(); } @@ -704,8 +843,10 @@ class rbtree iterator insert_unique_commit(const value_type& v, insert_commit_data &data) { NodePtr tmp = AllocHolder::create_node(v); - iiterator it(this->icont().insert_unique_commit(*tmp, data)); - return iterator(it); + scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_unique_commit(*tmp, data)); + destroy_deallocator.release(); + return ret; } template<class MovableConvertible> @@ -713,8 +854,10 @@ class rbtree (BOOST_FWD_REF(MovableConvertible) mv, insert_commit_data &data) { NodePtr tmp = AllocHolder::create_node(boost::forward<MovableConvertible>(mv)); - iiterator it(this->icont().insert_unique_commit(*tmp, data)); - return iterator(it); + scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_unique_commit(*tmp, data)); + destroy_deallocator.release(); + return ret; } std::pair<iterator,bool> insert_unique(const value_type& v) @@ -722,10 +865,10 @@ class rbtree insert_commit_data data; std::pair<iterator,bool> ret = this->insert_unique_check(KeyOfValue()(v), data); - if(!ret.second) - return ret; - return std::pair<iterator,bool> - (this->insert_unique_commit(v, data), true); + if(ret.second){ + ret.first = this->insert_unique_commit(v, data); + } + return ret; } template<class MovableConvertible> @@ -734,13 +877,22 @@ class rbtree insert_commit_data data; std::pair<iterator,bool> ret = this->insert_unique_check(KeyOfValue()(mv), data); - if(!ret.second) - return ret; - return std::pair<iterator,bool> - (this->insert_unique_commit(boost::forward<MovableConvertible>(mv), data), true); + if(ret.second){ + ret.first = this->insert_unique_commit(boost::forward<MovableConvertible>(mv), data); + } + return ret; } private: + + template<class MovableConvertible> + void push_back_impl(BOOST_FWD_REF(MovableConvertible) mv) + { + NodePtr tmp(AllocHolder::create_node(boost::forward<MovableConvertible>(mv))); + //push_back has no-throw guarantee so avoid any deallocator/destroyer + this->icont().push_back(*tmp); + } + std::pair<iterator, bool> emplace_unique_impl(NodePtr p) { value_type &v = p->get_data(); @@ -786,15 +938,21 @@ class rbtree template <class... Args> iterator emplace_equal(Args&&... args) { - NodePtr p(AllocHolder::create_node(boost::forward<Args>(args)...)); - return iterator(this->icont().insert_equal(this->icont().end(), *p)); + NodePtr tmp(AllocHolder::create_node(boost::forward<Args>(args)...)); + scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_equal(this->icont().end(), *tmp)); + destroy_deallocator.release(); + return ret; } template <class... Args> iterator emplace_hint_equal(const_iterator hint, Args&&... args) { - NodePtr p(AllocHolder::create_node(boost::forward<Args>(args)...)); - return iterator(this->icont().insert_equal(hint.get(), *p)); + NodePtr tmp(AllocHolder::create_node(boost::forward<Args>(args)...)); + scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_equal(hint.get(), *tmp)); + destroy_deallocator.release(); + return ret; } #else //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING @@ -818,16 +976,22 @@ class rbtree BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ - NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ - return iterator(this->icont().insert_equal(this->icont().end(), *p)); \ + NodePtr tmp(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ + scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc()); \ + iterator ret(this->icont().insert_equal(this->icont().end(), *tmp)); \ + destroy_deallocator.release(); \ + return ret; \ } \ \ BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ iterator emplace_hint_equal(const_iterator hint \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ - NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ - return iterator(this->icont().insert_equal(hint.get(), *p)); \ + NodePtr tmp(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ + scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc()); \ + iterator ret(this->icont().insert_equal(hint.get(), *tmp)); \ + destroy_deallocator.release(); \ + return ret; \ } \ //! #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) @@ -859,53 +1023,53 @@ class rbtree template <class InputIterator> void insert_unique(InputIterator first, InputIterator last) { - if(this->empty()){ - //Insert with end hint, to achieve linear - //complexity if [first, last) is ordered - const_iterator hint(this->cend()); - for( ; first != last; ++first) - hint = this->insert_unique(hint, *first); - } - else{ - for( ; first != last; ++first) - this->insert_unique(*first); - } + for( ; first != last; ++first) + this->insert_unique(*first); } iterator insert_equal(const value_type& v) { - NodePtr p(AllocHolder::create_node(v)); - return iterator(this->icont().insert_equal(this->icont().end(), *p)); + NodePtr tmp(AllocHolder::create_node(v)); + scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_equal(this->icont().end(), *tmp)); + destroy_deallocator.release(); + return ret; } template<class MovableConvertible> iterator insert_equal(BOOST_FWD_REF(MovableConvertible) mv) { - NodePtr p(AllocHolder::create_node(boost::forward<MovableConvertible>(mv))); - return iterator(this->icont().insert_equal(this->icont().end(), *p)); + NodePtr tmp(AllocHolder::create_node(boost::forward<MovableConvertible>(mv))); + scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_equal(this->icont().end(), *tmp)); + destroy_deallocator.release(); + return ret; } iterator insert_equal(const_iterator hint, const value_type& v) { - NodePtr p(AllocHolder::create_node(v)); - return iterator(this->icont().insert_equal(hint.get(), *p)); + NodePtr tmp(AllocHolder::create_node(v)); + scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_equal(hint.get(), *tmp)); + destroy_deallocator.release(); + return ret; } template<class MovableConvertible> iterator insert_equal(const_iterator hint, BOOST_FWD_REF(MovableConvertible) mv) { - NodePtr p(AllocHolder::create_node(boost::forward<MovableConvertible>(mv))); - return iterator(this->icont().insert_equal(hint.get(), *p)); + NodePtr tmp(AllocHolder::create_node(boost::forward<MovableConvertible>(mv))); + scoped_destroy_deallocator<NodeAlloc> destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_equal(hint.get(), *tmp)); + destroy_deallocator.release(); + return ret; } template <class InputIterator> void insert_equal(InputIterator first, InputIterator last) { - //Insert with end hint, to achieve linear - //complexity if [first, last) is ordered - const_iterator hint(this->cend()); for( ; first != last; ++first) - hint = this->insert_equal(hint, *first); + this->insert_equal(*first); } iterator erase(const_iterator position) @@ -920,7 +1084,8 @@ class rbtree void clear() { AllocHolder::clear(alloc_version()); } - // set operations: + // search operations. Const and non-const overloads even if no iterator is returned + // so splay implementations can to their rebalancing when searching in non-const versions iterator find(const key_type& k) { return iterator(this->icont().find(k, KeyNodeCompare(value_comp()))); } @@ -943,187 +1108,60 @@ class rbtree { return const_iterator(this->non_const_icont().upper_bound(k, KeyNodeCompare(value_comp()))); } std::pair<iterator,iterator> equal_range(const key_type& k) - { + { std::pair<iiterator, iiterator> ret = this->icont().equal_range(k, KeyNodeCompare(value_comp())); return std::pair<iterator,iterator>(iterator(ret.first), iterator(ret.second)); } std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const - { + { std::pair<iiterator, iiterator> ret = this->non_const_icont().equal_range(k, KeyNodeCompare(value_comp())); return std::pair<const_iterator,const_iterator> (const_iterator(ret.first), const_iterator(ret.second)); } - private: - //Iterator range version - template<class InpIterator> - void priv_create_and_insert_nodes - (InpIterator beg, InpIterator end, bool unique, allocator_v1, std::input_iterator_tag) + std::pair<iterator,iterator> lower_bound_range(const key_type& k) { - if(unique){ - for (; beg != end; ++beg){ - this->insert_unique(*beg); - } - } - else{ - for (; beg != end; ++beg){ - this->insert_equal(*beg); - } - } - } - - template<class InpIterator> - void priv_create_and_insert_nodes - (InpIterator beg, InpIterator end, bool unique, allocator_v2, std::input_iterator_tag) - { //Just forward to the default one - priv_create_and_insert_nodes(beg, end, unique, allocator_v1(), std::input_iterator_tag()); + std::pair<iiterator, iiterator> ret = + this->icont().lower_bound_range(k, KeyNodeCompare(value_comp())); + return std::pair<iterator,iterator>(iterator(ret.first), iterator(ret.second)); } - class insertion_functor; - friend class insertion_functor; - - class insertion_functor - { - Icont &icont_; - - public: - insertion_functor(Icont &icont) - : icont_(icont) - {} - - void operator()(Node &n) - { this->icont_.insert_equal(this->icont_.cend(), n); } - }; - - - template<class FwdIterator> - void priv_create_and_insert_nodes - (FwdIterator beg, FwdIterator end, bool unique, allocator_v2, std::forward_iterator_tag) + std::pair<const_iterator, const_iterator> lower_bound_range(const key_type& k) const { - if(beg != end){ - if(unique){ - priv_create_and_insert_nodes(beg, end, unique, allocator_v2(), std::input_iterator_tag()); - } - else{ - //Optimized allocation and construction - this->allocate_many_and_construct - (beg, std::distance(beg, end), insertion_functor(this->icont())); - } - } + std::pair<iiterator, iiterator> ret = + this->non_const_icont().lower_bound_range(k, KeyNodeCompare(value_comp())); + return std::pair<const_iterator,const_iterator> + (const_iterator(ret.first), const_iterator(ret.second)); } - //Iterator range version - template<class InpIterator> - void priv_create_and_insert_ordered_nodes - (InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) - { - const_iterator cend_n(this->cend()); - for (; beg != end; ++beg){ - this->insert_before(cend_n, *beg); - } - } + void rebalance() + { intrusive_tree_proxy_t::rebalance(this->icont()); } - template<class InpIterator> - void priv_create_and_insert_ordered_nodes - (InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) - { //Just forward to the default one - priv_create_and_insert_ordered_nodes(beg, end, allocator_v1(), std::input_iterator_tag()); - } + friend bool operator==(const tree& x, const tree& y) + { return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); } - class back_insertion_functor; - friend class back_insertion_functor; + friend bool operator<(const tree& x, const tree& y) + { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } - class back_insertion_functor - { - Icont &icont_; + friend bool operator!=(const tree& x, const tree& y) + { return !(x == y); } - public: - back_insertion_functor(Icont &icont) - : icont_(icont) - {} + friend bool operator>(const tree& x, const tree& y) + { return y < x; } - void operator()(Node &n) - { this->icont_.push_back(n); } - }; + friend bool operator<=(const tree& x, const tree& y) + { return !(y < x); } + friend bool operator>=(const tree& x, const tree& y) + { return !(x < y); } - template<class FwdIterator> - void priv_create_and_insert_ordered_nodes - (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), back_insertion_functor(this->icont())); - } - } + friend void swap(tree& x, tree& y) + { x.swap(y); } }; -template <class Key, class Value, class KeyOfValue, - class KeyCompare, class A> -inline bool -operator==(const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x, - const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& y) -{ - return x.size() == y.size() && - std::equal(x.begin(), x.end(), y.begin()); -} - -template <class Key, class Value, class KeyOfValue, - class KeyCompare, class A> -inline bool -operator<(const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x, - const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& y) -{ - return std::lexicographical_compare(x.begin(), x.end(), - y.begin(), y.end()); -} - -template <class Key, class Value, class KeyOfValue, - class KeyCompare, class A> -inline bool -operator!=(const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x, - const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& y) { - return !(x == y); -} - -template <class Key, class Value, class KeyOfValue, - class KeyCompare, class A> -inline bool -operator>(const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x, - const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& y) { - return y < x; -} - -template <class Key, class Value, class KeyOfValue, - class KeyCompare, class A> -inline bool -operator<=(const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x, - const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& y) { - return !(y < x); -} - -template <class Key, class Value, class KeyOfValue, - class KeyCompare, class A> -inline bool -operator>=(const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x, - const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& y) { - return !(x < y); -} - - -template <class Key, class Value, class KeyOfValue, - class KeyCompare, class A> -inline void -swap(rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x, - rbtree<Key,Value,KeyOfValue,KeyCompare,A>& y) -{ - x.swap(y); -} - } //namespace container_detail { } //namespace container { /* @@ -1132,9 +1170,9 @@ swap(rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x, template <class K, class V, class KOV, class C, class A> struct has_trivial_destructor_after_move - <boost::container::container_detail::rbtree<K, V, KOV, C, A> > + <boost::container::container_detail::tree<K, V, KOV, C, A> > { - static const bool value = has_trivial_destructor<A>::value && has_trivial_destructor<C>::value; + static const bool value = has_trivial_destructor_after_move<A>::value && has_trivial_destructor_after_move<C>::value; }; */ } //namespace boost { diff --git a/boost/container/detail/type_traits.hpp b/boost/container/detail/type_traits.hpp index 0e096e54e3..9ff361454a 100644 --- a/boost/container/detail/type_traits.hpp +++ b/boost/container/detail/type_traits.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // (C) Copyright John Maddock 2000. -// (C) Copyright Ion Gaztanaga 2005-2012. +// (C) Copyright Ion Gaztanaga 2005-2013. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -15,13 +15,12 @@ #ifndef BOOST_CONTAINER_CONTAINER_DETAIL_TYPE_TRAITS_HPP #define BOOST_CONTAINER_CONTAINER_DETAIL_TYPE_TRAITS_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" - -#include <boost/move/move.hpp> +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> namespace boost { namespace container { @@ -90,7 +89,7 @@ struct remove_reference<T&> typedef T type; }; -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template<class T> struct remove_reference<T&&> @@ -100,6 +99,15 @@ struct remove_reference<T&&> #else +} // namespace container_detail { +} //namespace container { + +template<class T> +class rv; + +namespace container { +namespace container_detail { + template<class T> struct remove_reference< ::boost::rv<T> > { @@ -164,6 +172,10 @@ template <class T> struct add_const_reference<T&> { typedef T& type; }; +template <class T> +struct add_const +{ typedef const T type; }; + template <typename T, typename U> struct is_same { @@ -201,6 +213,21 @@ struct remove_ref_const typedef typename remove_const< typename remove_reference<T>::type >::type type; }; +template <class T> +struct make_unsigned +{ + typedef T type; +}; + +template <> struct make_unsigned<bool> {}; +template <> struct make_unsigned<signed char> {typedef unsigned char type;}; +template <> struct make_unsigned<signed short> {typedef unsigned short type;}; +template <> struct make_unsigned<signed int> {typedef unsigned int type;}; +template <> struct make_unsigned<signed long> {typedef unsigned long type;}; +#ifdef BOOST_HAS_LONG_LONG +template <> struct make_unsigned<signed long long> {typedef unsigned long long type;}; +#endif + } // namespace container_detail } //namespace container { } //namespace boost { diff --git a/boost/container/detail/utilities.hpp b/boost/container/detail/utilities.hpp index 152b5e162e..25f035df50 100644 --- a/boost/container/detail/utilities.hpp +++ b/boost/container/detail/utilities.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,29 +11,101 @@ #ifndef BOOST_CONTAINER_DETAIL_UTILITIES_HPP #define BOOST_CONTAINER_DETAIL_UTILITIES_HPP -#include "config_begin.hpp" +#if defined(_MSC_VER) +# pragma once +#endif + +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> + #include <cstdio> -#include <boost/type_traits/is_fundamental.hpp> +#include <cstring> //for ::memmove / ::memcpy #include <boost/type_traits/is_pointer.hpp> #include <boost/type_traits/is_enum.hpp> -#include <boost/type_traits/is_member_pointer.hpp> #include <boost/type_traits/is_class.hpp> -#include <boost/move/move.hpp> +#include <boost/type_traits/is_integral.hpp> +#include <boost/type_traits/is_floating_point.hpp> +#include <boost/type_traits/is_copy_constructible.hpp> +#include <boost/type_traits/has_trivial_destructor.hpp> +#include <boost/type_traits/has_trivial_copy.hpp> +#include <boost/type_traits/has_trivial_assign.hpp> +#include <boost/type_traits/is_pod.hpp> +#include <boost/move/core.hpp> +#include <boost/move/utility_core.hpp> +#include <boost/move/iterator.hpp> +#include <boost/assert.hpp> +#include <boost/container/throw_exception.hpp> #include <boost/container/detail/mpl.hpp> #include <boost/container/detail/type_traits.hpp> #include <boost/container/allocator_traits.hpp> -#include <algorithm> +#include <boost/core/no_exceptions_support.hpp> +#include <boost/container/detail/memory_util.hpp> +#include <boost/intrusive/pointer_traits.hpp> +#include <boost/aligned_storage.hpp> +#include <iterator> +#include <utility> //std::distance namespace boost { namespace container { + +////////////////////////////////////////////////////////////////////////////// +// +// swap +// +////////////////////////////////////////////////////////////////////////////// + +namespace container_swap { + +template<class T, bool IsClass = boost::is_class<T>::value > +struct has_member_swap +{ + static const bool value = boost::container::container_detail:: + has_member_function_callable_with_swap<T, T &>::value; +}; + +template<class T> +struct has_member_swap<T, false> +{ + static const bool value = false; +}; + +} //namespace container_swap { + +template<class T> inline +typename container_detail::enable_if_c + <container_swap::has_member_swap<T>::value, void>::type +swap_dispatch(T &left, T &right) //swap using member swap +{ + left.swap(right); // may throw +} + +template<class T> inline +typename container_detail::enable_if_c + <!container_swap::has_member_swap<T>::value/* && boost::has_move_emulation_enabled<T>::value*/, void>::type + swap_dispatch(T &left, T &right) +{ + T temp(boost::move(left)); // may throw + left = boost::move(right); // may throw + right = boost::move(temp); // may throw +} +/* +template<class T> inline +typename container_detail::enable_if_c + <!container_swap::has_member_swap<T>::value && !boost::has_move_emulation_enabled<T>::value, void>::type + swap_dispatch(T &left, T &right) +{ + using std::swap; + swap(left, right); // may throw +} +*/ namespace container_detail { template <typename T> inline T* addressof(T& obj) { return static_cast<T*>( - static_cast<void*>( - const_cast<char*>( + static_cast<void*>( + const_cast<char*>( &reinterpret_cast<const char&>(obj) ))); } @@ -46,42 +118,73 @@ template<class T> const T &min_value(const T &a, const T &b) { return a < b ? a : b; } -template <class SizeType> -SizeType - get_next_capacity(const SizeType max_size - ,const SizeType capacity - ,const SizeType n) +enum NextCapacityOption { NextCapacityDouble, NextCapacity60Percent }; + +template<class SizeType, NextCapacityOption Option> +struct next_capacity_calculator; + +template<class SizeType> +struct next_capacity_calculator<SizeType, NextCapacityDouble> { -// if (n > max_size - capacity) -// throw std::length_error("get_next_capacity"); + static SizeType get(const SizeType max_size + ,const SizeType capacity + ,const SizeType n) + { + const SizeType remaining = max_size - capacity; + if ( remaining < n ) + boost::container::throw_length_error("get_next_capacity, allocator's max_size reached"); + const SizeType additional = max_value(n, capacity); + return ( remaining < additional ) ? max_size : ( capacity + additional ); + } +}; - const SizeType m3 = max_size/3; - if (capacity < m3) - return capacity + max_value(3*(capacity+1)/5, n); +template<class SizeType> +struct next_capacity_calculator<SizeType, NextCapacity60Percent> +{ + static SizeType get(const SizeType max_size + ,const SizeType capacity + ,const SizeType n) + { + const SizeType remaining = max_size - capacity; + if ( remaining < n ) + boost::container::throw_length_error("get_next_capacity, allocator's max_size reached"); + const SizeType m3 = max_size/3; - if (capacity < m3*2) - return capacity + max_value((capacity+1)/2, n); + if (capacity < m3) + return capacity + max_value(3*(capacity+1)/5, n); - return max_size; -} + if (capacity < m3*2) + return capacity + max_value((capacity+1)/2, n); + return max_size; + } +}; template <class T> inline T* to_raw_pointer(T* p) { return p; } template <class Pointer> -inline typename Pointer::element_type* +inline typename boost::intrusive::pointer_traits<Pointer>::element_type* to_raw_pointer(const Pointer &p) { return boost::container::container_detail::to_raw_pointer(p.operator->()); } -//!To avoid ADL problems with swap template <class T> -inline void do_swap(T& x, T& y) -{ - using std::swap; - swap(x, y); -} +inline T* iterator_to_pointer(T* i) +{ return i; } + +template <class Iterator> +inline typename std::iterator_traits<Iterator>::pointer + iterator_to_pointer(const Iterator &i) +{ return i.operator->(); } + +template <class Iterator> +inline + typename boost::intrusive::pointer_traits + <typename std::iterator_traits<Iterator>::pointer>::element_type* + iterator_to_raw_pointer(const Iterator &i) +{ return (to_raw_pointer)((iterator_to_pointer)(i)); } + template<class AllocatorType> inline void swap_alloc(AllocatorType &, AllocatorType &, container_detail::false_type) @@ -90,7 +193,7 @@ inline void swap_alloc(AllocatorType &, AllocatorType &, container_detail::false template<class AllocatorType> inline void swap_alloc(AllocatorType &l, AllocatorType &r, container_detail::true_type) -{ container_detail::do_swap(l, r); } +{ boost::container::swap_dispatch(l, r); } template<class AllocatorType> inline void assign_alloc(AllocatorType &, const AllocatorType &, container_detail::false_type) @@ -122,101 +225,340 @@ struct ct_rounded_size { enum { value = ((OrigSize-1)/RoundTo+1)*RoundTo }; }; -/* -template <class _TypeT> -struct __rw_is_enum + +template<class I> +struct are_elements_contiguous +{ + static const bool value = false; +}; + +///////////////////////// +// raw pointers +///////////////////////// + +template<class T> +struct are_elements_contiguous<T*> +{ + static const bool value = true; +}; + +///////////////////////// +// predeclarations +///////////////////////// + +#ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + +template<class Pointer> +class vector_iterator; + +template<class Pointer> +class vector_const_iterator; + +#endif //BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + +} //namespace container_detail { +} //namespace container { + +namespace interprocess { + +template <class PointedType, class DifferenceType, class OffsetType, std::size_t OffsetAlignment> +class offset_ptr; + +} //namespace interprocess { + +namespace container { + +namespace container_detail { + +///////////////////////// +//vector_[const_]iterator +///////////////////////// + +#ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + +template<class Pointer> +struct are_elements_contiguous<boost::container::container_detail::vector_iterator<Pointer> > { - struct _C_no { }; - struct _C_yes { int _C_dummy [2]; }; + static const bool value = true; +}; - struct _C_indirect { - // prevent classes with user-defined conversions from matching +template<class Pointer> +struct are_elements_contiguous<boost::container::container_detail::vector_const_iterator<Pointer> > +{ + static const bool value = true; +}; + +#endif //BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER - // use double to prevent float->int gcc conversion warnings - _C_indirect (double); +///////////////////////// +// offset_ptr +///////////////////////// + +template <class PointedType, class DifferenceType, class OffsetType, std::size_t OffsetAlignment> +struct are_elements_contiguous< ::boost::interprocess::offset_ptr<PointedType, DifferenceType, OffsetType, OffsetAlignment> > +{ + static const bool value = true; }; -// nested struct gets rid of bogus gcc errors -struct _C_nest { - // supply first argument to prevent HP aCC warnings - static _C_no _C_is (int, ...); - static _C_yes _C_is (int, _C_indirect); +template <typename I, typename O> +struct are_contiguous_and_same +{ + static const bool is_same_io = + is_same< typename remove_const< typename ::std::iterator_traits<I>::value_type >::type + , typename ::std::iterator_traits<O>::value_type + >::value; + static const bool value = is_same_io && + are_elements_contiguous<I>::value && + are_elements_contiguous<O>::value; +}; - static _TypeT _C_make_T (); +template <typename I, typename O> +struct is_memtransfer_copy_assignable +{ + static const bool value = are_contiguous_and_same<I, O>::value && + boost::has_trivial_assign< typename ::std::iterator_traits<I>::value_type >::value; }; -enum { - _C_val = sizeof (_C_yes) == sizeof (_C_nest::_C_is (0, _C_nest::_C_make_T ())) - && !::boost::is_fundamental<_TypeT>::value +template <typename I, typename O> +struct is_memtransfer_copy_constructible +{ + static const bool value = are_contiguous_and_same<I, O>::value && + boost::has_trivial_copy< typename ::std::iterator_traits<I>::value_type >::value; }; +template <typename I, typename O, typename R> +struct enable_if_memtransfer_copy_constructible + : public enable_if_c<container_detail::is_memtransfer_copy_constructible<I, O>::value, R> +{}; + +template <typename I, typename O, typename R> +struct disable_if_memtransfer_copy_constructible + : public enable_if_c<!container_detail::is_memtransfer_copy_constructible<I, O>::value, R> +{}; + +template <typename I, typename O, typename R> +struct enable_if_memtransfer_copy_assignable + : public enable_if_c<container_detail::is_memtransfer_copy_assignable<I, O>::value, R> +{}; + +template <typename I, typename O, typename R> +struct disable_if_memtransfer_copy_assignable + : public enable_if_c<!container_detail::is_memtransfer_copy_assignable<I, O>::value, R> +{}; + +template + <typename I, // I models InputIterator + typename F> // F models ForwardIterator +inline F memmove(I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ + typedef typename std::iterator_traits<I>::value_type value_type; + typename std::iterator_traits<I>::difference_type n = std::distance(f, l); + ::memmove((iterator_to_raw_pointer)(r), (iterator_to_raw_pointer)(f), sizeof(value_type)*n); + std::advance(r, n); + return r; +} + +template + <typename I, // I models InputIterator + typename F> // F models ForwardIterator +F memmove_n(I f, typename std::iterator_traits<I>::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ + typedef typename std::iterator_traits<I>::value_type value_type; + ::memmove((iterator_to_raw_pointer)(r), (iterator_to_raw_pointer)(f), sizeof(value_type)*n); + std::advance(r, n); + return r; +} + +template + <typename I, // I models InputIterator + typename F> // F models ForwardIterator +I memmove_n_source(I f, typename std::iterator_traits<I>::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ + typedef typename std::iterator_traits<I>::value_type value_type; + ::memmove((iterator_to_raw_pointer)(r), (iterator_to_raw_pointer)(f), sizeof(value_type)*n); + std::advance(f, n); + return f; +} + +template + <typename I, // I models InputIterator + typename F> // F models ForwardIterator +I memmove_n_source_dest(I f, typename std::iterator_traits<I>::difference_type n, F &r) BOOST_CONTAINER_NOEXCEPT +{ + typedef typename std::iterator_traits<I>::value_type value_type; + ::memmove((iterator_to_raw_pointer)(r), (iterator_to_raw_pointer)(f), sizeof(value_type)*n); + std::advance(f, n); + std::advance(r, n); + return f; +} + +template <typename O> +struct is_memzero_initializable +{ + typedef typename ::std::iterator_traits<O>::value_type value_type; + static const bool value = are_elements_contiguous<O>::value && + ( ::boost::is_integral<value_type>::value || ::boost::is_enum<value_type>::value + #if defined(BOOST_CONTAINER_MEMZEROED_POINTER_IS_NULL) + || ::boost::is_pointer<value_type>::value + #endif + #if defined(BOOST_CONTAINER_MEMZEROED_FLOATING_POINT_IS_ZERO) + || ::boost::is_floating_point<value_type>::value + #endif + #if defined(BOOST_CONTAINER_MEMZEROED_FLOATING_POINT_IS_ZERO) && defined(BOOST_CONTAINER_MEMZEROED_POINTER_IS_NULL) + || ::boost::is_pod<value_type>::value + #endif + ); }; -*/ -template<class T> -struct move_const_ref_type - : if_c -// < ::boost::is_fundamental<T>::value || ::boost::is_pointer<T>::value || ::boost::is_member_pointer<T>::value || ::boost::is_enum<T>::value - < !::boost::is_class<T>::value - ,const T & - ,BOOST_CATCH_CONST_RLVALUE(T) - > +template <typename O, typename R> +struct enable_if_memzero_initializable + : public enable_if_c<container_detail::is_memzero_initializable<O>::value, R> +{}; + +template <typename O, typename R> +struct disable_if_memzero_initializable + : public enable_if_c<!container_detail::is_memzero_initializable<O>::value, R> {}; } //namespace container_detail { + ////////////////////////////////////////////////////////////////////////////// // // uninitialized_move_alloc // ////////////////////////////////////////////////////////////////////////////// + //! <b>Effects</b>: //! \code -//! for (; first != last; ++result, ++first) -//! allocator_traits::construct(a, &*result, boost::move(*first)); +//! for (; f != l; ++r, ++f) +//! allocator_traits::construct(a, &*r, boost::move(*f)); //! \endcode //! -//! <b>Returns</b>: result +//! <b>Returns</b>: r template <typename A, typename I, // I models InputIterator typename F> // F models ForwardIterator -F uninitialized_move_alloc(A &a, I f, I l, F r) +inline typename container_detail::disable_if_memtransfer_copy_constructible<I, F, F>::type + uninitialized_move_alloc(A &a, I f, I l, F r) { - while (f != l) { - allocator_traits<A>::construct(a, container_detail::to_raw_pointer(&*r), boost::move(*f)); - ++f; ++r; + F back = r; + BOOST_TRY{ + while (f != l) { + allocator_traits<A>::construct(a, container_detail::iterator_to_raw_pointer(r), boost::move(*f)); + ++f; ++r; + } } + BOOST_CATCH(...){ + for (; back != r; ++back){ + allocator_traits<A>::destroy(a, container_detail::iterator_to_raw_pointer(back)); + } + BOOST_RETHROW; + } + BOOST_CATCH_END return r; } +template + <typename A, + typename I, // I models InputIterator + typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memtransfer_copy_constructible<I, F, F>::type + uninitialized_move_alloc(A &, I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memmove(f, l, r); } + ////////////////////////////////////////////////////////////////////////////// // -// uninitialized_copy_alloc +// uninitialized_move_alloc_n // ////////////////////////////////////////////////////////////////////////////// //! <b>Effects</b>: //! \code -//! for (; first != last; ++result, ++first) -//! allocator_traits::construct(a, &*result, *first); +//! for (; n--; ++r, ++f) +//! allocator_traits::construct(a, &*r, boost::move(*f)); //! \endcode //! -//! <b>Returns</b>: result +//! <b>Returns</b>: r template <typename A, typename I, // I models InputIterator typename F> // F models ForwardIterator -F uninitialized_copy_alloc(A &a, I f, I l, F r) +inline typename container_detail::disable_if_memtransfer_copy_constructible<I, F, F>::type + uninitialized_move_alloc_n(A &a, I f, typename std::iterator_traits<I>::difference_type n, F r) { - while (f != l) { - allocator_traits<A>::construct(a, container_detail::to_raw_pointer(&*r), *f); - ++f; ++r; + F back = r; + BOOST_TRY{ + while (n--) { + allocator_traits<A>::construct(a, container_detail::iterator_to_raw_pointer(r), boost::move(*f)); + ++f; ++r; + } } + BOOST_CATCH(...){ + for (; back != r; ++back){ + allocator_traits<A>::destroy(a, container_detail::iterator_to_raw_pointer(back)); + } + BOOST_RETHROW; + } + BOOST_CATCH_END return r; } +template + <typename A, + typename I, // I models InputIterator + typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memtransfer_copy_constructible<I, F, F>::type + uninitialized_move_alloc_n(A &, I f, typename std::iterator_traits<I>::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memmove_n(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_move_alloc_n_source +// +////////////////////////////////////////////////////////////////////////////// + +//! <b>Effects</b>: +//! \code +//! for (; n--; ++r, ++f) +//! allocator_traits::construct(a, &*r, boost::move(*f)); +//! \endcode +//! +//! <b>Returns</b>: f (after incremented) +template + <typename A, + typename I, // I models InputIterator + typename F> // F models ForwardIterator +inline typename container_detail::disable_if_memtransfer_copy_constructible<I, F, I>::type + uninitialized_move_alloc_n_source(A &a, I f, typename std::iterator_traits<I>::difference_type n, F r) +{ + F back = r; + BOOST_TRY{ + while (n--) { + allocator_traits<A>::construct(a, container_detail::iterator_to_raw_pointer(r), boost::move(*f)); + ++f; ++r; + } + } + BOOST_CATCH(...){ + for (; back != r; ++back){ + allocator_traits<A>::destroy(a, container_detail::iterator_to_raw_pointer(back)); + } + BOOST_RETHROW; + } + BOOST_CATCH_END + return f; +} + +template + <typename A, + typename I, // I models InputIterator + typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memtransfer_copy_constructible<I, F, I>::type + uninitialized_move_alloc_n_source(A &, I f, typename std::iterator_traits<I>::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memmove_n_source(f, n, r); } + ////////////////////////////////////////////////////////////////////////////// // // uninitialized_copy_alloc @@ -225,58 +567,701 @@ F uninitialized_copy_alloc(A &a, I f, I l, F r) //! <b>Effects</b>: //! \code -//! for (; first != last; ++result, ++first) -//! allocator_traits::construct(a, &*result, *first); +//! for (; f != l; ++r, ++f) +//! allocator_traits::construct(a, &*r, *f); +//! \endcode +//! +//! <b>Returns</b>: r +template + <typename A, + typename I, // I models InputIterator + typename F> // F models ForwardIterator +inline typename container_detail::disable_if_memtransfer_copy_constructible<I, F, F>::type + uninitialized_copy_alloc(A &a, I f, I l, F r) +{ + F back = r; + BOOST_TRY{ + while (f != l) { + allocator_traits<A>::construct(a, container_detail::iterator_to_raw_pointer(r), *f); + ++f; ++r; + } + } + BOOST_CATCH(...){ + for (; back != r; ++back){ + allocator_traits<A>::destroy(a, container_detail::iterator_to_raw_pointer(back)); + } + BOOST_RETHROW; + } + BOOST_CATCH_END + return r; +} + +template + <typename A, + typename I, // I models InputIterator + typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memtransfer_copy_constructible<I, F, F>::type + uninitialized_copy_alloc(A &, I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memmove(f, l, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_copy_alloc_n +// +////////////////////////////////////////////////////////////////////////////// + +//! <b>Effects</b>: +//! \code +//! for (; n--; ++r, ++f) +//! allocator_traits::construct(a, &*r, *f); //! \endcode //! -//! <b>Returns</b>: result +//! <b>Returns</b>: r +template + <typename A, + typename I, // I models InputIterator + typename F> // F models ForwardIterator +inline typename container_detail::disable_if_memtransfer_copy_constructible<I, F, F>::type + uninitialized_copy_alloc_n(A &a, I f, typename std::iterator_traits<I>::difference_type n, F r) +{ + F back = r; + BOOST_TRY{ + while (n--) { + allocator_traits<A>::construct(a, container_detail::iterator_to_raw_pointer(r), *f); + ++f; ++r; + } + } + BOOST_CATCH(...){ + for (; back != r; ++back){ + allocator_traits<A>::destroy(a, container_detail::iterator_to_raw_pointer(back)); + } + BOOST_RETHROW; + } + BOOST_CATCH_END + return r; +} + +template + <typename A, + typename I, // I models InputIterator + typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memtransfer_copy_constructible<I, F, F>::type + uninitialized_copy_alloc_n(A &, I f, typename std::iterator_traits<I>::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memmove_n(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_copy_alloc_n_source +// +////////////////////////////////////////////////////////////////////////////// + +//! <b>Effects</b>: +//! \code +//! for (; n--; ++r, ++f) +//! allocator_traits::construct(a, &*r, *f); +//! \endcode +//! +//! <b>Returns</b>: f (after incremented) +template + <typename A, + typename I, // I models InputIterator + typename F> // F models ForwardIterator +inline typename container_detail::disable_if_memtransfer_copy_constructible<I, F, I>::type + uninitialized_copy_alloc_n_source(A &a, I f, typename std::iterator_traits<I>::difference_type n, F r) +{ + F back = r; + BOOST_TRY{ + while (n--) { + allocator_traits<A>::construct(a, container_detail::iterator_to_raw_pointer(r), *f); + ++f; ++r; + } + } + BOOST_CATCH(...){ + for (; back != r; ++back){ + allocator_traits<A>::destroy(a, container_detail::iterator_to_raw_pointer(back)); + } + BOOST_RETHROW; + } + BOOST_CATCH_END + return f; +} + +template + <typename A, + typename I, // I models InputIterator + typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memtransfer_copy_constructible<I, F, I>::type + uninitialized_copy_alloc_n_source(A &, I f, typename std::iterator_traits<I>::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memmove_n_source(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_value_init_alloc_n +// +////////////////////////////////////////////////////////////////////////////// + +//! <b>Effects</b>: +//! \code +//! for (; n--; ++r, ++f) +//! allocator_traits::construct(a, &*r); +//! \endcode +//! +//! <b>Returns</b>: r +template + <typename A, + typename F> // F models ForwardIterator +inline typename container_detail::disable_if_memzero_initializable<F, F>::type + uninitialized_value_init_alloc_n(A &a, typename allocator_traits<A>::difference_type n, F r) +{ + F back = r; + BOOST_TRY{ + while (n--) { + allocator_traits<A>::construct(a, container_detail::iterator_to_raw_pointer(r)); + ++r; + } + } + BOOST_CATCH(...){ + for (; back != r; ++back){ + allocator_traits<A>::destroy(a, container_detail::iterator_to_raw_pointer(back)); + } + BOOST_RETHROW; + } + BOOST_CATCH_END + return r; +} + +template + <typename A, + typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memzero_initializable<F, F>::type + uninitialized_value_init_alloc_n(A &, typename allocator_traits<A>::difference_type n, F r) +{ + typedef typename std::iterator_traits<F>::value_type value_type; + ::memset((void*)container_detail::iterator_to_raw_pointer(r), 0, sizeof(value_type)*n); + std::advance(r, n); + return r; +} + +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_default_init_alloc_n +// +////////////////////////////////////////////////////////////////////////////// + +//! <b>Effects</b>: +//! \code +//! for (; n--; ++r, ++f) +//! allocator_traits::construct(a, &*r); +//! \endcode +//! +//! <b>Returns</b>: r +template + <typename A, + typename F> // F models ForwardIterator +inline F uninitialized_default_init_alloc_n(A &a, typename allocator_traits<A>::difference_type n, F r) +{ + F back = r; + BOOST_TRY{ + while (n--) { + allocator_traits<A>::construct(a, container_detail::iterator_to_raw_pointer(r), default_init); + ++r; + } + } + BOOST_CATCH(...){ + for (; back != r; ++back){ + allocator_traits<A>::destroy(a, container_detail::iterator_to_raw_pointer(back)); + } + BOOST_RETHROW; + } + BOOST_CATCH_END + return r; +} + +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_fill_alloc +// +////////////////////////////////////////////////////////////////////////////// + +//! <b>Effects</b>: +//! \code +//! for (; f != l; ++r, ++f) +//! allocator_traits::construct(a, &*r, *f); +//! \endcode +//! +//! <b>Returns</b>: r template <typename A, typename F, // F models ForwardIterator typename T> -void uninitialized_fill_alloc(A &a, F f, F l, const T &t) +inline void uninitialized_fill_alloc(A &a, F f, F l, const T &t) +{ + F back = f; + BOOST_TRY{ + while (f != l) { + allocator_traits<A>::construct(a, container_detail::iterator_to_raw_pointer(f), t); + ++f; + } + } + BOOST_CATCH(...){ + for (; back != l; ++back){ + allocator_traits<A>::destroy(a, container_detail::iterator_to_raw_pointer(back)); + } + BOOST_RETHROW; + } + BOOST_CATCH_END +} + + +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_fill_alloc_n +// +////////////////////////////////////////////////////////////////////////////// + +//! <b>Effects</b>: +//! \code +//! for (; n--; ++r, ++f) +//! allocator_traits::construct(a, &*r, v); +//! \endcode +//! +//! <b>Returns</b>: r +template + <typename A, + typename T, + typename F> // F models ForwardIterator +inline F uninitialized_fill_alloc_n(A &a, const T &v, typename allocator_traits<A>::difference_type n, F r) +{ + F back = r; + BOOST_TRY{ + while (n--) { + allocator_traits<A>::construct(a, container_detail::iterator_to_raw_pointer(r), v); + ++r; + } + } + BOOST_CATCH(...){ + for (; back != r; ++back){ + allocator_traits<A>::destroy(a, container_detail::iterator_to_raw_pointer(back)); + } + BOOST_RETHROW; + } + BOOST_CATCH_END + return r; +} + +////////////////////////////////////////////////////////////////////////////// +// +// copy +// +////////////////////////////////////////////////////////////////////////////// + +template +<typename I, // I models InputIterator +typename F> // F models ForwardIterator +inline typename container_detail::disable_if_memtransfer_copy_assignable<I, F, F>::type + copy(I f, I l, F r) { while (f != l) { - allocator_traits<A>::construct(a, container_detail::to_raw_pointer(&*f), t); - ++f; + *r = *f; + ++f; ++r; } + return r; } +template +<typename I, // I models InputIterator +typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memtransfer_copy_assignable<I, F, F>::type + copy(I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memmove(f, l, r); } + ////////////////////////////////////////////////////////////////////////////// // -// uninitialized_copy_or_move_alloc +// copy_n // ////////////////////////////////////////////////////////////////////////////// template -<typename A -,typename I // I models InputIterator +<typename I, // I models InputIterator +typename F> // F models ForwardIterator +inline typename container_detail::disable_if_memtransfer_copy_assignable<I, F, F>::type + copy_n(I f, typename std::iterator_traits<I>::difference_type n, F r) +{ + while (n--) { + *r = *f; + ++f; ++r; + } + return r; +} + +template +<typename I, // I models InputIterator +typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memtransfer_copy_assignable<I, F, F>::type + copy_n(I f, typename std::iterator_traits<I>::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memmove_n(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// copy_n_source +// +////////////////////////////////////////////////////////////////////////////// + +template +<typename I, // I models InputIterator +typename F> // F models ForwardIterator +inline typename container_detail::disable_if_memtransfer_copy_assignable<I, F, I>::type + copy_n_source(I f, typename std::iterator_traits<I>::difference_type n, F r) +{ + while (n--) { + *r = *f; + ++f; ++r; + } + return f; +} + +template +<typename I, // I models InputIterator +typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memtransfer_copy_assignable<I, F, I>::type + copy_n_source(I f, typename std::iterator_traits<I>::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memmove_n_source(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// copy_n_source_dest +// +////////////////////////////////////////////////////////////////////////////// + +template +<typename I, // I models InputIterator +typename F> // F models ForwardIterator +inline typename container_detail::disable_if_memtransfer_copy_assignable<I, F, I>::type + copy_n_source_dest(I f, typename std::iterator_traits<I>::difference_type n, F &r) +{ + while (n--) { + *r = *f; + ++f; ++r; + } + return f; +} + +template +<typename I, // I models InputIterator +typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memtransfer_copy_assignable<I, F, I>::type + copy_n_source_dest(I f, typename std::iterator_traits<I>::difference_type n, F &r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memmove_n_source_dest(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// move +// +////////////////////////////////////////////////////////////////////////////// + +template +<typename I, // I models InputIterator +typename F> // F models ForwardIterator +inline typename container_detail::disable_if_memtransfer_copy_assignable<I, F, F>::type + move(I f, I l, F r) +{ + while (f != l) { + *r = ::boost::move(*f); + ++f; ++r; + } + return r; +} + +template +<typename I, // I models InputIterator +typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memtransfer_copy_assignable<I, F, F>::type + move(I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memmove(f, l, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// move_n +// +////////////////////////////////////////////////////////////////////////////// + +template +<typename I, // I models InputIterator +typename F> // F models ForwardIterator +inline typename container_detail::disable_if_memtransfer_copy_assignable<I, F, F>::type + move_n(I f, typename std::iterator_traits<I>::difference_type n, F r) +{ + while (n--) { + *r = ::boost::move(*f); + ++f; ++r; + } + return r; +} + +template +<typename I, // I models InputIterator +typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memtransfer_copy_assignable<I, F, F>::type + move_n(I f, typename std::iterator_traits<I>::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memmove_n(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// move_n_source +// +////////////////////////////////////////////////////////////////////////////// + +template +<typename I // I models InputIterator ,typename F> // F models ForwardIterator -F uninitialized_copy_or_move_alloc - (A &a, I f, I l, F r - ,typename boost::container::container_detail::enable_if - < boost::move_detail::is_move_iterator<I> >::type* = 0) +inline typename container_detail::disable_if_memtransfer_copy_assignable<I, F, I>::type + move_n_source(I f, typename std::iterator_traits<I>::difference_type n, F r) { - return ::boost::container::uninitialized_move_alloc(a, f, l, r); + while (n--) { + *r = ::boost::move(*f); + ++f; ++r; + } + return f; } template -<typename A -,typename I // I models InputIterator +<typename I // I models InputIterator +,typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memtransfer_copy_assignable<I, F, I>::type + move_n_source(I f, typename std::iterator_traits<I>::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memmove_n_source(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// move_n_source_dest +// +////////////////////////////////////////////////////////////////////////////// + +template +<typename I // I models InputIterator ,typename F> // F models ForwardIterator -F uninitialized_copy_or_move_alloc - (A &a, I f, I l, F r - ,typename boost::container::container_detail::disable_if - < boost::move_detail::is_move_iterator<I> >::type* = 0) +inline typename container_detail::disable_if_memtransfer_copy_assignable<I, F, I>::type + move_n_source_dest(I f, typename std::iterator_traits<I>::difference_type n, F &r) { - return ::boost::container::uninitialized_copy_alloc(a, f, l, r); + while (n--) { + *r = ::boost::move(*f); + ++f; ++r; + } + return f; } +template +<typename I // I models InputIterator +,typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memtransfer_copy_assignable<I, F, I>::type + move_n_source_dest(I f, typename std::iterator_traits<I>::difference_type n, F &r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memmove_n_source_dest(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// destroy_n +// +////////////////////////////////////////////////////////////////////////////// + +template + <typename A + ,typename I> // I models InputIterator +inline void destroy_alloc_n(A &a, I f, typename std::iterator_traits<I>::difference_type n + ,typename boost::container::container_detail::enable_if_c + < !boost::has_trivial_destructor<typename std::iterator_traits<I>::value_type>::value >::type* = 0) +{ + while(n--){ + allocator_traits<A>::destroy(a, container_detail::iterator_to_raw_pointer(f++)); + } +} + +template + <typename A + ,typename I> // I models InputIterator +inline void destroy_alloc_n(A &, I, typename std::iterator_traits<I>::difference_type + ,typename boost::container::container_detail::enable_if_c + < boost::has_trivial_destructor<typename std::iterator_traits<I>::value_type>::value >::type* = 0) +{} + +////////////////////////////////////////////////////////////////////////////// +// +// deep_swap_alloc_n +// +////////////////////////////////////////////////////////////////////////////// + +template + <std::size_t MaxTmpBytes + ,typename A + ,typename F // F models ForwardIterator + ,typename G // G models ForwardIterator + > +inline typename container_detail::disable_if_memtransfer_copy_assignable<F, G, void>::type + deep_swap_alloc_n( A &a, F short_range_f, typename allocator_traits<A>::size_type n_i + , G large_range_f, typename allocator_traits<A>::size_type n_j) +{ + typename allocator_traits<A>::size_type n = 0; + for (; n != n_i ; ++short_range_f, ++large_range_f, ++n){ + boost::container::swap_dispatch(*short_range_f, *large_range_f); + } + boost::container::uninitialized_move_alloc_n(a, large_range_f, n_j - n_i, short_range_f); // may throw + boost::container::destroy_alloc_n(a, large_range_f, n_j - n_i); +} + +static const std::size_t DeepSwapAllocNMaxStorage = std::size_t(1) << std::size_t(11); //2K bytes + +template + <std::size_t MaxTmpBytes + ,typename A + ,typename F // F models ForwardIterator + ,typename G // G models ForwardIterator + > +inline typename container_detail::enable_if_c + < container_detail::is_memtransfer_copy_assignable<F, G>::value && (MaxTmpBytes <= DeepSwapAllocNMaxStorage) && false + , void>::type + deep_swap_alloc_n( A &a, F short_range_f, typename allocator_traits<A>::size_type n_i + , G large_range_f, typename allocator_traits<A>::size_type n_j) +{ + typedef typename allocator_traits<A>::value_type value_type; + typedef typename boost::aligned_storage + <MaxTmpBytes, container_detail::alignment_of<value_type>::value>::type storage_type; + storage_type storage; + + const std::size_t n_i_bytes = sizeof(value_type)*n_i; + void *const large_ptr = static_cast<void*>(container_detail::iterator_to_raw_pointer(large_range_f)); + void *const short_ptr = static_cast<void*>(container_detail::iterator_to_raw_pointer(short_range_f)); + void *const stora_ptr = static_cast<void*>(container_detail::iterator_to_raw_pointer(storage)); + ::memcpy(stora_ptr, large_ptr, n_i_bytes); + ::memcpy(large_ptr, short_ptr, n_i_bytes); + ::memcpy(short_ptr, stora_ptr, n_i_bytes); + std::advance(large_range_f, n_i); + std::advance(short_range_f, n_i); + boost::container::uninitialized_move_alloc_n(a, large_range_f, n_j - n_i, short_range_f); // may throw + boost::container::destroy_alloc_n(a, large_range_f, n_j - n_i); +} + +template + <std::size_t MaxTmpBytes + ,typename A + ,typename F // F models ForwardIterator + ,typename G // G models ForwardIterator + > +inline typename container_detail::enable_if_c + < container_detail::is_memtransfer_copy_assignable<F, G>::value && true//(MaxTmpBytes > DeepSwapAllocNMaxStorage) + , void>::type + deep_swap_alloc_n( A &a, F short_range_f, typename allocator_traits<A>::size_type n_i + , G large_range_f, typename allocator_traits<A>::size_type n_j) +{ + typedef typename allocator_traits<A>::value_type value_type; + typedef typename boost::aligned_storage + <DeepSwapAllocNMaxStorage, container_detail::alignment_of<value_type>::value>::type storage_type; + storage_type storage; + const std::size_t sizeof_storage = sizeof(storage); + + std::size_t n_i_bytes = sizeof(value_type)*n_i; + char *large_ptr = static_cast<char*>(static_cast<void*>(container_detail::iterator_to_raw_pointer(large_range_f))); + char *short_ptr = static_cast<char*>(static_cast<void*>(container_detail::iterator_to_raw_pointer(short_range_f))); + char *stora_ptr = static_cast<char*>(static_cast<void*>(&storage)); + + std::size_t szt_times = n_i_bytes/sizeof_storage; + const std::size_t szt_rem = n_i_bytes%sizeof_storage; + + //Loop unrolling using Duff's device, as it seems it helps on some architectures + const std::size_t Unroll = 4; + std::size_t n = (szt_times + (Unroll-1))/Unroll; + const std::size_t branch_number = (!szt_times)*Unroll + (szt_times % Unroll); + switch(branch_number){ + case 4: + break; + case 0: do{ + ::memcpy(stora_ptr, large_ptr, sizeof_storage); + ::memcpy(large_ptr, short_ptr, sizeof_storage); + ::memcpy(short_ptr, stora_ptr, sizeof_storage); + large_ptr += sizeof_storage; + short_ptr += sizeof_storage; + BOOST_CONTAINER_FALLTHOUGH + case 3: + ::memcpy(stora_ptr, large_ptr, sizeof_storage); + ::memcpy(large_ptr, short_ptr, sizeof_storage); + ::memcpy(short_ptr, stora_ptr, sizeof_storage); + large_ptr += sizeof_storage; + short_ptr += sizeof_storage; + BOOST_CONTAINER_FALLTHOUGH + case 2: + ::memcpy(stora_ptr, large_ptr, sizeof_storage); + ::memcpy(large_ptr, short_ptr, sizeof_storage); + ::memcpy(short_ptr, stora_ptr, sizeof_storage); + large_ptr += sizeof_storage; + short_ptr += sizeof_storage; + BOOST_CONTAINER_FALLTHOUGH + case 1: + ::memcpy(stora_ptr, large_ptr, sizeof_storage); + ::memcpy(large_ptr, short_ptr, sizeof_storage); + ::memcpy(short_ptr, stora_ptr, sizeof_storage); + large_ptr += sizeof_storage; + short_ptr += sizeof_storage; + } while(--n); + } + ::memcpy(stora_ptr, large_ptr, szt_rem); + ::memcpy(large_ptr, short_ptr, szt_rem); + ::memcpy(short_ptr, stora_ptr, szt_rem); + std::advance(large_range_f, n_i); + std::advance(short_range_f, n_i); + boost::container::uninitialized_move_alloc_n(a, large_range_f, n_j - n_i, short_range_f); // may throw + boost::container::destroy_alloc_n(a, large_range_f, n_j - n_i); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// copy_assign_range_alloc_n +// +////////////////////////////////////////////////////////////////////////////// + +template + <typename A + ,typename I // F models InputIterator + ,typename O // G models OutputIterator + > +void copy_assign_range_alloc_n( A &a, I inp_start, typename allocator_traits<A>::size_type n_i + , O out_start, typename allocator_traits<A>::size_type n_o ) +{ + if (n_o < n_i){ + inp_start = boost::container::copy_n_source_dest(inp_start, n_o, out_start); // may throw + boost::container::uninitialized_copy_alloc_n(a, inp_start, n_i - n_o, out_start);// may throw + } + else{ + out_start = boost::container::copy_n(inp_start, n_i, out_start); // may throw + boost::container::destroy_alloc_n(a, out_start, n_o - n_i); + } +} + +////////////////////////////////////////////////////////////////////////////// +// +// move_assign_range_alloc_n +// +////////////////////////////////////////////////////////////////////////////// + +template + <typename A + ,typename I // F models InputIterator + ,typename O // G models OutputIterator + > +void move_assign_range_alloc_n( A &a, I inp_start, typename allocator_traits<A>::size_type n_i + , O out_start, typename allocator_traits<A>::size_type n_o ) +{ + if (n_o < n_i){ + inp_start = boost::container::move_n_source_dest(inp_start, n_o, out_start); // may throw + boost::container::uninitialized_move_alloc_n(a, inp_start, n_i - n_o, out_start); // may throw + } + else{ + out_start = boost::container::move_n(inp_start, n_i, out_start); // may throw + boost::container::destroy_alloc_n(a, out_start, n_o - n_i); + } +} } //namespace container { } //namespace boost { - #include <boost/container/detail/config_end.hpp> #endif //#ifndef BOOST_CONTAINER_DETAIL_UTILITIES_HPP diff --git a/boost/container/detail/value_init.hpp b/boost/container/detail/value_init.hpp index ec1a99c56d..68f9678358 100644 --- a/boost/container/detail/value_init.hpp +++ b/boost/container/detail/value_init.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. +// (C) Copyright Ion Gaztanaga 2005-2013. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -13,11 +13,11 @@ #ifndef BOOST_CONTAINER_DETAIL_VALUE_INIT_HPP #define BOOST_CONTAINER_DETAIL_VALUE_INIT_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" +#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> namespace boost { diff --git a/boost/container/detail/variadic_templates_tools.hpp b/boost/container/detail/variadic_templates_tools.hpp index d903dfa04c..b07fe3050e 100644 --- a/boost/container/detail/variadic_templates_tools.hpp +++ b/boost/container/detail/variadic_templates_tools.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,12 +11,13 @@ #ifndef BOOST_CONTAINER_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP #define BOOST_CONTAINER_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif -#include "config_begin.hpp" +#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> + #include <boost/container/detail/type_traits.hpp> #include <cstddef> //std::size_t diff --git a/boost/container/detail/version_type.hpp b/boost/container/detail/version_type.hpp index e47ba26f12..2eabc62483 100644 --- a/boost/container/detail/version_type.hpp +++ b/boost/container/detail/version_type.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -16,7 +16,12 @@ #ifndef BOOST_CONTAINER_DETAIL_VERSION_TYPE_HPP #define BOOST_CONTAINER_DETAIL_VERSION_TYPE_HPP -#include "config_begin.hpp" +#if defined(_MSC_VER) +# pragma once +#endif + +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> #include <boost/container/detail/mpl.hpp> #include <boost/container/detail/type_traits.hpp> @@ -80,13 +85,19 @@ struct version<T, true> template <class T> struct version : public container_detail::integral_constant<unsigned, impl::version<T>::value> +{}; + +template<class T, unsigned N> +struct is_version { + static const bool value = + is_same< typename version<T>::type, integral_constant<unsigned, N> >::value; }; } //namespace container_detail { } //namespace container { } //namespace boost{ -#include "config_end.hpp" +#include <boost/container/detail/config_end.hpp> #endif //#define BOOST_CONTAINER_DETAIL_VERSION_TYPE_HPP diff --git a/boost/container/detail/workaround.hpp b/boost/container/detail/workaround.hpp index c4440743fc..55ebe339ce 100644 --- a/boost/container/detail/workaround.hpp +++ b/boost/container/detail/workaround.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,26 +11,62 @@ #ifndef BOOST_CONTAINER_DETAIL_WORKAROUND_HPP #define BOOST_CONTAINER_DETAIL_WORKAROUND_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include <boost/container/detail/config_begin.hpp> -#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)\ +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)\ && !defined(BOOST_INTERPROCESS_DISABLE_VARIADIC_TMPL) #define BOOST_CONTAINER_PERFECT_FORWARDING #endif -#if defined(BOOST_NO_NOEXCEPT) - #define BOOST_CONTAINER_NOEXCEPT +#if defined(BOOST_NO_CXX11_NOEXCEPT) + #if defined(BOOST_MSVC) + #define BOOST_CONTAINER_NOEXCEPT throw() + #else + #define BOOST_CONTAINER_NOEXCEPT + #endif #define BOOST_CONTAINER_NOEXCEPT_IF(x) #else #define BOOST_CONTAINER_NOEXCEPT noexcept #define BOOST_CONTAINER_NOEXCEPT_IF(x) noexcept(x) #endif -#if !defined(BOOST_NO_VARIADIC_TEMPLATES) && defined(__GXX_EXPERIMENTAL_CXX0X__)\ +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && defined(__GXX_EXPERIMENTAL_CXX0X__)\ && (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__ < 40700) #define BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST #endif +#if !defined(BOOST_FALLTHOUGH) + #define BOOST_CONTAINER_FALLTHOUGH +#else + #define BOOST_CONTAINER_FALLTHOUGH BOOST_FALLTHOUGH; +#endif + +//Macros for documentation purposes. For code, expands to the argument +#define BOOST_CONTAINER_IMPDEF(TYPE) TYPE +#define BOOST_CONTAINER_SEEDOC(TYPE) TYPE + +//Macros for memset optimization. In most platforms +//memsetting pointers and floatings is safe and faster. +// +//If your platform does not offer these guarantees +//define these to value zero. +#ifndef BOOST_CONTAINER_MEMZEROED_FLOATING_POINT_IS_NOT_ZERO +#define BOOST_CONTAINER_MEMZEROED_FLOATING_POINT_IS_ZERO 1 +#endif + +#ifndef BOOST_CONTAINER_MEMZEROED_POINTER_IS_NOT_NULL +#define BOOST_CONTAINER_MEMZEROED_POINTER_IS_NULL +#endif + +#define BOOST_CONTAINER_DOC1ST(TYPE1, TYPE2) TYPE2 +#define BOOST_CONTAINER_I , +#define BOOST_CONTAINER_DOCIGN(T) T +#define BOOST_CONTAINER_DOCONLY(T) + #include <boost/container/detail/config_end.hpp> #endif //#ifndef BOOST_CONTAINER_DETAIL_WORKAROUND_HPP |