summaryrefslogtreecommitdiff
path: root/boost/interprocess/mem_algo/rbtree_best_fit.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/interprocess/mem_algo/rbtree_best_fit.hpp')
-rw-r--r--boost/interprocess/mem_algo/rbtree_best_fit.hpp139
1 files changed, 66 insertions, 73 deletions
diff --git a/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/boost/interprocess/mem_algo/rbtree_best_fit.hpp
index 7ccc642e29..fb04889c17 100644
--- a/boost/interprocess/mem_algo/rbtree_best_fit.hpp
+++ b/boost/interprocess/mem_algo/rbtree_best_fit.hpp
@@ -1,6 +1,6 @@
//////////////////////////////////////////////////////////////////////////////
//
-// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
+// (C) Copyright Ion Gaztanaga 2005-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)
//
@@ -11,7 +11,7 @@
#ifndef BOOST_INTERPROCESS_MEM_ALGO_RBTREE_BEST_FIT_HPP
#define BOOST_INTERPROCESS_MEM_ALGO_RBTREE_BEST_FIT_HPP
-#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+#if defined(_MSC_VER)
# pragma once
#endif
@@ -31,11 +31,12 @@
#include <boost/interprocess/detail/math_functions.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
+#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/type_with_alignment.hpp>
+#include <boost/type_traits/make_unsigned.hpp>
#include <boost/intrusive/pointer_traits.hpp>
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
-#include <boost/type_traits.hpp>
#include <algorithm>
#include <utility>
#include <climits>
@@ -65,7 +66,7 @@ namespace interprocess {
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
class rbtree_best_fit
{
- /// @cond
+ #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
rbtree_best_fit();
rbtree_best_fit(const rbtree_best_fit &);
@@ -81,20 +82,19 @@ class rbtree_best_fit
pointer_traits<VoidPointer>::template
rebind_pointer<char>::type char_ptr;
- /// @endcond
+ #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Shared mutex family used for the rest of the Interprocess framework
typedef MutexFamily mutex_family;
//!Pointer type to be used with the rest of the Interprocess framework
typedef VoidPointer void_pointer;
- typedef boost::container::container_detail::
- basic_multiallocation_chain<VoidPointer> multiallocation_chain;
+ typedef ipcdetail::basic_multiallocation_chain<VoidPointer> multiallocation_chain;
typedef typename boost::intrusive::pointer_traits<char_ptr>::difference_type difference_type;
typedef typename boost::make_unsigned<difference_type>::type size_type;
- /// @cond
+ #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
@@ -132,7 +132,7 @@ class rbtree_best_fit
{ return size < block.m_size; }
bool operator()(const block_ctrl &block, size_type size) const
- { return block.m_size < size; }
+ { return block.m_size < size; }
};
//!Shared mutex to protect memory allocate/deallocate
@@ -141,6 +141,7 @@ class rbtree_best_fit
<block_ctrl, bi::base_hook<TreeHook> >::type Imultiset;
typedef typename Imultiset::iterator imultiset_iterator;
+ typedef typename Imultiset::const_iterator imultiset_const_iterator;
//!This struct includes needed data and derives from
//!mutex_type to allow EBO when using null mutex_type
@@ -157,11 +158,11 @@ class rbtree_best_fit
} m_header;
friend class ipcdetail::memory_algorithm_common<rbtree_best_fit>;
-
+
typedef ipcdetail::memory_algorithm_common<rbtree_best_fit> algo_impl_t;
public:
- /// @endcond
+ #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Constructor. "size" is the total size of the managed memory segment,
//!"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(rbtree_best_fit)
@@ -179,34 +180,32 @@ class rbtree_best_fit
//!Allocates bytes, returns 0 if there is not more memory
void* allocate (size_type nbytes);
- /// @cond
+ #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Experimental. Dont' use
//!Multiple element allocation, same size
- multiallocation_chain allocate_many(size_type elem_bytes, size_type num_elements)
+ void allocate_many(size_type elem_bytes, size_type num_elements, multiallocation_chain &chain)
{
-
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
- return algo_impl_t::allocate_many(this, elem_bytes, num_elements);
+ algo_impl_t::allocate_many(this, elem_bytes, num_elements, chain);
}
//!Multiple element allocation, different size
- multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element)
+ void allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
{
-
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
- return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element);
+ algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element, chain);
}
//!Multiple element allocation, different size
- void deallocate_many(multiallocation_chain chain);
+ void deallocate_many(multiallocation_chain &chain);
- /// @endcond
+ #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Deallocates previously allocated bytes
void deallocate (void *addr);
@@ -253,7 +252,7 @@ class rbtree_best_fit
//!Alignment must be power of 2
void* allocate_aligned (size_type nbytes, size_type alignment);
- /// @cond
+ #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
static size_type priv_first_block_offset_from_this(const void *this_ptr, size_type extra_hdr_bytes);
@@ -339,7 +338,7 @@ class rbtree_best_fit
void priv_add_segment(void *addr, size_type size);
public:
-
+
static const size_type Alignment = !MemAlignment
? size_type(::boost::alignment_of< ::boost::detail::max_align>::value)
: size_type(MemAlignment)
@@ -362,12 +361,12 @@ class rbtree_best_fit
//Make sure the maximum alignment is power of two
BOOST_STATIC_ASSERT((0 == (Alignment & (Alignment - size_type(1u)))));
- /// @endcond
+ #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
static const size_type PayloadPerAllocation = AllocatedCtrlBytes - UsableByPreviousChunk;
};
-/// @cond
+#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
inline typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::size_type
@@ -385,16 +384,16 @@ inline typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::size_ty
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
- priv_add_segment(void *addr, size_type size)
-{
+ priv_add_segment(void *addr, size_type segment_size)
+{
//Check alignment
algo_impl_t::check_alignment(addr);
//Check size
- BOOST_ASSERT(size >= (BlockCtrlBytes + EndCtrlBlockBytes));
+ BOOST_ASSERT(segment_size >= (BlockCtrlBytes + EndCtrlBlockBytes));
//Initialize the first big block and the "end" node
block_ctrl *first_big_block = new(addr)block_ctrl;
- first_big_block->m_size = size/Alignment - EndCtrlBlockUnits;
+ first_big_block->m_size = segment_size/Alignment - EndCtrlBlockUnits;
BOOST_ASSERT(first_big_block->m_size >= BlockCtrlUnits);
//The "end" node is just a node of size 0 with the "end" bit set
@@ -451,18 +450,18 @@ inline typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_c
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
inline rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
- rbtree_best_fit(size_type size, size_type extra_hdr_bytes)
+ rbtree_best_fit(size_type segment_size, size_type extra_hdr_bytes)
{
//Initialize the header
m_header.m_allocated = 0;
- m_header.m_size = size;
+ m_header.m_size = segment_size;
m_header.m_extra_hdr_bytes = extra_hdr_bytes;
//Now write calculate the offset of the first big block that will
//cover the whole segment
- BOOST_ASSERT(get_min_size(extra_hdr_bytes) <= size);
+ BOOST_ASSERT(get_min_size(extra_hdr_bytes) <= segment_size);
size_type block1_off = priv_first_block_offset_from_this(this, extra_hdr_bytes);
- priv_add_segment(reinterpret_cast<char*>(this) + block1_off, size - block1_off);
+ priv_add_segment(reinterpret_cast<char*>(this) + block1_off, segment_size - block1_off);
}
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
@@ -570,7 +569,7 @@ void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::shrink_to_fit()
size_type shrunk_border_offset = (size_type)(reinterpret_cast<char*>(last_block) -
reinterpret_cast<char*>(this)) + EndCtrlBlockBytes;
-
+
block_ctrl *new_end_block = last_block;
algo_impl_t::assert_alignment(new_end_block);
@@ -672,7 +671,7 @@ bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
inline void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
allocate(size_type nbytes)
-{
+{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
@@ -816,7 +815,6 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
block_ctrl *reuse = priv_get_block(reuse_ptr);
//Sanity check
- //BOOST_ASSERT(reuse->m_size == priv_tail_size(reuse));
algo_impl_t::assert_alignment(reuse);
block_ctrl *prev_block;
@@ -851,7 +849,7 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
if(!priv_expand(reuse_ptr, received_size, received_size, received_size2)){
BOOST_ASSERT(0);
}
- BOOST_ASSERT(received_size = received_size2);
+ BOOST_ASSERT(received_size == received_size2);
}
//We need a minimum size to split the previous one
if(prev_block->m_size >= (needs_backwards_aligned/Alignment + BlockCtrlUnits)){
@@ -884,7 +882,7 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
received_size = needs_backwards_aligned + received_size;
m_header.m_allocated += needs_backwards_aligned;
-
+
//Check alignment
algo_impl_t::assert_alignment(new_block);
@@ -930,12 +928,12 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
inline void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
- deallocate_many(typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::multiallocation_chain chain)
+ deallocate_many(typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::multiallocation_chain &chain)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
- algo_impl_t::deallocate_many(this, boost::move(chain));
+ algo_impl_t::deallocate_many(this, chain);
}
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
@@ -1043,8 +1041,7 @@ bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
//The block must be marked as allocated and the sizes must be equal
BOOST_ASSERT(priv_is_allocated_block(block));
- //BOOST_ASSERT(old_block_units == priv_tail_size(block));
-
+
//Put this to a safe value
received_size = (old_block_units - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk;
if(received_size >= preferred_size || received_size >= min_size)
@@ -1208,9 +1205,6 @@ bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_is_allocated_
(void)next_block_prev_allocated;
BOOST_ASSERT(allocated == next_block_prev_allocated);
}
- else{
- block = block;
- }
#endif
return allocated;
}
@@ -1228,9 +1222,7 @@ bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_is_prev_alloc
block_ctrl *prev = priv_prev_block(block);
(void)prev;
BOOST_ASSERT(!prev->m_allocated);
- }
- else{
- block = block;
+ BOOST_ASSERT(prev->m_size == block->m_prev_size);
}
#endif
return false;
@@ -1284,7 +1276,7 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_check_and_al
imultiset_iterator it_hint;
if(it_old == m_header.m_imultiset.begin()
- || (--imultiset_iterator(it_old))->m_size < rem_block->m_size){
+ || (--imultiset_iterator(it_old))->m_size <= rem_block->m_size){
//option a: slow but secure
//m_header.m_imultiset.insert(m_header.m_imultiset.erase(it_old), *rem_block);
//option b: Construct an empty node and swap
@@ -1298,7 +1290,7 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_check_and_al
m_header.m_imultiset.erase(it_old);
m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *rem_block);
}
-
+
}
else if (block->m_size >= nunits){
m_header.m_imultiset.erase(it_old);
@@ -1318,7 +1310,7 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_check_and_al
//Clear the memory occupied by the tree hook, since this won't be
//cleared with zero_free_memory
TreeHook *t = static_cast<TreeHook*>(block);
- //Just clear the memory part reserved for the user
+ //Just clear the memory part reserved for the user
std::size_t tree_hook_offset_in_block = (char*)t - (char*)block;
//volatile char *ptr =
char *ptr = reinterpret_cast<char*>(block)+tree_hook_offset_in_block;
@@ -1344,10 +1336,9 @@ void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_deallocate(vo
if(!addr) return;
block_ctrl *block = priv_get_block(addr);
-
+
//The blocks must be marked as allocated and the sizes must be equal
BOOST_ASSERT(priv_is_allocated_block(block));
-// BOOST_ASSERT(block->m_size == priv_tail_size(block));
//Check if alignment and block size are right
algo_impl_t::assert_alignment(addr);
@@ -1362,42 +1353,44 @@ void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_deallocate(vo
block_ctrl *block_to_insert = block;
//Get the next block
- block_ctrl *next_block = priv_next_block(block);
- bool merge_with_prev = !priv_is_prev_allocated(block);
- bool merge_with_next = !priv_is_allocated_block(next_block);
+ block_ctrl *const next_block = priv_next_block(block);
+ const bool merge_with_prev = !priv_is_prev_allocated(block);
+ const bool merge_with_next = !priv_is_allocated_block(next_block);
//Merge logic. First just update block sizes, then fix free blocks tree
if(merge_with_prev || merge_with_next){
//Merge if the previous is free
if(merge_with_prev){
//Get the previous block
- block_ctrl *prev_block = priv_prev_block(block);
- prev_block->m_size += block->m_size;
- BOOST_ASSERT(prev_block->m_size >= BlockCtrlUnits);
- block_to_insert = prev_block;
+ block_to_insert = priv_prev_block(block);
+ block_to_insert->m_size += block->m_size;
+ BOOST_ASSERT(block_to_insert->m_size >= BlockCtrlUnits);
}
//Merge if the next is free
if(merge_with_next){
block_to_insert->m_size += next_block->m_size;
BOOST_ASSERT(block_to_insert->m_size >= BlockCtrlUnits);
- if(merge_with_prev)
- m_header.m_imultiset.erase(Imultiset::s_iterator_to(*next_block));
+ const imultiset_iterator next_it = Imultiset::s_iterator_to(*next_block);
+ if(merge_with_prev){
+ m_header.m_imultiset.erase(next_it);
+ }
+ else{
+ m_header.m_imultiset.replace_node(next_it, *block_to_insert);
+ }
}
- bool only_merge_next = !merge_with_prev && merge_with_next;
- imultiset_iterator free_block_to_check_it
- (Imultiset::s_iterator_to(only_merge_next ? *next_block : *block_to_insert));
- imultiset_iterator was_bigger_it(free_block_to_check_it);
-
//Now try to shortcut erasure + insertion (O(log(N))) with
//a O(1) operation if merging does not alter tree positions
- if(++was_bigger_it != m_header.m_imultiset.end() &&
- block_to_insert->m_size > was_bigger_it->m_size ){
- m_header.m_imultiset.erase(free_block_to_check_it);
- m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *block_to_insert);
+ const imultiset_iterator block_to_check_it = Imultiset::s_iterator_to(*block_to_insert);
+ imultiset_const_iterator next_to_check_it(block_to_check_it), end_it(m_header.m_imultiset.end());
+
+ if(++next_to_check_it != end_it && block_to_insert->m_size > next_to_check_it->m_size){
+ //Block is bigger than next, so move it
+ m_header.m_imultiset.erase(block_to_check_it);
+ m_header.m_imultiset.insert(end_it, *block_to_insert);
}
- else if(only_merge_next){
- m_header.m_imultiset.replace_node(free_block_to_check_it, *block_to_insert);
+ else{
+ //Block size increment didn't violate tree invariants so there is nothing to fix
}
}
else{
@@ -1406,7 +1399,7 @@ void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_deallocate(vo
priv_mark_as_free_block(block_to_insert);
}
-/// @endcond
+#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace interprocess {
} //namespace boost {