1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4******************************************************************************
5*
6* Copyright (C) 1997-2016, International Business Machines
7* Corporation and others. All Rights Reserved.
8*
9******************************************************************************
10*
11* File CMEMORY.H
12*
13* Contains stdlib.h/string.h memory functions
14*
15* @author Bertrand A. Damiba
16*
17* Modification History:
18*
19* Date Name Description
20* 6/20/98 Bertrand Created.
21* 05/03/99 stephen Changed from functions to macros.
22*
23******************************************************************************
24*/
25
26#ifndef CMEMORY_H
27#define CMEMORY_H
28
29#include "unicode/utypes.h"
30
31#include <stddef.h>
32#include <string.h>
33#include "unicode/localpointer.h"
34
35#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
36#include <stdio.h>
37#endif
38
39
40#define uprv_memcpy(dst, src, size) U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size)
41#define uprv_memmove(dst, src, size) U_STANDARD_CPP_NAMESPACE memmove(dst, src, size)
42
43/**
44 * \def UPRV_LENGTHOF
45 * Convenience macro to determine the length of a fixed array at compile-time.
46 * @param array A fixed length array
47 * @return The length of the array, in elements
48 * @internal
49 */
50#define UPRV_LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
51#define uprv_memset(buffer, mark, size) U_STANDARD_CPP_NAMESPACE memset(buffer, mark, size)
52#define uprv_memcmp(buffer1, buffer2, size) U_STANDARD_CPP_NAMESPACE memcmp(buffer1, buffer2,size)
53#define uprv_memchr(ptr, value, num) U_STANDARD_CPP_NAMESPACE memchr(ptr, value, num)
54
55U_CAPI void * U_EXPORT2
56uprv_malloc(size_t s) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR(1);
57
58U_CAPI void * U_EXPORT2
59uprv_realloc(void *mem, size_t size) U_ALLOC_SIZE_ATTR(2);
60
61U_CAPI void U_EXPORT2
62uprv_free(void *mem);
63
64U_CAPI void * U_EXPORT2
65uprv_calloc(size_t num, size_t size) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR2(1,2);
66
67/**
68 * Get the least significant bits of a pointer (a memory address).
69 * For example, with a mask of 3, the macro gets the 2 least significant bits,
70 * which will be 0 if the pointer is 32-bit (4-byte) aligned.
71 *
72 * uintptr_t is the most appropriate integer type to cast to.
73 */
74#define U_POINTER_MASK_LSB(ptr, mask) ((uintptr_t)(ptr) & (mask))
75
76/**
77 * Create & return an instance of "type" in statically allocated storage.
78 * e.g.
79 * static std::mutex *myMutex = STATIC_NEW(std::mutex);
80 * To destroy an object created in this way, invoke the destructor explicitly, e.g.
81 * myMutex->~mutex();
82 * DO NOT use delete.
83 * DO NOT use with class UMutex, which has specific support for static instances.
84 *
85 * STATIC_NEW is intended for use when
86 * - We want a static (or global) object.
87 * - We don't want it to ever be destructed, or to explicitly control destruction,
88 * to avoid use-after-destruction problems.
89 * - We want to avoid an ordinary heap allocated object,
90 * to avoid the possibility of memory allocation failures, and
91 * to avoid memory leak reports, from valgrind, for example.
92 * This is defined as a macro rather than a template function because each invocation
93 * must define distinct static storage for the object being returned.
94 */
95#define STATIC_NEW(type) [] () { \
96 alignas(type) static char storage[sizeof(type)]; \
97 return new(storage) type();} ()
98
99/**
100 * Heap clean up function, called from u_cleanup()
101 * Clears any user heap functions from u_setMemoryFunctions()
102 * Does NOT deallocate any remaining allocated memory.
103 */
104U_CFUNC UBool
105cmemory_cleanup(void);
106
107/**
108 * A function called by <TT>uhash_remove</TT>,
109 * <TT>uhash_close</TT>, or <TT>uhash_put</TT> to delete
110 * an existing key or value.
111 * @param obj A key or value stored in a hashtable
112 * @see uprv_deleteUObject
113 */
114typedef void U_CALLCONV UObjectDeleter(void* obj);
115
116/**
117 * Deleter for UObject instances.
118 * Works for all subclasses of UObject because it has a virtual destructor.
119 */
120U_CAPI void U_EXPORT2
121uprv_deleteUObject(void *obj);
122
123#ifdef __cplusplus
124
125#include <utility>
126#include "unicode/uobject.h"
127
128U_NAMESPACE_BEGIN
129
130/**
131 * "Smart pointer" class, deletes memory via uprv_free().
132 * For most methods see the LocalPointerBase base class.
133 * Adds operator[] for array item access.
134 *
135 * @see LocalPointerBase
136 */
137template<typename T>
138class LocalMemory : public LocalPointerBase<T> {
139public:
140 using LocalPointerBase<T>::operator*;
141 using LocalPointerBase<T>::operator->;
142 /**
143 * Constructor takes ownership.
144 * @param p simple pointer to an array of T items that is adopted
145 */
146 explicit LocalMemory(T *p=NULL) : LocalPointerBase<T>(p) {}
147 /**
148 * Move constructor, leaves src with isNull().
149 * @param src source smart pointer
150 */
151 LocalMemory(LocalMemory<T> &&src) U_NOEXCEPT : LocalPointerBase<T>(src.ptr) {
152 src.ptr=NULL;
153 }
154 /**
155 * Destructor deletes the memory it owns.
156 */
157 ~LocalMemory() {
158 uprv_free(LocalPointerBase<T>::ptr);
159 }
160 /**
161 * Move assignment operator, leaves src with isNull().
162 * The behavior is undefined if *this and src are the same object.
163 * @param src source smart pointer
164 * @return *this
165 */
166 LocalMemory<T> &operator=(LocalMemory<T> &&src) U_NOEXCEPT {
167 uprv_free(LocalPointerBase<T>::ptr);
168 LocalPointerBase<T>::ptr=src.ptr;
169 src.ptr=NULL;
170 return *this;
171 }
172 /**
173 * Swap pointers.
174 * @param other other smart pointer
175 */
176 void swap(LocalMemory<T> &other) U_NOEXCEPT {
177 T *temp=LocalPointerBase<T>::ptr;
178 LocalPointerBase<T>::ptr=other.ptr;
179 other.ptr=temp;
180 }
181 /**
182 * Non-member LocalMemory swap function.
183 * @param p1 will get p2's pointer
184 * @param p2 will get p1's pointer
185 */
186 friend inline void swap(LocalMemory<T> &p1, LocalMemory<T> &p2) U_NOEXCEPT {
187 p1.swap(p2);
188 }
189 /**
190 * Deletes the array it owns,
191 * and adopts (takes ownership of) the one passed in.
192 * @param p simple pointer to an array of T items that is adopted
193 */
194 void adoptInstead(T *p) {
195 uprv_free(LocalPointerBase<T>::ptr);
196 LocalPointerBase<T>::ptr=p;
197 }
198 /**
199 * Deletes the array it owns, allocates a new one and reset its bytes to 0.
200 * Returns the new array pointer.
201 * If the allocation fails, then the current array is unchanged and
202 * this method returns NULL.
203 * @param newCapacity must be >0
204 * @return the allocated array pointer, or NULL if the allocation failed
205 */
206 inline T *allocateInsteadAndReset(int32_t newCapacity=1);
207 /**
208 * Deletes the array it owns and allocates a new one, copying length T items.
209 * Returns the new array pointer.
210 * If the allocation fails, then the current array is unchanged and
211 * this method returns NULL.
212 * @param newCapacity must be >0
213 * @param length number of T items to be copied from the old array to the new one;
214 * must be no more than the capacity of the old array,
215 * which the caller must track because the LocalMemory does not track it
216 * @return the allocated array pointer, or NULL if the allocation failed
217 */
218 inline T *allocateInsteadAndCopy(int32_t newCapacity=1, int32_t length=0);
219 /**
220 * Array item access (writable).
221 * No index bounds check.
222 * @param i array index
223 * @return reference to the array item
224 */
225 T &operator[](ptrdiff_t i) const { return LocalPointerBase<T>::ptr[i]; }
226};
227
228template<typename T>
229inline T *LocalMemory<T>::allocateInsteadAndReset(int32_t newCapacity) {
230 if(newCapacity>0) {
231 T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
232 if(p!=NULL) {
233 uprv_memset(p, 0, newCapacity*sizeof(T));
234 uprv_free(LocalPointerBase<T>::ptr);
235 LocalPointerBase<T>::ptr=p;
236 }
237 return p;
238 } else {
239 return NULL;
240 }
241}
242
243
244template<typename T>
245inline T *LocalMemory<T>::allocateInsteadAndCopy(int32_t newCapacity, int32_t length) {
246 if(newCapacity>0) {
247 T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
248 if(p!=NULL) {
249 if(length>0) {
250 if(length>newCapacity) {
251 length=newCapacity;
252 }
253 uprv_memcpy(p, LocalPointerBase<T>::ptr, (size_t)length*sizeof(T));
254 }
255 uprv_free(LocalPointerBase<T>::ptr);
256 LocalPointerBase<T>::ptr=p;
257 }
258 return p;
259 } else {
260 return NULL;
261 }
262}
263
264/**
265 * Simple array/buffer management class using uprv_malloc() and uprv_free().
266 * Provides an internal array with fixed capacity. Can alias another array
267 * or allocate one.
268 *
269 * The array address is properly aligned for type T. It might not be properly
270 * aligned for types larger than T (or larger than the largest subtype of T).
271 *
272 * Unlike LocalMemory and LocalArray, this class never adopts
273 * (takes ownership of) another array.
274 *
275 * WARNING: MaybeStackArray only works with primitive (plain-old data) types.
276 * It does NOT know how to call a destructor! If you work with classes with
277 * destructors, consider:
278 *
279 * - LocalArray in localpointer.h if you know the length ahead of time
280 * - MaybeStackVector if you know the length at runtime
281 */
282template<typename T, int32_t stackCapacity>
283class MaybeStackArray {
284public:
285 // No heap allocation. Use only on the stack.
286 static void* U_EXPORT2 operator new(size_t) U_NOEXCEPT = delete;
287 static void* U_EXPORT2 operator new[](size_t) U_NOEXCEPT = delete;
288#if U_HAVE_PLACEMENT_NEW
289 static void* U_EXPORT2 operator new(size_t, void*) U_NOEXCEPT = delete;
290#endif
291
292 /**
293 * Default constructor initializes with internal T[stackCapacity] buffer.
294 */
295 MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(FALSE) {}
296 /**
297 * Automatically allocates the heap array if the argument is larger than the stack capacity.
298 * Intended for use when an approximate capacity is known at compile time but the true
299 * capacity is not known until runtime.
300 */
301 MaybeStackArray(int32_t newCapacity) : MaybeStackArray() {
302 if (capacity < newCapacity) { resize(newCapacity); }
303 }
304 /**
305 * Destructor deletes the array (if owned).
306 */
307 ~MaybeStackArray() { releaseArray(); }
308 /**
309 * Move constructor: transfers ownership or copies the stack array.
310 */
311 MaybeStackArray(MaybeStackArray<T, stackCapacity> &&src) U_NOEXCEPT;
312 /**
313 * Move assignment: transfers ownership or copies the stack array.
314 */
315 MaybeStackArray<T, stackCapacity> &operator=(MaybeStackArray<T, stackCapacity> &&src) U_NOEXCEPT;
316 /**
317 * Returns the array capacity (number of T items).
318 * @return array capacity
319 */
320 int32_t getCapacity() const { return capacity; }
321 /**
322 * Access without ownership change.
323 * @return the array pointer
324 */
325 T *getAlias() const { return ptr; }
326 /**
327 * Returns the array limit. Simple convenience method.
328 * @return getAlias()+getCapacity()
329 */
330 T *getArrayLimit() const { return getAlias()+capacity; }
331 // No "operator T *() const" because that can make
332 // expressions like mbs[index] ambiguous for some compilers.
333 /**
334 * Array item access (const).
335 * No index bounds check.
336 * @param i array index
337 * @return reference to the array item
338 */
339 const T &operator[](ptrdiff_t i) const { return ptr[i]; }
340 /**
341 * Array item access (writable).
342 * No index bounds check.
343 * @param i array index
344 * @return reference to the array item
345 */
346 T &operator[](ptrdiff_t i) { return ptr[i]; }
347 /**
348 * Deletes the array (if owned) and aliases another one, no transfer of ownership.
349 * If the arguments are illegal, then the current array is unchanged.
350 * @param otherArray must not be NULL
351 * @param otherCapacity must be >0
352 */
353 void aliasInstead(T *otherArray, int32_t otherCapacity) {
354 if(otherArray!=NULL && otherCapacity>0) {
355 releaseArray();
356 ptr=otherArray;
357 capacity=otherCapacity;
358 needToRelease=FALSE;
359 }
360 }
361 /**
362 * Deletes the array (if owned) and allocates a new one, copying length T items.
363 * Returns the new array pointer.
364 * If the allocation fails, then the current array is unchanged and
365 * this method returns NULL.
366 * @param newCapacity can be less than or greater than the current capacity;
367 * must be >0
368 * @param length number of T items to be copied from the old array to the new one
369 * @return the allocated array pointer, or NULL if the allocation failed
370 */
371 inline T *resize(int32_t newCapacity, int32_t length=0);
372 /**
373 * Gives up ownership of the array if owned, or else clones it,
374 * copying length T items; resets itself to the internal stack array.
375 * Returns NULL if the allocation failed.
376 * @param length number of T items to copy when cloning,
377 * and capacity of the clone when cloning
378 * @param resultCapacity will be set to the returned array's capacity (output-only)
379 * @return the array pointer;
380 * caller becomes responsible for deleting the array
381 */
382 inline T *orphanOrClone(int32_t length, int32_t &resultCapacity);
383private:
384 T *ptr;
385 int32_t capacity;
386 UBool needToRelease;
387 T stackArray[stackCapacity];
388 void releaseArray() {
389 if(needToRelease) {
390 uprv_free(ptr);
391 }
392 }
393 void resetToStackArray() {
394 ptr=stackArray;
395 capacity=stackCapacity;
396 needToRelease=FALSE;
397 }
398 /* No comparison operators with other MaybeStackArray's. */
399 bool operator==(const MaybeStackArray & /*other*/) {return FALSE;}
400 bool operator!=(const MaybeStackArray & /*other*/) {return TRUE;}
401 /* No ownership transfer: No copy constructor, no assignment operator. */
402 MaybeStackArray(const MaybeStackArray & /*other*/) {}
403 void operator=(const MaybeStackArray & /*other*/) {}
404};
405
406template<typename T, int32_t stackCapacity>
407icu::MaybeStackArray<T, stackCapacity>::MaybeStackArray(
408 MaybeStackArray <T, stackCapacity>&& src) U_NOEXCEPT
409 : ptr(src.ptr), capacity(src.capacity), needToRelease(src.needToRelease) {
410 if (src.ptr == src.stackArray) {
411 ptr = stackArray;
412 uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);
413 } else {
414 src.resetToStackArray(); // take ownership away from src
415 }
416}
417
418template<typename T, int32_t stackCapacity>
419inline MaybeStackArray <T, stackCapacity>&
420MaybeStackArray<T, stackCapacity>::operator=(MaybeStackArray <T, stackCapacity>&& src) U_NOEXCEPT {
421 releaseArray(); // in case this instance had its own memory allocated
422 capacity = src.capacity;
423 needToRelease = src.needToRelease;
424 if (src.ptr == src.stackArray) {
425 ptr = stackArray;
426 uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);
427 } else {
428 ptr = src.ptr;
429 src.resetToStackArray(); // take ownership away from src
430 }
431 return *this;
432}
433
434template<typename T, int32_t stackCapacity>
435inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
436 if(newCapacity>0) {
437#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
438 ::fprintf(::stderr,"MaybeStacArray (resize) alloc %d * %lu\n", newCapacity,sizeof(T));
439#endif
440 T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
441 if(p!=NULL) {
442 if(length>0) {
443 if(length>capacity) {
444 length=capacity;
445 }
446 if(length>newCapacity) {
447 length=newCapacity;
448 }
449 uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
450 }
451 releaseArray();
452 ptr=p;
453 capacity=newCapacity;
454 needToRelease=TRUE;
455 }
456 return p;
457 } else {
458 return NULL;
459 }
460}
461
462template<typename T, int32_t stackCapacity>
463inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) {
464 T *p;
465 if(needToRelease) {
466 p=ptr;
467 } else if(length<=0) {
468 return NULL;
469 } else {
470 if(length>capacity) {
471 length=capacity;
472 }
473 p=(T *)uprv_malloc(length*sizeof(T));
474#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
475 ::fprintf(::stderr,"MaybeStacArray (orphan) alloc %d * %lu\n", length,sizeof(T));
476#endif
477 if(p==NULL) {
478 return NULL;
479 }
480 uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
481 }
482 resultCapacity=length;
483 resetToStackArray();
484 return p;
485}
486
487/**
488 * Variant of MaybeStackArray that allocates a header struct and an array
489 * in one contiguous memory block, using uprv_malloc() and uprv_free().
490 * Provides internal memory with fixed array capacity. Can alias another memory
491 * block or allocate one.
492 * The stackCapacity is the number of T items in the internal memory,
493 * not counting the H header.
494 * Unlike LocalMemory and LocalArray, this class never adopts
495 * (takes ownership of) another memory block.
496 */
497template<typename H, typename T, int32_t stackCapacity>
498class MaybeStackHeaderAndArray {
499public:
500 // No heap allocation. Use only on the stack.
501 static void* U_EXPORT2 operator new(size_t) U_NOEXCEPT = delete;
502 static void* U_EXPORT2 operator new[](size_t) U_NOEXCEPT = delete;
503#if U_HAVE_PLACEMENT_NEW
504 static void* U_EXPORT2 operator new(size_t, void*) U_NOEXCEPT = delete;
505#endif
506
507 /**
508 * Default constructor initializes with internal H+T[stackCapacity] buffer.
509 */
510 MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(FALSE) {}
511 /**
512 * Destructor deletes the memory (if owned).
513 */
514 ~MaybeStackHeaderAndArray() { releaseMemory(); }
515 /**
516 * Returns the array capacity (number of T items).
517 * @return array capacity
518 */
519 int32_t getCapacity() const { return capacity; }
520 /**
521 * Access without ownership change.
522 * @return the header pointer
523 */
524 H *getAlias() const { return ptr; }
525 /**
526 * Returns the array start.
527 * @return array start, same address as getAlias()+1
528 */
529 T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }
530 /**
531 * Returns the array limit.
532 * @return array limit
533 */
534 T *getArrayLimit() const { return getArrayStart()+capacity; }
535 /**
536 * Access without ownership change. Same as getAlias().
537 * A class instance can be used directly in expressions that take a T *.
538 * @return the header pointer
539 */
540 operator H *() const { return ptr; }
541 /**
542 * Array item access (writable).
543 * No index bounds check.
544 * @param i array index
545 * @return reference to the array item
546 */
547 T &operator[](ptrdiff_t i) { return getArrayStart()[i]; }
548 /**
549 * Deletes the memory block (if owned) and aliases another one, no transfer of ownership.
550 * If the arguments are illegal, then the current memory is unchanged.
551 * @param otherArray must not be NULL
552 * @param otherCapacity must be >0
553 */
554 void aliasInstead(H *otherMemory, int32_t otherCapacity) {
555 if(otherMemory!=NULL && otherCapacity>0) {
556 releaseMemory();
557 ptr=otherMemory;
558 capacity=otherCapacity;
559 needToRelease=FALSE;
560 }
561 }
562 /**
563 * Deletes the memory block (if owned) and allocates a new one,
564 * copying the header and length T array items.
565 * Returns the new header pointer.
566 * If the allocation fails, then the current memory is unchanged and
567 * this method returns NULL.
568 * @param newCapacity can be less than or greater than the current capacity;
569 * must be >0
570 * @param length number of T items to be copied from the old array to the new one
571 * @return the allocated pointer, or NULL if the allocation failed
572 */
573 inline H *resize(int32_t newCapacity, int32_t length=0);
574 /**
575 * Gives up ownership of the memory if owned, or else clones it,
576 * copying the header and length T array items; resets itself to the internal memory.
577 * Returns NULL if the allocation failed.
578 * @param length number of T items to copy when cloning,
579 * and array capacity of the clone when cloning
580 * @param resultCapacity will be set to the returned array's capacity (output-only)
581 * @return the header pointer;
582 * caller becomes responsible for deleting the array
583 */
584 inline H *orphanOrClone(int32_t length, int32_t &resultCapacity);
585private:
586 H *ptr;
587 int32_t capacity;
588 UBool needToRelease;
589 // stackHeader must precede stackArray immediately.
590 H stackHeader;
591 T stackArray[stackCapacity];
592 void releaseMemory() {
593 if(needToRelease) {
594 uprv_free(ptr);
595 }
596 }
597 /* No comparison operators with other MaybeStackHeaderAndArray's. */
598 bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return FALSE;}
599 bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return TRUE;}
600 /* No ownership transfer: No copy constructor, no assignment operator. */
601 MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {}
602 void operator=(const MaybeStackHeaderAndArray & /*other*/) {}
603};
604
605template<typename H, typename T, int32_t stackCapacity>
606inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity,
607 int32_t length) {
608 if(newCapacity>=0) {
609#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
610 ::fprintf(::stderr,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H),newCapacity,sizeof(T));
611#endif
612 H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T));
613 if(p!=NULL) {
614 if(length<0) {
615 length=0;
616 } else if(length>0) {
617 if(length>capacity) {
618 length=capacity;
619 }
620 if(length>newCapacity) {
621 length=newCapacity;
622 }
623 }
624 uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
625 releaseMemory();
626 ptr=p;
627 capacity=newCapacity;
628 needToRelease=TRUE;
629 }
630 return p;
631 } else {
632 return NULL;
633 }
634}
635
636template<typename H, typename T, int32_t stackCapacity>
637inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length,
638 int32_t &resultCapacity) {
639 H *p;
640 if(needToRelease) {
641 p=ptr;
642 } else {
643 if(length<0) {
644 length=0;
645 } else if(length>capacity) {
646 length=capacity;
647 }
648#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
649 ::fprintf(::stderr,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H),length,sizeof(T));
650#endif
651 p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T));
652 if(p==NULL) {
653 return NULL;
654 }
655 uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
656 }
657 resultCapacity=length;
658 ptr=&stackHeader;
659 capacity=stackCapacity;
660 needToRelease=FALSE;
661 return p;
662}
663
664/**
665 * A simple memory management class that creates new heap allocated objects (of
666 * any class that has a public constructor), keeps track of them and eventually
667 * deletes them all in its own destructor.
668 *
669 * A typical use-case would be code like this:
670 *
671 * MemoryPool<MyType> pool;
672 *
673 * MyType* o1 = pool.create();
674 * if (o1 != nullptr) {
675 * foo(o1);
676 * }
677 *
678 * MyType* o2 = pool.create(1, 2, 3);
679 * if (o2 != nullptr) {
680 * bar(o2);
681 * }
682 *
683 * // MemoryPool will take care of deleting the MyType objects.
684 *
685 * It doesn't do anything more than that, and is intentionally kept minimalist.
686 */
687template<typename T, int32_t stackCapacity = 8>
688class MemoryPool : public UMemory {
689public:
690 MemoryPool() : fCount(0), fPool() {}
691
692 ~MemoryPool() {
693 for (int32_t i = 0; i < fCount; ++i) {
694 delete fPool[i];
695 }
696 }
697
698 MemoryPool(const MemoryPool&) = delete;
699 MemoryPool& operator=(const MemoryPool&) = delete;
700
701 MemoryPool(MemoryPool&& other) U_NOEXCEPT : fCount(other.fCount),
702 fPool(std::move(other.fPool)) {
703 other.fCount = 0;
704 }
705
706 MemoryPool& operator=(MemoryPool&& other) U_NOEXCEPT {
707 fCount = other.fCount;
708 fPool = std::move(other.fPool);
709 other.fCount = 0;
710 return *this;
711 }
712
713 /**
714 * Creates a new object of typename T, by forwarding any and all arguments
715 * to the typename T constructor.
716 *
717 * @param args Arguments to be forwarded to the typename T constructor.
718 * @return A pointer to the newly created object, or nullptr on error.
719 */
720 template<typename... Args>
721 T* create(Args&&... args) {
722 int32_t capacity = fPool.getCapacity();
723 if (fCount == capacity &&
724 fPool.resize(capacity == stackCapacity ? 4 * capacity : 2 * capacity,
725 capacity) == nullptr) {
726 return nullptr;
727 }
728 return fPool[fCount++] = new T(std::forward<Args>(args)...);
729 }
730
731 /**
732 * @return Number of elements that have been allocated.
733 */
734 int32_t count() const {
735 return fCount;
736 }
737
738protected:
739 int32_t fCount;
740 MaybeStackArray<T*, stackCapacity> fPool;
741};
742
743/**
744 * An internal Vector-like implementation based on MemoryPool.
745 *
746 * Heap-allocates each element and stores pointers.
747 *
748 * To append an item to the vector, use emplaceBack.
749 *
750 * MaybeStackVector<MyType> vector;
751 * MyType* element = vector.emplaceBack();
752 * if (!element) {
753 * status = U_MEMORY_ALLOCATION_ERROR;
754 * }
755 * // do stuff with element
756 *
757 * To loop over the vector, use a for loop with indices:
758 *
759 * for (int32_t i = 0; i < vector.length(); i++) {
760 * MyType* element = vector[i];
761 * }
762 */
763template<typename T, int32_t stackCapacity = 8>
764class MaybeStackVector : protected MemoryPool<T, stackCapacity> {
765public:
766 using MemoryPool<T, stackCapacity>::MemoryPool;
767 using MemoryPool<T, stackCapacity>::operator=;
768
769 template<typename... Args>
770 T* emplaceBack(Args&&... args) {
771 return this->create(args...);
772 }
773
774 int32_t length() const {
775 return this->fCount;
776 }
777
778 T** getAlias() {
779 return this->fPool.getAlias();
780 }
781
782 /**
783 * Array item access (read-only).
784 * No index bounds check.
785 * @param i array index
786 * @return reference to the array item
787 */
788 const T* operator[](ptrdiff_t i) const {
789 return this->fPool[i];
790 }
791
792 /**
793 * Array item access (writable).
794 * No index bounds check.
795 * @param i array index
796 * @return reference to the array item
797 */
798 T* operator[](ptrdiff_t i) {
799 return this->fPool[i];
800 }
801
802 /**
803 * Append all the items from another MaybeStackVector to this one.
804 */
805 void appendAll(const MaybeStackVector& other, UErrorCode& status) {
806 for (int32_t i = 0; i < other.fCount; i++) {
807 T* item = emplaceBack(*other[i]);
808 if (!item) {
809 status = U_MEMORY_ALLOCATION_ERROR;
810 return;
811 }
812 }
813 }
814};
815
816
817U_NAMESPACE_END
818
819#endif /* __cplusplus */
820#endif /* CMEMORY_H */
821