]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/simplepatternformatter.cpp
ICU-531.30.tar.gz
[apple/icu.git] / icuSources / common / simplepatternformatter.cpp
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:
24 SimplePatternFormatterIdBuilder() : id(0), idLen(0) { }
25 ~SimplePatternFormatterIdBuilder() { }
26 void reset() { id = 0; idLen = 0; }
27 int32_t getId() const { return id; }
28 void appendTo(UChar *buffer, int32_t *len) const;
29 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
40 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
52 void SimplePatternFormatterIdBuilder::add(UChar ch) {
53 id = id * 10 + (ch - 0x30);
54 idLen++;
55 }
56
57 SimplePatternFormatter::SimplePatternFormatter() :
58 noPlaceholders(),
59 placeholdersByOffset(placeholderBuffer),
60 placeholderSize(0),
61 placeholderCapacity(EXPECTED_PLACEHOLDER_COUNT),
62 placeholderCount(0) {
63 }
64
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
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
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
104 SimplePatternFormatter::~SimplePatternFormatter() {
105 if (placeholdersByOffset != placeholderBuffer) {
106 uprv_free(placeholdersByOffset);
107 }
108 }
109
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
186 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
200 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
215 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
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
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
249 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
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
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