Update of /cvsroot/boost/boost/boost/interprocess/mem_algo/detail
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv22035/mem_algo/detail

Modified Files:
        simple_seq_fit_impl.hpp 
Log Message:
New Interprocess version

Index: simple_seq_fit_impl.hpp
===================================================================
RCS file: 
/cvsroot/boost/boost/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- simple_seq_fit_impl.hpp     23 Jun 2007 12:53:01 -0000      1.6
+++ simple_seq_fit_impl.hpp     22 Jul 2007 14:06:08 -0000      1.7
@@ -46,10 +46,10 @@
 
 namespace detail {
 
-/*!This class implements the simple sequential fit algorithm with a simply
-   linked list of free buffers.
-   This class is intended as a base class for single segment and multi-segment
-   implementations.*/
+//!This class implements the simple sequential fit algorithm with a simply
+//!linked list of free buffers.
+//!This class is intended as a base class for single segment and multi-segment
+//!implementations.
 template<class MutexFamily, class VoidPointer>
 class simple_seq_fit_impl
 {
@@ -59,9 +59,11 @@
    simple_seq_fit_impl &operator=(const simple_seq_fit_impl &);
 
    public:
-   /*!Shared interprocess_mutex family used for the rest of the Interprocess 
framework*/
+   class multiallocation_iterator;
+
+   //!Shared interprocess_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*/
+   //!Pointer type to be used with the rest of the Interprocess framework
    typedef VoidPointer        void_pointer;
 
    private:
@@ -72,14 +74,14 @@
    class block_ctrl;
    friend class block_ctrl;
 
-   /*!Block control structure*/
+   //!Block control structure
    class block_ctrl
    {
       public:
-      /*!Offset pointer to the next block.*/
+      //!Offset pointer to the next block.
       block_ctrl_ptr m_next;
-      /*!This block's memory size (including block_ctrl 
-         header) in BasicSize units*/
+      //!This block's memory size (including block_ctrl 
+      //!header) in BasicSize units
       std::size_t    m_size;
    
       std::size_t get_user_bytes() const
@@ -101,91 +103,198 @@
       }
    };
 
-   /*!Shared interprocess_mutex to protect memory allocate/deallocate*/
+   //!Shared interprocess_mutex to protect memory allocate/deallocate
    typedef typename MutexFamily::mutex_type        interprocess_mutex;
 
-   /*!This struct includes needed data and derives from
-      interprocess_mutex to allow EBO when using null interprocess_mutex*/
+   //!This struct includes needed data and derives from
+   //!interprocess_mutex to allow EBO when using null interprocess_mutex
    struct header_t : public interprocess_mutex
    {
-      /*!Pointer to the first free block*/
+      //!Pointer to the first free block
       block_ctrl        m_root;
-      /*!Allocated bytes for internal checking*/
+      //!Allocated bytes for internal checking
       std::size_t       m_allocated;
-      /*!The size of the memory segment*/
+      //!The size of the memory segment
       std::size_t       m_size;
    }  m_header;
 
+   friend class multiallocation_iterator;
+
    public:
-   /*!Constructor. "size" is the total size of the managed memory segment, 
-      "extra_hdr_bytes" indicates the extra bytes beginning in the 
sizeof(simple_seq_fit_impl)
-      offset that the allocator should not use at all.*/
+   class multiallocation_iterator
+      :  public std::iterator<std::bidirectional_iterator_tag, char *>
+   {
+      void unspecified_bool_type_func() const {}
+      typedef void (multiallocation_iterator::*unspecified_bool_type)() const;
+
+      public:
+      typedef char *       value_type;
+      typedef value_type & reference;
+      typedef value_type * pointer;
+
+      multiallocation_iterator()
+         : block_(0), n_elements_ (0)
+      {}
+
+      multiallocation_iterator(void *many_allocation, std::size_t n_elements)
+         : block_(static_cast<block_ctrl*>(many_allocation)), n_elements_ 
(n_elements)
+      {}
+
+      multiallocation_iterator &operator=(const multiallocation_iterator 
&other)
+      {  block_ = other.block_;  n_elements_ = other.n_elements_;  return 
*this;  }
+
+      public:
+      multiallocation_iterator& operator++() 
+      {
+         --n_elements_;
+         block_ = (block_ctrl*)((char*)block_ + block_->m_size*Alignment);
+         return *this;
+      }
+      
+      multiallocation_iterator operator++(int)
+      {
+         multiallocation_iterator result(block_, n_elements_);
+         ++*this;
+         return result;
+      }
+
+      multiallocation_iterator& operator--() 
+      { 
+         ++n_elements_;
+         block_ = (block_ctrl*)((char*)block_ - block_->m_size*Alignment);
+         return *this;
+      }
+      
+      multiallocation_iterator operator--(int)
+      {
+         multiallocation_iterator result(block_, n_elements_);
+         --*this;
+         return result;
+      }
+
+      bool operator== (const multiallocation_iterator& other) const
+      { return n_elements_ == other.n_elements_; }
+
+      bool operator!= (const multiallocation_iterator& other) const
+      { return !operator== (other); }
+
+      value_type operator*() const
+      {
+         value_type v = (char*)block_ + BlockCtrlBytes;
+         return v;
+      }
+
+      operator unspecified_bool_type() const  
+      {  return n_elements_? 
&multiallocation_iterator::unspecified_bool_type_func : 0;   }
+
+      pointer operator->() const
+      { return &operator*(); }
+
+      private:
+      block_ctrl *block_;
+      std::size_t n_elements_;
+   };
+
+   //!Constructor. "size" is the total size of the managed memory segment, 
+   //!"extra_hdr_bytes" indicates the extra bytes beginning in the 
sizeof(simple_seq_fit_impl)
+   //!offset that the allocator should not use at all.
    simple_seq_fit_impl           (std::size_t size, std::size_t 
extra_hdr_bytes);
-   /*!Destructor.*/
+
+   //!Destructor
    ~simple_seq_fit_impl();
-   /*!Obtains the minimum size needed by the algorithm*/
+
+   //!Obtains the minimum size needed by the algorithm
    static std::size_t get_min_size (std::size_t extra_hdr_bytes);
 
    //Functions for single segment management
 
-   /*!Allocates bytes, returns 0 if there is not more memory*/
+   //!Allocates bytes, returns 0 if there is not more memory
    void* allocate             (std::size_t nbytes);
 
-   /*!Deallocates previously allocated bytes*/
+   /// @cond
+
+   //!Multiple element allocation, same size
+   multiallocation_iterator allocate_many(std::size_t elem_size, std::size_t 
min_elements, std::size_t preferred_elements, std::size_t &received_elements);
+
+   //!Multiple element allocation, different size
+   multiallocation_iterator allocate_many(const std::size_t *elem_sizes, 
std::size_t n_elements, std::size_t sizeof_element);
+
+   /// @endcond
+
+   //!Deallocates previously allocated bytes
    void   deallocate          (void *addr);
 
-   /*!Returns the size of the memory segment*/
+   //!Returns the size of the memory segment
    std::size_t get_size()  const;
 
-   /*!Returns the number of free bytes of the memory segment*/
+   //!Returns the number of free bytes of the memory segment
    std::size_t get_free_memory()  const;
 
-   /*!Increases managed memory in extra_size bytes more*/
+   //!Increases managed memory in extra_size bytes more
    void grow(std::size_t extra_size);
 
-   /*!Returns true if all allocated memory has been deallocated*/
+   //!Returns true if all allocated memory has been deallocated
    bool all_memory_deallocated();
 
-   /*!Makes an internal sanity check and returns true if success*/
+   //!Makes an internal sanity check and returns true if success
    bool check_sanity();
 
    //!Initializes to zero all the memory that's not in use.
    //!This function is normally used for security reasons.
    void zero_free_memory();
 
-   std::pair<void *, bool>
+   template<class T>
+   std::pair<T *, bool>
       allocation_command  (allocation_type command,   std::size_t limit_size,
                            std::size_t preferred_size,std::size_t 
&received_size, 
-                           void *reuse_ptr = 0, std::size_t backwards_multiple 
= 1);
+                           T *reuse_ptr = 0);
 
