]>
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 | ||
51004dcb | 39 | |
b75a7d8f A |
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) | |
51004dcb | 42 | |
b331163b A |
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])) | |
b75a7d8f A |
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 | |
51004dcb | 55 | uprv_malloc(size_t s) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR(1); |
b75a7d8f A |
56 | |
57 | U_CAPI void * U_EXPORT2 | |
51004dcb | 58 | uprv_realloc(void *mem, size_t size) U_ALLOC_SIZE_ATTR(2); |
b75a7d8f A |
59 | |
60 | U_CAPI void U_EXPORT2 | |
61 | uprv_free(void *mem); | |
62 | ||
4388f060 | 63 | U_CAPI void * U_EXPORT2 |
51004dcb | 64 | uprv_calloc(size_t num, size_t size) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR2(1,2); |
4388f060 | 65 | |
b75a7d8f A |
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 | ||
729e4ab9 A |
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 | ||
b75a7d8f A |
87 | /** |
88 | * Get the amount of bytes that a pointer is off by from | |
729e4ab9 | 89 | * the previous UAlignedMemory-aligned pointer. |
b75a7d8f | 90 | */ |
729e4ab9 | 91 | #define U_ALIGNMENT_OFFSET(ptr) U_POINTER_MASK_LSB(ptr, sizeof(UAlignedMemory) - 1) |
b75a7d8f A |
92 | |
93 | /** | |
94 | * Get the amount of bytes to add to a pointer | |
729e4ab9 | 95 | * in order to get the next UAlignedMemory-aligned address. |
b75a7d8f A |
96 | */ |
97 | #define U_ALIGNMENT_OFFSET_UP(ptr) (sizeof(UAlignedMemory) - U_ALIGNMENT_OFFSET(ptr)) | |
98 | ||
374ca955 A |
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 | ||
4388f060 A |
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 | |
729e4ab9 A |
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: | |
2ca993e8 A |
137 | using LocalPointerBase<T>::operator*; |
138 | using LocalPointerBase<T>::operator->; | |
729e4ab9 A |
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) {} | |
2ca993e8 A |
144 | /** |
145 | * Move constructor, leaves src with isNull(). | |
146 | * @param src source smart pointer | |
147 | */ | |
148 | LocalMemory(LocalMemory<T> &&src) U_NOEXCEPT : LocalPointerBase<T>(src.ptr) { | |
149 | src.ptr=NULL; | |
150 | } | |
729e4ab9 A |
151 | /** |
152 | * Destructor deletes the memory it owns. | |
153 | */ | |
154 | ~LocalMemory() { | |
155 | uprv_free(LocalPointerBase<T>::ptr); | |
156 | } | |
2ca993e8 A |
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 | } | |
2ca993e8 A |
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 | */ | |
174 | LocalMemory<T> &moveFrom(LocalMemory<T> &src) U_NOEXCEPT { | |
175 | delete[] 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 | */ | |
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 | */ | |
194 | friend inline void swap(LocalMemory<T> &p1, LocalMemory<T> &p2) U_NOEXCEPT { | |
195 | p1.swap(p2); | |
196 | } | |
729e4ab9 A |
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 | */ | |
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> | |
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> | |
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 | } | |
a62d09fc | 261 | uprv_memcpy(p, LocalPointerBase<T>::ptr, (size_t)length*sizeof(T)); |
729e4ab9 A |
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 | template<typename T, int32_t stackCapacity> | |
284 | class MaybeStackArray { | |
285 | public: | |
286 | /** | |
287 | * Default constructor initializes with internal T[stackCapacity] buffer. | |
288 | */ | |
289 | MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(FALSE) {} | |
0f5d89e8 A |
290 | /** |
291 | * Automatically allocates the heap array if the argument is larger than the stack capacity. | |
292 | * Intended for use when an approximate capacity is known at compile time but the true | |
293 | * capacity is not known until runtime. | |
294 | */ | |
295 | MaybeStackArray(int32_t newCapacity) : MaybeStackArray() { | |
296 | if (capacity < newCapacity) { resize(newCapacity); } | |
297 | }; | |
729e4ab9 A |
298 | /** |
299 | * Destructor deletes the array (if owned). | |
300 | */ | |
301 | ~MaybeStackArray() { releaseArray(); } | |
0f5d89e8 A |
302 | /** |
303 | * Move constructor: transfers ownership or copies the stack array. | |
304 | */ | |
305 | MaybeStackArray(MaybeStackArray<T, stackCapacity> &&src) U_NOEXCEPT; | |
306 | /** | |
307 | * Move assignment: transfers ownership or copies the stack array. | |
308 | */ | |
309 | MaybeStackArray<T, stackCapacity> &operator=(MaybeStackArray<T, stackCapacity> &&src) U_NOEXCEPT; | |
729e4ab9 A |
310 | /** |
311 | * Returns the array capacity (number of T items). | |
312 | * @return array capacity | |
313 | */ | |
314 | int32_t getCapacity() const { return capacity; } | |
315 | /** | |
316 | * Access without ownership change. | |
317 | * @return the array pointer | |
318 | */ | |
319 | T *getAlias() const { return ptr; } | |
320 | /** | |
321 | * Returns the array limit. Simple convenience method. | |
322 | * @return getAlias()+getCapacity() | |
323 | */ | |
324 | T *getArrayLimit() const { return getAlias()+capacity; } | |
51004dcb A |
325 | // No "operator T *() const" because that can make |
326 | // expressions like mbs[index] ambiguous for some compilers. | |
729e4ab9 | 327 | /** |
51004dcb A |
328 | * Array item access (const). |
329 | * No index bounds check. | |
330 | * @param i array index | |
331 | * @return reference to the array item | |
729e4ab9 | 332 | */ |
51004dcb | 333 | const T &operator[](ptrdiff_t i) const { return ptr[i]; } |
729e4ab9 A |
334 | /** |
335 | * Array item access (writable). | |
336 | * No index bounds check. | |
337 | * @param i array index | |
338 | * @return reference to the array item | |
339 | */ | |
340 | T &operator[](ptrdiff_t i) { return ptr[i]; } | |
341 | /** | |
342 | * Deletes the array (if owned) and aliases another one, no transfer of ownership. | |
343 | * If the arguments are illegal, then the current array is unchanged. | |
344 | * @param otherArray must not be NULL | |
345 | * @param otherCapacity must be >0 | |
346 | */ | |
347 | void aliasInstead(T *otherArray, int32_t otherCapacity) { | |
348 | if(otherArray!=NULL && otherCapacity>0) { | |
349 | releaseArray(); | |
350 | ptr=otherArray; | |
351 | capacity=otherCapacity; | |
352 | needToRelease=FALSE; | |
353 | } | |
4388f060 | 354 | } |
729e4ab9 A |
355 | /** |
356 | * Deletes the array (if owned) and allocates a new one, copying length T items. | |
357 | * Returns the new array pointer. | |
358 | * If the allocation fails, then the current array is unchanged and | |
359 | * this method returns NULL. | |
360 | * @param newCapacity can be less than or greater than the current capacity; | |
361 | * must be >0 | |
362 | * @param length number of T items to be copied from the old array to the new one | |
363 | * @return the allocated array pointer, or NULL if the allocation failed | |
364 | */ | |
365 | inline T *resize(int32_t newCapacity, int32_t length=0); | |
366 | /** | |
367 | * Gives up ownership of the array if owned, or else clones it, | |
368 | * copying length T items; resets itself to the internal stack array. | |
369 | * Returns NULL if the allocation failed. | |
370 | * @param length number of T items to copy when cloning, | |
371 | * and capacity of the clone when cloning | |
372 | * @param resultCapacity will be set to the returned array's capacity (output-only) | |
373 | * @return the array pointer; | |
374 | * caller becomes responsible for deleting the array | |
729e4ab9 A |
375 | */ |
376 | inline T *orphanOrClone(int32_t length, int32_t &resultCapacity); | |
377 | private: | |
378 | T *ptr; | |
379 | int32_t capacity; | |
380 | UBool needToRelease; | |
381 | T stackArray[stackCapacity]; | |
382 | void releaseArray() { | |
383 | if(needToRelease) { | |
384 | uprv_free(ptr); | |
385 | } | |
386 | } | |
0f5d89e8 A |
387 | void resetToStackArray() { |
388 | ptr=stackArray; | |
389 | capacity=stackCapacity; | |
390 | needToRelease=FALSE; | |
391 | } | |
729e4ab9 | 392 | /* No comparison operators with other MaybeStackArray's. */ |
4388f060 A |
393 | bool operator==(const MaybeStackArray & /*other*/) {return FALSE;} |
394 | bool operator!=(const MaybeStackArray & /*other*/) {return TRUE;} | |
729e4ab9 | 395 | /* No ownership transfer: No copy constructor, no assignment operator. */ |
4388f060 A |
396 | MaybeStackArray(const MaybeStackArray & /*other*/) {} |
397 | void operator=(const MaybeStackArray & /*other*/) {} | |
729e4ab9 A |
398 | |
399 | // No heap allocation. Use only on the stack. | |
400 | // (Declaring these functions private triggers a cascade of problems: | |
401 | // MSVC insists on exporting an instantiation of MaybeStackArray, which | |
402 | // requires that all functions be defined. | |
403 | // An empty implementation of new() is rejected, it must return a value. | |
404 | // Returning NULL is rejected by gcc for operator new. | |
405 | // The expedient thing is just not to override operator new. | |
406 | // While relatively pointless, heap allocated instances will function. | |
407 | // static void * U_EXPORT2 operator new(size_t size); | |
408 | // static void * U_EXPORT2 operator new[](size_t size); | |
409 | #if U_HAVE_PLACEMENT_NEW | |
410 | // static void * U_EXPORT2 operator new(size_t, void *ptr); | |
411 | #endif | |
412 | }; | |
413 | ||
0f5d89e8 A |
414 | template<typename T, int32_t stackCapacity> |
415 | icu::MaybeStackArray<T, stackCapacity>::MaybeStackArray( | |
416 | MaybeStackArray <T, stackCapacity>&& src) U_NOEXCEPT | |
417 | : ptr(src.ptr), capacity(src.capacity), needToRelease(src.needToRelease) { | |
418 | if (src.ptr == src.stackArray) { | |
419 | ptr = stackArray; | |
420 | uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity); | |
421 | } else { | |
422 | src.resetToStackArray(); // take ownership away from src | |
423 | } | |
424 | } | |
425 | ||
426 | template<typename T, int32_t stackCapacity> | |
427 | inline MaybeStackArray <T, stackCapacity>& | |
428 | MaybeStackArray<T, stackCapacity>::operator=(MaybeStackArray <T, stackCapacity>&& src) U_NOEXCEPT { | |
429 | releaseArray(); // in case this instance had its own memory allocated | |
430 | capacity = src.capacity; | |
431 | needToRelease = src.needToRelease; | |
432 | if (src.ptr == src.stackArray) { | |
433 | ptr = stackArray; | |
434 | uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity); | |
435 | } else { | |
436 | ptr = src.ptr; | |
437 | src.resetToStackArray(); // take ownership away from src | |
438 | } | |
439 | return *this; | |
440 | } | |
441 | ||
729e4ab9 A |
442 | template<typename T, int32_t stackCapacity> |
443 | inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) { | |
444 | if(newCapacity>0) { | |
51004dcb A |
445 | #if U_DEBUG && defined(UPRV_MALLOC_COUNT) |
446 | ::fprintf(::stderr,"MaybeStacArray (resize) alloc %d * %lu\n", newCapacity,sizeof(T)); | |
447 | #endif | |
729e4ab9 A |
448 | T *p=(T *)uprv_malloc(newCapacity*sizeof(T)); |
449 | if(p!=NULL) { | |
450 | if(length>0) { | |
451 | if(length>capacity) { | |
452 | length=capacity; | |
453 | } | |
454 | if(length>newCapacity) { | |
455 | length=newCapacity; | |
456 | } | |
a62d09fc | 457 | uprv_memcpy(p, ptr, (size_t)length*sizeof(T)); |
729e4ab9 A |
458 | } |
459 | releaseArray(); | |
460 | ptr=p; | |
461 | capacity=newCapacity; | |
462 | needToRelease=TRUE; | |
463 | } | |
464 | return p; | |
465 | } else { | |
466 | return NULL; | |
467 | } | |
468 | } | |
469 | ||
470 | template<typename T, int32_t stackCapacity> | |
471 | inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) { | |
472 | T *p; | |
473 | if(needToRelease) { | |
474 | p=ptr; | |
475 | } else if(length<=0) { | |
476 | return NULL; | |
477 | } else { | |
478 | if(length>capacity) { | |
479 | length=capacity; | |
480 | } | |
481 | p=(T *)uprv_malloc(length*sizeof(T)); | |
51004dcb A |
482 | #if U_DEBUG && defined(UPRV_MALLOC_COUNT) |
483 | ::fprintf(::stderr,"MaybeStacArray (orphan) alloc %d * %lu\n", length,sizeof(T)); | |
484 | #endif | |
729e4ab9 A |
485 | if(p==NULL) { |
486 | return NULL; | |
487 | } | |
a62d09fc | 488 | uprv_memcpy(p, ptr, (size_t)length*sizeof(T)); |
729e4ab9 A |
489 | } |
490 | resultCapacity=length; | |
0f5d89e8 | 491 | resetToStackArray(); |
729e4ab9 A |
492 | return p; |
493 | } | |
494 | ||
495 | /** | |
496 | * Variant of MaybeStackArray that allocates a header struct and an array | |
497 | * in one contiguous memory block, using uprv_malloc() and uprv_free(). | |
498 | * Provides internal memory with fixed array capacity. Can alias another memory | |
499 | * block or allocate one. | |
500 | * The stackCapacity is the number of T items in the internal memory, | |
501 | * not counting the H header. | |
502 | * Unlike LocalMemory and LocalArray, this class never adopts | |
503 | * (takes ownership of) another memory block. | |
504 | */ | |
505 | template<typename H, typename T, int32_t stackCapacity> | |
506 | class MaybeStackHeaderAndArray { | |
507 | public: | |
508 | /** | |
509 | * Default constructor initializes with internal H+T[stackCapacity] buffer. | |
510 | */ | |
511 | MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(FALSE) {} | |
512 | /** | |
513 | * Destructor deletes the memory (if owned). | |
514 | */ | |
515 | ~MaybeStackHeaderAndArray() { releaseMemory(); } | |
516 | /** | |
517 | * Returns the array capacity (number of T items). | |
518 | * @return array capacity | |
519 | */ | |
520 | int32_t getCapacity() const { return capacity; } | |
521 | /** | |
522 | * Access without ownership change. | |
523 | * @return the header pointer | |
524 | */ | |
525 | H *getAlias() const { return ptr; } | |
526 | /** | |
527 | * Returns the array start. | |
528 | * @return array start, same address as getAlias()+1 | |
529 | */ | |
530 | T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); } | |
531 | /** | |
532 | * Returns the array limit. | |
533 | * @return array limit | |
534 | */ | |
535 | T *getArrayLimit() const { return getArrayStart()+capacity; } | |
536 | /** | |
537 | * Access without ownership change. Same as getAlias(). | |
538 | * A class instance can be used directly in expressions that take a T *. | |
539 | * @return the header pointer | |
540 | */ | |
541 | operator H *() const { return ptr; } | |
542 | /** | |
543 | * Array item access (writable). | |
544 | * No index bounds check. | |
545 | * @param i array index | |
546 | * @return reference to the array item | |
547 | */ | |
548 | T &operator[](ptrdiff_t i) { return getArrayStart()[i]; } | |
549 | /** | |
550 | * Deletes the memory block (if owned) and aliases another one, no transfer of ownership. | |
551 | * If the arguments are illegal, then the current memory is unchanged. | |
552 | * @param otherArray must not be NULL | |
553 | * @param otherCapacity must be >0 | |
554 | */ | |
555 | void aliasInstead(H *otherMemory, int32_t otherCapacity) { | |
556 | if(otherMemory!=NULL && otherCapacity>0) { | |
557 | releaseMemory(); | |
558 | ptr=otherMemory; | |
559 | capacity=otherCapacity; | |
560 | needToRelease=FALSE; | |
561 | } | |
4388f060 | 562 | } |
729e4ab9 A |
563 | /** |
564 | * Deletes the memory block (if owned) and allocates a new one, | |
565 | * copying the header and length T array items. | |
566 | * Returns the new header pointer. | |
567 | * If the allocation fails, then the current memory is unchanged and | |
568 | * this method returns NULL. | |
569 | * @param newCapacity can be less than or greater than the current capacity; | |
570 | * must be >0 | |
571 | * @param length number of T items to be copied from the old array to the new one | |
572 | * @return the allocated pointer, or NULL if the allocation failed | |
573 | */ | |
574 | inline H *resize(int32_t newCapacity, int32_t length=0); | |
575 | /** | |
576 | * Gives up ownership of the memory if owned, or else clones it, | |
577 | * copying the header and length T array items; resets itself to the internal memory. | |
578 | * Returns NULL if the allocation failed. | |
579 | * @param length number of T items to copy when cloning, | |
580 | * and array capacity of the clone when cloning | |
581 | * @param resultCapacity will be set to the returned array's capacity (output-only) | |
582 | * @return the header pointer; | |
583 | * caller becomes responsible for deleting the array | |
729e4ab9 A |
584 | */ |
585 | inline H *orphanOrClone(int32_t length, int32_t &resultCapacity); | |
586 | private: | |
587 | H *ptr; | |
588 | int32_t capacity; | |
589 | UBool needToRelease; | |
590 | // stackHeader must precede stackArray immediately. | |
591 | H stackHeader; | |
592 | T stackArray[stackCapacity]; | |
593 | void releaseMemory() { | |
594 | if(needToRelease) { | |
595 | uprv_free(ptr); | |
596 | } | |
597 | } | |
598 | /* No comparison operators with other MaybeStackHeaderAndArray's. */ | |
4388f060 A |
599 | bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return FALSE;} |
600 | bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return TRUE;} | |
729e4ab9 | 601 | /* No ownership transfer: No copy constructor, no assignment operator. */ |
4388f060 A |
602 | MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {} |
603 | void operator=(const MaybeStackHeaderAndArray & /*other*/) {} | |
729e4ab9 A |
604 | |
605 | // No heap allocation. Use only on the stack. | |
606 | // (Declaring these functions private triggers a cascade of problems; | |
607 | // see the MaybeStackArray class for details.) | |
608 | // static void * U_EXPORT2 operator new(size_t size); | |
609 | // static void * U_EXPORT2 operator new[](size_t size); | |
610 | #if U_HAVE_PLACEMENT_NEW | |
611 | // static void * U_EXPORT2 operator new(size_t, void *ptr); | |
b75a7d8f | 612 | #endif |
729e4ab9 A |
613 | }; |
614 | ||
615 | template<typename H, typename T, int32_t stackCapacity> | |
616 | inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity, | |
617 | int32_t length) { | |
618 | if(newCapacity>=0) { | |
51004dcb A |
619 | #if U_DEBUG && defined(UPRV_MALLOC_COUNT) |
620 | ::fprintf(::stderr,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H),newCapacity,sizeof(T)); | |
621 | #endif | |
729e4ab9 A |
622 | H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T)); |
623 | if(p!=NULL) { | |
624 | if(length<0) { | |
625 | length=0; | |
626 | } else if(length>0) { | |
627 | if(length>capacity) { | |
628 | length=capacity; | |
629 | } | |
630 | if(length>newCapacity) { | |
631 | length=newCapacity; | |
632 | } | |
633 | } | |
a62d09fc | 634 | uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T)); |
729e4ab9 A |
635 | releaseMemory(); |
636 | ptr=p; | |
637 | capacity=newCapacity; | |
638 | needToRelease=TRUE; | |
639 | } | |
640 | return p; | |
641 | } else { | |
642 | return NULL; | |
643 | } | |
644 | } | |
645 | ||
646 | template<typename H, typename T, int32_t stackCapacity> | |
647 | inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length, | |
648 | int32_t &resultCapacity) { | |
649 | H *p; | |
650 | if(needToRelease) { | |
651 | p=ptr; | |
652 | } else { | |
653 | if(length<0) { | |
654 | length=0; | |
655 | } else if(length>capacity) { | |
656 | length=capacity; | |
657 | } | |
51004dcb A |
658 | #if U_DEBUG && defined(UPRV_MALLOC_COUNT) |
659 | ::fprintf(::stderr,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H),length,sizeof(T)); | |
660 | #endif | |
729e4ab9 A |
661 | p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T)); |
662 | if(p==NULL) { | |
663 | return NULL; | |
664 | } | |
a62d09fc | 665 | uprv_memcpy(p, ptr, sizeof(H)+(size_t)length*sizeof(T)); |
729e4ab9 A |
666 | } |
667 | resultCapacity=length; | |
668 | ptr=&stackHeader; | |
669 | capacity=stackCapacity; | |
670 | needToRelease=FALSE; | |
671 | return p; | |
672 | } | |
673 | ||
674 | U_NAMESPACE_END | |
675 | ||
4388f060 | 676 | #endif /* __cplusplus */ |
729e4ab9 | 677 | #endif /* CMEMORY_H */ |