1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 ******************************************************************************
5 *
6 * Copyright (C) 1997-2016, International Business Machines
7 * Corporation and others. All Rights Reserved.
8 *
9 ******************************************************************************
10 *
11 * File CMEMORY.H
12 *
13 * Contains stdlib.h/string.h memory functions
14 *
15 * @author Bertrand A. Damiba
16 *
17 * Modification History:
18 *
19 * Date Name Description
20 * 6/20/98 Bertrand Created.
21 * 05/03/99 stephen Changed from functions to macros.
22 *
23 ******************************************************************************
24 */
25
26 #ifndef CMEMORY_H
27 #define CMEMORY_H
28
29 #include "unicode/utypes.h"
30
31 #include <stddef.h>
32 #include <string.h>
33 #include "unicode/localpointer.h"
34
35 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
36 #include <stdio.h>
37 #endif
38
39
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)
42
43 /**
44 * \def UPRV_LENGTHOF
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
48 * @internal
49 */
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
54 U_CAPI void * U_EXPORT2
55 uprv_malloc(size_t s) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR(1);
56
57 U_CAPI void * U_EXPORT2
58 uprv_realloc(void *mem, size_t size) U_ALLOC_SIZE_ATTR(2);
59
60 U_CAPI void U_EXPORT2
61 uprv_free(void *mem);
62
63 U_CAPI void * U_EXPORT2
64 uprv_calloc(size_t num, size_t size) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR2(1,2);
65
66 /**
67 * This should align the memory properly on any machine.
68 * This is very useful for the safeClone functions.
69 */
70 typedef union {
71 long t1;
72 double t2;
73 void *t3;
74 } UAlignedMemory;
75
76 /**
77 * Get the least significant bits of a pointer (a memory address).
78 * For example, with a mask of 3, the macro gets the 2 least significant bits,
79 * which will be 0 if the pointer is 32-bit (4-byte) aligned.
80 *
81 * ptrdiff_t is the most appropriate integer type to cast to.
82 * size_t should work too, since on most (or all?) platforms it has the same
83 * width as ptrdiff_t.
84 */
85 #define U_POINTER_MASK_LSB(ptr, mask) (((ptrdiff_t)(char *)(ptr)) & (mask))
86
87 /**
88 * Get the amount of bytes that a pointer is off by from
89 * the previous UAlignedMemory-aligned pointer.
90 */
91 #define U_ALIGNMENT_OFFSET(ptr) U_POINTER_MASK_LSB(ptr, sizeof(UAlignedMemory) - 1)
92
93 /**
94 * Get the amount of bytes to add to a pointer
95 * in order to get the next UAlignedMemory-aligned address.
96 */
97 #define U_ALIGNMENT_OFFSET_UP(ptr) (sizeof(UAlignedMemory) - U_ALIGNMENT_OFFSET(ptr))
98
99 /**
100 * Heap clean up function, called from u_cleanup()
101 * Clears any user heap functions from u_setMemoryFunctions()
102 * Does NOT deallocate any remaining allocated memory.
103 */
104 U_CFUNC UBool
105 cmemory_cleanup(void);
106
107 /**
108 * A function called by <TT>uhash_remove</TT>,
109 * <TT>uhash_close</TT>, or <TT>uhash_put</TT> to delete
110 * an existing key or value.
111 * @param obj A key or value stored in a hashtable
112 * @see uprv_deleteUObject
113 */
114 typedef void U_CALLCONV UObjectDeleter(void* obj);
115
116 /**
117 * Deleter for UObject instances.
118 * Works for all subclasses of UObject because it has a virtual destructor.
119 */
120 U_CAPI void U_EXPORT2
121 uprv_deleteUObject(void *obj);
122
123 #ifdef __cplusplus
124
125 U_NAMESPACE_BEGIN
126
127 /**
128 * "Smart pointer" class, deletes memory via uprv_free().
129 * For most methods see the LocalPointerBase base class.
130 * Adds operator[] for array item access.
131 *
132 * @see LocalPointerBase
133 */
134 template<typename T>
135 class LocalMemory : public LocalPointerBase<T> {
136 public:
137 using LocalPointerBase<T>::operator*;
138 using LocalPointerBase<T>::operator->;
139 /**
140 * Constructor takes ownership.
141 * @param p simple pointer to an array of T items that is adopted
142 */
143 explicit LocalMemory(T *p=NULL) : LocalPointerBase<T>(p) {}
144 /**
145 * Move constructor, leaves src with isNull().
146 * @param src source smart pointer
147 */
LocalMemory(LocalMemory<T> && src)148 LocalMemory(LocalMemory<T> &&src) U_NOEXCEPT : LocalPointerBase<T>(src.ptr) {
149 src.ptr=NULL;
150 }
151 /**
152 * Destructor deletes the memory it owns.
153 */
~LocalMemory()154 ~LocalMemory() {
155 uprv_free(LocalPointerBase<T>::ptr);
156 }
157 /**
158 * Move assignment operator, leaves src with isNull().
159 * The behavior is undefined if *this and src are the same object.
160 * @param src source smart pointer
161 * @return *this
162 */
163 LocalMemory<T> &operator=(LocalMemory<T> &&src) U_NOEXCEPT {
164 return moveFrom(src);
165 }
166 /**
167 * Move assignment, leaves src with isNull().
168 * The behavior is undefined if *this and src are the same object.
169 *
170 * Can be called explicitly, does not need C++11 support.
171 * @param src source smart pointer
172 * @return *this
173 */
moveFrom(LocalMemory<T> & src)174 LocalMemory<T> &moveFrom(LocalMemory<T> &src) U_NOEXCEPT {
175 uprv_free(LocalPointerBase<T>::ptr);
176 LocalPointerBase<T>::ptr=src.ptr;
177 src.ptr=NULL;
178 return *this;
179 }
180 /**
181 * Swap pointers.
182 * @param other other smart pointer
183 */
swap(LocalMemory<T> & other)184 void swap(LocalMemory<T> &other) U_NOEXCEPT {
185 T *temp=LocalPointerBase<T>::ptr;
186 LocalPointerBase<T>::ptr=other.ptr;
187 other.ptr=temp;
188 }
189 /**
190 * Non-member LocalMemory swap function.
191 * @param p1 will get p2's pointer
192 * @param p2 will get p1's pointer
193 */
swap(LocalMemory<T> & p1,LocalMemory<T> & p2)194 friend inline void swap(LocalMemory<T> &p1, LocalMemory<T> &p2) U_NOEXCEPT {
195 p1.swap(p2);
196 }
197 /**
198 * Deletes the array it owns,
199 * and adopts (takes ownership of) the one passed in.
200 * @param p simple pointer to an array of T items that is adopted
201 */
adoptInstead(T * p)202 void adoptInstead(T *p) {
203 uprv_free(LocalPointerBase<T>::ptr);
204 LocalPointerBase<T>::ptr=p;
205 }
206 /**
207 * Deletes the array it owns, allocates a new one and reset its bytes to 0.
208 * Returns the new array pointer.
209 * If the allocation fails, then the current array is unchanged and
210 * this method returns NULL.
211 * @param newCapacity must be >0
212 * @return the allocated array pointer, or NULL if the allocation failed
213 */
214 inline T *allocateInsteadAndReset(int32_t newCapacity=1);
215 /**
216 * Deletes the array it owns and allocates a new one, copying length T items.
217 * Returns the new array pointer.
218 * If the allocation fails, then the current array is unchanged and
219 * this method returns NULL.
220 * @param newCapacity must be >0
221 * @param length number of T items to be copied from the old array to the new one;
222 * must be no more than the capacity of the old array,
223 * which the caller must track because the LocalMemory does not track it
224 * @return the allocated array pointer, or NULL if the allocation failed
225 */
226 inline T *allocateInsteadAndCopy(int32_t newCapacity=1, int32_t length=0);
227 /**
228 * Array item access (writable).
229 * No index bounds check.
230 * @param i array index
231 * @return reference to the array item
232 */
233 T &operator[](ptrdiff_t i) const { return LocalPointerBase<T>::ptr[i]; }
234 };
235
236 template<typename T>
allocateInsteadAndReset(int32_t newCapacity)237 inline T *LocalMemory<T>::allocateInsteadAndReset(int32_t newCapacity) {
238 if(newCapacity>0) {
239 T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
240 if(p!=NULL) {
241 uprv_memset(p, 0, newCapacity*sizeof(T));
242 uprv_free(LocalPointerBase<T>::ptr);
243 LocalPointerBase<T>::ptr=p;
244 }
245 return p;
246 } else {
247 return NULL;
248 }
249 }
250
251
252 template<typename T>
allocateInsteadAndCopy(int32_t newCapacity,int32_t length)253 inline T *LocalMemory<T>::allocateInsteadAndCopy(int32_t newCapacity, int32_t length) {
254 if(newCapacity>0) {
255 T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
256 if(p!=NULL) {
257 if(length>0) {
258 if(length>newCapacity) {
259 length=newCapacity;
260 }
261 uprv_memcpy(p, LocalPointerBase<T>::ptr, (size_t)length*sizeof(T));
262 }
263 uprv_free(LocalPointerBase<T>::ptr);
264 LocalPointerBase<T>::ptr=p;
265 }
266 return p;
267 } else {
268 return NULL;
269 }
270 }
271
272 /**
273 * Simple array/buffer management class using uprv_malloc() and uprv_free().
274 * Provides an internal array with fixed capacity. Can alias another array
275 * or allocate one.
276 *
277 * The array address is properly aligned for type T. It might not be properly
278 * aligned for types larger than T (or larger than the largest subtype of T).
279 *
280 * Unlike LocalMemory and LocalArray, this class never adopts
281 * (takes ownership of) another array.
282 *
283 * WARNING: MaybeStackArray only works with primitive (plain-old data) types.
284 * It does NOT know how to call a destructor! If you work with classes with
285 * destructors, consider LocalArray in localpointer.h.
286 */
287 template<typename T, int32_t stackCapacity>
288 class MaybeStackArray {
289 public:
290 /**
291 * Default constructor initializes with internal T[stackCapacity] buffer.
292 */
MaybeStackArray()293 MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(FALSE) {}
294 /**
295 * Automatically allocates the heap array if the argument is larger than the stack capacity.
296 * Intended for use when an approximate capacity is known at compile time but the true
297 * capacity is not known until runtime.
298 */
MaybeStackArray(int32_t newCapacity)299 MaybeStackArray(int32_t newCapacity) : MaybeStackArray() {
300 if (capacity < newCapacity) { resize(newCapacity); }
301 };
302 /**
303 * Destructor deletes the array (if owned).
304 */
~MaybeStackArray()305 ~MaybeStackArray() { releaseArray(); }
306 /**
307 * Move constructor: transfers ownership or copies the stack array.
308 */
309 MaybeStackArray(MaybeStackArray<T, stackCapacity> &&src) U_NOEXCEPT;
310 /**
311 * Move assignment: transfers ownership or copies the stack array.
312 */
313 MaybeStackArray<T, stackCapacity> &operator=(MaybeStackArray<T, stackCapacity> &&src) U_NOEXCEPT;
314 /**
315 * Returns the array capacity (number of T items).
316 * @return array capacity
317 */
getCapacity()318 int32_t getCapacity() const { return capacity; }
319 /**
320 * Access without ownership change.
321 * @return the array pointer
322 */
getAlias()323 T *getAlias() const { return ptr; }
324 /**
325 * Returns the array limit. Simple convenience method.
326 * @return getAlias()+getCapacity()
327 */
getArrayLimit()328 T *getArrayLimit() const { return getAlias()+capacity; }
329 // No "operator T *() const" because that can make
330 // expressions like mbs[index] ambiguous for some compilers.
331 /**
332 * Array item access (const).
333 * No index bounds check.
334 * @param i array index
335 * @return reference to the array item
336 */
337 const T &operator[](ptrdiff_t i) const { return ptr[i]; }
338 /**
339 * Array item access (writable).
340 * No index bounds check.
341 * @param i array index
342 * @return reference to the array item
343 */
344 T &operator[](ptrdiff_t i) { return ptr[i]; }
345 /**
346 * Deletes the array (if owned) and aliases another one, no transfer of ownership.
347 * If the arguments are illegal, then the current array is unchanged.
348 * @param otherArray must not be NULL
349 * @param otherCapacity must be >0
350 */
aliasInstead(T * otherArray,int32_t otherCapacity)351 void aliasInstead(T *otherArray, int32_t otherCapacity) {
352 if(otherArray!=NULL && otherCapacity>0) {
353 releaseArray();
354 ptr=otherArray;
355 capacity=otherCapacity;
356 needToRelease=FALSE;
357 }
358 }
359 /**
360 * Deletes the array (if owned) and allocates a new one, copying length T items.
361 * Returns the new array pointer.
362 * If the allocation fails, then the current array is unchanged and
363 * this method returns NULL.
364 * @param newCapacity can be less than or greater than the current capacity;
365 * must be >0
366 * @param length number of T items to be copied from the old array to the new one
367 * @return the allocated array pointer, or NULL if the allocation failed
368 */
369 inline T *resize(int32_t newCapacity, int32_t length=0);
370 /**
371 * Gives up ownership of the array if owned, or else clones it,
372 * copying length T items; resets itself to the internal stack array.
373 * Returns NULL if the allocation failed.
374 * @param length number of T items to copy when cloning,
375 * and capacity of the clone when cloning
376 * @param resultCapacity will be set to the returned array's capacity (output-only)
377 * @return the array pointer;
378 * caller becomes responsible for deleting the array
379 */
380 inline T *orphanOrClone(int32_t length, int32_t &resultCapacity);
381 private:
382 T *ptr;
383 int32_t capacity;
384 UBool needToRelease;
385 T stackArray[stackCapacity];
releaseArray()386 void releaseArray() {
387 if(needToRelease) {
388 uprv_free(ptr);
389 }
390 }
resetToStackArray()391 void resetToStackArray() {
392 ptr=stackArray;
393 capacity=stackCapacity;
394 needToRelease=FALSE;
395 }
396 /* No comparison operators with other MaybeStackArray's. */
397 bool operator==(const MaybeStackArray & /*other*/) {return FALSE;}
398 bool operator!=(const MaybeStackArray & /*other*/) {return TRUE;}
399 /* No ownership transfer: No copy constructor, no assignment operator. */
MaybeStackArray(const MaybeStackArray &)400 MaybeStackArray(const MaybeStackArray & /*other*/) {}
401 void operator=(const MaybeStackArray & /*other*/) {}
402
403 // No heap allocation. Use only on the stack.
404 // (Declaring these functions private triggers a cascade of problems:
405 // MSVC insists on exporting an instantiation of MaybeStackArray, which
406 // requires that all functions be defined.
407 // An empty implementation of new() is rejected, it must return a value.
408 // Returning NULL is rejected by gcc for operator new.
409 // The expedient thing is just not to override operator new.
410 // While relatively pointless, heap allocated instances will function.
411 // static void * U_EXPORT2 operator new(size_t size);
412 // static void * U_EXPORT2 operator new[](size_t size);
413 #if U_HAVE_PLACEMENT_NEW
414 // static void * U_EXPORT2 operator new(size_t, void *ptr);
415 #endif
416 };
417
418 template<typename T, int32_t stackCapacity>
MaybeStackArray(MaybeStackArray<T,stackCapacity> && src)419 icu::MaybeStackArray<T, stackCapacity>::MaybeStackArray(
420 MaybeStackArray <T, stackCapacity>&& src) U_NOEXCEPT
421 : ptr(src.ptr), capacity(src.capacity), needToRelease(src.needToRelease) {
422 if (src.ptr == src.stackArray) {
423 ptr = stackArray;
424 uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);
425 } else {
426 src.resetToStackArray(); // take ownership away from src
427 }
428 }
429
430 template<typename T, int32_t stackCapacity>
431 inline MaybeStackArray <T, stackCapacity>&
432 MaybeStackArray<T, stackCapacity>::operator=(MaybeStackArray <T, stackCapacity>&& src) U_NOEXCEPT {
433 releaseArray(); // in case this instance had its own memory allocated
434 capacity = src.capacity;
435 needToRelease = src.needToRelease;
436 if (src.ptr == src.stackArray) {
437 ptr = stackArray;
438 uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);
439 } else {
440 ptr = src.ptr;
441 src.resetToStackArray(); // take ownership away from src
442 }
443 return *this;
444 }
445
446 template<typename T, int32_t stackCapacity>
resize(int32_t newCapacity,int32_t length)447 inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
448 if(newCapacity>0) {
449 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
450 ::fprintf(::stderr,"MaybeStacArray (resize) alloc %d * %lu\n", newCapacity,sizeof(T));
451 #endif
452 T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
453 if(p!=NULL) {
454 if(length>0) {
455 if(length>capacity) {
456 length=capacity;
457 }
458 if(length>newCapacity) {
459 length=newCapacity;
460 }
461 uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
462 }
463 releaseArray();
464 ptr=p;
465 capacity=newCapacity;
466 needToRelease=TRUE;
467 }
468 return p;
469 } else {
470 return NULL;
471 }
472 }
473
474 template<typename T, int32_t stackCapacity>
orphanOrClone(int32_t length,int32_t & resultCapacity)475 inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) {
476 T *p;
477 if(needToRelease) {
478 p=ptr;
479 } else if(length<=0) {
480 return NULL;
481 } else {
482 if(length>capacity) {
483 length=capacity;
484 }
485 p=(T *)uprv_malloc(length*sizeof(T));
486 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
487 ::fprintf(::stderr,"MaybeStacArray (orphan) alloc %d * %lu\n", length,sizeof(T));
488 #endif
489 if(p==NULL) {
490 return NULL;
491 }
492 uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
493 }
494 resultCapacity=length;
495 resetToStackArray();
496 return p;
497 }
498
499 /**
500 * Variant of MaybeStackArray that allocates a header struct and an array
501 * in one contiguous memory block, using uprv_malloc() and uprv_free().
502 * Provides internal memory with fixed array capacity. Can alias another memory
503 * block or allocate one.
504 * The stackCapacity is the number of T items in the internal memory,
505 * not counting the H header.
506 * Unlike LocalMemory and LocalArray, this class never adopts
507 * (takes ownership of) another memory block.
508 */
509 template<typename H, typename T, int32_t stackCapacity>
510 class MaybeStackHeaderAndArray {
511 public:
512 /**
513 * Default constructor initializes with internal H+T[stackCapacity] buffer.
514 */
MaybeStackHeaderAndArray()515 MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(FALSE) {}
516 /**
517 * Destructor deletes the memory (if owned).
518 */
~MaybeStackHeaderAndArray()519 ~MaybeStackHeaderAndArray() { releaseMemory(); }
520 /**
521 * Returns the array capacity (number of T items).
522 * @return array capacity
523 */
getCapacity()524 int32_t getCapacity() const { return capacity; }
525 /**
526 * Access without ownership change.
527 * @return the header pointer
528 */
getAlias()529 H *getAlias() const { return ptr; }
530 /**
531 * Returns the array start.
532 * @return array start, same address as getAlias()+1
533 */
getArrayStart()534 T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }
535 /**
536 * Returns the array limit.
537 * @return array limit
538 */
getArrayLimit()539 T *getArrayLimit() const { return getArrayStart()+capacity; }
540 /**
541 * Access without ownership change. Same as getAlias().
542 * A class instance can be used directly in expressions that take a T *.
543 * @return the header pointer
544 */
545 operator H *() const { return ptr; }
546 /**
547 * Array item access (writable).
548 * No index bounds check.
549 * @param i array index
550 * @return reference to the array item
551 */
552 T &operator[](ptrdiff_t i) { return getArrayStart()[i]; }
553 /**
554 * Deletes the memory block (if owned) and aliases another one, no transfer of ownership.
555 * If the arguments are illegal, then the current memory is unchanged.
556 * @param otherArray must not be NULL
557 * @param otherCapacity must be >0
558 */
aliasInstead(H * otherMemory,int32_t otherCapacity)559 void aliasInstead(H *otherMemory, int32_t otherCapacity) {
560 if(otherMemory!=NULL && otherCapacity>0) {
561 releaseMemory();
562 ptr=otherMemory;
563 capacity=otherCapacity;
564 needToRelease=FALSE;
565 }
566 }
567 /**
568 * Deletes the memory block (if owned) and allocates a new one,
569 * copying the header and length T array items.
570 * Returns the new header pointer.
571 * If the allocation fails, then the current memory is unchanged and
572 * this method returns NULL.
573 * @param newCapacity can be less than or greater than the current capacity;
574 * must be >0
575 * @param length number of T items to be copied from the old array to the new one
576 * @return the allocated pointer, or NULL if the allocation failed
577 */
578 inline H *resize(int32_t newCapacity, int32_t length=0);
579 /**
580 * Gives up ownership of the memory if owned, or else clones it,
581 * copying the header and length T array items; resets itself to the internal memory.
582 * Returns NULL if the allocation failed.
583 * @param length number of T items to copy when cloning,
584 * and array capacity of the clone when cloning
585 * @param resultCapacity will be set to the returned array's capacity (output-only)
586 * @return the header pointer;
587 * caller becomes responsible for deleting the array
588 */
589 inline H *orphanOrClone(int32_t length, int32_t &resultCapacity);
590 private:
591 H *ptr;
592 int32_t capacity;
593 UBool needToRelease;
594 // stackHeader must precede stackArray immediately.
595 H stackHeader;
596 T stackArray[stackCapacity];
releaseMemory()597 void releaseMemory() {
598 if(needToRelease) {
599 uprv_free(ptr);
600 }
601 }
602 /* No comparison operators with other MaybeStackHeaderAndArray's. */
603 bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return FALSE;}
604 bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return TRUE;}
605 /* No ownership transfer: No copy constructor, no assignment operator. */
MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray &)606 MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {}
607 void operator=(const MaybeStackHeaderAndArray & /*other*/) {}
608
609 // No heap allocation. Use only on the stack.
610 // (Declaring these functions private triggers a cascade of problems;
611 // see the MaybeStackArray class for details.)
612 // static void * U_EXPORT2 operator new(size_t size);
613 // static void * U_EXPORT2 operator new[](size_t size);
614 #if U_HAVE_PLACEMENT_NEW
615 // static void * U_EXPORT2 operator new(size_t, void *ptr);
616 #endif
617 };
618
619 template<typename H, typename T, int32_t stackCapacity>
resize(int32_t newCapacity,int32_t length)620 inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity,
621 int32_t length) {
622 if(newCapacity>=0) {
623 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
624 ::fprintf(::stderr,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H),newCapacity,sizeof(T));
625 #endif
626 H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T));
627 if(p!=NULL) {
628 if(length<0) {
629 length=0;
630 } else if(length>0) {
631 if(length>capacity) {
632 length=capacity;
633 }
634 if(length>newCapacity) {
635 length=newCapacity;
636 }
637 }
638 uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
639 releaseMemory();
640 ptr=p;
641 capacity=newCapacity;
642 needToRelease=TRUE;
643 }
644 return p;
645 } else {
646 return NULL;
647 }
648 }
649
650 template<typename H, typename T, int32_t stackCapacity>
orphanOrClone(int32_t length,int32_t & resultCapacity)651 inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length,
652 int32_t &resultCapacity) {
653 H *p;
654 if(needToRelease) {
655 p=ptr;
656 } else {
657 if(length<0) {
658 length=0;
659 } else if(length>capacity) {
660 length=capacity;
661 }
662 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
663 ::fprintf(::stderr,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H),length,sizeof(T));
664 #endif
665 p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T));
666 if(p==NULL) {
667 return NULL;
668 }
669 uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T));
670 }
671 resultCapacity=length;
672 ptr=&stackHeader;
673 capacity=stackCapacity;
674 needToRelease=FALSE;
675 return p;
676 }
677
678 U_NAMESPACE_END
679
680 #endif /* __cplusplus */
681 #endif /* CMEMORY_H */
682