LCOV - code coverage report
Current view: top level - asmjit - zone.h (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 73 93 78.5 %
Date: 2024-10-11 08:09:49 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             : Copyright (c) 2008-2017, Petr Kobalicek
       3             : 
       4             : This software is provided 'as-is', without any express or implied
       5             : warranty. In no event will the authors be held liable for any damages
       6             : arising from the use of this software.
       7             : 
       8             : Permission is granted to anyone to use this software for any purpose,
       9             : including commercial applications, and to alter it and redistribute it
      10             : freely, subject to the following restrictions:
      11             : 
      12             : 1. The origin of this software must not be misrepresented; you must not
      13             :    claim that you wrote the original software. If you use this software
      14             :    in a product, an acknowledgment in the product documentation would be
      15             :    appreciated but is not required.
      16             : 2. Altered source versions must be plainly marked as such, and must not be
      17             :    misrepresented as being the original software.
      18             : 3. This notice may not be removed or altered from any source distribution.
      19             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      20             : #ifndef __PLUMED_asmjit_zone_h
      21             : #define __PLUMED_asmjit_zone_h
      22             : #ifdef __PLUMED_HAS_ASMJIT
      23             : #pragma GCC diagnostic push
      24             : #pragma GCC diagnostic ignored "-Wpedantic"
      25             : // [AsmJit]
      26             : // Complete x86/x64 JIT and Remote Assembler for C++.
      27             : //
      28             : // [License]
      29             : // Zlib - See LICENSE.md file in the package.
      30             : 
      31             : // [Guard]
      32             : #ifndef _ASMJIT_BASE_ZONE_H
      33             : #define _ASMJIT_BASE_ZONE_H
      34             : 
      35             : // [Dependencies]
      36             : #include "./utils.h"
      37             : 
      38             : // [Api-Begin]
      39             : #include "./asmjit_apibegin.h"
      40             : 
      41             : namespace PLMD {
      42             : namespace asmjit {
      43             : 
      44             : //! \addtogroup asmjit_base
      45             : //! \{
      46             : 
      47             : // ============================================================================
      48             : // [asmjit::Zone]
      49             : // ============================================================================
      50             : 
      51             : //! Memory zone.
      52             : //!
      53             : //! Zone is an incremental memory allocator that allocates memory by simply
      54             : //! incrementing a pointer. It allocates blocks of memory by using standard
      55             : //! C `malloc`, but divides these blocks into smaller segments requested by
      56             : //! calling `Zone::alloc()` and friends.
      57             : //!
      58             : //! Zone has no function to release the allocated memory. It has to be released
      59             : //! all at once by calling `reset()`. If you need a more friendly allocator that
      60             : //! also supports `release()`, consider using \ref Zone with \ref ZoneHeap.
      61             : class Zone {
      62             : public:
      63             :   //! \internal
      64             :   //!
      65             :   //! A single block of memory.
      66             :   struct Block {
      67             :     Block* prev;                         //!< Link to the previous block.
      68             :     Block* next;                         //!< Link to the next block.
      69             :     size_t size;                         //!< Size of the block.
      70             :     uint8_t data[sizeof(void*)];         //!< Data.
      71             :   };
      72             : 
      73             :   enum {
      74             :     //! Zone allocator overhead.
      75             :     kZoneOverhead = Globals::kAllocOverhead + static_cast<int>(sizeof(Block))
      76             :   };
      77             : 
      78             :   // --------------------------------------------------------------------------
      79             :   // [Construction / Destruction]
      80             :   // --------------------------------------------------------------------------
      81             : 
      82             :   //! Create a new instance of `Zone` allocator.
      83             :   //!
      84             :   //! The `blockSize` parameter describes the default size of the block. If the
      85             :   //! `size` parameter passed to `alloc()` is greater than the default size
      86             :   //! `Zone` will allocate and use a larger block, but it will not change the
      87             :   //! default `blockSize`.
      88             :   //!
      89             :   //! It's not required, but it's good practice to set `blockSize` to a
      90             :   //! reasonable value that depends on the usage of `Zone`. Greater block sizes
      91             :   //! are generally safer and perform better than unreasonably low values.
      92             :   ASMJIT_API Zone(uint32_t blockSize, uint32_t blockAlignment = 0) noexcept;
      93             : 
      94             :   //! Destroy the `Zone` instance.
      95             :   //!
      96             :   //! This will destroy the `Zone` instance and release all blocks of memory
      97             :   //! allocated by it. It performs implicit `reset(true)`.
      98             :   ASMJIT_API ~Zone() noexcept;
      99             : 
     100             :   // --------------------------------------------------------------------------
     101             :   // [Reset]
     102             :   // --------------------------------------------------------------------------
     103             : 
     104             :   //! Reset the `Zone` invalidating all blocks allocated.
     105             :   //!
     106             :   //! If `releaseMemory` is true all buffers will be released to the system.
     107             :   ASMJIT_API void reset(bool releaseMemory = false) noexcept;
     108             : 
     109             :   // --------------------------------------------------------------------------
     110             :   // [Accessors]
     111             :   // --------------------------------------------------------------------------
     112             : 
     113             :   //! Get the default block size.
     114             :   ASMJIT_INLINE uint32_t getBlockSize() const noexcept { return _blockSize; }
     115             :   //! Get the default block alignment.
     116        7780 :   ASMJIT_INLINE uint32_t getBlockAlignment() const noexcept { return (uint32_t)1 << _blockAlignmentShift; }
     117             :   //! Get remaining size of the current block.
     118             :   ASMJIT_INLINE size_t getRemainingSize() const noexcept { return (size_t)(_end - _ptr); }
     119             : 
     120             :   //! Get the current zone cursor (dangerous).
     121             :   //!
     122             :   //! This is a function that can be used to get exclusive access to the current
     123             :   //! block's memory buffer.
     124       78122 :   ASMJIT_INLINE uint8_t* getCursor() noexcept { return _ptr; }
     125             :   //! Get the end of the current zone block, only useful if you use `getCursor()`.
     126       78122 :   ASMJIT_INLINE uint8_t* getEnd() noexcept { return _end; }
     127             : 
     128             :   //! Set the current zone cursor to `p` (must match the current block).
     129             :   //!
     130             :   //! This is a counterpart of `getZoneCursor()`.
     131             :   ASMJIT_INLINE void setCursor(uint8_t* p) noexcept {
     132             :     ASMJIT_ASSERT(p >= _ptr && p <= _end);
     133       74234 :     _ptr = p;
     134           0 :   }
     135             : 
     136             :   // --------------------------------------------------------------------------
     137             :   // [Alloc]
     138             :   // --------------------------------------------------------------------------
     139             : 
     140             :   //! Allocate `size` bytes of memory.
     141             :   //!
     142             :   //! Pointer returned is valid until the `Zone` instance is destroyed or reset
     143             :   //! by calling `reset()`. If you plan to make an instance of C++ from the
     144             :   //! given pointer use placement `new` and `delete` operators:
     145             :   //!
     146             :   //! ~~~
     147             :   //! using namespace asmjit;
     148             :   //!
     149             :   //! class Object { ... };
     150             :   //!
     151             :   //! // Create Zone with default block size of approximately 65536 bytes.
     152             :   //! Zone zone(65536 - Zone::kZoneOverhead);
     153             :   //!
     154             :   //! // Create your objects using zone object allocating, for example:
     155             :   //! Object* obj = static_cast<Object*>( zone.alloc(sizeof(Object)) );
     156             :   //
     157             :   //! if (!obj) {
     158             :   //!   // Handle out of memory error.
     159             :   //! }
     160             :   //!
     161             :   //! // Placement `new` and `delete` operators can be used to instantiate it.
     162             :   //! new(obj) Object();
     163             :   //!
     164             :   //! // ... lifetime of your objects ...
     165             :   //!
     166             :   //! // To destroy the instance (if required).
     167             :   //! obj->~Object();
     168             :   //!
     169             :   //! // Reset or destroy `Zone`.
     170             :   //! zone.reset();
     171             :   //! ~~~
     172             :   ASMJIT_INLINE void* alloc(size_t size) noexcept {
     173      114612 :     uint8_t* ptr = _ptr;
     174      114612 :     size_t remainingBytes = (size_t)(_end - ptr);
     175             : 
     176      114612 :     if (ASMJIT_UNLIKELY(remainingBytes < size))
     177        3892 :       return _alloc(size);
     178             : 
     179      110720 :     _ptr += size;
     180             :     ASMJIT_ASSERT(_ptr <= _end);
     181             : 
     182      110720 :     return static_cast<void*>(ptr);
     183             :   }
     184             : 
     185             :   //! Allocate `size` bytes without any checks.
     186             :   //!
     187             :   //! Can only be called if `getRemainingSize()` returns size at least equal
     188             :   //! to `size`.
     189             :   ASMJIT_INLINE void* allocNoCheck(size_t size) noexcept {
     190             :     ASMJIT_ASSERT((size_t)(_end - _ptr) >= size);
     191             : 
     192             :     uint8_t* ptr = _ptr;
     193             :     _ptr += size;
     194             :     return static_cast<void*>(ptr);
     195             :   }
     196             : 
     197             :   //! Allocate `size` bytes of zeroed memory.
     198             :   //!
     199             :   //! See \ref alloc() for more details.
     200             :   ASMJIT_API void* allocZeroed(size_t size) noexcept;
     201             : 
     202             :   //! Like `alloc()`, but the return pointer is casted to `T*`.
     203             :   template<typename T>
     204             :   ASMJIT_INLINE T* allocT(size_t size = sizeof(T)) noexcept {
     205             :     return static_cast<T*>(alloc(size));
     206             :   }
     207             : 
     208             :   //! Like `allocNoCheck()`, but the return pointer is casted to `T*`.
     209             :   template<typename T>
     210             :   ASMJIT_INLINE T* allocNoCheckT(size_t size = sizeof(T)) noexcept {
     211             :     return static_cast<T*>(allocNoCheck(size));
     212             :   }
     213             : 
     214             :   //! Like `allocZeroed()`, but the return pointer is casted to `T*`.
     215             :   template<typename T>
     216             :   ASMJIT_INLINE T* allocZeroedT(size_t size = sizeof(T)) noexcept {
     217       25684 :     return static_cast<T*>(allocZeroed(size));
     218             :   }
     219             : 
     220             :   //! Like `new(std::nothrow) T(...)`, but allocated by `Zone`.
     221             :   template<typename T>
     222             :   ASMJIT_INLINE T* newT() noexcept {
     223             :     void* p = alloc(sizeof(T));
     224             :     if (ASMJIT_UNLIKELY(!p))
     225             :       return nullptr;
     226             :     return new(p) T();
     227             :   }
     228             :   //! Like `new(std::nothrow) T(...)`, but allocated by `Zone`.
     229             :   template<typename T, typename P1>
     230             :   ASMJIT_INLINE T* newT(P1 p1) noexcept {
     231             :     void* p = alloc(sizeof(T));
     232             :     if (ASMJIT_UNLIKELY(!p))
     233             :       return nullptr;
     234             :     return new(p) T(p1);
     235             :   }
     236             : 
     237             :   //! \internal
     238             :   ASMJIT_API void* _alloc(size_t size) noexcept;
     239             : 
     240             :   //! Helper to duplicate data.
     241             :   ASMJIT_API void* dup(const void* data, size_t size, bool nullTerminate = false) noexcept;
     242             : 
     243             :   //! Helper to duplicate formatted string, maximum length is 256 bytes.
     244             :   ASMJIT_API char* sformat(const char* str, ...) noexcept;
     245             : 
     246             :   // --------------------------------------------------------------------------
     247             :   // [Members]
     248             :   // --------------------------------------------------------------------------
     249             : 
     250             :   uint8_t* _ptr;                         //!< Pointer in the current block's buffer.
     251             :   uint8_t* _end;                         //!< End of the current block's buffer.
     252             :   Block* _block;                         //!< Current block.
     253             : 
     254             : #if ASMJIT_ARCH_64BIT
     255             :   uint32_t _blockSize;                   //!< Default size of a newly allocated block.
     256             :   uint32_t _blockAlignmentShift;         //!< Minimum alignment of each block.
     257             : #else
     258             :   uint32_t _blockSize : 29;              //!< Default size of a newly allocated block.
     259             :   uint32_t _blockAlignmentShift : 3;     //!< Minimum alignment of each block.
     260             : #endif
     261             : };
     262             : 
     263             : // ============================================================================
     264             : // [asmjit::ZoneHeap]
     265             : // ============================================================================
     266             : 
     267             : //! Zone-based memory allocator that uses an existing \ref Zone and provides
     268             : //! a `release()` functionality on top of it. It uses \ref Zone only for chunks
     269             : //! that can be pooled, and uses libc `malloc()` for chunks that are large.
     270             : //!
     271             : //! The advantage of ZoneHeap is that it can allocate small chunks of memory
     272             : //! really fast, and these chunks, when released, will be reused by consecutive
     273             : //! calls to `alloc()`. Also, since ZoneHeap uses \ref Zone, you can turn any
     274             : //! \ref Zone into a \ref ZoneHeap, and use it in your \ref Pass when necessary.
     275             : //!
     276             : //! ZoneHeap is used by AsmJit containers to make containers having only
     277             : //! few elements fast (and lightweight) and to allow them to grow and use
     278             : //! dynamic blocks when require more storage.
     279             : class ZoneHeap {
     280             :   ASMJIT_NONCOPYABLE(ZoneHeap)
     281             : 
     282             :   enum {
     283             :     // In short, we pool chunks of these sizes:
     284             :     //   [32, 64, 96, 128, 192, 256, 320, 384, 448, 512]
     285             : 
     286             :     //! How many bytes per a low granularity pool (has to be at least 16).
     287             :     kLoGranularity = 32,
     288             :     //! Number of slots of a low granularity pool.
     289             :     kLoCount = 4,
     290             :     //! Maximum size of a block that can be allocated in a low granularity pool.
     291             :     kLoMaxSize = kLoGranularity * kLoCount,
     292             : 
     293             :     //! How many bytes per a high granularity pool.
     294             :     kHiGranularity = 64,
     295             :     //! Number of slots of a high granularity pool.
     296             :     kHiCount = 6,
     297             :     //! Maximum size of a block that can be allocated in a high granularity pool.
     298             :     kHiMaxSize = kLoMaxSize + kHiGranularity * kHiCount,
     299             : 
     300             :     //! Alignment of every pointer returned by `alloc()`.
     301             :     kBlockAlignment = kLoGranularity
     302             :   };
     303             : 
     304             :   //! Single-linked list used to store unused chunks.
     305             :   struct Slot {
     306             :     //! Link to a next slot in a single-linked list.
     307             :     Slot* next;
     308             :   };
     309             : 
     310             :   //! A block of memory that has been allocated dynamically and is not part of
     311             :   //! block-list used by the allocator. This is used to keep track of all these
     312             :   //! blocks so they can be freed by `reset()` if not freed explicitly.
     313             :   struct DynamicBlock {
     314             :     DynamicBlock* prev;
     315             :     DynamicBlock* next;
     316             :   };
     317             : 
     318             :   // --------------------------------------------------------------------------
     319             :   // [Construction / Destruction]
     320             :   // --------------------------------------------------------------------------
     321             : 
     322             :   //! Create a new `ZoneHeap`.
     323             :   //!
     324             :   //! NOTE: To use it, you must first `init()` it.
     325        1944 :   ASMJIT_INLINE ZoneHeap() noexcept {
     326             :     ::memset(this, 0, sizeof(*this));
     327             :   }
     328             :   //! Create a new `ZoneHeap` initialized to use `zone`.
     329        3888 :   explicit ASMJIT_INLINE ZoneHeap(Zone* zone) noexcept {
     330             :     ::memset(this, 0, sizeof(*this));
     331        3888 :     _zone = zone;
     332             :   }
     333             :   //! Destroy the `ZoneHeap`.
     334        3888 :   ASMJIT_INLINE ~ZoneHeap() noexcept { reset(); }
     335             : 
     336             :   // --------------------------------------------------------------------------
     337             :   // [Init / Reset]
     338             :   // --------------------------------------------------------------------------
     339             : 
     340             :   //! Get if the `ZoneHeap` is initialized (i.e. has `Zone`).
     341             :   ASMJIT_INLINE bool isInitialized() const noexcept { return _zone != nullptr; }
     342             : 
     343             :   //! Convenience method to initialize the `ZoneHeap` with `zone`.
     344             :   //!
     345             :   //! It's the same as calling `reset(zone)`.
     346             :   ASMJIT_INLINE void init(Zone* zone) noexcept { reset(zone); }
     347             : 
     348             :   //! Reset this `ZoneHeap` and also forget about the current `Zone` which
     349             :   //! is attached (if any). Reset optionally attaches a new `zone` passed, or
     350             :   //! keeps the `ZoneHeap` in an uninitialized state, if `zone` is null.
     351             :   ASMJIT_API void reset(Zone* zone = nullptr) noexcept;
     352             : 
     353             :   // --------------------------------------------------------------------------
     354             :   // [Accessors]
     355             :   // --------------------------------------------------------------------------
     356             : 
     357             :   //! Get the `Zone` the `ZoneHeap` is using, or null if it's not initialized.
     358             :   ASMJIT_INLINE Zone* getZone() const noexcept { return _zone; }
     359             : 
     360             :   // --------------------------------------------------------------------------
     361             :   // [Utilities]
     362             :   // --------------------------------------------------------------------------
     363             : 
     364             :   //! \internal
     365             :   //!
     366             :   //! Get the slot index to be used for `size`. Returns `true` if a valid slot
     367             :   //! has been written to `slot` and `allocatedSize` has been filled with slot
     368             :   //! exact size (`allocatedSize` can be equal or slightly greater than `size`).
     369             :   static ASMJIT_INLINE bool _getSlotIndex(size_t size, uint32_t& slot) noexcept {
     370             :     ASMJIT_ASSERT(size > 0);
     371        6588 :     if (size > kHiMaxSize)
     372             :       return false;
     373             : 
     374        6588 :     if (size <= kLoMaxSize)
     375        6580 :       slot = static_cast<uint32_t>((size - 1) / kLoGranularity);
     376             :     else
     377           8 :       slot = static_cast<uint32_t>((size - kLoMaxSize - 1) / kHiGranularity) + kLoCount;
     378             : 
     379             :     return true;
     380             :   }
     381             : 
     382             :   //! \overload
     383             :   static ASMJIT_INLINE bool _getSlotIndex(size_t size, uint32_t& slot, size_t& allocatedSize) noexcept {
     384             :     ASMJIT_ASSERT(size > 0);
     385       79806 :     if (size > kHiMaxSize)
     386             :       return false;
     387             : 
     388       79798 :     if (size <= kLoMaxSize) {
     389       74994 :       slot = static_cast<uint32_t>((size - 1) / kLoGranularity);
     390       74994 :       allocatedSize = Utils::alignTo(size, kLoGranularity);
     391             :     }
     392             :     else {
     393        4804 :       slot = static_cast<uint32_t>((size - kLoMaxSize - 1) / kHiGranularity) + kLoCount;
     394        4804 :       allocatedSize = Utils::alignTo(size, kHiGranularity);
     395             :     }
     396             : 
     397             :     return true;
     398             :   }
     399             : 
     400             :   // --------------------------------------------------------------------------
     401             :   // [Alloc / Release]
     402             :   // --------------------------------------------------------------------------
     403             : 
     404             :   ASMJIT_API void* _alloc(size_t size, size_t& allocatedSize) noexcept;
     405             :   ASMJIT_API void* _allocZeroed(size_t size, size_t& allocatedSize) noexcept;
     406             :   ASMJIT_API void _releaseDynamic(void* p, size_t size) noexcept;
     407             : 
     408             :   //! Allocate `size` bytes of memory, ideally from an available pool.
     409             :   //!
     410             :   //! NOTE: `size` can't be zero, it will assert in debug mode in such case.
     411             :   ASMJIT_INLINE void* alloc(size_t size) noexcept {
     412             :     ASMJIT_ASSERT(isInitialized());
     413             :     size_t allocatedSize;
     414       57666 :     return _alloc(size, allocatedSize);
     415             :   }
     416             : 
     417             :   //! Like `alloc(size)`, but provides a second argument `allocatedSize` that
     418             :   //! provides a way to know how big the block returned actually is. This is
     419             :   //! useful for containers to prevent growing too early.
     420             :   ASMJIT_INLINE void* alloc(size_t size, size_t& allocatedSize) noexcept {
     421             :     ASMJIT_ASSERT(isInitialized());
     422       18252 :     return _alloc(size, allocatedSize);
     423             :   }
     424             : 
     425             :   //! Like `alloc()`, but the return pointer is casted to `T*`.
     426             :   template<typename T>
     427             :   ASMJIT_INLINE T* allocT(size_t size = sizeof(T)) noexcept {
     428             :     return static_cast<T*>(alloc(size));
     429             :   }
     430             : 
     431             :   //! Like `alloc(size)`, but returns zeroed memory.
     432             :   ASMJIT_INLINE void* allocZeroed(size_t size) noexcept {
     433             :     ASMJIT_ASSERT(isInitialized());
     434             : 
     435             :     size_t allocatedSize;
     436        3888 :     return _allocZeroed(size, allocatedSize);
     437             :   }
     438             : 
     439             :   //! Like `alloc(size, allocatedSize)`, but returns zeroed memory.
     440             :   ASMJIT_INLINE void* allocZeroed(size_t size, size_t& allocatedSize) noexcept {
     441             :     ASMJIT_ASSERT(isInitialized());
     442             : 
     443             :     return _allocZeroed(size, allocatedSize);
     444             :   }
     445             : 
     446             :   //! Like `allocZeroed()`, but the return pointer is casted to `T*`.
     447             :   template<typename T>
     448             :   ASMJIT_INLINE T* allocZeroedT(size_t size = sizeof(T)) noexcept {
     449             :     return static_cast<T*>(allocZeroed(size));
     450             :   }
     451             : 
     452             :   //! Release the memory previously allocated by `alloc()`. The `size` argument
     453             :   //! has to be the same as used to call `alloc()` or `allocatedSize` returned
     454             :   //! by `alloc()`.
     455             :   ASMJIT_INLINE void release(void* p, size_t size) noexcept {
     456             :     ASMJIT_ASSERT(isInitialized());
     457             : 
     458             :     ASMJIT_ASSERT(p != nullptr);
     459             :     ASMJIT_ASSERT(size != 0);
     460             : 
     461             :     uint32_t slot;
     462             :     if (_getSlotIndex(size, slot)) {
     463             :       //printf("RELEASING %p of size %d (SLOT %u)\n", p, int(size), slot);
     464        6588 :       static_cast<Slot*>(p)->next = static_cast<Slot*>(_slots[slot]);
     465        6588 :       _slots[slot] = static_cast<Slot*>(p);
     466             :     }
     467             :     else {
     468           0 :       _releaseDynamic(p, size);
     469             :     }
     470             :   }
     471             : 
     472             :   // --------------------------------------------------------------------------
     473             :   // [Members]
     474             :   // --------------------------------------------------------------------------
     475             : 
     476             :   Zone* _zone;                           //!< Zone used to allocate memory that fits into slots.
     477             :   Slot* _slots[kLoCount + kHiCount];     //!< Indexed slots containing released memory.
     478             :   DynamicBlock* _dynamicBlocks;          //!< Dynamic blocks for larger allocations (no slots).
     479             : };
     480             : 
     481             : // ============================================================================
     482             : // [asmjit::ZoneList<T>]
     483             : // ============================================================================
     484             : 
     485             : //! \internal
     486             : template <typename T>
     487             : class ZoneList {
     488             : public:
     489             :   ASMJIT_NONCOPYABLE(ZoneList<T>)
     490             : 
     491             :   // --------------------------------------------------------------------------
     492             :   // [Link]
     493             :   // --------------------------------------------------------------------------
     494             : 
     495             :   //! ZoneList node.
     496             :   struct Link {
     497             :     //! Get next node.
     498        3888 :     ASMJIT_INLINE Link* getNext() const noexcept { return _next; }
     499             :     //! Get value.
     500        1944 :     ASMJIT_INLINE T getValue() const noexcept { return _value; }
     501             :     //! Set value to `value`.
     502        3888 :     ASMJIT_INLINE void setValue(const T& value) noexcept { _value = value; }
     503             : 
     504             :     Link* _next;
     505             :     T _value;
     506             :   };
     507             : 
     508             :   // --------------------------------------------------------------------------
     509             :   // [Appender]
     510             :   // --------------------------------------------------------------------------
     511             : 
     512             :   //! Specialized appender that takes advantage of ZoneList structure. You must
     513             :   //! initialize it and then call done().
     514             :   struct Appender {
     515             :     ASMJIT_INLINE Appender(ZoneList<T>& list) noexcept { init(list); }
     516             : 
     517             :     ASMJIT_INLINE void init(ZoneList<T>& list) noexcept {
     518             :       pPrev = &list._first;
     519             :     }
     520             : 
     521             :     ASMJIT_INLINE void done(ZoneList<T>& list) noexcept {
     522             :       list._last = *pPrev;
     523             :       *pPrev = nullptr;
     524             :     }
     525             : 
     526             :     ASMJIT_INLINE void append(Link* node) noexcept {
     527             :       *pPrev = node;
     528             :       pPrev = &node->_next;
     529             :     }
     530             : 
     531             :     Link** pPrev;
     532             :   };
     533             : 
     534             :   // --------------------------------------------------------------------------
     535             :   // [Construction / Destruction]
     536             :   // --------------------------------------------------------------------------
     537             : 
     538        1944 :   ASMJIT_INLINE ZoneList() noexcept : _first(nullptr), _last(nullptr) {}
     539           0 :   ASMJIT_INLINE ~ZoneList() noexcept {}
     540             : 
     541             :   // --------------------------------------------------------------------------
     542             :   // [Data]
     543             :   // --------------------------------------------------------------------------
     544             : 
     545             :   ASMJIT_INLINE bool isEmpty() const noexcept { return _first != nullptr; }
     546        7776 :   ASMJIT_INLINE Link* getFirst() const noexcept { return _first; }
     547             :   ASMJIT_INLINE Link* getLast() const noexcept { return _last; }
     548             : 
     549             :   // --------------------------------------------------------------------------
     550             :   // [Ops]
     551             :   // --------------------------------------------------------------------------
     552             : 
     553             :   ASMJIT_INLINE void reset() noexcept {
     554        1944 :     _first = nullptr;
     555        1944 :     _last = nullptr;
     556             :   }
     557             : 
     558             :   ASMJIT_INLINE void prepend(Link* link) noexcept {
     559             :     link->_next = _first;
     560             :     if (!_first) _last = link;
     561             :     _first = link;
     562             :   }
     563             : 
     564             :   ASMJIT_INLINE void append(Link* link) noexcept {
     565        3888 :     link->_next = nullptr;
     566        3888 :     if (!_first)
     567        3888 :       _first = link;
     568             :     else
     569           0 :       _last->_next = link;
     570        3888 :     _last = link;
     571             :   }
     572             : 
     573             :   // --------------------------------------------------------------------------
     574             :   // [Members]
     575             :   // --------------------------------------------------------------------------
     576             : 
     577             :   Link* _first;
     578             :   Link* _last;
     579             : };
     580             : 
     581             : // ============================================================================
     582             : // [asmjit::ZoneVectorBase]
     583             : // ============================================================================
     584             : 
     585             : //! \internal
     586             : class ZoneVectorBase {
     587             : public:
     588             :   ASMJIT_NONCOPYABLE(ZoneVectorBase)
     589             : 
     590             : protected:
     591             :   // --------------------------------------------------------------------------
     592             :   // [Construction / Destruction]
     593             :   // --------------------------------------------------------------------------
     594             : 
     595             :   //! Create a new instance of `ZoneVectorBase`.
     596             :   explicit ASMJIT_INLINE ZoneVectorBase() noexcept
     597        7776 :     : _data(nullptr),
     598        7776 :       _length(0),
     599        7776 :       _capacity(0) {}
     600             : 
     601             :   // --------------------------------------------------------------------------
     602             :   // [Accessors]
     603             :   // --------------------------------------------------------------------------
     604             : 
     605             : public:
     606             :   //! Get if the vector is empty.
     607             :   ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; }
     608             :   //! Get vector length.
     609       73224 :   ASMJIT_INLINE size_t getLength() const noexcept { return _length; }
     610             :   //! Get vector capacity.
     611             :   ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; }
     612             : 
     613             :   // --------------------------------------------------------------------------
     614             :   // [Ops]
     615             :   // --------------------------------------------------------------------------
     616             : 
     617             :   //! Makes the vector empty (won't change the capacity or data pointer).
     618             :   ASMJIT_INLINE void clear() noexcept { _length = 0; }
     619             :   //! Reset the vector data and set its `length` to zero.
     620             :   ASMJIT_INLINE void reset() noexcept {
     621        5832 :     _data = nullptr;
     622        5832 :     _length = 0;
     623        5832 :     _capacity = 0;
     624             :   }
     625             : 
     626             :   //! Truncate the vector to at most `n` items.
     627             :   ASMJIT_INLINE void truncate(size_t n) noexcept {
     628             :     _length = std::min(_length, n);
     629             :   }
     630             : 
     631             :   // --------------------------------------------------------------------------
     632             :   // [Memory Management]
     633             :   // --------------------------------------------------------------------------
     634             : 
     635             : protected:
     636             :   ASMJIT_INLINE void _release(ZoneHeap* heap, size_t sizeOfT) noexcept {
     637             :     if (_data != nullptr) {
     638             :       heap->release(_data, _capacity * sizeOfT);
     639             :       reset();
     640             :     }
     641             :   }
     642             : 
     643             :   ASMJIT_API Error _grow(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept;
     644             :   ASMJIT_API Error _resize(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept;
     645             :   ASMJIT_API Error _reserve(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept;
     646             : 
     647             :   // --------------------------------------------------------------------------
     648             :   // [Members]
     649             :   // --------------------------------------------------------------------------
     650             : 
     651             : public:
     652             :   void* _data;                           //!< Vector data.
     653             :   size_t _length;                        //!< Length of the vector.
     654             :   size_t _capacity;                      //!< Capacity of the vector.
     655             : };
     656             : 
     657             : // ============================================================================
     658             : // [asmjit::ZoneVector<T>]
     659             : // ============================================================================
     660             : 
     661             : //! Template used to store and manage array of Zone allocated data.
     662             : //!
     663             : //! This template has these advantages over other std::vector<>:
     664             : //! - Always non-copyable (designed to be non-copyable, we want it).
     665             : //! - No copy-on-write (some implementations of STL can use it).
     666             : //! - Optimized for working only with POD types.
     667             : //! - Uses ZoneHeap, thus small vectors are basically for free.
     668             : template <typename T>
     669             : class ZoneVector : public ZoneVectorBase {
     670             : public:
     671             :   ASMJIT_NONCOPYABLE(ZoneVector<T>)
     672             : 
     673             :   // --------------------------------------------------------------------------
     674             :   // [Construction / Destruction]
     675             :   // --------------------------------------------------------------------------
     676             : 
     677             :   //! Create a new instance of `ZoneVector<T>`.
     678             :   explicit ASMJIT_INLINE ZoneVector() noexcept : ZoneVectorBase() {}
     679             : 
     680             :   // --------------------------------------------------------------------------
     681             :   // [Accessors]
     682             :   // --------------------------------------------------------------------------
     683             : 
     684             :   //! Get data.
     685       11664 :   ASMJIT_INLINE T* getData() noexcept { return static_cast<T*>(_data); }
     686             :   //! \overload
     687      136066 :   ASMJIT_INLINE const T* getData() const noexcept { return static_cast<const T*>(_data); }
     688             : 
     689             :   // --------------------------------------------------------------------------
     690             :   // [Ops]
     691             :   // --------------------------------------------------------------------------
     692             : 
     693             :   //! Prepend `item` to the vector.
     694             :   Error prepend(ZoneHeap* heap, const T& item) noexcept {
     695             :     if (ASMJIT_UNLIKELY(_length == _capacity))
     696             :       ASMJIT_PROPAGATE(grow(heap, 1));
     697             : 
     698             :     ::memmove(static_cast<T*>(_data) + 1, _data, _length * sizeof(T));
     699             :     ::memcpy(_data, &item, sizeof(T));
     700             : 
     701             :     _length++;
     702             :     return kErrorOk;
     703             :   }
     704             : 
     705             :   //! Insert an `item` at the specified `index`.
     706             :   Error insert(ZoneHeap* heap, size_t index, const T& item) noexcept {
     707             :     ASMJIT_ASSERT(index <= _length);
     708             : 
     709             :     if (ASMJIT_UNLIKELY(_length == _capacity))
     710             :       ASMJIT_PROPAGATE(grow(heap, 1));
     711             : 
     712             :     T* dst = static_cast<T*>(_data) + index;
     713             :     ::memmove(dst + 1, dst, _length - index);
     714             :     ::memcpy(dst, &item, sizeof(T));
     715             : 
     716             :     _length++;
     717             :     return kErrorOk;
     718             :   }
     719             : 
     720             :   //! Append `item` to the vector.
     721       25684 :   Error append(ZoneHeap* heap, const T& item) noexcept {
     722       25684 :     if (ASMJIT_UNLIKELY(_length == _capacity))
     723        5238 :       ASMJIT_PROPAGATE(grow(heap, 1));
     724             : 
     725       25684 :     ::memcpy(static_cast<T*>(_data) + _length, &item, sizeof(T));
     726             : 
     727       25684 :     _length++;
     728       25684 :     return kErrorOk;
     729             :   }
     730             : 
     731             :   Error concat(ZoneHeap* heap, const ZoneVector<T>& other) noexcept {
     732             :     size_t count = other._length;
     733             :     if (_capacity - _length < count)
     734             :       ASMJIT_PROPAGATE(grow(heap, count));
     735             : 
     736             :     ::memcpy(static_cast<T*>(_data) + _length, other._data, count * sizeof(T));
     737             : 
     738             :     _length += count;
     739             :     return kErrorOk;
     740             :   }
     741             : 
     742             :   //! Prepend `item` to the vector (unsafe case).
     743             :   //!
     744             :   //! Can only be used together with `willGrow()`. If `willGrow(N)` returns
     745             :   //! `kErrorOk` then N elements can be added to the vector without checking
     746             :   //! if there is a place for them. Used mostly internally.
     747             :   ASMJIT_INLINE void prependUnsafe(const T& item) noexcept {
     748             :     ASMJIT_ASSERT(_length < _capacity);
     749             :     T* data = static_cast<T*>(_data);
     750             : 
     751             :     if (_length)
     752             :       ::memmove(data + 1, data, _length * sizeof(T));
     753             : 
     754             :     ::memcpy(data, &item, sizeof(T));
     755             :     _length++;
     756             :   }
     757             : 
     758             :   //! Append `item` to the vector (unsafe case).
     759             :   //!
     760             :   //! Can only be used together with `willGrow()`. If `willGrow(N)` returns
     761             :   //! `kErrorOk` then N elements can be added to the vector without checking
     762             :   //! if there is a place for them. Used mostly internally.
     763             :   ASMJIT_INLINE void appendUnsafe(const T& item) noexcept {
     764             :     ASMJIT_ASSERT(_length < _capacity);
     765             : 
     766       29572 :     ::memcpy(static_cast<T*>(_data) + _length, &item, sizeof(T));
     767       27628 :     _length++;
     768        1944 :   }
     769             : 
     770             :   //! Concatenate all items of `other` at the end of the vector.
     771             :   ASMJIT_INLINE void concatUnsafe(const ZoneVector<T>& other) noexcept {
     772             :     size_t count = other._length;
     773             :     ASMJIT_ASSERT(_capacity - _length >= count);
     774             : 
     775             :     ::memcpy(static_cast<T*>(_data) + _length, other._data, count * sizeof(T));
     776             :     _length += count;
     777             :   }
     778             : 
     779             :   //! Get index of `val` or `kInvalidIndex` if not found.
     780             :   ASMJIT_INLINE size_t indexOf(const T& val) const noexcept {
     781           0 :     const T* data = static_cast<const T*>(_data);
     782           0 :     size_t length = _length;
     783             : 
     784           0 :     for (size_t i = 0; i < length; i++)
     785           0 :       if (data[i] == val)
     786             :         return i;
     787             : 
     788             :     return Globals::kInvalidIndex;
     789             :   }
     790             : 
     791             :   //! Get whether the vector contains `val`.
     792             :   ASMJIT_INLINE bool contains(const T& val) const noexcept {
     793             :     return indexOf(val) != Globals::kInvalidIndex;
     794             :   }
     795             : 
     796             :   //! Remove item at index `i`.
     797             :   ASMJIT_INLINE void removeAt(size_t i) noexcept {
     798             :     ASMJIT_ASSERT(i < _length);
     799             : 
     800           0 :     T* data = static_cast<T*>(_data) + i;
     801           0 :     _length--;
     802           0 :     ::memmove(data, data + 1, _length - i);
     803           0 :   }
     804             : 
     805             :   //! Swap this pod-vector with `other`.
     806             :   ASMJIT_INLINE void swap(ZoneVector<T>& other) noexcept {
     807             :     Utils::swap(_length, other._length);
     808             :     Utils::swap(_capacity, other._capacity);
     809             :     Utils::swap(_data, other._data);
     810             :   }
     811             : 
     812             :   //! Get item at index `i` (const).
     813             :   ASMJIT_INLINE const T& getAt(size_t i) const noexcept {
     814             :     ASMJIT_ASSERT(i < _length);
     815             :     return getData()[i];
     816             :   }
     817             : 
     818             :   //! Get item at index `i`.
     819             :   ASMJIT_INLINE T& operator[](size_t i) noexcept {
     820             :     ASMJIT_ASSERT(i < _length);
     821        7776 :     return getData()[i];
     822             :   }
     823             : 
     824             :   //! Get item at index `i`.
     825             :   ASMJIT_INLINE const T& operator[](size_t i) const noexcept {
     826             :     ASMJIT_ASSERT(i < _length);
     827      132178 :     return getData()[i];
     828             :   }
     829             : 
     830             :   // --------------------------------------------------------------------------
     831             :   // [Memory Management]
     832             :   // --------------------------------------------------------------------------
     833             : 
     834             :   //! Release the memory held by `ZoneVector<T>` back to the `heap`.
     835             :   ASMJIT_INLINE void release(ZoneHeap* heap) noexcept { _release(heap, sizeof(T)); }
     836             : 
     837             :   //! Called to grow the buffer to fit at least `n` elements more.
     838       16308 :   ASMJIT_INLINE Error grow(ZoneHeap* heap, size_t n) noexcept { return ZoneVectorBase::_grow(heap, sizeof(T), n); }
     839             : 
     840             :   //! Resize the vector to hold `n` elements.
     841             :   //!
     842             :   //! If `n` is greater than the current length then the additional elements'
     843             :   //! content will be initialized to zero. If `n` is less than the current
     844             :   //! length then the vector will be truncated to exactly `n` elements.
     845        3888 :   ASMJIT_INLINE Error resize(ZoneHeap* heap, size_t n) noexcept { return ZoneVectorBase::_resize(heap, sizeof(T), n); }
     846             : 
     847             :   //! Realloc internal array to fit at least `n` items.
     848             :   ASMJIT_INLINE Error reserve(ZoneHeap* heap, size_t n) noexcept { return ZoneVectorBase::_reserve(heap, sizeof(T), n); }
     849             : 
     850             :   ASMJIT_INLINE Error willGrow(ZoneHeap* heap, size_t n = 1) noexcept {
     851       31516 :     return _capacity - _length < n ? grow(heap, n) : static_cast<Error>(kErrorOk);
     852             :   }
     853             : };
     854             : 
     855             : // ============================================================================
     856             : // [asmjit::ZoneBitVector]
     857             : // ============================================================================
     858             : 
     859             : class ZoneBitVector {
     860             : public:
     861             :   ASMJIT_NONCOPYABLE(ZoneBitVector)
     862             : 
     863             :   //! Storage used to store a pack of bits (should by compatible with a machine word).
     864             :   typedef uintptr_t BitWord;
     865             :   enum { kBitsPerWord = static_cast<int>(sizeof(BitWord)) * 8 };
     866             : 
     867             :   static ASMJIT_INLINE size_t _wordsPerBits(size_t nBits) noexcept {
     868           0 :     return ((nBits + kBitsPerWord) / kBitsPerWord) - 1;
     869             :   }
     870             : 
     871             :   // Return all bits zero if 0 and all bits set if 1.
     872             :   static ASMJIT_INLINE BitWord _patternFromBit(bool bit) noexcept {
     873           0 :     BitWord bitAsWord = static_cast<BitWord>(bit);
     874             :     ASMJIT_ASSERT(bitAsWord == 0 || bitAsWord == 1);
     875           0 :     return static_cast<BitWord>(0) - bitAsWord;
     876             :   }
     877             : 
     878             :   // --------------------------------------------------------------------------
     879             :   // [Construction / Destruction]
     880             :   // --------------------------------------------------------------------------
     881             : 
     882             :   explicit ASMJIT_INLINE ZoneBitVector() noexcept :
     883             :     _data(nullptr),
     884             :     _length(0),
     885             :     _capacity(0) {}
     886             : 
     887             :   // --------------------------------------------------------------------------
     888             :   // [Accessors]
     889             :   // --------------------------------------------------------------------------
     890             : 
     891             :   //! Get if the bit-vector is empty (has no bits).
     892             :   ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; }
     893             :   //! Get a length of this bit-vector (in bits).
     894             :   ASMJIT_INLINE size_t getLength() const noexcept { return _length; }
     895             :   //! Get a capacity of this bit-vector (in bits).
     896             :   ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; }
     897             : 
     898             :   //! Get data.
     899             :   ASMJIT_INLINE BitWord* getData() noexcept { return _data; }
     900             :   //! \overload
     901             :   ASMJIT_INLINE const BitWord* getData() const noexcept { return _data; }
     902             : 
     903             :   // --------------------------------------------------------------------------
     904             :   // [Ops]
     905             :   // --------------------------------------------------------------------------
     906             : 
     907             :   ASMJIT_INLINE void clear() noexcept {
     908             :     _length = 0;
     909             :   }
     910             : 
     911             :   ASMJIT_INLINE void reset() noexcept {
     912             :     _data = nullptr;
     913             :     _length = 0;
     914             :     _capacity = 0;
     915             :   }
     916             : 
     917             :   ASMJIT_INLINE void truncate(size_t newLength) noexcept {
     918             :     _length = std::min(_length, newLength);
     919             :     _clearUnusedBits();
     920             :   }
     921             : 
     922             :   ASMJIT_INLINE bool getAt(size_t index) const noexcept {
     923             :     ASMJIT_ASSERT(index < _length);
     924             : 
     925             :     size_t idx = index / kBitsPerWord;
     926             :     size_t bit = index % kBitsPerWord;
     927             :     return static_cast<bool>((_data[idx] >> bit) & 1);
     928             :   }
     929             : 
     930             :   ASMJIT_INLINE void setAt(size_t index, bool value) noexcept {
     931             :     ASMJIT_ASSERT(index < _length);
     932             : 
     933             :     size_t idx = index / kBitsPerWord;
     934             :     size_t bit = index % kBitsPerWord;
     935             :     if (value)
     936             :       _data[idx] |= static_cast<BitWord>(1) << bit;
     937             :     else
     938             :       _data[idx] &= ~(static_cast<BitWord>(1) << bit);
     939             :   }
     940             : 
     941             :   ASMJIT_INLINE void toggleAt(size_t index) noexcept {
     942             :     ASMJIT_ASSERT(index < _length);
     943             : 
     944             :     size_t idx = index / kBitsPerWord;
     945             :     size_t bit = index % kBitsPerWord;
     946             :     _data[idx] ^= static_cast<BitWord>(1) << bit;
     947             :   }
     948             : 
     949             :   ASMJIT_INLINE Error append(ZoneHeap* heap, bool value) noexcept {
     950             :     size_t index = _length;
     951             :     if (ASMJIT_UNLIKELY(index >= _capacity))
     952             :       return _append(heap, value);
     953             : 
     954             :     size_t idx = index / kBitsPerWord;
     955             :     size_t bit = index % kBitsPerWord;
     956             : 
     957             :     if (bit == 0)
     958             :       _data[idx] = static_cast<BitWord>(value) << bit;
     959             :     else
     960             :       _data[idx] |= static_cast<BitWord>(value) << bit;
     961             : 
     962             :     _length++;
     963             :     return kErrorOk;
     964             :   }
     965             : 
     966             :   ASMJIT_API Error fill(size_t fromIndex, size_t toIndex, bool value) noexcept;
     967             : 
     968             :   ASMJIT_INLINE void and_(const ZoneBitVector& other) noexcept {
     969             :     BitWord* dst = _data;
     970             :     const BitWord* src = other._data;
     971             : 
     972             :     size_t numWords = (std::min(_length, other._length) + kBitsPerWord - 1) / kBitsPerWord;
     973             :     for (size_t i = 0; i < numWords; i++)
     974             :       dst[i] = dst[i] & src[i];
     975             :     _clearUnusedBits();
     976             :   }
     977             : 
     978             :   ASMJIT_INLINE void andNot(const ZoneBitVector& other) noexcept {
     979             :     BitWord* dst = _data;
     980             :     const BitWord* src = other._data;
     981             : 
     982             :     size_t numWords = (std::min(_length, other._length) + kBitsPerWord - 1) / kBitsPerWord;
     983             :     for (size_t i = 0; i < numWords; i++)
     984             :       dst[i] = dst[i] & ~src[i];
     985             :     _clearUnusedBits();
     986             :   }
     987             : 
     988             :   ASMJIT_INLINE void or_(const ZoneBitVector& other) noexcept {
     989             :     BitWord* dst = _data;
     990             :     const BitWord* src = other._data;
     991             : 
     992             :     size_t numWords = (std::min(_length, other._length) + kBitsPerWord - 1) / kBitsPerWord;
     993             :     for (size_t i = 0; i < numWords; i++)
     994             :       dst[i] = dst[i] | src[i];
     995             :     _clearUnusedBits();
     996             :   }
     997             : 
     998             :   ASMJIT_INLINE void _clearUnusedBits() noexcept {
     999             :     size_t idx = _length / kBitsPerWord;
    1000             :     size_t bit = _length % kBitsPerWord;
    1001             : 
    1002             :     if (!bit) return;
    1003             :     _data[idx] &= (static_cast<BitWord>(1) << bit) - 1U;
    1004             :   }
    1005             : 
    1006             :   // --------------------------------------------------------------------------
    1007             :   // [Memory Management]
    1008             :   // --------------------------------------------------------------------------
    1009             : 
    1010             :   ASMJIT_INLINE void release(ZoneHeap* heap) noexcept {
    1011             :     if (_data != nullptr) {
    1012             :       heap->release(_data, _capacity / 8);
    1013             :       reset();
    1014             :     }
    1015             :   }
    1016             : 
    1017             :   ASMJIT_INLINE Error resize(ZoneHeap* heap, size_t newLength, bool newBitsValue = false) noexcept {
    1018             :     return _resize(heap, newLength, newLength, newBitsValue);
    1019             :   }
    1020             : 
    1021             :   ASMJIT_API Error _resize(ZoneHeap* heap, size_t newLength, size_t idealCapacity, bool newBitsValue) noexcept;
    1022             :   ASMJIT_API Error _append(ZoneHeap* heap, bool value) noexcept;
    1023             : 
    1024             :   // --------------------------------------------------------------------------
    1025             :   // [Members]
    1026             :   // --------------------------------------------------------------------------
    1027             : 
    1028             :   BitWord* _data;                        //!< Bits.
    1029             :   size_t _length;                        //!< Length of the bit-vector (in bits).
    1030             :   size_t _capacity;                      //!< Capacity of the bit-vector (in bits).
    1031             : };
    1032             : 
    1033             : // ============================================================================
    1034             : // [asmjit::ZoneHashNode]
    1035             : // ============================================================================
    1036             : 
    1037             : //! Node used by \ref ZoneHash<> template.
    1038             : //!
    1039             : //! You must provide function `bool eq(const Key& key)` in order to make
    1040             : //! `ZoneHash::get()` working.
    1041             : class ZoneHashNode {
    1042             : public:
    1043             :   ASMJIT_INLINE ZoneHashNode(uint32_t hVal = 0) noexcept
    1044             :     : _hashNext(nullptr),
    1045             :       _hVal(hVal) {}
    1046             : 
    1047             :   //! Next node in the chain, null if it terminates the chain.
    1048             :   ZoneHashNode* _hashNext;
    1049             :   //! Key hash.
    1050             :   uint32_t _hVal;
    1051             :   //! Should be used by Node that inherits ZoneHashNode, it aligns ZoneHashNode.
    1052             :   uint32_t _customData;
    1053             : };
    1054             : 
    1055             : // ============================================================================
    1056             : // [asmjit::ZoneHashBase]
    1057             : // ============================================================================
    1058             : 
    1059             : class ZoneHashBase {
    1060             : public:
    1061             :   ASMJIT_NONCOPYABLE(ZoneHashBase)
    1062             : 
    1063             :   // --------------------------------------------------------------------------
    1064             :   // [Construction / Destruction]
    1065             :   // --------------------------------------------------------------------------
    1066             : 
    1067        1944 :   ASMJIT_INLINE ZoneHashBase(ZoneHeap* heap) noexcept {
    1068        1944 :     _heap = heap;
    1069        1944 :     _size = 0;
    1070        1944 :     _bucketsCount = 1;
    1071        1944 :     _bucketsGrow = 1;
    1072        1944 :     _data = _embedded;
    1073        1944 :     _embedded[0] = nullptr;
    1074             :   }
    1075        1944 :   ASMJIT_INLINE ~ZoneHashBase() noexcept { reset(nullptr); }
    1076             : 
    1077             :   // --------------------------------------------------------------------------
    1078             :   // [Reset]
    1079             :   // --------------------------------------------------------------------------
    1080             : 
    1081             :   ASMJIT_INLINE bool isInitialized() const noexcept { return _heap != nullptr; }
    1082             :   ASMJIT_API void reset(ZoneHeap* heap) noexcept;
    1083             : 
    1084             :   // --------------------------------------------------------------------------
    1085             :   // [Accessors]
    1086             :   // --------------------------------------------------------------------------
    1087             : 
    1088             :   //! Get a `ZoneHeap` attached to this container.
    1089             :   ASMJIT_INLINE ZoneHeap* getHeap() const noexcept { return _heap; }
    1090             : 
    1091             :   ASMJIT_INLINE size_t getSize() const noexcept { return _size; }
    1092             : 
    1093             :   // --------------------------------------------------------------------------
    1094             :   // [Ops]
    1095             :   // --------------------------------------------------------------------------
    1096             : 
    1097             :   ASMJIT_API void _rehash(uint32_t newCount) noexcept;
    1098             :   ASMJIT_API ZoneHashNode* _put(ZoneHashNode* node) noexcept;
    1099             :   ASMJIT_API ZoneHashNode* _del(ZoneHashNode* node) noexcept;
    1100             : 
    1101             :   // --------------------------------------------------------------------------
    1102             :   // [Members]
    1103             :   // --------------------------------------------------------------------------
    1104             : 
    1105             :   ZoneHeap* _heap;                       //!< ZoneHeap used to allocate data.
    1106             :   size_t _size;                          //!< Count of records inserted into the hash table.
    1107             :   uint32_t _bucketsCount;                //!< Count of hash buckets.
    1108             :   uint32_t _bucketsGrow;                 //!< When buckets array should grow.
    1109             : 
    1110             :   ZoneHashNode** _data;                  //!< Buckets data.
    1111             :   ZoneHashNode* _embedded[1];            //!< Embedded data, used by empty hash tables.
    1112             : };
    1113             : 
    1114             : // ============================================================================
    1115             : // [asmjit::ZoneHash<Key, Node>]
    1116             : // ============================================================================
    1117             : 
    1118             : //! Low-level hash table specialized for storing string keys and POD values.
    1119             : //!
    1120             : //! This hash table allows duplicates to be inserted (the API is so low
    1121             : //! level that it's up to you if you allow it or not, as you should first
    1122             : //! `get()` the node and then modify it or insert a new node by using `put()`,
    1123             : //! depending on the intention).
    1124             : template<typename Node>
    1125             : class ZoneHash : public ZoneHashBase {
    1126             : public:
    1127             :   explicit ASMJIT_INLINE ZoneHash(ZoneHeap* heap = nullptr) noexcept
    1128             :     : ZoneHashBase(heap) {}
    1129        1944 :   ASMJIT_INLINE ~ZoneHash() noexcept {}
    1130             : 
    1131             :   template<typename Key>
    1132             :   ASMJIT_INLINE Node* get(const Key& key) const noexcept {
    1133           0 :     uint32_t hMod = key.hVal % _bucketsCount;
    1134           0 :     Node* node = static_cast<Node*>(_data[hMod]);
    1135             : 
    1136           0 :     while (node && !key.matches(node))
    1137           0 :       node = static_cast<Node*>(node->_hashNext);
    1138             :     return node;
    1139             :   }
    1140             : 
    1141           0 :   ASMJIT_INLINE Node* put(Node* node) noexcept { return static_cast<Node*>(_put(node)); }
    1142             :   ASMJIT_INLINE Node* del(Node* node) noexcept { return static_cast<Node*>(_del(node)); }
    1143             : };
    1144             : 
    1145             : //! \}
    1146             : 
    1147             : } // asmjit namespace
    1148             : } // namespace PLMD
    1149             : 
    1150             : // [Api-End]
    1151             : #include "./asmjit_apiend.h"
    1152             : 
    1153             : // [Guard]
    1154             : #endif // _ASMJIT_BASE_ZONE_H
    1155             : #pragma GCC diagnostic pop
    1156             : #endif // __PLUMED_HAS_ASMJIT
    1157             : #endif

Generated by: LCOV version 1.15