-   /*!Returns the size of the buffer previously allocated pointed by ptr*/
+   //!Returns the size of the buffer previously allocated pointed by ptr
    std::size_t size(void *ptr) const;
 
-   /*!Allocates aligned bytes, returns 0 if there is not more memory.
-      Alignment must be power of 2*/
+   //!Allocates aligned bytes, returns 0 if there is not more memory.
+   //!Alignment must be power of 2
    void* allocate_aligned     (std::size_t nbytes, std::size_t alignment);
 
    private:
-   /*!Real allocation algorithm with min allocation option*/
+   std::pair<void*, bool>
+      priv_allocation_command(allocation_type command,   std::size_t 
limit_size,
+                        std::size_t preferred_size,std::size_t &received_size, 
+                        void *reuse_ptr, std::size_t sizeof_object);
+
+   //!Real allocation algorithm with min allocation option
    std::pair<void *, bool> priv_allocate(allocation_type command
                                         ,std::size_t min_size
                                         ,std::size_t preferred_size
                                         ,std::size_t &received_size
                                         ,void *reuse_ptr = 0);
-   /*!Returns next block if it's free.
-      Returns 0 if next block is not free.*/
+
+   //!Common function to implement the previous two
+   multiallocation_iterator priv_allocate_many
+      (const std::size_t *elem_sizes, std::size_t n_elements, std::size_t 
sizeof_element);
+
+   multiallocation_iterator priv_allocate_many
+      ( std::size_t elem_size, std::size_t min_elements
+      , std::size_t preferred_elements, std::size_t &received_elements);
+
+   //!Returns the number of total units that a user buffer
+   //!of "userbytes" bytes really occupies (including header)
+   static std::size_t priv_get_total_units(std::size_t userbytes);
+
+   //!Returns next block if it's free.
+   //!Returns 0 if next block is not free.
    block_ctrl *priv_next_block_if_free(block_ctrl *ptr);
 
