• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ******************************************************************************
3 * Copyright (C) 2014, International Business Machines
4 * Corporation and others.  All Rights Reserved.
5 ******************************************************************************
6 * simplepatternformatter.cpp
7 */
8 #include "simplepatternformatter.h"
9 #include "cstring.h"
10 #include "uassert.h"
11 
12 #define LENGTHOF(array) (int32_t)(sizeof(array) / sizeof((array)[0]))
13 
14 U_NAMESPACE_BEGIN
15 
16 typedef enum SimplePatternFormatterCompileState {
17     INIT,
18     APOSTROPHE,
19     PLACEHOLDER
20 } SimplePatternFormatterCompileState;
21 
22 class SimplePatternFormatterIdBuilder {
23 public:
SimplePatternFormatterIdBuilder()24     SimplePatternFormatterIdBuilder() : id(0), idLen(0) { }
~SimplePatternFormatterIdBuilder()25     ~SimplePatternFormatterIdBuilder() { }
reset()26     void reset() { id = 0; idLen = 0; }
getId() const27     int32_t getId() const { return id; }
28     void appendTo(UChar *buffer, int32_t *len) const;
isValid() const29     UBool isValid() const { return (idLen > 0); }
30     void add(UChar ch);
31 private:
32     int32_t id;
33     int32_t idLen;
34     SimplePatternFormatterIdBuilder(
35             const SimplePatternFormatterIdBuilder &other);
36     SimplePatternFormatterIdBuilder &operator=(
37             const SimplePatternFormatterIdBuilder &other);
38 };
39 
appendTo(UChar * buffer,int32_t * len) const40 void SimplePatternFormatterIdBuilder::appendTo(
41         UChar *buffer, int32_t *len) const {
42     int32_t origLen = *len;
43     int32_t kId = id;
44     for (int32_t i = origLen + idLen - 1; i >= origLen; i--) {
45         int32_t digit = kId % 10;
46         buffer[i] = digit + 0x30;
47         kId /= 10;
48     }
49     *len = origLen + idLen;
50 }
51 
add(UChar ch)52 void SimplePatternFormatterIdBuilder::add(UChar ch) {
53     id = id * 10 + (ch - 0x30);
54     idLen++;
55 }
56 
SimplePatternFormatter()57 SimplePatternFormatter::SimplePatternFormatter() :
58         noPlaceholders(),
59         placeholdersByOffset(placeholderBuffer),
60         placeholderSize(0),
61         placeholderCapacity(EXPECTED_PLACEHOLDER_COUNT),
62         placeholderCount(0) {
63 }
64 
SimplePatternFormatter(const UnicodeString & pattern)65 SimplePatternFormatter::SimplePatternFormatter(const UnicodeString &pattern) :
66         noPlaceholders(),
67         placeholdersByOffset(placeholderBuffer),
68         placeholderSize(0),
69         placeholderCapacity(EXPECTED_PLACEHOLDER_COUNT),
70         placeholderCount(0) {
71     UErrorCode status = U_ZERO_ERROR;
72     compile(pattern, status);
73 }
74 
SimplePatternFormatter(const SimplePatternFormatter & other)75 SimplePatternFormatter::SimplePatternFormatter(
76         const SimplePatternFormatter &other) :
77         noPlaceholders(other.noPlaceholders),
78         placeholdersByOffset(placeholderBuffer),
79         placeholderSize(0),
80         placeholderCapacity(EXPECTED_PLACEHOLDER_COUNT),
81         placeholderCount(other.placeholderCount) {
82     placeholderSize = ensureCapacity(other.placeholderSize);
83     uprv_memcpy(
84             placeholdersByOffset,
85             other.placeholdersByOffset,
86             placeholderSize * 2 * sizeof(int32_t));
87 }
88 
operator =(const SimplePatternFormatter & other)89 SimplePatternFormatter &SimplePatternFormatter::operator=(
90         const SimplePatternFormatter& other) {
91     if (this == &other) {
92         return *this;
93     }
94     noPlaceholders = other.noPlaceholders;
95     placeholderCount = other.placeholderCount;
96     placeholderSize = ensureCapacity(other.placeholderSize);
97     uprv_memcpy(
98             placeholdersByOffset,
99             other.placeholdersByOffset,
100             placeholderSize * 2 * sizeof(int32_t));
101     return *this;
102 }
103 
~SimplePatternFormatter()104 SimplePatternFormatter::~SimplePatternFormatter() {
105     if (placeholdersByOffset != placeholderBuffer) {
106         uprv_free(placeholdersByOffset);
107     }
108 }
109 
compile(const UnicodeString & pattern,UErrorCode & status)110 UBool SimplePatternFormatter::compile(
111         const UnicodeString &pattern, UErrorCode &status) {
112     if (U_FAILURE(status)) {
113         return FALSE;
114     }
115     const UChar *patternBuffer = pattern.getBuffer();
116     int32_t patternLength = pattern.length();
117     UChar *buffer = noPlaceholders.getBuffer(patternLength);
118     int32_t len = 0;
119     placeholderSize = 0;
120     placeholderCount = 0;
121     SimplePatternFormatterCompileState state = INIT;
122     SimplePatternFormatterIdBuilder idBuilder;
123     for (int32_t i = 0; i < patternLength; ++i) {
124         UChar ch = patternBuffer[i];
125         switch (state) {
126         case INIT:
127             if (ch == 0x27) {
128                 state = APOSTROPHE;
129             } else if (ch == 0x7B) {
130                 state = PLACEHOLDER;
131                 idBuilder.reset();
132             } else {
133                buffer[len++] = ch;
134             }
135             break;
136         case APOSTROPHE:
137             if (ch == 0x27) {
138                 buffer[len++] = 0x27;
139             } else if (ch == 0x7B) {
140                 buffer[len++] = 0x7B;
141             } else {
142                 buffer[len++] = 0x27;
143                 buffer[len++] = ch;
144             }
145             state = INIT;
146             break;
147         case PLACEHOLDER:
148             if (ch >= 0x30 && ch <= 0x39) {
149                 idBuilder.add(ch);
150             } else if (ch == 0x7D && idBuilder.isValid()) {
151                 if (!addPlaceholder(idBuilder.getId(), len)) {
152                     status = U_MEMORY_ALLOCATION_ERROR;
153                     return FALSE;
154                 }
155                 state = INIT;
156             } else {
157                 buffer[len++] = 0x7B;
158                 idBuilder.appendTo(buffer, &len);
159                 buffer[len++] = ch;
160                 state = INIT;
161             }
162             break;
163         default:
164             U_ASSERT(FALSE);
165             break;
166         }
167     }
168     switch (state) {
169     case INIT:
170         break;
171     case APOSTROPHE:
172         buffer[len++] = 0x27;
173         break;
174     case PLACEHOLDER:
175         buffer[len++] = 0X7B;
176         idBuilder.appendTo(buffer, &len);
177         break;
178     default:
179         U_ASSERT(false);
180         break;
181     }
182     noPlaceholders.releaseBuffer(len);
183     return TRUE;
184 }
185 
format(const UnicodeString & arg0,UnicodeString & appendTo,UErrorCode & status) const186 UnicodeString& SimplePatternFormatter::format(
187         const UnicodeString &arg0,
188         UnicodeString &appendTo,
189         UErrorCode &status) const {
190     const UnicodeString *params[] = {&arg0};
191     return format(
192             params,
193             LENGTHOF(params),
194             appendTo,
195             NULL,
196             0,
197             status);
198 }
199 
format(const UnicodeString & arg0,const UnicodeString & arg1,UnicodeString & appendTo,UErrorCode & status) const200 UnicodeString& SimplePatternFormatter::format(
201         const UnicodeString &arg0,
202         const UnicodeString &arg1,
203         UnicodeString &appendTo,
204         UErrorCode &status) const {
205     const UnicodeString *params[] = {&arg0, &arg1};
206     return format(
207             params,
208             LENGTHOF(params),
209             appendTo,
210             NULL,
211             0,
212             status);
213 }
214 
format(const UnicodeString & arg0,const UnicodeString & arg1,const UnicodeString & arg2,UnicodeString & appendTo,UErrorCode & status) const215 UnicodeString& SimplePatternFormatter::format(
216         const UnicodeString &arg0,
217         const UnicodeString &arg1,
218         const UnicodeString &arg2,
219         UnicodeString &appendTo,
220         UErrorCode &status) const {
221     const UnicodeString *params[] = {&arg0, &arg1, &arg2};
222     return format(
223             params,
224             LENGTHOF(params),
225             appendTo,
226             NULL,
227             0,
228             status);
229 }
230 
updatePlaceholderOffset(int32_t placeholderId,int32_t placeholderOffset,int32_t * offsetArray,int32_t offsetArrayLength)231 static void updatePlaceholderOffset(
232         int32_t placeholderId,
233         int32_t placeholderOffset,
234         int32_t *offsetArray,
235         int32_t offsetArrayLength) {
236     if (placeholderId < offsetArrayLength) {
237         offsetArray[placeholderId] = placeholderOffset;
238     }
239 }
240 
appendRange(const UnicodeString & src,int32_t start,int32_t end,UnicodeString & dest)241 static void appendRange(
242         const UnicodeString &src,
243         int32_t start,
244         int32_t end,
245         UnicodeString &dest) {
246     dest.append(src, start, end - start);
247 }
248 
format(const UnicodeString * const * placeholderValues,int32_t placeholderValueCount,UnicodeString & appendTo,int32_t * offsetArray,int32_t offsetArrayLength,UErrorCode & status) const249 UnicodeString& SimplePatternFormatter::format(
250         const UnicodeString * const *placeholderValues,
251         int32_t placeholderValueCount,
252         UnicodeString &appendTo,
253         int32_t *offsetArray,
254         int32_t offsetArrayLength,
255         UErrorCode &status) const {
256     if (U_FAILURE(status)) {
257         return appendTo;
258     }
259     if (placeholderValueCount < placeholderCount) {
260         status = U_ILLEGAL_ARGUMENT_ERROR;
261         return appendTo;
262     }
263     for (int32_t i = 0; i < offsetArrayLength; ++i) {
264         offsetArray[i] = -1;
265     }
266     if (placeholderSize == 0) {
267         appendTo.append(noPlaceholders);
268         return appendTo;
269     }
270     appendRange(
271             noPlaceholders,
272             0,
273             placeholdersByOffset[0],
274             appendTo);
275     updatePlaceholderOffset(
276             placeholdersByOffset[1],
277             appendTo.length(),
278             offsetArray,
279             offsetArrayLength);
280     appendTo.append(*placeholderValues[placeholdersByOffset[1]]);
281     for (int32_t i = 1; i < placeholderSize; ++i) {
282         appendRange(
283                 noPlaceholders,
284                 placeholdersByOffset[2 * i - 2],
285                 placeholdersByOffset[2 * i],
286                 appendTo);
287         updatePlaceholderOffset(
288                 placeholdersByOffset[2 * i + 1],
289                 appendTo.length(),
290                 offsetArray,
291                 offsetArrayLength);
292         appendTo.append(*placeholderValues[placeholdersByOffset[2 * i + 1]]);
293     }
294     appendRange(
295             noPlaceholders,
296             placeholdersByOffset[2 * placeholderSize - 2],
297             noPlaceholders.length(),
298             appendTo);
299     return appendTo;
300 }
301 
ensureCapacity(int32_t atLeast)302 int32_t SimplePatternFormatter::ensureCapacity(int32_t atLeast) {
303     if (atLeast <= placeholderCapacity) {
304         return atLeast;
305     }
306     // aim to double capacity each time
307     int32_t newCapacity = 2*atLeast - 2;
308 
309     // allocate new buffer
310     int32_t *newBuffer = (int32_t *) uprv_malloc(2 * newCapacity * sizeof(int32_t));
311     if (newBuffer == NULL) {
312         return placeholderCapacity;
313     }
314 
315     // Copy contents of old buffer to new buffer
316     uprv_memcpy(newBuffer, placeholdersByOffset, 2 * placeholderSize * sizeof(int32_t));
317 
318     // free old buffer
319     if (placeholdersByOffset != placeholderBuffer) {
320         uprv_free(placeholdersByOffset);
321     }
322 
323     // Use new buffer
324     placeholdersByOffset = newBuffer;
325     placeholderCapacity = newCapacity;
326     return atLeast;
327 }
328 
addPlaceholder(int32_t id,int32_t offset)329 UBool SimplePatternFormatter::addPlaceholder(int32_t id, int32_t offset) {
330     if (ensureCapacity(placeholderSize + 1) < placeholderSize + 1) {
331         return FALSE;
332     }
333     ++placeholderSize;
334     placeholdersByOffset[2 * placeholderSize - 2] = offset;
335     placeholdersByOffset[2 * placeholderSize - 1] = id;
336     if (id >= placeholderCount) {
337         placeholderCount = id + 1;
338     }
339     return TRUE;
340 }
341 
342 U_NAMESPACE_END
343