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