diff --git a/icu4c/source/common/locid.cpp b/icu4c/source/common/locid.cpp index b069f5446b9..f19b5d7e9f4 100644 --- a/icu4c/source/common/locid.cpp +++ b/icu4c/source/common/locid.cpp @@ -1176,30 +1176,7 @@ public: const UnicodeString* snext(UErrorCode& status) { int32_t resultLength = 0; - const char* starter = next(&resultLength, status); - if(starter != NULL) { - UChar *buffer = currUSKey.getBuffer(resultLength+1); - if(buffer != NULL) { - u_charsToUChars(starter, buffer, resultLength); - buffer[resultLength] = 0; - currUSKey.releaseBuffer(resultLength); - return &currUSKey; - } else { - status = U_MEMORY_ALLOCATION_ERROR; - } - } - return NULL; - } - - const UChar* unext(int32_t* resultLength, UErrorCode& status) { - if(snext(status) != NULL) { - if(resultLength != NULL) { - *resultLength = currUSKey.length(); - } - return currUSKey.getTerminatedBuffer(); - } else { - return NULL; - } + return setChars(next(&resultLength, status), resultLength, status); } void reset(UErrorCode& /*status*/) { diff --git a/icu4c/source/common/unicode/strenum.h b/icu4c/source/common/unicode/strenum.h index f09d870719a..aee7c81f3f7 100644 --- a/icu4c/source/common/unicode/strenum.h +++ b/icu4c/source/common/unicode/strenum.h @@ -11,11 +11,10 @@ #define STRENUM_H #include "unicode/uobject.h" +#include "unicode/unistr.h" U_NAMESPACE_BEGIN -class UnicodeString; - /** * Base class for 'pure' C++ implementations of uenum api. Adds a * method that returns the next UnicodeString since in C++ this can @@ -43,6 +42,9 @@ class UnicodeString; * upon any subsequent call to the enumeration's destructor, next, * unext, snext, or reset.

* + * ICU 2.8 adds some default implementations and helper functions + * for subclasses. + * * @draft ICU 2.4 */ class U_COMMON_API StringEnumeration : public UObject { @@ -109,13 +111,16 @@ public: * status is set to U_INVARIANT_CONVERSION_ERROR and the return * value is undefined (though not NULL).

* + * Starting with ICU 2.8, the default implementation calls snext() + * and handles the conversion. + * * @param status the error code. * @param resultLength a pointer to receive the length, can be NULL. * @return a pointer to the string, or NULL. * * @draft ICU 2.4 */ - virtual const char* next(int32_t *resultLength, UErrorCode& status) = 0; + virtual const char* next(int32_t *resultLength, UErrorCode& status); /** *

Returns the next element as a NUL-terminated UChar*. If there @@ -131,13 +136,16 @@ public: *

If the iterator is out of sync with its service, status is set * to U_ENUM_OUT_OF_SYNC_ERROR and NULL is returned.

* + * Starting with ICU 2.8, the default implementation calls snext() + * and handles the conversion. + * * @param status the error code. * @param resultLength a ponter to receive the length, can be NULL. * @return a pointer to the string, or NULL. * * @draft ICU 2.4 */ - virtual const UChar* unext(int32_t *resultLength, UErrorCode& status) = 0; + virtual const UChar* unext(int32_t *resultLength, UErrorCode& status); /** *

Returns the next element a UnicodeString*. If there are no @@ -170,6 +178,68 @@ public: * @draft ICU 2.4 */ virtual void reset(UErrorCode& status) = 0; + +protected: + /** + * UnicodeString field for use with default implementations and subclasses. + * @draft ICU 2.8 + */ + UnicodeString unistr; + /** + * char * default buffer for use with default implementations and subclasses. + * @draft ICU 2.8 + */ + char charsBuffer[32]; + /** + * char * buffer for use with default implementations and subclasses. + * Allocated in constructor and in ensureCharsCapacity(). + * @draft ICU 2.8 + */ + char *chars; + /** + * Capacity of chars, for use with default implementations and subclasses. + * @draft ICU 2.8 + */ + int32_t charsCapacity; + + /** + * Default constructor for use with default implementations and subclasses. + * @draft ICU 2.8 + */ + StringEnumeration(); + + /** + * Ensures that chars is at least as large as the requested capacity. + * For use with default implementations and subclasses. + * + * @param capacity Requested capacity. + * @param status ICU in/out error code. + * @draft ICU 2.8 + */ + void ensureCharsCapacity(int32_t capacity, UErrorCode &status); + + /** + * Converts s to Unicode and sets unistr to the result. + * For use with default implementations and subclasses, + * especially for implementations of snext() in terms of next(). + * This is provided with a helper function instead of a default implementation + * of snext() to avoid potential infinite loops between next() and snext(). + * + * For example: + * \code + * const UnicodeString* snext(UErrorCode& status) { + * int32_t resultLength=0; + * return setChars(next(&resultLength, status), resultLength, status); + * } + * \endcode + * + * @param s String to be converted to Unicode. + * @param length Length of the string. + * @param status ICU in/out error code. + * @return A pointer to unistr. + * @draft ICU 2.8 + */ + UnicodeString *setChars(const char *s, int32_t length, UErrorCode &status); }; U_NAMESPACE_END diff --git a/icu4c/source/common/ustrenum.cpp b/icu4c/source/common/ustrenum.cpp index e6ff62fef4e..169aa8d0d17 100644 --- a/icu4c/source/common/ustrenum.cpp +++ b/icu4c/source/common/ustrenum.cpp @@ -15,7 +15,11 @@ #include "cstring.h" #include "cmemory.h" -#define THIS(en) ((StringEnumeration*)(en->context)) +// StringEnumeration implementation ---------------------------------------- *** + +StringEnumeration::StringEnumeration() + : chars(charsBuffer), charsCapacity(sizeof(charsBuffer)) { +} StringEnumeration::~StringEnumeration() {} @@ -25,6 +29,86 @@ StringEnumeration::clone() const { return NULL; } +const char * +StringEnumeration::next(int32_t *resultLength, UErrorCode &status) { + const UnicodeString *s=snext(status); + if(s!=NULL) { + unistr=*s; + ensureCharsCapacity(unistr.length()+1, status); + if(U_SUCCESS(status)) { + if(resultLength!=NULL) { + *resultLength=unistr.length(); + } + unistr.extract(0, INT32_MAX, chars, charsCapacity, ""); + return chars; + } + } + + return NULL; +} + +const UChar * +StringEnumeration::unext(int32_t *resultLength, UErrorCode &status) { + const UnicodeString *s=snext(status); + if(s!=NULL) { + unistr=*s; + if(U_SUCCESS(status)) { + if(resultLength!=NULL) { + *resultLength=unistr.length(); + } + return unistr.getTerminatedBuffer(); + } + } + + return NULL; +} + +void +StringEnumeration::ensureCharsCapacity(int32_t capacity, UErrorCode &status) { + if(U_SUCCESS(status) && capacity>charsCapacity) { + if(capacity<(charsCapacity+charsCapacity/2)) { + // avoid allocation thrashing + capacity=charsCapacity+charsCapacity/2; + } + if(chars!=charsBuffer) { + uprv_free(chars); + } + chars=(char *)uprv_malloc(capacity); + if(chars==NULL) { + chars=charsBuffer; + charsCapacity=sizeof(charsBuffer); + status=U_MEMORY_ALLOCATION_ERROR; + } else { + charsCapacity=capacity; + } + } +} + +UnicodeString * +StringEnumeration::setChars(const char *s, int32_t length, UErrorCode &status) { + if(U_SUCCESS(status) && s!=NULL) { + if(length<0) { + length=uprv_strlen(s); + } + + UChar *buffer=unistr.getBuffer(length+1); + if(buffer!=NULL) { + u_charsToUChars(s, buffer, length); + buffer[length]=0; + unistr.releaseBuffer(length); + return &unistr; + } else { + status=U_MEMORY_ALLOCATION_ERROR; + } + } + + return NULL; +} + +// C wrapper --------------------------------------------------------------- *** + +#define THIS(en) ((StringEnumeration*)(en->context)) + U_CDECL_BEGIN /**