]>
git.saurik.com Git - apple/icu.git/blob - icuSources/common/cmemory.h
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 ******************************************************************************
6 * Copyright (C) 1997-2016, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 ******************************************************************************
13 * Contains stdlib.h/string.h memory functions
15 * @author Bertrand A. Damiba
17 * Modification History:
19 * Date Name Description
20 * 6/20/98 Bertrand Created.
21 * 05/03/99 stephen Changed from functions to macros.
23 ******************************************************************************
29 #include "unicode/utypes.h"
33 #include "unicode/localpointer.h"
35 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
40 #define uprv_memcpy(dst, src, size) U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size)
41 #define uprv_memmove(dst, src, size) U_STANDARD_CPP_NAMESPACE memmove(dst, src, size)
45 * Convenience macro to determine the length of a fixed array at compile-time.
46 * @param array A fixed length array
47 * @return The length of the array, in elements
50 #define UPRV_LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
51 #define uprv_memset(buffer, mark, size) U_STANDARD_CPP_NAMESPACE memset(buffer, mark, size)
52 #define uprv_memcmp(buffer1, buffer2, size) U_STANDARD_CPP_NAMESPACE memcmp(buffer1, buffer2,size)
53 #define uprv_memchr(ptr, value, num) U_STANDARD_CPP_NAMESPACE memchr(ptr, value, num)
55 U_CAPI
void * U_EXPORT2
56 uprv_malloc(size_t s
) U_MALLOC_ATTR
U_ALLOC_SIZE_ATTR(1);
58 U_CAPI
void * U_EXPORT2
59 uprv_realloc(void *mem
, size_t size
) U_ALLOC_SIZE_ATTR(2);
64 U_CAPI
void * U_EXPORT2
65 uprv_calloc(size_t num
, size_t size
) U_MALLOC_ATTR
U_ALLOC_SIZE_ATTR2(1,2);
68 * This should align the memory properly on any machine.
69 * This is very useful for the safeClone functions.
78 * Get the least significant bits of a pointer (a memory address).
79 * For example, with a mask of 3, the macro gets the 2 least significant bits,
80 * which will be 0 if the pointer is 32-bit (4-byte) aligned.
82 * ptrdiff_t is the most appropriate integer type to cast to.
83 * size_t should work too, since on most (or all?) platforms it has the same
86 #define U_POINTER_MASK_LSB(ptr, mask) (((ptrdiff_t)(char *)(ptr)) & (mask))
89 * Get the amount of bytes that a pointer is off by from
90 * the previous UAlignedMemory-aligned pointer.
92 #define U_ALIGNMENT_OFFSET(ptr) U_POINTER_MASK_LSB(ptr, sizeof(UAlignedMemory) - 1)
95 * Get the amount of bytes to add to a pointer
96 * in order to get the next UAlignedMemory-aligned address.
98 #define U_ALIGNMENT_OFFSET_UP(ptr) (sizeof(UAlignedMemory) - U_ALIGNMENT_OFFSET(ptr))
101 * Create & return an instance of "type" in statically allocated storage.
103 * static std::mutex *myMutex = STATIC_NEW(std::mutex);
104 * This is intended for use when
105 * - We want a static (or global) object.
106 * - We don't want it to ever be destructed, to avoid order-of-destruction
107 * or use-after-destruction problems.
108 * - We want to avoid an ordinary heap allocated object, to avoid triggering
109 * memory leak reports, from valgrind, for example.
110 * This is defined as a macro rather than a template function because each invocation
111 * must define distinct static storage for the object being returned.
113 #define STATIC_NEW(type) [] () { \
114 alignas(type) static char storage[sizeof(type)]; \
115 return new(storage) type();} ();
118 * Heap clean up function, called from u_cleanup()
119 * Clears any user heap functions from u_setMemoryFunctions()
120 * Does NOT deallocate any remaining allocated memory.
123 cmemory_cleanup(void);
126 * A function called by <TT>uhash_remove</TT>,
127 * <TT>uhash_close</TT>, or <TT>uhash_put</TT> to delete
128 * an existing key or value.
129 * @param obj A key or value stored in a hashtable
130 * @see uprv_deleteUObject
132 typedef void U_CALLCONV
UObjectDeleter(void* obj
);
135 * Deleter for UObject instances.
136 * Works for all subclasses of UObject because it has a virtual destructor.
138 U_CAPI
void U_EXPORT2
139 uprv_deleteUObject(void *obj
);
144 #include "unicode/uobject.h"
149 * "Smart pointer" class, deletes memory via uprv_free().
150 * For most methods see the LocalPointerBase base class.
151 * Adds operator[] for array item access.
153 * @see LocalPointerBase
156 class LocalMemory
: public LocalPointerBase
<T
> {
158 using LocalPointerBase
<T
>::operator*;
159 using LocalPointerBase
<T
>::operator->;
161 * Constructor takes ownership.
162 * @param p simple pointer to an array of T items that is adopted
164 explicit LocalMemory(T
*p
=NULL
) : LocalPointerBase
<T
>(p
) {}
166 * Move constructor, leaves src with isNull().
167 * @param src source smart pointer
169 LocalMemory(LocalMemory
<T
> &&src
) U_NOEXCEPT
: LocalPointerBase
<T
>(src
.ptr
) {
173 * Destructor deletes the memory it owns.
176 uprv_free(LocalPointerBase
<T
>::ptr
);
179 * Move assignment operator, leaves src with isNull().
180 * The behavior is undefined if *this and src are the same object.
181 * @param src source smart pointer
184 LocalMemory
<T
> &operator=(LocalMemory
<T
> &&src
) U_NOEXCEPT
{
185 uprv_free(LocalPointerBase
<T
>::ptr
);
186 LocalPointerBase
<T
>::ptr
=src
.ptr
;
192 * @param other other smart pointer
194 void swap(LocalMemory
<T
> &other
) U_NOEXCEPT
{
195 T
*temp
=LocalPointerBase
<T
>::ptr
;
196 LocalPointerBase
<T
>::ptr
=other
.ptr
;
200 * Non-member LocalMemory swap function.
201 * @param p1 will get p2's pointer
202 * @param p2 will get p1's pointer
204 friend inline void swap(LocalMemory
<T
> &p1
, LocalMemory
<T
> &p2
) U_NOEXCEPT
{
208 * Deletes the array it owns,
209 * and adopts (takes ownership of) the one passed in.
210 * @param p simple pointer to an array of T items that is adopted
212 void adoptInstead(T
*p
) {
213 uprv_free(LocalPointerBase
<T
>::ptr
);
214 LocalPointerBase
<T
>::ptr
=p
;
217 * Deletes the array it owns, allocates a new one and reset its bytes to 0.
218 * Returns the new array pointer.
219 * If the allocation fails, then the current array is unchanged and
220 * this method returns NULL.
221 * @param newCapacity must be >0
222 * @return the allocated array pointer, or NULL if the allocation failed
224 inline T
*allocateInsteadAndReset(int32_t newCapacity
=1);
226 * Deletes the array it owns and allocates a new one, copying length T items.
227 * Returns the new array pointer.
228 * If the allocation fails, then the current array is unchanged and
229 * this method returns NULL.
230 * @param newCapacity must be >0
231 * @param length number of T items to be copied from the old array to the new one;
232 * must be no more than the capacity of the old array,
233 * which the caller must track because the LocalMemory does not track it
234 * @return the allocated array pointer, or NULL if the allocation failed
236 inline T
*allocateInsteadAndCopy(int32_t newCapacity
=1, int32_t length
=0);
238 * Array item access (writable).
239 * No index bounds check.
240 * @param i array index
241 * @return reference to the array item
243 T
&operator[](ptrdiff_t i
) const { return LocalPointerBase
<T
>::ptr
[i
]; }
247 inline T
*LocalMemory
<T
>::allocateInsteadAndReset(int32_t newCapacity
) {
249 T
*p
=(T
*)uprv_malloc(newCapacity
*sizeof(T
));
251 uprv_memset(p
, 0, newCapacity
*sizeof(T
));
252 uprv_free(LocalPointerBase
<T
>::ptr
);
253 LocalPointerBase
<T
>::ptr
=p
;
263 inline T
*LocalMemory
<T
>::allocateInsteadAndCopy(int32_t newCapacity
, int32_t length
) {
265 T
*p
=(T
*)uprv_malloc(newCapacity
*sizeof(T
));
268 if(length
>newCapacity
) {
271 uprv_memcpy(p
, LocalPointerBase
<T
>::ptr
, (size_t)length
*sizeof(T
));
273 uprv_free(LocalPointerBase
<T
>::ptr
);
274 LocalPointerBase
<T
>::ptr
=p
;
283 * Simple array/buffer management class using uprv_malloc() and uprv_free().
284 * Provides an internal array with fixed capacity. Can alias another array
287 * The array address is properly aligned for type T. It might not be properly
288 * aligned for types larger than T (or larger than the largest subtype of T).
290 * Unlike LocalMemory and LocalArray, this class never adopts
291 * (takes ownership of) another array.
293 * WARNING: MaybeStackArray only works with primitive (plain-old data) types.
294 * It does NOT know how to call a destructor! If you work with classes with
295 * destructors, consider LocalArray in localpointer.h or MemoryPool.
297 template<typename T
, int32_t stackCapacity
>
298 class MaybeStackArray
{
300 // No heap allocation. Use only on the stack.
301 static void* U_EXPORT2
operator new(size_t) U_NOEXCEPT
= delete;
302 static void* U_EXPORT2
operator new[](size_t) U_NOEXCEPT
= delete;
303 #if U_HAVE_PLACEMENT_NEW
304 static void* U_EXPORT2
operator new(size_t, void*) U_NOEXCEPT
= delete;
308 * Default constructor initializes with internal T[stackCapacity] buffer.
310 MaybeStackArray() : ptr(stackArray
), capacity(stackCapacity
), needToRelease(FALSE
) {}
312 * Automatically allocates the heap array if the argument is larger than the stack capacity.
313 * Intended for use when an approximate capacity is known at compile time but the true
314 * capacity is not known until runtime.
316 MaybeStackArray(int32_t newCapacity
) : MaybeStackArray() {
317 if (capacity
< newCapacity
) { resize(newCapacity
); }
320 * Destructor deletes the array (if owned).
322 ~MaybeStackArray() { releaseArray(); }
324 * Move constructor: transfers ownership or copies the stack array.
326 MaybeStackArray(MaybeStackArray
<T
, stackCapacity
> &&src
) U_NOEXCEPT
;
328 * Move assignment: transfers ownership or copies the stack array.
330 MaybeStackArray
<T
, stackCapacity
> &operator=(MaybeStackArray
<T
, stackCapacity
> &&src
) U_NOEXCEPT
;
332 * Returns the array capacity (number of T items).
333 * @return array capacity
335 int32_t getCapacity() const { return capacity
; }
337 * Access without ownership change.
338 * @return the array pointer
340 T
*getAlias() const { return ptr
; }
342 * Returns the array limit. Simple convenience method.
343 * @return getAlias()+getCapacity()
345 T
*getArrayLimit() const { return getAlias()+capacity
; }
346 // No "operator T *() const" because that can make
347 // expressions like mbs[index] ambiguous for some compilers.
349 * Array item access (const).
350 * No index bounds check.
351 * @param i array index
352 * @return reference to the array item
354 const T
&operator[](ptrdiff_t i
) const { return ptr
[i
]; }
356 * Array item access (writable).
357 * No index bounds check.
358 * @param i array index
359 * @return reference to the array item
361 T
&operator[](ptrdiff_t i
) { return ptr
[i
]; }
363 * Deletes the array (if owned) and aliases another one, no transfer of ownership.
364 * If the arguments are illegal, then the current array is unchanged.
365 * @param otherArray must not be NULL
366 * @param otherCapacity must be >0
368 void aliasInstead(T
*otherArray
, int32_t otherCapacity
) {
369 if(otherArray
!=NULL
&& otherCapacity
>0) {
372 capacity
=otherCapacity
;
377 * Deletes the array (if owned) and allocates a new one, copying length T items.
378 * Returns the new array pointer.
379 * If the allocation fails, then the current array is unchanged and
380 * this method returns NULL.
381 * @param newCapacity can be less than or greater than the current capacity;
383 * @param length number of T items to be copied from the old array to the new one
384 * @return the allocated array pointer, or NULL if the allocation failed
386 inline T
*resize(int32_t newCapacity
, int32_t length
=0);
388 * Gives up ownership of the array if owned, or else clones it,
389 * copying length T items; resets itself to the internal stack array.
390 * Returns NULL if the allocation failed.
391 * @param length number of T items to copy when cloning,
392 * and capacity of the clone when cloning
393 * @param resultCapacity will be set to the returned array's capacity (output-only)
394 * @return the array pointer;
395 * caller becomes responsible for deleting the array
397 inline T
*orphanOrClone(int32_t length
, int32_t &resultCapacity
);
402 T stackArray
[stackCapacity
];
403 void releaseArray() {
408 void resetToStackArray() {
410 capacity
=stackCapacity
;
413 /* No comparison operators with other MaybeStackArray's. */
414 bool operator==(const MaybeStackArray
& /*other*/) {return FALSE
;}
415 bool operator!=(const MaybeStackArray
& /*other*/) {return TRUE
;}
416 /* No ownership transfer: No copy constructor, no assignment operator. */
417 MaybeStackArray(const MaybeStackArray
& /*other*/) {}
418 void operator=(const MaybeStackArray
& /*other*/) {}
421 template<typename T
, int32_t stackCapacity
>
422 icu::MaybeStackArray
<T
, stackCapacity
>::MaybeStackArray(
423 MaybeStackArray
<T
, stackCapacity
>&& src
) U_NOEXCEPT
424 : ptr(src
.ptr
), capacity(src
.capacity
), needToRelease(src
.needToRelease
) {
425 if (src
.ptr
== src
.stackArray
) {
427 uprv_memcpy(stackArray
, src
.stackArray
, sizeof(T
) * src
.capacity
);
429 src
.resetToStackArray(); // take ownership away from src
433 template<typename T
, int32_t stackCapacity
>
434 inline MaybeStackArray
<T
, stackCapacity
>&
435 MaybeStackArray
<T
, stackCapacity
>::operator=(MaybeStackArray
<T
, stackCapacity
>&& src
) U_NOEXCEPT
{
436 releaseArray(); // in case this instance had its own memory allocated
437 capacity
= src
.capacity
;
438 needToRelease
= src
.needToRelease
;
439 if (src
.ptr
== src
.stackArray
) {
441 uprv_memcpy(stackArray
, src
.stackArray
, sizeof(T
) * src
.capacity
);
444 src
.resetToStackArray(); // take ownership away from src
449 template<typename T
, int32_t stackCapacity
>
450 inline T
*MaybeStackArray
<T
, stackCapacity
>::resize(int32_t newCapacity
, int32_t length
) {
452 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
453 ::fprintf(::stderr
,"MaybeStacArray (resize) alloc %d * %lu\n", newCapacity
,sizeof(T
));
455 T
*p
=(T
*)uprv_malloc(newCapacity
*sizeof(T
));
458 if(length
>capacity
) {
461 if(length
>newCapacity
) {
464 uprv_memcpy(p
, ptr
, (size_t)length
*sizeof(T
));
468 capacity
=newCapacity
;
477 template<typename T
, int32_t stackCapacity
>
478 inline T
*MaybeStackArray
<T
, stackCapacity
>::orphanOrClone(int32_t length
, int32_t &resultCapacity
) {
482 } else if(length
<=0) {
485 if(length
>capacity
) {
488 p
=(T
*)uprv_malloc(length
*sizeof(T
));
489 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
490 ::fprintf(::stderr
,"MaybeStacArray (orphan) alloc %d * %lu\n", length
,sizeof(T
));
495 uprv_memcpy(p
, ptr
, (size_t)length
*sizeof(T
));
497 resultCapacity
=length
;
503 * Variant of MaybeStackArray that allocates a header struct and an array
504 * in one contiguous memory block, using uprv_malloc() and uprv_free().
505 * Provides internal memory with fixed array capacity. Can alias another memory
506 * block or allocate one.
507 * The stackCapacity is the number of T items in the internal memory,
508 * not counting the H header.
509 * Unlike LocalMemory and LocalArray, this class never adopts
510 * (takes ownership of) another memory block.
512 template<typename H
, typename T
, int32_t stackCapacity
>
513 class MaybeStackHeaderAndArray
{
515 // No heap allocation. Use only on the stack.
516 static void* U_EXPORT2
operator new(size_t) U_NOEXCEPT
= delete;
517 static void* U_EXPORT2
operator new[](size_t) U_NOEXCEPT
= delete;
518 #if U_HAVE_PLACEMENT_NEW
519 static void* U_EXPORT2
operator new(size_t, void*) U_NOEXCEPT
= delete;
523 * Default constructor initializes with internal H+T[stackCapacity] buffer.
525 MaybeStackHeaderAndArray() : ptr(&stackHeader
), capacity(stackCapacity
), needToRelease(FALSE
) {}
527 * Destructor deletes the memory (if owned).
529 ~MaybeStackHeaderAndArray() { releaseMemory(); }
531 * Returns the array capacity (number of T items).
532 * @return array capacity
534 int32_t getCapacity() const { return capacity
; }
536 * Access without ownership change.
537 * @return the header pointer
539 H
*getAlias() const { return ptr
; }
541 * Returns the array start.
542 * @return array start, same address as getAlias()+1
544 T
*getArrayStart() const { return reinterpret_cast<T
*>(getAlias()+1); }
546 * Returns the array limit.
547 * @return array limit
549 T
*getArrayLimit() const { return getArrayStart()+capacity
; }
551 * Access without ownership change. Same as getAlias().
552 * A class instance can be used directly in expressions that take a T *.
553 * @return the header pointer
555 operator H
*() const { return ptr
; }
557 * Array item access (writable).
558 * No index bounds check.
559 * @param i array index
560 * @return reference to the array item
562 T
&operator[](ptrdiff_t i
) { return getArrayStart()[i
]; }
564 * Deletes the memory block (if owned) and aliases another one, no transfer of ownership.
565 * If the arguments are illegal, then the current memory is unchanged.
566 * @param otherArray must not be NULL
567 * @param otherCapacity must be >0
569 void aliasInstead(H
*otherMemory
, int32_t otherCapacity
) {
570 if(otherMemory
!=NULL
&& otherCapacity
>0) {
573 capacity
=otherCapacity
;
578 * Deletes the memory block (if owned) and allocates a new one,
579 * copying the header and length T array items.
580 * Returns the new header pointer.
581 * If the allocation fails, then the current memory is unchanged and
582 * this method returns NULL.
583 * @param newCapacity can be less than or greater than the current capacity;
585 * @param length number of T items to be copied from the old array to the new one
586 * @return the allocated pointer, or NULL if the allocation failed
588 inline H
*resize(int32_t newCapacity
, int32_t length
=0);
590 * Gives up ownership of the memory if owned, or else clones it,
591 * copying the header and length T array items; resets itself to the internal memory.
592 * Returns NULL if the allocation failed.
593 * @param length number of T items to copy when cloning,
594 * and array capacity of the clone when cloning
595 * @param resultCapacity will be set to the returned array's capacity (output-only)
596 * @return the header pointer;
597 * caller becomes responsible for deleting the array
599 inline H
*orphanOrClone(int32_t length
, int32_t &resultCapacity
);
604 // stackHeader must precede stackArray immediately.
606 T stackArray
[stackCapacity
];
607 void releaseMemory() {
612 /* No comparison operators with other MaybeStackHeaderAndArray's. */
613 bool operator==(const MaybeStackHeaderAndArray
& /*other*/) {return FALSE
;}
614 bool operator!=(const MaybeStackHeaderAndArray
& /*other*/) {return TRUE
;}
615 /* No ownership transfer: No copy constructor, no assignment operator. */
616 MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray
& /*other*/) {}
617 void operator=(const MaybeStackHeaderAndArray
& /*other*/) {}
620 template<typename H
, typename T
, int32_t stackCapacity
>
621 inline H
*MaybeStackHeaderAndArray
<H
, T
, stackCapacity
>::resize(int32_t newCapacity
,
624 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
625 ::fprintf(::stderr
,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H
),newCapacity
,sizeof(T
));
627 H
*p
=(H
*)uprv_malloc(sizeof(H
)+newCapacity
*sizeof(T
));
631 } else if(length
>0) {
632 if(length
>capacity
) {
635 if(length
>newCapacity
) {
639 uprv_memcpy(p
, ptr
, sizeof(H
)+(size_t)length
*sizeof(T
));
642 capacity
=newCapacity
;
651 template<typename H
, typename T
, int32_t stackCapacity
>
652 inline H
*MaybeStackHeaderAndArray
<H
, T
, stackCapacity
>::orphanOrClone(int32_t length
,
653 int32_t &resultCapacity
) {
660 } else if(length
>capacity
) {
663 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
664 ::fprintf(::stderr
,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H
),length
,sizeof(T
));
666 p
=(H
*)uprv_malloc(sizeof(H
)+length
*sizeof(T
));
670 uprv_memcpy(p
, ptr
, sizeof(H
)+(size_t)length
*sizeof(T
));
672 resultCapacity
=length
;
674 capacity
=stackCapacity
;
680 * A simple memory management class that creates new heap allocated objects (of
681 * any class that has a public constructor), keeps track of them and eventually
682 * deletes them all in its own destructor.
684 * A typical use-case would be code like this:
686 * MemoryPool<MyType> pool;
688 * MyType* o1 = pool.create();
689 * if (o1 != nullptr) {
693 * MyType* o2 = pool.create(1, 2, 3);
694 * if (o2 != nullptr) {
698 * // MemoryPool will take care of deleting the MyType objects.
700 * It doesn't do anything more than that, and is intentionally kept minimalist.
702 template<typename T
, int32_t stackCapacity
= 8>
703 class MemoryPool
: public UMemory
{
705 MemoryPool() : count(0), pool() {}
708 for (int32_t i
= 0; i
< count
; ++i
) {
713 MemoryPool(const MemoryPool
&) = delete;
714 MemoryPool
& operator=(const MemoryPool
&) = delete;
716 MemoryPool(MemoryPool
&& other
) U_NOEXCEPT
: count(other
.count
),
717 pool(std::move(other
.pool
)) {
721 MemoryPool
& operator=(MemoryPool
&& other
) U_NOEXCEPT
{
723 pool
= std::move(other
.pool
);
729 * Creates a new object of typename T, by forwarding any and all arguments
730 * to the typename T constructor.
732 * @param args Arguments to be forwarded to the typename T constructor.
733 * @return A pointer to the newly created object, or nullptr on error.
735 template<typename
... Args
>
736 T
* create(Args
&&... args
) {
737 int32_t capacity
= pool
.getCapacity();
738 if (count
== capacity
&&
739 pool
.resize(capacity
== stackCapacity
? 4 * capacity
: 2 * capacity
,
740 capacity
) == nullptr) {
743 return pool
[count
++] = new T(std::forward
<Args
>(args
)...);
748 MaybeStackArray
<T
*, stackCapacity
> pool
;
753 #endif /* __cplusplus */
754 #endif /* CMEMORY_H */