/src/icu/icu4c/source/i18n/regexst.cpp
Line | Count | Source |
1 | | // © 2016 and later: Unicode, Inc. and others. |
2 | | // License & terms of use: http://www.unicode.org/copyright.html |
3 | | // |
4 | | // regexst.h |
5 | | // |
6 | | // Copyright (C) 2004-2015, International Business Machines Corporation and others. |
7 | | // All Rights Reserved. |
8 | | // |
9 | | // This file contains class RegexStaticSets |
10 | | // |
11 | | // This class is internal to the regular expression implementation. |
12 | | // For the public Regular Expression API, see the file "unicode/regex.h" |
13 | | // |
14 | | // RegexStaticSets groups together the common UnicodeSets that are needed |
15 | | // for compiling or executing RegularExpressions. This grouping simplifies |
16 | | // the thread safe lazy creation and sharing of these sets across |
17 | | // all instances of regular expressions. |
18 | | // |
19 | | #include "unicode/utypes.h" |
20 | | |
21 | | #if !UCONFIG_NO_REGULAR_EXPRESSIONS |
22 | | |
23 | | #include "unicode/unistr.h" |
24 | | #include "unicode/uniset.h" |
25 | | #include "unicode/uchar.h" |
26 | | #include "unicode/regex.h" |
27 | | #include "uprops.h" |
28 | | #include "cmemory.h" |
29 | | #include "cstring.h" |
30 | | #include "uassert.h" |
31 | | #include "ucln_in.h" |
32 | | #include "umutex.h" |
33 | | |
34 | | #include "regexcst.h" // Contains state table for the regex pattern parser. |
35 | | // generated by a Perl script. |
36 | | #include "regexst.h" |
37 | | |
38 | | U_NAMESPACE_BEGIN |
39 | | |
40 | | // "Rule Char" Characters are those with special meaning, and therefore |
41 | | // need to be escaped to appear as literals in a regexp. |
42 | | constexpr char16_t const *gRuleSet_rule_chars = u"*?+[(){}^$|\\."; |
43 | | |
44 | | // |
45 | | // The backslash escape characters that ICU's unescape() function will handle. |
46 | | // |
47 | | constexpr char16_t const *gUnescapeChars = u"acefnrtuUx"; |
48 | | |
49 | | // |
50 | | // Unicode Set pattern for Regular Expression \w |
51 | | // |
52 | | constexpr char16_t const *gIsWordPattern = u"[\\p{Alphabetic}\\p{M}\\p{Nd}\\p{Pc}\\u200c\\u200d]"; |
53 | | |
54 | | // |
55 | | // Unicode Set Definitions for Regular Expression \s |
56 | | // |
57 | | constexpr char16_t const *gIsSpacePattern = u"[\\p{WhiteSpace}]"; |
58 | | |
59 | | // |
60 | | // UnicodeSets used in implementation of Grapheme Cluster detection, \X |
61 | | // |
62 | | constexpr char16_t const *gGC_ControlPattern = u"[[:Zl:][:Zp:][:Cc:][:Cf:]-[:Grapheme_Extend:]]"; |
63 | | constexpr char16_t const *gGC_ExtendPattern = u"[\\p{Grapheme_Extend}]"; |
64 | | constexpr char16_t const *gGC_LPattern = u"[\\p{Hangul_Syllable_Type=L}]"; |
65 | | constexpr char16_t const *gGC_VPattern = u"[\\p{Hangul_Syllable_Type=V}]"; |
66 | | constexpr char16_t const *gGC_TPattern = u"[\\p{Hangul_Syllable_Type=T}]"; |
67 | | constexpr char16_t const *gGC_LVPattern = u"[\\p{Hangul_Syllable_Type=LV}]"; |
68 | | constexpr char16_t const *gGC_LVTPattern = u"[\\p{Hangul_Syllable_Type=LVT}]"; |
69 | | |
70 | | |
71 | | RegexStaticSets *RegexStaticSets::gStaticSets = nullptr; |
72 | | UInitOnce gStaticSetsInitOnce {}; |
73 | | |
74 | | |
75 | 2 | RegexStaticSets::RegexStaticSets(UErrorCode *status) { |
76 | | // Initialize the shared static sets to their correct values. |
77 | 2 | fUnescapeCharSet.addAll(UnicodeString(true, gUnescapeChars, -1)).freeze(); |
78 | 2 | fPropSets[URX_ISWORD_SET].applyPattern(UnicodeString(true, gIsWordPattern, -1), *status).freeze(); |
79 | 2 | fPropSets[URX_ISSPACE_SET].applyPattern(UnicodeString(true, gIsSpacePattern, -1), *status).freeze(); |
80 | 2 | fPropSets[URX_GC_EXTEND].applyPattern(UnicodeString(true, gGC_ExtendPattern, -1), *status).freeze(); |
81 | 2 | fPropSets[URX_GC_CONTROL].applyPattern(UnicodeString(true, gGC_ControlPattern, -1), *status).freeze(); |
82 | 2 | fPropSets[URX_GC_L].applyPattern(UnicodeString(true, gGC_LPattern, -1), *status).freeze(); |
83 | 2 | fPropSets[URX_GC_V].applyPattern(UnicodeString(true, gGC_VPattern, -1), *status).freeze(); |
84 | 2 | fPropSets[URX_GC_T].applyPattern(UnicodeString(true, gGC_TPattern, -1), *status).freeze(); |
85 | 2 | fPropSets[URX_GC_LV].applyPattern(UnicodeString(true, gGC_LVPattern, -1), *status).freeze(); |
86 | 2 | fPropSets[URX_GC_LVT].applyPattern(UnicodeString(true, gGC_LVTPattern, -1), *status).freeze(); |
87 | | |
88 | | |
89 | | // |
90 | | // "Normal" is the set of characters that don't need special handling |
91 | | // when finding grapheme cluster boundaries. |
92 | | // |
93 | 2 | fPropSets[URX_GC_NORMAL].complement(); |
94 | 2 | fPropSets[URX_GC_NORMAL].remove(0xac00, 0xd7a4); |
95 | 2 | fPropSets[URX_GC_NORMAL].removeAll(fPropSets[URX_GC_CONTROL]); |
96 | 2 | fPropSets[URX_GC_NORMAL].removeAll(fPropSets[URX_GC_L]); |
97 | 2 | fPropSets[URX_GC_NORMAL].removeAll(fPropSets[URX_GC_V]); |
98 | 2 | fPropSets[URX_GC_NORMAL].removeAll(fPropSets[URX_GC_T]); |
99 | 2 | fPropSets[URX_GC_NORMAL].freeze(); |
100 | | |
101 | | // Initialize the 8-bit fast bit sets from the parallel full |
102 | | // UnicodeSets. |
103 | | // |
104 | | // TODO: 25 Oct 2019 are these fast 8-bit sets worth keeping? |
105 | | // Measured 3.5% gain on (non) matching with the pattern "x(?:\\S+)+x" |
106 | | // This runs in exponential time, making it easy to adjust the time for |
107 | | // convenient measuring. |
108 | | // |
109 | | // This 8 bit optimization dates from the early days of ICU, |
110 | | // with a less optimized UnicodeSet. At the time, the difference |
111 | | // was substantial. |
112 | | |
113 | 28 | for (int32_t i=0; i<URX_LAST_SET; i++) { |
114 | 26 | fPropSets8[i].init(&fPropSets[i]); |
115 | 26 | } |
116 | | |
117 | | // Sets used while parsing rules, but not referenced from the parse state table |
118 | 2 | fRuleSets[kRuleSet_rule_char-128] |
119 | 2 | .addAll(UnicodeString(gRuleSet_rule_chars)).complement().freeze(); |
120 | | |
121 | 2 | fRuleSets[kRuleSet_digit_char-128].add(u'0', u'9').freeze(); |
122 | 2 | fRuleSets[kRuleSet_ascii_letter-128].add(u'A', u'Z').add(u'a', u'z').freeze(); |
123 | 2 | fRuleDigitsAlias = &fRuleSets[kRuleSet_digit_char-128]; |
124 | | |
125 | | // Finally, initialize an empty UText string for utility purposes |
126 | 2 | fEmptyText = utext_openUChars(nullptr, nullptr, 0, status); |
127 | | |
128 | 2 | } |
129 | | |
130 | | |
131 | 0 | RegexStaticSets::~RegexStaticSets() { |
132 | 0 | fRuleDigitsAlias = nullptr; |
133 | 0 | utext_close(fEmptyText); |
134 | 0 | } |
135 | | |
136 | | |
137 | | //------------------------------------------------------------------------------ |
138 | | // |
139 | | // regex_cleanup Memory cleanup function, free/delete all |
140 | | // cached memory. Called by ICU's u_cleanup() function. |
141 | | // |
142 | | //------------------------------------------------------------------------------ |
143 | | |
144 | | U_CDECL_BEGIN |
145 | | static UBool U_CALLCONV |
146 | 0 | regex_cleanup() { |
147 | 0 | delete RegexStaticSets::gStaticSets; |
148 | 0 | RegexStaticSets::gStaticSets = nullptr; |
149 | 0 | gStaticSetsInitOnce.reset(); |
150 | 0 | return true; |
151 | 0 | } |
152 | | |
153 | 2 | static void U_CALLCONV initStaticSets(UErrorCode &status) { |
154 | 2 | U_ASSERT(RegexStaticSets::gStaticSets == nullptr); |
155 | 2 | ucln_i18n_registerCleanup(UCLN_I18N_REGEX, regex_cleanup); |
156 | 2 | RegexStaticSets::gStaticSets = new RegexStaticSets(&status); |
157 | 2 | if (U_FAILURE(status)) { |
158 | 0 | delete RegexStaticSets::gStaticSets; |
159 | 0 | RegexStaticSets::gStaticSets = nullptr; |
160 | 0 | } |
161 | 2 | if (RegexStaticSets::gStaticSets == nullptr && U_SUCCESS(status)) { |
162 | 0 | status = U_MEMORY_ALLOCATION_ERROR; |
163 | 0 | } |
164 | 2 | } |
165 | | U_CDECL_END |
166 | | |
167 | 20.8k | void RegexStaticSets::initGlobals(UErrorCode *status) { |
168 | 20.8k | umtx_initOnce(gStaticSetsInitOnce, &initStaticSets, *status); |
169 | 20.8k | } |
170 | | |
171 | | U_NAMESPACE_END |
172 | | #endif // !UCONFIG_NO_REGULAR_EXPRESSIONS |