Coverage Report

Created: 2026-09-28 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/icu/icu4c/source/common/rbbistbl.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
//  file:  rbbistbl.cpp    Implementation of the ICU RBBISymbolTable class
5
//
6
/*
7
***************************************************************************
8
*   Copyright (C) 2002-2014 International Business Machines Corporation
9
*   and others. All rights reserved.
10
***************************************************************************
11
*/
12
13
#include "unicode/utypes.h"
14
15
#if !UCONFIG_NO_BREAK_ITERATION
16
17
#include "unicode/unistr.h"
18
#include "unicode/uniset.h"
19
#include "unicode/uchar.h"
20
#include "unicode/parsepos.h"
21
22
#include "cstr.h"
23
#include "rbbinode.h"
24
#include "rbbirb.h"
25
#include "umutex.h"
26
27
28
//
29
//  RBBISymbolTableEntry_deleter    Used by the UHashTable to delete the contents
30
//                                  when the hash table is deleted.
31
//
32
U_CDECL_BEGIN
33
0
static void U_CALLCONV RBBISymbolTableEntry_deleter(void *p) {
34
0
    icu::RBBISymbolTableEntry *px = (icu::RBBISymbolTableEntry *)p;
35
0
    delete px;
36
0
}
37
U_CDECL_END
38
39
40
41
U_NAMESPACE_BEGIN
42
43
RBBISymbolTable::RBBISymbolTable(RBBIRuleScanner *rs, const UnicodeString &rules, UErrorCode &status)
44
0
    : fRules(rules), fRuleScanner(rs)
45
0
{
46
0
    fHashTable       = nullptr;
47
48
0
    fHashTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, nullptr, &status);
49
    // uhash_open checks status
50
0
    if (U_FAILURE(status)) {
51
0
        return;
52
0
    }
53
0
    uhash_setValueDeleter(fHashTable, RBBISymbolTableEntry_deleter);
54
0
}
55
56
57
58
RBBISymbolTable::~RBBISymbolTable()
59
0
{
60
0
    uhash_close(fHashTable);
61
0
}
62
63
64
//
65
//  RBBISymbolTable::lookup       This function from the abstract symbol table interface
66
//                                looks up a variable name and returns a UnicodeString
67
//                                containing the substitution text.
68
//
69
//                                The variable name does NOT include the leading $.
70
//
71
const UnicodeString  *RBBISymbolTable::lookup(const UnicodeString& s) const
72
0
{
73
0
    const RBBISymbolTableEntry* const el =
74
0
        static_cast<const RBBISymbolTableEntry*>(uhash_get(fHashTable, &s));
75
0
    if (el == nullptr) {
76
0
        return nullptr;
77
0
    }
78
0
    const RBBINode& exprNode = *el->val->fLeftChild; // Root node of expression for variable
79
    // Return the original source string for the expression.
80
    // Note that for set-valued variables used in UnicodeSet expressions, this would be rejected by
81
    // the UnicodeSet parser if the source itself contains variable references.  For instance, with
82
    //     $CaseIgnorable   = [[:Mn:][:Me:][:Cf:][:Lm:][:Sk:] \u0027 \u00AD \u2019];
83
    //     $Cased = [[:Upper_Case:][:Lower_Case:][:Lt:] - $CaseIgnorable];
84
    // If lookupSet were not overridden, when parsing the right-hand side of
85
    //     $NotCased        = [[^ $Cased] - $CaseIgnorable];
86
    // there would be a call to lookup("Cased") which would return
87
    //     "[[:Upper_Case:][:Lower_Case:][:Lt:]-$CaseIgnorable]". This contains a variable, which is
88
    // disallowed by the UnicodeSet parser inside a variable expansion.
89
    // However, set-valued variables are pre-parsed, and returned by lookupSet instead, so this call
90
    // to lookup() never happens; instead, lookupSet("CaseIgnorable") is called when computing
91
    // $Cased and returns the non-null value of $CaseIgnorable, and then when computing $NotCased,
92
    // lookupSet("Cased") returns the value computed for $Cased.
93
0
    return &exprNode.fText;
94
0
}
95
96
0
const UnicodeSet* RBBISymbolTable::lookupSet(const UnicodeString& s) const {
97
0
    const RBBISymbolTableEntry* const el = static_cast<const RBBISymbolTableEntry*>(uhash_get(fHashTable, &s));
98
0
    if (el == nullptr) {
99
0
        return nullptr;
100
0
    }
101
0
    const RBBINode& exprNode = *el->val->fLeftChild;
102
0
    if (exprNode.fType == RBBINode::setRef) {
103
0
        return exprNode.fLeftChild->fInputSet;
104
0
    } else {
105
0
        return nullptr;
106
0
    }
107
0
}
108
109
110
111
//  No longer used, see ICU-23297.
112
0
const UnicodeFunctor* RBBISymbolTable::lookupMatcher(UChar32 /*ch*/) const {
113
0
    return nullptr;
114
0
}
115
116
//
117
// RBBISymbolTable::parseReference   This function from the abstract symbol table interface
118
//                                   looks for a $variable name in the source text.
119
//                                   It does not look it up, only scans for it.
120
//                                   It is used by the UnicodeSet parser.
121
//
122
//                                   This implementation is lifted pretty much verbatim
123
//                                   from the rules based transliterator implementation.
124
//                                   I didn't see an obvious way of sharing it.
125
//
126
UnicodeString   RBBISymbolTable::parseReference(const UnicodeString& text,
127
                                                ParsePosition& pos, int32_t limit) const
