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