intl/icu/source/common/ustrenum.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*
michael@0 2 **********************************************************************
michael@0 3 * Copyright (c) 2002-2012, International Business Machines
michael@0 4 * Corporation and others. All Rights Reserved.
michael@0 5 **********************************************************************
michael@0 6 * Author: Alan Liu
michael@0 7 * Created: November 11 2002
michael@0 8 * Since: ICU 2.4
michael@0 9 **********************************************************************
michael@0 10 */
michael@0 11 #include "utypeinfo.h" // for 'typeid' to work
michael@0 12
michael@0 13 #include "unicode/ustring.h"
michael@0 14 #include "unicode/strenum.h"
michael@0 15 #include "unicode/putil.h"
michael@0 16 #include "uenumimp.h"
michael@0 17 #include "ustrenum.h"
michael@0 18 #include "cstring.h"
michael@0 19 #include "cmemory.h"
michael@0 20 #include "uassert.h"
michael@0 21
michael@0 22 U_NAMESPACE_BEGIN
michael@0 23 // StringEnumeration implementation ---------------------------------------- ***
michael@0 24
michael@0 25 StringEnumeration::StringEnumeration()
michael@0 26 : chars(charsBuffer), charsCapacity(sizeof(charsBuffer)) {
michael@0 27 }
michael@0 28
michael@0 29 StringEnumeration::~StringEnumeration() {
michael@0 30 if (chars != NULL && chars != charsBuffer) {
michael@0 31 uprv_free(chars);
michael@0 32 }
michael@0 33 }
michael@0 34
michael@0 35 // StringEnumeration base class clone() default implementation, does not clone
michael@0 36 StringEnumeration *
michael@0 37 StringEnumeration::clone() const {
michael@0 38 return NULL;
michael@0 39 }
michael@0 40
michael@0 41 const char *
michael@0 42 StringEnumeration::next(int32_t *resultLength, UErrorCode &status) {
michael@0 43 const UnicodeString *s=snext(status);
michael@0 44 if(U_SUCCESS(status) && s!=NULL) {
michael@0 45 unistr=*s;
michael@0 46 ensureCharsCapacity(unistr.length()+1, status);
michael@0 47 if(U_SUCCESS(status)) {
michael@0 48 if(resultLength!=NULL) {
michael@0 49 *resultLength=unistr.length();
michael@0 50 }
michael@0 51 unistr.extract(0, INT32_MAX, chars, charsCapacity, US_INV);
michael@0 52 return chars;
michael@0 53 }
michael@0 54 }
michael@0 55
michael@0 56 return NULL;
michael@0 57 }
michael@0 58
michael@0 59 const UChar *
michael@0 60 StringEnumeration::unext(int32_t *resultLength, UErrorCode &status) {
michael@0 61 const UnicodeString *s=snext(status);
michael@0 62 if(U_SUCCESS(status) && s!=NULL) {
michael@0 63 unistr=*s;
michael@0 64 if(resultLength!=NULL) {
michael@0 65 *resultLength=unistr.length();
michael@0 66 }
michael@0 67 return unistr.getTerminatedBuffer();
michael@0 68 }
michael@0 69
michael@0 70 return NULL;
michael@0 71 }
michael@0 72
michael@0 73 const UnicodeString *
michael@0 74 StringEnumeration::snext(UErrorCode &status) {
michael@0 75 int32_t length;
michael@0 76 const char *s=next(&length, status);
michael@0 77 return setChars(s, length, status);
michael@0 78 }
michael@0 79
michael@0 80 void
michael@0 81 StringEnumeration::ensureCharsCapacity(int32_t capacity, UErrorCode &status) {
michael@0 82 if(U_SUCCESS(status) && capacity>charsCapacity) {
michael@0 83 if(capacity<(charsCapacity+charsCapacity/2)) {
michael@0 84 // avoid allocation thrashing
michael@0 85 capacity=charsCapacity+charsCapacity/2;
michael@0 86 }
michael@0 87 if(chars!=charsBuffer) {
michael@0 88 uprv_free(chars);
michael@0 89 }
michael@0 90 chars=(char *)uprv_malloc(capacity);
michael@0 91 if(chars==NULL) {
michael@0 92 chars=charsBuffer;
michael@0 93 charsCapacity=sizeof(charsBuffer);
michael@0 94 status=U_MEMORY_ALLOCATION_ERROR;
michael@0 95 } else {
michael@0 96 charsCapacity=capacity;
michael@0 97 }
michael@0 98 }
michael@0 99 }
michael@0 100
michael@0 101 UnicodeString *
michael@0 102 StringEnumeration::setChars(const char *s, int32_t length, UErrorCode &status) {
michael@0 103 if(U_SUCCESS(status) && s!=NULL) {
michael@0 104 if(length<0) {
michael@0 105 length=(int32_t)uprv_strlen(s);
michael@0 106 }
michael@0 107
michael@0 108 UChar *buffer=unistr.getBuffer(length+1);
michael@0 109 if(buffer!=NULL) {
michael@0 110 u_charsToUChars(s, buffer, length);
michael@0 111 buffer[length]=0;
michael@0 112 unistr.releaseBuffer(length);
michael@0 113 return &unistr;
michael@0 114 } else {
michael@0 115 status=U_MEMORY_ALLOCATION_ERROR;
michael@0 116 }
michael@0 117 }
michael@0 118
michael@0 119 return NULL;
michael@0 120 }
michael@0 121 UBool
michael@0 122 StringEnumeration::operator==(const StringEnumeration& that)const {
michael@0 123 return typeid(*this) == typeid(that);
michael@0 124 }
michael@0 125
michael@0 126 UBool
michael@0 127 StringEnumeration::operator!=(const StringEnumeration& that)const {
michael@0 128 return !operator==(that);
michael@0 129 }
michael@0 130
michael@0 131 // UStringEnumeration implementation --------------------------------------- ***
michael@0 132
michael@0 133 UStringEnumeration::UStringEnumeration(UEnumeration* _uenum) :
michael@0 134 uenum(_uenum) {
michael@0 135 U_ASSERT(_uenum != 0);
michael@0 136 }
michael@0 137
michael@0 138 UStringEnumeration::~UStringEnumeration() {
michael@0 139 uenum_close(uenum);
michael@0 140 }
michael@0 141
michael@0 142 int32_t UStringEnumeration::count(UErrorCode& status) const {
michael@0 143 return uenum_count(uenum, &status);
michael@0 144 }
michael@0 145
michael@0 146 const char *UStringEnumeration::next(int32_t *resultLength, UErrorCode &status) {
michael@0 147 return uenum_next(uenum, resultLength, &status);
michael@0 148 }
michael@0 149
michael@0 150 const UnicodeString* UStringEnumeration::snext(UErrorCode& status) {
michael@0 151 int32_t length;
michael@0 152 const UChar* str = uenum_unext(uenum, &length, &status);
michael@0 153 if (str == 0 || U_FAILURE(status)) {
michael@0 154 return 0;
michael@0 155 }
michael@0 156 return &unistr.setTo(str, length);
michael@0 157 }
michael@0 158
michael@0 159 void UStringEnumeration::reset(UErrorCode& status) {
michael@0 160 uenum_reset(uenum, &status);
michael@0 161 }
michael@0 162
michael@0 163 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration)
michael@0 164 U_NAMESPACE_END
michael@0 165
michael@0 166 // C wrapper --------------------------------------------------------------- ***
michael@0 167
michael@0 168 #define THIS(en) ((icu::StringEnumeration*)(en->context))
michael@0 169
michael@0 170 U_CDECL_BEGIN
michael@0 171
michael@0 172 /**
michael@0 173 * Wrapper API to make StringEnumeration look like UEnumeration.
michael@0 174 */
michael@0 175 static void U_CALLCONV
michael@0 176 ustrenum_close(UEnumeration* en) {
michael@0 177 delete THIS(en);
michael@0 178 uprv_free(en);
michael@0 179 }
michael@0 180
michael@0 181 /**
michael@0 182 * Wrapper API to make StringEnumeration look like UEnumeration.
michael@0 183 */
michael@0 184 static int32_t U_CALLCONV
michael@0 185 ustrenum_count(UEnumeration* en,
michael@0 186 UErrorCode* ec)
michael@0 187 {
michael@0 188 return THIS(en)->count(*ec);
michael@0 189 }
michael@0 190
michael@0 191 /**
michael@0 192 * Wrapper API to make StringEnumeration look like UEnumeration.
michael@0 193 */
michael@0 194 static const UChar* U_CALLCONV
michael@0 195 ustrenum_unext(UEnumeration* en,
michael@0 196 int32_t* resultLength,
michael@0 197 UErrorCode* ec)
michael@0 198 {
michael@0 199 return THIS(en)->unext(resultLength, *ec);
michael@0 200 }
michael@0 201
michael@0 202 /**
michael@0 203 * Wrapper API to make StringEnumeration look like UEnumeration.
michael@0 204 */
michael@0 205 static const char* U_CALLCONV
michael@0 206 ustrenum_next(UEnumeration* en,
michael@0 207 int32_t* resultLength,
michael@0 208 UErrorCode* ec)
michael@0 209 {
michael@0 210 return THIS(en)->next(resultLength, *ec);
michael@0 211 }
michael@0 212
michael@0 213 /**
michael@0 214 * Wrapper API to make StringEnumeration look like UEnumeration.
michael@0 215 */
michael@0 216 static void U_CALLCONV
michael@0 217 ustrenum_reset(UEnumeration* en,
michael@0 218 UErrorCode* ec)
michael@0 219 {
michael@0 220 THIS(en)->reset(*ec);
michael@0 221 }
michael@0 222
michael@0 223 /**
michael@0 224 * Pseudo-vtable for UEnumeration wrapper around StringEnumeration.
michael@0 225 * The StringEnumeration pointer will be stored in 'context'.
michael@0 226 */
michael@0 227 static const UEnumeration USTRENUM_VT = {
michael@0 228 NULL,
michael@0 229 NULL, // store StringEnumeration pointer here
michael@0 230 ustrenum_close,
michael@0 231 ustrenum_count,
michael@0 232 ustrenum_unext,
michael@0 233 ustrenum_next,
michael@0 234 ustrenum_reset
michael@0 235 };
michael@0 236
michael@0 237 U_CDECL_END
michael@0 238
michael@0 239 /**
michael@0 240 * Given a StringEnumeration, wrap it in a UEnumeration. The
michael@0 241 * StringEnumeration is adopted; after this call, the caller must not
michael@0 242 * delete it (regardless of error status).
michael@0 243 */
michael@0 244 U_CAPI UEnumeration* U_EXPORT2
michael@0 245 uenum_openFromStringEnumeration(icu::StringEnumeration* adopted, UErrorCode* ec) {
michael@0 246 UEnumeration* result = NULL;
michael@0 247 if (U_SUCCESS(*ec) && adopted != NULL) {
michael@0 248 result = (UEnumeration*) uprv_malloc(sizeof(UEnumeration));
michael@0 249 if (result == NULL) {
michael@0 250 *ec = U_MEMORY_ALLOCATION_ERROR;
michael@0 251 } else {
michael@0 252 uprv_memcpy(result, &USTRENUM_VT, sizeof(USTRENUM_VT));
michael@0 253 result->context = adopted;
michael@0 254 }
michael@0 255 }
michael@0 256 if (result == NULL) {
michael@0 257 delete adopted;
michael@0 258 }
michael@0 259 return result;
michael@0 260 }
michael@0 261
michael@0 262 // C wrapper --------------------------------------------------------------- ***
michael@0 263
michael@0 264 U_CDECL_BEGIN
michael@0 265
michael@0 266 typedef struct UCharStringEnumeration {
michael@0 267 UEnumeration uenum;
michael@0 268 int32_t index, count;
michael@0 269 } UCharStringEnumeration;
michael@0 270
michael@0 271 static void U_CALLCONV
michael@0 272 ucharstrenum_close(UEnumeration* en) {
michael@0 273 uprv_free(en);
michael@0 274 }
michael@0 275
michael@0 276 static int32_t U_CALLCONV
michael@0 277 ucharstrenum_count(UEnumeration* en,
michael@0 278 UErrorCode* /*ec*/) {
michael@0 279 return ((UCharStringEnumeration*)en)->count;
michael@0 280 }
michael@0 281
michael@0 282 static const UChar* U_CALLCONV
michael@0 283 ucharstrenum_unext(UEnumeration* en,
michael@0 284 int32_t* resultLength,
michael@0 285 UErrorCode* /*ec*/) {
michael@0 286 UCharStringEnumeration *e = (UCharStringEnumeration*) en;
michael@0 287 if (e->index >= e->count) {
michael@0 288 return NULL;
michael@0 289 }
michael@0 290 const UChar* result = ((const UChar**)e->uenum.context)[e->index++];
michael@0 291 if (resultLength) {
michael@0 292 *resultLength = (int32_t)u_strlen(result);
michael@0 293 }
michael@0 294 return result;
michael@0 295 }
michael@0 296
michael@0 297
michael@0 298 static const char* U_CALLCONV
michael@0 299 ucharstrenum_next(UEnumeration* en,
michael@0 300 int32_t* resultLength,
michael@0 301 UErrorCode* /*ec*/) {
michael@0 302 UCharStringEnumeration *e = (UCharStringEnumeration*) en;
michael@0 303 if (e->index >= e->count) {
michael@0 304 return NULL;
michael@0 305 }
michael@0 306 const char* result = ((const char**)e->uenum.context)[e->index++];
michael@0 307 if (resultLength) {
michael@0 308 *resultLength = (int32_t)uprv_strlen(result);
michael@0 309 }
michael@0 310 return result;
michael@0 311 }
michael@0 312
michael@0 313 static void U_CALLCONV
michael@0 314 ucharstrenum_reset(UEnumeration* en,
michael@0 315 UErrorCode* /*ec*/) {
michael@0 316 ((UCharStringEnumeration*)en)->index = 0;
michael@0 317 }
michael@0 318
michael@0 319 static const UEnumeration UCHARSTRENUM_VT = {
michael@0 320 NULL,
michael@0 321 NULL, // store StringEnumeration pointer here
michael@0 322 ucharstrenum_close,
michael@0 323 ucharstrenum_count,
michael@0 324 uenum_unextDefault,
michael@0 325 ucharstrenum_next,
michael@0 326 ucharstrenum_reset
michael@0 327 };
michael@0 328
michael@0 329 static const UEnumeration UCHARSTRENUM_U_VT = {
michael@0 330 NULL,
michael@0 331 NULL, // store StringEnumeration pointer here
michael@0 332 ucharstrenum_close,
michael@0 333 ucharstrenum_count,
michael@0 334 ucharstrenum_unext,
michael@0 335 uenum_nextDefault,
michael@0 336 ucharstrenum_reset
michael@0 337 };
michael@0 338
michael@0 339 U_CDECL_END
michael@0 340
michael@0 341 U_CAPI UEnumeration* U_EXPORT2
michael@0 342 uenum_openCharStringsEnumeration(const char* const strings[], int32_t count,
michael@0 343 UErrorCode* ec) {
michael@0 344 UCharStringEnumeration* result = NULL;
michael@0 345 if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) {
michael@0 346 result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration));
michael@0 347 if (result == NULL) {
michael@0 348 *ec = U_MEMORY_ALLOCATION_ERROR;
michael@0 349 } else {
michael@0 350 U_ASSERT((char*)result==(char*)(&result->uenum));
michael@0 351 uprv_memcpy(result, &UCHARSTRENUM_VT, sizeof(UCHARSTRENUM_VT));
michael@0 352 result->uenum.context = (void*)strings;
michael@0 353 result->index = 0;
michael@0 354 result->count = count;
michael@0 355 }
michael@0 356 }
michael@0 357 return (UEnumeration*) result;
michael@0 358 }
michael@0 359
michael@0 360 U_CAPI UEnumeration* U_EXPORT2
michael@0 361 uenum_openUCharStringsEnumeration(const UChar* const strings[], int32_t count,
michael@0 362 UErrorCode* ec) {
michael@0 363 UCharStringEnumeration* result = NULL;
michael@0 364 if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) {
michael@0 365 result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration));
michael@0 366 if (result == NULL) {
michael@0 367 *ec = U_MEMORY_ALLOCATION_ERROR;
michael@0 368 } else {
michael@0 369 U_ASSERT((char*)result==(char*)(&result->uenum));
michael@0 370 uprv_memcpy(result, &UCHARSTRENUM_U_VT, sizeof(UCHARSTRENUM_U_VT));
michael@0 371 result->uenum.context = (void*)strings;
michael@0 372 result->index = 0;
michael@0 373 result->count = count;
michael@0 374 }
michael@0 375 }
michael@0 376 return (UEnumeration*) result;
michael@0 377 }
michael@0 378
michael@0 379
michael@0 380 // end C Wrapper

mercurial