ICU-7247 add internal LocalMemory and MaybeStackArray classes

X-SVN-Rev: 26951
This commit is contained in:
Markus Scherer 2009-11-18 23:35:52 +00:00
parent 9a9fcc0fac
commit 3b12074b40
2 changed files with 308 additions and 48 deletions

View File

@ -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 <stddef.h>
#include <string.h>
@ -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<typename T>
class LocalMemory : public LocalPointerBase<T> {
public:
/**
* Constructor takes ownership.
* @param p simple pointer to an array of T items that is adopted
*/
explicit LocalMemory(T *p=NULL) : LocalPointerBase<T>(p) {}
/**
* Destructor deletes the memory it owns.
*/
~LocalMemory() {
uprv_free(LocalPointerBase<T>::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<T>::ptr);
LocalPointerBase<T>::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<T>::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<typename T, int32_t stackCapacity>
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 */

View File

@ -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<length) {
length=newLength;
}
}
void setLimit(const UChar *newLimit) {
UChar *start=uchars.getAlias();
if(start<=newLimit && newLimit<(start+length)) {
length=(int32_t)(newLimit-start);
}
}
UChar &operator[](ptrdiff_t i) { return uchars[i]; }
UBool append(UChar c) {
if(length>=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(newCapacity<doubleCapacity) {
newCapacity=doubleCapacity;
}
if(NULL==uchars.resize(newCapacity, length)) {
return NULL;
}
}
resultCapacity=uchars.getCapacity()-length;
return uchars.getAlias()+length;
}
void releaseAppendBuffer(int32_t len) {
length+=len;
}
UBool append(const UChar *p, int32_t len) {
int32_t newLength=length+len;
if(p==(uchars.getAlias()+length)) {
length=newLength;
return TRUE; // caller wrote to the getAppendBuffer()
}
if(newLength>uchars.getCapacity()) {
int32_t newCapacity=length+2*len;
int32_t doubleCapacity=2*uchars.getCapacity();
if(newCapacity<doubleCapacity) {
newCapacity=doubleCapacity;
}
if(NULL==uchars.resize(newCapacity, length)) {
return FALSE;
}
}
u_memcpy(uchars.getAlias(), p, len);
length=newLength;
return TRUE;
}
private:
MaybeStackArray<UChar, _STACK_BUFFER_CAPACITY> 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) {
if(c==0) {
goto endloop; /* break out of outer loop */
return result; /* break out of outer loop */
}
} else if(((norm32=_getNorm32(c))&ccOrQCMask)!=0) {
break;
@ -3121,7 +3191,7 @@ _quickCheck(const UChar *src,
} else {
for(;;) {
if(src==limit) {
goto endloop; /* break out of outer loop */
return result; /* break out of outer loop */
} else if((c=*src++)>=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;
}