diff --git a/icu4c/source/common/cmemory.h b/icu4c/source/common/cmemory.h index 4bce1934393..9fca0f75edb 100644 --- a/icu4c/source/common/cmemory.h +++ b/icu4c/source/common/cmemory.h @@ -1,7 +1,7 @@ /* ****************************************************************************** * -* Copyright (C) 1997-2008, International Business Machines +* Copyright (C) 1997-2009, International Business Machines * Corporation and others. All Rights Reserved. * ****************************************************************************** @@ -25,6 +25,7 @@ #define CMEMORY_H #include "unicode/utypes.h" +#include "unicode/localpointer.h" #include #include @@ -91,4 +92,200 @@ cmemory_inUse(void); U_CFUNC UBool cmemory_cleanup(void); +#ifdef XP_CPLUSPLUS + +U_NAMESPACE_BEGIN + +/** + * "Smart pointer" class, deletes memory via uprv_free(). + * For most methods see the LocalPointerBase base class. + * Adds operator[] for array item access. + * + * @see LocalPointerBase + */ +template +class LocalMemory : public LocalPointerBase { +public: + /** + * Constructor takes ownership. + * @param p simple pointer to an array of T items that is adopted + */ + explicit LocalMemory(T *p=NULL) : LocalPointerBase(p) {} + /** + * Destructor deletes the memory it owns. + */ + ~LocalMemory() { + uprv_free(LocalPointerBase::ptr); + } + /** + * Deletes the array it owns, + * and adopts (takes ownership of) the one passed in. + * @param p simple pointer to an array of T items that is adopted + */ + void adoptInstead(T *p) { + uprv_free(LocalPointerBase::ptr); + LocalPointerBase::ptr=p; + } + /** + * Array item access (writable). + * No index bounds check. + * @param i array index + * @return reference to the array item + */ + T &operator[](ptrdiff_t i) const { return LocalPointerBase::ptr[i]; } +}; + +/** + * Simple array/buffer management class using uprv_malloc() and uprv_free(). + * Provides an internal array with fixed capacity. Can alias another array + * or allocate one. + * Unlike LocalMemory and LocalArray, this class never adopts + * (takes ownership of) another array. + */ +template +class MaybeStackArray { +public: + /** + * Default constructor initializes with internal T[stackCapacity] buffer. + */ + MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(FALSE) {} + /** + * Destructor deletes the array (if owned). + */ + ~MaybeStackArray() { releaseArray(); } + /** + * Returns the array capacity (number of T items). + * @return array capacity + */ + int32_t getCapacity() const { return capacity; } + /** + * Access without ownership change. + * @return the array pointer + */ + T *getAlias() const { return ptr; } + /** + * Returns the array limit. Simple convenience method. + * @return getAlias()+getCapacity() + */ + T *getArrayLimit() const { return getAlias()+capacity; } + /** + * Access without ownership change. Same as getAlias(). + * A class instance can be used directly in expressions that take a T *. + * @return the array pointer + */ + operator T *() const { return ptr; } + /** + * Array item access (writable). + * No index bounds check. + * @param i array index + * @return reference to the array item + */ + T &operator[](ptrdiff_t i) { return ptr[i]; } + /** + * Deletes the array (if owned) and aliases another one, no transfer of ownership. + * If the arguments are illegal, then the current array is unchanged. + * @param otherArray must not be NULL + * @param otherCapacity must be >0 + */ + void aliasInstead(T *otherArray, int32_t otherCapacity) { + if(otherArray!=NULL && otherCapacity>0) { + releaseArray(); + ptr=otherArray; + capacity=otherCapacity; + needToRelease=FALSE; + } + }; + /** + * Deletes the array (if owned) and allocates a new one, copying length T items. + * Returns the new array pointer. + * If the allocation fails, then the current array is unchanged and + * this method returns NULL. + * @param newCapacity can be less than or greater than the current capacity; + * must be >0 + * @param length number of T items to be copied from the old array to the new one + * @return the allocated array pointer, or NULL if the allocation failed + */ + T *resize(int32_t newCapacity, int32_t length=0) { + if(newCapacity>0) { + T *p=(T *)uprv_malloc(newCapacity*sizeof(T)); + if(p!=NULL) { + if(length>0) { + if(length>capacity) { + length=capacity; + } + if(length>newCapacity) { + length=newCapacity; + } + uprv_memcpy(p, ptr, length*sizeof(T)); + } + releaseArray(); + ptr=p; + capacity=newCapacity; + needToRelease=TRUE; + } + return p; + } else { + return NULL; + } + } + /** + * Gives up ownership of the array if owned, or else clones it, + * copying length T items; resets itself to the internal stack array. + * Returns NULL if the allocation failed. + * @param length number of T items to copy when cloning, + * and capacity of the clone when cloning + * @param resultCapacity will be set to the returned array's capacity (output-only) + * @return the array pointer; + * caller becomes responsible for deleting the array + * @draft ICU 4.4 + */ + T *orphanOrClone(int32_t length, int32_t &resultCapacity) { + T *p; + if(needToRelease) { + p=ptr; + } else if(length<=0) { + return NULL; + } else { + if(length>capacity) { + length=capacity; + } + p=(T *)uprv_malloc(length*sizeof(T)); + if(p==NULL) { + return NULL; + } + uprv_memcpy(p, ptr, length*sizeof(T)); + } + resultCapacity=length; + ptr=stackArray; + capacity=stackCapacity; + needToRelease=FALSE; + return p; + } +private: + T *ptr; + int32_t capacity; + UBool needToRelease; + T stackArray[stackCapacity]; + void releaseArray() { + if(needToRelease) { + uprv_free(ptr); + } + } + // No comparison operators with other MaybeStackArray's. + bool operator==(const MaybeStackArray &other); + bool operator!=(const MaybeStackArray &other); + // No ownership transfer: No copy constructor, no assignment operator. + MaybeStackArray(const MaybeStackArray &other); + void operator=(const MaybeStackArray &other); + // No heap allocation. Use only on the stack. + static void * U_EXPORT2 operator new(size_t size); + static void * U_EXPORT2 operator new[](size_t size); +#if U_HAVE_PLACEMENT_NEW + static void * U_EXPORT2 operator new(size_t, void *ptr); #endif +}; + +U_NAMESPACE_END + +#endif /* XP_CPLUSPLUS */ +#endif /* CMEMORY_H */ diff --git a/icu4c/source/common/unorm.cpp b/icu4c/source/common/unorm.cpp index 120c3c18c7d..343d47a210f 100644 --- a/icu4c/source/common/unorm.cpp +++ b/icu4c/source/common/unorm.cpp @@ -1977,10 +1977,84 @@ _composeHangul(UChar prev, UChar c, uint32_t norm32, const UChar *&src, const UC return FALSE; } +class UCharBuffer { +public: + UCharBuffer() : uchars(), length(0) {} + ~UCharBuffer() {} + UChar *getAlias() const { return uchars.getAlias(); } + UChar *getLimit() const { return getAlias()+length; } + operator UChar *() const { return uchars.getAlias(); } + int32_t getLength() const { return length; } + void setLength(int32_t newLength) { + if(newLength<0) { + length=0; + } else if(newLength=uchars.getCapacity() && NULL==uchars.resize(2*uchars.getCapacity(), length)) { + return FALSE; + } + uchars[length++]=c; + } + UChar *getAppendBuffer(int32_t minCapacity, + int32_t desiredCapacityHint, + int32_t &resultCapacity) { + int32_t capacity=uchars.getCapacity(); + int32_t restCapacity=capacity-length; + if(minCapacity>restCapacity) { + int32_t newCapacity=capacity+desiredCapacityHint; + int32_t doubleCapacity=2*capacity; + if(newCapacityuchars.getCapacity()) { + int32_t newCapacity=length+2*len; + int32_t doubleCapacity=2*uchars.getCapacity(); + if(newCapacity uchars; + int32_t length; +}; + /* - * recompose the characters in [p..limit[ + * recompose the characters in the buffer * (which is in NFD - decomposed and canonically ordered), - * adjust limit, and return the trailing cc + * and return the trailing cc * * since for NFKC we may get Jamos in decompositions, we need to * recompose those too @@ -1991,7 +2065,9 @@ _composeHangul(UChar prev, UChar c, uint32_t norm32, const UChar *&src, const UC * while the combining mark that is removed has at least one code unit */ static uint8_t -_recompose(UChar *p, UChar *&limit, int32_t options, const UnicodeSet *nx) { +_recompose(UCharBuffer &buffer, int32_t options, const UnicodeSet *nx) { + UChar *p; + UChar *limit; UChar *starter, *pRemove, *q, *r; uint32_t combineFlags; UChar c, c2; @@ -2000,6 +2076,8 @@ _recompose(UChar *p, UChar *&limit, int32_t options, const UnicodeSet *nx) { uint8_t cc, prevCC; UBool starterIsSupplementary; + p=buffer.getAlias(); + limit=buffer.getLimit(); starter=NULL; /* no starter */ combineFwdIndex=0; /* will not be used until starter!=NULL - avoid compiler warnings */ combineBackIndex=0; /* will always be set if combineFlags!=0 - avoid compiler warnings */ @@ -2070,7 +2148,7 @@ _recompose(UChar *p, UChar *&limit, int32_t options, const UnicodeSet *nx) { *q++=*r++; } p=pRemove; - limit=q; + buffer.setLimit(limit=q); } c2=0; /* c2 held *starter temporarily */ @@ -2155,7 +2233,7 @@ _recompose(UChar *p, UChar *&limit, int32_t options, const UnicodeSet *nx) { *q++=*r++; } p=pRemove; - limit=q; + buffer.setLimit(limit=q); } /* keep prevCC because we removed the combining mark */ @@ -2209,41 +2287,48 @@ _recompose(UChar *p, UChar *&limit, int32_t options, const UnicodeSet *nx) { /* decompose and recompose [prevStarter..src[ */ static const UChar * -_composePart(UChar *stackBuffer, UChar *&buffer, int32_t &bufferCapacity, int32_t &length, +_composePart(UCharBuffer &buffer, const UChar *prevStarter, const UChar *src, uint8_t &prevCC, int32_t options, const UnicodeSet *nx, UErrorCode *pErrorCode) { - UChar *recomposeLimit; uint8_t trailCC; UBool compat; compat=(UBool)((options&_NORM_OPTIONS_COMPAT)!=0); /* decompose [prevStarter..src[ */ - length=_decompose(buffer, bufferCapacity, + // TODO: change _decompose() to write to the UCharBuffer + int32_t capacity; + int32_t length=(int32_t)(src-prevStarter); + UChar *p=buffer.getAppendBuffer(length, 2*length, capacity); + if(p==NULL) { + *pErrorCode=U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + length=_decompose(p, capacity, prevStarter, (int32_t)(src-prevStarter), compat, nx, trailCC); - if(length>bufferCapacity) { - if(!u_growBufferFromStatic(stackBuffer, &buffer, &bufferCapacity, 2*length, 0)) { + if(length>capacity) { + p=buffer.getAppendBuffer(length, 2*length, capacity); + if(p==NULL) { *pErrorCode=U_MEMORY_ALLOCATION_ERROR; return NULL; } - length=_decompose(buffer, bufferCapacity, + length=_decompose(p, capacity, prevStarter, (int32_t)(src-prevStarter), compat, nx, trailCC); } + buffer.releaseAppendBuffer(length); /* recompose the decomposition */ - recomposeLimit=buffer+length; if(length>=2) { - prevCC=_recompose(buffer, recomposeLimit, options, nx); + prevCC=_recompose(buffer, options, nx); } - /* return with a pointer to the recomposition and its length */ - length=(int32_t)(recomposeLimit-buffer); + /* return with a pointer to the recomposition */ return buffer; } @@ -2252,10 +2337,7 @@ _compose(UChar *dest, int32_t destCapacity, const UChar *src, int32_t srcLength, int32_t options, const UnicodeSet *nx, UErrorCode *pErrorCode) { - UChar stackBuffer[_STACK_BUFFER_CAPACITY]; - UChar *buffer; - int32_t bufferCapacity; - + UCharBuffer buffer; const UChar *limit, *prevSrc, *prevStarter; uint32_t norm32, ccOrQCMask, qcMask; int32_t destIndex, reorderStartIndex, length; @@ -2271,8 +2353,6 @@ _compose(UChar *dest, int32_t destCapacity, } /* initialize */ - buffer=stackBuffer; - bufferCapacity=_STACK_BUFFER_CAPACITY; /* * prevStarter points to the last character before the current one @@ -2469,8 +2549,8 @@ _compose(UChar *dest, int32_t destCapacity, src=_findNextStarter(src, limit, qcMask, decompQCMask, minNoMaybe); /* compose [prevStarter..src[ */ - p=_composePart(stackBuffer, buffer, bufferCapacity, - length, /* output */ + buffer.setLength(0); + p=_composePart(buffer, /* output */ prevStarter, src, prevCC, /* output */ options, nx, @@ -2482,6 +2562,7 @@ _compose(UChar *dest, int32_t destCapacity, } /* append the recomposed buffer contents to the destination buffer */ + length=buffer.getLength(); if((destIndex+length)<=destCapacity) { while(length>0) { dest[destIndex++]=*p++; @@ -2523,11 +2604,6 @@ _compose(UChar *dest, int32_t destCapacity, } } - /* cleanup */ - if(buffer!=stackBuffer) { - uprv_free(buffer); - } - return destIndex; } @@ -3027,10 +3103,6 @@ _quickCheck(const UChar *src, UBool allowMaybe, const UnicodeSet *nx, UErrorCode *pErrorCode) { - UChar stackBuffer[_STACK_BUFFER_CAPACITY]; - UChar *buffer; - int32_t bufferCapacity; - const UChar *start, *limit; uint32_t norm32, qcNorm32, ccOrQCMask, qcMask; int32_t options; @@ -3086,9 +3158,7 @@ _quickCheck(const UChar *src, } /* initialize */ - buffer=stackBuffer; - bufferCapacity=_STACK_BUFFER_CAPACITY; - + UCharBuffer buffer; ccOrQCMask=_NORM_CC_MASK|qcMask; result=UNORM_YES; prevCC=0; @@ -3111,7 +3181,7 @@ _quickCheck(const UChar *src, c=*src++; if(c=minNoMaybe && ((norm32=_getNorm32(c))&ccOrQCMask)!=0) { break; } @@ -3169,7 +3239,6 @@ _quickCheck(const UChar *src, /* normalize a section around here to see if it is really normalized or not */ const UChar *prevStarter; uint32_t decompQCMask; - int32_t length; decompQCMask=(qcMask<<2)&0xf; /* decomposition quick check mask */ @@ -3184,8 +3253,8 @@ _quickCheck(const UChar *src, src=_findNextStarter(src, limit, qcMask, decompQCMask, minNoMaybe); /* decompose and recompose [prevStarter..src[ */ - _composePart(stackBuffer, buffer, bufferCapacity, - length, + buffer.setLength(0); + _composePart(buffer, prevStarter, src, prevCC, @@ -3196,7 +3265,7 @@ _quickCheck(const UChar *src, } /* compare the normalized version with the original */ - if(0!=uprv_strCompare(prevStarter, (int32_t)(src-prevStarter), buffer, length, FALSE, FALSE)) { + if(0!=uprv_strCompare(prevStarter, (int32_t)(src-prevStarter), buffer, buffer.getLength(), FALSE, FALSE)) { result=UNORM_NO; /* normalization differs */ break; } @@ -3205,12 +3274,6 @@ _quickCheck(const UChar *src, } } } -endloop: - - if(buffer!=stackBuffer) { - uprv_free(buffer); - } - return result; }