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