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