Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-26 08:49:03

0001 //////////////////////////////////////////////////////////////////////////////
0002 //
0003 // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
0004 // Software License, Version 1.0. (See accompanying file
0005 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // See http://www.boost.org/libs/interprocess for documentation.
0008 //
0009 //////////////////////////////////////////////////////////////////////////////
0010 
0011 #ifndef BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP
0012 #define BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP
0013 
0014 #ifndef BOOST_CONFIG_HPP
0015 #  include <boost/config.hpp>
0016 #endif
0017 0018 ">#
0019 #if defined(BOOST_HAS_PRAGMA_ONCE)
0020 #  pragma once
0021 #endif
0022 
0023 #include <boost/interprocess/detail/config_begin.hpp>
0024 #include <boost/interprocess/detail/workaround.hpp>
0025 
0026 // interprocess
0027 #include <boost/interprocess/interprocess_fwd.hpp>
0028 #include <boost/interprocess/containers/allocation_type.hpp>
0029 // interprocess/detail
0030 #include <boost/interprocess/detail/math_functions.hpp>
0031 #include <boost/interprocess/detail/min_max.hpp>
0032 #include <boost/interprocess/detail/type_traits.hpp>
0033 #include <boost/interprocess/detail/utilities.hpp>
0034 // container/detail
0035 #include <boost/container/detail/multiallocation_chain.hpp>
0036 #include <boost/container/detail/placement_new.hpp>
0037 // move
0038 #include <boost/move/utility_core.hpp>
0039 // move/detail
0040 #include <boost/move/detail/force_ptr.hpp>
0041 // other boost
0042 #include <boost/assert.hpp>
0043 
0044 //!\file
0045 //!Implements common operations for memory algorithms.
0046 
0047 namespace boost {
0048 namespace interprocess {
0049 namespace ipcdetail {
0050 
0051 template<class VoidPointer>
0052 class basic_multiallocation_chain
0053    : public boost::container::dtl::
0054       basic_multiallocation_chain<VoidPointer>
0055 {
0056    BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_multiallocation_chain)
0057    typedef boost::container::dtl::
0058       basic_multiallocation_chain<VoidPointer> base_t;
0059    public:
0060 
0061    basic_multiallocation_chain()
0062       :  base_t()
0063    {}
0064 
0065    basic_multiallocation_chain(BOOST_RV_REF(basic_multiallocation_chain) other)
0066       :  base_t(::boost::move(static_cast<base_t&>(other)))
0067    {}
0068 
0069    basic_multiallocation_chain& operator=(BOOST_RV_REF(basic_multiallocation_chain) other)
0070    {
0071       this->base_t::operator=(::boost::move(static_cast<base_t&>(other)));
0072       return *this;
0073    }
0074 
0075    void *pop_front()
0076    {
0077       return boost::interprocess::ipcdetail::to_raw_pointer(this->base_t::pop_front());
0078    }
0079 };
0080 
0081 //!This class implements several allocation functions shared by different algorithms
0082 //!(aligned allocation, multiple allocation...).
0083 template<class MemoryAlgorithm>
0084 class memory_algorithm_common
0085 {
0086    public:
0087    typedef typename MemoryAlgorithm::void_pointer              void_pointer;
0088    typedef typename MemoryAlgorithm::block_ctrl                block_ctrl;
0089    typedef typename MemoryAlgorithm::multiallocation_chain     multiallocation_chain;
0090    typedef memory_algorithm_common<MemoryAlgorithm>            this_type;
0091    typedef typename MemoryAlgorithm::size_type                 size_type;
0092 
0093    static const size_type Alignment              = MemoryAlgorithm::Alignment;
0094    static const size_type AllocatedCtrlBytes     = MemoryAlgorithm::AllocatedCtrlBytes;
0095    static const size_type AllocatedCtrlUnits     = MemoryAlgorithm::AllocatedCtrlUnits;
0096    static const size_type BlockCtrlBytes         = MemoryAlgorithm::BlockCtrlBytes;
0097    static const size_type BlockCtrlUnits         = MemoryAlgorithm::BlockCtrlUnits;
0098    static const size_type UsableByPreviousChunk  = MemoryAlgorithm::UsableByPreviousChunk;
0099 
0100    static void assert_alignment(const void *ptr)
0101    {  assert_alignment((std::size_t)ptr); }
0102 
0103    static void assert_alignment(size_type uint_ptr)
0104    {
0105       (void)uint_ptr;
0106       BOOST_ASSERT(uint_ptr % Alignment == 0);
0107    }
0108 
0109    static bool check_alignment(const void *ptr)
0110    {  return (((std::size_t)ptr) % Alignment == 0);   }
0111 
0112    static size_type ceil_units(size_type size)
0113    {  return get_rounded_size(size, Alignment)/Alignment; }
0114 
0115    static size_type floor_units(size_type size)
0116    {  return size/Alignment;  }
0117 
0118    static size_type user_buffer_ceil_units(size_type size)
0119    {
0120       if(size <= UsableByPreviousChunk)
0121          return 0;
0122       return ceil_units(size - UsableByPreviousChunk);
0123    }
0124 
0125    static size_type multiple_of_units(size_type size)
0126    {  return get_rounded_size(size, Alignment);  }
0127 
0128    static void allocate_many
0129       (MemoryAlgorithm *memory_algo, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
0130    {
0131       return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0, chain);
0132    }
0133 
0134    static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain)
0135    {
0136       return this_type::priv_deallocate_many(memory_algo, chain);
0137    }
0138 
0139    static bool calculate_lcm_and_needs_backwards_lcmed
0140       (size_type backwards_multiple, size_type received_size, size_type size_to_achieve,
0141       size_type &lcm_out, size_type &needs_backwards_lcmed_out)
0142    {
0143       // Now calculate lcm_val
0144       size_type max = backwards_multiple;
0145       size_type min = Alignment;
0146       size_type needs_backwards;
0147       size_type needs_backwards_lcmed;
0148       size_type lcm_val;
0149       size_type current_forward;
0150       //Swap if necessary
0151       if(max < min){
0152          size_type tmp = min;
0153          min = max;
0154          max = tmp;
0155       }
0156       //Check if it's power of two
0157       if((backwards_multiple & (backwards_multiple-1)) == 0){
0158          if(0 != (size_to_achieve & ((backwards_multiple-1)))){
0159             return false;
0160          }
0161 
0162          lcm_val = max;
0163          //If we want to use minbytes data to get a buffer between maxbytes
0164          //and minbytes if maxbytes can't be achieved, calculate the
0165          //biggest of all possibilities
0166          current_forward = get_truncated_size_po2(received_size, backwards_multiple);
0167          needs_backwards = size_to_achieve - current_forward;
0168          BOOST_ASSERT((needs_backwards % backwards_multiple) == 0);
0169          needs_backwards_lcmed = get_rounded_size_po2(needs_backwards, lcm_val);
0170          lcm_out = lcm_val;
0171          needs_backwards_lcmed_out = needs_backwards_lcmed;
0172          return true;
0173       }
0174       //Check if it's multiple of alignment
0175       else if((backwards_multiple & (Alignment - 1u)) == 0){
0176          lcm_val = backwards_multiple;
0177          current_forward = get_truncated_size(received_size, backwards_multiple);
0178          //No need to round needs_backwards because backwards_multiple == lcm_val
0179          needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
0180          BOOST_ASSERT((needs_backwards_lcmed & (Alignment - 1u)) == 0);
0181          lcm_out = lcm_val;
0182          needs_backwards_lcmed_out = needs_backwards_lcmed;
0183          return true;
0184       }
0185       //Check if it's multiple of the half of the alignmment
0186       else if((backwards_multiple & ((Alignment/2u) - 1u)) == 0){
0187          lcm_val = backwards_multiple*2u;
0188          current_forward = get_truncated_size(received_size, backwards_multiple);
0189          needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
0190          if(0 != (needs_backwards_lcmed & (Alignment-1)))
0191          //while(0 != (needs_backwards_lcmed & (Alignment-1)))
0192             needs_backwards_lcmed += backwards_multiple;
0193          BOOST_ASSERT((needs_backwards_lcmed % lcm_val) == 0);
0194          lcm_out = lcm_val;
0195          needs_backwards_lcmed_out = needs_backwards_lcmed;
0196          return true;
0197       }
0198       //Check if it's multiple of the quarter of the alignmment
0199       else if((backwards_multiple & ((Alignment/4u) - 1u)) == 0){
0200          size_type remainder;
0201          lcm_val = backwards_multiple*4u;
0202          current_forward = get_truncated_size(received_size, backwards_multiple);
0203          needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
0204          //while(0 != (needs_backwards_lcmed & (Alignment-1)))
0205             //needs_backwards_lcmed += backwards_multiple;
0206          if(0 != (remainder = ((needs_backwards_lcmed & (Alignment-1))>>(Alignment/8u)))){
0207             if(backwards_multiple & Alignment/2u){
0208                needs_backwards_lcmed += (remainder)*backwards_multiple;
0209             }
0210             else{
0211                needs_backwards_lcmed += (4-remainder)*backwards_multiple;
0212             }
0213          }
0214          BOOST_ASSERT((needs_backwards_lcmed % lcm_val) == 0);
0215          lcm_out = lcm_val;
0216          needs_backwards_lcmed_out = needs_backwards_lcmed;
0217          return true;
0218       }
0219       else{
0220          lcm_val = lcm(max, min);
0221       }
0222       //If we want to use minbytes data to get a buffer between maxbytes
0223       //and minbytes if maxbytes can't be achieved, calculate the
0224       //biggest of all possibilities
0225       current_forward = get_truncated_size(received_size, backwards_multiple);
0226       needs_backwards = size_to_achieve - current_forward;
0227       BOOST_ASSERT((needs_backwards % backwards_multiple) == 0);
0228       needs_backwards_lcmed = get_rounded_size(needs_backwards, lcm_val);
0229       lcm_out = lcm_val;
0230       needs_backwards_lcmed_out = needs_backwards_lcmed;
0231       return true;
0232    }
0233 
0234    static void allocate_many
0235       ( MemoryAlgorithm *memory_algo
0236       , const size_type *elem_sizes
0237       , size_type n_elements
0238       , size_type sizeof_element
0239       , multiallocation_chain &chain)
0240    {
0241       this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element, chain);
0242    }
0243 
0244    static void* allocate_aligned
0245       (MemoryAlgorithm * const memory_algo, const size_type nbytes, const size_type alignment)
0246    {
0247 
0248       //Ensure power of 2
0249       const bool alignment_ok = (alignment & (alignment - 1u)) == 0;
0250       if (!alignment_ok){
0251          //Alignment is not power of two
0252          BOOST_ASSERT(alignment_ok);
0253          return 0;
0254       }
0255 
0256       if(alignment <= Alignment){
0257          size_type real_size = nbytes;
0258          void *ignore_reuse = 0;
0259          return memory_algo->priv_allocate
0260             (boost::interprocess::allocate_new, nbytes, real_size, ignore_reuse);
0261       }
0262 
0263       //To fulfill user's request we need at least min_user_units
0264       size_type needed_units = user_buffer_ceil_units(nbytes);
0265       //However, there is a minimum allocation unit count (BlockCtrlUnits) to be able to deallocate the buffer,
0266       //The allocation will give us a part of it (AllocatedCtrlUnits) so (BlockCtrlUnits - AllocatedCtrlUnits)
0267       //is the minimum ammount of blocks we need to allocate.
0268       needed_units += max_value(needed_units, BlockCtrlUnits - AllocatedCtrlUnits);
0269       //If we need to align, we need to at least move enough to create a new block at the beginning
0270       //that can be marked as free, so we need BlockCtrlUnits units for that
0271       needed_units += BlockCtrlUnits;
0272       //Finally, we need to add extra space to be sure we will find an aligned address
0273       needed_units += (alignment - Alignment)/Alignment;
0274 
0275       //Transform units to bytes
0276       const size_type request = needed_units*Alignment + UsableByPreviousChunk;
0277 
0278       //Now allocate the buffer
0279       size_type real_size = request;
0280       void *ignore_reuse = 0;
0281       void *const buffer = memory_algo->priv_allocate(boost::interprocess::allocate_new, request, real_size, ignore_reuse);
0282       if(!buffer){
0283          return 0;
0284       }
0285       else if ((((std::size_t)(buffer)) & (alignment-1)) == 0){
0286          //If we are lucky and the buffer is aligned, just split it and
0287          //return the high part
0288          block_ctrl *const first  = memory_algo->priv_get_block(buffer);
0289          const size_type orig_first_units = first->m_size;
0290          const size_type first_min_units =
0291             max_value(user_buffer_ceil_units(nbytes) + AllocatedCtrlUnits, size_type(BlockCtrlUnits));
0292          //We can create a new block in the end of the segment
0293          if(orig_first_units >= (first_min_units + BlockCtrlUnits)){
0294             block_ctrl *second =  move_detail::force_ptr<block_ctrl*>
0295                (reinterpret_cast<char*>(first) + Alignment*first_min_units);
0296             //Update first size
0297             first->m_size  = first_min_units & block_ctrl::size_mask;
0298             memory_algo->priv_mark_new_allocated_block(first);
0299 
0300             //Deallocate the remaining memory
0301             second->m_size = (orig_first_units - first_min_units) & block_ctrl::size_mask;
0302             memory_algo->priv_mark_new_allocated_block(second);
0303             memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(second));
0304          }
0305          return buffer;
0306       }
0307 
0308       //Now obtain the address of the allocated block
0309       block_ctrl* const first = memory_algo->priv_get_block(buffer);
0310       //The block must be marked as allocated
0311       BOOST_ASSERT(memory_algo->priv_is_allocated_block(first));
0312       //Assert allocated block has at least the desired size
0313       BOOST_ASSERT(first->m_size >= (needed_units + AllocatedCtrlUnits));
0314       //Assert allocated block can be splitted in the two blocks
0315       BOOST_ASSERT(first->m_size >= 2 * BlockCtrlUnits);
0316 
0317       //Buffer is not overaligned, so find the aligned part
0318 
0319       // BCB: BlockControlBytes
0320       // ACB: AllocatedControlBytes (<= BlockControlBytes)
0321       //
0322       //  __________> Block control ("first")
0323       // |           _________> Block control ("second")
0324       // |          |      ___> usr_buf, overaligned
0325       // |          |     |
0326       //  -----------------------------------------------------
0327       // | BCB+more | ACB |
0328       //  -----------------------------------------------------
0329       char *const usr_buf = reinterpret_cast<char*>
0330          (reinterpret_cast<std::size_t>(static_cast<char*>(buffer)
0331             + BlockCtrlBytes                 //Minimum to create a free block at the beginning
0332             + alignment - 1) & -alignment);  //This is the alignment trick
0333 
0334       //Assert the user buffer is inside the allocated range
0335       BOOST_ASSERT(usr_buf <= (reinterpret_cast<char*>(first) + first->m_size*Alignment));
0336       //Assert all user data is inside the allocated range
0337       BOOST_ASSERT((usr_buf + nbytes) <= (reinterpret_cast<char*>(first) + first->m_size*Alignment + UsableByPreviousChunk));
0338 
0339       //Set the new size of the secone block
0340       const size_type orig_first_units = first->m_size;
0341 
0342       block_ctrl* const second = memory_algo->priv_get_block(usr_buf);
0343 
0344       //Update first block size until second block starts and deallocate it
0345       const size_type final_first_units =
0346          size_type(reinterpret_cast<char*>(second) - reinterpret_cast<char*>(first))/Alignment & block_ctrl::size_mask;
0347 
0348       //Now check if we can create a new buffer in the end
0349       //
0350       //  _______________________> "first" (free block)
0351       // |           ____________> "second" block
0352       // |          |      ______> user data aligned here (usr_buf)
0353       // |          |     |            ____> optional "third" (free block)
0354       //  ----------|-----|-----------|------------------------------
0355       // | BCB+more | ACB | user_data | BCB |
0356       //  -----------------------------------------------------
0357       //This size will be the minimum size to be able to create a
0358       //new block in the end.
0359       const size_type orig_second_units = orig_first_units - final_first_units;
0360       const size_type second_min_units = max_value( size_type(BlockCtrlUnits)
0361                                                   , user_buffer_ceil_units(nbytes) + AllocatedCtrlUnits );
0362 
0363       //Check if we can create a new free block (of size BlockCtrlUnits) at the end of the segment
0364       if(orig_second_units >= (second_min_units + BlockCtrlUnits)){
0365          //Now obtain the address of the end block
0366          block_ctrl *const third = ::new (reinterpret_cast<char*>(second) + Alignment*second_min_units, boost_container_new_t()) block_ctrl;
0367          second->m_size = second_min_units & block_ctrl::size_mask;
0368          third->m_size  = (orig_second_units - second->m_size) & block_ctrl::size_mask;
0369          BOOST_ASSERT(third->m_size >= BlockCtrlUnits);
0370          memory_algo->priv_mark_new_allocated_block(second);
0371          memory_algo->priv_mark_new_allocated_block(third);
0372          //We can deallocate third block because the previous "second" is properly set
0373          memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(third));
0374       }
0375       else{
0376          second->m_size = orig_second_units & block_ctrl::size_mask;
0377          BOOST_ASSERT(second->m_size >= BlockCtrlUnits);
0378          memory_algo->priv_mark_new_allocated_block(second);
0379       }
0380 
0381       //We can deallocate first block because the next "second" is properly set
0382       first->m_size = final_first_units & block_ctrl::size_mask;
0383       //Now mark second's previous allocated flag as allocated
0384       memory_algo->priv_mark_new_allocated_block(first);
0385       memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(first));
0386 
0387       //Make sure all user data fits
0388       BOOST_ASSERT((reinterpret_cast<char*>(usr_buf) + nbytes) <= (reinterpret_cast<char*>(second) + second->m_size*Alignment + UsableByPreviousChunk));
0389       //Make sure user data is properly aligned
0390       BOOST_ASSERT(0 == ((std::size_t)usr_buf & (alignment-1u)));
0391       return usr_buf;
0392    }
0393 
0394    static bool try_shrink
0395       (MemoryAlgorithm *memory_algo, void *ptr
0396       ,const size_type max_size, size_type &received_size)
0397    {
0398       size_type const preferred_size = received_size;
0399       (void)memory_algo;
0400       //Obtain the real block
0401       block_ctrl *block = memory_algo->priv_get_block(ptr);
0402       size_type old_block_units = (size_type)block->m_size;
0403 
0404       //The block must be marked as allocated
0405       BOOST_ASSERT(memory_algo->priv_is_allocated_block(block));
0406 
0407       //Check if alignment and block size are right
0408       assert_alignment(ptr);
0409 
0410       //Put this to a safe value
0411       received_size = (old_block_units - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk;
0412 
0413       //Now translate it to Alignment units
0414       const size_type max_user_units       = floor_units(max_size - UsableByPreviousChunk);
0415       const size_type preferred_user_units = ceil_units(preferred_size - UsableByPreviousChunk);
0416 
0417       //Check if rounded max and preferred are possible correct
0418       if(max_user_units < preferred_user_units)
0419          return false;
0420 
0421       //Check if the block is smaller than the requested minimum
0422       size_type old_user_units = old_block_units - AllocatedCtrlUnits;
0423 
0424       if(old_user_units < preferred_user_units)
0425          return false;
0426 
0427       //If the block is smaller than the requested minimum
0428       if(old_user_units == preferred_user_units)
0429          return true;
0430 
0431       size_type shrunk_user_units =
0432          ((BlockCtrlUnits - AllocatedCtrlUnits) >= preferred_user_units)
0433          ? (BlockCtrlUnits - AllocatedCtrlUnits)
0434          : preferred_user_units;
0435 
0436       //Some parameter checks
0437       if(max_user_units < shrunk_user_units)
0438          return false;
0439 
0440       //We must be able to create at least a new empty block
0441       if((old_user_units - shrunk_user_units) < BlockCtrlUnits ){
0442          return false;
0443       }
0444 
0445       //Update new size
0446       received_size = shrunk_user_units*Alignment + UsableByPreviousChunk;
0447       return true;
0448    }
0449 
0450    static bool shrink
0451       (MemoryAlgorithm *memory_algo, void *ptr
0452       ,const size_type max_size, size_type &received_size)
0453    {
0454       size_type const preferred_size = received_size;
0455       //Obtain the real block
0456       block_ctrl *block = memory_algo->priv_get_block(ptr);
0457       size_type old_block_units = (size_type)block->m_size;
0458 
0459       if(!try_shrink(memory_algo, ptr, max_size, received_size)){
0460          return false;
0461       }
0462 
0463       //Check if the old size was just the shrunk size (no splitting)
0464       if((old_block_units - AllocatedCtrlUnits) == ceil_units(preferred_size - UsableByPreviousChunk))
0465          return true;
0466 
0467       //Now we can just rewrite the size of the old buffer
0468       block->m_size = ((received_size-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits) & block_ctrl::size_mask;
0469       BOOST_ASSERT(block->m_size >= BlockCtrlUnits);
0470 
0471       //We create the new block
0472       block_ctrl *new_block = move_detail::force_ptr<block_ctrl*>
0473                   (reinterpret_cast<char*>(block) + block->m_size*Alignment);
0474       //Write control data to simulate this new block was previously allocated
0475       //and deallocate it
0476       new_block->m_size = (old_block_units - block->m_size) & block_ctrl::size_mask;
0477       BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits);
0478       memory_algo->priv_mark_new_allocated_block(block);
0479       memory_algo->priv_mark_new_allocated_block(new_block);
0480       memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(new_block));
0481       return true;
0482    }
0483 
0484    private:
0485    static void priv_allocate_many
0486       ( MemoryAlgorithm *memory_algo
0487       , const size_type *elem_sizes
0488       , size_type n_elements
0489       , size_type sizeof_element
0490       , multiallocation_chain &chain)
0491    {
0492       //Note: sizeof_element == 0 indicates that we want to
0493       //allocate n_elements of the same size "*elem_sizes"
0494 
0495       //Calculate the total size of all requests
0496       size_type total_request_units = 0;
0497       size_type elem_units = 0;
0498       const size_type ptr_size_units = memory_algo->priv_get_total_units(sizeof(void_pointer));
0499       if(!sizeof_element){
0500          elem_units = memory_algo->priv_get_total_units(*elem_sizes);
0501          elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
0502          total_request_units = n_elements*elem_units;
0503       }
0504       else{
0505          for(size_type i = 0; i < n_elements; ++i){
0506             if(multiplication_overflows(elem_sizes[i], sizeof_element)){
0507                total_request_units = 0;
0508                break;
0509             }
0510             elem_units = memory_algo->priv_get_total_units(elem_sizes[i]*sizeof_element);
0511             elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
0512             if(sum_overflows(total_request_units, elem_units)){
0513                total_request_units = 0;
0514                break;
0515             }
0516             total_request_units += elem_units;
0517          }
0518       }
0519 
0520       if(total_request_units && !multiplication_overflows(total_request_units, Alignment)){
0521          size_type low_idx = 0;
0522          while(low_idx < n_elements){
0523             size_type total_bytes = total_request_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
0524             size_type min_allocation = (!sizeof_element)
0525                ?  elem_units
0526                :  memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
0527             min_allocation = min_allocation*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
0528 
0529             size_type received_size = total_bytes;
0530             void *ignore_reuse = 0;
0531             void *ret = memory_algo->priv_allocate
0532                (boost::interprocess::allocate_new, min_allocation, received_size, ignore_reuse);
0533             if(!ret){
0534                break;
0535             }
0536 
0537             block_ctrl *block = memory_algo->priv_get_block(ret);
0538             size_type received_units = (size_type)block->m_size;
0539             char *block_address = reinterpret_cast<char*>(block);
0540 
0541             size_type total_used_units = 0;
0542             while(total_used_units < received_units){
0543                if(sizeof_element){
0544                   elem_units = memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
0545                   elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
0546                }
0547                if(total_used_units + elem_units > received_units)
0548                   break;
0549                total_request_units -= elem_units;
0550                //This is the position where the new block must be created
0551                block_ctrl *new_block = move_detail::force_ptr<block_ctrl*>(block_address);
0552                assert_alignment(new_block);
0553 
0554                //The last block should take all the remaining space
0555                if((low_idx + 1) == n_elements ||
0556                   (total_used_units + elem_units +
0557                   ((!sizeof_element)
0558                      ? elem_units
0559                : max_value(memory_algo->priv_get_total_units(elem_sizes[low_idx+1]*sizeof_element), ptr_size_units))
0560                    > received_units)){
0561                   //By default, the new block will use the rest of the buffer
0562                   new_block->m_size = (received_units - total_used_units) & block_ctrl::size_mask;
0563                   memory_algo->priv_mark_new_allocated_block(new_block);
0564 
0565                   //If the remaining units are bigger than needed and we can
0566                   //split it obtaining a new free memory block do it.
0567                   if((received_units - total_used_units) >= (elem_units + MemoryAlgorithm::BlockCtrlUnits)){
0568                      size_type shrunk_request = elem_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
0569                      size_type shrunk_received = shrunk_request;
0570                      bool shrink_ok = shrink
0571                            (memory_algo
0572                            ,memory_algo->priv_get_user_buffer(new_block)
0573                            ,shrunk_request
0574                            ,shrunk_received);
0575                      (void)shrink_ok;
0576                      //Shrink must always succeed with passed parameters
0577                      BOOST_ASSERT(shrink_ok);
0578                      //Some sanity checks
0579                      BOOST_ASSERT(shrunk_request == shrunk_received);
0580                      BOOST_ASSERT(elem_units == ((shrunk_request-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits));
0581                      //"new_block->m_size" must have been reduced to elem_units by "shrink"
0582                      BOOST_ASSERT(new_block->m_size == elem_units);
0583                      //Now update the total received units with the reduction
0584                      received_units = elem_units + total_used_units;
0585                   }
0586                }
0587                else{
0588                   new_block->m_size = elem_units & block_ctrl::size_mask;
0589                   memory_algo->priv_mark_new_allocated_block(new_block);
0590                }
0591 
0592                block_address += new_block->m_size*Alignment;
0593                total_used_units += (size_type)new_block->m_size;
0594                //Check we have enough room to overwrite the intrusive pointer
0595                BOOST_ASSERT((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(void_pointer));
0596                void_pointer p = ::new(memory_algo->priv_get_user_buffer(new_block), boost_container_new_t())void_pointer(0);
0597                chain.push_back(p);
0598                ++low_idx;
0599             }
0600             //Sanity check
0601             BOOST_ASSERT(total_used_units == received_units);
0602          }
0603 
0604          if(low_idx != n_elements){
0605             priv_deallocate_many(memory_algo, chain);
0606          }
0607       }
0608    }
0609 
0610    static void priv_deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain)
0611    {
0612       while(!chain.empty()){
0613          memory_algo->priv_deallocate(to_raw_pointer(chain.pop_front()));
0614       }
0615    }
0616 };
0617 
0618 }  //namespace ipcdetail {
0619 }  //namespace interprocess {
0620 }  //namespace boost {
0621 
0622 #include <boost/interprocess/detail/config_end.hpp>
0623 
0624 #endif   //#ifndef BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP