ICU-8314 Appendable interface, AppendableAdapter default impl & UnicodeString is-an Appendable

X-SVN-Rev: 29390
This commit is contained in:
Markus Scherer 2011-02-03 05:28:01 +00:00
parent 7c69a86709
commit d8ea46628b
12 changed files with 553 additions and 110 deletions

View file

@ -86,7 +86,7 @@ ucnv_ext.o ucnvmbcs.o ucnv2022.o ucnvhz.o ucnv_lmb.o ucnvisci.o ucnvdisp.o ucnv_
uresbund.o ures_cnv.o uresdata.o resbund.o resbund_cnv.o \
ucat.o locmap.o uloc.o locid.o locutil.o locavailable.o locdispnames.o loclikely.o locresdata.o \
bytestream.o stringpiece.o bytestrie.o bytestrieiterator.o \
ustr_cnv.o unistr_cnv.o unistr.o unistr_case.o unistr_props.o \
appendable.o ustr_cnv.o unistr_cnv.o unistr.o unistr_case.o unistr_props.o \
utf_impl.o ustring.o ustrcase.o ucasemap.o cstring.o ustrfmt.o ustrtrns.o ustr_wcs.o utext.o \
normalizer2impl.o normalizer2.o filterednormalizer2.o normlzr.o unorm.o unormcmp.o unorm_it.o \
chariter.o schriter.o uchriter.o uiter.o \

View file

@ -0,0 +1,71 @@
/*
*******************************************************************************
* Copyright (C) 2011, International Business Machines
* Corporation and others. All Rights Reserved.
*******************************************************************************
* file name: appendable.cpp
* encoding: US-ASCII
* tab size: 8 (not used)
* indentation:4
*
* created on: 2010dec07
* created by: Markus W. Scherer
*/
#include "unicode/utypes.h"
#include "unicode/appendable.h"
U_NAMESPACE_BEGIN
Appendable::~Appendable() {}
UBool
AppendableAdapter::appendCodePoint(UChar32 c) {
if(c<=0xffff) {
return appendCodeUnit((UChar)c);
} else {
return appendCodeUnit(U16_LEAD(c)) && appendCodeUnit(U16_TRAIL(c));
}
}
UBool
AppendableAdapter::appendString(const UChar *s, int32_t length) {
if(length<0) {
UChar c;
while((c=*s++)!=0) {
if(!appendCodeUnit(c)) {
return FALSE;
}
}
} else if(length>0) {
const UChar *limit=s+length;
do {
if(!appendCodeUnit(*s++)) {
return FALSE;
}
} while(s<limit);
}
return TRUE;
}
UBool
AppendableAdapter::reserveAppendCapacity(int32_t /*appendCapacity*/) {
return TRUE;
}
UChar *
AppendableAdapter::getAppendBuffer(int32_t minCapacity,
int32_t /*desiredCapacityHint*/,
UChar *scratch, int32_t scratchCapacity,
int32_t *resultCapacity) {
if(minCapacity<1 || scratchCapacity<minCapacity) {
*resultCapacity=0;
return NULL;
}
*resultCapacity=scratchCapacity;
return scratch;
}
UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(AppendableAdapter)
U_NAMESPACE_END

View file

@ -399,6 +399,7 @@
<ClCompile Include="servrbf.cpp" />
<ClCompile Include="servslkf.cpp" />
<ClCompile Include="usprep.cpp" />
<ClCompile Include="appendable.cpp" />
<ClCompile Include="bytestream.cpp" />
<ClCompile Include="bytestrie.cpp" />
<ClCompile Include="bytestrieiterator.cpp" />
@ -1351,6 +1352,20 @@
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
</CustomBuild>
<CustomBuild Include="unicode\appendable.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
</CustomBuild>

View file

@ -0,0 +1,213 @@
/*
*******************************************************************************
* Copyright (C) 2011, International Business Machines
* Corporation and others. All Rights Reserved.
*******************************************************************************
* file name: appendable.h
* encoding: US-ASCII
* tab size: 8 (not used)
* indentation:4
*
* created on: 2010dec07
* created by: Markus W. Scherer
*/
#ifndef __APPENDABLE_H__
#define __APPENDABLE_H__
/**
* \file
* \brief C++ API: Appendable interface: Sink for Unicode code points and 16-bit code units (UChars).
*/
#include "unicode/utypes.h"
#include "unicode/uobject.h"
U_NAMESPACE_BEGIN
/**
* Interface/mixin class for objects to which Unicode characters and strings can be appended.
* Combines elements of Java Appendable and ICU4C ByteSink.
*
* This class is not intended for public subclassing.
* You should subclass AppendableAdapter instead, in case methods are added to this interface.
*
* This interface can be used in APIs where it does not matter whether the actual destination is
* a UnicodeString, a UChar[] array, a UnicodeSet, or any other object
* that receives and processes characters and/or strings.
*
* Note: UnicodeString is-an Appendable.
*
* The methods do not take UErrorCode parameters.
* If an error occurs (e.g., out-of-memory),
* in addition to returning FALSE from failing operations,
* the implementation must prevent unexpected behavior (e.g., crashes)
* from further calls and should make the error condition available separately
* (e.g., store a UErrorCode, make/keep a UnicodeString bogus).
* @draft ICU 4.8
*/
class U_COMMON_API Appendable /* not : public UObject because this is an interface/mixin class */ {
public:
/**
* Destructor.
* @draft ICU 4.8
*/
virtual ~Appendable();
/**
* Appends a 16-bit code unit.
* @param c code unit
* @return TRUE if the operation succeeded
* @draft ICU 4.8
*/
virtual UBool appendCodeUnit(UChar c) = 0;
/**
* Appends a code point.
* @param c code point 0..0x10ffff
* @return TRUE if the operation succeeded
* @draft ICU 4.8
*/
virtual UBool appendCodePoint(UChar32 c) = 0;
/**
* Appends a string.
* @param s string, must not be NULL if length!=0
* @param length string length, or -1 if NUL-terminated
* @return TRUE if the operation succeeded
* @draft ICU 4.8
*/
virtual UBool appendString(const UChar *s, int32_t length) = 0;
/**
* Tells the object that the caller is going to append roughly
* appendCapacity UChars. A subclass might use this to pre-allocate
* a larger buffer if necessary.
* @param appendCapacity estimated number of UChars that will be appended
* @return TRUE if the operation succeeded
* @draft ICU 4.8
*/
virtual UBool reserveAppendCapacity(int32_t appendCapacity) = 0;
/**
* Returns a writable buffer for appending and writes the buffer's capacity to
* *resultCapacity. Guarantees *resultCapacity>=minCapacity.
* May return a pointer to the caller-owned scratch buffer which must have
* scratchCapacity>=minCapacity.
* The returned buffer is only valid until the next operation
* on this Appendable.
*
* After writing at most *resultCapacity UChars, call appendString() with the
* pointer returned from this function and the number of UChars written.
* Many appendString() implementations will avoid copying UChars if this function
* returned an internal buffer.
*
* Partial usage example:
* \code
* int32_t capacity;
* UChar* buffer = app.getAppendBuffer(..., &capacity);
* ... Write n UChars into buffer, with n <= capacity.
* app.appendString(buffer, n);
* \endcode
* In many implementations, that call to append will avoid copying UChars.
*
* If the Appendable allocates or reallocates an internal buffer, it should use
* the desiredCapacityHint if appropriate.
* If a caller cannot provide a reasonable guess at the desired capacity,
* it should pass desiredCapacityHint=0.
*
* If a non-scratch buffer is returned, the caller may only pass
* a prefix to it to appendString().
* That is, it is not correct to pass an interior pointer to appendString().
*
* @param minCapacity required minimum capacity of the returned buffer;
* must be non-negative
* @param desiredCapacityHint desired capacity of the returned buffer;
* must be non-negative
* @param scratch default caller-owned buffer
* @param scratchCapacity capacity of the scratch buffer
* @param resultCapacity pointer to an integer which will be set to the
* capacity of the returned buffer
* @return a buffer with *resultCapacity>=minCapacity
* @draft ICU 4.8
*/
virtual UChar *getAppendBuffer(int32_t minCapacity,
int32_t desiredCapacityHint,
UChar *scratch, int32_t scratchCapacity,
int32_t *resultCapacity) = 0;
};
/**
* Default Appendable implementation.
* This class provides default implementations for all Appendable methods
* except appendCodeUnit(), to make subclassing easy.
* @draft ICU 4.8
*/
class U_COMMON_API AppendableAdapter : public UObject, public Appendable {
public:
/**
* Appends a code point.
* The default implementation calls appendCodeUnit(UChar) once or twice.
* @param c code point 0..0x10ffff
* @return TRUE if the operation succeeded
* @draft ICU 4.8
*/
virtual UBool appendCodePoint(UChar32 c);
/**
* Appends a string.
* The default implementation calls appendCodeUnit(UChar) for each code unit.
* @param s string, must not be NULL if length!=0
* @param length string length, or -1 if NUL-terminated
* @return TRUE if the operation succeeded
* @draft ICU 4.8
*/
virtual UBool appendString(const UChar *s, int32_t length);
/**
* Tells the object that the caller is going to append roughly
* appendCapacity UChars. A subclass might use this to pre-allocate
* a larger buffer if necessary.
* The default implementation does nothing. (It always returns TRUE.)
* @param appendCapacity estimated number of UChars that will be appended
* @return TRUE if the operation succeeded
* @draft ICU 4.8
*/
virtual UBool reserveAppendCapacity(int32_t appendCapacity);
/**
* Returns a writable buffer for appending and writes the buffer's capacity to
* *resultCapacity. Guarantees *resultCapacity>=minCapacity.
* May return a pointer to the caller-owned scratch buffer which must have
* scratchCapacity>=minCapacity.
* The returned buffer is only valid until the next operation
* on this Appendable.
*
* For details see Appendable::getAppendBuffer().
*
* The default implementation always returns the scratch buffer.
*
* @param minCapacity required minimum capacity of the returned buffer;
* must be non-negative
* @param desiredCapacityHint desired capacity of the returned buffer;
* must be non-negative
* @param scratch default caller-owned buffer
* @param scratchCapacity capacity of the scratch buffer
* @param resultCapacity pointer to an integer which will be set to the
* capacity of the returned buffer
* @return a buffer with *resultCapacity>=minCapacity
* @draft ICU 4.8
*/
virtual UChar *getAppendBuffer(int32_t minCapacity,
int32_t desiredCapacityHint,
UChar *scratch, int32_t scratchCapacity,
int32_t *resultCapacity);
private:
// No ICU "poor man's RTTI" for this class nor its subclasses.
virtual UClassID getDynamicClassID() const;
};
U_NAMESPACE_END
#endif // __APPENDABLE_H__

