11cb0ef41Sopenharmony_ci// © 2016 and later: Unicode, Inc. and others. 21cb0ef41Sopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html 31cb0ef41Sopenharmony_ci/* 41cb0ef41Sopenharmony_ci****************************************************************************** 51cb0ef41Sopenharmony_ci* 61cb0ef41Sopenharmony_ci* Copyright (C) 1997-2016, International Business Machines 71cb0ef41Sopenharmony_ci* Corporation and others. All Rights Reserved. 81cb0ef41Sopenharmony_ci* 91cb0ef41Sopenharmony_ci****************************************************************************** 101cb0ef41Sopenharmony_ci* 111cb0ef41Sopenharmony_ci* File CMEMORY.H 121cb0ef41Sopenharmony_ci* 131cb0ef41Sopenharmony_ci* Contains stdlib.h/string.h memory functions 141cb0ef41Sopenharmony_ci* 151cb0ef41Sopenharmony_ci* @author Bertrand A. Damiba 161cb0ef41Sopenharmony_ci* 171cb0ef41Sopenharmony_ci* Modification History: 181cb0ef41Sopenharmony_ci* 191cb0ef41Sopenharmony_ci* Date Name Description 201cb0ef41Sopenharmony_ci* 6/20/98 Bertrand Created. 211cb0ef41Sopenharmony_ci* 05/03/99 stephen Changed from functions to macros. 221cb0ef41Sopenharmony_ci* 231cb0ef41Sopenharmony_ci****************************************************************************** 241cb0ef41Sopenharmony_ci*/ 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci#ifndef CMEMORY_H 271cb0ef41Sopenharmony_ci#define CMEMORY_H 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ci#include "unicode/utypes.h" 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ci#include <stddef.h> 321cb0ef41Sopenharmony_ci#include <string.h> 331cb0ef41Sopenharmony_ci#include "unicode/localpointer.h" 341cb0ef41Sopenharmony_ci#include "uassert.h" 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ci#if U_DEBUG && defined(UPRV_MALLOC_COUNT) 371cb0ef41Sopenharmony_ci#include <stdio.h> 381cb0ef41Sopenharmony_ci#endif 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci// uprv_memcpy and uprv_memmove 411cb0ef41Sopenharmony_ci#if defined(__clang__) 421cb0ef41Sopenharmony_ci#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \ 431cb0ef41Sopenharmony_ci /* Suppress warnings about addresses that will never be NULL */ \ 441cb0ef41Sopenharmony_ci _Pragma("clang diagnostic push") \ 451cb0ef41Sopenharmony_ci _Pragma("clang diagnostic ignored \"-Waddress\"") \ 461cb0ef41Sopenharmony_ci U_ASSERT(dst != NULL); \ 471cb0ef41Sopenharmony_ci U_ASSERT(src != NULL); \ 481cb0ef41Sopenharmony_ci _Pragma("clang diagnostic pop") \ 491cb0ef41Sopenharmony_ci U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \ 501cb0ef41Sopenharmony_ci} UPRV_BLOCK_MACRO_END 511cb0ef41Sopenharmony_ci#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \ 521cb0ef41Sopenharmony_ci /* Suppress warnings about addresses that will never be NULL */ \ 531cb0ef41Sopenharmony_ci _Pragma("clang diagnostic push") \ 541cb0ef41Sopenharmony_ci _Pragma("clang diagnostic ignored \"-Waddress\"") \ 551cb0ef41Sopenharmony_ci U_ASSERT(dst != NULL); \ 561cb0ef41Sopenharmony_ci U_ASSERT(src != NULL); \ 571cb0ef41Sopenharmony_ci _Pragma("clang diagnostic pop") \ 581cb0ef41Sopenharmony_ci U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \ 591cb0ef41Sopenharmony_ci} UPRV_BLOCK_MACRO_END 601cb0ef41Sopenharmony_ci#elif defined(__GNUC__) 611cb0ef41Sopenharmony_ci#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \ 621cb0ef41Sopenharmony_ci /* Suppress warnings about addresses that will never be NULL */ \ 631cb0ef41Sopenharmony_ci _Pragma("GCC diagnostic push") \ 641cb0ef41Sopenharmony_ci _Pragma("GCC diagnostic ignored \"-Waddress\"") \ 651cb0ef41Sopenharmony_ci U_ASSERT(dst != NULL); \ 661cb0ef41Sopenharmony_ci U_ASSERT(src != NULL); \ 671cb0ef41Sopenharmony_ci _Pragma("GCC diagnostic pop") \ 681cb0ef41Sopenharmony_ci U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \ 691cb0ef41Sopenharmony_ci} UPRV_BLOCK_MACRO_END 701cb0ef41Sopenharmony_ci#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \ 711cb0ef41Sopenharmony_ci /* Suppress warnings about addresses that will never be NULL */ \ 721cb0ef41Sopenharmony_ci _Pragma("GCC diagnostic push") \ 731cb0ef41Sopenharmony_ci _Pragma("GCC diagnostic ignored \"-Waddress\"") \ 741cb0ef41Sopenharmony_ci U_ASSERT(dst != NULL); \ 751cb0ef41Sopenharmony_ci U_ASSERT(src != NULL); \ 761cb0ef41Sopenharmony_ci _Pragma("GCC diagnostic pop") \ 771cb0ef41Sopenharmony_ci U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \ 781cb0ef41Sopenharmony_ci} UPRV_BLOCK_MACRO_END 791cb0ef41Sopenharmony_ci#else 801cb0ef41Sopenharmony_ci#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \ 811cb0ef41Sopenharmony_ci U_ASSERT(dst != NULL); \ 821cb0ef41Sopenharmony_ci U_ASSERT(src != NULL); \ 831cb0ef41Sopenharmony_ci U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \ 841cb0ef41Sopenharmony_ci} UPRV_BLOCK_MACRO_END 851cb0ef41Sopenharmony_ci#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \ 861cb0ef41Sopenharmony_ci U_ASSERT(dst != NULL); \ 871cb0ef41Sopenharmony_ci U_ASSERT(src != NULL); \ 881cb0ef41Sopenharmony_ci U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \ 891cb0ef41Sopenharmony_ci} UPRV_BLOCK_MACRO_END 901cb0ef41Sopenharmony_ci#endif 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci/** 931cb0ef41Sopenharmony_ci * \def UPRV_LENGTHOF 941cb0ef41Sopenharmony_ci * Convenience macro to determine the length of a fixed array at compile-time. 951cb0ef41Sopenharmony_ci * @param array A fixed length array 961cb0ef41Sopenharmony_ci * @return The length of the array, in elements 971cb0ef41Sopenharmony_ci * @internal 981cb0ef41Sopenharmony_ci */ 991cb0ef41Sopenharmony_ci#define UPRV_LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) 1001cb0ef41Sopenharmony_ci#define uprv_memset(buffer, mark, size) U_STANDARD_CPP_NAMESPACE memset(buffer, mark, size) 1011cb0ef41Sopenharmony_ci#define uprv_memcmp(buffer1, buffer2, size) U_STANDARD_CPP_NAMESPACE memcmp(buffer1, buffer2,size) 1021cb0ef41Sopenharmony_ci#define uprv_memchr(ptr, value, num) U_STANDARD_CPP_NAMESPACE memchr(ptr, value, num) 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ciU_CAPI void * U_EXPORT2 1051cb0ef41Sopenharmony_ciuprv_malloc(size_t s) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR(1); 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ciU_CAPI void * U_EXPORT2 1081cb0ef41Sopenharmony_ciuprv_realloc(void *mem, size_t size) U_ALLOC_SIZE_ATTR(2); 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ciU_CAPI void U_EXPORT2 1111cb0ef41Sopenharmony_ciuprv_free(void *mem); 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ciU_CAPI void * U_EXPORT2 1141cb0ef41Sopenharmony_ciuprv_calloc(size_t num, size_t size) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR2(1,2); 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci/** 1171cb0ef41Sopenharmony_ci * Get the least significant bits of a pointer (a memory address). 1181cb0ef41Sopenharmony_ci * For example, with a mask of 3, the macro gets the 2 least significant bits, 1191cb0ef41Sopenharmony_ci * which will be 0 if the pointer is 32-bit (4-byte) aligned. 1201cb0ef41Sopenharmony_ci * 1211cb0ef41Sopenharmony_ci * uintptr_t is the most appropriate integer type to cast to. 1221cb0ef41Sopenharmony_ci */ 1231cb0ef41Sopenharmony_ci#define U_POINTER_MASK_LSB(ptr, mask) ((uintptr_t)(ptr) & (mask)) 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_ci/** 1261cb0ef41Sopenharmony_ci * Create & return an instance of "type" in statically allocated storage. 1271cb0ef41Sopenharmony_ci * e.g. 1281cb0ef41Sopenharmony_ci * static std::mutex *myMutex = STATIC_NEW(std::mutex); 1291cb0ef41Sopenharmony_ci * To destroy an object created in this way, invoke the destructor explicitly, e.g. 1301cb0ef41Sopenharmony_ci * myMutex->~mutex(); 1311cb0ef41Sopenharmony_ci * DO NOT use delete. 1321cb0ef41Sopenharmony_ci * DO NOT use with class UMutex, which has specific support for static instances. 1331cb0ef41Sopenharmony_ci * 1341cb0ef41Sopenharmony_ci * STATIC_NEW is intended for use when 1351cb0ef41Sopenharmony_ci * - We want a static (or global) object. 1361cb0ef41Sopenharmony_ci * - We don't want it to ever be destructed, or to explicitly control destruction, 1371cb0ef41Sopenharmony_ci * to avoid use-after-destruction problems. 1381cb0ef41Sopenharmony_ci * - We want to avoid an ordinary heap allocated object, 1391cb0ef41Sopenharmony_ci * to avoid the possibility of memory allocation failures, and 1401cb0ef41Sopenharmony_ci * to avoid memory leak reports, from valgrind, for example. 1411cb0ef41Sopenharmony_ci * This is defined as a macro rather than a template function because each invocation 1421cb0ef41Sopenharmony_ci * must define distinct static storage for the object being returned. 1431cb0ef41Sopenharmony_ci */ 1441cb0ef41Sopenharmony_ci#define STATIC_NEW(type) [] () { \ 1451cb0ef41Sopenharmony_ci alignas(type) static char storage[sizeof(type)]; \ 1461cb0ef41Sopenharmony_ci return new(storage) type();} () 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci/** 1491cb0ef41Sopenharmony_ci * Heap clean up function, called from u_cleanup() 1501cb0ef41Sopenharmony_ci * Clears any user heap functions from u_setMemoryFunctions() 1511cb0ef41Sopenharmony_ci * Does NOT deallocate any remaining allocated memory. 1521cb0ef41Sopenharmony_ci */ 1531cb0ef41Sopenharmony_ciU_CFUNC UBool 1541cb0ef41Sopenharmony_cicmemory_cleanup(void); 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci/** 1571cb0ef41Sopenharmony_ci * A function called by <TT>uhash_remove</TT>, 1581cb0ef41Sopenharmony_ci * <TT>uhash_close</TT>, or <TT>uhash_put</TT> to delete 1591cb0ef41Sopenharmony_ci * an existing key or value. 1601cb0ef41Sopenharmony_ci * @param obj A key or value stored in a hashtable 1611cb0ef41Sopenharmony_ci * @see uprv_deleteUObject 1621cb0ef41Sopenharmony_ci */ 1631cb0ef41Sopenharmony_citypedef void U_CALLCONV UObjectDeleter(void* obj); 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci/** 1661cb0ef41Sopenharmony_ci * Deleter for UObject instances. 1671cb0ef41Sopenharmony_ci * Works for all subclasses of UObject because it has a virtual destructor. 1681cb0ef41Sopenharmony_ci */ 1691cb0ef41Sopenharmony_ciU_CAPI void U_EXPORT2 1701cb0ef41Sopenharmony_ciuprv_deleteUObject(void *obj); 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci#ifdef __cplusplus 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci#include <utility> 1751cb0ef41Sopenharmony_ci#include "unicode/uobject.h" 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ciU_NAMESPACE_BEGIN 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ci/** 1801cb0ef41Sopenharmony_ci * "Smart pointer" class, deletes memory via uprv_free(). 1811cb0ef41Sopenharmony_ci * For most methods see the LocalPointerBase base class. 1821cb0ef41Sopenharmony_ci * Adds operator[] for array item access. 1831cb0ef41Sopenharmony_ci * 1841cb0ef41Sopenharmony_ci * @see LocalPointerBase 1851cb0ef41Sopenharmony_ci */ 1861cb0ef41Sopenharmony_citemplate<typename T> 1871cb0ef41Sopenharmony_ciclass LocalMemory : public LocalPointerBase<T> { 1881cb0ef41Sopenharmony_cipublic: 1891cb0ef41Sopenharmony_ci using LocalPointerBase<T>::operator*; 1901cb0ef41Sopenharmony_ci using LocalPointerBase<T>::operator->; 1911cb0ef41Sopenharmony_ci /** 1921cb0ef41Sopenharmony_ci * Constructor takes ownership. 1931cb0ef41Sopenharmony_ci * @param p simple pointer to an array of T items that is adopted 1941cb0ef41Sopenharmony_ci */ 1951cb0ef41Sopenharmony_ci explicit LocalMemory(T *p=nullptr) : LocalPointerBase<T>(p) {} 1961cb0ef41Sopenharmony_ci /** 1971cb0ef41Sopenharmony_ci * Move constructor, leaves src with isNull(). 1981cb0ef41Sopenharmony_ci * @param src source smart pointer 1991cb0ef41Sopenharmony_ci */ 2001cb0ef41Sopenharmony_ci LocalMemory(LocalMemory<T> &&src) noexcept : LocalPointerBase<T>(src.ptr) { 2011cb0ef41Sopenharmony_ci src.ptr=nullptr; 2021cb0ef41Sopenharmony_ci } 2031cb0ef41Sopenharmony_ci /** 2041cb0ef41Sopenharmony_ci * Destructor deletes the memory it owns. 2051cb0ef41Sopenharmony_ci */ 2061cb0ef41Sopenharmony_ci ~LocalMemory() { 2071cb0ef41Sopenharmony_ci uprv_free(LocalPointerBase<T>::ptr); 2081cb0ef41Sopenharmony_ci } 2091cb0ef41Sopenharmony_ci /** 2101cb0ef41Sopenharmony_ci * Move assignment operator, leaves src with isNull(). 2111cb0ef41Sopenharmony_ci * The behavior is undefined if *this and src are the same object. 2121cb0ef41Sopenharmony_ci * @param src source smart pointer 2131cb0ef41Sopenharmony_ci * @return *this 2141cb0ef41Sopenharmony_ci */ 2151cb0ef41Sopenharmony_ci LocalMemory<T> &operator=(LocalMemory<T> &&src) noexcept { 2161cb0ef41Sopenharmony_ci uprv_free(LocalPointerBase<T>::ptr); 2171cb0ef41Sopenharmony_ci LocalPointerBase<T>::ptr=src.ptr; 2181cb0ef41Sopenharmony_ci src.ptr=nullptr; 2191cb0ef41Sopenharmony_ci return *this; 2201cb0ef41Sopenharmony_ci } 2211cb0ef41Sopenharmony_ci /** 2221cb0ef41Sopenharmony_ci * Swap pointers. 2231cb0ef41Sopenharmony_ci * @param other other smart pointer 2241cb0ef41Sopenharmony_ci */ 2251cb0ef41Sopenharmony_ci void swap(LocalMemory<T> &other) noexcept { 2261cb0ef41Sopenharmony_ci T *temp=LocalPointerBase<T>::ptr; 2271cb0ef41Sopenharmony_ci LocalPointerBase<T>::ptr=other.ptr; 2281cb0ef41Sopenharmony_ci other.ptr=temp; 2291cb0ef41Sopenharmony_ci } 2301cb0ef41Sopenharmony_ci /** 2311cb0ef41Sopenharmony_ci * Non-member LocalMemory swap function. 2321cb0ef41Sopenharmony_ci * @param p1 will get p2's pointer 2331cb0ef41Sopenharmony_ci * @param p2 will get p1's pointer 2341cb0ef41Sopenharmony_ci */ 2351cb0ef41Sopenharmony_ci friend inline void swap(LocalMemory<T> &p1, LocalMemory<T> &p2) noexcept { 2361cb0ef41Sopenharmony_ci p1.swap(p2); 2371cb0ef41Sopenharmony_ci } 2381cb0ef41Sopenharmony_ci /** 2391cb0ef41Sopenharmony_ci * Deletes the array it owns, 2401cb0ef41Sopenharmony_ci * and adopts (takes ownership of) the one passed in. 2411cb0ef41Sopenharmony_ci * @param p simple pointer to an array of T items that is adopted 2421cb0ef41Sopenharmony_ci */ 2431cb0ef41Sopenharmony_ci void adoptInstead(T *p) { 2441cb0ef41Sopenharmony_ci uprv_free(LocalPointerBase<T>::ptr); 2451cb0ef41Sopenharmony_ci LocalPointerBase<T>::ptr=p; 2461cb0ef41Sopenharmony_ci } 2471cb0ef41Sopenharmony_ci /** 2481cb0ef41Sopenharmony_ci * Deletes the array it owns, allocates a new one and reset its bytes to 0. 2491cb0ef41Sopenharmony_ci * Returns the new array pointer. 2501cb0ef41Sopenharmony_ci * If the allocation fails, then the current array is unchanged and 2511cb0ef41Sopenharmony_ci * this method returns nullptr. 2521cb0ef41Sopenharmony_ci * @param newCapacity must be >0 2531cb0ef41Sopenharmony_ci * @return the allocated array pointer, or nullptr if the allocation failed 2541cb0ef41Sopenharmony_ci */ 2551cb0ef41Sopenharmony_ci inline T *allocateInsteadAndReset(int32_t newCapacity=1); 2561cb0ef41Sopenharmony_ci /** 2571cb0ef41Sopenharmony_ci * Deletes the array it owns and allocates a new one, copying length T items. 2581cb0ef41Sopenharmony_ci * Returns the new array pointer. 2591cb0ef41Sopenharmony_ci * If the allocation fails, then the current array is unchanged and 2601cb0ef41Sopenharmony_ci * this method returns nullptr. 2611cb0ef41Sopenharmony_ci * @param newCapacity must be >0 2621cb0ef41Sopenharmony_ci * @param length number of T items to be copied from the old array to the new one; 2631cb0ef41Sopenharmony_ci * must be no more than the capacity of the old array, 2641cb0ef41Sopenharmony_ci * which the caller must track because the LocalMemory does not track it 2651cb0ef41Sopenharmony_ci * @return the allocated array pointer, or nullptr if the allocation failed 2661cb0ef41Sopenharmony_ci */ 2671cb0ef41Sopenharmony_ci inline T *allocateInsteadAndCopy(int32_t newCapacity=1, int32_t length=0); 2681cb0ef41Sopenharmony_ci /** 2691cb0ef41Sopenharmony_ci * Array item access (writable). 2701cb0ef41Sopenharmony_ci * No index bounds check. 2711cb0ef41Sopenharmony_ci * @param i array index 2721cb0ef41Sopenharmony_ci * @return reference to the array item 2731cb0ef41Sopenharmony_ci */ 2741cb0ef41Sopenharmony_ci T &operator[](ptrdiff_t i) const { return LocalPointerBase<T>::ptr[i]; } 2751cb0ef41Sopenharmony_ci}; 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_citemplate<typename T> 2781cb0ef41Sopenharmony_ciinline T *LocalMemory<T>::allocateInsteadAndReset(int32_t newCapacity) { 2791cb0ef41Sopenharmony_ci if(newCapacity>0) { 2801cb0ef41Sopenharmony_ci T *p=(T *)uprv_malloc(newCapacity*sizeof(T)); 2811cb0ef41Sopenharmony_ci if(p!=nullptr) { 2821cb0ef41Sopenharmony_ci uprv_memset(p, 0, newCapacity*sizeof(T)); 2831cb0ef41Sopenharmony_ci uprv_free(LocalPointerBase<T>::ptr); 2841cb0ef41Sopenharmony_ci LocalPointerBase<T>::ptr=p; 2851cb0ef41Sopenharmony_ci } 2861cb0ef41Sopenharmony_ci return p; 2871cb0ef41Sopenharmony_ci } else { 2881cb0ef41Sopenharmony_ci return nullptr; 2891cb0ef41Sopenharmony_ci } 2901cb0ef41Sopenharmony_ci} 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_citemplate<typename T> 2941cb0ef41Sopenharmony_ciinline T *LocalMemory<T>::allocateInsteadAndCopy(int32_t newCapacity, int32_t length) { 2951cb0ef41Sopenharmony_ci if(newCapacity>0) { 2961cb0ef41Sopenharmony_ci T *p=(T *)uprv_malloc(newCapacity*sizeof(T)); 2971cb0ef41Sopenharmony_ci if(p!=nullptr) { 2981cb0ef41Sopenharmony_ci if(length>0) { 2991cb0ef41Sopenharmony_ci if(length>newCapacity) { 3001cb0ef41Sopenharmony_ci length=newCapacity; 3011cb0ef41Sopenharmony_ci } 3021cb0ef41Sopenharmony_ci uprv_memcpy(p, LocalPointerBase<T>::ptr, (size_t)length*sizeof(T)); 3031cb0ef41Sopenharmony_ci } 3041cb0ef41Sopenharmony_ci uprv_free(LocalPointerBase<T>::ptr); 3051cb0ef41Sopenharmony_ci LocalPointerBase<T>::ptr=p; 3061cb0ef41Sopenharmony_ci } 3071cb0ef41Sopenharmony_ci return p; 3081cb0ef41Sopenharmony_ci } else { 3091cb0ef41Sopenharmony_ci return nullptr; 3101cb0ef41Sopenharmony_ci } 3111cb0ef41Sopenharmony_ci} 3121cb0ef41Sopenharmony_ci 3131cb0ef41Sopenharmony_ci/** 3141cb0ef41Sopenharmony_ci * Simple array/buffer management class using uprv_malloc() and uprv_free(). 3151cb0ef41Sopenharmony_ci * Provides an internal array with fixed capacity. Can alias another array 3161cb0ef41Sopenharmony_ci * or allocate one. 3171cb0ef41Sopenharmony_ci * 3181cb0ef41Sopenharmony_ci * The array address is properly aligned for type T. It might not be properly 3191cb0ef41Sopenharmony_ci * aligned for types larger than T (or larger than the largest subtype of T). 3201cb0ef41Sopenharmony_ci * 3211cb0ef41Sopenharmony_ci * Unlike LocalMemory and LocalArray, this class never adopts 3221cb0ef41Sopenharmony_ci * (takes ownership of) another array. 3231cb0ef41Sopenharmony_ci * 3241cb0ef41Sopenharmony_ci * WARNING: MaybeStackArray only works with primitive (plain-old data) types. 3251cb0ef41Sopenharmony_ci * It does NOT know how to call a destructor! If you work with classes with 3261cb0ef41Sopenharmony_ci * destructors, consider: 3271cb0ef41Sopenharmony_ci * 3281cb0ef41Sopenharmony_ci * - LocalArray in localpointer.h if you know the length ahead of time 3291cb0ef41Sopenharmony_ci * - MaybeStackVector if you know the length at runtime 3301cb0ef41Sopenharmony_ci */ 3311cb0ef41Sopenharmony_citemplate<typename T, int32_t stackCapacity> 3321cb0ef41Sopenharmony_ciclass MaybeStackArray { 3331cb0ef41Sopenharmony_cipublic: 3341cb0ef41Sopenharmony_ci // No heap allocation. Use only on the stack. 3351cb0ef41Sopenharmony_ci static void* U_EXPORT2 operator new(size_t) noexcept = delete; 3361cb0ef41Sopenharmony_ci static void* U_EXPORT2 operator new[](size_t) noexcept = delete; 3371cb0ef41Sopenharmony_ci#if U_HAVE_PLACEMENT_NEW 3381cb0ef41Sopenharmony_ci static void* U_EXPORT2 operator new(size_t, void*) noexcept = delete; 3391cb0ef41Sopenharmony_ci#endif 3401cb0ef41Sopenharmony_ci 3411cb0ef41Sopenharmony_ci /** 3421cb0ef41Sopenharmony_ci * Default constructor initializes with internal T[stackCapacity] buffer. 3431cb0ef41Sopenharmony_ci */ 3441cb0ef41Sopenharmony_ci MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(false) {} 3451cb0ef41Sopenharmony_ci /** 3461cb0ef41Sopenharmony_ci * Automatically allocates the heap array if the argument is larger than the stack capacity. 3471cb0ef41Sopenharmony_ci * Intended for use when an approximate capacity is known at compile time but the true 3481cb0ef41Sopenharmony_ci * capacity is not known until runtime. 3491cb0ef41Sopenharmony_ci */ 3501cb0ef41Sopenharmony_ci MaybeStackArray(int32_t newCapacity, UErrorCode status) : MaybeStackArray() { 3511cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 3521cb0ef41Sopenharmony_ci return; 3531cb0ef41Sopenharmony_ci } 3541cb0ef41Sopenharmony_ci if (capacity < newCapacity) { 3551cb0ef41Sopenharmony_ci if (resize(newCapacity) == nullptr) { 3561cb0ef41Sopenharmony_ci status = U_MEMORY_ALLOCATION_ERROR; 3571cb0ef41Sopenharmony_ci } 3581cb0ef41Sopenharmony_ci } 3591cb0ef41Sopenharmony_ci } 3601cb0ef41Sopenharmony_ci /** 3611cb0ef41Sopenharmony_ci * Destructor deletes the array (if owned). 3621cb0ef41Sopenharmony_ci */ 3631cb0ef41Sopenharmony_ci ~MaybeStackArray() { releaseArray(); } 3641cb0ef41Sopenharmony_ci /** 3651cb0ef41Sopenharmony_ci * Move constructor: transfers ownership or copies the stack array. 3661cb0ef41Sopenharmony_ci */ 3671cb0ef41Sopenharmony_ci MaybeStackArray(MaybeStackArray<T, stackCapacity> &&src) noexcept; 3681cb0ef41Sopenharmony_ci /** 3691cb0ef41Sopenharmony_ci * Move assignment: transfers ownership or copies the stack array. 3701cb0ef41Sopenharmony_ci */ 3711cb0ef41Sopenharmony_ci MaybeStackArray<T, stackCapacity> &operator=(MaybeStackArray<T, stackCapacity> &&src) noexcept; 3721cb0ef41Sopenharmony_ci /** 3731cb0ef41Sopenharmony_ci * Returns the array capacity (number of T items). 3741cb0ef41Sopenharmony_ci * @return array capacity 3751cb0ef41Sopenharmony_ci */ 3761cb0ef41Sopenharmony_ci int32_t getCapacity() const { return capacity; } 3771cb0ef41Sopenharmony_ci /** 3781cb0ef41Sopenharmony_ci * Access without ownership change. 3791cb0ef41Sopenharmony_ci * @return the array pointer 3801cb0ef41Sopenharmony_ci */ 3811cb0ef41Sopenharmony_ci T *getAlias() const { return ptr; } 3821cb0ef41Sopenharmony_ci /** 3831cb0ef41Sopenharmony_ci * Returns the array limit. Simple convenience method. 3841cb0ef41Sopenharmony_ci * @return getAlias()+getCapacity() 3851cb0ef41Sopenharmony_ci */ 3861cb0ef41Sopenharmony_ci T *getArrayLimit() const { return getAlias()+capacity; } 3871cb0ef41Sopenharmony_ci // No "operator T *() const" because that can make 3881cb0ef41Sopenharmony_ci // expressions like mbs[index] ambiguous for some compilers. 3891cb0ef41Sopenharmony_ci /** 3901cb0ef41Sopenharmony_ci * Array item access (const). 3911cb0ef41Sopenharmony_ci * No index bounds check. 3921cb0ef41Sopenharmony_ci * @param i array index 3931cb0ef41Sopenharmony_ci * @return reference to the array item 3941cb0ef41Sopenharmony_ci */ 3951cb0ef41Sopenharmony_ci const T &operator[](ptrdiff_t i) const { return ptr[i]; } 3961cb0ef41Sopenharmony_ci /** 3971cb0ef41Sopenharmony_ci * Array item access (writable). 3981cb0ef41Sopenharmony_ci * No index bounds check. 3991cb0ef41Sopenharmony_ci * @param i array index 4001cb0ef41Sopenharmony_ci * @return reference to the array item 4011cb0ef41Sopenharmony_ci */ 4021cb0ef41Sopenharmony_ci T &operator[](ptrdiff_t i) { return ptr[i]; } 4031cb0ef41Sopenharmony_ci /** 4041cb0ef41Sopenharmony_ci * Deletes the array (if owned) and aliases another one, no transfer of ownership. 4051cb0ef41Sopenharmony_ci * If the arguments are illegal, then the current array is unchanged. 4061cb0ef41Sopenharmony_ci * @param otherArray must not be nullptr 4071cb0ef41Sopenharmony_ci * @param otherCapacity must be >0 4081cb0ef41Sopenharmony_ci */ 4091cb0ef41Sopenharmony_ci void aliasInstead(T *otherArray, int32_t otherCapacity) { 4101cb0ef41Sopenharmony_ci if(otherArray!=nullptr && otherCapacity>0) { 4111cb0ef41Sopenharmony_ci releaseArray(); 4121cb0ef41Sopenharmony_ci ptr=otherArray; 4131cb0ef41Sopenharmony_ci capacity=otherCapacity; 4141cb0ef41Sopenharmony_ci needToRelease=false; 4151cb0ef41Sopenharmony_ci } 4161cb0ef41Sopenharmony_ci } 4171cb0ef41Sopenharmony_ci /** 4181cb0ef41Sopenharmony_ci * Deletes the array (if owned) and allocates a new one, copying length T items. 4191cb0ef41Sopenharmony_ci * Returns the new array pointer. 4201cb0ef41Sopenharmony_ci * If the allocation fails, then the current array is unchanged and 4211cb0ef41Sopenharmony_ci * this method returns nullptr. 4221cb0ef41Sopenharmony_ci * @param newCapacity can be less than or greater than the current capacity; 4231cb0ef41Sopenharmony_ci * must be >0 4241cb0ef41Sopenharmony_ci * @param length number of T items to be copied from the old array to the new one 4251cb0ef41Sopenharmony_ci * @return the allocated array pointer, or nullptr if the allocation failed 4261cb0ef41Sopenharmony_ci */ 4271cb0ef41Sopenharmony_ci inline T *resize(int32_t newCapacity, int32_t length=0); 4281cb0ef41Sopenharmony_ci /** 4291cb0ef41Sopenharmony_ci * Gives up ownership of the array if owned, or else clones it, 4301cb0ef41Sopenharmony_ci * copying length T items; resets itself to the internal stack array. 4311cb0ef41Sopenharmony_ci * Returns nullptr if the allocation failed. 4321cb0ef41Sopenharmony_ci * @param length number of T items to copy when cloning, 4331cb0ef41Sopenharmony_ci * and capacity of the clone when cloning 4341cb0ef41Sopenharmony_ci * @param resultCapacity will be set to the returned array's capacity (output-only) 4351cb0ef41Sopenharmony_ci * @return the array pointer; 4361cb0ef41Sopenharmony_ci * caller becomes responsible for deleting the array 4371cb0ef41Sopenharmony_ci */ 4381cb0ef41Sopenharmony_ci inline T *orphanOrClone(int32_t length, int32_t &resultCapacity); 4391cb0ef41Sopenharmony_ci 4401cb0ef41Sopenharmony_ciprotected: 4411cb0ef41Sopenharmony_ci // Resizes the array to the size of src, then copies the contents of src. 4421cb0ef41Sopenharmony_ci void copyFrom(const MaybeStackArray &src, UErrorCode &status) { 4431cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 4441cb0ef41Sopenharmony_ci return; 4451cb0ef41Sopenharmony_ci } 4461cb0ef41Sopenharmony_ci if (this->resize(src.capacity, 0) == nullptr) { 4471cb0ef41Sopenharmony_ci status = U_MEMORY_ALLOCATION_ERROR; 4481cb0ef41Sopenharmony_ci return; 4491cb0ef41Sopenharmony_ci } 4501cb0ef41Sopenharmony_ci uprv_memcpy(this->ptr, src.ptr, (size_t)capacity * sizeof(T)); 4511cb0ef41Sopenharmony_ci } 4521cb0ef41Sopenharmony_ci 4531cb0ef41Sopenharmony_ciprivate: 4541cb0ef41Sopenharmony_ci T *ptr; 4551cb0ef41Sopenharmony_ci int32_t capacity; 4561cb0ef41Sopenharmony_ci UBool needToRelease; 4571cb0ef41Sopenharmony_ci T stackArray[stackCapacity]; 4581cb0ef41Sopenharmony_ci void releaseArray() { 4591cb0ef41Sopenharmony_ci if(needToRelease) { 4601cb0ef41Sopenharmony_ci uprv_free(ptr); 4611cb0ef41Sopenharmony_ci } 4621cb0ef41Sopenharmony_ci } 4631cb0ef41Sopenharmony_ci void resetToStackArray() { 4641cb0ef41Sopenharmony_ci ptr=stackArray; 4651cb0ef41Sopenharmony_ci capacity=stackCapacity; 4661cb0ef41Sopenharmony_ci needToRelease=false; 4671cb0ef41Sopenharmony_ci } 4681cb0ef41Sopenharmony_ci /* No comparison operators with other MaybeStackArray's. */ 4691cb0ef41Sopenharmony_ci bool operator==(const MaybeStackArray & /*other*/) = delete; 4701cb0ef41Sopenharmony_ci bool operator!=(const MaybeStackArray & /*other*/) = delete; 4711cb0ef41Sopenharmony_ci /* No ownership transfer: No copy constructor, no assignment operator. */ 4721cb0ef41Sopenharmony_ci MaybeStackArray(const MaybeStackArray & /*other*/) = delete; 4731cb0ef41Sopenharmony_ci void operator=(const MaybeStackArray & /*other*/) = delete; 4741cb0ef41Sopenharmony_ci}; 4751cb0ef41Sopenharmony_ci 4761cb0ef41Sopenharmony_citemplate<typename T, int32_t stackCapacity> 4771cb0ef41Sopenharmony_ciicu::MaybeStackArray<T, stackCapacity>::MaybeStackArray( 4781cb0ef41Sopenharmony_ci MaybeStackArray <T, stackCapacity>&& src) noexcept 4791cb0ef41Sopenharmony_ci : ptr(src.ptr), capacity(src.capacity), needToRelease(src.needToRelease) { 4801cb0ef41Sopenharmony_ci if (src.ptr == src.stackArray) { 4811cb0ef41Sopenharmony_ci ptr = stackArray; 4821cb0ef41Sopenharmony_ci uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity); 4831cb0ef41Sopenharmony_ci } else { 4841cb0ef41Sopenharmony_ci src.resetToStackArray(); // take ownership away from src 4851cb0ef41Sopenharmony_ci } 4861cb0ef41Sopenharmony_ci} 4871cb0ef41Sopenharmony_ci 4881cb0ef41Sopenharmony_citemplate<typename T, int32_t stackCapacity> 4891cb0ef41Sopenharmony_ciinline MaybeStackArray <T, stackCapacity>& 4901cb0ef41Sopenharmony_ciMaybeStackArray<T, stackCapacity>::operator=(MaybeStackArray <T, stackCapacity>&& src) noexcept { 4911cb0ef41Sopenharmony_ci releaseArray(); // in case this instance had its own memory allocated 4921cb0ef41Sopenharmony_ci capacity = src.capacity; 4931cb0ef41Sopenharmony_ci needToRelease = src.needToRelease; 4941cb0ef41Sopenharmony_ci if (src.ptr == src.stackArray) { 4951cb0ef41Sopenharmony_ci ptr = stackArray; 4961cb0ef41Sopenharmony_ci uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity); 4971cb0ef41Sopenharmony_ci } else { 4981cb0ef41Sopenharmony_ci ptr = src.ptr; 4991cb0ef41Sopenharmony_ci src.resetToStackArray(); // take ownership away from src 5001cb0ef41Sopenharmony_ci } 5011cb0ef41Sopenharmony_ci return *this; 5021cb0ef41Sopenharmony_ci} 5031cb0ef41Sopenharmony_ci 5041cb0ef41Sopenharmony_citemplate<typename T, int32_t stackCapacity> 5051cb0ef41Sopenharmony_ciinline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) { 5061cb0ef41Sopenharmony_ci if(newCapacity>0) { 5071cb0ef41Sopenharmony_ci#if U_DEBUG && defined(UPRV_MALLOC_COUNT) 5081cb0ef41Sopenharmony_ci ::fprintf(::stderr, "MaybeStackArray (resize) alloc %d * %lu\n", newCapacity, sizeof(T)); 5091cb0ef41Sopenharmony_ci#endif 5101cb0ef41Sopenharmony_ci T *p=(T *)uprv_malloc(newCapacity*sizeof(T)); 5111cb0ef41Sopenharmony_ci if(p!=nullptr) { 5121cb0ef41Sopenharmony_ci if(length>0) { 5131cb0ef41Sopenharmony_ci if(length>capacity) { 5141cb0ef41Sopenharmony_ci length=capacity; 5151cb0ef41Sopenharmony_ci } 5161cb0ef41Sopenharmony_ci if(length>newCapacity) { 5171cb0ef41Sopenharmony_ci length=newCapacity; 5181cb0ef41Sopenharmony_ci } 5191cb0ef41Sopenharmony_ci uprv_memcpy(p, ptr, (size_t)length*sizeof(T)); 5201cb0ef41Sopenharmony_ci } 5211cb0ef41Sopenharmony_ci releaseArray(); 5221cb0ef41Sopenharmony_ci ptr=p; 5231cb0ef41Sopenharmony_ci capacity=newCapacity; 5241cb0ef41Sopenharmony_ci needToRelease=true; 5251cb0ef41Sopenharmony_ci } 5261cb0ef41Sopenharmony_ci return p; 5271cb0ef41Sopenharmony_ci } else { 5281cb0ef41Sopenharmony_ci return nullptr; 5291cb0ef41Sopenharmony_ci } 5301cb0ef41Sopenharmony_ci} 5311cb0ef41Sopenharmony_ci 5321cb0ef41Sopenharmony_citemplate<typename T, int32_t stackCapacity> 5331cb0ef41Sopenharmony_ciinline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) { 5341cb0ef41Sopenharmony_ci T *p; 5351cb0ef41Sopenharmony_ci if(needToRelease) { 5361cb0ef41Sopenharmony_ci p=ptr; 5371cb0ef41Sopenharmony_ci } else if(length<=0) { 5381cb0ef41Sopenharmony_ci return nullptr; 5391cb0ef41Sopenharmony_ci } else { 5401cb0ef41Sopenharmony_ci if(length>capacity) { 5411cb0ef41Sopenharmony_ci length=capacity; 5421cb0ef41Sopenharmony_ci } 5431cb0ef41Sopenharmony_ci p=(T *)uprv_malloc(length*sizeof(T)); 5441cb0ef41Sopenharmony_ci#if U_DEBUG && defined(UPRV_MALLOC_COUNT) 5451cb0ef41Sopenharmony_ci ::fprintf(::stderr,"MaybeStacArray (orphan) alloc %d * %lu\n", length,sizeof(T)); 5461cb0ef41Sopenharmony_ci#endif 5471cb0ef41Sopenharmony_ci if(p==nullptr) { 5481cb0ef41Sopenharmony_ci return nullptr; 5491cb0ef41Sopenharmony_ci } 5501cb0ef41Sopenharmony_ci uprv_memcpy(p, ptr, (size_t)length*sizeof(T)); 5511cb0ef41Sopenharmony_ci } 5521cb0ef41Sopenharmony_ci resultCapacity=length; 5531cb0ef41Sopenharmony_ci resetToStackArray(); 5541cb0ef41Sopenharmony_ci return p; 5551cb0ef41Sopenharmony_ci} 5561cb0ef41Sopenharmony_ci 5571cb0ef41Sopenharmony_ci/** 5581cb0ef41Sopenharmony_ci * Variant of MaybeStackArray that allocates a header struct and an array 5591cb0ef41Sopenharmony_ci * in one contiguous memory block, using uprv_malloc() and uprv_free(). 5601cb0ef41Sopenharmony_ci * Provides internal memory with fixed array capacity. Can alias another memory 5611cb0ef41Sopenharmony_ci * block or allocate one. 5621cb0ef41Sopenharmony_ci * The stackCapacity is the number of T items in the internal memory, 5631cb0ef41Sopenharmony_ci * not counting the H header. 5641cb0ef41Sopenharmony_ci * Unlike LocalMemory and LocalArray, this class never adopts 5651cb0ef41Sopenharmony_ci * (takes ownership of) another memory block. 5661cb0ef41Sopenharmony_ci */ 5671cb0ef41Sopenharmony_citemplate<typename H, typename T, int32_t stackCapacity> 5681cb0ef41Sopenharmony_ciclass MaybeStackHeaderAndArray { 5691cb0ef41Sopenharmony_cipublic: 5701cb0ef41Sopenharmony_ci // No heap allocation. Use only on the stack. 5711cb0ef41Sopenharmony_ci static void* U_EXPORT2 operator new(size_t) noexcept = delete; 5721cb0ef41Sopenharmony_ci static void* U_EXPORT2 operator new[](size_t) noexcept = delete; 5731cb0ef41Sopenharmony_ci#if U_HAVE_PLACEMENT_NEW 5741cb0ef41Sopenharmony_ci static void* U_EXPORT2 operator new(size_t, void*) noexcept = delete; 5751cb0ef41Sopenharmony_ci#endif 5761cb0ef41Sopenharmony_ci 5771cb0ef41Sopenharmony_ci /** 5781cb0ef41Sopenharmony_ci * Default constructor initializes with internal H+T[stackCapacity] buffer. 5791cb0ef41Sopenharmony_ci */ 5801cb0ef41Sopenharmony_ci MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(false) {} 5811cb0ef41Sopenharmony_ci /** 5821cb0ef41Sopenharmony_ci * Destructor deletes the memory (if owned). 5831cb0ef41Sopenharmony_ci */ 5841cb0ef41Sopenharmony_ci ~MaybeStackHeaderAndArray() { releaseMemory(); } 5851cb0ef41Sopenharmony_ci /** 5861cb0ef41Sopenharmony_ci * Returns the array capacity (number of T items). 5871cb0ef41Sopenharmony_ci * @return array capacity 5881cb0ef41Sopenharmony_ci */ 5891cb0ef41Sopenharmony_ci int32_t getCapacity() const { return capacity; } 5901cb0ef41Sopenharmony_ci /** 5911cb0ef41Sopenharmony_ci * Access without ownership change. 5921cb0ef41Sopenharmony_ci * @return the header pointer 5931cb0ef41Sopenharmony_ci */ 5941cb0ef41Sopenharmony_ci H *getAlias() const { return ptr; } 5951cb0ef41Sopenharmony_ci /** 5961cb0ef41Sopenharmony_ci * Returns the array start. 5971cb0ef41Sopenharmony_ci * @return array start, same address as getAlias()+1 5981cb0ef41Sopenharmony_ci */ 5991cb0ef41Sopenharmony_ci T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); } 6001cb0ef41Sopenharmony_ci /** 6011cb0ef41Sopenharmony_ci * Returns the array limit. 6021cb0ef41Sopenharmony_ci * @return array limit 6031cb0ef41Sopenharmony_ci */ 6041cb0ef41Sopenharmony_ci T *getArrayLimit() const { return getArrayStart()+capacity; } 6051cb0ef41Sopenharmony_ci /** 6061cb0ef41Sopenharmony_ci * Access without ownership change. Same as getAlias(). 6071cb0ef41Sopenharmony_ci * A class instance can be used directly in expressions that take a T *. 6081cb0ef41Sopenharmony_ci * @return the header pointer 6091cb0ef41Sopenharmony_ci */ 6101cb0ef41Sopenharmony_ci operator H *() const { return ptr; } 6111cb0ef41Sopenharmony_ci /** 6121cb0ef41Sopenharmony_ci * Array item access (writable). 6131cb0ef41Sopenharmony_ci * No index bounds check. 6141cb0ef41Sopenharmony_ci * @param i array index 6151cb0ef41Sopenharmony_ci * @return reference to the array item 6161cb0ef41Sopenharmony_ci */ 6171cb0ef41Sopenharmony_ci T &operator[](ptrdiff_t i) { return getArrayStart()[i]; } 6181cb0ef41Sopenharmony_ci /** 6191cb0ef41Sopenharmony_ci * Deletes the memory block (if owned) and aliases another one, no transfer of ownership. 6201cb0ef41Sopenharmony_ci * If the arguments are illegal, then the current memory is unchanged. 6211cb0ef41Sopenharmony_ci * @param otherArray must not be nullptr 6221cb0ef41Sopenharmony_ci * @param otherCapacity must be >0 6231cb0ef41Sopenharmony_ci */ 6241cb0ef41Sopenharmony_ci void aliasInstead(H *otherMemory, int32_t otherCapacity) { 6251cb0ef41Sopenharmony_ci if(otherMemory!=nullptr && otherCapacity>0) { 6261cb0ef41Sopenharmony_ci releaseMemory(); 6271cb0ef41Sopenharmony_ci ptr=otherMemory; 6281cb0ef41Sopenharmony_ci capacity=otherCapacity; 6291cb0ef41Sopenharmony_ci needToRelease=false; 6301cb0ef41Sopenharmony_ci } 6311cb0ef41Sopenharmony_ci } 6321cb0ef41Sopenharmony_ci /** 6331cb0ef41Sopenharmony_ci * Deletes the memory block (if owned) and allocates a new one, 6341cb0ef41Sopenharmony_ci * copying the header and length T array items. 6351cb0ef41Sopenharmony_ci * Returns the new header pointer. 6361cb0ef41Sopenharmony_ci * If the allocation fails, then the current memory is unchanged and 6371cb0ef41Sopenharmony_ci * this method returns nullptr. 6381cb0ef41Sopenharmony_ci * @param newCapacity can be less than or greater than the current capacity; 6391cb0ef41Sopenharmony_ci * must be >0 6401cb0ef41Sopenharmony_ci * @param length number of T items to be copied from the old array to the new one 6411cb0ef41Sopenharmony_ci * @return the allocated pointer, or nullptr if the allocation failed 6421cb0ef41Sopenharmony_ci */ 6431cb0ef41Sopenharmony_ci inline H *resize(int32_t newCapacity, int32_t length=0); 6441cb0ef41Sopenharmony_ci /** 6451cb0ef41Sopenharmony_ci * Gives up ownership of the memory if owned, or else clones it, 6461cb0ef41Sopenharmony_ci * copying the header and length T array items; resets itself to the internal memory. 6471cb0ef41Sopenharmony_ci * Returns nullptr if the allocation failed. 6481cb0ef41Sopenharmony_ci * @param length number of T items to copy when cloning, 6491cb0ef41Sopenharmony_ci * and array capacity of the clone when cloning 6501cb0ef41Sopenharmony_ci * @param resultCapacity will be set to the returned array's capacity (output-only) 6511cb0ef41Sopenharmony_ci * @return the header pointer; 6521cb0ef41Sopenharmony_ci * caller becomes responsible for deleting the array 6531cb0ef41Sopenharmony_ci */ 6541cb0ef41Sopenharmony_ci inline H *orphanOrClone(int32_t length, int32_t &resultCapacity); 6551cb0ef41Sopenharmony_ciprivate: 6561cb0ef41Sopenharmony_ci H *ptr; 6571cb0ef41Sopenharmony_ci int32_t capacity; 6581cb0ef41Sopenharmony_ci UBool needToRelease; 6591cb0ef41Sopenharmony_ci // stackHeader must precede stackArray immediately. 6601cb0ef41Sopenharmony_ci H stackHeader; 6611cb0ef41Sopenharmony_ci T stackArray[stackCapacity]; 6621cb0ef41Sopenharmony_ci void releaseMemory() { 6631cb0ef41Sopenharmony_ci if(needToRelease) { 6641cb0ef41Sopenharmony_ci uprv_free(ptr); 6651cb0ef41Sopenharmony_ci } 6661cb0ef41Sopenharmony_ci } 6671cb0ef41Sopenharmony_ci /* No comparison operators with other MaybeStackHeaderAndArray's. */ 6681cb0ef41Sopenharmony_ci bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return false;} 6691cb0ef41Sopenharmony_ci bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return true;} 6701cb0ef41Sopenharmony_ci /* No ownership transfer: No copy constructor, no assignment operator. */ 6711cb0ef41Sopenharmony_ci MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {} 6721cb0ef41Sopenharmony_ci void operator=(const MaybeStackHeaderAndArray & /*other*/) {} 6731cb0ef41Sopenharmony_ci}; 6741cb0ef41Sopenharmony_ci 6751cb0ef41Sopenharmony_citemplate<typename H, typename T, int32_t stackCapacity> 6761cb0ef41Sopenharmony_ciinline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity, 6771cb0ef41Sopenharmony_ci int32_t length) { 6781cb0ef41Sopenharmony_ci if(newCapacity>=0) { 6791cb0ef41Sopenharmony_ci#if U_DEBUG && defined(UPRV_MALLOC_COUNT) 6801cb0ef41Sopenharmony_ci ::fprintf(::stderr,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H),newCapacity,sizeof(T)); 6811cb0ef41Sopenharmony_ci#endif 6821cb0ef41Sopenharmony_ci H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T)); 6831cb0ef41Sopenharmony_ci if(p!=nullptr) { 6841cb0ef41Sopenharmony_ci if(length<0) { 6851cb0ef41Sopenharmony_ci length=0; 6861cb0ef41Sopenharmony_ci } else if(length>0) { 6871cb0ef41Sopenharmony_ci if(length>capacity) { 6881cb0ef41Sopenharmony_ci length=capacity; 6891cb0ef41Sopenharmony_ci } 6901cb0ef41Sopenharmony_ci if(length>newCapacity) { 6911cb0ef41Sopenharmony_ci length=newCapacity; 6921cb0ef41Sopenharmony_ci } 6931cb0ef41Sopenharmony_ci } 6941cb0ef41Sopenharmony_ci uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T)); 6951cb0ef41Sopenharmony_ci releaseMemory(); 6961cb0ef41Sopenharmony_ci ptr=p; 6971cb0ef41Sopenharmony_ci capacity=newCapacity; 6981cb0ef41Sopenharmony_ci needToRelease=true; 6991cb0ef41Sopenharmony_ci } 7001cb0ef41Sopenharmony_ci return p; 7011cb0ef41Sopenharmony_ci } else { 7021cb0ef41Sopenharmony_ci return nullptr; 7031cb0ef41Sopenharmony_ci } 7041cb0ef41Sopenharmony_ci} 7051cb0ef41Sopenharmony_ci 7061cb0ef41Sopenharmony_citemplate<typename H, typename T, int32_t stackCapacity> 7071cb0ef41Sopenharmony_ciinline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length, 7081cb0ef41Sopenharmony_ci int32_t &resultCapacity) { 7091cb0ef41Sopenharmony_ci H *p; 7101cb0ef41Sopenharmony_ci if(needToRelease) { 7111cb0ef41Sopenharmony_ci p=ptr; 7121cb0ef41Sopenharmony_ci } else { 7131cb0ef41Sopenharmony_ci if(length<0) { 7141cb0ef41Sopenharmony_ci length=0; 7151cb0ef41Sopenharmony_ci } else if(length>capacity) { 7161cb0ef41Sopenharmony_ci length=capacity; 7171cb0ef41Sopenharmony_ci } 7181cb0ef41Sopenharmony_ci#if U_DEBUG && defined(UPRV_MALLOC_COUNT) 7191cb0ef41Sopenharmony_ci ::fprintf(::stderr,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H),length,sizeof(T)); 7201cb0ef41Sopenharmony_ci#endif 7211cb0ef41Sopenharmony_ci p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T)); 7221cb0ef41Sopenharmony_ci if(p==nullptr) { 7231cb0ef41Sopenharmony_ci return nullptr; 7241cb0ef41Sopenharmony_ci } 7251cb0ef41Sopenharmony_ci uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T)); 7261cb0ef41Sopenharmony_ci } 7271cb0ef41Sopenharmony_ci resultCapacity=length; 7281cb0ef41Sopenharmony_ci ptr=&stackHeader; 7291cb0ef41Sopenharmony_ci capacity=stackCapacity; 7301cb0ef41Sopenharmony_ci needToRelease=false; 7311cb0ef41Sopenharmony_ci return p; 7321cb0ef41Sopenharmony_ci} 7331cb0ef41Sopenharmony_ci 7341cb0ef41Sopenharmony_ci/** 7351cb0ef41Sopenharmony_ci * A simple memory management class that creates new heap allocated objects (of 7361cb0ef41Sopenharmony_ci * any class that has a public constructor), keeps track of them and eventually 7371cb0ef41Sopenharmony_ci * deletes them all in its own destructor. 7381cb0ef41Sopenharmony_ci * 7391cb0ef41Sopenharmony_ci * A typical use-case would be code like this: 7401cb0ef41Sopenharmony_ci * 7411cb0ef41Sopenharmony_ci * MemoryPool<MyType> pool; 7421cb0ef41Sopenharmony_ci * 7431cb0ef41Sopenharmony_ci * MyType* o1 = pool.create(); 7441cb0ef41Sopenharmony_ci * if (o1 != nullptr) { 7451cb0ef41Sopenharmony_ci * foo(o1); 7461cb0ef41Sopenharmony_ci * } 7471cb0ef41Sopenharmony_ci * 7481cb0ef41Sopenharmony_ci * MyType* o2 = pool.create(1, 2, 3); 7491cb0ef41Sopenharmony_ci * if (o2 != nullptr) { 7501cb0ef41Sopenharmony_ci * bar(o2); 7511cb0ef41Sopenharmony_ci * } 7521cb0ef41Sopenharmony_ci * 7531cb0ef41Sopenharmony_ci * // MemoryPool will take care of deleting the MyType objects. 7541cb0ef41Sopenharmony_ci * 7551cb0ef41Sopenharmony_ci * It doesn't do anything more than that, and is intentionally kept minimalist. 7561cb0ef41Sopenharmony_ci */ 7571cb0ef41Sopenharmony_citemplate<typename T, int32_t stackCapacity = 8> 7581cb0ef41Sopenharmony_ciclass MemoryPool : public UMemory { 7591cb0ef41Sopenharmony_cipublic: 7601cb0ef41Sopenharmony_ci MemoryPool() : fCount(0), fPool() {} 7611cb0ef41Sopenharmony_ci 7621cb0ef41Sopenharmony_ci ~MemoryPool() { 7631cb0ef41Sopenharmony_ci for (int32_t i = 0; i < fCount; ++i) { 7641cb0ef41Sopenharmony_ci delete fPool[i]; 7651cb0ef41Sopenharmony_ci } 7661cb0ef41Sopenharmony_ci } 7671cb0ef41Sopenharmony_ci 7681cb0ef41Sopenharmony_ci MemoryPool(const MemoryPool&) = delete; 7691cb0ef41Sopenharmony_ci MemoryPool& operator=(const MemoryPool&) = delete; 7701cb0ef41Sopenharmony_ci 7711cb0ef41Sopenharmony_ci MemoryPool(MemoryPool&& other) noexcept : fCount(other.fCount), 7721cb0ef41Sopenharmony_ci fPool(std::move(other.fPool)) { 7731cb0ef41Sopenharmony_ci other.fCount = 0; 7741cb0ef41Sopenharmony_ci } 7751cb0ef41Sopenharmony_ci 7761cb0ef41Sopenharmony_ci MemoryPool& operator=(MemoryPool&& other) noexcept { 7771cb0ef41Sopenharmony_ci // Since `this` may contain instances that need to be deleted, we can't 7781cb0ef41Sopenharmony_ci // just throw them away and replace them with `other`. The normal way of 7791cb0ef41Sopenharmony_ci // dealing with this in C++ is to swap `this` and `other`, rather than 7801cb0ef41Sopenharmony_ci // simply overwrite: the destruction of `other` can then take care of 7811cb0ef41Sopenharmony_ci // running MemoryPool::~MemoryPool() over the still-to-be-deallocated 7821cb0ef41Sopenharmony_ci // instances. 7831cb0ef41Sopenharmony_ci std::swap(fCount, other.fCount); 7841cb0ef41Sopenharmony_ci std::swap(fPool, other.fPool); 7851cb0ef41Sopenharmony_ci return *this; 7861cb0ef41Sopenharmony_ci } 7871cb0ef41Sopenharmony_ci 7881cb0ef41Sopenharmony_ci /** 7891cb0ef41Sopenharmony_ci * Creates a new object of typename T, by forwarding any and all arguments 7901cb0ef41Sopenharmony_ci * to the typename T constructor. 7911cb0ef41Sopenharmony_ci * 7921cb0ef41Sopenharmony_ci * @param args Arguments to be forwarded to the typename T constructor. 7931cb0ef41Sopenharmony_ci * @return A pointer to the newly created object, or nullptr on error. 7941cb0ef41Sopenharmony_ci */ 7951cb0ef41Sopenharmony_ci template<typename... Args> 7961cb0ef41Sopenharmony_ci T* create(Args&&... args) { 7971cb0ef41Sopenharmony_ci int32_t capacity = fPool.getCapacity(); 7981cb0ef41Sopenharmony_ci if (fCount == capacity && 7991cb0ef41Sopenharmony_ci fPool.resize(capacity == stackCapacity ? 4 * capacity : 2 * capacity, 8001cb0ef41Sopenharmony_ci capacity) == nullptr) { 8011cb0ef41Sopenharmony_ci return nullptr; 8021cb0ef41Sopenharmony_ci } 8031cb0ef41Sopenharmony_ci return fPool[fCount++] = new T(std::forward<Args>(args)...); 8041cb0ef41Sopenharmony_ci } 8051cb0ef41Sopenharmony_ci 8061cb0ef41Sopenharmony_ci template <typename... Args> 8071cb0ef41Sopenharmony_ci T* createAndCheckErrorCode(UErrorCode &status, Args &&... args) { 8081cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 8091cb0ef41Sopenharmony_ci return nullptr; 8101cb0ef41Sopenharmony_ci } 8111cb0ef41Sopenharmony_ci T *pointer = this->create(args...); 8121cb0ef41Sopenharmony_ci if (U_SUCCESS(status) && pointer == nullptr) { 8131cb0ef41Sopenharmony_ci status = U_MEMORY_ALLOCATION_ERROR; 8141cb0ef41Sopenharmony_ci } 8151cb0ef41Sopenharmony_ci return pointer; 8161cb0ef41Sopenharmony_ci } 8171cb0ef41Sopenharmony_ci 8181cb0ef41Sopenharmony_ci /** 8191cb0ef41Sopenharmony_ci * @return Number of elements that have been allocated. 8201cb0ef41Sopenharmony_ci */ 8211cb0ef41Sopenharmony_ci int32_t count() const { 8221cb0ef41Sopenharmony_ci return fCount; 8231cb0ef41Sopenharmony_ci } 8241cb0ef41Sopenharmony_ci 8251cb0ef41Sopenharmony_ciprotected: 8261cb0ef41Sopenharmony_ci int32_t fCount; 8271cb0ef41Sopenharmony_ci MaybeStackArray<T*, stackCapacity> fPool; 8281cb0ef41Sopenharmony_ci}; 8291cb0ef41Sopenharmony_ci 8301cb0ef41Sopenharmony_ci/** 8311cb0ef41Sopenharmony_ci * An internal Vector-like implementation based on MemoryPool. 8321cb0ef41Sopenharmony_ci * 8331cb0ef41Sopenharmony_ci * Heap-allocates each element and stores pointers. 8341cb0ef41Sopenharmony_ci * 8351cb0ef41Sopenharmony_ci * To append an item to the vector, use emplaceBack. 8361cb0ef41Sopenharmony_ci * 8371cb0ef41Sopenharmony_ci * MaybeStackVector<MyType> vector; 8381cb0ef41Sopenharmony_ci * MyType* element = vector.emplaceBack(); 8391cb0ef41Sopenharmony_ci * if (!element) { 8401cb0ef41Sopenharmony_ci * status = U_MEMORY_ALLOCATION_ERROR; 8411cb0ef41Sopenharmony_ci * } 8421cb0ef41Sopenharmony_ci * // do stuff with element 8431cb0ef41Sopenharmony_ci * 8441cb0ef41Sopenharmony_ci * To loop over the vector, use a for loop with indices: 8451cb0ef41Sopenharmony_ci * 8461cb0ef41Sopenharmony_ci * for (int32_t i = 0; i < vector.length(); i++) { 8471cb0ef41Sopenharmony_ci * MyType* element = vector[i]; 8481cb0ef41Sopenharmony_ci * } 8491cb0ef41Sopenharmony_ci */ 8501cb0ef41Sopenharmony_citemplate<typename T, int32_t stackCapacity = 8> 8511cb0ef41Sopenharmony_ciclass MaybeStackVector : protected MemoryPool<T, stackCapacity> { 8521cb0ef41Sopenharmony_cipublic: 8531cb0ef41Sopenharmony_ci template<typename... Args> 8541cb0ef41Sopenharmony_ci T* emplaceBack(Args&&... args) { 8551cb0ef41Sopenharmony_ci return this->create(args...); 8561cb0ef41Sopenharmony_ci } 8571cb0ef41Sopenharmony_ci 8581cb0ef41Sopenharmony_ci template <typename... Args> 8591cb0ef41Sopenharmony_ci T *emplaceBackAndCheckErrorCode(UErrorCode &status, Args &&... args) { 8601cb0ef41Sopenharmony_ci return this->createAndCheckErrorCode(status, args...); 8611cb0ef41Sopenharmony_ci } 8621cb0ef41Sopenharmony_ci 8631cb0ef41Sopenharmony_ci int32_t length() const { 8641cb0ef41Sopenharmony_ci return this->fCount; 8651cb0ef41Sopenharmony_ci } 8661cb0ef41Sopenharmony_ci 8671cb0ef41Sopenharmony_ci T** getAlias() { 8681cb0ef41Sopenharmony_ci return this->fPool.getAlias(); 8691cb0ef41Sopenharmony_ci } 8701cb0ef41Sopenharmony_ci 8711cb0ef41Sopenharmony_ci const T *const *getAlias() const { 8721cb0ef41Sopenharmony_ci return this->fPool.getAlias(); 8731cb0ef41Sopenharmony_ci } 8741cb0ef41Sopenharmony_ci 8751cb0ef41Sopenharmony_ci /** 8761cb0ef41Sopenharmony_ci * Array item access (read-only). 8771cb0ef41Sopenharmony_ci * No index bounds check. 8781cb0ef41Sopenharmony_ci * @param i array index 8791cb0ef41Sopenharmony_ci * @return reference to the array item 8801cb0ef41Sopenharmony_ci */ 8811cb0ef41Sopenharmony_ci const T* operator[](ptrdiff_t i) const { 8821cb0ef41Sopenharmony_ci return this->fPool[i]; 8831cb0ef41Sopenharmony_ci } 8841cb0ef41Sopenharmony_ci 8851cb0ef41Sopenharmony_ci /** 8861cb0ef41Sopenharmony_ci * Array item access (writable). 8871cb0ef41Sopenharmony_ci * No index bounds check. 8881cb0ef41Sopenharmony_ci * @param i array index 8891cb0ef41Sopenharmony_ci * @return reference to the array item 8901cb0ef41Sopenharmony_ci */ 8911cb0ef41Sopenharmony_ci T* operator[](ptrdiff_t i) { 8921cb0ef41Sopenharmony_ci return this->fPool[i]; 8931cb0ef41Sopenharmony_ci } 8941cb0ef41Sopenharmony_ci}; 8951cb0ef41Sopenharmony_ci 8961cb0ef41Sopenharmony_ci 8971cb0ef41Sopenharmony_ciU_NAMESPACE_END 8981cb0ef41Sopenharmony_ci 8991cb0ef41Sopenharmony_ci#endif /* __cplusplus */ 9001cb0ef41Sopenharmony_ci#endif /* CMEMORY_H */ 901