• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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