LCOV - code coverage report
Current view: top level - asmjit - zone.h (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 74 74 100.0 %
Date: 2026-11-05 10:19:06 Functions: 18 29 62.1 %

          Line data    Source code
       1             : #ifdef __PLUMED_HAS_ASMJIT
       2             : // This file is part of AsmJit project <https://asmjit.com>
       3             : //
       4             : // See asmjit.h or LICENSE.md for license and copyright information
       5             : // SPDX-License-Identifier: Zlib
       6             : 
       7             : #ifndef ASMJIT_CORE_ZONE_H_INCLUDED
       8             : #define ASMJIT_CORE_ZONE_H_INCLUDED
       9             : 
      10             : #include "support.h"
      11             : 
      12             : ASMJIT_BEGIN_NAMESPACE
      13             : 
      14             : //! \addtogroup asmjit_zone
      15             : //! \{
      16             : 
      17             : //! Zone memory.
      18             : //!
      19             : //! Zone is an incremental memory allocator that allocates memory by simply incrementing a pointer. It allocates
      20             : //! blocks of memory by using C's `malloc()`, but divides these blocks into smaller segments requested by calling
      21             : //! `Zone::alloc()` and friends.
      22             : //!
      23             : //! Zone has no function to release the allocated memory. It has to be released all at once by calling `reset()`.
      24             : //! If you need a more friendly allocator that also supports `release()`, consider using `Zone` with `ZoneAllocator`.
      25             : class Zone {
      26             : public:
      27             :   ASMJIT_NONCOPYABLE(Zone)
      28             : 
      29             :   //! \cond INTERNAL
      30             : 
      31             :   //! A single block of memory managed by `Zone`.
      32             :   struct Block {
      33             :     inline uint8_t* data() const noexcept {
      34      110922 :       return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(this) + sizeof(*this));
      35             :     }
      36             : 
      37             :     //! Link to the previous block.
      38             :     Block* prev;
      39             :     //! Link to the next block.
      40             :     Block* next;
      41             :     //! Size of the block.
      42             :     size_t size;
      43             :   };
      44             : 
      45             :   enum Limits : size_t {
      46             :     kBlockSize = sizeof(Block),
      47             :     kBlockOverhead = Globals::kAllocOverhead + kBlockSize,
      48             : 
      49             :     kMinBlockSize = 64, // The number is ridiculously small, but still possible.
      50             :     kMaxBlockSize = size_t(1) << (sizeof(size_t) * 8 - 4 - 1),
      51             :     kMinAlignment = 1,
      52             :     kMaxAlignment = 64
      53             :   };
      54             : 
      55             :   //! Pointer in the current block.
      56             :   uint8_t* _ptr;
      57             :   //! End of the current block.
      58             :   uint8_t* _end;
      59             :   //! Current block.
      60             :   Block* _block;
      61             : 
      62             :   union {
      63             :     struct {
      64             :       //! Default block size.
      65             :       size_t _blockSize : Support::bitSizeOf<size_t>() - 4;
      66             :       //! First block is temporary (ZoneTmp).
      67             :       size_t _isTemporary : 1;
      68             :       //! Block alignment (1 << alignment).
      69             :       size_t _blockAlignmentShift : 3;
      70             :     };
      71             :     size_t _packedData;
      72             :   };
      73             : 
      74             :   static ASMJIT_API const Block _zeroBlock;
      75             : 
      76             :   //! \endcond
      77             : 
      78             :   //! \name Construction & Destruction
      79             :   //! \{
      80             : 
      81             :   //! Creates a new Zone.
      82             :   //!
      83             :   //! The `blockSize` parameter describes the default size of the block. If the `size` parameter passed to `alloc()`
      84             :   //! is greater than the default size `Zone` will allocate and use a larger block, but it will not change the
      85             :   //! default `blockSize`.
      86             :   //!
      87             :   //! It's not required, but it's good practice to set `blockSize` to a reasonable value that depends on the usage
      88             :   //! of `Zone`. Greater block sizes are generally safer and perform better than unreasonably low block sizes.
      89      109968 :   inline explicit Zone(size_t blockSize, size_t blockAlignment = 1) noexcept {
      90       54984 :     _init(blockSize, blockAlignment, nullptr);
      91             :   }
      92             : 
      93             :   //! Creates a new Zone with a first block pointing to a `temporary` memory.
      94             :   inline Zone(size_t blockSize, size_t blockAlignment, const Support::Temporary& temporary) noexcept {
      95             :     _init(blockSize, blockAlignment, &temporary);
      96             :   }
      97             : 
      98             :   //! \overload
      99       27492 :   inline Zone(size_t blockSize, size_t blockAlignment, const Support::Temporary* temporary) noexcept {
     100       27492 :     _init(blockSize, blockAlignment, temporary);
     101             :   }
     102             : 
     103             :   //! Moves an existing `Zone`.
     104             :   //!
     105             :   //! \note You cannot move an existing `ZoneTmp` as it uses embedded storage. Attempting to move `ZoneTmp` would
     106             :   //! result in assertion failure in debug mode and undefined behavior in release mode.
     107             :   inline Zone(Zone&& other) noexcept
     108             :     : _ptr(other._ptr),
     109             :       _end(other._end),
     110             :       _block(other._block),
     111             :       _packedData(other._packedData) {
     112             :     ASMJIT_ASSERT(!other.isTemporary());
     113             :     other._block = const_cast<Block*>(&_zeroBlock);
     114             :     other._ptr = other._block->data();
     115             :     other._end = other._block->data();
     116             :   }
     117             : 
     118             :   //! Destroys the `Zone` instance.
     119             :   //!
     120             :   //! This will destroy the `Zone` instance and release all blocks of memory allocated by it. It performs implicit
     121             :   //! `reset(ResetPolicy::kHard)`.
     122       82476 :   inline ~Zone() noexcept { reset(ResetPolicy::kHard); }
     123             : 
     124             :   ASMJIT_API void _init(size_t blockSize, size_t blockAlignment, const Support::Temporary* temporary) noexcept;
     125             : 
     126             :   //! Resets the `Zone` invalidating all blocks allocated.
     127             :   //!
     128             :   //! See `Globals::ResetPolicy` for more details.
     129             :   ASMJIT_API void reset(ResetPolicy resetPolicy = ResetPolicy::kSoft) noexcept;
     130             : 
     131             :   //! \}
     132             : 
     133             :   //! \name Accessors
     134             :   //! \{
     135             : 
     136             :   //! Tests whether this `Zone` is actually a `ZoneTmp` that uses temporary memory.
     137             :   inline bool isTemporary() const noexcept { return _isTemporary != 0; }
     138             : 
     139             :   //! Returns the default block size.
     140      110922 :   inline size_t blockSize() const noexcept { return _blockSize; }
     141             :   //! Returns the default block alignment.
     142      110922 :   inline size_t blockAlignment() const noexcept { return size_t(1) << _blockAlignmentShift; }
     143             :   //! Returns remaining size of the current block.
     144      331808 :   inline size_t remainingSize() const noexcept { return (size_t)(_end - _ptr); }
     145             : 
     146             :   //! Returns the current zone cursor (dangerous).
     147             :   //!
     148             :   //! This is a function that can be used to get exclusive access to the current block's memory buffer.
     149             :   template<typename T = uint8_t>
     150     2487597 :   inline T* ptr() noexcept { return reinterpret_cast<T*>(_ptr); }
     151             : 
     152             :   //! Returns the end of the current zone block, only useful if you use `ptr()`.
     153             :   template<typename T = uint8_t>
     154     2487597 :   inline T* end() noexcept { return reinterpret_cast<T*>(_end); }
     155             : 
     156             :   //! Sets the current zone pointer to `ptr` (must be within the current block).
     157             :   template<typename T>
     158             :   inline void setPtr(T* ptr) noexcept {
     159             :     uint8_t* p = reinterpret_cast<uint8_t*>(ptr);
     160             :     ASMJIT_ASSERT(p >= _ptr && p <= _end);
     161     2432277 :     _ptr = p;
     162         123 :   }
     163             : 
     164             :   //! Sets the end zone pointer to `end` (must be within the current block).
     165             :   template<typename T>
     166             :   inline void setEnd(T* end) noexcept {
     167             :     uint8_t* p = reinterpret_cast<uint8_t*>(end);
     168             :     ASMJIT_ASSERT(p >= _ptr && p <= _end);
     169             :     _end = p;
     170             :   }
     171             : 
     172             :   //! \}
     173             : 
     174             :   //! \name Utilities
     175             :   //! \{
     176             : 
     177             :   inline void swap(Zone& other) noexcept {
     178             :     // This could lead to a disaster.
     179             :     ASMJIT_ASSERT(!this->isTemporary());
     180             :     ASMJIT_ASSERT(!other.isTemporary());
     181             : 
     182             :     std::swap(_ptr, other._ptr);
     183             :     std::swap(_end, other._end);
     184             :     std::swap(_block, other._block);
     185             :     std::swap(_packedData, other._packedData);
     186             :   }
     187             : 
     188             :   //! Aligns the current pointer to `alignment`.
     189             :   inline void align(size_t alignment) noexcept {
     190     2542581 :     _ptr = Support::min(Support::alignUp(_ptr, alignment), _end);
     191             :   }
     192             : 
     193             :   //! Ensures the remaining size is at least equal or greater than `size`.
     194             :   //!
     195             :   //! \note This function doesn't respect any alignment. If you need to ensure there is enough room for an aligned
     196             :   //! allocation you need to call `align()` before calling `ensure()`.
     197             :   inline Error ensure(size_t size) noexcept {
     198             :     if (size <= remainingSize())
     199             :       return kErrorOk;
     200             :     else
     201             :       return _alloc(0, 1) ? kErrorOk : DebugUtils::errored(kErrorOutOfMemory);
     202             :   }
     203             : 
     204       54984 :   inline void _assignBlock(Block* block) noexcept {
     205             :     size_t alignment = blockAlignment();
     206       54984 :     _ptr = Support::alignUp(block->data(), alignment);
     207       54984 :     _end = Support::alignDown(block->data() + block->size, alignment);
     208       54984 :     _block = block;
     209       54984 :   }
     210             : 
     211             :   inline void _assignZeroBlock() noexcept {
     212             :     Block* block = const_cast<Block*>(&_zeroBlock);
     213      137460 :     _ptr = block->data();
     214      137460 :     _end = block->data();
     215      137460 :     _block = block;
     216             :   }
     217             : 
     218             :   //! \}
     219             : 
     220             :   //! \name Allocation
     221             :   //! \{
     222             : 
     223             :   //! Allocates the requested memory specified by `size`.
     224             :   //!
     225             :   //! Pointer returned is valid until the `Zone` instance is destroyed or reset by calling `reset()`. If you plan to
     226             :   //! make an instance of C++ from the given pointer use placement `new` and `delete` operators:
     227             :   //!
     228             :   //! ```
     229             :   //! using namespace asmjit;
     230             :   //!
     231             :   //! class Object { ... };
     232             :   //!
     233             :   //! // Create Zone with default block size of approximately 65536 bytes.
     234             :   //! Zone zone(65536 - Zone::kBlockOverhead);
     235             :   //!
     236             :   //! // Create your objects using zone object allocating, for example:
     237             :   //! Object* obj = static_cast<Object*>( zone.alloc(sizeof(Object)) );
     238             :   //!
     239             :   //! if (!obj) {
     240             :   //!   // Handle out of memory error.
     241             :   //! }
     242             :   //!
     243             :   //! // Placement `new` and `delete` operators can be used to instantiate it.
     244             :   //! new(obj) Object();
     245             :   //!
     246             :   //! // ... lifetime of your objects ...
     247             :   //!
     248             :   //! // To destroy the instance (if required).
     249             :   //! obj->~Object();
     250             :   //!
     251             :   //! // Reset or destroy `Zone`.
     252             :   //! zone.reset();
     253             :   //! ```
     254      331808 :   inline void* alloc(size_t size) noexcept {
     255      331808 :     if (ASMJIT_UNLIKELY(size > remainingSize()))
     256          60 :       return _alloc(size, 1);
     257             : 
     258             :     uint8_t* ptr = _ptr;
     259      331748 :     _ptr += size;
     260      331748 :     return static_cast<void*>(ptr);
     261             :   }
     262             : 
     263             :   //! Allocates the requested memory specified by `size` and `alignment`.
     264      847503 :   inline void* alloc(size_t size, size_t alignment) noexcept {
     265             :     ASMJIT_ASSERT(Support::isPowerOf2(alignment));
     266      847503 :     uint8_t* ptr = Support::alignUp(_ptr, alignment);
     267             : 
     268      847503 :     if (ptr >= _end || size > (size_t)(_end - ptr))
     269       55542 :       return _alloc(size, alignment);
     270             : 
     271      791961 :     _ptr = ptr + size;
     272      791961 :     return static_cast<void*>(ptr);
     273             :   }
     274             : 
     275             :   //! Allocates the requested memory specified by `size` without doing any checks.
     276             :   //!
     277             :   //! Can only be called if `remainingSize()` returns size at least equal to `size`.
     278             :   inline void* allocNoCheck(size_t size) noexcept {
     279             :     ASMJIT_ASSERT(remainingSize() >= size);
     280             : 
     281             :     uint8_t* ptr = _ptr;
     282             :     _ptr += size;
     283             :     return static_cast<void*>(ptr);
     284             :   }
     285             : 
     286             :   //! Allocates the requested memory specified by `size` and `alignment` without doing any checks.
     287             :   //!
     288             :   //! Performs the same operation as `Zone::allocNoCheck(size)` with `alignment` applied.
     289             :   inline void* allocNoCheck(size_t size, size_t alignment) noexcept {
     290             :     ASMJIT_ASSERT(Support::isPowerOf2(alignment));
     291             : 
     292             :     uint8_t* ptr = Support::alignUp(_ptr, alignment);
     293             :     ASMJIT_ASSERT(size <= (size_t)(_end - ptr));
     294             : 
     295             :     _ptr = ptr + size;
     296             :     return static_cast<void*>(ptr);
     297             :   }
     298             : 
     299             :   //! Allocates `size` bytes of zeroed memory. See `alloc()` for more details.
     300             :   ASMJIT_API void* allocZeroed(size_t size, size_t alignment = 1) noexcept;
     301             : 
     302             :   //! Like `alloc()`, but the return pointer is casted to `T*`.
     303             :   template<typename T>
     304             :   inline T* allocT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept {
     305      192444 :     return static_cast<T*>(alloc(size, alignment));
     306             :   }
     307             : 
     308             :   //! Like `allocNoCheck()`, but the return pointer is casted to `T*`.
     309             :   template<typename T>
     310             :   inline T* allocNoCheckT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept {
     311             :     return static_cast<T*>(allocNoCheck(size, alignment));
     312             :   }
     313             : 
     314             :   //! Like `allocZeroed()`, but the return pointer is casted to `T*`.
     315             :   template<typename T>
     316             :   inline T* allocZeroedT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept {
     317      273777 :     return static_cast<T*>(allocZeroed(size, alignment));
     318             :   }
     319             : 
     320             :   //! Like `new(std::nothrow) T(...)`, but allocated by `Zone`.
     321             :   template<typename T>
     322       54984 :   inline T* newT() noexcept {
     323       54984 :     void* p = alloc(sizeof(T), alignof(T));
     324       54984 :     if (ASMJIT_UNLIKELY(!p))
     325             :       return nullptr;
     326       54984 :     return new(p) T();
     327             :   }
     328             : 
     329             :   //! Like `new(std::nothrow) T(...)`, but allocated by `Zone`.
     330             :   template<typename T, typename... Args>
     331      326298 :   inline T* newT(Args&&... args) noexcept {
     332      326298 :     void* p = alloc(sizeof(T), alignof(T));
     333      326298 :     if (ASMJIT_UNLIKELY(!p))
     334             :       return nullptr;
     335      326298 :     return new(p) T(std::forward<Args>(args)...);
     336             :   }
     337             : 
     338             :   //! \cond INTERNAL
     339             :   //!
     340             :   //! Internal alloc function used by other inlines.
     341             :   ASMJIT_API void* _alloc(size_t size, size_t alignment) noexcept;
     342             :   //! \endcond
     343             : 
     344             :   //! Helper to duplicate data.
     345             :   ASMJIT_API void* dup(const void* data, size_t size, bool nullTerminate = false) noexcept;
     346             : 
     347             :   //! Helper to duplicate data.
     348       54984 :   inline void* dupAligned(const void* data, size_t size, size_t alignment, bool nullTerminate = false) noexcept {
     349             :     align(alignment);
     350       54984 :     return dup(data, size, nullTerminate);
     351             :   }
     352             : 
     353             :   //! Helper to duplicate a formatted string, maximum size is 256 bytes.
     354             :   ASMJIT_API char* sformat(const char* str, ...) noexcept;
     355             : 
     356             :   //! \}
     357             : };
     358             : 
     359             : //! \ref Zone with `N` bytes of a static storage, used for the initial block.
     360             : //!
     361             : //! Temporary zones are used in cases where it's known that some memory will be required, but in many cases it won't
     362             : //! exceed N bytes, so the whole operation can be performed without a dynamic memory allocation.
     363             : template<size_t N>
     364             : class ZoneTmp : public Zone {
     365             : public:
     366             :   ASMJIT_NONCOPYABLE(ZoneTmp)
     367             : 
     368             :   //! Temporary storage, embedded after \ref Zone.
     369             :   struct Storage {
     370             :     char data[N];
     371             :   } _storage;
     372             : 
     373             :   //! Creates a temporary zone. Dynamic block size is specified by `blockSize`.
     374             :   inline explicit ZoneTmp(size_t blockSize, size_t blockAlignment = 1) noexcept
     375             :     : Zone(blockSize, blockAlignment, Support::Temporary(_storage.data, N)) {}
     376             : };
     377             : 
     378             : //! Zone-based memory allocator that uses an existing `Zone` and provides a `release()` functionality on top of it.
     379             : //! It uses `Zone` only for chunks that can be pooled, and uses libc `malloc()` for chunks that are large.
     380             : //!
     381             : //! The advantage of ZoneAllocator is that it can allocate small chunks of memory really fast, and these chunks,
     382             : //! when released, will be reused by consecutive calls to `alloc()`. Also, since ZoneAllocator uses `Zone`, you can
     383             : //! turn any `Zone` into a `ZoneAllocator`, and use it in your `Pass` when necessary.
     384             : //!
     385             : //! ZoneAllocator is used by AsmJit containers to make containers having only few elements fast (and lightweight)
     386             : //! and to allow them to grow and use dynamic blocks when require more storage.
     387             : class ZoneAllocator {
     388             : public:
     389             :   ASMJIT_NONCOPYABLE(ZoneAllocator)
     390             : 
     391             :   //! \cond INTERNAL
     392             : 
     393             :   // In short, we pool chunks of these sizes:
     394             :   //   [32, 64, 96, 128, 192, 256, 320, 384, 448, 512]
     395             : 
     396             :   enum : uint32_t {
     397             :     //! How many bytes per a low granularity pool (has to be at least 16).
     398             :     kLoGranularity = 32,
     399             :     //! Number of slots of a low granularity pool.
     400             :     kLoCount = 4,
     401             :     //! Maximum size of a block that can be allocated in a low granularity pool.
     402             :     kLoMaxSize = kLoGranularity * kLoCount,
     403             : 
     404             :     //! How many bytes per a high granularity pool.
     405             :     kHiGranularity = 64,
     406             :     //! Number of slots of a high granularity pool.
     407             :     kHiCount = 6,
     408             :     //! Maximum size of a block that can be allocated in a high granularity pool.
     409             :     kHiMaxSize = kLoMaxSize + kHiGranularity * kHiCount,
     410             : 
     411             :     //! Alignment of every pointer returned by `alloc()`.
     412             :     kBlockAlignment = kLoGranularity
     413             :   };
     414             : 
     415             :   //! Single-linked list used to store unused chunks.
     416             :   struct Slot {
     417             :     //! Link to a next slot in a single-linked list.
     418             :     Slot* next;
     419             :   };
     420             : 
     421             :   //! A block of memory that has been allocated dynamically and is not part of block-list used by the allocator.
     422             :   //! This is used to keep track of all these blocks so they can be freed by `reset()` if not freed explicitly.
     423             :   struct DynamicBlock {
     424             :     DynamicBlock* prev;
     425             :     DynamicBlock* next;
     426             :   };
     427             : 
     428             :   //! \endcond
     429             : 
     430             :   //! \name Members
     431             :   //! \{
     432             : 
     433             :   //! Zone used to allocate memory that fits into slots.
     434             :   Zone* _zone;
     435             :   //! Indexed slots containing released memory.
     436             :   Slot* _slots[kLoCount + kHiCount];
     437             :   //! Dynamic blocks for larger allocations (no slots).
     438             :   DynamicBlock* _dynamicBlocks;
     439             : 
     440             :   //! \}
     441             : 
     442             :   //! \name Construction & Destruction
     443             :   //! \{
     444             : 
     445             :   //! Creates a new `ZoneAllocator`.
     446             :   //!
     447             :   //! \note To use it, you must first `init()` it.
     448       27492 :   inline ZoneAllocator() noexcept {
     449             :     memset(this, 0, sizeof(*this));
     450       27492 :   }
     451             : 
     452             :   //! Creates a new `ZoneAllocator` initialized to use `zone`.
     453       54984 :   inline explicit ZoneAllocator(Zone* zone) noexcept {
     454             :     memset(this, 0, sizeof(*this));
     455       54984 :     _zone = zone;
     456       54984 :   }
     457             : 
     458             :   //! Destroys the `ZoneAllocator`.
     459       82476 :   inline ~ZoneAllocator() noexcept { reset(); }
     460             : 
     461             :   //! Tests whether the `ZoneAllocator` is initialized (i.e. has `Zone`).
     462             :   inline bool isInitialized() const noexcept { return _zone != nullptr; }
     463             : 
     464             :   //! Convenience function to initialize the `ZoneAllocator` with `zone`.
     465             :   //!
     466             :   //! It's the same as calling `reset(zone)`.
     467             :   inline void init(Zone* zone) noexcept { reset(zone); }
     468             : 
     469             :   //! Resets this `ZoneAllocator` and also forget about the current `Zone` which is attached (if any). Reset
     470             :   //! optionally attaches a new `zone` passed, or keeps the `ZoneAllocator` in an uninitialized state, if
     471             :   //! `zone` is null.
     472             :   ASMJIT_API void reset(Zone* zone = nullptr) noexcept;
     473             : 
     474             :   //! \}
     475             : 
     476             :   //! \name Accessors
     477             :   //! \{
     478             : 
     479             :   //! Returns the assigned `Zone` of this allocator or null if this `ZoneAllocator` is not initialized.
     480      850550 :   inline Zone* zone() const noexcept { return _zone; }
     481             : 
     482             :   //! \}
     483             : 
     484             :   //! \cond
     485             :   //! \name Internals
     486             :   //! \{
     487             : 
     488             :   //! Returns the slot index to be used for `size`. Returns `true` if a valid slot has been written to `slot` and
     489             :   //! `allocatedSize` has been filled with slot exact size (`allocatedSize` can be equal or slightly greater than
     490             :   //! `size`).
     491             :   static inline bool _getSlotIndex(size_t size, uint32_t& slot) noexcept {
     492             :     ASMJIT_ASSERT(size > 0);
     493      311167 :     if (size > kHiMaxSize)
     494             :       return false;
     495             : 
     496      297148 :     if (size <= kLoMaxSize)
     497      289711 :       slot = uint32_t((size - 1) / kLoGranularity);
     498             :     else
     499        7437 :       slot = uint32_t((size - kLoMaxSize - 1) / kHiGranularity) + kLoCount;
     500             : 
     501             :     return true;
     502             :   }
     503             : 
     504             :   //! \overload
     505     2796496 :   static inline bool _getSlotIndex(size_t size, uint32_t& slot, size_t& allocatedSize) noexcept {
     506             :     ASMJIT_ASSERT(size > 0);
     507     2796496 :     if (size > kHiMaxSize)
     508             :       return false;
     509             : 
     510     2738298 :     if (size <= kLoMaxSize) {
     511     2608528 :       slot = uint32_t((size - 1) / kLoGranularity);
     512     2608528 :       allocatedSize = Support::alignUp(size, kLoGranularity);
     513             :     }
     514             :     else {
     515      129770 :       slot = uint32_t((size - kLoMaxSize - 1) / kHiGranularity) + kLoCount;
     516      129770 :       allocatedSize = Support::alignUp(size, kHiGranularity);
     517             :     }
     518             : 
     519             :     return true;
     520             :   }
     521             : 
     522             :   //! \}
     523             :   //! \endcond
     524             : 
     525             :   //! \name Allocation
     526             :   //! \{
     527             : 
     528             :   //! \cond INTERNAL
     529             :   ASMJIT_API void* _alloc(size_t size, size_t& allocatedSize) noexcept;
     530             :   ASMJIT_API void* _allocZeroed(size_t size, size_t& allocatedSize) noexcept;
     531             :   ASMJIT_API void _releaseDynamic(void* p, size_t size) noexcept;
     532             :   //! \endcond
     533             : 
     534             :   //! Allocates `size` bytes of memory, ideally from an available pool.
     535             :   //!
     536             :   //! \note `size` can't be zero, it will assert in debug mode in such case.
     537             :   inline void* alloc(size_t size) noexcept {
     538             :     ASMJIT_ASSERT(isInitialized());
     539             :     size_t allocatedSize;
     540      587759 :     return _alloc(size, allocatedSize);
     541             :   }
     542             : 
     543             :   //! Like `alloc(size)`, but provides a second argument `allocatedSize` that provides a way to know how big
     544             :   //! the block returned actually is. This is useful for containers to prevent growing too early.
     545             :   inline void* alloc(size_t size, size_t& allocatedSize) noexcept {
     546             :     ASMJIT_ASSERT(isInitialized());
     547     1979162 :     return _alloc(size, allocatedSize);
     548             :   }
     549             : 
     550             :   //! Like `alloc()`, but the return pointer is casted to `T*`.
     551             :   template<typename T>
     552             :   inline T* allocT(size_t size = sizeof(T)) noexcept {
     553             :     return static_cast<T*>(alloc(size));
     554             :   }
     555             : 
     556             :   //! Like `alloc(size)`, but returns zeroed memory.
     557             :   inline void* allocZeroed(size_t size) noexcept {
     558             :     ASMJIT_ASSERT(isInitialized());
     559             :     size_t allocatedSize;
     560       82476 :     return _allocZeroed(size, allocatedSize);
     561             :   }
     562             : 
     563             :   //! Like `alloc(size, allocatedSize)`, but returns zeroed memory.
     564             :   inline void* allocZeroed(size_t size, size_t& allocatedSize) noexcept {
     565             :     ASMJIT_ASSERT(isInitialized());
     566             :     return _allocZeroed(size, allocatedSize);
     567             :   }
     568             : 
     569             :   //! Like `allocZeroed()`, but the return pointer is casted to `T*`.
     570             :   template<typename T>
     571             :   inline T* allocZeroedT(size_t size = sizeof(T)) noexcept {
     572             :     return static_cast<T*>(allocZeroed(size));
     573             :   }
     574             : 
     575             :   //! Like `new(std::nothrow) T(...)`, but allocated by `Zone`.
     576             :   template<typename T>
     577             :   inline T* newT() noexcept {
     578             :     void* p = allocT<T>();
     579             :     if (ASMJIT_UNLIKELY(!p))
     580             :       return nullptr;
     581             :     return new(p) T();
     582             :   }
     583             :   //! Like `new(std::nothrow) T(...)`, but allocated by `Zone`.
     584             :   template<typename T, typename... Args>
     585      147099 :   inline T* newT(Args&&... args) noexcept {
     586             :     void* p = allocT<T>();
     587      147099 :     if (ASMJIT_UNLIKELY(!p))
     588             :       return nullptr;
     589      147099 :     return new(p) T(std::forward<Args>(args)...);
     590             :   }
     591             : 
     592             :   //! Releases the memory previously allocated by `alloc()`. The `size` argument has to be the same as used to call
     593             :   //! `alloc()` or `allocatedSize` returned  by `alloc()`.
     594      311167 :   inline void release(void* p, size_t size) noexcept {
     595             :     ASMJIT_ASSERT(isInitialized());
     596             :     ASMJIT_ASSERT(p != nullptr);
     597             :     ASMJIT_ASSERT(size != 0);
     598             : 
     599             :     uint32_t slot;
     600             :     if (_getSlotIndex(size, slot)) {
     601      352132 :       static_cast<Slot*>(p)->next = static_cast<Slot*>(_slots[slot]);
     602      352132 :       _slots[slot] = static_cast<Slot*>(p);
     603             :     }
     604             :     else {
     605       14019 :       _releaseDynamic(p, size);
     606             :     }
     607      311167 :   }
     608             : 
     609             :   //! \}
     610             : };
     611             : 
     612             : //! \}
     613             : 
     614             : ASMJIT_END_NAMESPACE
     615             : 
     616             : #endif // ASMJIT_CORE_ZONE_H_INCLUDED
     617             : 
     618             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16