Home | History | Annotate | Download | only in i18n
      1 /*
      2 *******************************************************************************
      3 * Copyright (C) 2013-2014, International Business Machines
      4 * Corporation and others.  All Rights Reserved.
      5 *******************************************************************************
      6 * collationsettings.cpp
      7 *
      8 * created on: 2013feb07
      9 * created by: Markus W. Scherer
     10 */
     11 
     12 #include "unicode/utypes.h"
     13 
     14 #if !UCONFIG_NO_COLLATION
     15 
     16 #include "unicode/ucol.h"
     17 #include "cmemory.h"
     18 #include "collation.h"
     19 #include "collationsettings.h"
     20 #include "sharedobject.h"
     21 #include "uassert.h"
     22 #include "umutex.h"
     23 
     24 U_NAMESPACE_BEGIN
     25 
     26 CollationSettings::CollationSettings(const CollationSettings &other)
     27         : SharedObject(other),
     28           options(other.options), variableTop(other.variableTop),
     29           reorderTable(NULL),
     30           reorderCodes(NULL), reorderCodesLength(0), reorderCodesCapacity(0),
     31           fastLatinOptions(other.fastLatinOptions) {
     32     int32_t length = other.reorderCodesLength;
     33     if(length == 0) {
     34         U_ASSERT(other.reorderTable == NULL);
     35     } else {
     36         U_ASSERT(other.reorderTable != NULL);
     37         if(other.reorderCodesCapacity == 0) {
     38             aliasReordering(other.reorderCodes, length, other.reorderTable);
     39         } else {
     40             setReordering(other.reorderCodes, length, other.reorderTable);
     41         }
     42     }
     43     if(fastLatinOptions >= 0) {
     44         uprv_memcpy(fastLatinPrimaries, other.fastLatinPrimaries, sizeof(fastLatinPrimaries));
     45     }
     46 }
     47 
     48 CollationSettings::~CollationSettings() {
     49     if(reorderCodesCapacity != 0) {
     50         uprv_free(const_cast<int32_t *>(reorderCodes));
     51     }
     52 }
     53 
     54 UBool
     55 CollationSettings::operator==(const CollationSettings &other) const {
     56     if(options != other.options) { return FALSE; }
     57     if((options & ALTERNATE_MASK) != 0 && variableTop != other.variableTop) { return FALSE; }
     58     if(reorderCodesLength != other.reorderCodesLength) { return FALSE; }
     59     for(int32_t i = 0; i < reorderCodesLength; ++i) {
     60         if(reorderCodes[i] != other.reorderCodes[i]) { return FALSE; }
     61     }
     62     return TRUE;
     63 }
     64 
     65 int32_t
     66 CollationSettings::hashCode() const {
     67     int32_t h = options << 8;
     68     if((options & ALTERNATE_MASK) != 0) { h ^= variableTop; }
     69     h ^= reorderCodesLength;
     70     for(int32_t i = 0; i < reorderCodesLength; ++i) {
     71         h ^= (reorderCodes[i] << i);
     72     }
     73     return h;
     74 }
     75 
     76 void
     77 CollationSettings::resetReordering() {
     78     // When we turn off reordering, we want to set a NULL permutation
     79     // rather than a no-op permutation.
     80     // Keep the memory via reorderCodes and its capacity.
     81     reorderTable = NULL;
     82     reorderCodesLength = 0;
     83 }
     84 
     85 void
     86 CollationSettings::aliasReordering(const int32_t *codes, int32_t length, const uint8_t *table) {
     87     if(length == 0) {
     88         resetReordering();
     89     } else {
     90         // We need to release the memory before setting the alias pointer.
     91         if(reorderCodesCapacity != 0) {
     92             uprv_free(const_cast<int32_t *>(reorderCodes));
     93             reorderCodesCapacity = 0;
     94         }
     95         reorderTable = table;
     96         reorderCodes = codes;
     97         reorderCodesLength = length;
     98     }
     99 }
    100 
    101 UBool
    102 CollationSettings::setReordering(const int32_t *codes, int32_t length, const uint8_t table[256]) {
    103     if(length == 0) {
    104         resetReordering();
    105     } else {
    106         uint8_t *ownedTable;
    107         int32_t *ownedCodes;
    108         if(length <= reorderCodesCapacity) {
    109             ownedTable = const_cast<uint8_t *>(reorderTable);
    110             ownedCodes = const_cast<int32_t *>(reorderCodes);
    111         } else {
    112             // Allocate one memory block for the codes and the 16-aligned table.
    113             int32_t capacity = (length + 3) & ~3;  // round up to a multiple of 4 ints
    114             uint8_t *bytes = (uint8_t *)uprv_malloc(256 + capacity * 4);
    115             if(bytes == NULL) { return FALSE; }
    116             if(reorderCodesCapacity != 0) {
    117                 uprv_free(const_cast<int32_t *>(reorderCodes));
    118             }
    119             reorderTable = ownedTable = bytes + capacity * 4;
    120             reorderCodes = ownedCodes = (int32_t *)bytes;
    121             reorderCodesCapacity = capacity;
    122         }
    123         uprv_memcpy(ownedTable, table, 256);
    124         uprv_memcpy(ownedCodes, codes, length * 4);
    125         reorderCodesLength = length;
    126     }
    127     return TRUE;
    128 }
    129 
    130 void
    131 CollationSettings::setStrength(int32_t value, int32_t defaultOptions, UErrorCode &errorCode) {
    132     if(U_FAILURE(errorCode)) { return; }
    133     int32_t noStrength = options & ~STRENGTH_MASK;
    134     switch(value) {
    135     case UCOL_PRIMARY:
    136     case UCOL_SECONDARY:
    137     case UCOL_TERTIARY:
    138     case UCOL_QUATERNARY:
    139     case UCOL_IDENTICAL:
    140         options = noStrength | (value << STRENGTH_SHIFT);
    141         break;
    142     case UCOL_DEFAULT:
    143         options = noStrength | (defaultOptions & STRENGTH_MASK);
    144         break;
    145     default:
    146         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    147         break;
    148     }
    149 }
    150 
    151 void
    152 CollationSettings::setFlag(int32_t bit, UColAttributeValue value,
    153                            int32_t defaultOptions, UErrorCode &errorCode) {
    154     if(U_FAILURE(errorCode)) { return; }
    155     switch(value) {
    156     case UCOL_ON:
    157         options |= bit;
    158         break;
    159     case UCOL_OFF:
    160         options &= ~bit;
    161         break;
    162     case UCOL_DEFAULT:
    163         options = (options & ~bit) | (defaultOptions & bit);
    164         break;
    165     default:
    166         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    167         break;
    168     }
    169 }
    170 
    171 void
    172 CollationSettings::setCaseFirst(UColAttributeValue value,
    173                                 int32_t defaultOptions, UErrorCode &errorCode) {
    174     if(U_FAILURE(errorCode)) { return; }
    175     int32_t noCaseFirst = options & ~CASE_FIRST_AND_UPPER_MASK;
    176     switch(value) {
    177     case UCOL_OFF:
    178         options = noCaseFirst;
    179         break;
    180     case UCOL_LOWER_FIRST:
    181         options = noCaseFirst | CASE_FIRST;
    182         break;
    183     case UCOL_UPPER_FIRST:
    184         options = noCaseFirst | CASE_FIRST_AND_UPPER_MASK;
    185         break;
    186     case UCOL_DEFAULT:
    187         options = noCaseFirst | (defaultOptions & CASE_FIRST_AND_UPPER_MASK);
    188         break;
    189     default:
    190         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    191         break;
    192     }
    193 }
    194 
    195 void
    196 CollationSettings::setAlternateHandling(UColAttributeValue value,
    197                                         int32_t defaultOptions, UErrorCode &errorCode) {
    198     if(U_FAILURE(errorCode)) { return; }
    199     int32_t noAlternate = options & ~ALTERNATE_MASK;
    200     switch(value) {
    201     case UCOL_NON_IGNORABLE:
    202         options = noAlternate;
    203         break;
    204     case UCOL_SHIFTED:
    205         options = noAlternate | SHIFTED;
    206         break;
    207     case UCOL_DEFAULT:
    208         options = noAlternate | (defaultOptions & ALTERNATE_MASK);
    209         break;
    210     default:
    211         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    212         break;
    213     }
    214 }
    215 
    216 void
    217 CollationSettings::setMaxVariable(int32_t value, int32_t defaultOptions, UErrorCode &errorCode) {
    218     if(U_FAILURE(errorCode)) { return; }
    219     int32_t noMax = options & ~MAX_VARIABLE_MASK;
    220     switch(value) {
    221     case MAX_VAR_SPACE:
    222     case MAX_VAR_PUNCT:
    223     case MAX_VAR_SYMBOL:
    224     case MAX_VAR_CURRENCY:
    225         options = noMax | (value << MAX_VARIABLE_SHIFT);
    226         break;
    227     case UCOL_DEFAULT:
    228         options = noMax | (defaultOptions & MAX_VARIABLE_MASK);
    229         break;
    230     default:
    231         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    232         break;
    233     }
    234 }
    235 
    236 U_NAMESPACE_END
    237 
    238 #endif  // !UCONFIG_NO_COLLATION
    239