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