cmemory.h 30 KB

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