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