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
|