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 * 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 */
104 U_CFUNC UBool
105 cmemory_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 */
114 typedef 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 */
120 U_CAPI void U_EXPORT2
121 uprv_deleteUObject(void *obj);
122
123 #ifdef __cplusplus
124
125 #include <utility>
126 #include "unicode/uobject.h"
127
128 U_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 */
137 template<typename T>
138 class LocalMemory : public LocalPointerBase<T> {
139 public:
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 */
LocalMemory(LocalMemory<T> && src)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 */
~LocalMemory()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 */
swap(LocalMemory<T> & other)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 */
swap(LocalMemory<T> & p1,LocalMemory<T> & p2)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 */
adoptInstead(T * p)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
228 template<typename T>
allocateInsteadAndReset(int32_t newCapacity)229 inline 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
244 template<typename T>
allocateInsteadAndCopy(int32_t newCapacity,int32_t length)245 inline 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 LocalArray in localpointer.h or MemoryPool.
278 */
279 template<typename T, int32_t stackCapacity>
280 class MaybeStackArray {
281 public:
282 // No heap allocation. Use only on the stack.
283 static void* U_EXPORT2 operator new(size_t) U_NOEXCEPT = delete;
284 static void* U_EXPORT2 operator new[](size_t) U_NOEXCEPT = delete;
285 #if U_HAVE_PLACEMENT_NEW
286 static void* U_EXPORT2 operator new(size_t, void*) U_NOEXCEPT = delete;
287 #endif
288
289 /**
290 * Default constructor initializes with internal T[stackCapacity] buffer.
291 */
MaybeStackArray()292 MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(FALSE) {}
293 /**
294 * Automatically allocates the heap array if the argument is larger than the stack capacity.
295 * Intended for use when an approximate capacity is known at compile time but the true
296 * capacity is not known until runtime.
297 */
MaybeStackArray(int32_t newCapacity)298 MaybeStackArray(int32_t newCapacity) : MaybeStackArray() {
299 if (capacity < newCapacity) { resize(newCapacity); }
300 }
301 /**
302 * Destructor deletes the array (if owned).
303 */
~MaybeStackArray()304 ~MaybeStackArray() { releaseArray(); }
305 /**
306 * Move constructor: transfers ownership or copies the stack array.
307 */
308 MaybeStackArray(MaybeStackArray<T, stackCapacity> &&src) U_NOEXCEPT;
309 /**
310 * Move assignment: transfers ownership or copies the stack array.
311 */
312 MaybeStackArray<T, stackCapacity> &operator=(MaybeStackArray<T, stackCapacity> &&src) U_NOEXCEPT;
313 /**
314 * Returns the array capacity (number of T items).
315 * @return array capacity
316 */
getCapacity()317 int32_t getCapacity() const { return capacity; }
318 /**
319 * Access without ownership change.
320 * @return the array pointer
321 */
getAlias()322 T *getAlias() const { return ptr; }
323 /**
324 * Returns the array limit. Simple convenience method.
325 * @return getAlias()+getCapacity()
326 */
getArrayLimit()327 T *getArrayLimit() const { return getAlias()+capacity; }
328 // No "operator T *() const" because that can make
329 // expressions like mbs[index] ambiguous for some compilers.
330 /**
331 * Array item access (const).
332 * No index bounds check.
333 * @param i array index
334 * @return reference to the array item
335 */
336 const T &operator[](ptrdiff_t i) const { return ptr[i]; }
337 /**
338 * Array item access (writable).
339 * No index bounds check.
340 * @param i array index
341 * @return reference to the array item
342 */
343 T &operator[](ptrdiff_t i) { return ptr[i]; }
344 /**
345 * Deletes the array (if owned) and aliases another one, no transfer of ownership.
346 * If the arguments are illegal, then the current array is unchanged.
347 * @param otherArray must not be NULL
348 * @param otherCapacity must be >0
349 */
aliasInstead(T * otherArray,int32_t otherCapacity)350 void aliasInstead(T *otherArray, int32_t otherCapacity) {
351 if(otherArray!=NULL && otherCapacity>0) {
352 releaseArray();
353 ptr=otherArray;
354 capacity=otherCapacity;
355 needToRelease=FALSE;
356 }
357 }
358 /**
359 * Deletes the array (if owned) and allocates a new one, copying length T items.
360 * Returns the new array pointer.
361 * If the allocation fails, then the current array is unchanged and
362 * this method returns NULL.
363 * @param newCapacity can be less than or greater than the current capacity;
364 * must be >0
365 * @param length number of T items to be copied from the old array to the new one
366 * @return the allocated array pointer, or NULL if the allocation failed
367 */
368 inline T *resize(int32_t newCapacity, int32_t length=0);
369 /**
370 * Gives up ownership of the array if owned, or else clones it,
371 * copying length T items; resets itself to the internal stack array.
372 * Returns NULL if the allocation failed.
373 * @param length number of T items to copy when cloning,
374 * and capacity of the clone when cloning
375 * @param resultCapacity will be set to the returned array's capacity (output-only)
376 * @return the array pointer;
377 * caller becomes responsible for deleting the array
378 */
379 inline T *orphanOrClone(int32_t length, int32_t &resultCapacity);
380 private:
381 T *ptr;
382 int32_t capacity;
383 UBool needToRelease;
384 T stackArray[stackCapacity];
releaseArray()385 void releaseArray() {
386 if(needToRelease) {
387 uprv_free(ptr);
388 }
389 }
resetToStackArray()390 void resetToStackArray() {
391 ptr=stackArray;
392 capacity=stackCapacity;
393 needToRelease=FALSE;
394 }
395 /* No comparison operators with other MaybeStackArray's. */
396 bool operator==(const MaybeStackArray & /*other*/) {return FALSE;}
397 bool operator!=(const MaybeStackArray & /*other*/) {return TRUE;}
398 /* No ownership transfer: No copy constructor, no assignment operator. */
MaybeStackArray(const MaybeStackArray &)399 MaybeStackArray(const MaybeStackArray & /*other*/) {}
400 void operator=(const MaybeStackArray & /*other*/) {}
401 };
402
403 template<typename T, int32_t stackCapacity>
MaybeStackArray(MaybeStackArray<T,stackCapacity> && src)404 icu::MaybeStackArray<T, stackCapacity>::MaybeStackArray(
405 MaybeStackArray <T, stackCapacity>&& src) U_NOEXCEPT
406 : ptr(src.ptr), capacity(src.capacity), needToRelease(src.needToRelease) {
407 if (src.ptr == src.stackArray) {
408 ptr = stackArray;
409 uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);
410 } else {
411 src.resetToStackArray(); // take ownership away from src
412 }
413 }
414
415 template<typename T, int32_t stackCapacity>
416 inline MaybeStackArray <T, stackCapacity>&
417 MaybeStackArray<T, stackCapacity>::operator=(MaybeStackArray <T, stackCapacity>&& src) U_NOEXCEPT {
418 releaseArray(); // in case this instance had its own memory allocated
419 capacity = src.capacity;
420 needToRelease = src.needToRelease;
421 if (src.ptr == src.stackArray) {
422 ptr = stackArray;
423 uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);
424 } else {
425 ptr = src.ptr;
426 src.resetToStackArray(); // take ownership away from src
427 }
428 return *this;
429 }
430
431 template<typename T, int32_t stackCapacity>
resize(int32_t newCapacity,int32_t length)432 inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
433 if(newCapacity>0) {
434 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
435 ::fprintf(::stderr,"MaybeStacArray (resize) alloc %d * %lu\n", newCapacity,sizeof(T));
436 #endif
437 T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
438 if(p!=NULL) {
439 if(length>0) {
440 if(length>capacity) {
441 length=capacity;
442 }
443 if(length>newCapacity) {
444 length=newCapacity;
445 }
446 uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
447 }
448 releaseArray();
449 ptr=p;
450 capacity=newCapacity;
451 needToRelease=TRUE;
452 }
453 return p;
454 } else {
455 return NULL;
456 }
457 }
458
459 template<typename T, int32_t stackCapacity>
orphanOrClone(int32_t length,int32_t & resultCapacity)460 inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) {
461 T *p;
462 if(needToRelease) {
463 p=ptr;
464 } else if(length<=0) {
465 return NULL;
466 } else {
467 if(length>capacity) {
468 length=capacity;
469 }
470 p=(T *)uprv_malloc(length*sizeof(T));
471 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
472 ::fprintf(::stderr,"MaybeStacArray (orphan) alloc %d * %lu\n", length,sizeof(T));
473 #endif
474 if(p==NULL) {
475 return NULL;
476 }
477 uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
478 }
479 resultCapacity=length;
480 resetToStackArray();
481 return p;
482 }
483
484 /**
485 * Variant of MaybeStackArray that allocates a header struct and an array
486 * in one contiguous memory block, using uprv_malloc() and uprv_free().
487 * Provides internal memory with fixed array capacity. Can alias another memory
488 * block or allocate one.
489 * The stackCapacity is the number of T items in the internal memory,
490 * not counting the H header.
491 * Unlike LocalMemory and LocalArray, this class never adopts
492 * (takes ownership of) another memory block.
493 */
494 template<typename H, typename T, int32_t stackCapacity>
495 class MaybeStackHeaderAndArray {
496 public:
497 // No heap allocation. Use only on the stack.
498 static void* U_EXPORT2 operator new(size_t) U_NOEXCEPT = delete;
499 static void* U_EXPORT2 operator new[](size_t) U_NOEXCEPT = delete;
500 #if U_HAVE_PLACEMENT_NEW
501 static void* U_EXPORT2 operator new(size_t, void*) U_NOEXCEPT = delete;
502 #endif
503
504 /**
505 * Default constructor initializes with internal H+T[stackCapacity] buffer.
506 */
MaybeStackHeaderAndArray()507 MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(FALSE) {}
508 /**
509 * Destructor deletes the memory (if owned).
510 */
~MaybeStackHeaderAndArray()511 ~MaybeStackHeaderAndArray() { releaseMemory(); }
512 /**
513 * Returns the array capacity (number of T items).
514 * @return array capacity
515 */
getCapacity()516 int32_t getCapacity() const { return capacity; }
517 /**
518 * Access without ownership change.
519 * @return the header pointer
520 */
getAlias()521 H *getAlias() const { return ptr; }
522 /**
523 * Returns the array start.
524 * @return array start, same address as getAlias()+1
525 */
getArrayStart()526 T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }
527 /**
528 * Returns the array limit.
529 * @return array limit
530 */
getArrayLimit()531 T *getArrayLimit() const { return getArrayStart()+capacity; }
532 /**
533 * Access without ownership change. Same as getAlias().
534 * A class instance can be used directly in expressions that take a T *.
535 * @return the header pointer
536 */
537 operator H *() const { return ptr; }
538 /**
539 * Array item access (writable).
540 * No index bounds check.
541 * @param i array index
542 * @return reference to the array item
543 */
544 T &operator[](ptrdiff_t i) { return getArrayStart()[i]; }
545 /**
546 * Deletes the memory block (if owned) and aliases another one, no transfer of ownership.
547 * If the arguments are illegal, then the current memory is unchanged.
548 * @param otherArray must not be NULL
549 * @param otherCapacity must be >0
550 */
aliasInstead(H * otherMemory,int32_t otherCapacity)551 void aliasInstead(H *otherMemory, int32_t otherCapacity) {
552 if(otherMemory!=NULL && otherCapacity>0) {
553 releaseMemory();
554 ptr=otherMemory;
555 capacity=otherCapacity;
556 needToRelease=FALSE;
557 }
558 }
559 /**
560 * Deletes the memory block (if owned) and allocates a new one,
561 * copying the header and length T array items.
562 * Returns the new header pointer.
563 * If the allocation fails, then the current memory is unchanged and
564 * this method returns NULL.
565 * @param newCapacity can be less than or greater than the current capacity;
566 * must be >0
567 * @param length number of T items to be copied from the old array to the new one
568 * @return the allocated pointer, or NULL if the allocation failed
569 */
570 inline H *resize(int32_t newCapacity, int32_t length=0);
571 /**
572 * Gives up ownership of the memory if owned, or else clones it,
573 * copying the header and length T array items; resets itself to the internal memory.
574 * Returns NULL if the allocation failed.
575 * @param length number of T items to copy when cloning,
576 * and array capacity of the clone when cloning
577 * @param resultCapacity will be set to the returned array's capacity (output-only)
578 * @return the header pointer;
579 * caller becomes responsible for deleting the array
580 */
581 inline H *orphanOrClone(int32_t length, int32_t &resultCapacity);
582 private:
583 H *ptr;
584 int32_t capacity;
585 UBool needToRelease;
586 // stackHeader must precede stackArray immediately.
587 H stackHeader;
588 T stackArray[stackCapacity];
releaseMemory()589 void releaseMemory() {
590 if(needToRelease) {
591 uprv_free(ptr);
592 }
593 }
594 /* No comparison operators with other MaybeStackHeaderAndArray's. */
595 bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return FALSE;}
596 bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return TRUE;}
597 /* No ownership transfer: No copy constructor, no assignment operator. */
MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray &)598 MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {}
599 void operator=(const MaybeStackHeaderAndArray & /*other*/) {}
600 };
601
602 template<typename H, typename T, int32_t stackCapacity>
resize(int32_t newCapacity,int32_t length)603 inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity,
604 int32_t length) {
605 if(newCapacity>=0) {
606 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
607 ::fprintf(::stderr,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H),newCapacity,sizeof(T));
608 #endif
609 H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T));
610 if(p!=NULL) {
611 if(length<0) {
612 length=0;
613 } else if(length>0) {
614 if(length>capacity) {
615 length=capacity;
616 }
617 if(length>newCapacity) {
618 length=newCapacity;
619 }
620 }
621 uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
622 releaseMemory();
623 ptr=p;
624 capacity=newCapacity;
625 needToRelease=TRUE;
626 }
627 return p;
628 } else {
629 return NULL;
630 }
631 }
632
633 template<typename H, typename T, int32_t stackCapacity>
orphanOrClone(int32_t length,int32_t & resultCapacity)634 inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length,
635 int32_t &resultCapacity) {
636 H *p;
637 if(needToRelease) {
638 p=ptr;
639 } else {
640 if(length<0) {
641 length=0;
642 } else if(length>capacity) {
643 length=capacity;
644 }
645 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
646 ::fprintf(::stderr,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H),length,sizeof(T));
647 #endif
648 p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T));
649 if(p==NULL) {
650 return NULL;
651 }
652 uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
653 }
654 resultCapacity=length;
655 ptr=&stackHeader;
656 capacity=stackCapacity;
657 needToRelease=FALSE;
658 return p;
659 }
660
661 /**
662 * A simple memory management class that creates new heap allocated objects (of
663 * any class that has a public constructor), keeps track of them and eventually
664 * deletes them all in its own destructor.
665 *
666 * A typical use-case would be code like this:
667 *
668 * MemoryPool<MyType> pool;
669 *
670 * MyType* o1 = pool.create();
671 * if (o1 != nullptr) {
672 * foo(o1);
673 * }
674 *
675 * MyType* o2 = pool.create(1, 2, 3);
676 * if (o2 != nullptr) {
677 * bar(o2);
678 * }
679 *
680 * // MemoryPool will take care of deleting the MyType objects.
681 *
682 * It doesn't do anything more than that, and is intentionally kept minimalist.
683 */
684 template<typename T, int32_t stackCapacity = 8>
685 class MemoryPool : public UMemory {
686 public:
MemoryPool()687 MemoryPool() : count(0), pool() {}
688
~MemoryPool()689 ~MemoryPool() {
690 for (int32_t i = 0; i < count; ++i) {
691 delete pool[i];
692 }
693 }
694
695 MemoryPool(const MemoryPool&) = delete;
696 MemoryPool& operator=(const MemoryPool&) = delete;
697
MemoryPool(MemoryPool && other)698 MemoryPool(MemoryPool&& other) U_NOEXCEPT : count(other.count),
699 pool(std::move(other.pool)) {
700 other.count = 0;
701 }
702
703 MemoryPool& operator=(MemoryPool&& other) U_NOEXCEPT {
704 count = other.count;
705 pool = std::move(other.pool);
706 other.count = 0;
707 return *this;
708 }
709
710 /**
711 * Creates a new object of typename T, by forwarding any and all arguments
712 * to the typename T constructor.
713 *
714 * @param args Arguments to be forwarded to the typename T constructor.
715 * @return A pointer to the newly created object, or nullptr on error.
716 */
717 template<typename... Args>
create(Args &&...args)718 T* create(Args&&... args) {
719 int32_t capacity = pool.getCapacity();
720 if (count == capacity &&
721 pool.resize(capacity == stackCapacity ? 4 * capacity : 2 * capacity,
722 capacity) == nullptr) {
723 return nullptr;
724 }
725 return pool[count++] = new T(std::forward<Args>(args)...);
726 }
727
728 private:
729 int32_t count;
730 MaybeStackArray<T*, stackCapacity> pool;
731 };
732
733 U_NAMESPACE_END
734
735 #endif /* __cplusplus */
736 #endif /* CMEMORY_H */
737