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