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