-   /*!Returns previous block's if it's free.
-      Returns 0 if previous block is not free.*/
+   //!Returns previous block's if it's free.
+   //!Returns 0 if previous block is not free.
    std::pair<block_ctrl*, block_ctrl*>priv_prev_block_if_free(block_ctrl *ptr);
 
-   /*!Real expand function implementation*/
+   //!Real expand function implementation
    bool priv_expand(void *ptr
                    ,std::size_t min_size, std::size_t preferred_size
                    ,std::size_t &received_size);
 
-   /*!Real expand to both sides implementation*/
+   //!Real expand to both sides implementation
    void* priv_expand_both_sides(allocation_type command
                                ,std::size_t min_size
                                ,std::size_t preferred_size
@@ -193,7 +302,7 @@
                                ,void *reuse_ptr
                                ,bool only_preferred_backwards);
 
-   /*!Real shrink function implementation*/
+   //!Real shrink function implementation
    bool priv_shrink(void *ptr
                    ,std::size_t max_size, std::size_t preferred_size
                    ,std::size_t &received_size);
@@ -201,16 +310,16 @@
    //!Real private aligned allocation function
    void* priv_allocate_aligned     (std::size_t nbytes, std::size_t alignment);
 
-   /*!Checks if block has enough memory and splits/unlinks the block
-      returning the address to the users*/
+   //!Checks if block has enough memory and splits/unlinks the block
+   //!returning the address to the users
    void* priv_check_and_allocate(std::size_t units
                                 ,block_ctrl* prev
                                 ,block_ctrl* block
                                 ,std::size_t &received_size);
-   /*!Real deallocation algorithm*/
+   //!Real deallocation algorithm
    void priv_deallocate(void *addr);
 
-   /*!Makes a new memory portion available for allocation*/
+   //!Makes a new memory portion available for allocation
    void priv_add_segment(void *addr, std::size_t size);
 
    enum { Alignment      = detail::alignment_of<detail::max_align>::value  };
@@ -219,7 +328,7 @@
    enum { MinBlockSize   = BlockCtrlSize + Alignment  };
 
    public:
