1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
|
#pragma once
#include "unicode_table.h"
#include <util/system/defaults.h> // wchar32, ui64, ULL()
enum WC_TYPE { // TODO move no NUnicode
Lu_UPPER = 1, // 'Ъ'
Ll_LOWER = 2, // 'ъ'
Lt_TITLE = 3, // 'Ъ'
Lm_EXTENDER = 4, // '-'
Lm_LETTER = 5, // 'ъ'
Lo_OTHER = 6, // '?'
Lo_IDEOGRAPH = 7, // '?'
Lo_KATAKANA = 8, // '?'
Lo_HIRAGANA = 9, // '?'
Lo_LEADING = 10, // '?'
Lo_VOWEL = 11, // '?'
Lo_TRAILING = 12, // '?'
Mn_NONSPACING = 13, // '`'
Me_ENCLOSING = 14, // '`'
Mc_SPACING = 15, // '`'
Nd_DIGIT = 16, // '9' // convert to digit
Nl_LETTER = 17, // 'X' // X,V,C,L,I ...
Nl_IDEOGRAPH = 18, // '?'
No_OTHER = 19, // '9'
Zs_SPACE = 20, // ' ' [\40\240] SPACE ... NO-BREAK SPACE (00A0)
Zs_ZWSPACE = 21, // ' ' // nothing ?
Zl_LINE = 22, // '\n'
Zp_PARAGRAPH = 23, // '\n'
Cc_ASCII = 24, // '\x1A' // can not happen
Cc_SPACE = 25, // '\x1A' // can not happen
Cc_SEPARATOR = 26, // '\x1A' // can not happen
Cf_FORMAT = 27, // '\x1A' // nothing ?
Cf_JOIN = 28, // '\x1A' // nothing ?
Cf_BIDI = 29, // '\x1A' // nothing ?
Cf_ZWNBSP = 30, // '\x1A' // nothing ?
Cn_UNASSIGNED = 0, // '?'
Co_PRIVATE = 0, // '?'
Cs_LOW = 31, // '?'
Cs_HIGH = 32, // '?'
Pd_DASH = 33, // '-'
Pd_HYPHEN = 34, // '-' [-] HYPHEN-MINUS
Ps_START = 35, // '(' [([{] LEFT PARENTHESIS ... LEFT CURLY BRACKET
Ps_QUOTE = 36, // '"'
Pe_END = 37, // ')' [)]}] RIGHT PARENTHESIS ... RIGHT CURLY BRACKET
Pe_QUOTE = 38, // '"'
Pi_QUOTE = 39, // '"'
Pf_QUOTE = 40, // '"'
Pc_CONNECTOR = 41, // '_' [_] LOW LINE
Po_OTHER = 42, // '*' [#%&*/@\] NUMBER SIGN ... REVERSE SOLIDUS
Po_QUOTE = 43, // '"' ["] QUOTATION MARK
Po_TERMINAL = 44, // '.' [!,.:;?] EXCLAMATION MARK ... QUESTION MARK
Po_EXTENDER = 45, // '-' [№] MIDDLE DOT (00B7)
Po_HYPHEN = 46, // '-'
Sm_MATH = 47, // '=' [+<=>|~] PLUS SIGN ... TILDE
Sm_MINUS = 48, // '-'
Sc_CURRENCY = 49, // '$' [$] DOLLAR SIGN
Sk_MODIFIER = 50, // '`' [^`] CIRCUMFLEX ACCENT ... GRAVE ACCENT
So_OTHER = 51, // '°' [°] DEGREE SIGN (00B0)
Ps_SINGLE_QUOTE = 52, // '\'' ['] OPENING SINGLE QUOTE
Pe_SINGLE_QUOTE = 53, // '\'' ['] CLOSING SINGLE QUOTE
Pi_SINGLE_QUOTE = 54, // '\'' ['] INITIAL SINGLE QUOTE
Pf_SINGLE_QUOTE = 55, // '\'' ['] FINAL SINGLE QUOTE
Po_SINGLE_QUOTE = 56, // '\'' ['] APOSTROPHE and PRIME
CCL_NUM = 57,
CCL_MASK = 0x3F,
IS_ASCII_XDIGIT = 1 << 6,
IS_DIGIT = 1 << 7,
IS_NONBREAK = 1 << 8,
IS_PRIVATE = 1 << 9,
IS_COMPAT = 1 << 10,
IS_CANON = 1 << 11,
NFD_QC = 1 << 12,
NFC_QC = 1 << 13,
NFKD_QC = 1 << 14,
NFKC_QC = 1 << 15,
BIDI_OFFSET = 16,
SVAL_OFFSET = 22,
};
const size_t DEFCHAR_BUF = 58; // CCL_NUM + 1
#define SHIFT(i) (ULL(1) << (i))
namespace NUnicode {
using TCombining = ui8;
namespace NPrivate {
struct TProperty {
ui32 Info;
i32 Lower;
i32 Upper;
i32 Title;
TCombining Combining;
};
extern const size_t DEFAULT_KEY;
using TUnidataTable = NUnicodeTable::TTable<NUnicodeTable::TSubtable<NUnicodeTable::UNICODE_TABLE_SHIFT, NUnicodeTable::TValues<TProperty>>>;
const TUnidataTable& UnidataTable();
inline const TProperty& CharProperty(wchar32 ch) {
return UnidataTable().Get(ch, DEFAULT_KEY);
}
inline ui32 CharInfo(wchar32 ch) {
return CharProperty(ch).Info;
}
inline bool IsBidi(wchar32 ch, ui32 type) {
return ((NUnicode::NPrivate::CharInfo(ch) >> BIDI_OFFSET) & 15) == type;
}
}
inline size_t UnicodeInstancesLimit() {
return NPrivate::UnidataTable().Size();
}
inline TCombining DecompositionCombining(wchar32 ch) {
return NPrivate::CharProperty(ch).Combining;
}
inline WC_TYPE CharType(wchar32 ch) {
return (WC_TYPE)(NUnicode::NPrivate::CharInfo(ch) & CCL_MASK);
}
inline bool CharHasType(wchar32 ch, ui64 type_bits) {
return (SHIFT(NUnicode::CharType(ch)) & type_bits) != 0;
}
}
// all usefull properties
inline bool IsComposed(wchar32 ch) {
return NUnicode::NPrivate::CharInfo(ch) & (IS_COMPAT | IS_CANON);
}
inline bool IsCanonComposed(wchar32 ch) {
return NUnicode::NPrivate::CharInfo(ch) & IS_CANON;
}
inline bool IsCompatComposed(wchar32 ch) {
return NUnicode::NPrivate::CharInfo(ch) & IS_COMPAT;
}
inline bool IsWhitespace(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Cc_SPACE) | SHIFT(Zs_SPACE) | SHIFT(Zs_ZWSPACE) | SHIFT(Zl_LINE) | SHIFT(Zp_PARAGRAPH));
}
inline bool IsAsciiCntrl(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Cc_ASCII) | SHIFT(Cc_SPACE) | SHIFT(Cc_SEPARATOR));
}
inline bool IsBidiCntrl(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Cf_BIDI));
}
inline bool IsJoinCntrl(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Cf_JOIN));
}
inline bool IsFormatCntrl(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Cf_FORMAT));
}
inline bool IsIgnorableCntrl(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Cf_FORMAT) | SHIFT(Cf_JOIN) | SHIFT(Cf_BIDI) | SHIFT(Cf_ZWNBSP));
}
inline bool IsCntrl(wchar32 ch) {
return NUnicode::CharHasType(ch,
SHIFT(Cf_FORMAT) | SHIFT(Cf_JOIN) | SHIFT(Cf_BIDI) | SHIFT(Cf_ZWNBSP) |
SHIFT(Cc_ASCII) | SHIFT(Cc_SPACE) | SHIFT(Cc_SEPARATOR));
}
inline bool IsZerowidth(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Cf_FORMAT) | SHIFT(Cf_JOIN) | SHIFT(Cf_BIDI) | SHIFT(Cf_ZWNBSP) | SHIFT(Zs_ZWSPACE));
}
inline bool IsLineSep(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Zl_LINE));
}
inline bool IsParaSep(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Zp_PARAGRAPH));
}
inline bool IsDash(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Pd_DASH) | SHIFT(Pd_HYPHEN) | SHIFT(Sm_MINUS));
}
inline bool IsHyphen(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Pd_HYPHEN) | SHIFT(Po_HYPHEN));
}
inline bool IsQuotation(wchar32 ch) {
return NUnicode::CharHasType(ch,
SHIFT(Po_QUOTE) | SHIFT(Ps_QUOTE) | SHIFT(Pe_QUOTE) | SHIFT(Pi_QUOTE) |
SHIFT(Pf_QUOTE) | SHIFT(Po_SINGLE_QUOTE) | SHIFT(Ps_SINGLE_QUOTE) |
SHIFT(Pe_SINGLE_QUOTE) | SHIFT(Pi_SINGLE_QUOTE) | SHIFT(Pf_SINGLE_QUOTE));
}
inline bool IsSingleQuotation(wchar32 ch) {
return NUnicode::CharHasType(ch,
SHIFT(Po_SINGLE_QUOTE) | SHIFT(Ps_SINGLE_QUOTE) | SHIFT(Pe_SINGLE_QUOTE) |
SHIFT(Pi_SINGLE_QUOTE) | SHIFT(Pf_SINGLE_QUOTE));
}
inline bool IsTerminal(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Po_TERMINAL));
}
inline bool IsPairedPunct(wchar32 ch) {
return NUnicode::CharHasType(ch,
SHIFT(Ps_START) | SHIFT(Pe_END) | SHIFT(Ps_QUOTE) | SHIFT(Pe_QUOTE) |
SHIFT(Pi_QUOTE) | SHIFT(Pf_QUOTE) | SHIFT(Ps_SINGLE_QUOTE) |
SHIFT(Pe_SINGLE_QUOTE) | SHIFT(Pi_SINGLE_QUOTE) | SHIFT(Pf_SINGLE_QUOTE));
}
inline bool IsLeftPunct(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Ps_START) | SHIFT(Ps_QUOTE) | SHIFT(Ps_SINGLE_QUOTE));
}
inline bool IsRightPunct(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Pe_END) | SHIFT(Pe_QUOTE) | SHIFT(Pe_SINGLE_QUOTE));
}
inline bool IsCombining(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Mc_SPACING) | SHIFT(Mn_NONSPACING) | SHIFT(Me_ENCLOSING));
}
inline bool IsNonspacing(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Mn_NONSPACING) | SHIFT(Me_ENCLOSING));
}
inline bool IsAlphabetic(wchar32 ch) {
return NUnicode::CharHasType(ch,
SHIFT(Lu_UPPER) | SHIFT(Ll_LOWER) | SHIFT(Lt_TITLE) | SHIFT(Lm_EXTENDER) | SHIFT(Lm_LETTER) | SHIFT(Lo_OTHER) | SHIFT(Nl_LETTER));
}
inline bool IsIdeographic(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Lo_IDEOGRAPH) | SHIFT(Nl_IDEOGRAPH));
}
inline bool IsKatakana(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Lo_KATAKANA));
}
inline bool IsHiragana(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Lo_HIRAGANA));
}
inline bool IsHangulLeading(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Lo_LEADING));
}
inline bool IsHangulVowel(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Lo_VOWEL));
}
inline bool IsHangulTrailing(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Lo_TRAILING));
}
inline bool IsHexdigit(wchar32 ch) {
return NUnicode::NPrivate::CharInfo(ch) & IS_ASCII_XDIGIT;
}
inline bool IsDecdigit(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Nd_DIGIT));
}
inline bool IsNumeric(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Nd_DIGIT) | SHIFT(Nl_LETTER) | SHIFT(Nl_IDEOGRAPH) | SHIFT(No_OTHER));
}
inline bool IsCurrency(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Sc_CURRENCY));
}
inline bool IsMath(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Sm_MATH));
}
inline bool IsSymbol(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Sm_MATH) | SHIFT(Sm_MINUS) | SHIFT(Sc_CURRENCY) | SHIFT(Sk_MODIFIER) | SHIFT(So_OTHER));
}
inline bool IsLowSurrogate(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Cs_LOW));
}
inline bool IsHighSurrogate(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Cs_HIGH));
}
inline bool IsNonbreak(wchar32 ch) {
return NUnicode::NPrivate::CharInfo(ch) & IS_NONBREAK;
}
inline bool IsPrivate(wchar32 ch) {
return (NUnicode::NPrivate::CharInfo(ch) & IS_PRIVATE) && !NUnicode::CharHasType(ch, SHIFT(Cs_HIGH));
}
inline bool IsUnassigned(wchar32 ch) {
return (NUnicode::CharType(ch) == 0) && !(NUnicode::NPrivate::CharInfo(ch) & IS_PRIVATE);
}
inline bool IsPrivateHighSurrogate(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Cs_HIGH)) && (NUnicode::NPrivate::CharInfo(ch) & IS_PRIVATE);
}
// transformations
inline wchar32 ToLower(wchar32 ch) {
return static_cast<wchar32>(ch + NUnicode::NPrivate::CharProperty(ch).Lower);
}
inline wchar32 ToUpper(wchar32 ch) {
return static_cast<wchar32>(ch + NUnicode::NPrivate::CharProperty(ch).Upper);
}
inline wchar32 ToTitle(wchar32 ch) {
return static_cast<wchar32>(ch + NUnicode::NPrivate::CharProperty(ch).Title);
}
inline int ToDigit(wchar32 ch) {
ui32 i = NUnicode::NPrivate::CharInfo(ch);
return (i & IS_DIGIT) ? static_cast<int>(i >> SVAL_OFFSET) : -1;
}
// BIDI properties
inline bool IsBidiLeft(wchar32 ch) {
return NUnicode::NPrivate::IsBidi(ch, 1);
}
inline bool IsBidiRight(wchar32 ch) {
return NUnicode::NPrivate::IsBidi(ch, 2);
}
inline bool IsBidiEuronum(wchar32 ch) {
return NUnicode::NPrivate::IsBidi(ch, 3);
}
inline bool IsBidiEurosep(wchar32 ch) {
return NUnicode::NPrivate::IsBidi(ch, 4);
}
inline bool IsBidiEuroterm(wchar32 ch) {
return NUnicode::NPrivate::IsBidi(ch, 5);
}
inline bool IsBidiArabnum(wchar32 ch) {
return NUnicode::NPrivate::IsBidi(ch, 6);
}
inline bool IsBidiCommsep(wchar32 ch) {
return NUnicode::NPrivate::IsBidi(ch, 7);
}
inline bool IsBidiBlocksep(wchar32 ch) {
return NUnicode::NPrivate::IsBidi(ch, 8);
}
inline bool IsBidiSegmsep(wchar32 ch) {
return NUnicode::NPrivate::IsBidi(ch, 9);
}
inline bool IsBidiSpace(wchar32 ch) {
return NUnicode::NPrivate::IsBidi(ch, 10);
}
inline bool IsBidiNeutral(wchar32 ch) {
return NUnicode::NPrivate::IsBidi(ch, 11);
}
inline bool IsBidiNotappl(wchar32 ch) {
return NUnicode::NPrivate::IsBidi(ch, 0);
}
inline bool IsSpace(wchar32 ch) {
return IsWhitespace(ch);
}
inline bool IsLower(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Ll_LOWER));
}
inline bool IsUpper(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Lu_UPPER));
}
inline bool IsTitle(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Lt_TITLE));
}
inline bool IsAlpha(wchar32 ch) {
return NUnicode::CharHasType(ch,
SHIFT(Lu_UPPER) | SHIFT(Ll_LOWER) | SHIFT(Lt_TITLE) | SHIFT(Lm_LETTER) | SHIFT(Lm_EXTENDER) |
SHIFT(Lo_OTHER) | SHIFT(Lo_IDEOGRAPH) | SHIFT(Lo_KATAKANA) | SHIFT(Lo_HIRAGANA) |
SHIFT(Lo_LEADING) | SHIFT(Lo_VOWEL) | SHIFT(Lo_TRAILING));
}
inline bool IsAlnum(wchar32 ch) {
return NUnicode::CharHasType(ch,
SHIFT(Lu_UPPER) | SHIFT(Ll_LOWER) | SHIFT(Lt_TITLE) | SHIFT(Lm_LETTER) | SHIFT(Lm_EXTENDER) |
SHIFT(Lo_OTHER) | SHIFT(Lo_IDEOGRAPH) | SHIFT(Lo_KATAKANA) | SHIFT(Lo_HIRAGANA) |
SHIFT(Lo_LEADING) | SHIFT(Lo_VOWEL) | SHIFT(Lo_TRAILING) |
SHIFT(Nd_DIGIT) | SHIFT(Nl_LETTER) | SHIFT(Nl_IDEOGRAPH) | SHIFT(No_OTHER));
}
inline bool IsPunct(wchar32 ch) {
return NUnicode::CharHasType(ch,
SHIFT(Pd_DASH) |
SHIFT(Pd_HYPHEN) | SHIFT(Ps_START) | SHIFT(Ps_QUOTE) | SHIFT(Pe_END) | SHIFT(Pe_QUOTE) | SHIFT(Pc_CONNECTOR) |
SHIFT(Po_OTHER) | SHIFT(Po_QUOTE) | SHIFT(Po_TERMINAL) | SHIFT(Po_EXTENDER) | SHIFT(Po_HYPHEN) |
SHIFT(Pi_QUOTE) | SHIFT(Pf_QUOTE));
}
inline bool IsXdigit(wchar32 ch) {
return IsHexdigit(ch);
}
inline bool IsDigit(wchar32 ch) {
return IsDecdigit(ch);
}
inline bool IsCommonDigit(wchar32 ch) {
// IsDigit returns true for some exotic symbols like "VAI DIGIT TWO" (U+A622)
// and cannot be used safely with FromString() convertors
const wchar32 ZERO = '0';
const wchar32 NINE = '9';
return ch >= ZERO && ch <= NINE;
}
inline bool IsGraph(wchar32 ch) {
return IsAlnum(ch) || IsPunct(ch) || IsSymbol(ch);
}
inline bool IsBlank(wchar32 ch) {
return NUnicode::CharHasType(ch, SHIFT(Zs_SPACE) | SHIFT(Zs_ZWSPACE)) || ch == '\t';
}
inline bool IsPrint(wchar32 ch) {
return IsAlnum(ch) || IsPunct(ch) || IsSymbol(ch) || IsBlank(ch);
}
inline bool IsRomanDigit(wchar32 ch) {
if (NUnicode::CharHasType(ch, SHIFT(Nl_LETTER)) && 0x2160 <= ch && ch <= 0x2188)
return true;
if (ch < 127) {
switch (static_cast<char>(::ToLower(ch))) {
case 'i':
case 'v':
case 'x':
case 'l':
case 'c':
case 'd':
case 'm':
return true;
}
}
return false;
}
#undef SHIFT
|