ICU-7247 add internal LocalMemory and MaybeStackArray classes
X-SVN-Rev: 26951
This commit is contained in:
parent
9a9fcc0fac
commit
3b12074b40
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user