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