tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

cmemory.h (30667B)


      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 #include "uassert.h"
     35 
     36 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
     37 #include <stdio.h>
     38 #endif
     39 
     40 // uprv_memcpy and uprv_memmove
     41 #if defined(__clang__)
     42 #define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
     43    /* Suppress warnings about addresses that will never be NULL */ \
     44    _Pragma("clang diagnostic push") \
     45    _Pragma("clang diagnostic ignored \"-Waddress\"") \
     46    U_ASSERT(dst != NULL); \
     47    U_ASSERT(src != NULL); \
     48    _Pragma("clang diagnostic pop") \
     49    U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
     50 } UPRV_BLOCK_MACRO_END
     51 #define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
     52    /* Suppress warnings about addresses that will never be NULL */ \
     53    _Pragma("clang diagnostic push") \
     54    _Pragma("clang diagnostic ignored \"-Waddress\"") \
     55    U_ASSERT(dst != NULL); \
     56    U_ASSERT(src != NULL); \
     57    _Pragma("clang diagnostic pop") \
     58    U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
     59 } UPRV_BLOCK_MACRO_END
     60 #elif defined(__GNUC__)
     61 #define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
     62    /* Suppress warnings about addresses that will never be NULL */ \
     63    _Pragma("GCC diagnostic push") \
     64    _Pragma("GCC diagnostic ignored \"-Waddress\"") \
     65    U_ASSERT(dst != NULL); \
     66    U_ASSERT(src != NULL); \
     67    _Pragma("GCC diagnostic pop") \
     68    U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
     69 } UPRV_BLOCK_MACRO_END
     70 #define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
     71    /* Suppress warnings about addresses that will never be NULL */ \
     72    _Pragma("GCC diagnostic push") \
     73    _Pragma("GCC diagnostic ignored \"-Waddress\"") \
     74    U_ASSERT(dst != NULL); \
     75    U_ASSERT(src != NULL); \
     76    _Pragma("GCC diagnostic pop") \
     77    U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
     78 } UPRV_BLOCK_MACRO_END
     79 #else
     80 #define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
     81    U_ASSERT(dst != NULL); \
     82    U_ASSERT(src != NULL); \
     83    U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
     84 } UPRV_BLOCK_MACRO_END
     85 #define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
     86    U_ASSERT(dst != NULL); \
     87    U_ASSERT(src != NULL); \
     88    U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
     89 } UPRV_BLOCK_MACRO_END
     90 #endif
     91 
     92 /**
     93 * \def UPRV_LENGTHOF
     94 * Convenience macro to determine the length of a fixed array at compile-time.
     95 * @param array A fixed length array
     96 * @return The length of the array, in elements
     97 * @internal
     98 */
     99 #define UPRV_LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
    100 #define uprv_memset(buffer, mark, size) U_STANDARD_CPP_NAMESPACE memset(buffer, mark, size)
    101 #define uprv_memcmp(buffer1, buffer2, size) U_STANDARD_CPP_NAMESPACE memcmp(buffer1, buffer2,size)
    102 #define uprv_memchr(ptr, value, num) U_STANDARD_CPP_NAMESPACE memchr(ptr, value, num)
    103 
    104 U_CAPI void * U_EXPORT2
    105 uprv_malloc(size_t s) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR(1);
    106 
    107 U_CAPI void * U_EXPORT2
    108 uprv_realloc(void *mem, size_t size) U_ALLOC_SIZE_ATTR(2);
    109 
    110 U_CAPI void U_EXPORT2
    111 uprv_free(void *mem);
    112 
    113 U_CAPI void * U_EXPORT2
    114 uprv_calloc(size_t num, size_t size) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR2(1,2);
    115 
    116 /**
    117 * Get the least significant bits of a pointer (a memory address).
    118 * For example, with a mask of 3, the macro gets the 2 least significant bits,
    119 * which will be 0 if the pointer is 32-bit (4-byte) aligned.
    120 *
    121 * uintptr_t is the most appropriate integer type to cast to.
    122 */
    123 #define U_POINTER_MASK_LSB(ptr, mask) ((uintptr_t)(ptr) & (mask))
    124 
    125 /**
    126 * Create & return an instance of "type" in statically allocated storage.
    127 * e.g.
    128 *    static std::mutex *myMutex = STATIC_NEW(std::mutex);
    129 * To destroy an object created in this way, invoke the destructor explicitly, e.g.
    130 *    myMutex->~mutex();
    131 * DO NOT use delete.
    132 * DO NOT use with class UMutex, which has specific support for static instances.
    133 *
    134 * STATIC_NEW is intended for use when
    135 *   - We want a static (or global) object.
    136 *   - We don't want it to ever be destructed, or to explicitly control destruction,
    137 *     to avoid use-after-destruction problems.
    138 *   - We want to avoid an ordinary heap allocated object,
    139 *     to avoid the possibility of memory allocation failures, and
    140 *     to avoid memory leak reports, from valgrind, for example.
    141 * This is defined as a macro rather than a template function because each invocation
    142 * must define distinct static storage for the object being returned.
    143 */
    144 #define STATIC_NEW(type) [] () { \
    145    alignas(type) static char storage[sizeof(type)]; \
    146    return new(storage) type();} ()
    147 
    148 /**
    149  *  Heap clean up function, called from u_cleanup()
    150  *    Clears any user heap functions from u_setMemoryFunctions()
    151  *    Does NOT deallocate any remaining allocated memory.
    152  */
    153 U_CFUNC UBool 
    154 cmemory_cleanup(void);
    155 
    156 /**
    157 * A function called by <TT>uhash_remove</TT>,
    158 * <TT>uhash_close</TT>, or <TT>uhash_put</TT> to delete
    159 * an existing key or value.
    160 * @param obj A key or value stored in a hashtable
    161 * @see uprv_deleteUObject
    162 */
    163 typedef void U_CALLCONV UObjectDeleter(void* obj);
    164 
    165 /**
    166 * Deleter for UObject instances.
    167 * Works for all subclasses of UObject because it has a virtual destructor.
    168 */
    169 U_CAPI void U_EXPORT2
    170 uprv_deleteUObject(void *obj);
    171 
    172 #ifdef __cplusplus
    173 
    174 #include <utility>
    175 #include "unicode/uobject.h"
    176 
    177 U_NAMESPACE_BEGIN
    178 
    179 /**
    180 * "Smart pointer" class, deletes memory via uprv_free().
    181 * For most methods see the LocalPointerBase base class.
    182 * Adds operator[] for array item access.
    183 *
    184 * @see LocalPointerBase
    185 */
    186 template<typename T>
    187 class LocalMemory : public LocalPointerBase<T> {
    188 public:
    189    using LocalPointerBase<T>::operator*;
    190    using LocalPointerBase<T>::operator->;
    191    /**
    192     * Constructor takes ownership.
    193     * @param p simple pointer to an array of T items that is adopted
    194     */
    195    explicit LocalMemory(T *p=nullptr) : LocalPointerBase<T>(p) {}
    196    /**
    197     * Move constructor, leaves src with isNull().
    198     * @param src source smart pointer
    199     */
    200    LocalMemory(LocalMemory<T> &&src) noexcept : LocalPointerBase<T>(src.ptr) {
    201        src.ptr=nullptr;
    202    }
    203    /**
    204     * Destructor deletes the memory it owns.
    205     */
    206    ~LocalMemory() {
    207        uprv_free(LocalPointerBase<T>::ptr);
    208    }
    209    /**
    210     * Move assignment operator, leaves src with isNull().
    211     * The behavior is undefined if *this and src are the same object.
    212     * @param src source smart pointer
    213     * @return *this
    214     */
    215    LocalMemory<T> &operator=(LocalMemory<T> &&src) noexcept {
    216        uprv_free(LocalPointerBase<T>::ptr);
    217        LocalPointerBase<T>::ptr=src.ptr;
    218        src.ptr=nullptr;
    219        return *this;
    220    }
    221    /**
    222     * Swap pointers.
    223     * @param other other smart pointer
    224     */
    225    void swap(LocalMemory<T> &other) noexcept {
    226        T *temp=LocalPointerBase<T>::ptr;
    227        LocalPointerBase<T>::ptr=other.ptr;
    228        other.ptr=temp;
    229    }
    230    /**
    231     * Non-member LocalMemory swap function.
    232     * @param p1 will get p2's pointer
    233     * @param p2 will get p1's pointer
    234     */
    235    friend inline void swap(LocalMemory<T> &p1, LocalMemory<T> &p2) noexcept {
    236        p1.swap(p2);
    237    }
    238    /**
    239     * Deletes the array it owns,
    240     * and adopts (takes ownership of) the one passed in.
    241     * @param p simple pointer to an array of T items that is adopted
    242     */
    243    void adoptInstead(T *p) {
    244        uprv_free(LocalPointerBase<T>::ptr);
    245        LocalPointerBase<T>::ptr=p;
    246    }
    247    /**
    248     * Deletes the array it owns, allocates a new one and reset its bytes to 0.
    249     * Returns the new array pointer.
    250     * If the allocation fails, then the current array is unchanged and
    251     * this method returns nullptr.
    252     * @param newCapacity must be >0
    253     * @return the allocated array pointer, or nullptr if the allocation failed
    254     */
    255    inline T *allocateInsteadAndReset(int32_t newCapacity=1);
    256    /**
    257     * Deletes the array it owns and allocates a new one, copying length T items.
    258     * Returns the new array pointer.
    259     * If the allocation fails, then the current array is unchanged and
    260     * this method returns nullptr.
    261     * @param newCapacity must be >0
    262     * @param length number of T items to be copied from the old array to the new one;
    263     *               must be no more than the capacity of the old array,
    264     *               which the caller must track because the LocalMemory does not track it
    265     * @return the allocated array pointer, or nullptr if the allocation failed
    266     */
    267    inline T *allocateInsteadAndCopy(int32_t newCapacity=1, int32_t length=0);
    268    /**
    269     * Array item access (writable).
    270     * No index bounds check.
    271     * @param i array index
    272     * @return reference to the array item
    273     */
    274    T &operator[](ptrdiff_t i) const { return LocalPointerBase<T>::ptr[i]; }
    275 };
    276 
    277 template<typename T>
    278 inline T *LocalMemory<T>::allocateInsteadAndReset(int32_t newCapacity) {
    279    if(newCapacity>0) {
    280        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
    281        if(p!=nullptr) {
    282            uprv_memset(p, 0, newCapacity*sizeof(T));
    283            uprv_free(LocalPointerBase<T>::ptr);
    284            LocalPointerBase<T>::ptr=p;
    285        }
    286        return p;
    287    } else {
    288        return nullptr;
    289    }
    290 }
    291 
    292 
    293 template<typename T>
    294 inline T *LocalMemory<T>::allocateInsteadAndCopy(int32_t newCapacity, int32_t length) {
    295    if(newCapacity>0) {
    296        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
    297        if(p!=nullptr) {
    298            if(length>0) {
    299                if(length>newCapacity) {
    300                    length=newCapacity;
    301                }
    302                uprv_memcpy(p, LocalPointerBase<T>::ptr, (size_t)length*sizeof(T));
    303            }
    304            uprv_free(LocalPointerBase<T>::ptr);
    305            LocalPointerBase<T>::ptr=p;
    306        }
    307        return p;
    308    } else {
    309        return nullptr;
    310    }
    311 }
    312 
    313 /**
    314 * Simple array/buffer management class using uprv_malloc() and uprv_free().
    315 * Provides an internal array with fixed capacity. Can alias another array
    316 * or allocate one.
    317 *
    318 * The array address is properly aligned for type T. It might not be properly
    319 * aligned for types larger than T (or larger than the largest subtype of T).
    320 *
    321 * Unlike LocalMemory and LocalArray, this class never adopts
    322 * (takes ownership of) another array.
    323 *
    324 * WARNING: MaybeStackArray only works with primitive (plain-old data) types.
    325 * It does NOT know how to call a destructor! If you work with classes with
    326 * destructors, consider:
    327 *
    328 * - LocalArray in localpointer.h if you know the length ahead of time
    329 * - MaybeStackVector if you know the length at runtime
    330 */
    331 template<typename T, int32_t stackCapacity>
    332 class MaybeStackArray {
    333 public:
    334    // No heap allocation. Use only on the stack.
    335    static void* U_EXPORT2 operator new(size_t) noexcept = delete;
    336    static void* U_EXPORT2 operator new[](size_t) noexcept = delete;
    337    static void* U_EXPORT2 operator new(size_t, void*) noexcept = delete;
    338 
    339    /**
    340     * Default constructor initializes with internal T[stackCapacity] buffer.
    341     */
    342    MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(false) {}
    343    /**
    344     * Automatically allocates the heap array if the argument is larger than the stack capacity.
    345     * Intended for use when an approximate capacity is known at compile time but the true
    346     * capacity is not known until runtime.
    347     */
    348    MaybeStackArray(int32_t newCapacity, UErrorCode status) : MaybeStackArray() {
    349        if (U_FAILURE(status)) {
    350            return;
    351        }
    352        if (capacity < newCapacity) {
    353            if (resize(newCapacity) == nullptr) {
    354                status = U_MEMORY_ALLOCATION_ERROR;
    355            }
    356        }
    357    }
    358    /**
    359     * Destructor deletes the array (if owned).
    360     */
    361    ~MaybeStackArray() { releaseArray(); }
    362    /**
    363     * Move constructor: transfers ownership or copies the stack array.
    364     */
    365    MaybeStackArray(MaybeStackArray<T, stackCapacity> &&src) noexcept;
    366    /**
    367     * Move assignment: transfers ownership or copies the stack array.
    368     */
    369    MaybeStackArray<T, stackCapacity> &operator=(MaybeStackArray<T, stackCapacity> &&src) noexcept;
    370    /**
    371     * Returns the array capacity (number of T items).
    372     * @return array capacity
    373     */
    374    int32_t getCapacity() const { return capacity; }
    375    /**
    376     * Access without ownership change.
    377     * @return the array pointer
    378     */
    379    T *getAlias() const { return ptr; }
    380    /**
    381     * Returns the array limit. Simple convenience method.
    382     * @return getAlias()+getCapacity()
    383     */
    384    T *getArrayLimit() const { return getAlias()+capacity; }
    385    // No "operator T *() const" because that can make
    386    // expressions like mbs[index] ambiguous for some compilers.
    387    /**
    388     * Array item access (const).
    389     * No index bounds check.
    390     * @param i array index
    391     * @return reference to the array item
    392     */
    393    const T &operator[](ptrdiff_t i) const { return ptr[i]; }
    394    /**
    395     * Array item access (writable).
    396     * No index bounds check.
    397     * @param i array index
    398     * @return reference to the array item
    399     */
    400    T &operator[](ptrdiff_t i) { return ptr[i]; }
    401    /**
    402     * Deletes the array (if owned) and aliases another one, no transfer of ownership.
    403     * If the arguments are illegal, then the current array is unchanged.
    404     * @param otherArray must not be nullptr
    405     * @param otherCapacity must be >0
    406     */
    407    void aliasInstead(T *otherArray, int32_t otherCapacity) {
    408        if(otherArray!=nullptr && otherCapacity>0) {
    409            releaseArray();
    410            ptr=otherArray;
    411            capacity=otherCapacity;
    412            needToRelease=false;
    413        }
    414    }
    415    /**
    416     * Deletes the array (if owned) and allocates a new one, copying length T items.
    417     * Returns the new array pointer.
    418     * If the allocation fails, then the current array is unchanged and
    419     * this method returns nullptr.
    420     * @param newCapacity can be less than or greater than the current capacity;
    421     *                    must be >0
    422     * @param length number of T items to be copied from the old array to the new one
    423     * @return the allocated array pointer, or nullptr if the allocation failed
    424     */
    425    inline T *resize(int32_t newCapacity, int32_t length=0);
    426    /**
    427     * Gives up ownership of the array if owned, or else clones it,
    428     * copying length T items; resets itself to the internal stack array.
    429     * Returns nullptr if the allocation failed.
    430     * @param length number of T items to copy when cloning,
    431     *        and capacity of the clone when cloning
    432     * @param resultCapacity will be set to the returned array's capacity (output-only)
    433     * @return the array pointer;
    434     *         caller becomes responsible for deleting the array
    435     */
    436    inline T *orphanOrClone(int32_t length, int32_t &resultCapacity);
    437 
    438 protected:
    439    // Resizes the array to the size of src, then copies the contents of src.
    440    void copyFrom(const MaybeStackArray &src, UErrorCode &status) {
    441        if (U_FAILURE(status)) {
    442            return;
    443        }
    444        if (this->resize(src.capacity, 0) == nullptr) {
    445            status = U_MEMORY_ALLOCATION_ERROR;
    446            return;
    447        }
    448        uprv_memcpy(this->ptr, src.ptr, (size_t)capacity * sizeof(T));
    449    }
    450 
    451 private:
    452    T *ptr;
    453    int32_t capacity;
    454    UBool needToRelease;
    455    T stackArray[stackCapacity];
    456    void releaseArray() {
    457        if(needToRelease) {
    458            uprv_free(ptr);
    459        }
    460    }
    461    void resetToStackArray() {
    462        ptr=stackArray;
    463        capacity=stackCapacity;
    464        needToRelease=false;
    465    }
    466    /* No comparison operators with other MaybeStackArray's. */
    467    bool operator==(const MaybeStackArray & /*other*/) = delete;
    468    bool operator!=(const MaybeStackArray & /*other*/) = delete;
    469    /* No ownership transfer: No copy constructor, no assignment operator. */
    470    MaybeStackArray(const MaybeStackArray & /*other*/) = delete;
    471    void operator=(const MaybeStackArray & /*other*/) = delete;
    472 };
    473 
    474 template<typename T, int32_t stackCapacity>
    475 icu::MaybeStackArray<T, stackCapacity>::MaybeStackArray(
    476        MaybeStackArray <T, stackCapacity>&& src) noexcept
    477        : ptr(src.ptr), capacity(src.capacity), needToRelease(src.needToRelease) {
    478    if (src.ptr == src.stackArray) {
    479        ptr = stackArray;
    480        uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);
    481    } else {
    482        src.resetToStackArray();  // take ownership away from src
    483    }
    484 }
    485 
    486 template<typename T, int32_t stackCapacity>
    487 inline MaybeStackArray <T, stackCapacity>&
    488 MaybeStackArray<T, stackCapacity>::operator=(MaybeStackArray <T, stackCapacity>&& src) noexcept {
    489    releaseArray();  // in case this instance had its own memory allocated
    490    capacity = src.capacity;
    491    needToRelease = src.needToRelease;
    492    if (src.ptr == src.stackArray) {
    493        ptr = stackArray;
    494        uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);
    495    } else {
    496        ptr = src.ptr;
    497        src.resetToStackArray();  // take ownership away from src
    498    }
    499    return *this;
    500 }
    501 
    502 template<typename T, int32_t stackCapacity>
    503 inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
    504    if(newCapacity>0) {
    505 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
    506        ::fprintf(::stderr, "MaybeStackArray (resize) alloc %d * %lu\n", newCapacity, sizeof(T));
    507 #endif
    508        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
    509        if(p!=nullptr) {
    510            if(length>0) {
    511                if(length>capacity) {
    512                    length=capacity;
    513                }
    514                if(length>newCapacity) {
    515                    length=newCapacity;
    516                }
    517                uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
    518            }
    519            releaseArray();
    520            ptr=p;
    521            capacity=newCapacity;
    522            needToRelease=true;
    523        }
    524        return p;
    525    } else {
    526        return nullptr;
    527    }
    528 }
    529 
    530 template<typename T, int32_t stackCapacity>
    531 inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) {
    532    T *p;
    533    if(needToRelease) {
    534        p=ptr;
    535    } else if(length<=0) {
    536        return nullptr;
    537    } else {
    538        if(length>capacity) {
    539            length=capacity;
    540        }
    541        p=(T *)uprv_malloc(length*sizeof(T));
    542 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
    543      ::fprintf(::stderr,"MaybeStacArray (orphan) alloc %d * %lu\n", length,sizeof(T));
    544 #endif
    545        if(p==nullptr) {
    546            return nullptr;
    547        }
    548        uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
    549    }
    550    resultCapacity=length;
    551    resetToStackArray();
    552    return p;
    553 }
    554 
    555 /**
    556 * Variant of MaybeStackArray that allocates a header struct and an array
    557 * in one contiguous memory block, using uprv_malloc() and uprv_free().
    558 * Provides internal memory with fixed array capacity. Can alias another memory
    559 * block or allocate one.
    560 * The stackCapacity is the number of T items in the internal memory,
    561 * not counting the H header.
    562 * Unlike LocalMemory and LocalArray, this class never adopts
    563 * (takes ownership of) another memory block.
    564 */
    565 template<typename H, typename T, int32_t stackCapacity>
    566 class MaybeStackHeaderAndArray {
    567 public:
    568    // No heap allocation. Use only on the stack.
    569    static void* U_EXPORT2 operator new(size_t) noexcept = delete;
    570    static void* U_EXPORT2 operator new[](size_t) noexcept = delete;
    571    static void* U_EXPORT2 operator new(size_t, void*) noexcept = delete;
    572 
    573    /**
    574     * Default constructor initializes with internal H+T[stackCapacity] buffer.
    575     */
    576    MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(false) {}
    577    /**
    578     * Destructor deletes the memory (if owned).
    579     */
    580    ~MaybeStackHeaderAndArray() { releaseMemory(); }
    581    /**
    582     * Returns the array capacity (number of T items).
    583     * @return array capacity
    584     */
    585    int32_t getCapacity() const { return capacity; }
    586    /**
    587     * Access without ownership change.
    588     * @return the header pointer
    589     */
    590    H *getAlias() const { return ptr; }
    591    /**
    592     * Returns the array start.
    593     * @return array start, same address as getAlias()+1
    594     */
    595    T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }
    596    /**
    597     * Returns the array limit.
    598     * @return array limit
    599     */
    600    T *getArrayLimit() const { return getArrayStart()+capacity; }
    601    /**
    602     * Access without ownership change. Same as getAlias().
    603     * A class instance can be used directly in expressions that take a T *.
    604     * @return the header pointer
    605     */
    606    operator H *() const { return ptr; }
    607    /**
    608     * Array item access (writable).
    609     * No index bounds check.
    610     * @param i array index
    611     * @return reference to the array item
    612     */
    613    T &operator[](ptrdiff_t i) { return getArrayStart()[i]; }
    614    /**
    615     * Deletes the memory block (if owned) and aliases another one, no transfer of ownership.
    616     * If the arguments are illegal, then the current memory is unchanged.
    617     * @param otherArray must not be nullptr
    618     * @param otherCapacity must be >0
    619     */
    620    void aliasInstead(H *otherMemory, int32_t otherCapacity) {
    621        if(otherMemory!=nullptr && otherCapacity>0) {
    622            releaseMemory();
    623            ptr=otherMemory;
    624            capacity=otherCapacity;
    625            needToRelease=false;
    626        }
    627    }
    628    /**
    629     * Deletes the memory block (if owned) and allocates a new one,
    630     * copying the header and length T array items.
    631     * Returns the new header pointer.
    632     * If the allocation fails, then the current memory is unchanged and
    633     * this method returns nullptr.
    634     * @param newCapacity can be less than or greater than the current capacity;
    635     *                    must be >0
    636     * @param length number of T items to be copied from the old array to the new one
    637     * @return the allocated pointer, or nullptr if the allocation failed
    638     */
    639    inline H *resize(int32_t newCapacity, int32_t length=0);
    640    /**
    641     * Gives up ownership of the memory if owned, or else clones it,
    642     * copying the header and length T array items; resets itself to the internal memory.
    643     * Returns nullptr if the allocation failed.
    644     * @param length number of T items to copy when cloning,
    645     *        and array capacity of the clone when cloning
    646     * @param resultCapacity will be set to the returned array's capacity (output-only)
    647     * @return the header pointer;
    648     *         caller becomes responsible for deleting the array
    649     */
    650    inline H *orphanOrClone(int32_t length, int32_t &resultCapacity);
    651 private:
    652    H *ptr;
    653    int32_t capacity;
    654    UBool needToRelease;
    655    // stackHeader must precede stackArray immediately.
    656    H stackHeader;
    657    T stackArray[stackCapacity];
    658    void releaseMemory() {
    659        if(needToRelease) {
    660            uprv_free(ptr);
    661        }
    662    }
    663    /* No comparison operators with other MaybeStackHeaderAndArray's. */
    664    bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return false;}
    665    bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return true;}
    666    /* No ownership transfer: No copy constructor, no assignment operator. */
    667    MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {}
    668    void operator=(const MaybeStackHeaderAndArray & /*other*/) {}
    669 };
    670 
    671 template<typename H, typename T, int32_t stackCapacity>
    672 inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity,
    673                                                                int32_t length) {
    674    if(newCapacity>=0) {
    675 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
    676      ::fprintf(::stderr,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H),newCapacity,sizeof(T));
    677 #endif
    678        H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T));
    679        if(p!=nullptr) {
    680            if(length<0) {
    681                length=0;
    682            } else if(length>0) {
    683                if(length>capacity) {
    684                    length=capacity;
    685                }
    686                if(length>newCapacity) {
    687                    length=newCapacity;
    688                }
    689            }
    690            uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
    691            releaseMemory();
    692            ptr=p;
    693            capacity=newCapacity;
    694            needToRelease=true;
    695        }
    696        return p;
    697    } else {
    698        return nullptr;
    699    }
    700 }
    701 
    702 template<typename H, typename T, int32_t stackCapacity>
    703 inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length,
    704                                                                       int32_t &resultCapacity) {
    705    H *p;
    706    if(needToRelease) {
    707        p=ptr;
    708    } else {
    709        if(length<0) {
    710            length=0;
    711        } else if(length>capacity) {
    712            length=capacity;
    713        }
    714 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
    715      ::fprintf(::stderr,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H),length,sizeof(T));
    716 #endif
    717        p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T));
    718        if(p==nullptr) {
    719            return nullptr;
    720        }
    721        uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
    722    }
    723    resultCapacity=length;
    724    ptr=&stackHeader;
    725    capacity=stackCapacity;
    726    needToRelease=false;
    727    return p;
    728 }
    729 
    730 /**
    731 * A simple memory management class that creates new heap allocated objects (of
    732 * any class that has a public constructor), keeps track of them and eventually
    733 * deletes them all in its own destructor.
    734 *
    735 * A typical use-case would be code like this:
    736 *
    737 *     MemoryPool<MyType> pool;
    738 *
    739 *     MyType* o1 = pool.create();
    740 *     if (o1 != nullptr) {
    741 *         foo(o1);
    742 *     }
    743 *
    744 *     MyType* o2 = pool.create(1, 2, 3);
    745 *     if (o2 != nullptr) {
    746 *         bar(o2);
    747 *     }
    748 *
    749 *     // MemoryPool will take care of deleting the MyType objects.
    750 *
    751 * It doesn't do anything more than that, and is intentionally kept minimalist.
    752 */
    753 template<typename T, int32_t stackCapacity = 8>
    754 class MemoryPool : public UMemory {
    755 public:
    756    MemoryPool() : fCount(0), fPool() {}
    757 
    758    ~MemoryPool() {
    759        for (int32_t i = 0; i < fCount; ++i) {
    760            delete fPool[i];
    761        }
    762    }
    763 
    764    MemoryPool(const MemoryPool&) = delete;
    765    MemoryPool& operator=(const MemoryPool&) = delete;
    766 
    767    MemoryPool(MemoryPool&& other) noexcept : fCount(other.fCount),
    768                                                fPool(std::move(other.fPool)) {
    769        other.fCount = 0;
    770    }
    771 
    772    MemoryPool& operator=(MemoryPool&& other) noexcept {
    773        // Since `this` may contain instances that need to be deleted, we can't
    774        // just throw them away and replace them with `other`. The normal way of
    775        // dealing with this in C++ is to swap `this` and `other`, rather than
    776        // simply overwrite: the destruction of `other` can then take care of
    777        // running MemoryPool::~MemoryPool() over the still-to-be-deallocated
    778        // instances.
    779        std::swap(fCount, other.fCount);
    780        std::swap(fPool, other.fPool);
    781        return *this;
    782    }
    783 
    784    /**
    785     * Creates a new object of typename T, by forwarding any and all arguments
    786     * to the typename T constructor.
    787     *
    788     * @param args Arguments to be forwarded to the typename T constructor.
    789     * @return A pointer to the newly created object, or nullptr on error.
    790     */
    791    template<typename... Args>
    792    T* create(Args&&... args) {
    793        int32_t capacity = fPool.getCapacity();
    794        if (fCount == capacity &&
    795            fPool.resize(capacity == stackCapacity ? 4 * capacity : 2 * capacity,
    796                         capacity) == nullptr) {
    797            return nullptr;
    798        }
    799        return fPool[fCount++] = new T(std::forward<Args>(args)...);
    800    }
    801 
    802    template <typename... Args>
    803    T* createAndCheckErrorCode(UErrorCode &status, Args &&... args) {
    804        if (U_FAILURE(status)) {
    805            return nullptr;
    806        }
    807        T *pointer = this->create(args...);
    808        if (U_SUCCESS(status) && pointer == nullptr) {
    809            status = U_MEMORY_ALLOCATION_ERROR;
    810        }
    811        return pointer;
    812    }
    813 
    814    /**
    815     * @return Number of elements that have been allocated.
    816     */
    817    int32_t count() const {
    818        return fCount;
    819    }
    820 
    821 protected:
    822    int32_t fCount;
    823    MaybeStackArray<T*, stackCapacity> fPool;
    824 };
    825 
    826 /**
    827 * An internal Vector-like implementation based on MemoryPool.
    828 *
    829 * Heap-allocates each element and stores pointers.
    830 *
    831 * To append an item to the vector, use emplaceBack.
    832 *
    833 *     MaybeStackVector<MyType> vector;
    834 *     MyType* element = vector.emplaceBack();
    835 *     if (!element) {
    836 *         status = U_MEMORY_ALLOCATION_ERROR;
    837 *     }
    838 *     // do stuff with element
    839 *
    840 * To loop over the vector, use a for loop with indices:
    841 *
    842 *     for (int32_t i = 0; i < vector.length(); i++) {
    843 *         MyType* element = vector[i];
    844 *     }
    845 */
    846 template<typename T, int32_t stackCapacity = 8>
    847 class MaybeStackVector : protected MemoryPool<T, stackCapacity> {
    848 public:
    849    template<typename... Args>
    850    T* emplaceBack(Args&&... args) {
    851        return this->create(args...);
    852    }
    853 
    854    template <typename... Args>
    855    T *emplaceBackAndCheckErrorCode(UErrorCode &status, Args &&... args) {
    856        return this->createAndCheckErrorCode(status, args...);
    857    }
    858 
    859    int32_t length() const {
    860        return this->fCount;
    861    }
    862 
    863    T** getAlias() {
    864        return this->fPool.getAlias();
    865    }
    866 
    867    const T *const *getAlias() const {
    868        return this->fPool.getAlias();
    869    }
    870 
    871    /**
    872     * Array item access (read-only).
    873     * No index bounds check.
    874     * @param i array index
    875     * @return reference to the array item
    876     */
    877    const T* operator[](ptrdiff_t i) const {
    878        return this->fPool[i];
    879    }
    880 
    881    /**
    882     * Array item access (writable).
    883     * No index bounds check.
    884     * @param i array index
    885     * @return reference to the array item
    886     */
    887    T* operator[](ptrdiff_t i) {
    888        return this->fPool[i];
    889    }
    890 };
    891 
    892 
    893 U_NAMESPACE_END
    894 
    895 #endif  /* __cplusplus */
    896 #endif  /* CMEMORY_H */