Line data Source code
1 : // © 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 0 : StringEnumeration::StringEnumeration()
28 0 : : chars(charsBuffer), charsCapacity(sizeof(charsBuffer)) {
29 0 : }
30 :
31 0 : StringEnumeration::~StringEnumeration() {
32 0 : if (chars != NULL && chars != charsBuffer) {
33 0 : uprv_free(chars);
34 : }
35 0 : }
36 :
37 : // StringEnumeration base class clone() default implementation, does not clone
38 : StringEnumeration *
39 0 : StringEnumeration::clone() const {
40 0 : return NULL;
41 : }
42 :
43 : const char *
44 0 : StringEnumeration::next(int32_t *resultLength, UErrorCode &status) {
45 0 : const UnicodeString *s=snext(status);
46 0 : if(U_SUCCESS(status) && s!=NULL) {
47 0 : unistr=*s;
48 0 : ensureCharsCapacity(unistr.length()+1, status);
49 0 : if(U_SUCCESS(status)) {
50 0 : if(resultLength!=NULL) {
51 0 : *resultLength=unistr.length();
52 : }
53 0 : unistr.extract(0, INT32_MAX, chars, charsCapacity, US_INV);
54 0 : return chars;
55 : }
56 : }
57 :
58 0 : return NULL;
59 : }
60 :
61 : const UChar *
62 0 : StringEnumeration::unext(int32_t *resultLength, UErrorCode &status) {
63 0 : const UnicodeString *s=snext(status);
64 0 : if(U_SUCCESS(status) && s!=NULL) {
65 0 : unistr=*s;
66 0 : if(resultLength!=NULL) {
67 0 : *resultLength=unistr.length();
68 : }
69 0 : return unistr.getTerminatedBuffer();
70 : }
71 :
72 0 : return NULL;
73 : }
74 :
75 : const UnicodeString *
76 0 : StringEnumeration::snext(UErrorCode &status) {
77 : int32_t length;
78 0 : const char *s=next(&length, status);
79 0 : return setChars(s, length, status);
80 : }
81 :
82 : void
83 0 : StringEnumeration::ensureCharsCapacity(int32_t capacity, UErrorCode &status) {
84 0 : if(U_SUCCESS(status) && capacity>charsCapacity) {
85 0 : if(capacity<(charsCapacity+charsCapacity/2)) {
86 : // avoid allocation thrashing
87 0 : capacity=charsCapacity+charsCapacity/2;
88 : }
89 0 : if(chars!=charsBuffer) {
90 0 : uprv_free(chars);
91 : }
92 0 : chars=(char *)uprv_malloc(capacity);
93 0 : if(chars==NULL) {
94 0 : chars=charsBuffer;
95 0 : charsCapacity=sizeof(charsBuffer);
96 0 : status=U_MEMORY_ALLOCATION_ERROR;
97 : } else {
98 0 : charsCapacity=capacity;
99 : }
100 : }
101 0 : }
102 :
103 : UnicodeString *
104 0 : StringEnumeration::setChars(const char *s, int32_t length, UErrorCode &status) {
105 0 : if(U_SUCCESS(status) && s!=NULL) {
106 0 : if(length<0) {
107 0 : length=(int32_t)uprv_strlen(s);
108 : }
109 :
110 0 : UChar *buffer=unistr.getBuffer(length+1);
111 0 : if(buffer!=NULL) {
112 0 : u_charsToUChars(s, buffer, length);
113 0 : buffer[length]=0;
114 0 : unistr.releaseBuffer(length);
115 0 : return &unistr;
116 : } else {
117 0 : status=U_MEMORY_ALLOCATION_ERROR;
118 : }
119 : }
120 :
121 0 : return NULL;
122 : }
123 : UBool
124 0 : StringEnumeration::operator==(const StringEnumeration& that)const {
125 0 : return typeid(*this) == typeid(that);
126 : }
127 :
128 : UBool
129 0 : StringEnumeration::operator!=(const StringEnumeration& that)const {
130 0 : return !operator==(that);
131 : }
132 :
133 : // UStringEnumeration implementation --------------------------------------- ***
134 :
135 : UStringEnumeration * U_EXPORT2
136 0 : UStringEnumeration::fromUEnumeration(
137 : UEnumeration *uenumToAdopt, UErrorCode &status) {
138 0 : if (U_FAILURE(status)) {
139 0 : uenum_close(uenumToAdopt);
140 0 : return NULL;
141 : }
142 0 : UStringEnumeration *result = new UStringEnumeration(uenumToAdopt);
143 0 : if (result == NULL) {
144 0 : status = U_MEMORY_ALLOCATION_ERROR;
145 0 : uenum_close(uenumToAdopt);
146 0 : return NULL;
147 : }
148 0 : return result;
149 : }
150 :
151 0 : UStringEnumeration::UStringEnumeration(UEnumeration* _uenum) :
152 0 : uenum(_uenum) {
153 0 : U_ASSERT(_uenum != 0);
154 0 : }
155 :
156 0 : UStringEnumeration::~UStringEnumeration() {
157 0 : uenum_close(uenum);
158 0 : }
159 :
160 0 : int32_t UStringEnumeration::count(UErrorCode& status) const {
161 0 : return uenum_count(uenum, &status);
162 : }
163 :
164 0 : const char *UStringEnumeration::next(int32_t *resultLength, UErrorCode &status) {
165 0 : return uenum_next(uenum, resultLength, &status);
166 : }
167 :
168 0 : const UnicodeString* UStringEnumeration::snext(UErrorCode& status) {
169 : int32_t length;
170 0 : const UChar* str = uenum_unext(uenum, &length, &status);
171 0 : if (str == 0 || U_FAILURE(status)) {
172 0 : return 0;
173 : }
174 0 : return &unistr.setTo(str, length);
175 : }
176 :
177 0 : void UStringEnumeration::reset(UErrorCode& status) {
178 0 : uenum_reset(uenum, &status);
179 0 : }
180 :
181 0 : 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 0 : ustrenum_close(UEnumeration* en) {
195 0 : delete THIS(en);
196 0 : uprv_free(en);
197 0 : }
198 :
199 : /**
200 : * Wrapper API to make StringEnumeration look like UEnumeration.
201 : */
202 : static int32_t U_CALLCONV
203 0 : ustrenum_count(UEnumeration* en,
204 : UErrorCode* ec)
205 : {
206 0 : 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 0 : ustrenum_unext(UEnumeration* en,
214 : int32_t* resultLength,
215 : UErrorCode* ec)
216 : {
217 0 : 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 0 : ustrenum_next(UEnumeration* en,
225 : int32_t* resultLength,
226 : UErrorCode* ec)
227 : {
228 0 : 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 0 : ustrenum_reset(UEnumeration* en,
236 : UErrorCode* ec)
237 : {
238 0 : THIS(en)->reset(*ec);
239 0 : }
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 0 : uenum_openFromStringEnumeration(icu::StringEnumeration* adopted, UErrorCode* ec) {
264 0 : UEnumeration* result = NULL;
265 0 : if (U_SUCCESS(*ec) && adopted != NULL) {
266 0 : result = (UEnumeration*) uprv_malloc(sizeof(UEnumeration));
267 0 : if (result == NULL) {
268 0 : *ec = U_MEMORY_ALLOCATION_ERROR;
269 : } else {
270 0 : uprv_memcpy(result, &USTRENUM_VT, sizeof(USTRENUM_VT));
271 0 : result->context = adopted;
272 : }
273 : }
274 0 : if (result == NULL) {
275 0 : delete adopted;
276 : }
277 0 : 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 0 : ucharstrenum_close(UEnumeration* en) {
291 0 : uprv_free(en);
292 0 : }
293 :
294 : static int32_t U_CALLCONV
295 0 : ucharstrenum_count(UEnumeration* en,
296 : UErrorCode* /*ec*/) {
297 0 : return ((UCharStringEnumeration*)en)->count;
298 : }
299 :
300 : static const UChar* U_CALLCONV
301 0 : ucharstrenum_unext(UEnumeration* en,
302 : int32_t* resultLength,
303 : UErrorCode* /*ec*/) {
304 0 : UCharStringEnumeration *e = (UCharStringEnumeration*) en;
305 0 : if (e->index >= e->count) {
306 0 : return NULL;
307 : }
308 0 : const UChar* result = ((const UChar**)e->uenum.context)[e->index++];
309 0 : if (resultLength) {
310 0 : *resultLength = (int32_t)u_strlen(result);
311 : }
312 0 : return result;
313 : }
314 :
315 :
316 : static const char* U_CALLCONV
317 0 : ucharstrenum_next(UEnumeration* en,
318 : int32_t* resultLength,
319 : UErrorCode* /*ec*/) {
320 0 : UCharStringEnumeration *e = (UCharStringEnumeration*) en;
321 0 : if (e->index >= e->count) {
322 0 : return NULL;
323 : }
324 0 : const char* result = ((const char**)e->uenum.context)[e->index++];
325 0 : if (resultLength) {
326 0 : *resultLength = (int32_t)uprv_strlen(result);
327 : }
328 0 : return result;
329 : }
330 :
331 : static void U_CALLCONV
332 0 : ucharstrenum_reset(UEnumeration* en,
333 : UErrorCode* /*ec*/) {
334 0 : ((UCharStringEnumeration*)en)->index = 0;
335 0 : }
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 0 : uenum_openCharStringsEnumeration(const char* const strings[], int32_t count,
361 : UErrorCode* ec) {
362 0 : UCharStringEnumeration* result = NULL;
363 0 : if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) {
364 0 : result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration));
365 0 : if (result == NULL) {
366 0 : *ec = U_MEMORY_ALLOCATION_ERROR;
367 : } else {
368 : U_ASSERT((char*)result==(char*)(&result->uenum));
369 0 : uprv_memcpy(result, &UCHARSTRENUM_VT, sizeof(UCHARSTRENUM_VT));
370 0 : result->uenum.context = (void*)strings;
371 0 : result->index = 0;
372 0 : result->count = count;
373 : }
374 : }
375 0 : return (UEnumeration*) result;
376 : }
377 :
378 : U_CAPI UEnumeration* U_EXPORT2
379 0 : uenum_openUCharStringsEnumeration(const UChar* const strings[], int32_t count,
380 : UErrorCode* ec) {
381 0 : UCharStringEnumeration* result = NULL;
382 0 : if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) {
383 0 : result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration));
384 0 : if (result == NULL) {
385 0 : *ec = U_MEMORY_ALLOCATION_ERROR;
386 : } else {
387 : U_ASSERT((char*)result==(char*)(&result->uenum));
388 0 : uprv_memcpy(result, &UCHARSTRENUM_U_VT, sizeof(UCHARSTRENUM_U_VT));
389 0 : result->uenum.context = (void*)strings;
390 0 : result->index = 0;
391 0 : result->count = count;
392 : }
393 : }
394 0 : return (UEnumeration*) result;
395 : }
396 :
397 :
398 : // end C Wrapper
|