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