• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
~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      */
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];
releaseArray()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. */
MaybeStackArray(const MaybeStackArray &)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>
resize(int32_t newCapacity,int32_t length)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>
orphanOrClone(int32_t length,int32_t & resultCapacity)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      */
MaybeStackHeaderAndArray()377     MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(FALSE) {}
378     /**
379      * Destructor deletes the memory (if owned).
380      */
~MaybeStackHeaderAndArray()381     ~MaybeStackHeaderAndArray() { releaseMemory(); }
382     /**
383      * Returns the array capacity (number of T items).
384      * @return array capacity
385      */
getCapacity()386     int32_t getCapacity() const { return capacity; }
387     /**
388      * Access without ownership change.
389      * @return the header pointer
390      */
getAlias()391     H *getAlias() const { return ptr; }
392     /**
393      * Returns the array start.
394      * @return array start, same address as getAlias()+1
395      */
getArrayStart()396     T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }
397     /**
398      * Returns the array limit.
399      * @return array limit
400      */
getArrayLimit()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      */
aliasInstead(H * otherMemory,int32_t otherCapacity)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];
releaseMemory()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. */
MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray &)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>
resize(int32_t newCapacity,int32_t length)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>
orphanOrClone(int32_t length,int32_t & resultCapacity)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