diff --git a/icu4c/source/common/unicode/strenum.h b/icu4c/source/common/unicode/strenum.h index a166c1aaa9b..4817835d6fc 100644 --- a/icu4c/source/common/unicode/strenum.h +++ b/icu4c/source/common/unicode/strenum.h @@ -10,26 +10,148 @@ #ifndef STRENUM_H #define STRENUM_H -#include "uobject.h" +#include "unicode/utypes.h" U_NAMESPACE_BEGIN class UnicodeString; /** - * Base class for 'pure' C++ implementations. Adds method that - * returns the next UnicodeString since in C++ this might be a - * common storage model for strings. + *
Base class for 'pure' C++ implementations of uenum api. Adds a + * method that returns the next UnicodeString since in C++ this can + * be a common storage format for strings.
+ * + *The model is that the enumeration is over strings maintained by + * a 'service.' At any point, the service might change, invalidating + * the enumerator (though this is expected to be rare). The iterator + * returns an error if this has occurred. Lack of the error is no + * guarantee that the service didn't change immediately after the + * call, so the returned string still might not be 'valid' on + * subsequent use.
+ * + *Strings may take the form of const char*, const UChar*, or const + * UnicodeString*. The type you get is determine by the variant of + * 'next' that you call. In general the StringEnumeration is + * optimized for one of these types, but all StringEnumerations can + * return all types. Returned strings are each terminated with a NUL. + * Depending on the service data, they might also include embedded NUL + * characters, so API is provided to optionally return the true + * length, counting the embedded NULs but not counting the terminating + * NUL.
+ * + *The pointers returned by next, unext, and snext become invalid + * upon any subsequent call to the enumeration's destructor, next, + * unext, snext, or reset.
+ * + * @draft ICU 2.4 */ -class U_COMMON_API StringEnumeration : public UMemory { +class U_COMMON_API StringEnumeration { /* not : public UObject because this is an interface/mixin class */ public: + /** + * Destructor. + * @draft ICU 2.4 + */ virtual ~StringEnumeration(); + + /** + *Return the number of elements that the iterator traverses. If + * the iterator is out of sync with its service, status is set to + * U_ENUM_OUT_OF_SYNC_ERROR, and the return value is zero.
+ * + *The return value will not change except possibly as a result of + * a subsequent call to reset, or if the iterator becomes out of sync.
+ * + *This is a convenience function. It can end up being very + * expensive as all the items might have to be pre-fetched + * (depending on the storage format of the data being + * traversed).
+ * + * @param status the error code. + * @return number of elements in the iterator. + * + * @draft ICU 2.4 */ virtual int32_t count(UErrorCode& status) const = 0; - virtual const char* next(UErrorCode& status) = 0; - virtual const UChar* unext(UErrorCode& status) = 0; + /** + *Returns the next element as a NUL-terminated char*. If there + * are no more elements, returns NULL. If the resultLength pointer + * is not NULL, the length of the string (not counting the + * terminating NUL) is returned at that address. If an error + * status is returned, the value at resultLength is undefined.
+ * + *The returned pointer is owned by this iterator and must not be + * deleted by the caller. The pointer is valid until the next call + * to next, unext, snext, reset, or the enumerator's destructor.
+ * + *If the iterator is out of sync with its service, status is set + * to U_ENUM_OUT_OF_SYNC_ERROR and NULL is returned.
+ * + *If the native service string is a UChar* string, it is + * converted to char* with the invariant converter. If the + * conversion fails (because a character cannot be converted) then + * status is set to U_INVARIANT_CONVERSION_ERROR and the return + * value is undefined (though not NULL).
+ * + * @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; + + /** + *Returns the next element as a NUL-terminated UChar*. If there + * are no more elements, returns NULL. If the resultLength pointer + * is not NULL, the length of the string (not counting the + * terminating NUL) is returned at that address. If an error + * status is returned, the value at resultLength is undefined.
+ * + *The returned pointer is owned by this iterator and must not be + * deleted by the caller. The pointer is valid until the next call + * to next, unext, snext, reset, or the enumerator's destructor.
+ * + *If the iterator is out of sync with its service, status is set + * to U_ENUM_OUT_OF_SYNC_ERROR and NULL is returned.
+ * + * @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; + + /** + *Returns the next element a UnicodeString*. If there are no + * more elements, returns NULL.
+ * + *The returned pointer is owned by this iterator and must not be + * deleted by the caller. The pointer is valid until the next call + * to next, unext, snext, reset, or the enumerator's destructor.
+ * + *If the iterator is out of sync with its service, status is set + * to U_ENUM_OUT_OF_SYNC_ERROR and NULL is returned.
+ * + * @param status the error code. + * @return a pointer to the string, or NULL. + * + * @draft ICU 2.4 + */ virtual const UnicodeString* snext(UErrorCode& status) = 0; + /** + *Resets the iterator. This re-establishes sync with the + * service and rewinds the iterator to start at the first + * element.
+ * + *Previous pointers returned by next, unext, or snext become + * invalid, and the value returned by count might change.
+ * + * @param status the error code. + * + * @draft ICU 2.4 + */ virtual void reset(UErrorCode& status) = 0; }; diff --git a/icu4c/source/common/ustrenum.cpp b/icu4c/source/common/ustrenum.cpp index 9b25c6751d0..2fe2ef1aa5d 100644 --- a/icu4c/source/common/ustrenum.cpp +++ b/icu4c/source/common/ustrenum.cpp @@ -46,9 +46,7 @@ ustrenum_unext(UEnumeration* en, int32_t* resultLength, UErrorCode* ec) { - const UChar* result = THIS(en)->unext(*ec); - *resultLength = (result != NULL) ? u_strlen(result) : 0; - return result; + return THIS(en)->unext(resultLength, *ec); } /** @@ -59,9 +57,7 @@ ustrenum_next(UEnumeration* en, int32_t* resultLength, UErrorCode* ec) { - const char* result = THIS(en)->next(*ec); - *resultLength = (result != NULL) ? uprv_strlen(result) : 0; - return result; + return THIS(en)->next(resultLength, *ec); } /** diff --git a/icu4c/source/i18n/timezone.cpp b/icu4c/source/i18n/timezone.cpp index 8272c862034..a5f650bf4cb 100644 --- a/icu4c/source/i18n/timezone.cpp +++ b/icu4c/source/i18n/timezone.cpp @@ -608,7 +608,7 @@ public: return U_FAILURE(status) ? 0 : len; } - const char* next(UErrorCode& status) { + const char* next(int32_t* resultLength, UErrorCode& status) { const UnicodeString* us = snext(status); if (us) { int newlen; @@ -620,16 +620,25 @@ public: } if (U_SUCCESS(status)) { ((char*)_bufp)[newlen] = 0; + if (resultLength) { + resultLength[0] = newlen; + } return (const char*)_bufp; } } return NULL; } - const UChar* unext(UErrorCode& status) { + const UChar* unext(int32_t* resultLength, UErrorCode& status) { const UnicodeString* us = snext(status); - // TimeZone terminates the ID strings when it builds them - return (us == NULL) ? NULL : us->getBuffer(); + if (us != NULL) { + if (resultLength) { + resultLength[0] = us->length(); + } + // TimeZone terminates the ID strings when it builds them + return us->getBuffer(); + } + return NULL; } const UnicodeString* snext(UErrorCode& status) {