LCOV - code coverage report
Current view: top level - source/lib/allocators - DynamicArena.h (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 34 43 79.1 %
Date: 2023-01-19 00:18:29 Functions: 17 49 34.7 %

          Line data    Source code
       1             : /* Copyright (C) 2021 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             : #ifndef INCLUDED_ALLOCATORS_DYNAMIC_ARENA
      24             : #define INCLUDED_ALLOCATORS_DYNAMIC_ARENA
      25             : 
      26             : #include "lib/bits.h"
      27             : 
      28             : #include <cstdlib>
      29             : #include <new> // bad_alloc
      30             : #include <utility>
      31             : #include <vector>
      32             : 
      33             : namespace Allocators {
      34             : 
      35             : /**
      36             :  * 'Blind' memory allocator. Characteristics:
      37             :  * - grows dynamically, and linearily, by BLOCK_SIZE
      38             :  * - no reallocations, pointers remain valid
      39             :  * - can allocate objects up to BLOCK_SIZE in size
      40             :  * - can handle any aligment (up to BLOCK_SIZE)
      41             :  * - Doesn't de-allocate unless cleared or destroyed.
      42             :  */
      43             : template<size_t BLOCK_SIZE>
      44           6 : class DynamicArena
      45             : {
      46             : protected:
      47             :     class Block
      48             :     {
      49             :     public:
      50          10 :         Block()
      51          10 :         {
      52          10 :             m_Data = static_cast<uint8_t*>(
      53          10 :                 std::malloc(BLOCK_SIZE * sizeof(uint8_t)));
      54          10 :             if (!m_Data)
      55             :             {
      56           0 :                 debug_warn("DynamicArena failed to allocate chunk");
      57           0 :                 throw std::bad_alloc();
      58             :             }
      59          10 :         }
      60             : 
      61          10 :         ~Block()
      62             :         {
      63          10 :             std::free(static_cast<void*>(m_Data));
      64          10 :         }
      65             : 
      66             :         Block(const Block& other) = delete;
      67             :         Block& operator=(const Block& other) = delete;
      68             : 
      69           0 :         Block(Block&& other)
      70           0 :             : m_Size(other.m_Size), m_Data(other.m_Data)
      71             :         {
      72           0 :             other.m_Size = 0;
      73           0 :             other.m_Data = nullptr;
      74           0 :         }
      75             : 
      76             :         Block& operator=(Block&& other)
      77             :         {
      78             :             if (&other == this)
      79             :                 return *this;
      80             : 
      81             :             Block tmp(std::move(other));
      82             :             swap(*this, tmp);
      83             : 
      84             :             return *this;
      85             :         }
      86             : 
      87             :         friend void swap(Block& lhs, Block& rhs)
      88             :         {
      89             :             using std::swap;
      90             : 
      91             :             swap(lhs.m_Size, rhs.m_Size);
      92             :             swap(lhs.m_Data, rhs.m_Data);
      93             :         }
      94             : 
      95          21 :         bool Available(size_t n, size_t alignment) const
      96             :         {
      97          21 :             return n + ROUND_UP(m_Size, alignment) <= BLOCK_SIZE;
      98             :         }
      99             : 
     100          21 :         uint8_t* Allocate(size_t n, size_t alignment)
     101             :         {
     102          21 :             m_Size = ROUND_UP(m_Size, alignment);
     103          21 :             uint8_t* ptr = &m_Data[m_Size];
     104          21 :             m_Size += n;
     105          21 :             return ptr;
     106             :         }
     107             : 
     108             :     private:
     109             :         size_t m_Size = 0;
     110             :         uint8_t* m_Data = nullptr;
     111             :     };
     112             : 
     113             :     NONCOPYABLE(DynamicArena);
     114             : public:
     115           6 :     DynamicArena()
     116           6 :     {
     117           6 :         m_Blocks.reserve(16);
     118           6 :         AllocateNewBlock();
     119           6 :     };
     120             : 
     121          10 :     void AllocateNewBlock()
     122             :     {
     123          10 :         m_Blocks.emplace_back();
     124          10 :     }
     125             : 
     126          21 :     void* allocate(size_t n, const void*, size_t alignment)
     127             :     {
     128             :         // Safely handle zero-sized allocations (happens with GCC STL - see ticket #909).
     129          21 :         if (n == 0)
     130           1 :             n = 1;
     131             : 
     132          21 :         if (n > BLOCK_SIZE)
     133             :         {
     134           0 :             debug_warn("DynamicArena cannot allocate more than chunk size");
     135           0 :             throw std::bad_alloc();
     136             :         }
     137             : 
     138          21 :         if (!m_Blocks.back().Available(n, alignment))
     139           4 :             AllocateNewBlock();
     140             : 
     141          21 :         return reinterpret_cast<void*>(m_Blocks.back().Allocate(n, alignment));
     142             :     }
     143             : 
     144           8 :     void deallocate(void* UNUSED(p), size_t UNUSED(n))
     145             :     {
     146             :         // ignored
     147           8 :     }
     148             : 
     149             :     void clear()
     150             :     {
     151             :         m_Blocks.clear();
     152             :         AllocateNewBlock();
     153             :     }
     154             : 
     155             : protected:
     156             :     std::vector<Block> m_Blocks;
     157             : };
     158             : 
     159             : } // namespace Allocators
     160             : 
     161             : #endif // INCLUDED_ALLOCATORS_DYNAMIC_ARENA

Generated by: LCOV version 1.13