mem_algo_common.hpp
来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 751 行 · 第 1/2 页
HPP
751 行
////////////////////////////////////////////////////////////////////////////////// (C) Copyright Ion Gaztanaga 2005-2008. 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/interprocess for documentation.////////////////////////////////////////////////////////////////////////////////#ifndef BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP#define BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP#if (defined _MSC_VER) && (_MSC_VER >= 1200)# pragma once#endif#include <boost/interprocess/detail/config_begin.hpp>#include <boost/interprocess/detail/workaround.hpp>#include <boost/interprocess/interprocess_fwd.hpp>#include <boost/interprocess/allocators/allocation_type.hpp>#include <boost/interprocess/detail/utilities.hpp>#include <boost/interprocess/detail/type_traits.hpp>#include <boost/interprocess/detail/iterators.hpp>#include <boost/interprocess/detail/math_functions.hpp>#include <boost/interprocess/detail/utilities.hpp>#include <boost/assert.hpp>#include <boost/static_assert.hpp>//!\file//!Implements common operations for memory algorithms.namespace boost {namespace interprocess {namespace detail {template<class VoidPointer>struct multi_allocation_next{ typedef typename detail:: pointer_to_other<VoidPointer, multi_allocation_next>::type multi_allocation_next_ptr; multi_allocation_next(multi_allocation_next_ptr n) : next_(n) {} multi_allocation_next_ptr next_;};//!This iterator is returned by "allocate_many" functions so that//!the user can access the multiple buffers allocated in a single calltemplate<class VoidPointer>class basic_multiallocation_iterator : public std::iterator<std::input_iterator_tag, char>{ void unspecified_bool_type_func() const {} typedef void (basic_multiallocation_iterator::*unspecified_bool_type)() const; typedef typename detail:: pointer_to_other <VoidPointer, multi_allocation_next<VoidPointer> >::type multi_allocation_next_ptr; public: typedef char value_type; typedef value_type & reference; typedef value_type * pointer; basic_multiallocation_iterator() : next_alloc_(0) {} basic_multiallocation_iterator(multi_allocation_next_ptr next) : next_alloc_(next) {} basic_multiallocation_iterator &operator=(const basic_multiallocation_iterator &other) { next_alloc_ = other.next_alloc_; return *this; } public: basic_multiallocation_iterator& operator++() { next_alloc_.next_ = detail::get_pointer(next_alloc_.next_->next_); return *this; } basic_multiallocation_iterator operator++(int) { basic_multiallocation_iterator result(next_alloc_.next_); ++*this; return result; } bool operator== (const basic_multiallocation_iterator& other) const { return next_alloc_.next_ == other.next_alloc_.next_; } bool operator!= (const basic_multiallocation_iterator& other) const { return !operator== (other); } reference operator*() const { return *reinterpret_cast<char*>(detail::get_pointer(next_alloc_.next_)); } operator unspecified_bool_type() const { return next_alloc_.next_? &basic_multiallocation_iterator::unspecified_bool_type_func : 0; } pointer operator->() const { return &(*(*this)); } static basic_multiallocation_iterator create_simple_range(void *mem) { basic_multiallocation_iterator it; typedef multi_allocation_next<VoidPointer> next_impl_t; next_impl_t * tmp_mem = static_cast<next_impl_t*>(mem); it = basic_multiallocation_iterator<VoidPointer>(tmp_mem); tmp_mem->next_ = 0; return it; } multi_allocation_next<VoidPointer> &get_multi_allocation_next() { return *next_alloc_.next_; } private: multi_allocation_next<VoidPointer> next_alloc_;};template<class VoidPointer>class basic_multiallocation_chain{ private: basic_multiallocation_iterator<VoidPointer> it_; VoidPointer last_mem_; std::size_t num_mem_; basic_multiallocation_chain(const basic_multiallocation_chain &); basic_multiallocation_chain &operator=(const basic_multiallocation_chain &); public: typedef basic_multiallocation_iterator<VoidPointer> multiallocation_iterator; basic_multiallocation_chain() : it_(0), last_mem_(0), num_mem_(0) {} void reset() { this->it_ = multiallocation_iterator(); this->last_mem_ = 0; this->num_mem_ = 0; } void push_back(void *mem) { typedef multi_allocation_next<VoidPointer> next_impl_t; next_impl_t * tmp_mem = static_cast<next_impl_t*>(mem); if(!this->last_mem_){ this->it_ = basic_multiallocation_iterator<VoidPointer>(tmp_mem); } else{ static_cast<next_impl_t*>(detail::get_pointer(this->last_mem_))->next_ = tmp_mem; } tmp_mem->next_ = 0; this->last_mem_ = tmp_mem; ++num_mem_; } void push_front(void *mem) { typedef multi_allocation_next<VoidPointer> next_impl_t; next_impl_t * tmp_mem = static_cast<next_impl_t*>(mem); ++num_mem_; if(!this->last_mem_){ this->it_ = basic_multiallocation_iterator<VoidPointer>(tmp_mem); tmp_mem->next_ = 0; this->last_mem_ = tmp_mem; } else{ next_impl_t * old_first = &this->it_.get_multi_allocation_next(); tmp_mem->next_ = old_first; this->it_ = basic_multiallocation_iterator<VoidPointer>(tmp_mem); } } void swap(basic_multiallocation_chain &other_chain) { std::swap(this->it_, other_chain.it_); std::swap(this->last_mem_, other_chain.last_mem_); std::swap(this->num_mem_, other_chain.num_mem_); } void splice_back(basic_multiallocation_chain &other_chain) { typedef multi_allocation_next<VoidPointer> next_impl_t; multiallocation_iterator end_it; multiallocation_iterator other_it = other_chain.get_it(); multiallocation_iterator this_it = this->get_it(); if(end_it == other_it){ return; } else if(end_it == this_it){ this->swap(other_chain); } else{ static_cast<next_impl_t*>(detail::get_pointer(this->last_mem_))->next_ = &other_chain.it_.get_multi_allocation_next(); this->last_mem_ = other_chain.last_mem_; this->num_mem_ += other_chain.num_mem_; } } void *pop_front() { multiallocation_iterator itend; if(this->it_ == itend){ this->last_mem_= 0; this->num_mem_ = 0; return 0; } else{ void *addr = &*it_; ++it_; --num_mem_; if(!num_mem_){ this->last_mem_ = 0; this->it_ = multiallocation_iterator(); } return addr; } } bool empty() const { return !num_mem_; } multiallocation_iterator get_it() const { return it_; } std::size_t size() const { return num_mem_; }};//!This class implements several allocation functions shared by different algorithms//!(aligned allocation, multiple allocation...).template<class MemoryAlgorithm>class memory_algorithm_common{ public: typedef typename MemoryAlgorithm::void_pointer void_pointer; typedef typename MemoryAlgorithm::block_ctrl block_ctrl; typedef typename MemoryAlgorithm::multiallocation_iterator multiallocation_iterator; typedef multi_allocation_next<void_pointer> multi_allocation_next_t; typedef typename multi_allocation_next_t:: multi_allocation_next_ptr multi_allocation_next_ptr; typedef memory_algorithm_common<MemoryAlgorithm> this_type; static const std::size_t Alignment = MemoryAlgorithm::Alignment; static const std::size_t MinBlockUnits = MemoryAlgorithm::MinBlockUnits; static const std::size_t AllocatedCtrlBytes = MemoryAlgorithm::AllocatedCtrlBytes; static const std::size_t AllocatedCtrlUnits = MemoryAlgorithm::AllocatedCtrlUnits; static const std::size_t BlockCtrlBytes = MemoryAlgorithm::BlockCtrlBytes; static const std::size_t BlockCtrlUnits = MemoryAlgorithm::BlockCtrlUnits; static const std::size_t UsableByPreviousChunk = MemoryAlgorithm::UsableByPreviousChunk; static void assert_alignment(const void *ptr) { assert_alignment((std::size_t)ptr); } static void assert_alignment(std::size_t uint_ptr) { (void)uint_ptr; BOOST_ASSERT(uint_ptr % Alignment == 0); } static bool check_alignment(const void *ptr) { return (((std::size_t)ptr) % Alignment == 0); } static std::size_t ceil_units(std::size_t size) { return detail::get_rounded_size(size, Alignment)/Alignment; } static std::size_t floor_units(std::size_t size) { return size/Alignment; } static std::size_t multiple_of_units(std::size_t size) { return detail::get_rounded_size(size, Alignment); } static multiallocation_iterator allocate_many (MemoryAlgorithm *memory_algo, std::size_t elem_bytes, std::size_t n_elements) { return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0); } static bool calculate_lcm_and_needs_backwards_lcmed (std::size_t backwards_multiple, std::size_t received_size, std::size_t size_to_achieve, std::size_t &lcm_out, std::size_t &needs_backwards_lcmed_out) { // Now calculate lcm std::size_t max = backwards_multiple; std::size_t min = Alignment; std::size_t needs_backwards; std::size_t needs_backwards_lcmed; std::size_t lcm; std::size_t current_forward; //Swap if necessary if(max < min){ std::size_t tmp = min; min = max; max = tmp; } //Check if it's power of two if((backwards_multiple & (backwards_multiple-1)) == 0){ if(0 != (size_to_achieve & ((backwards_multiple-1)))){ return false; } lcm = max; //If we want to use minbytes data to get a buffer between maxbytes //and minbytes if maxbytes can't be achieved, calculate the //biggest of all possibilities current_forward = detail::get_truncated_size_po2(received_size, backwards_multiple); needs_backwards = size_to_achieve - current_forward; assert((needs_backwards % backwards_multiple) == 0); needs_backwards_lcmed = detail::get_rounded_size_po2(needs_backwards, lcm); lcm_out = lcm; needs_backwards_lcmed_out = needs_backwards_lcmed; return true; } //Check if it's multiple of alignment else if((backwards_multiple & (Alignment - 1u)) == 0){ lcm = backwards_multiple; current_forward = detail::get_truncated_size(received_size, backwards_multiple); //No need to round needs_backwards because backwards_multiple == lcm needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; assert((needs_backwards_lcmed & (Alignment - 1u)) == 0); lcm_out = lcm; needs_backwards_lcmed_out = needs_backwards_lcmed; return true; } //Check if it's multiple of the half of the alignmment else if((backwards_multiple & ((Alignment/2u) - 1u)) == 0){ lcm = backwards_multiple*2u; current_forward = detail::get_truncated_size(received_size, backwards_multiple); needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; if(0 != (needs_backwards_lcmed & (Alignment-1))) //while(0 != (needs_backwards_lcmed & (Alignment-1))) needs_backwards_lcmed += backwards_multiple; assert((needs_backwards_lcmed % lcm) == 0); lcm_out = lcm; needs_backwards_lcmed_out = needs_backwards_lcmed; return true; } //Check if it's multiple of the half of the alignmment else if((backwards_multiple & ((Alignment/4u) - 1u)) == 0){ std::size_t remainder; lcm = backwards_multiple*4u; current_forward = detail::get_truncated_size(received_size, backwards_multiple); needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; //while(0 != (needs_backwards_lcmed & (Alignment-1))) //needs_backwards_lcmed += backwards_multiple; if(0 != (remainder = ((needs_backwards_lcmed & (Alignment-1))>>(Alignment/8u)))){ if(backwards_multiple & Alignment/2u){ needs_backwards_lcmed += (remainder)*backwards_multiple; } else{ needs_backwards_lcmed += (4-remainder)*backwards_multiple; } } assert((needs_backwards_lcmed % lcm) == 0); lcm_out = lcm; needs_backwards_lcmed_out = needs_backwards_lcmed; return true; } else{ lcm = detail::lcm(max, min); } //If we want to use minbytes data to get a buffer between maxbytes //and minbytes if maxbytes can't be achieved, calculate the //biggest of all possibilities current_forward = detail::get_truncated_size(received_size, backwards_multiple); needs_backwards = size_to_achieve - current_forward;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?