-   enum {   PayloadPerAllocation = BlockCtrlBytes  };
+   static const std::size_t PayloadPerAllocation = BlockCtrlBytes;
 };
 
 template<class MutexFamily, class VoidPointer>
@@ -394,19 +503,43 @@
 }
 
 template<class MutexFamily, class VoidPointer>
-inline std::pair<void *, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
-   allocation_command  (allocation_type command,   std::size_t min_size,
+template<class T>
+inline std::pair<T*, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
+   allocation_command  (allocation_type command,   std::size_t limit_size,
                         std::size_t preferred_size,std::size_t &received_size, 
-                        void *reuse_ptr, std::size_t backwards_multiple)
+                        T *reuse_ptr)
+{
+   std::pair<void*, bool> ret = priv_allocation_command
+      (command, limit_size, preferred_size, received_size, reuse_ptr, 
sizeof(T));
+   BOOST_ASSERT(0 == ((std::size_t)ret.first % 
detail::alignment_of<T>::value));
+   return std::pair<T *, bool>(static_cast<T*>(ret.first), ret.second);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline std::pair<void*, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
+   priv_allocation_command (allocation_type command,   std::size_t limit_size,
+                       std::size_t preferred_size,std::size_t &received_size, 
+                       void *reuse_ptr, std::size_t sizeof_object)
 {
-   //-----------------------
-   boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
-   //-----------------------
-   (void)backwards_multiple;
    command &= ~expand_bwd;
-   if(!command)
-      return std::pair<void *, bool>(0, false);
-   return priv_allocate(command, min_size, preferred_size, received_size, 
reuse_ptr);
+   if(!command)   return std::pair<void *, bool>(0, false);
+
+   std::pair<void*, bool> ret;
+   std::size_t max_count = m_header.m_size/sizeof_object;
+   if(limit_size > max_count || preferred_size > max_count){
+      ret.first = 0; return ret;
+   }
+   std::size_t l_size = limit_size*sizeof_object;
+   std::size_t p_size = preferred_size*sizeof_object;
+   std::size_t r_size;
+   {
+      //-----------------------
+      boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+      //-----------------------
+      ret = priv_allocate(command, l_size, p_size, r_size, reuse_ptr);
+   }
+   received_size = r_size/sizeof_object;
+   return ret;
 }
 
 template<class MutexFamily, class VoidPointer>
@@ -500,6 +633,142 @@
 }
 
 template<class MutexFamily, class VoidPointer>
