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 "unicode/utypes.h" 28#include "unicode/localpointer.h" 29#include <stddef.h> 30#include <string.h> 31 32 33#define uprv_memcpy(dst, src, size) U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size) 34#define uprv_memmove(dst, src, size) U_STANDARD_CPP_NAMESPACE memmove(dst, src, size) 35#define uprv_memset(buffer, mark, size) U_STANDARD_CPP_NAMESPACE memset(buffer, mark, size) 36#define uprv_memcmp(buffer1, buffer2, size) U_STANDARD_CPP_NAMESPACE memcmp(buffer1, buffer2,size) 37 38U_CAPI void * U_EXPORT2 39uprv_malloc(size_t s); 40 41U_CAPI void * U_EXPORT2 42uprv_realloc(void *mem, size_t size); 43 44U_CAPI void U_EXPORT2 45uprv_free(void *mem); 46 47/** 48 * This should align the memory properly on any machine. 49 * This is very useful for the safeClone functions. 50 */ 51typedef union { 52 long t1; 53 double t2; 54 void *t3; 55} UAlignedMemory; 56 57/** 58 * Get the least significant bits of a pointer (a memory address). 59 * For example, with a mask of 3, the macro gets the 2 least significant bits, 60 * which will be 0 if the pointer is 32-bit (4-byte) aligned. 61 * 62 * ptrdiff_t is the most appropriate integer type to cast to. 63 * size_t should work too, since on most (or all?) platforms it has the same 64 * width as ptrdiff_t. 65 */ 66#define U_POINTER_MASK_LSB(ptr, mask) (((ptrdiff_t)(char *)(ptr)) & (mask)) 67 68/** 69 * Get the amount of bytes that a pointer is off by from 70 * the previous UAlignedMemory-aligned pointer. 71 */ 72#define U_ALIGNMENT_OFFSET(ptr) U_POINTER_MASK_LSB(ptr, sizeof(UAlignedMemory) - 1) 73 74/** 75 * Get the amount of bytes to add to a pointer 76 * in order to get the next UAlignedMemory-aligned address. 77 */ 78#define U_ALIGNMENT_OFFSET_UP(ptr) (sizeof(UAlignedMemory) - U_ALIGNMENT_OFFSET(ptr)) 79 80/** 81 * Indicate whether the ICU allocation functions have been used. 82 * This is used to determine whether ICU is in an initial, unused state. 83 */ 84U_CFUNC UBool 85cmemory_inUse(void); 86 87/** 88 * Heap clean up function, called from u_cleanup() 89 * Clears any user heap functions from u_setMemoryFunctions() 90 * Does NOT deallocate any remaining allocated memory. 91 */ 92U_CFUNC UBool 93cmemory_cleanup(void); 94 95#ifdef XP_CPLUSPLUS 96 97U_NAMESPACE_BEGIN 98 99/** 100 * "Smart pointer" class, deletes memory via uprv_free(). 101 * For most methods see the LocalPointerBase base class. 102 * Adds operator[] for array item access. 103 * 104 * @see LocalPointerBase 105 */ 106template<typename T> 107class LocalMemory : public LocalPointerBase<T> { 108public: 109 /** 110 * Constructor takes ownership. 111 * @param p simple pointer to an array of T items that is adopted 112 */ 113 explicit LocalMemory(T *p=NULL) : LocalPointerBase<T>(p) {} 114 /** 115 * Destructor deletes the memory it owns. 116 */ 117 ~LocalMemory() { 118 uprv_free(LocalPointerBase<T>::ptr); 119 } 120 /** 121 * Deletes the array it owns, 122 * and adopts (takes ownership of) the one passed in. 123 * @param p simple pointer to an array of T items that is adopted 124 */ 125 void adoptInstead(T *p) { 126 uprv_free(LocalPointerBase<T>::ptr); 127 LocalPointerBase<T>::ptr=p; 128 } 129 /** 130 * Deletes the array it owns, allocates a new one and reset its bytes to 0. 131 * Returns the new array pointer. 132 * If the allocation fails, then the current array is unchanged and 133 * this method returns NULL. 134 * @param newCapacity must be >0 135 * @return the allocated array pointer, or NULL if the allocation failed 136 */ 137 inline T *allocateInsteadAndReset(int32_t newCapacity=1); 138 /** 139 * Deletes the array it owns and allocates a new one, copying length T items. 140 * Returns the new array pointer. 141 * If the allocation fails, then the current array is unchanged and 142 * this method returns NULL. 143 * @param newCapacity must be >0 144 * @param length number of T items to be copied from the old array to the new one; 145 * must be no more than the capacity of the old array, 146 * which the caller must track because the LocalMemory does not track it 147 * @return the allocated array pointer, or NULL if the allocation failed 148 */ 149 inline T *allocateInsteadAndCopy(int32_t newCapacity=1, int32_t length=0); 150 /** 151 * Array item access (writable). 152 * No index bounds check. 153 * @param i array index 154 * @return reference to the array item 155 */ 156 T &operator[](ptrdiff_t i) const { return LocalPointerBase<T>::ptr[i]; } 157}; 158 159/** 160 * Simple array/buffer management class using uprv_malloc() and uprv_free(). 161 * Provides an internal array with fixed capacity. Can alias another array 162 * or allocate one. 163 * Unlike LocalMemory and LocalArray, this class never adopts 164 * (takes ownership of) another array. 165 */ 166template<typename T, int32_t stackCapacity> 167class MaybeStackArray { 168public: 169 /** 170 * Default constructor initializes with internal T[stackCapacity] buffer. 171 */ 172 MaybeStackArray() : needToRelease(FALSE), capacity(stackCapacity), ptr(stackArray) {} 173 /** 174 * Destructor deletes the array (if owned). 175 */ 176 ~MaybeStackArray() { releaseArray(); } 177 /** 178 * Returns the array capacity (number of T items). 179 * @return array capacity 180 */ 181 int32_t getCapacity() const { return capacity; } 182 /** 183 * Access without ownership change. 184 * @return the array pointer 185 */ 186 T *getAlias() const { return ptr; } 187 /** 188 * Returns the array limit. Simple convenience method. 189 * @return getAlias()+getCapacity() 190 */ 191 T *getArrayLimit() const { return getAlias()+capacity; } 192 /** 193 * Access without ownership change. Same as getAlias(). 194 * A class instance can be used directly in expressions that take a T *. 195 * @return the array pointer 196 */ 197 operator T *() const { return ptr; } 198 /** 199 * Array item access (writable). 200 * No index bounds check. 201 * @param i array index 202 * @return reference to the array item 203 */ 204 T &operator[](ptrdiff_t i) { return ptr[i]; } 205 /** 206 * Deletes the array (if owned) and aliases another one, no transfer of ownership. 207 * If the arguments are illegal, then the current array is unchanged. 208 * @param otherArray must not be NULL 209 * @param otherCapacity must be >0 210 */ 211 void aliasInstead(T *otherArray, int32_t otherCapacity) { 212 if(otherArray!=NULL && otherCapacity>0) { 213 releaseArray(); 214 ptr=otherArray; 215 capacity=otherCapacity; 216 needToRelease=FALSE; 217 } 218 }; 219 /** 220 * Deletes the array (if owned) and allocates a new one, copying length T items. 221 * Returns the new array pointer. 222 * If the allocation fails, then the current array is unchanged and 223 * this method returns NULL. 224 * @param newCapacity can be less than or greater than the current capacity; 225 * must be >0 226 * @param length number of T items to be copied from the old array to the new one 227 * @return the allocated array pointer, or NULL if the allocation failed 228 */ 229 inline T *resize(int32_t newCapacity, int32_t length=0); 230 /** 231 * Gives up ownership of the array if owned, or else clones it, 232 * copying length T items; resets itself to the internal stack array. 233 * Returns NULL if the allocation failed. 234 * @param length number of T items to copy when cloning, 235 * and capacity of the clone when cloning 236 * @param resultCapacity will be set to the returned array's capacity (output-only) 237 * @return the array pointer; 238 * caller becomes responsible for deleting the array 239 * @draft ICU 4.4 240 */ 241 inline T *orphanOrClone(int32_t length, int32_t &resultCapacity); 242private: 243 UBool needToRelease; 244 int32_t capacity; 245 T *ptr; 246 T stackArray[stackCapacity]; 247 void releaseArray() { 248 if(needToRelease) { 249 uprv_free(ptr); 250 } 251 } 252 /* No comparison operators with other MaybeStackArray's. */ 253 bool operator==(const MaybeStackArray & /*other*/) {return FALSE;}; 254 bool operator!=(const MaybeStackArray & /*other*/) {return TRUE;}; 255 /* No ownership transfer: No copy constructor, no assignment operator. */ 256 MaybeStackArray(const MaybeStackArray & /*other*/) {}; 257 void operator=(const MaybeStackArray & /*other*/) {}; 258 259 // No heap allocation. Use only on the stack. 260 // (Declaring these functions private triggers a cascade of problems: 261 // MSVC insists on exporting an instantiation of MaybeStackArray, which 262 // requires that all functions be defined. 263 // An empty implementation of new() is rejected, it must return a value. 264 // Returning NULL is rejected by gcc for operator new. 265 // The expedient thing is just not to override operator new. 266 // While relatively pointless, heap allocated instances will function. 267 // static void * U_EXPORT2 operator new(size_t size); 268 // static void * U_EXPORT2 operator new[](size_t size); 269#if U_HAVE_PLACEMENT_NEW 270 // static void * U_EXPORT2 operator new(size_t, void *ptr); 271#endif 272}; 273 274template<typename T> 275inline T *LocalMemory<T>::allocateInsteadAndReset(int32_t newCapacity) { 276 if(newCapacity>0) { 277 T *p=(T *)uprv_malloc(newCapacity*sizeof(T)); 278 if(p!=NULL) { 279 uprv_memset(p, 0, newCapacity*sizeof(T)); 280 uprv_free(LocalPointerBase<T>::ptr); 281 LocalPointerBase<T>::ptr=p; 282 } 283 return p; 284 } else { 285 return NULL; 286 } 287} 288 289 290template<typename T> 291inline T *LocalMemory<T>::allocateInsteadAndCopy(int32_t newCapacity, int32_t length) { 292 if(newCapacity>0) { 293 T *p=(T *)uprv_malloc(newCapacity*sizeof(T)); 294 if(p!=NULL) { 295 if(length>0) { 296 if(length>newCapacity) { 297 length=newCapacity; 298 } 299 uprv_memcpy(p, LocalPointerBase<T>::ptr, length*sizeof(T)); 300 } 301 uprv_free(LocalPointerBase<T>::ptr); 302 LocalPointerBase<T>::ptr=p; 303 } 304 return p; 305 } else { 306 return NULL; 307 } 308} 309 310template<typename T, int32_t stackCapacity> 311inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) { 312 if(newCapacity>0) { 313 T *p=(T *)uprv_malloc(newCapacity*sizeof(T)); 314 if(p!=NULL) { 315 if(length>0) { 316 if(length>capacity) { 317 length=capacity; 318 } 319 if(length>newCapacity) { 320 length=newCapacity; 321 } 322 uprv_memcpy(p, ptr, length*sizeof(T)); 323 } 324 releaseArray(); 325 ptr=p; 326 capacity=newCapacity; 327 needToRelease=TRUE; 328 } 329 return p; 330 } else { 331 return NULL; 332 } 333} 334 335template<typename T, int32_t stackCapacity> 336inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) { 337 T *p; 338 if(needToRelease) { 339 p=ptr; 340 } else if(length<=0) { 341 return NULL; 342 } else { 343 if(length>capacity) { 344 length=capacity; 345 } 346 p=(T *)uprv_malloc(length*sizeof(T)); 347 if(p==NULL) { 348 return NULL; 349 } 350 uprv_memcpy(p, ptr, length*sizeof(T)); 351 } 352 resultCapacity=length; 353 ptr=stackArray; 354 capacity=stackCapacity; 355 needToRelease=FALSE; 356 return p; 357} 358 359U_NAMESPACE_END 360 361#endif /* XP_CPLUSPLUS */ 362#endif /* CMEMORY_H */ 363