• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
~LocalMemory()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      */
adoptInstead(T * p)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>
allocateInsteadAndReset(int32_t newCapacity)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>
allocateInsteadAndCopy(int32_t newCapacity,int32_t length)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      */
MaybeStackArray()211     MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(FALSE) {}
212     /**
213      * Destructor deletes the array (if owned).
214      */
~MaybeStackArray()215     ~MaybeStackArray() { releaseArray(); }
216     /**
217      * Returns the array capacity (number of T items).
218      * @return array capacity
219      */
getCapacity()220     int32_t getCapacity() const { return capacity; }
221     /**
222      * Access without ownership change.
223      * @return the array pointer
224      */
getAlias()225     T *getAlias() const { return ptr; }
226     /**
227      * Returns the array limit. Simple convenience method.
228      * @return getAlias()+getCapacity()
229      */
getArrayLimit()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      */
aliasInstead(T * otherArray,int32_t otherCapacity)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];
releaseArray()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. */
MaybeStackArray(const MaybeStackArray &)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>
resize(int32_t newCapacity,int32_t length)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>
orphanOrClone(int32_t length,int32_t & resultCapacity)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      */
MaybeStackHeaderAndArray()378     MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(FALSE) {}
379     /**
380      * Destructor deletes the memory (if owned).
381      */
~MaybeStackHeaderAndArray()382     ~MaybeStackHeaderAndArray() { releaseMemory(); }
383     /**
384      * Returns the array capacity (number of T items).
385      * @return array capacity
386      */
getCapacity()387     int32_t getCapacity() const { return capacity; }
388     /**
389      * Access without ownership change.
390      * @return the header pointer
391      */
getAlias()392     H *getAlias() const { return ptr; }
393     /**
394      * Returns the array start.
395      * @return array start, same address as getAlias()+1
396      */
getArrayStart()397     T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }
398     /**
399      * Returns the array limit.
400      * @return array limit
401      */
getArrayLimit()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      */
aliasInstead(H * otherMemory,int32_t otherCapacity)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];
releaseMemory()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. */
MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray &)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>
resize(int32_t newCapacity,int32_t length)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>
orphanOrClone(int32_t length,int32_t & resultCapacity)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