128
0
{
129
0
    int32_t start = pos.getIndex();
130
0
    int32_t i = start;
131
0
    UnicodeString result;
132
0
    while (i < limit) {
133
0
        char16_t c = text.charAt(i);
134
0
        if ((i==start && !u_isIDStart(c)) || !u_isIDPart(c)) {
135
0
            break;
136
0
        }
137
0
        ++i;
138
0
    }
139
0
    if (i == start) { // No valid name chars
140
0
        return result; // Indicate failure with empty string
141
0
    }
142
0
    pos.setIndex(i);
143
0
    text.extractBetween(start, i, result);
144
0
    return result;
145
0
}
146
147
148
149
//
150
// RBBISymbolTable::lookupNode      Given a key (a variable name), return the
151
//                                  corresponding RBBI Node.  If there is no entry
152
//                                  in the table for this name, return nullptr.
153
//
154
0
RBBINode       *RBBISymbolTable::lookupNode(const UnicodeString &key) const{
155
156
0
    RBBINode             *retNode = nullptr;
157
0
    RBBISymbolTableEntry *el;
158
159
0
    el = static_cast<RBBISymbolTableEntry*>(uhash_get(fHashTable, &key));
160
0
    if (el != nullptr) {
161
0
        retNode = el->val;
162
0
    }
163
0
    return retNode;
164
0
}
165
166
167
//
168
//    RBBISymbolTable::addEntry     Add a new entry to the symbol table.
169
//                                  Indicate an error if the name already exists -
170
//                                    this will only occur in the case of duplicate
171
//                                    variable assignments.
172
//
173
0
void            RBBISymbolTable::addEntry  (const UnicodeString &key, RBBINode *val, UErrorCode &err) {
174
0
    RBBISymbolTableEntry *e;
175
    /* test for buffer overflows */
176
0
    if (U_FAILURE(err)) {
177
0
        return;
178
0
    }
179
0
    e = static_cast<RBBISymbolTableEntry*>(uhash_get(fHashTable, &key));
180
0
    if (e != nullptr) {
181
0
        err = U_BRK_VARIABLE_REDFINITION;
182
0
        return;
183
0
    }
184
185
0
    e = new RBBISymbolTableEntry;
186
0
    if (e == nullptr) {
187
0
        err = U_MEMORY_ALLOCATION_ERROR;
188
0
        return;
189
0
    }
190
0
    e->key = key;
191
0
    e->val = val;
192
0
    uhash_put( fHashTable, &e->key, e, &err);
193
0
}
194
195
196
0
RBBISymbolTableEntry::RBBISymbolTableEntry() : UMemory(), key(), val(nullptr) {}
197
198
0
RBBISymbolTableEntry::~RBBISymbolTableEntry() {
199
    // The "val" of a symbol table entry is a variable reference node.
200
    // The l. child of the val is the rhs expression from the assignment.
201
    // Unlike other node types, children of variable reference nodes are not
202
    //    automatically recursively deleted.  We do it manually here.
203
0
    delete val->fLeftChild;
204
0
    val->fLeftChild = nullptr;
205
206
0
    delete  val;
207
208
    // Note: the key UnicodeString is destructed by virtue of being in the object by value.
209
0
}
210
211
212
//
213
//  RBBISymbolTable::print    Debugging function, dump out the symbol table contents.
214
//
215
#ifdef RBBI_DEBUG
216
void RBBISymbolTable::rbbiSymtablePrint() const {
217
    RBBIDebugPrintf("Variable Definitions Symbol Table\n"
218
           "Name                  Node         serial  String Val\n"
219
           "-------------------------------------------------------------------\n");
220
221
    int32_t pos = UHASH_FIRST;
222
    const UHashElement  *e   = nullptr;
223
    for (;;) {
224
        e = uhash_nextElement(fHashTable,  &pos);
225
        if (e == nullptr ) {
226
            break;
227
        }
228
        RBBISymbolTableEntry  *s   = (RBBISymbolTableEntry *)e->value.pointer;
229
230
        RBBIDebugPrintf("%-19s   %8p %7d ", CStr(s->key)(), (void *)s->val, s->val->fSerialNum);
231
        RBBIDebugPrintf(" %s\n", CStr(s->val->fLeftChild->fText)());
232
    }
233
234
    RBBIDebugPrintf("\nParsed Variable Definitions\n");
235
    pos = -1;
236
    for (;;) {
237
        e = uhash_nextElement(fHashTable,  &pos);
238
        if (e == nullptr ) {
239
            break;
240
        }
241
        RBBISymbolTableEntry  *s   = (RBBISymbolTableEntry *)e->value.pointer;
242
        RBBIDebugPrintf("%s\n", CStr(s->key)());
243
        RBBINode::printTree(s->val, true);
244
        RBBINode::printTree(s->val->fLeftChild, false);
245
        RBBIDebugPrintf("\n");
246
    }
247
}
248
#endif
249
250
251
252
253
254
U_NAMESPACE_END
255
256
#endif /* #if !UCONFIG_NO_BREAK_ITERATION */