Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
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 |