LCOV - code coverage report
Current view: top level - source/lib/allocators - pool.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 2 76 2.6 %
Date: 2023-01-19 00:18:29 Functions: 2 19 10.5 %

          Line data    Source code
       1             : /* Copyright (C) 2011 Wildfire Games.
       2             :  *
       3             :  * Permission is hereby granted, free of charge, to any person obtaining
       4             :  * a copy of this software and associated documentation files (the
       5             :  * "Software"), to deal in the Software without restriction, including
       6             :  * without limitation the rights to use, copy, modify, merge, publish,
       7             :  * distribute, sublicense, and/or sell copies of the Software, and to
       8             :  * permit persons to whom the Software is furnished to do so, subject to
       9             :  * the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included
      12             :  * in all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      15             :  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      16             :  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      17             :  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
      18             :  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
      19             :  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      20             :  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      21             :  */
      22             : 
      23             : /*
      24             :  * pool allocator
      25             :  */
      26             : 
      27             : #include "precompiled.h"
      28             : #include "lib/allocators/pool.h"
      29             : 
      30             : #include "lib/alignment.h"
      31             : #include "lib/allocators/freelist.h"
      32             : 
      33             : #include "lib/timer.h"
      34             : 
      35             : namespace Allocators {
      36             : 
      37             : template<class Storage>
      38             : struct BasicPoolTest
      39             : {
      40           0 :     void operator()() const
      41             :     {
      42           0 :         Pool<double, Storage> p(100);
      43           0 :         const size_t initialSpace = p.RemainingObjects();
      44           0 :         double* p1 = p.Allocate();
      45           0 :         ENSURE(p1 != 0);
      46           0 :         ENSURE(p.Contains(uintptr_t(p1)));
      47           0 :         ENSURE(p.RemainingObjects() == initialSpace-1);
      48           0 :         ENSURE(p.Contains(uintptr_t(p1)+1));
      49           0 :         ENSURE(p.Contains(uintptr_t(p1)+sizeof(double)-1));
      50           0 :         ENSURE(!p.Contains(uintptr_t(p1)-1));
      51           0 :         ENSURE(!p.Contains(uintptr_t(p1)+sizeof(double)));
      52           0 :         if(p.RemainingObjects() == 0)
      53           0 :             ENSURE(p.Allocate() == 0);  // full
      54             :         else
      55           0 :             ENSURE(p.Allocate() != 0);  // can still expand
      56           0 :         p.DeallocateAll();
      57           0 :         ENSURE(!p.Contains(uintptr_t(p1)));
      58             : 
      59           0 :         p1 = p.Allocate();
      60           0 :         ENSURE(p1 != 0);
      61           0 :         ENSURE(p.Contains(uintptr_t(p1)));
      62           0 :         ENSURE(p.RemainingObjects() == initialSpace-1);
      63           0 :         double* p2 = p.Allocate();
      64           0 :         ENSURE(p2 != 0);
      65           0 :         ENSURE(p.Contains(uintptr_t(p2)));
      66           0 :         ENSURE(p.RemainingObjects() == initialSpace-2);
      67           0 :         ENSURE(p2 == (double*)(uintptr_t(p1)+sizeof(double)));
      68           0 :         if(p.RemainingObjects() == 0)
      69           0 :             ENSURE(p.Allocate() == 0);  // full
      70             :         else
      71           0 :             ENSURE(p.Allocate() != 0);  // can still expand
      72           0 :     }
      73             : };
      74             : 
      75           0 : void TestPool()
      76             : {
      77           0 :     ForEachStorage<BasicPoolTest>();
      78           0 : }
      79             : 
      80             : }   // namespace Allocators
      81             : 
      82             : 
      83           1 : TIMER_ADD_CLIENT(tc_pool_alloc);
      84             : 
      85           0 : Status pool_create(Pool* p, size_t max_size, size_t el_size)
      86             : {
      87           0 :     if(el_size == POOL_VARIABLE_ALLOCS)
      88           0 :         p->el_size = 0;
      89             :     else
      90           0 :         p->el_size = Align<allocationAlignment>(el_size);
      91           0 :     p->freelist = mem_freelist_Sentinel();
      92           0 :     RETURN_STATUS_IF_ERR(da_alloc(&p->da, max_size));
      93           0 :     return INFO::OK;
      94             : }
      95             : 
      96             : 
      97           0 : Status pool_destroy(Pool* p)
      98             : {
      99             :     // don't be picky and complain if the freelist isn't empty;
     100             :     // we don't care since it's all part of the da anyway.
     101             :     // however, zero it to prevent further allocs from succeeding.
     102           0 :     p->freelist = mem_freelist_Sentinel();
     103           0 :     return da_free(&p->da);
     104             : }
     105             : 
     106             : 
     107           0 : bool pool_contains(const Pool* p, void* el)
     108             : {
     109             :     // outside of our range
     110           0 :     if(!(p->da.base <= el && el < p->da.base+p->da.pos))
     111           0 :         return false;
     112             :     // sanity check: it should be aligned (if pool has fixed-size elements)
     113           0 :     if(p->el_size)
     114           0 :         ENSURE((uintptr_t)((u8*)el - p->da.base) % p->el_size == 0);
     115           0 :     return true;
     116             : }
     117             : 
     118             : 
     119           0 : void* pool_alloc(Pool* p, size_t size)
     120             : {
     121           0 :     TIMER_ACCRUE(tc_pool_alloc);
     122             :     // if pool allows variable sizes, go with the size parameter,
     123             :     // otherwise the pool el_size setting.
     124           0 :     const size_t el_size = p->el_size? p->el_size : Align<allocationAlignment>(size);
     125           0 :     ASSERT(el_size != 0);
     126             : 
     127             :     // note: freelist is always empty in pools with variable-sized elements
     128             :     // because they disallow pool_free.
     129           0 :     void* el = mem_freelist_Detach(p->freelist);
     130           0 :     if(!el) // freelist empty, need to allocate a new entry
     131             :     {
     132             :         // expand, if necessary
     133           0 :         if(da_reserve(&p->da, el_size) < 0)
     134           0 :             return 0;
     135             : 
     136           0 :         el = p->da.base + p->da.pos;
     137           0 :         p->da.pos += el_size;
     138             :     }
     139             : 
     140           0 :     ASSERT(pool_contains(p, el));   // paranoia
     141           0 :     return el;
     142             : }
     143             : 
     144             : 
     145           0 : void pool_free(Pool* p, void* el)
     146             : {
     147             :     // only allowed to free items if we were initialized with
     148             :     // fixed el_size. (this avoids having to pass el_size here and
     149             :     // check if requested_size matches that when allocating)
     150           0 :     if(p->el_size == 0)
     151             :     {
     152           0 :         DEBUG_WARN_ERR(ERR::LOGIC); // cannot free variable-size items
     153           0 :         return;
     154             :     }
     155             : 
     156           0 :     if(pool_contains(p, el))
     157           0 :         mem_freelist_AddToFront(p->freelist, el);
     158             :     else
     159           0 :         DEBUG_WARN_ERR(ERR::LOGIC); // invalid pointer (not in pool)
     160             : }
     161             : 
     162             : 
     163           0 : void pool_free_all(Pool* p)
     164             : {
     165           0 :     p->freelist = mem_freelist_Sentinel();
     166             : 
     167             :     // must be reset before da_set_size or CHECK_DA will complain.
     168           0 :     p->da.pos = 0;
     169             : 
     170           0 :     da_set_size(&p->da, 0);
     171           0 : }
     172             : 
     173           0 : size_t pool_committed(Pool* p)
     174             : {
     175           0 :     return p->da.cur_size;
     176           3 : }

Generated by: LCOV version 1.13