LCOV - code coverage report
Current view: top level - usr/include/boost/pool - simple_segregated_storage.hpp (source / functions) Hit Total Coverage
Test: ROSE Lines: 0 44 0.0 %
Date: 2022-12-08 13:48:47 Functions: 0 1 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (C) 2000, 2001 Stephen Cleary
       2             : //
       3             : // Distributed under the Boost Software License, Version 1.0. (See
       4             : // accompanying file LICENSE_1_0.txt or copy at
       5             : // http://www.boost.org/LICENSE_1_0.txt)
       6             : //
       7             : // See http://www.boost.org for updates, documentation, and revision history.
       8             : 
       9             : #ifndef BOOST_SIMPLE_SEGREGATED_STORAGE_HPP
      10             : #define BOOST_SIMPLE_SEGREGATED_STORAGE_HPP
      11             : 
      12             : /*!
      13             :   \file
      14             :   \brief Simple Segregated Storage.
      15             :   \details A simple segregated storage implementation:
      16             :   simple segregated storage is the basic idea behind the Boost Pool library.
      17             :   Simple segregated storage is the simplest, and probably the fastest,
      18             :   memory allocation/deallocation algorithm.
      19             :   It begins by partitioning a memory block into fixed-size chunks.
      20             :   Where the block comes from is not important until implementation time.
      21             :   A Pool is some object that uses Simple Segregated Storage in this fashion.
      22             : */
      23             : 
      24             : // std::greater
      25             : #include <functional>
      26             : 
      27             : #include <boost/pool/poolfwd.hpp>
      28             : 
      29             : #ifdef BOOST_MSVC
      30             : #pragma warning(push)
      31             : #pragma warning(disable:4127)  // Conditional expression is constant
      32             : #endif
      33             : 
      34             : #ifdef BOOST_POOL_VALIDATE
      35             : #  define BOOST_POOL_VALIDATE_INTERNALS validate();
      36             : #else
      37             : #  define BOOST_POOL_VALIDATE_INTERNALS
      38             : #endif
      39             : 
      40             : namespace boost {
      41             : 
      42             : /*! 
      43             : 
      44             : \brief Simple Segregated Storage is the simplest, and probably the fastest,
      45             : memory allocation/deallocation algorithm.  It is responsible for
      46             : partitioning a memory block into fixed-size chunks: where the block comes from 
      47             : is determined by the client of the class.
      48             : 
      49             : \details Template class simple_segregated_storage controls access to a free list of memory chunks. 
      50             : Please note that this is a very simple class, with preconditions on almost all its functions. It is intended to 
      51             : be the fastest and smallest possible quick memory allocator - e.g., something to use in embedded systems. 
      52             : This class delegates many difficult preconditions to the user (i.e., alignment issues).
      53             : 
      54             : An object of type simple_segregated_storage<SizeType>  is empty  if its free list is empty. 
      55             : If it is not empty, then it is ordered  if its free list is ordered. A free list is ordered if repeated calls 
      56             : to <tt>malloc()</tt> will result in a constantly-increasing sequence of values, as determined by <tt>std::less<void *></tt>. 
      57             : A member function is <i>order-preserving</i> if the free list maintains its order orientation (that is, an 
      58             : ordered free list is still ordered after the member function call).
      59             : 
      60             : */
      61             : template <typename SizeType>
      62             : class simple_segregated_storage
      63             : {
      64             :   public:
      65             :     typedef SizeType size_type;
      66             : 
      67             :   private:
      68             :     simple_segregated_storage(const simple_segregated_storage &);
      69             :     void operator=(const simple_segregated_storage &);
      70             : 
      71             :     static void * try_malloc_n(void * & start, size_type n,
      72             :         size_type partition_size);
      73             : 
      74             :   protected:
      75             :     void * first; /*!< This data member is the free list.
      76             :       It points to the first chunk in the free list,
      77             :       or is equal to 0 if the free list is empty.
      78             :     */
      79             : 
      80             :     void * find_prev(void * ptr);
      81             : 
      82             :     // for the sake of code readability :)
      83           0 :     static void * & nextof(void * const ptr)
      84             :     { //! The return value is just *ptr cast to the appropriate type. ptr must not be 0. (For the sake of code readability :)
      85             :     //! As an example, let us assume that we want to truncate the free list after the first chunk.
      86             :     //! That is, we want to set *first to 0; this will result in a free list with only one entry.
      87             :     //! The normal way to do this is to first cast first to a pointer to a pointer to void,
      88             :     //! and then dereference and assign (*static_cast<void **>(first) = 0;).
      89             :     //! This can be done more easily through the use of this convenience function (nextof(first) = 0;).
      90             :     //! \returns dereferenced pointer.
      91             :       return *(static_cast<void **>(ptr));
      92             :     }
      93             : 
      94             :   public:
      95             :     // Post: empty()
      96           0 :     simple_segregated_storage()
      97           0 :     :first(0)
      98             :     { //! Construct empty storage area.
      99             :       //! \post empty()
     100             :     }
     101             : 
     102             :     static void * segregate(void * block,
     103             :         size_type nsz, size_type npartition_sz,
     104             :         void * end = 0);
     105             : 
     106             :     // Same preconditions as 'segregate'
     107             :     // Post: !empty()
     108           0 :     void add_block(void * const block,
     109             :         const size_type nsz, const size_type npartition_sz)
     110             :     { //! Add block
     111             :       //! Segregate this block and merge its free list into the
     112             :       //!  free list referred to by "first".
     113             :       //! \pre Same as segregate.
     114             :       //!  \post !empty()
     115             :       BOOST_POOL_VALIDATE_INTERNALS
     116           0 :       first = segregate(block, nsz, npartition_sz, first);
     117             :       BOOST_POOL_VALIDATE_INTERNALS
     118           0 :     }
     119             : 
     120             :     // Same preconditions as 'segregate'
     121             :     // Post: !empty()
     122           0 :     void add_ordered_block(void * const block,
     123             :         const size_type nsz, const size_type npartition_sz)
     124             :     { //! add block (ordered into list)
     125             :       //! This (slower) version of add_block segregates the
     126             :       //!  block and merges its free list into our free list
     127             :       //!  in the proper order.
     128             :        BOOST_POOL_VALIDATE_INTERNALS
     129             :       // Find where "block" would go in the free list
     130           0 :       void * const loc = find_prev(block);
     131             : 
     132             :       // Place either at beginning or in middle/end
     133             :       if (loc == 0)
     134           0 :         add_block(block, nsz, npartition_sz);
     135             :       else
     136           0 :         nextof(loc) = segregate(block, nsz, npartition_sz, nextof(loc));
     137             :       BOOST_POOL_VALIDATE_INTERNALS
     138           0 :     }
     139             : 
     140             :     // default destructor.
     141             : 
     142           0 :     bool empty() const
     143             :     { //! \returns true only if simple_segregated_storage is empty.
     144             :       return (first == 0);
     145             :     }
     146             : 
     147           0 :     void * malloc BOOST_PREVENT_MACRO_SUBSTITUTION()
     148             :     { //! Create a chunk.
     149             :       //!  \pre !empty()
     150             :       //! Increment the "first" pointer to point to the next chunk.
     151             :        BOOST_POOL_VALIDATE_INTERNALS
     152           0 :       void * const ret = first;
     153             : 
     154             :       // Increment the "first" pointer to point to the next chunk.
     155           0 :       first = nextof(first);
     156             :       BOOST_POOL_VALIDATE_INTERNALS
     157             :       return ret;
     158             :     }
     159             : 
     160           0 :     void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const chunk)
     161             :     { //! Free a chunk.
     162             :       //! \pre chunk was previously returned from a malloc() referring to the same free list.
     163             :       //! \post !empty()
     164             :        BOOST_POOL_VALIDATE_INTERNALS
     165           0 :       nextof(chunk) = first;
     166           0 :       first = chunk;
     167             :       BOOST_POOL_VALIDATE_INTERNALS
     168             :     }
     169             : 
     170             :     void ordered_free(void * const chunk)
     171             :     { //! This (slower) implementation of 'free' places the memory
     172             :       //!  back in the list in its proper order.
     173             :       //! \pre chunk was previously returned from a malloc() referring to the same free list
     174             :       //! \post !empty().
     175             : 
     176             :       // Find where "chunk" goes in the free list
     177             :        BOOST_POOL_VALIDATE_INTERNALS
     178             :       void * const loc = find_prev(chunk);
     179             : 
     180             :       // Place either at beginning or in middle/end.
     181             :       if (loc == 0)
     182             :         (free)(chunk);
     183             :       else
     184             :       {
     185             :         nextof(chunk) = nextof(loc);
     186             :         nextof(loc) = chunk;
     187             :       }
     188             :       BOOST_POOL_VALIDATE_INTERNALS
     189             :     }
     190             : 
     191             :    void * malloc_n(size_type n, size_type partition_size);
     192             :     
     193             :     //! \pre chunks was previously allocated from *this with the same
     194             :     //!   values for n and partition_size.
     195             :     //! \post !empty()
     196             :     //! \note If you're allocating/deallocating n a lot, you should
     197             :     //!  be using an ordered pool.
     198             :     void free_n(void * const chunks, const size_type n,
     199             :         const size_type partition_size)
     200             :     { 
     201             :        BOOST_POOL_VALIDATE_INTERNALS
     202             :       if(n != 0)
     203             :         add_block(chunks, n * partition_size, partition_size);
     204             :        BOOST_POOL_VALIDATE_INTERNALS
     205             :     }
     206             : 
     207             :     // pre: chunks was previously allocated from *this with the same
     208             :     //   values for n and partition_size.
     209             :     // post: !empty()
     210             :     void ordered_free_n(void * const chunks, const size_type n,
     211             :         const size_type partition_size)
     212             :     { //! Free n chunks from order list.
     213             :       //! \pre chunks was previously allocated from *this with the same
     214             :       //!   values for n and partition_size.
     215             : 
     216             :       //! \pre n should not be zero (n == 0 has no effect).
     217             :        BOOST_POOL_VALIDATE_INTERNALS
     218             :       if(n != 0)
     219             :         add_ordered_block(chunks, n * partition_size, partition_size);
     220             :        BOOST_POOL_VALIDATE_INTERNALS
     221             :     }
     222             : #ifdef BOOST_POOL_VALIDATE
     223             :     void validate()
     224             :     {
     225             :        int index = 0;
     226             :        void* old = 0;
     227             :        void* ptr = first;
     228             :        while(ptr)
     229             :        {
     230             :           void* pt = nextof(ptr); // trigger possible segfault *before* we update variables
     231             :           ++index;
     232             :           old = ptr;
     233             :           ptr = nextof(ptr);
     234             :        }
     235             :     }
     236             : #endif
     237             : };
     238             : 
     239             : //! Traverses the free list referred to by "first",
     240             : //!  and returns the iterator previous to where
     241             : //!  "ptr" would go if it was in the free list.
     242             : //!  Returns 0 if "ptr" would go at the beginning
     243             : //!  of the free list (i.e., before "first").
     244             : 
     245             : //! \note Note that this function finds the location previous to where ptr would go
     246             : //! if it was in the free list.
     247             : //! It does not find the entry in the free list before ptr
     248             : //! (unless ptr is already in the free list).
     249             : //! Specifically, find_prev(0) will return 0,
     250             : //! not the last entry in the free list.
     251             : //! \returns location previous to where ptr would go if it was in the free list.
     252             : template <typename SizeType>
     253           0 : void * simple_segregated_storage<SizeType>::find_prev(void * const ptr)
     254             : { 
     255             :   // Handle border case.
     256           0 :   if (first == 0 || std::greater<void *>()(first, ptr))
     257             :     return 0;
     258             : 
     259             :   void * iter = first;
     260             :   while (true)
     261             :   {
     262             :     // if we're about to hit the end, or if we've found where "ptr" goes.
     263           0 :     if (nextof(iter) == 0 || std::greater<void *>()(nextof(iter), ptr))
     264             :       return iter;
     265             : 
     266           0 :     iter = nextof(iter);
     267             :   }
     268             : }
     269             : 
     270             : //! Segregate block into chunks.
     271             : //! \pre npartition_sz >= sizeof(void *)
     272             : //! \pre    npartition_sz = sizeof(void *) * i, for some integer i
     273             : //! \pre    nsz >= npartition_sz
     274             : //! \pre Block is properly aligned for an array of object of
     275             : //!        size npartition_sz and array of void *.
     276             : //! The requirements above guarantee that any pointer to a chunk
     277             : //! (which is a pointer to an element in an array of npartition_sz)
     278             : //! may be cast to void **.
     279             : template <typename SizeType>
     280           0 : void * simple_segregated_storage<SizeType>::segregate(
     281             :     void * const block,
     282             :     const size_type sz,
     283             :     const size_type partition_sz,
     284             :     void * const end)
     285             : {
     286             :   // Get pointer to last valid chunk, preventing overflow on size calculations
     287             :   //  The division followed by the multiplication just makes sure that
     288             :   //    old == block + partition_sz * i, for some integer i, even if the
     289             :   //    block size (sz) is not a multiple of the partition size.
     290           0 :   char * old = static_cast<char *>(block)
     291           0 :       + ((sz - partition_sz) / partition_sz) * partition_sz;
     292             : 
     293             :   // Set it to point to the end
     294           0 :   nextof(old) = end;
     295             : 
     296             :   // Handle border case where sz == partition_sz (i.e., we're handling an array
     297             :   //  of 1 element)
     298           0 :   if (old == block)
     299             :     return block;
     300             : 
     301             :   // Iterate backwards, building a singly-linked list of pointers
     302           0 :   for (char * iter = old - partition_sz; iter != block;
     303             :       old = iter, iter -= partition_sz)
     304           0 :     nextof(iter) = old;
     305             : 
     306             :   // Point the first pointer, too
     307           0 :   nextof(block) = old;
     308             : 
     309           0 :   return block;
     310             : }
     311             : 
     312             : //! \pre (n > 0), (start != 0), (nextof(start) != 0)
     313             : //! \post (start != 0)
     314             : //! The function attempts to find n contiguous chunks
     315             : //!  of size partition_size in the free list, starting at start.
     316             : //! If it succeds, it returns the last chunk in that contiguous
     317             : //!  sequence, so that the sequence is known by [start, {retval}]
     318             : //! If it fails, it does do either because it's at the end of the
     319             : //!  free list or hits a non-contiguous chunk.  In either case,
     320             : //!  it will return 0, and set start to the last considered
     321             : //!  chunk.  You are at the end of the free list if
     322             : //!  nextof(start) == 0.  Otherwise, start points to the last
     323             : //!  chunk in the contiguous sequence, and nextof(start) points
     324             : //!  to the first chunk in the next contiguous sequence (assuming
     325             : //!  an ordered free list).
     326             : template <typename SizeType>
     327             : void * simple_segregated_storage<SizeType>::try_malloc_n(
     328             :     void * & start, size_type n, const size_type partition_size)
     329             : {
     330           0 :   void * iter = nextof(start);
     331           0 :   while (--n != 0)
     332             :   {
     333           0 :     void * next = nextof(iter);
     334           0 :     if (next != static_cast<char *>(iter) + partition_size)
     335             :     {
     336             :       // next == 0 (end-of-list) or non-contiguous chunk found
     337             :       start = iter;
     338             :       return 0;
     339             :     }
     340             :     iter = next;
     341             :   }
     342             :   return iter;
     343             : }
     344             : 
     345             : //! Attempts to find a contiguous sequence of n partition_sz-sized chunks. If found, removes them 
     346             : //! all from the free list and returns a pointer to the first. If not found, returns 0. It is strongly 
     347             : //! recommended (but not required) that the free list be ordered, as this algorithm will fail to find 
     348             : //! a contiguous sequence unless it is contiguous in the free list as well. Order-preserving. 
     349             : //! O(N) with respect to the size of the free list.
     350             : template <typename SizeType>
     351           0 : void * simple_segregated_storage<SizeType>::malloc_n(const size_type n,
     352             :     const size_type partition_size)
     353             : {
     354             :    BOOST_POOL_VALIDATE_INTERNALS
     355           0 :   if(n == 0)
     356             :     return 0;
     357           0 :   void * start = &first;
     358             :   void * iter;
     359             :   do
     360             :   {
     361           0 :     if (nextof(start) == 0)
     362             :       return 0;
     363           0 :     iter = try_malloc_n(start, n, partition_size);
     364           0 :   } while (iter == 0);
     365           0 :   void * const ret = nextof(start);
     366           0 :   nextof(start) = nextof(iter);
     367             :   BOOST_POOL_VALIDATE_INTERNALS
     368           0 :   return ret;
     369             : }
     370             : 
     371             : } // namespace boost
     372             : 
     373             : #ifdef BOOST_MSVC
     374             : #pragma warning(pop)
     375             : #endif
     376             : 
     377             : #endif

Generated by: LCOV version 1.14