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