1 /* 2 ****************************************************************************** 3 * 4 * Copyright (C) 1997-2010, 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 * @draft ICU 4.4 279 */ 280 inline T *orphanOrClone(int32_t length, int32_t &resultCapacity); 281 private: 282 T *ptr; 283 int32_t capacity; 284 UBool needToRelease; 285 T stackArray[stackCapacity]; 286 void releaseArray() { 287 if(needToRelease) { 288 uprv_free(ptr); 289 } 290 } 291 /* No comparison operators with other MaybeStackArray's. */ 292 bool operator==(const MaybeStackArray & /*other*/) {return FALSE;}; 293 bool operator!=(const MaybeStackArray & /*other*/) {return TRUE;}; 294 /* No ownership transfer: No copy constructor, no assignment operator. */ 295 MaybeStackArray(const MaybeStackArray & /*other*/) {}; 296 void operator=(const MaybeStackArray & /*other*/) {}; 297 298 // No heap allocation. Use only on the stack. 299 // (Declaring these functions private triggers a cascade of problems: 300 // MSVC insists on exporting an instantiation of MaybeStackArray, which 301 // requires that all functions be defined. 302 // An empty implementation of new() is rejected, it must return a value. 303 // Returning NULL is rejected by gcc for operator new. 304 // The expedient thing is just not to override operator new. 305 // While relatively pointless, heap allocated instances will function. 306 // static void * U_EXPORT2 operator new(size_t size); 307 // static void * U_EXPORT2 operator new[](size_t size); 308 #if U_HAVE_PLACEMENT_NEW 309 // static void * U_EXPORT2 operator new(size_t, void *ptr); 310 #endif 311 }; 312 313 template<typename T, int32_t stackCapacity> 314 inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) { 315 if(newCapacity>0) { 316 T *p=(T *)uprv_malloc(newCapacity*sizeof(T)); 317 if(p!=NULL) { 318 if(length>0) { 319 if(length>capacity) { 320 length=capacity; 321 } 322 if(length>newCapacity) { 323 length=newCapacity; 324 } 325 uprv_memcpy(p, ptr, length*sizeof(T)); 326 } 327 releaseArray(); 328 ptr=p; 329 capacity=newCapacity; 330 needToRelease=TRUE; 331 } 332 return p; 333 } else { 334 return NULL; 335 } 336 } 337 338 template<typename T, int32_t stackCapacity> 339 inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) { 340 T *p; 341 if(needToRelease) { 342 p=ptr; 343 } else if(length<=0) { 344 return NULL; 345 } else { 346 if(length>capacity) { 347 length=capacity; 348 } 349 p=(T *)uprv_malloc(length*sizeof(T)); 350 if(p==NULL) { 351 return NULL; 352 } 353 uprv_memcpy(p, ptr, length*sizeof(T)); 354 } 355 resultCapacity=length; 356 ptr=stackArray; 357 capacity=stackCapacity; 358 needToRelease=FALSE; 359 return p; 360 } 361 362 /** 363 * Variant of MaybeStackArray that allocates a header struct and an array 364 * in one contiguous memory block, using uprv_malloc() and uprv_free(). 365 * Provides internal memory with fixed array capacity. Can alias another memory 366 * block or allocate one. 367 * The stackCapacity is the number of T items in the internal memory, 368 * not counting the H header. 369 * Unlike LocalMemory and LocalArray, this class never adopts 370 * (takes ownership of) another memory block. 371 */ 372 template<typename H, typename T, int32_t stackCapacity> 373 class MaybeStackHeaderAndArray { 374 public: 375 /** 376 * Default constructor initializes with internal H+T[stackCapacity] buffer. 377 */ 378 MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(FALSE) {} 379 /** 380 * Destructor deletes the memory (if owned). 381 */ 382 ~MaybeStackHeaderAndArray() { releaseMemory(); } 383 /** 384 * Returns the array capacity (number of T items). 385 * @return array capacity 386 */ 387 int32_t getCapacity() const { return capacity; } 388 /** 389 * Access without ownership change. 390 * @return the header pointer 391 */ 392 H *getAlias() const { return ptr; } 393 /** 394 * Returns the array start. 395 * @return array start, same address as getAlias()+1 396 */ 397 T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); } 398 /** 399 * Returns the array limit. 400 * @return array limit 401 */ 402 T *getArrayLimit() const { return getArrayStart()+capacity; } 403 /** 404 * Access without ownership change. Same as getAlias(). 405 * A class instance can be used directly in expressions that take a T *. 406 * @return the header pointer 407 */ 408 operator H *() const { return ptr; } 409 /** 410 * Array item access (writable). 411 * No index bounds check. 412 * @param i array index 413 * @return reference to the array item 414 */ 415 T &operator[](ptrdiff_t i) { return getArrayStart()[i]; } 416 /** 417 * Deletes the memory block (if owned) and aliases another one, no transfer of ownership. 418 * If the arguments are illegal, then the current memory is unchanged. 419 * @param otherArray must not be NULL 420 * @param otherCapacity must be >0 421 */ 422 void aliasInstead(H *otherMemory, int32_t otherCapacity) { 423 if(otherMemory!=NULL && otherCapacity>0) { 424 releaseMemory(); 425 ptr=otherMemory; 426 capacity=otherCapacity; 427 needToRelease=FALSE; 428 } 429 }; 430 /** 431 * Deletes the memory block (if owned) and allocates a new one, 432 * copying the header and length T array items. 433 * Returns the new header pointer. 434 * If the allocation fails, then the current memory is unchanged and 435 * this method returns NULL. 436 * @param newCapacity can be less than or greater than the current capacity; 437 * must be >0 438 * @param length number of T items to be copied from the old array to the new one 439 * @return the allocated pointer, or NULL if the allocation failed 440 */ 441 inline H *resize(int32_t newCapacity, int32_t length=0); 442 /** 443 * Gives up ownership of the memory if owned, or else clones it, 444 * copying the header and length T array items; resets itself to the internal memory. 445 * Returns NULL if the allocation failed. 446 * @param length number of T items to copy when cloning, 447 * and array capacity of the clone when cloning 448 * @param resultCapacity will be set to the returned array's capacity (output-only) 449 * @return the header pointer; 450 * caller becomes responsible for deleting the array 451 * @draft ICU 4.4 452 */ 453 inline H *orphanOrClone(int32_t length, int32_t &resultCapacity); 454 private: 455 H *ptr; 456 int32_t capacity; 457 UBool needToRelease; 458 // stackHeader must precede stackArray immediately. 459 H stackHeader; 460 T stackArray[stackCapacity]; 461 void releaseMemory() { 462 if(needToRelease) { 463 uprv_free(ptr); 464 } 465 } 466 /* No comparison operators with other MaybeStackHeaderAndArray's. */ 467 bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return FALSE;}; 468 bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return TRUE;}; 469 /* No ownership transfer: No copy constructor, no assignment operator. */ 470 MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {}; 471 void operator=(const MaybeStackHeaderAndArray & /*other*/) {}; 472 473 // No heap allocation. Use only on the stack. 474 // (Declaring these functions private triggers a cascade of problems; 475 // see the MaybeStackArray class for details.) 476 // static void * U_EXPORT2 operator new(size_t size); 477 // static void * U_EXPORT2 operator new[](size_t size); 478 #if U_HAVE_PLACEMENT_NEW 479 // static void * U_EXPORT2 operator new(size_t, void *ptr); 480 #endif 481 }; 482 483 template<typename H, typename T, int32_t stackCapacity> 484 inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity, 485 int32_t length) { 486 if(newCapacity>=0) { 487 H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T)); 488 if(p!=NULL) { 489 if(length<0) { 490 length=0; 491 } else if(length>0) { 492 if(length>capacity) { 493 length=capacity; 494 } 495 if(length>newCapacity) { 496 length=newCapacity; 497 } 498 } 499 uprv_memcpy(p, ptr, sizeof(H)+length*sizeof(T)); 500 releaseMemory(); 501 ptr=p; 502 capacity=newCapacity; 503 needToRelease=TRUE; 504 } 505 return p; 506 } else { 507 return NULL; 508 } 509 } 510 511 template<typename H, typename T, int32_t stackCapacity> 512 inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length, 513 int32_t &resultCapacity) { 514 H *p; 515 if(needToRelease) { 516 p=ptr; 517 } else { 518 if(length<0) { 519 length=0; 520 } else if(length>capacity) { 521 length=capacity; 522 } 523 p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T)); 524 if(p==NULL) { 525 return NULL; 526 } 527 uprv_memcpy(p, ptr, sizeof(H)+length*sizeof(T)); 528 } 529 resultCapacity=length; 530 ptr=&stackHeader; 531 capacity=stackCapacity; 532 needToRelease=FALSE; 533 return p; 534 } 535 536 U_NAMESPACE_END 537 538 #endif /* XP_CPLUSPLUS */ 539 #endif /* CMEMORY_H */ 540