View file

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (C) 1998-2010, International Business Machines
* Copyright (C) 1998-2011, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
*
@ -27,6 +27,7 @@
*/
#include "unicode/utypes.h"
#include "unicode/appendable.h"
#include "unicode/rep.h"
#include "unicode/std_string.h"
#include "unicode/stringpiece.h"
@ -184,7 +185,7 @@ class BreakIterator; // unicode/brkiter.h
* @see CharacterIterator
* @stable ICU 2.0
*/
class U_COMMON_API UnicodeString : public Replaceable
class U_COMMON_API UnicodeString : public Replaceable, public Appendable
{
public:
@ -2035,7 +2036,7 @@ public:
* @param srcStart the offset into <TT>srcChars</TT> where new characters
* will be obtained
* @param srcLength the number of characters in <TT>srcChars</TT> in
* the append string
* the append string; can be -1 if <TT>srcChars</TT> is NUL-terminated
* @return a reference to this
* @stable ICU 2.0
*/
@ -2047,7 +2048,8 @@ public:
* Append the characters in <TT>srcChars</TT> to the UnicodeString object
* at offset <TT>start</TT>. <TT>srcChars</TT> is not modified.
* @param srcChars the source for the new characters
* @param srcLength the number of Unicode characters in <TT>srcChars</TT>
* @param srcLength the number of Unicode characters in <TT>srcChars</TT>;
* can be -1 if <TT>srcChars</TT> is NUL-terminated
* @return a reference to this
* @stable ICU 2.0
*/
@ -2070,6 +2072,46 @@ public:
*/
inline UnicodeString& append(UChar32 srcChar);
/**
* Appends a 16-bit code unit.
* Equivalent to
* \code
* return !append(c).isBogus();
* \endcode
* (Implements Appendable.)
* @param c code unit
* @return TRUE if the operation succeeded
* @draft ICU 4.8
*/
virtual UBool appendCodeUnit(UChar c);
/**
* Appends a code point.
* Equivalent to
* \code
* return !append(c).isBogus();
* \endcode
* (Implements Appendable.)
* @param c code point 0..0x10ffff
* @return TRUE if the operation succeeded
* @draft ICU 4.8
*/
virtual UBool appendCodePoint(UChar32 c);
/**
* Appends a string.
* Equivalent to
* \code
* return !append(s, length).isBogus();
* \endcode
* (Implements Appendable.)
* @param s string, must not be NULL if length!=0
* @param length string length, or -1 if NUL-terminated
* @return TRUE if the operation succeeded
* @draft ICU 4.8
*/
virtual UBool appendString(const UChar *s, int32_t length);
/* Insert operations */
@ -2781,6 +2823,43 @@ public:
*/
inline const UChar *getTerminatedBuffer();
/**
* Tells the UnicodeString that the caller is going to append roughly
* appendCapacity UChars.
* (Implements Appendable.)
* @param appendCapacity estimated number of UChars that will be appended
* @return TRUE if the operation succeeded
* @draft ICU 4.8
*/
virtual UBool reserveAppendCapacity(int32_t appendCapacity);
/**
* Returns a writable buffer for appending and writes the buffer's capacity to
* *resultCapacity. Guarantees *resultCapacity>=minCapacity.
* May return a pointer to the caller-owned scratch buffer which must have
* scratchCapacity>=minCapacity.
* The returned buffer is only valid until the next operation
* on this UnicodeString.
*
* (Implements Appendable.)
* For details see Appendable::getAppendBuffer().
*
* @param minCapacity required minimum capacity of the returned buffer;
* must be non-negative
* @param desiredCapacityHint desired capacity of the returned buffer;
* must be non-negative
* @param scratch default caller-owned buffer
* @param scratchCapacity capacity of the scratch buffer
* @param resultCapacity pointer to an integer which will be set to the
* capacity of the returned buffer
* @return a buffer with *resultCapacity>=minCapacity
* @draft ICU 4.8
*/
virtual UChar *getAppendBuffer(int32_t minCapacity,
int32_t desiredCapacityHint,
UChar *scratch, int32_t scratchCapacity,
int32_t *resultCapacity);
//========================================
// Constructors
//========================================

View file

@ -1,6 +1,6 @@
/*
******************************************************************************
* Copyright (C) 1999-2010, International Business Machines Corporation and *
* Copyright (C) 1999-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*
@ -1260,14 +1260,24 @@ UnicodeString::doReplace(int32_t start,
}
// calculate the size of the string after the replace
int32_t newSize;
int32_t newLength;
// optimize append() onto a large-enough, owned string
if(start >= oldLength) {
newSize = oldLength + srcLength;
if(newSize <= getCapacity() && isBufferWritable()) {
us_arrayCopy(srcChars, srcStart, getArrayStart(), oldLength, srcLength);
setLength(newSize);
newLength = oldLength + srcLength;
if(newLength <= getCapacity() && isBufferWritable()) {
UChar *oldArray = getArrayStart();
// Do not copy characters when
// UChar *buffer=str.getAppendBuffer(...);
// is followed by
// str.append(buffer, length);
// or
// str.appendString(buffer, length)
// or similar.
if(srcChars + srcStart != oldArray + start || start > oldLength) {
us_arrayCopy(srcChars, srcStart, oldArray, oldLength, srcLength);
}
setLength(newLength);
return *this;
} else {
// pin the indices to legal values
@ -1278,14 +1288,14 @@ UnicodeString::doReplace(int32_t start,
// pin the indices to legal values
pinIndices(start, length);
newSize = oldLength - length + srcLength;
newLength = oldLength - length + srcLength;
}
// the following may change fArray but will not copy the current contents;
// therefore we need to keep the current fArray
UChar oldStackBuffer[US_STACKBUF_SIZE];
UChar *oldArray;
if((fFlags&kUsingStackBuffer) && (newSize > US_STACKBUF_SIZE)) {
if((fFlags&kUsingStackBuffer) && (newLength > US_STACKBUF_SIZE)) {
// copy the stack buffer contents because it will be overwritten with
// fUnion.fFields values
u_memcpy(oldStackBuffer, fUnion.fStackBuffer, oldLength);
@ -1296,7 +1306,7 @@ UnicodeString::doReplace(int32_t start,
// clone our array and allocate a bigger array if needed
int32_t *bufferToDelete = 0;
if(!cloneArrayIfNeeded(newSize, newSize + (newSize >> 2) + kGrowSize,
if(!cloneArrayIfNeeded(newLength, newLength + (newLength >> 2) + kGrowSize,
FALSE, &bufferToDelete)
) {
return *this;
@ -1321,7 +1331,7 @@ UnicodeString::doReplace(int32_t start,
// now fill in the hole with the new string
us_arrayCopy(srcChars, srcStart, newArray, start, srcLength);
setLength(newSize);
setLength(newLength);
// delayed delete in case srcChars == fArray when we started, and
// to keep oldArray alive for the above operations
@ -1332,6 +1342,28 @@ UnicodeString::doReplace(int32_t start,
return *this;
}
// Implements Appendable.
UBool
UnicodeString::appendCodeUnit(UChar c) {
return doReplace(length(), 0, &c, 0, 1).isWritable();
}
// Implements Appendable.
UBool
UnicodeString::appendCodePoint(UChar32 c) {
UChar buffer[U16_MAX_LENGTH];
int32_t cLength = 0;
UBool isError = FALSE;
U16_APPEND(buffer, cLength, U16_MAX_LENGTH, c, isError);
return !isError && doReplace(length(), 0, buffer, 0, cLength).isWritable();
}
// Implements Appendable.
UBool
UnicodeString::appendString(const UChar *s, int32_t sLength) {
return doReplace(length(), 0, s, 0, sLength).isWritable();
}
/**
* Replaceable API
*/
@ -1513,6 +1545,25 @@ UnicodeString::releaseBuffer(int32_t newLength) {
}
}
// Implements Appendable.
UChar *
UnicodeString::getAppendBuffer(int32_t minCapacity,
int32_t desiredCapacityHint,
UChar *scratch, int32_t scratchCapacity,
int32_t *resultCapacity) {
if(minCapacity < 1 || scratchCapacity < minCapacity) {
*resultCapacity = 0;
return NULL;
}
int32_t oldLength = length();
if(cloneArrayIfNeeded(oldLength + minCapacity, oldLength + desiredCapacityHint)) {
*resultCapacity = getCapacity() - oldLength;
return getArrayStart() + oldLength;
}
*resultCapacity = scratchCapacity;
return scratch;
}
//========================================
// Miscellaneous
//========================================
@ -1616,6 +1667,13 @@ UnicodeString::cloneArrayIfNeeded(int32_t newCapacity,
}
return TRUE;
}
// Implements Appendable.
UBool
UnicodeString::reserveAppendCapacity(int32_t appendCapacity) {
return cloneArrayIfNeeded(length() + appendCapacity);
}
U_NAMESPACE_END
#ifdef U_STATIC_IMPLEMENTATION

View file

@ -17,6 +17,7 @@
#include "unicode/utypes.h"
#include "unicode/localpointer.h"
#include "unicode/uniset.h"
#include "unicode/unistr.h"
#include "ucharstrie.h"
#include "ucharstriebuilder.h"
#include "intltest.h"
@ -494,23 +495,13 @@ void UCharsTrieTest::TestHasUniqueValue() {
}
}
class UnicodeStringAppendable : public Appendable {
public:
UnicodeStringAppendable(UnicodeString &dest) : str(dest) {}
virtual Appendable &append(UChar c) { str.append(c); return *this; }
UnicodeStringAppendable &reset() { str.remove(); return *this; }
private:
UnicodeString &str;
};
void UCharsTrieTest::TestGetNextUChars() {
LocalPointer<UCharsTrie> trie(buildMonthsTrie(USTRINGTRIE_BUILD_SMALL));
if(trie.isNull()) {
return; // buildTrie() reported an error
}
UnicodeString buffer;
UnicodeStringAppendable app(buffer);
int32_t count=trie->getNextUChars(app);
int32_t count=trie->getNextUChars(buffer);
if(count!=2 || buffer.length()!=2 || buffer[0]!=u_a || buffer[1]!=u_j) {
errln("months getNextUChars()!=[aj] at root");
}
@ -518,31 +509,31 @@ void UCharsTrieTest::TestGetNextUChars() {
trie->next(u_a);
trie->next(u_n);
// getNextUChars() directly after next()
count=trie->getNextUChars(app.reset());
count=trie->getNextUChars(buffer.remove());
if(count!=20 || buffer!=UNICODE_STRING_SIMPLE(".abcdefghijklmnopqru")) {
errln("months getNextUChars()!=[.abcdefghijklmnopqru] after \"jan\"");
}
// getNextUChars() after getValue()
trie->getValue(); // next() had returned USTRINGTRIE_INTERMEDIATE_VALUE.
count=trie->getNextUChars(app.reset());
count=trie->getNextUChars(buffer.remove());
if(count!=20 || buffer!=UNICODE_STRING_SIMPLE(".abcdefghijklmnopqru")) {
errln("months getNextUChars()!=[.abcdefghijklmnopqru] after \"jan\"+getValue()");
}
// getNextUChars() from a linear-match node
trie->next(u_u);
count=trie->getNextUChars(app.reset());
count=trie->getNextUChars(buffer.remove());
if(count!=1 || buffer.length()!=1 || buffer[0]!=u_a) {
errln("months getNextUChars()!=[a] after \"janu\"");
}
trie->next(u_a);
count=trie->getNextUChars(app.reset());
count=trie->getNextUChars(buffer.remove());
if(count!=1 || buffer.length()!=1 || buffer[0]!=u_r) {
errln("months getNextUChars()!=[r] after \"janua\"");
}
trie->next(u_r);
trie->next(u_y);
// getNextUChars() after a final match
count=trie->getNextUChars(app.reset());
count=trie->getNextUChars(buffer.remove());
if(count!=0 || buffer.length()!=0) {
errln("months getNextUChars()!=[] after \"january\"");
}

View file

@ -1,6 +1,6 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2010, International Business Machines Corporation and
* Copyright (c) 1997-2011, International Business Machines Corporation and
* others. All Rights Reserved.
* Copyright (C) 2010 , Yahoo! Inc.
********************************************************************/
@ -249,6 +249,7 @@ UObject *UObjectTest::testClassNoClassID(UObject *obj, const char *className, co
#include "reldtfmt.h"
// External Things
#include "unicode/appendable.h"
#include "unicode/brkiter.h"
#include "unicode/calendar.h"
#include "unicode/caniter.h"
@ -311,6 +312,12 @@ public:
};
#endif
// AppendableAdapter is abstract; we define a subclass to verify that there is no "poor man's RTTI".
class DummyAppendable : public AppendableAdapter {
public:
virtual UBool appendCodeUnit(UChar /*c*/) { return TRUE; }
};
void UObjectTest::testIDs()
{
ids_count = 0;
@ -445,7 +452,8 @@ void UObjectTest::testIDs()
TESTCLASSID_FACTORY(OlsonTimeZone, TimeZone::createTimeZone(UnicodeString("America/Los_Angeles")));
TESTCLASSID_FACTORY_HIDDEN(KeywordEnumeration, TimeZone::createEnumeration());
#endif
TESTCLASSID_NONE_DEFAULT(DummyAppendable);
TESTCLASSID_DEFAULT(UnicodeString);
TESTCLASSID_CTOR(UnicodeSet, (0, 1));
TESTCLASSID_ABSTRACT(UnicodeFilter);

View file

@ -1,10 +1,11 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2010, International Business Machines Corporation and
* Copyright (c) 1997-2011, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
#include "ustrtest.h"
#include "unicode/appendable.h"
#include "unicode/std_string.h"
#include "unicode/unistr.h"
#include "unicode/uchar.h"
@ -62,6 +63,8 @@ void UnicodeStringTest::runIndexedTest( int32_t index, UBool exec, const char* &
case 17: name = "TestUTF32"; if (exec) TestUTF32(); break;
case 18: name = "TestUTF8"; if (exec) TestUTF8(); break;
case 19: name = "TestReadOnlyAlias"; if (exec) TestReadOnlyAlias(); break;
case 20: name = "TestAppendable"; if (exec) TestAppendable(); break;
case 21: name = "TestUnicodeStringImplementsAppendable"; if (exec) TestUnicodeStringImplementsAppendable(); break;
default: name = ""; break; //needed to end loop
}
@ -2013,3 +2016,61 @@ UnicodeStringTest::TestReadOnlyAlias() {
errln("UnicodeString.setToBogus().tempSubStringBetween(8, 18) failed");
}
}
void
UnicodeStringTest::doTestAppendable(UnicodeString &dest, Appendable &app) {
static const UChar cde[3]={ 0x63, 0x64, 0x65 };
static const UChar fg[3]={ 0x66, 0x67, 0 };
if(!app.reserveAppendCapacity(12)) {
errln("Appendable.reserve(12) failed");
}
app.appendCodeUnit(0x61);
app.appendCodePoint(0x62);
app.appendCodePoint(0x50000);
app.appendString(cde, 3);
app.appendString(fg, -1);
UChar scratch[3];
int32_t capacity=-1;
UChar *buffer=app.getAppendBuffer(3, 3, scratch, 3, &capacity);
if(capacity<3) {
errln("Appendable.getAppendBuffer(min=3) returned capacity=%d<3", (int)capacity);
return;
}
static const UChar hij[3]={ 0x68, 0x69, 0x6a };
u_memcpy(buffer, hij, 3);
app.appendString(buffer, 3);
if(dest!=UNICODE_STRING_SIMPLE("ab\\U00050000cdefghij").unescape()) {
errln("Appendable.append(...) failed");
}
buffer=app.getAppendBuffer(0, 3, scratch, 3, &capacity);
if(buffer!=NULL || capacity!=0) {
errln("Appendable.getAppendBuffer(min=0) failed");
}
capacity=1;
buffer=app.getAppendBuffer(3, 3, scratch, 2, &capacity);
if(buffer!=NULL || capacity!=0) {
errln("Appendable.getAppendBuffer(scratch<min) failed");
}
}
class UnicodeStringAppendable : public AppendableAdapter {
public:
UnicodeStringAppendable(UnicodeString &dest) : str(dest) {}
virtual UBool appendCodeUnit(UChar c) { str.append(c); return TRUE; }
UnicodeStringAppendable &reset() { str.remove(); return *this; }
private:
UnicodeString &str;
};
void
UnicodeStringTest::TestAppendable() {
UnicodeString dest;
UnicodeStringAppendable app(dest);
doTestAppendable(dest, app);
}
void
UnicodeStringTest::TestUnicodeStringImplementsAppendable() {
UnicodeString dest;
doTestAppendable(dest, dest);
}

View file

@ -1,6 +1,6 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2010, International Business Machines Corporation and
* Copyright (c) 1997-2011, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
@ -10,6 +10,12 @@
#include "unicode/unistr.h"
#include "intltest.h"
U_NAMESPACE_BEGIN
class Appendable;
U_NAMESPACE_END
/**
* Perform API and functionality tests for class UnicodeString
**/
@ -70,13 +76,16 @@ public:
void TestUnescape(void);
void _testUnicodeStringHasMoreChar32Than(const UnicodeString &s, int32_t start, int32_t length, int32_t number);
void TestCountChar32(void);
void TestCountChar32();
void TestBogus();
void TestStringEnumeration();
void TestNameSpace(void);
void TestUTF32(void);
void TestUTF8(void);
void TestReadOnlyAlias(void);
void TestNameSpace();
void TestUTF32();
void TestUTF8();
void TestReadOnlyAlias();
void doTestAppendable(UnicodeString &dest, Appendable &app);
void TestAppendable();
void TestUnicodeStringImplementsAppendable();
};
class StringCaseTest: public IntlTest {

View file

@ -13,6 +13,7 @@
*/
#include "unicode/utypes.h"
#include "unicode/appendable.h"
#include "unicode/uobject.h"
#include "cmemory.h"
#include "uassert.h"
@ -20,35 +21,6 @@
U_NAMESPACE_BEGIN
Appendable &
Appendable::appendCodePoint(UChar32 c) {
if(c<=0xffff) {
return append((UChar)c);
} else {
return append(U16_LEAD(c)).append(U16_TRAIL(c));
}
}
Appendable &
Appendable::append(const UChar *s, int32_t length) {
if(s!=NULL && length!=0) {
if(length<0) {
UChar c;
while((c=*s++)!=0) {
append(c);
}
} else {
const UChar *limit=s+length;
while(s<limit) {
append(*s++);
}
}
}
return *this;
}
UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(Appendable)
UCharsTrie::~UCharsTrie() {
uprv_free(ownedArray_);
}
@ -376,7 +348,7 @@ UCharsTrie::getNextUChars(Appendable &out) const {
return 0;
}
if(remainingMatchLength_>=0) {
out.append(*pos); // Next unit of a pending linear-match node.
out.appendCodeUnit(*pos); // Next unit of a pending linear-match node.
return 1;
}
int32_t node=*pos++;
@ -392,11 +364,12 @@ UCharsTrie::getNextUChars(Appendable &out) const {
if(node==0) {
node=*pos++;
}
getNextBranchUChars(pos, ++node, out);
out.reserveAppendCapacity(++node);
getNextBranchUChars(pos, node, out);
return node;
} else {
// First unit of the linear-match node.
out.append(*pos);
out.appendCodeUnit(*pos);
return 1;
}
}
@ -410,10 +383,10 @@ UCharsTrie::getNextBranchUChars(const UChar *pos, int32_t length, Appendable &ou
pos=skipDelta(pos);
}
do {
out.append(*pos++);
out.appendCodeUnit(*pos++);
pos=skipValue(pos);
} while(--length>1);
out.append(*pos);
out.appendCodeUnit(*pos);
}
U_NAMESPACE_END

View file

@ -29,44 +29,10 @@
U_NAMESPACE_BEGIN
class Appendable;
class UCharsTrieBuilder;
class UVector32;
/**
* Base class for objects to which Unicode characters and strings can be appended.
* Combines elements of Java Appendable and ICU4C ByteSink.
* TODO: Should live in separate files, could be public API.
*/
class U_TOOLUTIL_API Appendable : public UObject {
public:
/**
* Appends a 16-bit code unit.
* @param c code unit
* @return *this
*/
virtual Appendable &append(UChar c) = 0;
/**
* Appends a code point; has a default implementation.
* @param c code point
* @return *this
*/
virtual Appendable &appendCodePoint(UChar32 c);
/**
* Appends a string; has a default implementation.
* @param s string
* @param length string length, or -1 if NUL-terminated
* @return *this
*/
virtual Appendable &append(const UChar *s, int32_t length);
// TODO: getAppendBuffer(), see ByteSink
// TODO: flush() (?) see ByteSink
private:
// No ICU "poor man's RTTI" for this class nor its subclasses.
virtual UClassID getDynamicClassID() const;
};
/**
* Light-weight, non-const reader class for a UCharsTrie.
* Traverses a UChar-serialized data structure with minimal state,
@ -263,7 +229,6 @@ public:
* Finds each UChar which continues the string from the current state.
* That is, each UChar c for which it would be next(c)!=USTRINGTRIE_NO_MATCH now.
* @param out Each next UChar is appended to this object.
* (Only uses the out.append(c) method.)
* @return the number of UChars which continue the string from here
*/
int32_t getNextUChars(Appendable &out) const;