Index: source/common/simplepatternformatter.cpp |
diff --git a/source/common/simplepatternformatter.cpp b/source/common/simplepatternformatter.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..30390f4150c013824df7235647f39f7f75c8ea8f |
--- /dev/null |
+++ b/source/common/simplepatternformatter.cpp |
@@ -0,0 +1,339 @@ |
+/* |
+****************************************************************************** |
+* Copyright (C) 2014, International Business Machines |
+* Corporation and others. All Rights Reserved. |
+****************************************************************************** |
+* simplepatternformatter.cpp |
+*/ |
+#include "simplepatternformatter.h" |
+#include "cstring.h" |
+#include "uassert.h" |
+ |
+U_NAMESPACE_BEGIN |
+ |
+typedef enum SimplePatternFormatterCompileState { |
+ INIT, |
+ APOSTROPHE, |
+ PLACEHOLDER |
+} SimplePatternFormatterCompileState; |
+ |
+class SimplePatternFormatterIdBuilder { |
+public: |
+ SimplePatternFormatterIdBuilder() : id(0), idLen(0) { } |
+ ~SimplePatternFormatterIdBuilder() { } |
+ void reset() { id = 0; idLen = 0; } |
+ int32_t getId() const { return id; } |
+ void appendTo(UChar *buffer, int32_t *len) const; |
+ UBool isValid() const { return (idLen > 0); } |
+ void add(UChar ch); |
+private: |
+ int32_t id; |
+ int32_t idLen; |
+ SimplePatternFormatterIdBuilder( |
+ const SimplePatternFormatterIdBuilder &other); |
+ SimplePatternFormatterIdBuilder &operator=( |
+ const SimplePatternFormatterIdBuilder &other); |
+}; |
+ |
+void SimplePatternFormatterIdBuilder::appendTo( |
+ UChar *buffer, int32_t *len) const { |
+ int32_t origLen = *len; |
+ int32_t kId = id; |
+ for (int32_t i = origLen + idLen - 1; i >= origLen; i--) { |
+ int32_t digit = kId % 10; |
+ buffer[i] = digit + 0x30; |
+ kId /= 10; |
+ } |
+ *len = origLen + idLen; |
+} |
+ |
+void SimplePatternFormatterIdBuilder::add(UChar ch) { |
+ id = id * 10 + (ch - 0x30); |
+ idLen++; |
+} |
+ |
+SimplePatternFormatter::SimplePatternFormatter() : |
+ noPlaceholders(), |
+ placeholders(), |
+ placeholderSize(0), |
+ placeholderCount(0) { |
+} |
+ |
+SimplePatternFormatter::SimplePatternFormatter(const UnicodeString &pattern) : |
+ noPlaceholders(), |
+ placeholders(), |
+ placeholderSize(0), |
+ placeholderCount(0) { |
+ UErrorCode status = U_ZERO_ERROR; |
+ compile(pattern, status); |
+} |
+ |
+SimplePatternFormatter::SimplePatternFormatter( |
+ const SimplePatternFormatter &other) : |
+ noPlaceholders(other.noPlaceholders), |
+ placeholders(), |
+ placeholderSize(0), |
+ placeholderCount(other.placeholderCount) { |
+ placeholderSize = ensureCapacity(other.placeholderSize); |
+ uprv_memcpy( |
+ placeholders.getAlias(), |
+ other.placeholders.getAlias(), |
+ placeholderSize * sizeof(PlaceholderInfo)); |
+} |
+ |
+SimplePatternFormatter &SimplePatternFormatter::operator=( |
+ const SimplePatternFormatter& other) { |
+ if (this == &other) { |
+ return *this; |
+ } |
+ noPlaceholders = other.noPlaceholders; |
+ placeholderSize = ensureCapacity(other.placeholderSize); |
+ placeholderCount = other.placeholderCount; |
+ uprv_memcpy( |
+ placeholders.getAlias(), |
+ other.placeholders.getAlias(), |
+ placeholderSize * sizeof(PlaceholderInfo)); |
+ return *this; |
+} |
+ |
+SimplePatternFormatter::~SimplePatternFormatter() { |
+} |
+ |
+UBool SimplePatternFormatter::compile( |
+ const UnicodeString &pattern, UErrorCode &status) { |
+ if (U_FAILURE(status)) { |
+ return FALSE; |
+ } |
+ const UChar *patternBuffer = pattern.getBuffer(); |
+ int32_t patternLength = pattern.length(); |
+ UChar *buffer = noPlaceholders.getBuffer(patternLength); |
+ int32_t len = 0; |
+ placeholderSize = 0; |
+ placeholderCount = 0; |
+ SimplePatternFormatterCompileState state = INIT; |
+ SimplePatternFormatterIdBuilder idBuilder; |
+ for (int32_t i = 0; i < patternLength; ++i) { |
+ UChar ch = patternBuffer[i]; |
+ switch (state) { |
+ case INIT: |
+ if (ch == 0x27) { |
+ state = APOSTROPHE; |
+ } else if (ch == 0x7B) { |
+ state = PLACEHOLDER; |
+ idBuilder.reset(); |
+ } else { |
+ buffer[len++] = ch; |
+ } |
+ break; |
+ case APOSTROPHE: |
+ if (ch == 0x27) { |
+ buffer[len++] = 0x27; |
+ } else if (ch == 0x7B) { |
+ buffer[len++] = 0x7B; |
+ } else { |
+ buffer[len++] = 0x27; |
+ buffer[len++] = ch; |
+ } |
+ state = INIT; |
+ break; |
+ case PLACEHOLDER: |
+ if (ch >= 0x30 && ch <= 0x39) { |
+ idBuilder.add(ch); |
+ } else if (ch == 0x7D && idBuilder.isValid()) { |
+ if (!addPlaceholder(idBuilder.getId(), len)) { |
+ status = U_MEMORY_ALLOCATION_ERROR; |
+ return FALSE; |
+ } |
+ state = INIT; |
+ } else { |
+ buffer[len++] = 0x7B; |
+ idBuilder.appendTo(buffer, &len); |
+ buffer[len++] = ch; |
+ state = INIT; |
+ } |
+ break; |
+ default: |
+ U_ASSERT(FALSE); |
+ break; |
+ } |
+ } |
+ switch (state) { |
+ case INIT: |
+ break; |
+ case APOSTROPHE: |
+ buffer[len++] = 0x27; |
+ break; |
+ case PLACEHOLDER: |
+ buffer[len++] = 0X7B; |
+ idBuilder.appendTo(buffer, &len); |
+ break; |
+ default: |
+ U_ASSERT(false); |
+ break; |
+ } |
+ noPlaceholders.releaseBuffer(len); |
+ return TRUE; |
+} |
+ |
+UBool SimplePatternFormatter::startsWithPlaceholder(int32_t id) const { |
+ if (placeholderSize == 0) { |
+ return FALSE; |
+ } |
+ return (placeholders[0].offset == 0 && placeholders[0].id == id); |
+} |
+ |
+UnicodeString& SimplePatternFormatter::format( |
+ const UnicodeString &arg0, |
+ UnicodeString &appendTo, |
+ UErrorCode &status) const { |
+ const UnicodeString *params[] = {&arg0}; |
+ return format( |
+ params, |
+ UPRV_LENGTHOF(params), |
+ appendTo, |
+ NULL, |
+ 0, |
+ status); |
+} |
+ |
+UnicodeString& SimplePatternFormatter::format( |
+ const UnicodeString &arg0, |
+ const UnicodeString &arg1, |
+ UnicodeString &appendTo, |
+ UErrorCode &status) const { |
+ const UnicodeString *params[] = {&arg0, &arg1}; |
+ return format( |
+ params, |
+ UPRV_LENGTHOF(params), |
+ appendTo, |
+ NULL, |
+ 0, |
+ status); |
+} |
+ |
+UnicodeString& SimplePatternFormatter::format( |
+ const UnicodeString &arg0, |
+ const UnicodeString &arg1, |
+ const UnicodeString &arg2, |
+ UnicodeString &appendTo, |
+ UErrorCode &status) const { |
+ const UnicodeString *params[] = {&arg0, &arg1, &arg2}; |
+ return format( |
+ params, |
+ UPRV_LENGTHOF(params), |
+ appendTo, |
+ NULL, |
+ 0, |
+ status); |
+} |
+ |
+static void updatePlaceholderOffset( |
+ int32_t placeholderId, |
+ int32_t placeholderOffset, |
+ int32_t *offsetArray, |
+ int32_t offsetArrayLength) { |
+ if (placeholderId < offsetArrayLength) { |
+ offsetArray[placeholderId] = placeholderOffset; |
+ } |
+} |
+ |
+static void appendRange( |
+ const UnicodeString &src, |
+ int32_t start, |
+ int32_t end, |
+ UnicodeString &dest) { |
+ dest.append(src, start, end - start); |
+} |
+ |
+UnicodeString& SimplePatternFormatter::format( |
+ const UnicodeString * const *placeholderValues, |
+ int32_t placeholderValueCount, |
+ UnicodeString &appendTo, |
+ int32_t *offsetArray, |
+ int32_t offsetArrayLength, |
+ UErrorCode &status) const { |
+ if (U_FAILURE(status)) { |
+ return appendTo; |
+ } |
+ if (placeholderValueCount < placeholderCount) { |
+ status = U_ILLEGAL_ARGUMENT_ERROR; |
+ return appendTo; |
+ } |
+ for (int32_t i = 0; i < offsetArrayLength; ++i) { |
+ offsetArray[i] = -1; |
+ } |
+ if (placeholderSize == 0) { |
+ appendTo.append(noPlaceholders); |
+ return appendTo; |
+ } |
+ if (placeholders[0].offset > 0 || |
+ placeholderValues[placeholders[0].id] != &appendTo) { |
+ appendRange( |
+ noPlaceholders, |
+ 0, |
+ placeholders[0].offset, |
+ appendTo); |
+ updatePlaceholderOffset( |
+ placeholders[0].id, |
+ appendTo.length(), |
+ offsetArray, |
+ offsetArrayLength); |
+ appendTo.append(*placeholderValues[placeholders[0].id]); |
+ } else { |
+ updatePlaceholderOffset( |
+ placeholders[0].id, |
+ 0, |
+ offsetArray, |
+ offsetArrayLength); |
+ } |
+ for (int32_t i = 1; i < placeholderSize; ++i) { |
+ appendRange( |
+ noPlaceholders, |
+ placeholders[i - 1].offset, |
+ placeholders[i].offset, |
+ appendTo); |
+ updatePlaceholderOffset( |
+ placeholders[i].id, |
+ appendTo.length(), |
+ offsetArray, |
+ offsetArrayLength); |
+ appendTo.append(*placeholderValues[placeholders[i].id]); |
+ } |
+ appendRange( |
+ noPlaceholders, |
+ placeholders[placeholderSize - 1].offset, |
+ noPlaceholders.length(), |
+ appendTo); |
+ return appendTo; |
+} |
+ |
+int32_t SimplePatternFormatter::ensureCapacity( |
+ int32_t desiredCapacity, int32_t allocationSize) { |
+ if (allocationSize < desiredCapacity) { |
+ allocationSize = desiredCapacity; |
+ } |
+ if (desiredCapacity <= placeholders.getCapacity()) { |
+ return desiredCapacity; |
+ } |
+ // allocate new buffer |
+ if (placeholders.resize(allocationSize, placeholderSize) == NULL) { |
+ return placeholders.getCapacity(); |
+ } |
+ return desiredCapacity; |
+} |
+ |
+UBool SimplePatternFormatter::addPlaceholder(int32_t id, int32_t offset) { |
+ if (ensureCapacity(placeholderSize + 1, 2 * placeholderSize) < placeholderSize + 1) { |
+ return FALSE; |
+ } |
+ ++placeholderSize; |
+ PlaceholderInfo *placeholderEnd = &placeholders[placeholderSize - 1]; |
+ placeholderEnd->offset = offset; |
+ placeholderEnd->id = id; |
+ if (id >= placeholderCount) { |
+ placeholderCount = id + 1; |
+ } |
+ return TRUE; |
+} |
+ |
+U_NAMESPACE_END |