intl/icu/source/common/cmemory.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial