ICU-8314 change Appendable into a base class, add UnicodeStringAppendable

X-SVN-Rev: 29392
This commit is contained in:
Markus Scherer 2011-02-03 22:07:22 +00:00
parent 66f9f5a1d2
commit d5599d7be9
7 changed files with 186 additions and 245 deletions

View file

@ -17,10 +17,8 @@
U_NAMESPACE_BEGIN
Appendable::~Appendable() {}
UBool
AppendableAdapter::appendCodePoint(UChar32 c) {
Appendable::appendCodePoint(UChar32 c) {
if(c<=0xffff) {
return appendCodeUnit((UChar)c);
} else {
@ -29,7 +27,7 @@ AppendableAdapter::appendCodePoint(UChar32 c) {
}
UBool
AppendableAdapter::appendString(const UChar *s, int32_t length) {
Appendable::appendString(const UChar *s, int32_t length) {
if(length<0) {
UChar c;
while((c=*s++)!=0) {
@ -49,15 +47,15 @@ AppendableAdapter::appendString(const UChar *s, int32_t length) {
}
UBool
AppendableAdapter::reserveAppendCapacity(int32_t /*appendCapacity*/) {
Appendable::reserveAppendCapacity(int32_t /*appendCapacity*/) {
return TRUE;
}
UChar *
AppendableAdapter::getAppendBuffer(int32_t minCapacity,
int32_t /*desiredCapacityHint*/,
UChar *scratch, int32_t scratchCapacity,
int32_t *resultCapacity) {
Appendable::getAppendBuffer(int32_t minCapacity,
int32_t /*desiredCapacityHint*/,
UChar *scratch, int32_t scratchCapacity,
int32_t *resultCapacity) {
if(minCapacity<1 || scratchCapacity<minCapacity) {
*resultCapacity=0;
return NULL;
@ -66,6 +64,8 @@ AppendableAdapter::getAppendBuffer(int32_t minCapacity,
return scratch;
}
UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(AppendableAdapter)
UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(Appendable)
// UnicodeStringAppendable is implemented in unistr.cpp.
U_NAMESPACE_END

View file

@ -17,7 +17,7 @@
/**
* \file
* \brief C++ API: Appendable interface: Sink for Unicode code points and 16-bit code units (UChars).
* \brief C++ API: Appendable class: Sink for Unicode code points and 16-bit code units (UChars).
*/
#include "unicode/utypes.h"
@ -25,18 +25,18 @@
U_NAMESPACE_BEGIN
class UnicodeString;
/**
* Interface/mixin class for objects to which Unicode characters and strings can be appended.
* Base 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
* This class 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.
* Implementation classes must implement at least appendCodeUnit(UChar).
* The base class provides default implementations for the other methods.
*
* The methods do not take UErrorCode parameters.
* If an error occurs (e.g., out-of-memory),
@ -46,14 +46,8 @@ U_NAMESPACE_BEGIN
* (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 */ {
class U_COMMON_API Appendable : public UObject {
public:
/**
* Destructor.
* @draft ICU 4.8
*/
virtual ~Appendable();
/**
* Appends a 16-bit code unit.
* @param c code unit
@ -62,89 +56,6 @@ public:
*/
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.
@ -183,7 +94,28 @@ public:
* The returned buffer is only valid until the next operation
* on this Appendable.
*
* For details see Appendable::getAppendBuffer().
* 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().
*
* The default implementation always returns the scratch buffer.
*
@ -208,6 +140,85 @@ private:
virtual UClassID getDynamicClassID() const;
};
/**
* An Appendable implementation which writes to a UnicodeString.
*
* This class is not intended for public subclassing.
* @draft ICU 4.8
*/
class U_COMMON_API UnicodeStringAppendable : public Appendable {
public:
/**
* Aliases the UnicodeString (keeps its reference) for writing.
* @param s The UnicodeString to which this Appendable will write.
* @draft ICU 4.8
*/
explicit UnicodeStringAppendable(UnicodeString &s) : str(s) {}
/**
* Appends a 16-bit code unit to the string.
* @param c code unit
* @return TRUE if the operation succeeded
* @draft ICU 4.8
*/
virtual UBool appendCodeUnit(UChar c);
/**
* Appends a code point to the string.
* @param c code point 0..0x10ffff
* @return TRUE if the operation succeeded
* @draft ICU 4.8
*/
virtual UBool appendCodePoint(UChar32 c);
/**
* Appends a string to the UnicodeString.
* @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 UnicodeString that the caller is going to append roughly
* appendCapacity UChars.
* @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 write operation
* on the UnicodeString.
*
* 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);
private:
UnicodeString &str;
};
U_NAMESPACE_END
#endif // __APPENDABLE_H__

View file

@ -27,7 +27,6 @@
*/
#include "unicode/utypes.h"
#include "unicode/appendable.h"
#include "unicode/rep.h"
#include "unicode/std_string.h"
#include "unicode/stringpiece.h"
@ -56,9 +55,10 @@ u_strlen(const UChar *s);
U_NAMESPACE_BEGIN
class BreakIterator; // unicode/brkiter.h
class Locale; // unicode/locid.h
class StringCharacterIterator;
class BreakIterator; // unicode/brkiter.h
class UnicodeStringAppendable; // unicode/appendable.h
/* The <iostream> include has been moved to unicode/ustream.h */
@ -185,7 +185,7 @@ class BreakIterator; // unicode/brkiter.h
* @see CharacterIterator
* @stable ICU 2.0
*/
class U_COMMON_API UnicodeString : public Replaceable, public Appendable
class U_COMMON_API UnicodeString : public Replaceable
{
public:
@ -2072,46 +2072,6 @@ 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 */
@ -2823,43 +2783,6 @@ 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
//========================================
@ -3472,6 +3395,7 @@ private:
};
friend class StringThreadTest;
friend class UnicodeStringAppendable;
union StackBufferOrFields; // forward declaration necessary before friend declaration
friend union StackBufferOrFields; // make US_STACKBUF_SIZE visible inside fUnion

View file

@ -19,6 +19,7 @@
*/
#include "unicode/utypes.h"
#include "unicode/appendable.h"
#include "unicode/putil.h"
#include "cstring.h"
#include "cmemory.h"
@ -1342,28 +1343,6 @@ 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
*/
@ -1545,25 +1524,6 @@ 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
//========================================
@ -1668,10 +1628,48 @@ UnicodeString::cloneArrayIfNeeded(int32_t newCapacity,
return TRUE;
}
// Implements Appendable.
// UnicodeStringAppendable ------------------------------------------------- ***
UBool
UnicodeString::reserveAppendCapacity(int32_t appendCapacity) {
return cloneArrayIfNeeded(length() + appendCapacity);
UnicodeStringAppendable::appendCodeUnit(UChar c) {
return str.doReplace(str.length(), 0, &c, 0, 1).isWritable();
}
UBool
UnicodeStringAppendable::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 && str.doReplace(str.length(), 0, buffer, 0, cLength).isWritable();
}
UBool
UnicodeStringAppendable::appendString(const UChar *s, int32_t length) {
return str.doReplace(str.length(), 0, s, 0, length).isWritable();
}
UBool
UnicodeStringAppendable::reserveAppendCapacity(int32_t appendCapacity) {
return str.cloneArrayIfNeeded(str.length() + appendCapacity);
}
UChar *
UnicodeStringAppendable::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 = str.length();
if(str.cloneArrayIfNeeded(oldLength + minCapacity, oldLength + desiredCapacityHint)) {
*resultCapacity = str.getCapacity() - oldLength;
return str.getArrayStart() + oldLength;
}
*resultCapacity = scratchCapacity;
return scratch;
}
U_NAMESPACE_END

View file

@ -15,6 +15,7 @@
#include <string.h>
#include "unicode/utypes.h"
#include "unicode/appendable.h"
#include "unicode/localpointer.h"
#include "unicode/uniset.h"
#include "unicode/unistr.h"
@ -501,7 +502,8 @@ void UCharsTrieTest::TestGetNextUChars() {
return; // buildTrie() reported an error
}
UnicodeString buffer;
int32_t count=trie->getNextUChars(buffer);
UnicodeStringAppendable app(buffer);
int32_t count=trie->getNextUChars(app);
if(count!=2 || buffer.length()!=2 || buffer[0]!=u_a || buffer[1]!=u_j) {
errln("months getNextUChars()!=[aj] at root");
}
@ -509,31 +511,36 @@ void UCharsTrieTest::TestGetNextUChars() {
trie->next(u_a);
trie->next(u_n);
// getNextUChars() directly after next()
count=trie->getNextUChars(buffer.remove());
buffer.remove();
count=trie->getNextUChars(app);
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(buffer.remove());
buffer.remove();
count=trie->getNextUChars(app);
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(buffer.remove());
buffer.remove();
count=trie->getNextUChars(app);
if(count!=1 || buffer.length()!=1 || buffer[0]!=u_a) {
errln("months getNextUChars()!=[a] after \"janu\"");
}
trie->next(u_a);
count=trie->getNextUChars(buffer.remove());
buffer.remove();
count=trie->getNextUChars(app);
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(buffer.remove());
buffer.remove();
count=trie->getNextUChars(app);
if(count!=0 || buffer.length()!=0) {
errln("months getNextUChars()!=[] after \"january\"");
}

View file

@ -312,8 +312,8 @@ public:
};
#endif
// AppendableAdapter is abstract; we define a subclass to verify that there is no "poor man's RTTI".
class DummyAppendable : public AppendableAdapter {
// Appendable is abstract; we define a subclass to verify that there is no "poor man's RTTI".
class DummyAppendable : public Appendable {
public:
virtual UBool appendCodeUnit(UChar /*c*/) { return TRUE; }
};

View file

@ -2053,11 +2053,11 @@ UnicodeStringTest::doTestAppendable(UnicodeString &dest, Appendable &app) {
}
}
class UnicodeStringAppendable : public AppendableAdapter {
class SimpleAppendable : public Appendable {
public:
UnicodeStringAppendable(UnicodeString &dest) : str(dest) {}
explicit SimpleAppendable(UnicodeString &dest) : str(dest) {}
virtual UBool appendCodeUnit(UChar c) { str.append(c); return TRUE; }
UnicodeStringAppendable &reset() { str.remove(); return *this; }
SimpleAppendable &reset() { str.remove(); return *this; }
private:
UnicodeString &str;
};
@ -2065,12 +2065,13 @@ private:
void
UnicodeStringTest::TestAppendable() {
UnicodeString dest;
UnicodeStringAppendable app(dest);
SimpleAppendable app(dest);
doTestAppendable(dest, app);
}
void
UnicodeStringTest::TestUnicodeStringImplementsAppendable() {
UnicodeString dest;
doTestAppendable(dest, dest);
UnicodeStringAppendable app(dest);
doTestAppendable(dest, app);
}