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