Home | History | Annotate | Download | only in common
      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      */
    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      */
    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>
    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>
    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      */
    258     MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(FALSE) {}
    259     /**
    260      * Destructor deletes the array (if owned).
    261      */
    262     ~MaybeStackArray() { releaseArray(); }
    263     /**
    264      * Returns the array capacity (number of T items).
    265      * @return array capacity
    266      */
    267     int32_t getCapacity() const { return capacity; }
    268     /**
    269      * Access without ownership change.
    270      * @return the array pointer
    271      */
    272     T *getAlias() const { return ptr; }
    273     /**
    274      * Returns the array limit. Simple convenience method.
    275      * @return getAlias()+getCapacity()
    276      */
    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      */
    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];
    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. */
    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>
    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>
    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      */
    433     MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(FALSE) {}
    434     /**
    435      * Destructor deletes the memory (if owned).
    436      */
    437     ~MaybeStackHeaderAndArray() { releaseMemory(); }
    438     /**
    439      * Returns the array capacity (number of T items).
    440      * @return array capacity
    441      */
    442     int32_t getCapacity() const { return capacity; }
    443     /**
    444      * Access without ownership change.
    445      * @return the header pointer
    446      */
    447     H *getAlias() const { return ptr; }
    448     /**
    449      * Returns the array start.
    450      * @return array start, same address as getAlias()+1
    451      */
    452     T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }
    453     /**
    454      * Returns the array limit.
    455      * @return array limit
    456      */
    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      */
    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];
    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. */
    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>
    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>
    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