Imported Upstream version 58.1
[platform/upstream/icu.git] / source / common / ustrenum.cpp
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
24 U_NAMESPACE_BEGIN
25 // StringEnumeration implementation ---------------------------------------- ***
26
27 StringEnumeration::StringEnumeration()
28     : chars(charsBuffer), charsCapacity(sizeof(charsBuffer)) {
29 }
30
31 StringEnumeration::~StringEnumeration() {
32     if (chars != NULL && chars != charsBuffer) {
33         uprv_free(chars);
34     }
35 }
36
37 // StringEnumeration base class clone() default implementation, does not clone
38 StringEnumeration *
39 StringEnumeration::clone() const {
40   return NULL;
41 }
42
43 const char *
44 StringEnumeration::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
61 const UChar *
62 StringEnumeration::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
75 const UnicodeString *
76 StringEnumeration::snext(UErrorCode &status) {
77     int32_t length;
78     const char *s=next(&length, status);
79     return setChars(s, length, status);
80 }
81
82 void
83 StringEnumeration::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
103 UnicodeString *
104 StringEnumeration::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 }
123 UBool 
124 StringEnumeration::operator==(const StringEnumeration& that)const {
125     return typeid(*this) == typeid(that); 
126 }
127
128 UBool
129 StringEnumeration::operator!=(const StringEnumeration& that)const {
130     return !operator==(that);
131 }
132
133 // UStringEnumeration implementation --------------------------------------- ***
134
135 UStringEnumeration * U_EXPORT2
136 UStringEnumeration::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
151 UStringEnumeration::UStringEnumeration(UEnumeration* _uenum) :
152     uenum(_uenum) {
153     U_ASSERT(_uenum != 0);
154 }
155
156 UStringEnumeration::~UStringEnumeration() {
157     uenum_close(uenum);
158 }
159
160 int32_t UStringEnumeration::count(UErrorCode& status) const {
161     return uenum_count(uenum, &status);
162 }
163
164 const char *UStringEnumeration::next(int32_t *resultLength, UErrorCode &status) {
165     return uenum_next(uenum, resultLength, &status);
166 }
167
168 const 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
177 void UStringEnumeration::reset(UErrorCode& status) {
178     uenum_reset(uenum, &status);
179 }
180
181 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration)
182 U_NAMESPACE_END
183
184 // C wrapper --------------------------------------------------------------- ***
185
186 #define THIS(en) ((icu::StringEnumeration*)(en->context))
187
188 U_CDECL_BEGIN
189
190 /**
191  * Wrapper API to make StringEnumeration look like UEnumeration.
192  */
193 static void U_CALLCONV
194 ustrenum_close(UEnumeration* en) {
195     delete THIS(en);
196     uprv_free(en);
197 }
198
199 /**
200  * Wrapper API to make StringEnumeration look like UEnumeration.
201  */
202 static int32_t U_CALLCONV
203 ustrenum_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  */
212 static const UChar* U_CALLCONV
213 ustrenum_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  */
223 static const char* U_CALLCONV
224 ustrenum_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  */
234 static void U_CALLCONV
235 ustrenum_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  */
245 static 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
255 U_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  */
262 U_CAPI UEnumeration* U_EXPORT2
263 uenum_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
282 U_CDECL_BEGIN
283
284 typedef struct UCharStringEnumeration {
285     UEnumeration uenum;
286     int32_t index, count;
287 } UCharStringEnumeration;
288
289 static void U_CALLCONV
290 ucharstrenum_close(UEnumeration* en) {
291     uprv_free(en);
292 }
293
294 static int32_t U_CALLCONV
295 ucharstrenum_count(UEnumeration* en,
296                    UErrorCode* /*ec*/) {
297     return ((UCharStringEnumeration*)en)->count;
298 }
299
300 static const UChar* U_CALLCONV
301 ucharstrenum_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
316 static const char* U_CALLCONV
317 ucharstrenum_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
331 static void U_CALLCONV
332 ucharstrenum_reset(UEnumeration* en,
333                    UErrorCode* /*ec*/) {
334     ((UCharStringEnumeration*)en)->index = 0;
335 }
336
337 static 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
347 static 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
357 U_CDECL_END
358
359 U_CAPI UEnumeration* U_EXPORT2
360 uenum_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
378 U_CAPI UEnumeration* U_EXPORT2
379 uenum_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