• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CollationSettings(const CollationSettings & other)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 
~CollationSettings()48 CollationSettings::~CollationSettings() {
49     if(reorderCodesCapacity != 0) {
50         uprv_free(const_cast<int32_t *>(reorderCodes));
51     }
52 }
53 
54 UBool
operator ==(const CollationSettings & other) const55 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
hashCode() const66 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
resetReordering()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
aliasReordering(const int32_t * codes,int32_t length,const uint8_t * table)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
setReordering(const int32_t * codes,int32_t length,const uint8_t table[256])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
setStrength(int32_t value,int32_t defaultOptions,UErrorCode & errorCode)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
setFlag(int32_t bit,UColAttributeValue value,int32_t defaultOptions,UErrorCode & errorCode)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
setCaseFirst(UColAttributeValue value,int32_t defaultOptions,UErrorCode & errorCode)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
setAlternateHandling(UColAttributeValue value,int32_t defaultOptions,UErrorCode & errorCode)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
setMaxVariable(int32_t value,int32_t defaultOptions,UErrorCode & errorCode)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