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.
getBlockSize()114   ASMJIT_INLINE uint32_t getBlockSize() const noexcept { return _blockSize; }
115   //! Get the default block alignment.
getBlockAlignment()116   ASMJIT_INLINE uint32_t getBlockAlignment() const noexcept { return (uint32_t)1 << _blockAlignmentShift; }
117   //! Get remaining size of the current block.
getRemainingSize()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.
getCursor()124   ASMJIT_INLINE uint8_t* getCursor() noexcept { return _ptr; }
125   //! Get the end of the current zone block, only useful if you use `getCursor()`.
getEnd()126   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()`.
setCursor(uint8_t * p)131   ASMJIT_INLINE void setCursor(uint8_t* p) noexcept {
132     ASMJIT_ASSERT(p >= _ptr && p <= _end);
133     _ptr = p;
134   }
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   //! ~~~
alloc(size_t size)172   ASMJIT_INLINE void* alloc(size_t size) noexcept {
173     uint8_t* ptr = _ptr;
174     size_t remainingBytes = (size_t)(_end - ptr);
175 
176     if (ASMJIT_UNLIKELY(remainingBytes < size))
177       return _alloc(size);
178 
179     _ptr += size;
180     ASMJIT_ASSERT(_ptr <= _end);
181 
182     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`.
allocNoCheck(size_t 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     return static_cast<T*>(allocZeroed(size));
218   }
219 
220   //! Like `new(std::nothrow) T(...)`, but allocated by `Zone`.
221   template<typename T>
newT()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>
newT(P1 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.
ZoneHeap()325   ASMJIT_INLINE ZoneHeap() noexcept {
326     ::memset(this, 0, sizeof(*this));
327   }
328   //! Create a new `ZoneHeap` initialized to use `zone`.
ZoneHeap(Zone * zone)329   explicit ASMJIT_INLINE ZoneHeap(Zone* zone) noexcept {
330     ::memset(this, 0, sizeof(*this));
331     _zone = zone;
332   }
333   //! Destroy the `ZoneHeap`.
~ZoneHeap()334   ASMJIT_INLINE ~ZoneHeap() noexcept { reset(); }
335 
336   // --------------------------------------------------------------------------
337   // [Init / Reset]
338   // --------------------------------------------------------------------------
339 
340   //! Get if the `ZoneHeap` is initialized (i.e. has `Zone`).
isInitialized()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)`.
init(Zone * 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.
getZone()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`).
_getSlotIndex(size_t size,uint32_t & slot)369   static ASMJIT_INLINE bool _getSlotIndex(size_t size, uint32_t& slot) noexcept {
370     ASMJIT_ASSERT(size > 0);
371     if (size > kHiMaxSize)
372       return false;
373 
374     if (size <= kLoMaxSize)
375       slot = static_cast<uint32_t>((size - 1) / kLoGranularity);
376     else
377       slot = static_cast<uint32_t>((size - kLoMaxSize - 1) / kHiGranularity) + kLoCount;
378 
379     return true;
380   }
381 
382   //! \overload
_getSlotIndex(size_t size,uint32_t & slot,size_t & allocatedSize)383   static ASMJIT_INLINE bool _getSlotIndex(size_t size, uint32_t& slot, size_t& allocatedSize) noexcept {
384     ASMJIT_ASSERT(size > 0);
385     if (size > kHiMaxSize)
386       return false;
387 
388     if (size <= kLoMaxSize) {
389       slot = static_cast<uint32_t>((size - 1) / kLoGranularity);
390       allocatedSize = Utils::alignTo(size, kLoGranularity);
391     }
392     else {
393       slot = static_cast<uint32_t>((size - kLoMaxSize - 1) / kHiGranularity) + kLoCount;
394       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.
alloc(size_t size)411   ASMJIT_INLINE void* alloc(size_t size) noexcept {
412     ASMJIT_ASSERT(isInitialized());
413     size_t allocatedSize;
414     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.
alloc(size_t size,size_t & allocatedSize)420   ASMJIT_INLINE void* alloc(size_t size, size_t& allocatedSize) noexcept {
421     ASMJIT_ASSERT(isInitialized());
422     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.
allocZeroed(size_t size)432   ASMJIT_INLINE void* allocZeroed(size_t size) noexcept {
433     ASMJIT_ASSERT(isInitialized());
434 
435     size_t allocatedSize;
436     return _allocZeroed(size, allocatedSize);
437   }
438 
439   //! Like `alloc(size, allocatedSize)`, but returns zeroed memory.
allocZeroed(size_t size,size_t & allocatedSize)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()`.
release(void * p,size_t size)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       static_cast<Slot*>(p)->next = static_cast<Slot*>(_slots[slot]);
465       _slots[slot] = static_cast<Slot*>(p);
466     }
467     else {
468       _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.
getNextLink498     ASMJIT_INLINE Link* getNext() const noexcept { return _next; }
499     //! Get value.
getValueLink500     ASMJIT_INLINE T getValue() const noexcept { return _value; }
501     //! Set value to `value`.
setValueLink502     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 {
AppenderAppender515     ASMJIT_INLINE Appender(ZoneList<T>& list) noexcept { init(list); }
516 
initAppender517     ASMJIT_INLINE void init(ZoneList<T>& list) noexcept {
518       pPrev = &list._first;
519     }
520 
doneAppender521     ASMJIT_INLINE void done(ZoneList<T>& list) noexcept {
522       list._last = *pPrev;
523       *pPrev = nullptr;
524     }
525 
appendAppender526     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 
ZoneList()538   ASMJIT_INLINE ZoneList() noexcept : _first(nullptr), _last(nullptr) {}
~ZoneList()539   ASMJIT_INLINE ~ZoneList() noexcept {}
540 
541   // --------------------------------------------------------------------------
542   // [Data]
543   // --------------------------------------------------------------------------
544 
isEmpty()545   ASMJIT_INLINE bool isEmpty() const noexcept { return _first != nullptr; }
getFirst()546   ASMJIT_INLINE Link* getFirst() const noexcept { return _first; }
getLast()547   ASMJIT_INLINE Link* getLast() const noexcept { return _last; }
548 
549   // --------------------------------------------------------------------------
550   // [Ops]
551   // --------------------------------------------------------------------------
552 
reset()553   ASMJIT_INLINE void reset() noexcept {
554     _first = nullptr;
555     _last = nullptr;
556   }
557 
prepend(Link * link)558   ASMJIT_INLINE void prepend(Link* link) noexcept {
559     link->_next = _first;
560     if (!_first) _last = link;
561     _first = link;
562   }
563 
append(Link * link)564   ASMJIT_INLINE void append(Link* link) noexcept {
565     link->_next = nullptr;
566     if (!_first)
567       _first = link;
568     else
569       _last->_next = link;
570     _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:
ASMJIT_NONCOPYABLE(ZoneVectorBase)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     : _data(nullptr),
598       _length(0),
599       _capacity(0) {}
600 
601   // --------------------------------------------------------------------------
602   // [Accessors]
603   // --------------------------------------------------------------------------
604 
605 public:
606   //! Get if the vector is empty.
isEmpty()607   ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; }
608   //! Get vector length.
getLength()609   ASMJIT_INLINE size_t getLength() const noexcept { return _length; }
610   //! Get vector capacity.
getCapacity()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).
clear()618   ASMJIT_INLINE void clear() noexcept { _length = 0; }
619   //! Reset the vector data and set its `length` to zero.
reset()620   ASMJIT_INLINE void reset() noexcept {
621     _data = nullptr;
622     _length = 0;
623     _capacity = 0;
624   }
625 
626   //! Truncate the vector to at most `n` items.
truncate(size_t n)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:
_release(ZoneHeap * heap,size_t sizeOfT)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:
ASMJIT_NONCOPYABLE(ZoneVector<T>)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.
getData()685   ASMJIT_INLINE T* getData() noexcept { return static_cast<T*>(_data); }
686   //! \overload
getData()687   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.
prepend(ZoneHeap * heap,const T & item)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`.
insert(ZoneHeap * heap,size_t index,const T & item)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.
append(ZoneHeap * heap,const T & item)721   Error append(ZoneHeap* heap, const T& item) noexcept {
722     if (ASMJIT_UNLIKELY(_length == _capacity))
723       ASMJIT_PROPAGATE(grow(heap, 1));
724 
725     ::memcpy(static_cast<T*>(_data) + _length, &item, sizeof(T));
726 
727     _length++;
728     return kErrorOk;
729   }
730 
concat(ZoneHeap * heap,const ZoneVector<T> & other)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.
prependUnsafe(const T & item)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.
appendUnsafe(const T & item)763   ASMJIT_INLINE void appendUnsafe(const T& item) noexcept {
764     ASMJIT_ASSERT(_length < _capacity);
765 
766     ::memcpy(static_cast<T*>(_data) + _length, &item, sizeof(T));
767     _length++;
768   }
769 
770   //! Concatenate all items of `other` at the end of the vector.
concatUnsafe(const ZoneVector<T> & other)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.
indexOf(const T & val)780   ASMJIT_INLINE size_t indexOf(const T& val) const noexcept {
781     const T* data = static_cast<const T*>(_data);
782     size_t length = _length;
783 
784     for (size_t i = 0; i < length; i++)
785       if (data[i] == val)
786         return i;
787 
788     return Globals::kInvalidIndex;
789   }
790 
791   //! Get whether the vector contains `val`.
contains(const T & 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`.
removeAt(size_t i)797   ASMJIT_INLINE void removeAt(size_t i) noexcept {
798     ASMJIT_ASSERT(i < _length);
799 
800     T* data = static_cast<T*>(_data) + i;
801     _length--;
802     ::memmove(data, data + 1, _length - i);
803   }
804 
805   //! Swap this pod-vector with `other`.
swap(ZoneVector<T> & 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).
getAt(size_t i)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     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     return getData()[i];
828   }
829 
830   // --------------------------------------------------------------------------
831   // [Memory Management]
832   // --------------------------------------------------------------------------
833 
834   //! Release the memory held by `ZoneVector<T>` back to the `heap`.
release(ZoneHeap * 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.
grow(ZoneHeap * heap,size_t n)838   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.
resize(ZoneHeap * heap,size_t n)845   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.
reserve(ZoneHeap * heap,size_t n)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     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 
_wordsPerBits(size_t nBits)867   static ASMJIT_INLINE size_t _wordsPerBits(size_t nBits) noexcept {
868     return ((nBits + kBitsPerWord) / kBitsPerWord) - 1;
869   }
870 
871   // Return all bits zero if 0 and all bits set if 1.
_patternFromBit(bool bit)872   static ASMJIT_INLINE BitWord _patternFromBit(bool bit) noexcept {
873     BitWord bitAsWord = static_cast<BitWord>(bit);
874     ASMJIT_ASSERT(bitAsWord == 0 || bitAsWord == 1);
875     return static_cast<BitWord>(0) - bitAsWord;
876   }
877 
878   // --------------------------------------------------------------------------
879   // [Construction / Destruction]
880   // --------------------------------------------------------------------------
881 
ZoneBitVector()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).
isEmpty()892   ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; }
893   //! Get a length of this bit-vector (in bits).
getLength()894   ASMJIT_INLINE size_t getLength() const noexcept { return _length; }
895   //! Get a capacity of this bit-vector (in bits).
getCapacity()896   ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; }
897 
898   //! Get data.
getData()899   ASMJIT_INLINE BitWord* getData() noexcept { return _data; }
900   //! \overload
getData()901   ASMJIT_INLINE const BitWord* getData() const noexcept { return _data; }
902 
903   // --------------------------------------------------------------------------
904   // [Ops]
905   // --------------------------------------------------------------------------
906 
clear()907   ASMJIT_INLINE void clear() noexcept {
908     _length = 0;
909   }
910 
reset()911   ASMJIT_INLINE void reset() noexcept {
912     _data = nullptr;
913     _length = 0;
914     _capacity = 0;
915   }
916 
truncate(size_t newLength)917   ASMJIT_INLINE void truncate(size_t newLength) noexcept {
918     _length = std::min(_length, newLength);
919     _clearUnusedBits();
920   }
921 
getAt(size_t index)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 
setAt(size_t index,bool value)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 
toggleAt(size_t index)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 
append(ZoneHeap * heap,bool value)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 
and_(const ZoneBitVector & other)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 
andNot(const ZoneBitVector & other)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 
or_(const ZoneBitVector & other)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 
_clearUnusedBits()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 
release(ZoneHeap * heap)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
_hashNext(nullptr)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:
ASMJIT_NONCOPYABLE(ZoneHashBase)1061   ASMJIT_NONCOPYABLE(ZoneHashBase)
1062 
1063   // --------------------------------------------------------------------------
1064   // [Construction / Destruction]
1065   // --------------------------------------------------------------------------
1066 
1067   ASMJIT_INLINE ZoneHashBase(ZoneHeap* heap) noexcept {
1068     _heap = heap;
1069     _size = 0;
1070     _bucketsCount = 1;
1071     _bucketsGrow = 1;
1072     _data = _embedded;
1073     _embedded[0] = nullptr;
1074   }
~ZoneHashBase()1075   ASMJIT_INLINE ~ZoneHashBase() noexcept { reset(nullptr); }
1076 
1077   // --------------------------------------------------------------------------
1078   // [Reset]
1079   // --------------------------------------------------------------------------
1080 
isInitialized()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.
getHeap()1089   ASMJIT_INLINE ZoneHeap* getHeap() const noexcept { return _heap; }
1090 
getSize()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
ZoneHashBase(heap)1128     : ZoneHashBase(heap) {}
~ZoneHash()1129   ASMJIT_INLINE ~ZoneHash() noexcept {}
1130 
1131   template<typename Key>
get(const Key & key)1132   ASMJIT_INLINE Node* get(const Key& key) const noexcept {
1133     uint32_t hMod = key.hVal % _bucketsCount;
1134     Node* node = static_cast<Node*>(_data[hMod]);
1135 
1136     while (node && !key.matches(node))
1137       node = static_cast<Node*>(node->_hashNext);
1138     return node;
1139   }
1140 
put(Node * node)1141   ASMJIT_INLINE Node* put(Node* node) noexcept { return static_cast<Node*>(_put(node)); }
del(Node * 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
1158