Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/intl/icu/source/i18n/scriptset.cpp
Line
Count
Source (jump to first uncovered line)
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
/*
4
**********************************************************************
5
*   Copyright (C) 2014, International Business Machines
6
*   Corporation and others.  All Rights Reserved.
7
**********************************************************************
8
*
9
* scriptset.cpp
10
*
11
* created on: 2013 Jan 7
12
* created by: Andy Heninger
13
*/
14
15
#include "unicode/utypes.h"
16
17
#include "unicode/uchar.h"
18
#include "unicode/unistr.h"
19
20
#include "scriptset.h"
21
#include "uassert.h"
22
#include "cmemory.h"
23
24
U_NAMESPACE_BEGIN
25
26
//----------------------------------------------------------------------------
27
//
28
//  ScriptSet implementation
29
//
30
//----------------------------------------------------------------------------
31
0
ScriptSet::ScriptSet() {
32
0
    for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
33
0
        bits[i] = 0;
34
0
    }
35
0
}
36
37
0
ScriptSet::~ScriptSet() {
38
0
}
39
40
0
ScriptSet::ScriptSet(const ScriptSet &other) {
41
0
    *this = other;
42
0
}
43
    
44
45
0
ScriptSet & ScriptSet::operator =(const ScriptSet &other) {
46
0
    for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
47
0
        bits[i] = other.bits[i];
48
0
    }
49
0
    return *this;
50
0
}
51
52
53
0
UBool ScriptSet::operator == (const ScriptSet &other) const {
54
0
    for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
55
0
        if (bits[i] != other.bits[i]) {
56
0
            return FALSE;
57
0
        }
58
0
    }
59
0
    return TRUE;
60
0
}
61
62
0
UBool ScriptSet::test(UScriptCode script, UErrorCode &status) const {
63
0
    if (U_FAILURE(status)) {
64
0
        return FALSE;
65
0
    }
66
0
    if (script < 0 || script >= (int32_t)sizeof(bits) * 8) {
67
0
        status = U_ILLEGAL_ARGUMENT_ERROR;
68
0
        return FALSE;
69
0
    }
70
0
    uint32_t index = script / 32;
71
0
    uint32_t bit   = 1 << (script & 31);
72
0
    return ((bits[index] & bit) != 0);
73
0
}
74
75
76
0
ScriptSet &ScriptSet::set(UScriptCode script, UErrorCode &status) {
77
0
    if (U_FAILURE(status)) {
78
0
        return *this;
79
0
    }
80
0
    if (script < 0 || script >= (int32_t)sizeof(bits) * 8) {
81
0
        status = U_ILLEGAL_ARGUMENT_ERROR;
82
0
        return *this;
83
0
    }
84
0
    uint32_t index = script / 32;
85
0
    uint32_t bit   = 1 << (script & 31);
86
0
    bits[index] |= bit;
87
0
    return *this;
88
0
}
89
90
0
ScriptSet &ScriptSet::reset(UScriptCode script, UErrorCode &status) {
91
0
    if (U_FAILURE(status)) {
92
0
        return *this;
93
0
    }
94
0
    if (script < 0 || script >= (int32_t)sizeof(bits) * 8) {
95
0
        status = U_ILLEGAL_ARGUMENT_ERROR;
96
0
        return *this;
97
0
    }
98
0
    uint32_t index = script / 32;
99
0
    uint32_t bit   = 1 << (script & 31);
100
0
    bits[index] &= ~bit;
101
0
    return *this;
102
0
}
103
104
105
106
0
ScriptSet &ScriptSet::Union(const ScriptSet &other) {
107
0
    for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
108
0
        bits[i] |= other.bits[i];
109
0
    }
110
0
    return *this;
111
0
}
112
113
0
ScriptSet &ScriptSet::intersect(const ScriptSet &other) {
114
0
    for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
115
0
        bits[i] &= other.bits[i];
116
0
    }
117
0
    return *this;
118
0
}
119
120
0
ScriptSet &ScriptSet::intersect(UScriptCode script, UErrorCode &status) {
121
0
    ScriptSet t;
122
0
    t.set(script, status);
123
0
    if (U_SUCCESS(status)) {
124
0
        this->intersect(t);
125
0
    }
126
0
    return *this;
127
0
}
128
    
