From e7251a2b04674aba4ff7c81cb09bbc886d10eb45 Mon Sep 17 00:00:00 2001
From: Markus Scherer
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 /**