Home | History | Annotate | Download | only in common
      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 
     14 U_NAMESPACE_BEGIN
     15 
     16 typedef enum SimplePatternFormatterCompileState {
     17     INIT,
     18     APOSTROPHE,
     19     PLACEHOLDER
     20 } SimplePatternFormatterCompileState;
     21 
     22 class SimplePatternFormatterIdBuilder {
     23 public:
     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);
     31 private:
     32     int32_t id;
     33     int32_t idLen;
     34     SimplePatternFormatterIdBuilder(
     35             const SimplePatternFormatterIdBuilder &other);
     36     SimplePatternFormatterIdBuilder &operator=(
     37             const SimplePatternFormatterIdBuilder &other);
     38 };
     39 
     40 void 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 
     52 void SimplePatternFormatterIdBuilder::add(UChar ch) {
     53     id = id * 10 + (ch - 0x30);
     54     idLen++;
     55 }
     56 
     57 SimplePatternFormatter::SimplePatternFormatter() :
     58         noPlaceholders(),
     59         placeholdersByOffset(placeholderBuffer),
     60         placeholderSize(0),
     61         placeholderCapacity(EXPECTED_PLACEHOLDER_COUNT),
     62         placeholderCount(0) {
     63 }
     64 
     65 SimplePatternFormatter::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 
     75 SimplePatternFormatter::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 
     89 SimplePatternFormatter &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 
    104 SimplePatternFormatter::~SimplePatternFormatter() {
    105     if (placeholdersByOffset != placeholderBuffer) {
    106         uprv_free(placeholdersByOffset);
    107     }
    108 }
    109 
    110 UBool 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 
    186 UnicodeString& 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 
    200 UnicodeString& 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 
    215 UnicodeString& 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 
    231 static 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 
    241 static 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 
    249 UnicodeString& 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 
    302 int32_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 
    329 UBool 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 
    342 U_NAMESPACE_END
    343