844d4e860b
X-SVN-Rev: 35027
343 lines
9.9 KiB
C++
343 lines
9.9 KiB
C++
/*
|
|
******************************************************************************
|
|
* Copyright (C) 2014, International Business Machines
|
|
* Corporation and others. All Rights Reserved.
|
|
******************************************************************************
|
|
* simplepatternformatter.cpp
|
|
*/
|
|
#include "simplepatternformatter.h"
|
|
#include "cstring.h"
|
|
#include "uassert.h"
|
|
|
|
#define LENGTHOF(array) (int32_t)(sizeof(array) / sizeof((array)[0]))
|
|
|
|
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(),
|
|
placeholdersByOffset(placeholderBuffer),
|
|
placeholderSize(0),
|
|
placeholderCapacity(EXPECTED_PLACEHOLDER_COUNT),
|
|
placeholderCount(0) {
|
|
}
|
|
|
|
SimplePatternFormatter::SimplePatternFormatter(const UnicodeString &pattern) :
|
|
noPlaceholders(),
|
|
placeholdersByOffset(placeholderBuffer),
|
|
placeholderSize(0),
|
|
placeholderCapacity(EXPECTED_PLACEHOLDER_COUNT),
|
|
placeholderCount(0) {
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
compile(pattern, status);
|
|
}
|
|
|
|
SimplePatternFormatter::SimplePatternFormatter(
|
|
const SimplePatternFormatter &other) :
|
|
noPlaceholders(other.noPlaceholders),
|
|
placeholdersByOffset(placeholderBuffer),
|
|
placeholderSize(0),
|
|
placeholderCapacity(EXPECTED_PLACEHOLDER_COUNT),
|
|
placeholderCount(other.placeholderCount) {
|
|
placeholderSize = ensureCapacity(other.placeholderSize);
|
|
uprv_memcpy(
|
|
placeholdersByOffset,
|
|
other.placeholdersByOffset,
|
|
placeholderSize * 2 * sizeof(int32_t));
|
|
}
|
|
|
|
SimplePatternFormatter &SimplePatternFormatter::operator=(
|
|
const SimplePatternFormatter& other) {
|
|
if (this == &other) {
|
|
return *this;
|
|
}
|
|
noPlaceholders = other.noPlaceholders;
|
|
placeholderCount = other.placeholderCount;
|
|
placeholderSize = ensureCapacity(other.placeholderSize);
|
|
uprv_memcpy(
|
|
placeholdersByOffset,
|
|
other.placeholdersByOffset,
|
|
placeholderSize * 2 * sizeof(int32_t));
|
|
return *this;
|
|
}
|
|
|
|
SimplePatternFormatter::~SimplePatternFormatter() {
|
|
if (placeholdersByOffset != placeholderBuffer) {
|
|
uprv_free(placeholdersByOffset);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
UnicodeString& SimplePatternFormatter::format(
|
|
const UnicodeString &arg0,
|
|
UnicodeString &appendTo,
|
|
UErrorCode &status) const {
|
|
const UnicodeString *params[] = {&arg0};
|
|
return format(
|
|
params,
|
|
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,
|
|
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,
|
|
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;
|
|
}
|
|
appendRange(
|
|
noPlaceholders,
|
|
0,
|
|
placeholdersByOffset[0],
|
|
appendTo);
|
|
updatePlaceholderOffset(
|
|
placeholdersByOffset[1],
|
|
appendTo.length(),
|
|
offsetArray,
|
|
offsetArrayLength);
|
|
appendTo.append(*placeholderValues[placeholdersByOffset[1]]);
|
|
for (int32_t i = 1; i < placeholderSize; ++i) {
|
|
appendRange(
|
|
noPlaceholders,
|
|
placeholdersByOffset[2 * i - 2],
|
|
placeholdersByOffset[2 * i],
|
|
appendTo);
|
|
updatePlaceholderOffset(
|
|
placeholdersByOffset[2 * i + 1],
|
|
appendTo.length(),
|
|
offsetArray,
|
|
offsetArrayLength);
|
|
appendTo.append(*placeholderValues[placeholdersByOffset[2 * i + 1]]);
|
|
}
|
|
appendRange(
|
|
noPlaceholders,
|
|
placeholdersByOffset[2 * placeholderSize - 2],
|
|
noPlaceholders.length(),
|
|
appendTo);
|
|
return appendTo;
|
|
}
|
|
|
|
int32_t SimplePatternFormatter::ensureCapacity(int32_t atLeast) {
|
|
if (atLeast <= placeholderCapacity) {
|
|
return atLeast;
|
|
}
|
|
// aim to double capacity each time
|
|
int32_t newCapacity = 2*atLeast - 2;
|
|
|
|
// allocate new buffer
|
|
int32_t *newBuffer = (int32_t *) uprv_malloc(2 * newCapacity * sizeof(int32_t));
|
|
if (newBuffer == NULL) {
|
|
return placeholderCapacity;
|
|
}
|
|
|
|
// Copy contents of old buffer to new buffer
|
|
uprv_memcpy(newBuffer, placeholdersByOffset, 2 * placeholderSize * sizeof(int32_t));
|
|
|
|
// free old buffer
|
|
if (placeholdersByOffset != placeholderBuffer) {
|
|
uprv_free(placeholdersByOffset);
|
|
}
|
|
|
|
// Use new buffer
|
|
placeholdersByOffset = newBuffer;
|
|
placeholderCapacity = newCapacity;
|
|
return atLeast;
|
|
}
|
|
|
|
UBool SimplePatternFormatter::addPlaceholder(int32_t id, int32_t offset) {
|
|
if (ensureCapacity(placeholderSize + 1) < placeholderSize + 1) {
|
|
return FALSE;
|
|
}
|
|
++placeholderSize;
|
|
placeholdersByOffset[2 * placeholderSize - 2] = offset;
|
|
placeholdersByOffset[2 * placeholderSize - 1] = id;
|
|
if (id >= placeholderCount) {
|
|
placeholderCount = id + 1;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
U_NAMESPACE_END
|