+inline typename simple_seq_fit_impl<MutexFamily, 
VoidPointer>::multiallocation_iterator
+   simple_seq_fit_impl<MutexFamily, VoidPointer>::
+   allocate_many(std::size_t elem_size, std::size_t min_elements, std::size_t 
preferred_elements, std::size_t &received_elements)
+{
+   //-----------------------
+   boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+   //-----------------------
+   return priv_allocate_many(elem_size, min_elements, preferred_elements, 
received_elements);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline typename simple_seq_fit_impl<MutexFamily, 
VoidPointer>::multiallocation_iterator
+   simple_seq_fit_impl<MutexFamily, VoidPointer>::
+   allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, 
std::size_t sizeof_element)
+{
+   //-----------------------
+   boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+   //-----------------------
+   return priv_allocate_many(elem_sizes, n_elements, sizeof_element);
+}
+
+template<class MutexFamily, class VoidPointer>
+typename simple_seq_fit_impl<MutexFamily, 
VoidPointer>::multiallocation_iterator
+   simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_allocate_many
+      (const std::size_t *elem_sizes, std::size_t n_elements, std::size_t 
sizeof_element)
+{
+   //Calculate the total size of all requests
+   std::size_t total_request_units;
+   total_request_units = 0;
+   for(std::size_t i = 0; i < n_elements; ++i){
+      std::size_t preferred_units = 
priv_get_total_units(elem_sizes[i]*sizeof_element);
+      total_request_units += preferred_units;
+   }
+
+   std::size_t total_bytes = total_request_units*Alignment - BlockCtrlBytes;
+
+   std::size_t received_size;
+   std::pair<void *, bool> ret = priv_allocate
+      (allocate_new, total_bytes, total_bytes, received_size, 0);
+   if(!ret.first){
+      return multiallocation_iterator();
+   }
+
+   block_ctrl *block = reinterpret_cast<block_ctrl*>
+                           (detail::char_ptr_cast(ret.first) - BlockCtrlBytes);
+   std::size_t received_units = block->m_size;
+   char *block_address = (char*)block;
+
+   total_request_units = 0;
+
+   {
+      std::size_t preferred_units;
+      //If all have the same size, we don't need calculate it
+      //every iteration
+      for(std::size_t i = 0; i < n_elements; ++i){
+         //If all have different size, we have to calculate it each iteration
+         preferred_units = priv_get_total_units(elem_sizes[i]*sizeof_element);
+         //This is the position where the new block must be created
+         block_ctrl *new_block = new(block_address)block_ctrl;
+         //The last block should take all the remaining space
+         if((i + 1) == n_elements){
+            new_block->m_size = received_units - total_request_units;
+         }
+         else{
+            new_block->m_size = preferred_units;
+         }
+         //assert(new_block->m_size >= BlockCtrlUnits);
+         new_block->m_next = 0;
+         block_address += new_block->m_size*Alignment;
+         total_request_units += new_block->m_size;
+      }
+      assert(total_request_units == received_units);
+   }
+   return multiallocation_iterator(block, n_elements);
+}
+
+template<class MutexFamily, class VoidPointer>
+typename simple_seq_fit_impl<MutexFamily, 
VoidPointer>::multiallocation_iterator
+   simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_allocate_many
+      ( std::size_t elem_size, std::size_t min_elements
+      , std::size_t preferred_elements, std::size_t &received_elements)
+{
+   //Calculate the total size of all requests
+   const std::size_t elem_units = priv_get_total_units(elem_size);
+   const std::size_t total_min_usr_units = min_elements*elem_units - 
BlockCtrlSize;
+   const std::size_t total_preferred_usr_units = preferred_elements*elem_units 
- BlockCtrlSize;
+
+   std::size_t received_size;
+   std::pair<void *, bool> ret = priv_allocate
+      ( allocate_new, total_min_usr_units*Alignment
+      , total_preferred_usr_units*Alignment, received_size, 0);
+   if(!ret.first){
+      received_elements = (received_size + BlockCtrlBytes)/elem_units;
+      return multiallocation_iterator();
+   }
+
+   block_ctrl *block = reinterpret_cast<block_ctrl*>
+      (detail::char_ptr_cast(ret.first) - BlockCtrlBytes);
+   std::size_t received_units = block->m_size;
+   char *block_address = (char*)block;
+
+   received_elements = received_units/elem_units;
+   if(received_elements > preferred_elements){
+      received_elements = preferred_elements;
+   }
+   std::size_t total_request_units = 0;
+   {
+      for(std::size_t i = 0; i < received_elements; ++i){
+         //If all have different size, we have to calculate it each iteration
+         //This is the position where the new block must be created
+         block_ctrl *new_block = new(block_address)block_ctrl;
+         //The last block should take all the remaining space
+         if((i + 1) == received_elements){
+            new_block->m_size = received_units - 
(received_elements-1)*elem_units;
+         }
+         else{
+            new_block->m_size = elem_units;
+         }
+         //assert(new_block->m_size >= BlockCtrlUnits);
+         new_block->m_next = 0;
+         block_address += new_block->m_size*Alignment;
+         total_request_units += new_block->m_size;
+      }
+      assert(total_request_units == received_units);
+   }
+   return multiallocation_iterator(block, received_elements);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>::
+   priv_get_total_units(std::size_t userbytes)
+{
+   return detail::get_rounded_size(userbytes, Alignment)/Alignment + 
BlockCtrlSize;
+}
+
+template<class MutexFamily, class VoidPointer>
 std::pair<void *, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
    priv_allocate(allocation_type command
                 ,std::size_t limit_size


-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
Boost-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/boost-cvs

Reply via email to