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