129
0
UBool ScriptSet::intersects(const ScriptSet &other) const {
130
0
    for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
131
0
        if ((bits[i] & other.bits[i]) != 0) {
132
0
            return true;
133
0
        }
134
0
    }
135
0
    return false;
136
0
}
137
138
0
UBool ScriptSet::contains(const ScriptSet &other) const {
139
0
    ScriptSet t(*this);
140
0
    t.intersect(other);
141
0
    return (t == other);
142
0
}
143
144
145
0
ScriptSet &ScriptSet::setAll() {
146
0
    for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
147
0
        bits[i] = 0xffffffffu;
148
0
    }
149
0
    return *this;
150
0
}
151
152
153
0
ScriptSet &ScriptSet::resetAll() {
154
0
    for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
155
0
        bits[i] = 0;
156
0
    }
157
0
    return *this;
158
0
}
159
160
0
int32_t ScriptSet::countMembers() const {
161
0
    // This bit counter is good for sparse numbers of '1's, which is
162
0
    //  very much the case that we will usually have.
163
0
    int32_t count = 0;
164
0
    for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
165
0
        uint32_t x = bits[i];
166
0
        while (x > 0) {
167
0
            count++;
168
0
            x &= (x - 1);    // and off the least significant one bit.
169
0
        }
170
0
    }
171
0
    return count;
172
0
}
173
174
0
int32_t ScriptSet::hashCode() const {
175
0
    int32_t hash = 0;
176
0
    for (int32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
177
0
        hash ^= bits[i];
178
0
    }
179
0
    return hash;
180
0
}
181
182
0
int32_t ScriptSet::nextSetBit(int32_t fromIndex) const {
183
0
    // TODO: Wants a better implementation.
184
0
    if (fromIndex < 0) {
185
0
        return -1;
186
0
    }
187
0
    UErrorCode status = U_ZERO_ERROR;
188
0
    for (int32_t scriptIndex = fromIndex; scriptIndex < (int32_t)sizeof(bits)*8; scriptIndex++) {
189
0
        if (test((UScriptCode)scriptIndex, status)) {
190
0
            return scriptIndex;
191
0
        }
192
0
    }
193
0
    return -1;
194
0
}
195
196
0
UBool ScriptSet::isEmpty() const {
197
0
    for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
198
0
        if (bits[i] != 0) {
199
0
            return FALSE;
200
0
        }
201
0
    }
202
0
    return TRUE;
