// © 2016 and later: Unicode, Inc. and others.1// License & terms of use: http://www.unicode.org/copyright.html2/*3******************************************************************************4*5* Copyright (C) 1997-2016, International Business Machines6* Corporation and others. All Rights Reserved.7*8******************************************************************************9*10* File CMEMORY.H11*12* Contains stdlib.h/string.h memory functions13*14* @author Bertrand A. Damiba15*16* Modification History:17*18* Date Name Description19* 6/20/98 Bertrand Created.20* 05/03/99 stephen Changed from functions to macros.21*22******************************************************************************23*/2425#ifndef CMEMORY_H26#define CMEMORY_H2728#include "unicode/utypes.h"2930#include <stddef.h>31#include <string.h>32#include "unicode/localpointer.h"33#include "uassert.h"3435#if U_DEBUG && defined(UPRV_MALLOC_COUNT)36#include <stdio.h>37#endif3839// uprv_memcpy and uprv_memmove40#if defined(__clang__)41#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \42/* Suppress warnings about addresses that will never be NULL */ \43_Pragma("clang diagnostic push") \44_Pragma("clang diagnostic ignored \"-Waddress\"") \45U_ASSERT(dst != NULL); \46U_ASSERT(src != NULL); \47_Pragma("clang diagnostic pop") \48U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \49} UPRV_BLOCK_MACRO_END50#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \51/* Suppress warnings about addresses that will never be NULL */ \52_Pragma("clang diagnostic push") \53_Pragma("clang diagnostic ignored \"-Waddress\"") \54U_ASSERT(dst != NULL); \55U_ASSERT(src != NULL); \56_Pragma("clang diagnostic pop") \57U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \58} UPRV_BLOCK_MACRO_END59#elif defined(__GNUC__)60#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \61/* Suppress warnings about addresses that will never be NULL */ \62_Pragma("GCC diagnostic push") \63_Pragma("GCC diagnostic ignored \"-Waddress\"") \64U_ASSERT(dst != NULL); \65U_ASSERT(src != NULL); \66_Pragma("GCC diagnostic pop") \67U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \68} UPRV_BLOCK_MACRO_END69#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \70/* Suppress warnings about addresses that will never be NULL */ \71_Pragma("GCC diagnostic push") \72_Pragma("GCC diagnostic ignored \"-Waddress\"") \73U_ASSERT(dst != NULL); \74U_ASSERT(src != NULL); \75_Pragma("GCC diagnostic pop") \76U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \77} UPRV_BLOCK_MACRO_END78#else79#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \80U_ASSERT(dst != NULL); \81U_ASSERT(src != NULL); \82U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \83} UPRV_BLOCK_MACRO_END84#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \85U_ASSERT(dst != NULL); \86U_ASSERT(src != NULL); \87U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \88} UPRV_BLOCK_MACRO_END89#endif9091/**92* \def UPRV_LENGTHOF93* Convenience macro to determine the length of a fixed array at compile-time.94* @param array A fixed length array95* @return The length of the array, in elements96* @internal97*/98#define UPRV_LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))99#define uprv_memset(buffer, mark, size) U_STANDARD_CPP_NAMESPACE memset(buffer, mark, size)100#define uprv_memcmp(buffer1, buffer2, size) U_STANDARD_CPP_NAMESPACE memcmp(buffer1, buffer2,size)101#define uprv_memchr(ptr, value, num) U_STANDARD_CPP_NAMESPACE memchr(ptr, value, num)102103U_CAPI void * U_EXPORT2104uprv_malloc(size_t s) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR(1);105106U_CAPI void * U_EXPORT2107uprv_realloc(void *mem, size_t size) U_ALLOC_SIZE_ATTR(2);108109U_CAPI void U_EXPORT2110uprv_free(void *mem);111112U_CAPI void * U_EXPORT2113uprv_calloc(size_t num, size_t size) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR2(1,2);114115/**116* Get the least significant bits of a pointer (a memory address).117* For example, with a mask of 3, the macro gets the 2 least significant bits,118* which will be 0 if the pointer is 32-bit (4-byte) aligned.119*120* uintptr_t is the most appropriate integer type to cast to.121*/122#define U_POINTER_MASK_LSB(ptr, mask) ((uintptr_t)(ptr) & (mask))123124/**125* Create & return an instance of "type" in statically allocated storage.126* e.g.127* static std::mutex *myMutex = STATIC_NEW(std::mutex);128* To destroy an object created in this way, invoke the destructor explicitly, e.g.129* myMutex->~mutex();130* DO NOT use delete.131* DO NOT use with class UMutex, which has specific support for static instances.132*133* STATIC_NEW is intended for use when134* - We want a static (or global) object.135* - We don't want it to ever be destructed, or to explicitly control destruction,136* to avoid use-after-destruction problems.137* - We want to avoid an ordinary heap allocated object,138* to avoid the possibility of memory allocation failures, and139* to avoid memory leak reports, from valgrind, for example.140* This is defined as a macro rather than a template function because each invocation141* must define distinct static storage for the object being returned.142*/143#define STATIC_NEW(type) [] () { \144alignas(type) static char storage[sizeof(type)]; \145return new(storage) type();} ()146147/**148* Heap clean up function, called from u_cleanup()149* Clears any user heap functions from u_setMemoryFunctions()150* Does NOT deallocate any remaining allocated memory.151*/152U_CFUNC UBool153cmemory_cleanup(void);154155/**156* A function called by <TT>uhash_remove</TT>,157* <TT>uhash_close</TT>, or <TT>uhash_put</TT> to delete158* an existing key or value.159* @param obj A key or value stored in a hashtable160* @see uprv_deleteUObject161*/162typedef void U_CALLCONV UObjectDeleter(void* obj);163164/**165* Deleter for UObject instances.166* Works for all subclasses of UObject because it has a virtual destructor.167*/168U_CAPI void U_EXPORT2169uprv_deleteUObject(void *obj);170171#ifdef __cplusplus172173#include <utility>174#include "unicode/uobject.h"175176U_NAMESPACE_BEGIN177178/**179* "Smart pointer" class, deletes memory via uprv_free().180* For most methods see the LocalPointerBase base class.181* Adds operator[] for array item access.182*183* @see LocalPointerBase184*/185template<typename T>186class LocalMemory : public LocalPointerBase<T> {187public:188using LocalPointerBase<T>::operator*;189using LocalPointerBase<T>::operator->;190/**191* Constructor takes ownership.192* @param p simple pointer to an array of T items that is adopted193*/194explicit LocalMemory(T *p=nullptr) : LocalPointerBase<T>(p) {}195/**196* Move constructor, leaves src with isNull().197* @param src source smart pointer198*/199LocalMemory(LocalMemory<T> &&src) noexcept : LocalPointerBase<T>(src.ptr) {200src.ptr=nullptr;201}202/**203* Destructor deletes the memory it owns.204*/205~LocalMemory() {206uprv_free(LocalPointerBase<T>::ptr);207}208/**209* Move assignment operator, leaves src with isNull().210* The behavior is undefined if *this and src are the same object.211* @param src source smart pointer212* @return *this213*/214LocalMemory<T> &operator=(LocalMemory<T> &&src) noexcept {215uprv_free(LocalPointerBase<T>::ptr);216LocalPointerBase<T>::ptr=src.ptr;217src.ptr=nullptr;218return *this;219}220/**221* Swap pointers.222* @param other other smart pointer223*/224void swap(LocalMemory<T> &other) noexcept {225T *temp=LocalPointerBase<T>::ptr;226LocalPointerBase<T>::ptr=other.ptr;227other.ptr=temp;228}229/**230* Non-member LocalMemory swap function.231* @param p1 will get p2's pointer232* @param p2 will get p1's pointer233*/234friend inline void swap(LocalMemory<T> &p1, LocalMemory<T> &p2) noexcept {235p1.swap(p2);236}237/**238* Deletes the array it owns,239* and adopts (takes ownership of) the one passed in.240* @param p simple pointer to an array of T items that is adopted241*/242void adoptInstead(T *p) {243uprv_free(LocalPointerBase<T>::ptr);244LocalPointerBase<T>::ptr=p;245}246/**247* Deletes the array it owns, allocates a new one and reset its bytes to 0.248* Returns the new array pointer.249* If the allocation fails, then the current array is unchanged and250* this method returns nullptr.251* @param newCapacity must be >0252* @return the allocated array pointer, or nullptr if the allocation failed253*/254inline T *allocateInsteadAndReset(int32_t newCapacity=1);255/**256* Deletes the array it owns and allocates a new one, copying length T items.257* Returns the new array pointer.258* If the allocation fails, then the current array is unchanged and259* this method returns nullptr.260* @param newCapacity must be >0261* @param length number of T items to be copied from the old array to the new one;262* must be no more than the capacity of the old array,263* which the caller must track because the LocalMemory does not track it264* @return the allocated array pointer, or nullptr if the allocation failed265*/266inline T *allocateInsteadAndCopy(int32_t newCapacity=1, int32_t length=0);267/**268* Array item access (writable).269* No index bounds check.270* @param i array index271* @return reference to the array item272*/273T &operator[](ptrdiff_t i) const { return LocalPointerBase<T>::ptr[i]; }274};275276template<typename T>277inline T *LocalMemory<T>::allocateInsteadAndReset(int32_t newCapacity) {278if(newCapacity>0) {279T *p=(T *)uprv_malloc(newCapacity*sizeof(T));280if(p!=nullptr) {281uprv_memset(p, 0, newCapacity*sizeof(T));282uprv_free(LocalPointerBase<T>::ptr);283LocalPointerBase<T>::ptr=p;284}285return p;286} else {287return nullptr;288}289}290291292template<typename T>293inline T *LocalMemory<T>::allocateInsteadAndCopy(int32_t newCapacity, int32_t length) {294if(newCapacity>0) {295T *p=(T *)uprv_malloc(newCapacity*sizeof(T));296if(p!=nullptr) {297if(length>0) {298if(length>newCapacity) {299length=newCapacity;300}301uprv_memcpy(p, LocalPointerBase<T>::ptr, (size_t)length*sizeof(T));302}303uprv_free(LocalPointerBase<T>::ptr);304LocalPointerBase<T>::ptr=p;305}306return p;307} else {308return nullptr;309}310}311312/**313* Simple array/buffer management class using uprv_malloc() and uprv_free().314* Provides an internal array with fixed capacity. Can alias another array315* or allocate one.316*317* The array address is properly aligned for type T. It might not be properly318* aligned for types larger than T (or larger than the largest subtype of T).319*320* Unlike LocalMemory and LocalArray, this class never adopts321* (takes ownership of) another array.322*323* WARNING: MaybeStackArray only works with primitive (plain-old data) types.324* It does NOT know how to call a destructor! If you work with classes with325* destructors, consider:326*327* - LocalArray in localpointer.h if you know the length ahead of time328* - MaybeStackVector if you know the length at runtime329*/330template<typename T, int32_t stackCapacity>331class MaybeStackArray {332public:333// No heap allocation. Use only on the stack.334static void* U_EXPORT2 operator new(size_t) noexcept = delete;335static void* U_EXPORT2 operator new[](size_t) noexcept = delete;336static void* U_EXPORT2 operator new(size_t, void*) noexcept = delete;337338/**339* Default constructor initializes with internal T[stackCapacity] buffer.340*/341MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(false) {}342/**343* Automatically allocates the heap array if the argument is larger than the stack capacity.344* Intended for use when an approximate capacity is known at compile time but the true345* capacity is not known until runtime.346*/347MaybeStackArray(int32_t newCapacity, UErrorCode status) : MaybeStackArray() {348if (U_FAILURE(status)) {349return;350}351if (capacity < newCapacity) {352if (resize(newCapacity) == nullptr) {353status = U_MEMORY_ALLOCATION_ERROR;354}355}356}357/**358* Destructor deletes the array (if owned).359*/360~MaybeStackArray() { releaseArray(); }361/**362* Move constructor: transfers ownership or copies the stack array.363*/364MaybeStackArray(MaybeStackArray<T, stackCapacity> &&src) noexcept;365/**366* Move assignment: transfers ownership or copies the stack array.367*/368MaybeStackArray<T, stackCapacity> &operator=(MaybeStackArray<T, stackCapacity> &&src) noexcept;369/**370* Returns the array capacity (number of T items).371* @return array capacity372*/373int32_t getCapacity() const { return capacity; }374/**375* Access without ownership change.376* @return the array pointer377*/378T *getAlias() const { return ptr; }379/**380* Returns the array limit. Simple convenience method.381* @return getAlias()+getCapacity()382*/383T *getArrayLimit() const { return getAlias()+capacity; }384// No "operator T *() const" because that can make385// expressions like mbs[index] ambiguous for some compilers.386/**387* Array item access (const).388* No index bounds check.389* @param i array index390* @return reference to the array item391*/392const T &operator[](ptrdiff_t i) const { return ptr[i]; }393/**394* Array item access (writable).395* No index bounds check.396* @param i array index397* @return reference to the array item398*/399T &operator[](ptrdiff_t i) { return ptr[i]; }400/**401* Deletes the array (if owned) and aliases another one, no transfer of ownership.402* If the arguments are illegal, then the current array is unchanged.403* @param otherArray must not be nullptr404* @param otherCapacity must be >0405*/406void aliasInstead(T *otherArray, int32_t otherCapacity) {407if(otherArray!=nullptr && otherCapacity>0) {408releaseArray();409ptr=otherArray;410capacity=otherCapacity;411needToRelease=false;412}413}414/**415* Deletes the array (if owned) and allocates a new one, copying length T items.416* Returns the new array pointer.417* If the allocation fails, then the current array is unchanged and418* this method returns nullptr.419* @param newCapacity can be less than or greater than the current capacity;420* must be >0421* @param length number of T items to be copied from the old array to the new one422* @return the allocated array pointer, or nullptr if the allocation failed423*/424inline T *resize(int32_t newCapacity, int32_t length=0);425/**426* Gives up ownership of the array if owned, or else clones it,427* copying length T items; resets itself to the internal stack array.428* Returns nullptr if the allocation failed.429* @param length number of T items to copy when cloning,430* and capacity of the clone when cloning431* @param resultCapacity will be set to the returned array's capacity (output-only)432* @return the array pointer;433* caller becomes responsible for deleting the array434*/435inline T *orphanOrClone(int32_t length, int32_t &resultCapacity);436437protected:438// Resizes the array to the size of src, then copies the contents of src.439void copyFrom(const MaybeStackArray &src, UErrorCode &status) {440if (U_FAILURE(status)) {441return;442}443if (this->resize(src.capacity, 0) == nullptr) {444status = U_MEMORY_ALLOCATION_ERROR;445return;446}447uprv_memcpy(this->ptr, src.ptr, (size_t)capacity * sizeof(T));448}449450private:451T *ptr;452int32_t capacity;453UBool needToRelease;454T stackArray[stackCapacity];455void releaseArray() {456if(needToRelease) {457uprv_free(ptr);458}459}460void resetToStackArray() {461ptr=stackArray;462capacity=stackCapacity;463needToRelease=false;464}465/* No comparison operators with other MaybeStackArray's. */466bool operator==(const MaybeStackArray & /*other*/) = delete;467bool operator!=(const MaybeStackArray & /*other*/) = delete;468/* No ownership transfer: No copy constructor, no assignment operator. */469MaybeStackArray(const MaybeStackArray & /*other*/) = delete;470void operator=(const MaybeStackArray & /*other*/) = delete;471};472473template<typename T, int32_t stackCapacity>474icu::MaybeStackArray<T, stackCapacity>::MaybeStackArray(475MaybeStackArray <T, stackCapacity>&& src) noexcept476: ptr(src.ptr), capacity(src.capacity), needToRelease(src.needToRelease) {477if (src.ptr == src.stackArray) {478ptr = stackArray;479uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);480} else {481src.resetToStackArray(); // take ownership away from src482}483}484485template<typename T, int32_t stackCapacity>486inline MaybeStackArray <T, stackCapacity>&487MaybeStackArray<T, stackCapacity>::operator=(MaybeStackArray <T, stackCapacity>&& src) noexcept {488releaseArray(); // in case this instance had its own memory allocated489capacity = src.capacity;490needToRelease = src.needToRelease;491if (src.ptr == src.stackArray) {492ptr = stackArray;493uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);494} else {495ptr = src.ptr;496src.resetToStackArray(); // take ownership away from src497}498return *this;499}500501template<typename T, int32_t stackCapacity>502inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {503if(newCapacity>0) {504#if U_DEBUG && defined(UPRV_MALLOC_COUNT)505::fprintf(::stderr, "MaybeStackArray (resize) alloc %d * %lu\n", newCapacity, sizeof(T));506#endif507T *p=(T *)uprv_malloc(newCapacity*sizeof(T));508if(p!=nullptr) {509if(length>0) {510if(length>capacity) {511length=capacity;512}513if(length>newCapacity) {514length=newCapacity;515}516uprv_memcpy(p, ptr, (size_t)length*sizeof(T));517}518releaseArray();519ptr=p;520capacity=newCapacity;521needToRelease=true;522}523return p;524} else {525return nullptr;526}527}528529template<typename T, int32_t stackCapacity>530inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) {531T *p;532if(needToRelease) {533p=ptr;534} else if(length<=0) {535return nullptr;536} else {537if(length>capacity) {538length=capacity;539}540p=(T *)uprv_malloc(length*sizeof(T));541#if U_DEBUG && defined(UPRV_MALLOC_COUNT)542::fprintf(::stderr,"MaybeStacArray (orphan) alloc %d * %lu\n", length,sizeof(T));543#endif544if(p==nullptr) {545return nullptr;546}547uprv_memcpy(p, ptr, (size_t)length*sizeof(T));548}549resultCapacity=length;550resetToStackArray();551return p;552}553554/**555* Variant of MaybeStackArray that allocates a header struct and an array556* in one contiguous memory block, using uprv_malloc() and uprv_free().557* Provides internal memory with fixed array capacity. Can alias another memory558* block or allocate one.559* The stackCapacity is the number of T items in the internal memory,560* not counting the H header.561* Unlike LocalMemory and LocalArray, this class never adopts562* (takes ownership of) another memory block.563*/564template<typename H, typename T, int32_t stackCapacity>565class MaybeStackHeaderAndArray {566public:567// No heap allocation. Use only on the stack.568static void* U_EXPORT2 operator new(size_t) noexcept = delete;569static void* U_EXPORT2 operator new[](size_t) noexcept = delete;570static void* U_EXPORT2 operator new(size_t, void*) noexcept = delete;571572/**573* Default constructor initializes with internal H+T[stackCapacity] buffer.574*/575MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(false) {}576/**577* Destructor deletes the memory (if owned).578*/579~MaybeStackHeaderAndArray() { releaseMemory(); }580/**581* Returns the array capacity (number of T items).582* @return array capacity583*/584int32_t getCapacity() const { return capacity; }585/**586* Access without ownership change.587* @return the header pointer588*/589H *getAlias() const { return ptr; }590/**591* Returns the array start.592* @return array start, same address as getAlias()+1593*/594T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }595/**596* Returns the array limit.597* @return array limit598*/599T *getArrayLimit() const { return getArrayStart()+capacity; }600/**601* Access without ownership change. Same as getAlias().602* A class instance can be used directly in expressions that take a T *.603* @return the header pointer604*/605operator H *() const { return ptr; }606/**607* Array item access (writable).608* No index bounds check.609* @param i array index610* @return reference to the array item611*/612T &operator[](ptrdiff_t i) { return getArrayStart()[i]; }613/**614* Deletes the memory block (if owned) and aliases another one, no transfer of ownership.615* If the arguments are illegal, then the current memory is unchanged.616* @param otherArray must not be nullptr617* @param otherCapacity must be >0618*/619void aliasInstead(H *otherMemory, int32_t otherCapacity) {620if(otherMemory!=nullptr && otherCapacity>0) {621releaseMemory();622ptr=otherMemory;623capacity=otherCapacity;624needToRelease=false;625}626}627/**628* Deletes the memory block (if owned) and allocates a new one,629* copying the header and length T array items.630* Returns the new header pointer.631* If the allocation fails, then the current memory is unchanged and632* this method returns nullptr.633* @param newCapacity can be less than or greater than the current capacity;634* must be >0635* @param length number of T items to be copied from the old array to the new one636* @return the allocated pointer, or nullptr if the allocation failed637*/638inline H *resize(int32_t newCapacity, int32_t length=0);639/**640* Gives up ownership of the memory if owned, or else clones it,641* copying the header and length T array items; resets itself to the internal memory.642* Returns nullptr if the allocation failed.643* @param length number of T items to copy when cloning,644* and array capacity of the clone when cloning645* @param resultCapacity will be set to the returned array's capacity (output-only)646* @return the header pointer;647* caller becomes responsible for deleting the array648*/649inline H *orphanOrClone(int32_t length, int32_t &resultCapacity);650private:651H *ptr;652int32_t capacity;653UBool needToRelease;654// stackHeader must precede stackArray immediately.655H stackHeader;656T stackArray[stackCapacity];657void releaseMemory() {658if(needToRelease) {659uprv_free(ptr);660}661}662/* No comparison operators with other MaybeStackHeaderAndArray's. */663bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return false;}664bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return true;}665/* No ownership transfer: No copy constructor, no assignment operator. */666MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {}667void operator=(const MaybeStackHeaderAndArray & /*other*/) {}668};669670template<typename H, typename T, int32_t stackCapacity>671inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity,672int32_t length) {673if(newCapacity>=0) {674#if U_DEBUG && defined(UPRV_MALLOC_COUNT)675::fprintf(::stderr,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H),newCapacity,sizeof(T));676#endif677H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T));678if(p!=nullptr) {679if(length<0) {680length=0;681} else if(length>0) {682if(length>capacity) {683length=capacity;684}685if(length>newCapacity) {686length=newCapacity;687}688}689uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));690releaseMemory();691ptr=p;692capacity=newCapacity;693needToRelease=true;694}695return p;696} else {697return nullptr;698}699}700701template<typename H, typename T, int32_t stackCapacity>702inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length,703int32_t &resultCapacity) {704H *p;705if(needToRelease) {706p=ptr;707} else {708if(length<0) {709length=0;710} else if(length>capacity) {711length=capacity;712}713#if U_DEBUG && defined(UPRV_MALLOC_COUNT)714::fprintf(::stderr,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H),length,sizeof(T));715#endif716p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T));717if(p==nullptr) {718return nullptr;719}720uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));721}722resultCapacity=length;723ptr=&stackHeader;724capacity=stackCapacity;725needToRelease=false;726return p;727}728729/**730* A simple memory management class that creates new heap allocated objects (of731* any class that has a public constructor), keeps track of them and eventually732* deletes them all in its own destructor.733*734* A typical use-case would be code like this:735*736* MemoryPool<MyType> pool;737*738* MyType* o1 = pool.create();739* if (o1 != nullptr) {740* foo(o1);741* }742*743* MyType* o2 = pool.create(1, 2, 3);744* if (o2 != nullptr) {745* bar(o2);746* }747*748* // MemoryPool will take care of deleting the MyType objects.749*750* It doesn't do anything more than that, and is intentionally kept minimalist.751*/752template<typename T, int32_t stackCapacity = 8>753class MemoryPool : public UMemory {754public:755MemoryPool() : fCount(0), fPool() {}756757~MemoryPool() {758for (int32_t i = 0; i < fCount; ++i) {759delete fPool[i];760}761}762763MemoryPool(const MemoryPool&) = delete;764MemoryPool& operator=(const MemoryPool&) = delete;765766MemoryPool(MemoryPool&& other) noexcept : fCount(other.fCount),767fPool(std::move(other.fPool)) {768other.fCount = 0;769}770771MemoryPool& operator=(MemoryPool&& other) noexcept {772// Since `this` may contain instances that need to be deleted, we can't773// just throw them away and replace them with `other`. The normal way of774// dealing with this in C++ is to swap `this` and `other`, rather than775// simply overwrite: the destruction of `other` can then take care of776// running MemoryPool::~MemoryPool() over the still-to-be-deallocated777// instances.778std::swap(fCount, other.fCount);779std::swap(fPool, other.fPool);780return *this;781}782783/**784* Creates a new object of typename T, by forwarding any and all arguments785* to the typename T constructor.786*787* @param args Arguments to be forwarded to the typename T constructor.788* @return A pointer to the newly created object, or nullptr on error.789*/790template<typename... Args>791T* create(Args&&... args) {792int32_t capacity = fPool.getCapacity();793if (fCount == capacity &&794fPool.resize(capacity == stackCapacity ? 4 * capacity : 2 * capacity,795capacity) == nullptr) {796return nullptr;797}798return fPool[fCount++] = new T(std::forward<Args>(args)...);799}800801template <typename... Args>802T* createAndCheckErrorCode(UErrorCode &status, Args &&... args) {803if (U_FAILURE(status)) {804return nullptr;805}806T *pointer = this->create(args...);807if (U_SUCCESS(status) && pointer == nullptr) {808status = U_MEMORY_ALLOCATION_ERROR;809}810return pointer;811}812813/**814* @return Number of elements that have been allocated.815*/816int32_t count() const {817return fCount;818}819820protected:821int32_t fCount;822MaybeStackArray<T*, stackCapacity> fPool;823};824825/**826* An internal Vector-like implementation based on MemoryPool.827*828* Heap-allocates each element and stores pointers.829*830* To append an item to the vector, use emplaceBack.831*832* MaybeStackVector<MyType> vector;833* MyType* element = vector.emplaceBack();834* if (!element) {835* status = U_MEMORY_ALLOCATION_ERROR;836* }837* // do stuff with element838*839* To loop over the vector, use a for loop with indices:840*841* for (int32_t i = 0; i < vector.length(); i++) {842* MyType* element = vector[i];843* }844*/845template<typename T, int32_t stackCapacity = 8>846class MaybeStackVector : protected MemoryPool<T, stackCapacity> {847public:848template<typename... Args>849T* emplaceBack(Args&&... args) {850return this->create(args...);851}852853template <typename... Args>854T *emplaceBackAndCheckErrorCode(UErrorCode &status, Args &&... args) {855return this->createAndCheckErrorCode(status, args...);856}857858int32_t length() const {859return this->fCount;860}861862T** getAlias() {863return this->fPool.getAlias();864}865866const T *const *getAlias() const {867return this->fPool.getAlias();868}869870/**871* Array item access (read-only).872* No index bounds check.873* @param i array index874* @return reference to the array item875*/876const T* operator[](ptrdiff_t i) const {877return this->fPool[i];878}879880/**881* Array item access (writable).882* No index bounds check.883* @param i array index884* @return reference to the array item885*/886T* operator[](ptrdiff_t i) {887return this->fPool[i];888}889};890891892U_NAMESPACE_END893894#endif /* __cplusplus */895#endif /* CMEMORY_H */896897898