Home | History | Annotate | Download | only in common
      1 /*
      2 ******************************************************************************
      3 *
      4 *   Copyright (C) 1997-2010, International Business Machines
      5 *   Corporation and others.  All Rights Reserved.
      6 *
      7 ******************************************************************************
      8 *
      9 * File CMEMORY.H
     10 *
     11 *  Contains stdlib.h/string.h memory functions
     12 *
     13 * @author       Bertrand A. Damiba
     14 *
     15 * Modification History:
     16 *
     17 *   Date        Name        Description
     18 *   6/20/98     Bertrand    Created.
     19 *  05/03/99     stephen     Changed from functions to macros.
     20 *
     21 ******************************************************************************
     22 */
     23 
     24 #ifndef CMEMORY_H
     25 #define CMEMORY_H
     26 
     27 #include <stddef.h>
     28 #include <string.h>
     29 #include "unicode/utypes.h"
     30 #include "unicode/localpointer.h"
     31 
     32 #define uprv_memcpy(dst, src, size) U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size)
     33 #define uprv_memmove(dst, src, size) U_STANDARD_CPP_NAMESPACE memmove(dst, src, size)
     34 #define uprv_memset(buffer, mark, size) U_STANDARD_CPP_NAMESPACE memset(buffer, mark, size)
     35 #define uprv_memcmp(buffer1, buffer2, size) U_STANDARD_CPP_NAMESPACE memcmp(buffer1, buffer2,size)
     36 
     37 U_CAPI void * U_EXPORT2
     38 uprv_malloc(size_t s);
     39 
     40 U_CAPI void * U_EXPORT2
     41 uprv_realloc(void *mem, size_t size);
     42 
     43 U_CAPI void U_EXPORT2
     44 uprv_free(void *mem);
     45 
     46 /**
     47  * This should align the memory properly on any machine.
     48  * This is very useful for the safeClone functions.
     49  */
     50 typedef union {
     51     long    t1;
     52     double  t2;
     53     void   *t3;
     54 } UAlignedMemory;
     55 
     56 /**
     57  * Get the least significant bits of a pointer (a memory address).
     58  * For example, with a mask of 3, the macro gets the 2 least significant bits,
     59  * which will be 0 if the pointer is 32-bit (4-byte) aligned.
     60  *
     61  * ptrdiff_t is the most appropriate integer type to cast to.
     62  * size_t should work too, since on most (or all?) platforms it has the same
     63  * width as ptrdiff_t.
     64  */
     65 #define U_POINTER_MASK_LSB(ptr, mask) (((ptrdiff_t)(char *)(ptr)) & (mask))
     66 
     67 /**
     68  * Get the amount of bytes that a pointer is off by from
     69  * the previous UAlignedMemory-aligned pointer.
     70  */
     71 #define U_ALIGNMENT_OFFSET(ptr) U_POINTER_MASK_LSB(ptr, sizeof(UAlignedMemory) - 1)
     72 
     73 /**
     74  * Get the amount of bytes to add to a pointer
     75  * in order to get the next UAlignedMemory-aligned address.
     76  */
     77 #define U_ALIGNMENT_OFFSET_UP(ptr) (sizeof(UAlignedMemory) - U_ALIGNMENT_OFFSET(ptr))
     78 
     79 /**
     80   *  Indicate whether the ICU allocation functions have been used.
     81   *  This is used to determine whether ICU is in an initial, unused state.
     82   */
     83 U_CFUNC UBool
     84 cmemory_inUse(void);
     85 
     86 /**
     87   *  Heap clean up function, called from u_cleanup()
     88   *    Clears any user heap functions from u_setMemoryFunctions()
     89   *    Does NOT deallocate any remaining allocated memory.
     90   */
     91 U_CFUNC UBool
     92 cmemory_cleanup(void);
     93 
     94 #ifdef XP_CPLUSPLUS
     95 
     96 U_NAMESPACE_BEGIN
     97 
     98 /**
     99  * "Smart pointer" class, deletes memory via uprv_free().
    100  * For most methods see the LocalPointerBase base class.
    101  * Adds operator[] for array item access.
    102  *
    103  * @see LocalPointerBase
    104  */
    105 template<typename T>
    106 class LocalMemory : public LocalPointerBase<T> {
    107 public:
    108     /**
    109      * Constructor takes ownership.
    110      * @param p simple pointer to an array of T items that is adopted
    111      */
    112     explicit LocalMemory(T *p=NULL) : LocalPointerBase<T>(p) {}
    113     /**
    114      * Destructor deletes the memory it owns.
    115      */
    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      * @draft ICU 4.4
    279      */
    280     inline T *orphanOrClone(int32_t length, int32_t &resultCapacity);
    281 private:
    282     T *ptr;
    283     int32_t capacity;
    284     UBool needToRelease;
    285     T stackArray[stackCapacity];
    286     void releaseArray() {
    287         if(needToRelease) {
    288             uprv_free(ptr);
    289         }
    290     }
    291     /* No comparison operators with other MaybeStackArray's. */
    292     bool operator==(const MaybeStackArray & /*other*/) {return FALSE;};
    293     bool operator!=(const MaybeStackArray & /*other*/) {return TRUE;};
    294     /* No ownership transfer: No copy constructor, no assignment operator. */
    295     MaybeStackArray(const MaybeStackArray & /*other*/) {};
    296     void operator=(const MaybeStackArray & /*other*/) {};
    297 
    298     // No heap allocation. Use only on the stack.
    299     //   (Declaring these functions private triggers a cascade of problems:
    300     //      MSVC insists on exporting an instantiation of MaybeStackArray, which
    301     //      requires that all functions be defined.
    302     //      An empty implementation of new() is rejected, it must return a value.
    303     //      Returning NULL is rejected by gcc for operator new.
    304     //      The expedient thing is just not to override operator new.
    305     //      While relatively pointless, heap allocated instances will function.
    306     // static void * U_EXPORT2 operator new(size_t size);
    307     // static void * U_EXPORT2 operator new[](size_t size);
    308 #if U_HAVE_PLACEMENT_NEW
    309     // static void * U_EXPORT2 operator new(size_t, void *ptr);
    310 #endif
    311 };
    312 
    313 template<typename T, int32_t stackCapacity>
    314 inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
    315     if(newCapacity>0) {
    316         T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
    317         if(p!=NULL) {
    318             if(length>0) {
    319                 if(length>capacity) {
    320                     length=capacity;
    321                 }
    322                 if(length>newCapacity) {
    323                     length=newCapacity;
    324                 }
    325                 uprv_memcpy(p, ptr, length*sizeof(T));
    326             }
    327             releaseArray();
    328             ptr=p;
    329             capacity=newCapacity;
    330             needToRelease=TRUE;
    331         }
    332         return p;
    333     } else {
    334         return NULL;
    335     }
    336 }
    337 
    338 template<typename T, int32_t stackCapacity>
    339 inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) {
    340     T *p;
    341     if(needToRelease) {
    342         p=ptr;
    343     } else if(length<=0) {
    344         return NULL;
    345     } else {
    346         if(length>capacity) {
    347             length=capacity;
    348         }
    349         p=(T *)uprv_malloc(length*sizeof(T));
    350         if(p==NULL) {
    351             return NULL;
    352         }
    353         uprv_memcpy(p, ptr, length*sizeof(T));
    354     }
    355     resultCapacity=length;
    356     ptr=stackArray;
    357     capacity=stackCapacity;
    358     needToRelease=FALSE;
    359     return p;
    360 }
    361 
    362 /**
    363  * Variant of MaybeStackArray that allocates a header struct and an array
    364  * in one contiguous memory block, using uprv_malloc() and uprv_free().
    365  * Provides internal memory with fixed array capacity. Can alias another memory
    366  * block or allocate one.
    367  * The stackCapacity is the number of T items in the internal memory,
    368  * not counting the H header.
    369  * Unlike LocalMemory and LocalArray, this class never adopts
    370  * (takes ownership of) another memory block.
    371  */
    372 template<typename H, typename T, int32_t stackCapacity>
    373 class MaybeStackHeaderAndArray {
    374 public:
    375     /**
    376      * Default constructor initializes with internal H+T[stackCapacity] buffer.
    377      */
    378     MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(FALSE) {}
    379     /**
    380      * Destructor deletes the memory (if owned).
    381      */
    382     ~MaybeStackHeaderAndArray() { releaseMemory(); }
    383     /**
    384      * Returns the array capacity (number of T items).
    385      * @return array capacity
    386      */
    387     int32_t getCapacity() const { return capacity; }
    388     /**
    389      * Access without ownership change.
    390      * @return the header pointer
    391      */
    392     H *getAlias() const { return ptr; }
    393     /**
    394      * Returns the array start.
    395      * @return array start, same address as getAlias()+1
    396      */
    397     T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }
    398     /**
    399      * Returns the array limit.
    400      * @return array limit
    401      */
    402     T *getArrayLimit() const { return getArrayStart()+capacity; }
    403     /**
    404      * Access without ownership change. Same as getAlias().
    405      * A class instance can be used directly in expressions that take a T *.
    406      * @return the header pointer
    407      */
    408     operator H *() const { return ptr; }
    409     /**
    410      * Array item access (writable).
    411      * No index bounds check.
    412      * @param i array index
    413      * @return reference to the array item
    414      */
    415     T &operator[](ptrdiff_t i) { return getArrayStart()[i]; }
    416     /**
    417      * Deletes the memory block (if owned) and aliases another one, no transfer of ownership.
    418      * If the arguments are illegal, then the current memory is unchanged.
    419      * @param otherArray must not be NULL
    420      * @param otherCapacity must be >0
    421      */
    422     void aliasInstead(H *otherMemory, int32_t otherCapacity) {
    423         if(otherMemory!=NULL && otherCapacity>0) {
    424             releaseMemory();
    425             ptr=otherMemory;
    426             capacity=otherCapacity;
    427             needToRelease=FALSE;
    428         }
    429     };
    430     /**
    431      * Deletes the memory block (if owned) and allocates a new one,
    432      * copying the header and length T array items.
    433      * Returns the new header pointer.
    434      * If the allocation fails, then the current memory is unchanged and
    435      * this method returns NULL.
    436      * @param newCapacity can be less than or greater than the current capacity;
    437      *                    must be >0
    438      * @param length number of T items to be copied from the old array to the new one
    439      * @return the allocated pointer, or NULL if the allocation failed
    440      */
    441     inline H *resize(int32_t newCapacity, int32_t length=0);
    442     /**
    443      * Gives up ownership of the memory if owned, or else clones it,
    444      * copying the header and length T array items; resets itself to the internal memory.
    445      * Returns NULL if the allocation failed.
    446      * @param length number of T items to copy when cloning,
    447      *        and array capacity of the clone when cloning
    448      * @param resultCapacity will be set to the returned array's capacity (output-only)
    449      * @return the header pointer;
    450      *         caller becomes responsible for deleting the array
    451      * @draft ICU 4.4
    452      */
    453     inline H *orphanOrClone(int32_t length, int32_t &resultCapacity);
    454 private:
    455     H *ptr;
    456     int32_t capacity;
    457     UBool needToRelease;
    458     // stackHeader must precede stackArray immediately.
    459     H stackHeader;
    460     T stackArray[stackCapacity];
    461     void releaseMemory() {
    462         if(needToRelease) {
    463             uprv_free(ptr);
    464         }
    465     }
    466     /* No comparison operators with other MaybeStackHeaderAndArray's. */
    467     bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return FALSE;};
    468     bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return TRUE;};
    469     /* No ownership transfer: No copy constructor, no assignment operator. */
    470     MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {};
    471     void operator=(const MaybeStackHeaderAndArray & /*other*/) {};
    472 
    473     // No heap allocation. Use only on the stack.
    474     //   (Declaring these functions private triggers a cascade of problems;
    475     //    see the MaybeStackArray class for details.)
    476     // static void * U_EXPORT2 operator new(size_t size);
    477     // static void * U_EXPORT2 operator new[](size_t size);
    478 #if U_HAVE_PLACEMENT_NEW
    479     // static void * U_EXPORT2 operator new(size_t, void *ptr);
    480 #endif
    481 };
    482 
    483 template<typename H, typename T, int32_t stackCapacity>
    484 inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity,
    485                                                                 int32_t length) {
    486     if(newCapacity>=0) {
    487         H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T));
    488         if(p!=NULL) {
    489             if(length<0) {
    490                 length=0;
    491             } else if(length>0) {
    492                 if(length>capacity) {
    493                     length=capacity;
    494                 }
    495                 if(length>newCapacity) {
    496                     length=newCapacity;
    497                 }
    498             }
    499             uprv_memcpy(p, ptr, sizeof(H)+length*sizeof(T));
    500             releaseMemory();
    501             ptr=p;
    502             capacity=newCapacity;
    503             needToRelease=TRUE;
    504         }
    505         return p;
    506     } else {
    507         return NULL;
    508     }
    509 }
    510 
    511 template<typename H, typename T, int32_t stackCapacity>
    512 inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length,
    513                                                                        int32_t &resultCapacity) {
    514     H *p;
    515     if(needToRelease) {
    516         p=ptr;
    517     } else {
    518         if(length<0) {
    519             length=0;
    520         } else if(length>capacity) {
    521             length=capacity;
    522         }
    523         p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T));
    524         if(p==NULL) {
    525             return NULL;
    526         }
    527         uprv_memcpy(p, ptr, sizeof(H)+length*sizeof(T));
    528     }
    529     resultCapacity=length;
    530     ptr=&stackHeader;
    531     capacity=stackCapacity;
    532     needToRelease=FALSE;
    533     return p;
    534 }
    535 
    536 U_NAMESPACE_END
    537 
    538 #endif  /* XP_CPLUSPLUS */
    539 #endif  /* CMEMORY_H */
    540