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
14U_NAMESPACE_BEGIN
15
16typedef enum SimplePatternFormatterCompileState {
17    INIT,
18    APOSTROPHE,
19    PLACEHOLDER
20} SimplePatternFormatterCompileState;
21
22class SimplePatternFormatterIdBuilder {
23public:
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);
31private:
32    int32_t id;
33    int32_t idLen;
34    SimplePatternFormatterIdBuilder(
35            const SimplePatternFormatterIdBuilder &other);
36    SimplePatternFormatterIdBuilder &operator=(
37            const SimplePatternFormatterIdBuilder &other);
38};
39
40void 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
52void SimplePatternFormatterIdBuilder::add(UChar ch) {
53    id = id * 10 + (ch - 0x30);
54    idLen++;
55}
56
57SimplePatternFormatter::SimplePatternFormatter() :
58        noPlaceholders(),
59        placeholdersByOffset(placeholderBuffer),
60        placeholderSize(0),
61        placeholderCapacity(EXPECTED_PLACEHOLDER_COUNT),
62        placeholderCount(0) {
63}
64
65SimplePatternFormatter::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
75SimplePatternFormatter::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
89SimplePatternFormatter &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
104SimplePatternFormatter::~SimplePatternFormatter() {
105    if (placeholdersByOffset != placeholderBuffer) {
106        uprv_free(placeholdersByOffset);
107    }
108}
109
110UBool 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
186UnicodeString& 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
200UnicodeString& 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
215UnicodeString& 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
231static 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
241static 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
249UnicodeString& 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
302int32_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
329UBool 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
342U_NAMESPACE_END
343