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