// © 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;336#if U_HAVE_PLACEMENT_NEW337static void* U_EXPORT2 operator new(size_t, void*) noexcept = delete;338#endif339340/**341* Default constructor initializes with internal T[stackCapacity] buffer.342*/343MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(false) {}344/**345* Automatically allocates the heap array if the argument is larger than the stack capacity.346* Intended for use when an approximate capacity is known at compile time but the true347* capacity is not known until runtime.348*/349MaybeStackArray(int32_t newCapacity, UErrorCode status) : MaybeStackArray() {350if (U_FAILURE(status)) {351return;352}353if (capacity < newCapacity) {354if (resize(newCapacity) == nullptr) {355status = U_MEMORY_ALLOCATION_ERROR;356}357}358}359/**360* Destructor deletes the array (if owned).361*/362~MaybeStackArray() { releaseArray(); }363/**364* Move constructor: transfers ownership or copies the stack array.365*/366MaybeStackArray(MaybeStackArray<T, stackCapacity> &&src) noexcept;367/**368* Move assignment: transfers ownership or copies the stack array.369*/370MaybeStackArray<T, stackCapacity> &operator=(MaybeStackArray<T, stackCapacity> &&src) noexcept;371/**372* Returns the array capacity (number of T items).373* @return array capacity374*/375int32_t getCapacity() const { return capacity; }376/**377* Access without ownership change.378* @return the array pointer379*/380T *getAlias() const { return ptr; }381/**382* Returns the array limit. Simple convenience method.383* @return getAlias()+getCapacity()384*/385T *getArrayLimit() const { return getAlias()+capacity; }386// No "operator T *() const" because that can make387// expressions like mbs[index] ambiguous for some compilers.388/**389* Array item access (const).390* No index bounds check.391* @param i array index392* @return reference to the array item393*/394const T &operator[](ptrdiff_t i) const { return ptr[i]; }395/**396* Array item access (writable).397* No index bounds check.398* @param i array index399* @return reference to the array item400*/401T &operator[](ptrdiff_t i) { return ptr[i]; }402/**403* Deletes the array (if owned) and aliases another one, no transfer of ownership.404* If the arguments are illegal, then the current array is unchanged.405* @param otherArray must not be nullptr406* @param otherCapacity must be >0407*/408void aliasInstead(T *otherArray, int32_t otherCapacity) {409if(otherArray!=nullptr && otherCapacity>0) {410releaseArray();411ptr=otherArray;412capacity=otherCapacity;413needToRelease=false;414}415}416/**417* Deletes the array (if owned) and allocates a new one, copying length T items.418* Returns the new array pointer.419* If the allocation fails, then the current array is unchanged and420* this method returns nullptr.421* @param newCapacity can be less than or greater than the current capacity;422* must be >0423* @param length number of T items to be copied from the old array to the new one424* @return the allocated array pointer, or nullptr if the allocation failed425*/426inline T *resize(int32_t newCapacity, int32_t length=0);427/**428* Gives up ownership of the array if owned, or else clones it,429* copying length T items; resets itself to the internal stack array.430* Returns nullptr if the allocation failed.431* @param length number of T items to copy when cloning,432* and capacity of the clone when cloning433* @param resultCapacity will be set to the returned array's capacity (output-only)434* @return the array pointer;435* caller becomes responsible for deleting the array436*/437inline T *orphanOrClone(int32_t length, int32_t &resultCapacity);438439protected:440// Resizes the array to the size of src, then copies the contents of src.441void copyFrom(const MaybeStackArray &src, UErrorCode &status) {442if (U_FAILURE(status)) {443return;444}445if (this->resize(src.capacity, 0) == nullptr) {446status = U_MEMORY_ALLOCATION_ERROR;447return;448}449uprv_memcpy(this->ptr, src.ptr, (size_t)capacity * sizeof(T));450}451452private:453T *ptr;454int32_t capacity;455UBool needToRelease;456T stackArray[stackCapacity];457void releaseArray() {458if(needToRelease) {459uprv_free(ptr);460}461}462void resetToStackArray() {463ptr=stackArray;464capacity=stackCapacity;465needToRelease=false;466}467/* No comparison operators with other MaybeStackArray's. */468bool operator==(const MaybeStackArray & /*other*/) = delete;469bool operator!=(const MaybeStackArray & /*other*/) = delete;470/* No ownership transfer: No copy constructor, no assignment operator. */471MaybeStackArray(const MaybeStackArray & /*other*/) = delete;472void operator=(const MaybeStackArray & /*other*/) = delete;473};474475template<typename T, int32_t stackCapacity>476icu::MaybeStackArray<T, stackCapacity>::MaybeStackArray(477MaybeStackArray <T, stackCapacity>&& src) noexcept478: ptr(src.ptr), capacity(src.capacity), needToRelease(src.needToRelease) {479if (src.ptr == src.stackArray) {480ptr = stackArray;481uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);482} else {483src.resetToStackArray(); // take ownership away from src484}485}486487template<typename T, int32_t stackCapacity>488inline MaybeStackArray <T, stackCapacity>&489MaybeStackArray<T, stackCapacity>::operator=(MaybeStackArray <T, stackCapacity>&& src) noexcept {490releaseArray(); // in case this instance had its own memory allocated491capacity = src.capacity;492needToRelease = src.needToRelease;493if (src.ptr == src.stackArray) {494ptr = stackArray;495uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);496} else {497ptr = src.ptr;498src.resetToStackArray(); // take ownership away from src499}500return *this;501}502503template<typename T, int32_t stackCapacity>504inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {505if(newCapacity>0) {506#if U_DEBUG && defined(UPRV_MALLOC_COUNT)507::fprintf(::stderr, "MaybeStackArray (resize) alloc %d * %lu\n", newCapacity, sizeof(T));508#endif509T *p=(T *)uprv_malloc(newCapacity*sizeof(T));510if(p!=nullptr) {511if(length>0) {512if(length>capacity) {513length=capacity;514}515if(length>newCapacity) {516length=newCapacity;517}518uprv_memcpy(p, ptr, (size_t)length*sizeof(T));519}520releaseArray();521ptr=p;522capacity=newCapacity;523needToRelease=true;524}525return p;526} else {527return nullptr;528}529}530531template<typename T, int32_t stackCapacity>532inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) {533T *p;534if(needToRelease) {535p=ptr;536} else if(length<=0) {537return nullptr;538} else {539if(length>capacity) {540length=capacity;541}542p=(T *)uprv_malloc(length*sizeof(T));543#if U_DEBUG && defined(UPRV_MALLOC_COUNT)544::fprintf(::stderr,"MaybeStacArray (orphan) alloc %d * %lu\n", length,sizeof(T));545#endif546if(p==nullptr) {547return nullptr;548}549uprv_memcpy(p, ptr, (size_t)length*sizeof(T));550}551resultCapacity=length;552resetToStackArray();553return p;554}555556/**557* Variant of MaybeStackArray that allocates a header struct and an array558* in one contiguous memory block, using uprv_malloc() and uprv_free().559* Provides internal memory with fixed array capacity. Can alias another memory560* block or allocate one.561* The stackCapacity is the number of T items in the internal memory,562* not counting the H header.563* Unlike LocalMemory and LocalArray, this class never adopts564* (takes ownership of) another memory block.565*/566template<typename H, typename T, int32_t stackCapacity>567class MaybeStackHeaderAndArray {568public:569// No heap allocation. Use only on the stack.570static void* U_EXPORT2 operator new(size_t) noexcept = delete;571static void* U_EXPORT2 operator new[](size_t) noexcept = delete;572#if U_HAVE_PLACEMENT_NEW573static void* U_EXPORT2 operator new(size_t, void*) noexcept = delete;574#endif575576/**577* Default constructor initializes with internal H+T[stackCapacity] buffer.578*/579MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(false) {}580/**581* Destructor deletes the memory (if owned).582*/583~MaybeStackHeaderAndArray() { releaseMemory(); }584/**585* Returns the array capacity (number of T items).586* @return array capacity587*/588int32_t getCapacity() const { return capacity; }589/**590* Access without ownership change.591* @return the header pointer592*/593H *getAlias() const { return ptr; }594/**595* Returns the array start.596* @return array start, same address as getAlias()+1597*/598T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }599/**600* Returns the array limit.601* @return array limit602*/603T *getArrayLimit() const { return getArrayStart()+capacity; }604/**605* Access without ownership change. Same as getAlias().606* A class instance can be used directly in expressions that take a T *.607* @return the header pointer608*/609operator H *() const { return ptr; }610/**611* Array item access (writable).612* No index bounds check.613* @param i array index614* @return reference to the array item615*/616T &operator[](ptrdiff_t i) { return getArrayStart()[i]; }617/**618* Deletes the memory block (if owned) and aliases another one, no transfer of ownership.619* If the arguments are illegal, then the current memory is unchanged.620* @param otherArray must not be nullptr621* @param otherCapacity must be >0622*/623void aliasInstead(H *otherMemory, int32_t otherCapacity) {624if(otherMemory!=nullptr && otherCapacity>0) {625releaseMemory();626ptr=otherMemory;627capacity=otherCapacity;628needToRelease=false;629}630}631/**632* Deletes the memory block (if owned) and allocates a new one,633* copying the header and length T array items.634* Returns the new header pointer.635* If the allocation fails, then the current memory is unchanged and636* this method returns nullptr.637* @param newCapacity can be less than or greater than the current capacity;638* must be >0639* @param length number of T items to be copied from the old array to the new one640* @return the allocated pointer, or nullptr if the allocation failed641*/642inline H *resize(int32_t newCapacity, int32_t length=0);643/**644* Gives up ownership of the memory if owned, or else clones it,645* copying the header and length T array items; resets itself to the internal memory.646* Returns nullptr if the allocation failed.647* @param length number of T items to copy when cloning,648* and array capacity of the clone when cloning649* @param resultCapacity will be set to the returned array's capacity (output-only)650* @return the header pointer;651* caller becomes responsible for deleting the array652*/653inline H *orphanOrClone(int32_t length, int32_t &resultCapacity);654private:655H *ptr;656int32_t capacity;657UBool needToRelease;658// stackHeader must precede stackArray immediately.659H stackHeader;660T stackArray[stackCapacity];661void releaseMemory() {662if(needToRelease) {663uprv_free(ptr);664}665}666/* No comparison operators with other MaybeStackHeaderAndArray's. */667bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return false;}668bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return true;}669/* No ownership transfer: No copy constructor, no assignment operator. */670MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {}671void operator=(const MaybeStackHeaderAndArray & /*other*/) {}672};673674template<typename H, typename T, int32_t stackCapacity>675inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity,676int32_t length) {677if(newCapacity>=0) {678#if U_DEBUG && defined(UPRV_MALLOC_COUNT)679::fprintf(::stderr,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H),newCapacity,sizeof(T));680#endif681H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T));682if(p!=nullptr) {683if(length<0) {684length=0;685} else if(length>0) {686if(length>capacity) {687length=capacity;688}689if(length>newCapacity) {690length=newCapacity;691}692}693uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));694releaseMemory();695ptr=p;696capacity=newCapacity;697needToRelease=true;698}699return p;700} else {701return nullptr;702}703}704705template<typename H, typename T, int32_t stackCapacity>706inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length,707int32_t &resultCapacity) {708H *p;709if(needToRelease) {710p=ptr;711} else {712if(length<0) {713length=0;714} else if(length>capacity) {715length=capacity;716}717#if U_DEBUG && defined(UPRV_MALLOC_COUNT)718::fprintf(::stderr,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H),length,sizeof(T));719#endif720p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T));721if(p==nullptr) {722return nullptr;723}724uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));725}726resultCapacity=length;727ptr=&stackHeader;728capacity=stackCapacity;729needToRelease=false;730return p;731}732733/**734* A simple memory management class that creates new heap allocated objects (of735* any class that has a public constructor), keeps track of them and eventually736* deletes them all in its own destructor.737*738* A typical use-case would be code like this:739*740* MemoryPool<MyType> pool;741*742* MyType* o1 = pool.create();743* if (o1 != nullptr) {744* foo(o1);745* }746*747* MyType* o2 = pool.create(1, 2, 3);748* if (o2 != nullptr) {749* bar(o2);750* }751*752* // MemoryPool will take care of deleting the MyType objects.753*754* It doesn't do anything more than that, and is intentionally kept minimalist.755*/756template<typename T, int32_t stackCapacity = 8>757class MemoryPool : public UMemory {758public:759MemoryPool() : fCount(0), fPool() {}760761~MemoryPool() {762for (int32_t i = 0; i < fCount; ++i) {763delete fPool[i];764}765}766767MemoryPool(const MemoryPool&) = delete;768MemoryPool& operator=(const MemoryPool&) = delete;769770MemoryPool(MemoryPool&& other) noexcept : fCount(other.fCount),771fPool(std::move(other.fPool)) {772other.fCount = 0;773}774775MemoryPool& operator=(MemoryPool&& other) noexcept {776// Since `this` may contain instances that need to be deleted, we can't777// just throw them away and replace them with `other`. The normal way of778// dealing with this in C++ is to swap `this` and `other`, rather than779// simply overwrite: the destruction of `other` can then take care of780// running MemoryPool::~MemoryPool() over the still-to-be-deallocated781// instances.782std::swap(fCount, other.fCount);783std::swap(fPool, other.fPool);784return *this;785}786787/**788* Creates a new object of typename T, by forwarding any and all arguments789* to the typename T constructor.790*791* @param args Arguments to be forwarded to the typename T constructor.792* @return A pointer to the newly created object, or nullptr on error.793*/794template<typename... Args>795T* create(Args&&... args) {796int32_t capacity = fPool.getCapacity();797if (fCount == capacity &&798fPool.resize(capacity == stackCapacity ? 4 * capacity : 2 * capacity,799capacity) == nullptr) {800return nullptr;801}802return fPool[fCount++] = new T(std::forward<Args>(args)...);803}804805template <typename... Args>806T* createAndCheckErrorCode(UErrorCode &status, Args &&... args) {807if (U_FAILURE(status)) {808return nullptr;809}810T *pointer = this->create(args...);811if (U_SUCCESS(status) && pointer == nullptr) {812status = U_MEMORY_ALLOCATION_ERROR;813}814return pointer;815}816817/**818* @return Number of elements that have been allocated.819*/820int32_t count() const {821return fCount;822}823824protected:825int32_t fCount;826MaybeStackArray<T*, stackCapacity> fPool;827};828829/**830* An internal Vector-like implementation based on MemoryPool.831*832* Heap-allocates each element and stores pointers.833*834* To append an item to the vector, use emplaceBack.835*836* MaybeStackVector<MyType> vector;837* MyType* element = vector.emplaceBack();838* if (!element) {839* status = U_MEMORY_ALLOCATION_ERROR;840* }841* // do stuff with element842*843* To loop over the vector, use a for loop with indices:844*845* for (int32_t i = 0; i < vector.length(); i++) {846* MyType* element = vector[i];847* }848*/849template<typename T, int32_t stackCapacity = 8>850class MaybeStackVector : protected MemoryPool<T, stackCapacity> {851public:852template<typename... Args>853T* emplaceBack(Args&&... args) {854return this->create(args...);855}856857template <typename... Args>858T *emplaceBackAndCheckErrorCode(UErrorCode &status, Args &&... args) {859return this->createAndCheckErrorCode(status, args...);860}861862int32_t length() const {863return this->fCount;864}865866T** getAlias() {867return this->fPool.getAlias();868}869870const T *const *getAlias() const {871return this->fPool.getAlias();872}873874/**875* Array item access (read-only).876* No index bounds check.877* @param i array index878* @return reference to the array item879*/880const T* operator[](ptrdiff_t i) const {881return this->fPool[i];882}883884/**885* Array item access (writable).886* No index bounds check.887* @param i array index888* @return reference to the array item889*/890T* operator[](ptrdiff_t i) {891return this->fPool[i];892}893};894895896U_NAMESPACE_END897898#endif /* __cplusplus */899#endif /* CMEMORY_H */900901902