203
0
}
204
205
0
UnicodeString &ScriptSet::displayScripts(UnicodeString &dest) const {
206
0
    UBool firstTime = TRUE;
207
0
    for (int32_t i = nextSetBit(0); i >= 0; i = nextSetBit(i + 1)) {
208
0
        if (!firstTime) {
209
0
            dest.append((UChar)0x20);
210
0
        }
211
0
        firstTime = FALSE;
212
0
        const char *scriptName = uscript_getShortName((UScriptCode(i)));
213
0
        dest.append(UnicodeString(scriptName, -1, US_INV));
214
0
    }
215
0
    return dest;
216
0
}
217
218
0
ScriptSet &ScriptSet::parseScripts(const UnicodeString &scriptString, UErrorCode &status) {
219
0
    resetAll();
220
0
    if (U_FAILURE(status)) {
221
0
        return *this;
222
0
    }
223
0
    UnicodeString oneScriptName;
224
0
    for (int32_t i=0; i<scriptString.length();) {
225
0
        UChar32 c = scriptString.char32At(i);
226
0
        i = scriptString.moveIndex32(i, 1);
227
0
        if (!u_isUWhiteSpace(c)) {
228
0
            oneScriptName.append(c);
229
0
            if (i < scriptString.length()) {
230
0
                continue;
231
0
            }
232
0
        }
233
0
        if (oneScriptName.length() > 0) {
234
0
            char buf[40];
235
0
            oneScriptName.extract(0, oneScriptName.length(), buf, sizeof(buf)-1, US_INV);
236
0
            buf[sizeof(buf)-1] = 0;
237
0
            int32_t sc = u_getPropertyValueEnum(UCHAR_SCRIPT, buf);
238
0
            if (sc == UCHAR_INVALID_CODE) {
239
0
                status = U_ILLEGAL_ARGUMENT_ERROR;
240
0
            } else {
241
0
                this->set((UScriptCode)sc, status);
242
0
            }
243
0
            if (U_FAILURE(status)) {
244
0
                return *this;
245
0
            }
246
0
            oneScriptName.remove();
247
0
        }
248
0
    }
249
0
    return *this;
250
0
}
251
252
0
void ScriptSet::setScriptExtensions(UChar32 codePoint, UErrorCode& status) {
253
0
    if (U_FAILURE(status)) { return; }
254
0
    static const int32_t FIRST_GUESS_SCRIPT_CAPACITY = 5;
255
0
    MaybeStackArray<UScriptCode,FIRST_GUESS_SCRIPT_CAPACITY> scripts;
256
0
    UErrorCode internalStatus = U_ZERO_ERROR;
257
0
    int32_t script_count = -1;
258
0
259
0
    while (TRUE) {
260
0
        script_count = uscript_getScriptExtensions(
261
0
            codePoint, scripts.getAlias(), scripts.getCapacity(), &internalStatus);
262
0
        if (internalStatus == U_BUFFER_OVERFLOW_ERROR) {
263
0
            // Need to allocate more space
264
0
            if (scripts.resize(script_count) == NULL) {
265
0
                status = U_MEMORY_ALLOCATION_ERROR;
266
0
                return;
267
0
            }
268
0
            internalStatus = U_ZERO_ERROR;
269
0
        } else {
270
0
            break;
271
0
        }
272
0
    }
273
0
274
0
    // Check if we failed for some reason other than buffer overflow
275
0
    if (U_FAILURE(internalStatus)) {
276
0
        status = internalStatus;
277
0
        return;
278
0
    }
279
0
280
0
    // Load the scripts into the ScriptSet and return
281
0
    for (int32_t i = 0; i < script_count; i++) {
282
0
        this->set(scripts[i], status);
283
0
        if (U_FAILURE(status)) { return; }
284
0
    }
285
0
}
286
287
U_NAMESPACE_END
288
289
U_CAPI UBool U_EXPORT2
290
0
uhash_equalsScriptSet(const UElement key1, const UElement key2) {
291
0
    icu::ScriptSet *s1 = static_cast<icu::ScriptSet *>(key1.pointer);
292
0
    icu::ScriptSet *s2 = static_cast<icu::ScriptSet *>(key2.pointer);
293
0
    return (*s1 == *s2);
294
0
}
295
296
U_CAPI int8_t U_EXPORT2
297
0
uhash_compareScriptSet(UElement key0, UElement key1) {
298
0
    icu::ScriptSet *s0 = static_cast<icu::ScriptSet *>(key0.pointer);
299
0
    icu::ScriptSet *s1 = static_cast<icu::ScriptSet *>(key1.pointer);
300
0
    int32_t diff = s0->countMembers() - s1->countMembers();
301
0
    if (diff != 0) return diff;
302
0
    int32_t i0 = s0->nextSetBit(0);
303
0
    int32_t i1 = s1->nextSetBit(0);
304
0
    while ((diff = i0-i1) == 0 && i0 > 0) {
305
0
        i0 = s0->nextSetBit(i0+1);
306
0
        i1 = s1->nextSetBit(i1+1);
307
0
    }
308
0
    return (int8_t)diff;
309
0
}
310
311
U_CAPI int32_t U_EXPORT2
312
0
uhash_hashScriptSet(const UElement key) {
313
0
    icu::ScriptSet *s = static_cast<icu::ScriptSet *>(key.pointer);
314
0
    return s->hashCode();
315
0
}
316
317
U_CAPI void U_EXPORT2
318
0
uhash_deleteScriptSet(void *obj) {
319
0
    icu::ScriptSet *s = static_cast<icu::ScriptSet *>(obj);
320
0
    delete s;
321
0
}