source: icGREP/icgrep-devel/icgrep/UCD/PropertyObjects.cpp @ 5683

Last change on this file since 5683 was 5683, checked in by cameron, 2 years ago

Support for \p{property=@identity@}

File size: 14.5 KB
Line 
1/*
2 *  Copyright (c) 2017 International Characters, Inc.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 *  icgrep is a trademark of International Characters, Inc.
5 *
6 */
7
8#include "PropertyObjects.h"
9#include "PropertyObjectTable.h"
10#include <llvm/Support/Casting.h>
11#include <algorithm>
12#include <assert.h>
13#include <sstream>
14#include <llvm/Support/raw_ostream.h>
15#include <llvm/Support/ErrorHandling.h>
16#include <toolchain/grep_pipeline.h>
17#include <util/aligned_allocator.h>
18#include <re/re_analysis.h>
19using namespace llvm;
20
21namespace UCD {
22
23std::string canonicalize_value_name(const std::string & prop_or_val) {
24    std::locale loc;
25    std::stringstream s;
26
27    for (char c : prop_or_val) {
28        if ((c != '_') && (c != ' ') && (c != '-')) {
29            s << std::tolower(c, loc);
30        }
31    }
32    return s.str();
33}
34
35const std::string & PropertyObject::GetPropertyValueGrepString() {
36    llvm::report_fatal_error("Property Value Grep String unsupported.");
37}
38
39const UnicodeSet PropertyObject::GetCodepointSet(const std::string &) {
40    llvm::report_fatal_error("Property " + UCD::property_full_name[the_property] + " unsupported.");
41}
42
43const UnicodeSet PropertyObject::GetCodepointSetMatchingPattern(re::RE * pattern) {
44    llvm::report_fatal_error("GetCodepointSetMatchingPattern unsupported");
45}
46   
47const UnicodeSet EnumeratedPropertyObject::GetCodepointSet(const std::string & value_spec) {
48    const int property_enum_val = GetPropertyValueEnumCode(value_spec);
49    if (property_enum_val < 0) {
50        llvm::report_fatal_error("Enumerated Property " + UCD::property_full_name[the_property] + ": unknown value: " + value_spec);
51    }
52    return GetCodepointSet(property_enum_val);
53}
54   
55const UnicodeSet PropertyObject::GetReflexiveSet() {
56    return UnicodeSet();
57}
58
59
60class PropertyValueAccumulator : public grep::MatchAccumulator {
61public:
62   
63    PropertyValueAccumulator(const char * searchBuffer, std::vector<std::string> & accumulatedPropertyValues)
64    : mSearchBuffer(searchBuffer), mParsedPropertyValueSet(accumulatedPropertyValues) {}
65   
66    void accumulate_match(const size_t lineNum, size_t line_start, size_t line_end) override;
67private:
68    const char * mSearchBuffer;
69    std::vector<std::string> & mParsedPropertyValueSet;
70};
71void PropertyValueAccumulator::accumulate_match(const size_t lineNum, size_t line_start, size_t line_end) {
72    assert (line_start <= line_end);
73    mParsedPropertyValueSet.emplace_back(mSearchBuffer + line_start, mSearchBuffer + line_end);
74}
75
76    const UnicodeSet EnumeratedPropertyObject::GetCodepointSetMatchingPattern(re::RE * pattern) {
77   
78   
79        AlignedAllocator<char, 32> alloc;
80        std::vector<std::string> accumulatedValues;
81       
82        const std::string & str = GetPropertyValueGrepString();
83       
84        const unsigned segmentSize = 8;
85        const auto n = str.length();
86        const auto w = 256 * segmentSize;
87        const auto m = w - (n % w);
88       
89        char * aligned = alloc.allocate(n + m, 0);
90        std::memcpy(aligned, str.data(), n);
91        std::memset(aligned + n, 0, m);
92       
93        PropertyValueAccumulator accum(aligned, accumulatedValues);
94        grepBuffer(pattern, aligned, n, & accum);
95        alloc.deallocate(aligned, 0);
96       
97        UnicodeSet a;
98        for (auto v : accumulatedValues) {
99            int e = GetPropertyValueEnumCode(v);
100            a = a + GetCodepointSet(e);
101        }
102        return a;
103}
104
105const UnicodeSet & EnumeratedPropertyObject::GetCodepointSet(const int property_enum_val) const {
106    assert (property_enum_val >= 0);
107    return *(property_value_sets[property_enum_val]);
108}
109
110std::vector<UnicodeSet> & EnumeratedPropertyObject::GetEnumerationBasisSets() {
111    // Return the previously computed vector of basis sets, if it exists.
112    if (LLVM_UNLIKELY(enumeration_basis_sets.empty())) {
113        // Otherwise compute and return.
114        // Basis set i is the set of all codepoints whose numerical enumeration code e
115        // has bit i set, i.e., (e >> i) & 1 == 1.
116        unsigned basis_count = 1;
117        while ((1UL << basis_count) < independent_enum_count) {
118            basis_count++;
119        }
120        for (unsigned i = 0; i < basis_count; i++) {
121            enumeration_basis_sets.push_back(UnicodeSet());
122            for (unsigned e = 0; e < independent_enum_count; e++) {
123                if (((e >> i) & 1UL) == 0) {
124                    enumeration_basis_sets[i] = enumeration_basis_sets[i] + *property_value_sets[e];
125                }
126            }
127        }
128    }
129    return enumeration_basis_sets;
130}
131
132const std::string & EnumeratedPropertyObject::GetPropertyValueGrepString() {
133    if (LLVM_LIKELY(mPropertyValueGrepString.empty())) {
134        std::stringstream buffer;
135        for (unsigned i = 0; i != property_value_full_names.size(); i++) {
136            buffer << property_value_full_names[i] + "\n";
137        }
138        for (unsigned i = 0; i != property_value_enum_names.size(); i++) {
139            if (property_value_enum_names[i] == property_value_full_names[i]) continue;
140            buffer << property_value_enum_names[i] + "\n";
141        }
142        for (auto & a : property_value_aliases) {
143            buffer << a.first + "\n";
144        }
145        mPropertyValueGrepString = buffer.str();
146    }
147    return mPropertyValueGrepString;
148}
149
150int EnumeratedPropertyObject::GetPropertyValueEnumCode(const std::string & value_spec) {
151    // The canonical full names are not stored in the precomputed alias map,
152    // to save space in the executable.   Add them if the property is used.
153    if (uninitialized) {
154        for (unsigned i = 0; i != property_value_full_names.size(); i++) {
155            property_value_aliases.insert({canonicalize_value_name(property_value_full_names[i]), i});
156        }
157        for (unsigned i = 0; i != property_value_enum_names.size(); i++) {
158            property_value_aliases.insert({canonicalize_value_name(property_value_enum_names[i]), i});
159        }
160        uninitialized = false;
161    }
162    const auto valit = property_value_aliases.find(canonicalize_value_name(value_spec));
163    if (valit == property_value_aliases.end())
164        return -1;
165    return valit->second;
166}
167
168PropertyObject::iterator ExtensionPropertyObject::begin() const {
169    if (const auto * obj = dyn_cast<EnumeratedPropertyObject>(property_object_table[base_property])) {
170        return obj->begin();
171    }
172    llvm::report_fatal_error("Iterators unsupported for this type of PropertyObject.");
173}
174
175PropertyObject::iterator ExtensionPropertyObject::end() const {
176    if (const auto * obj = dyn_cast<EnumeratedPropertyObject>(property_object_table[base_property])) {
177        return obj->end();
178    }
179    llvm::report_fatal_error("Iterators unsupported for this type of PropertyObject.");
180}
181
182const UnicodeSet ExtensionPropertyObject::GetCodepointSet(const std::string & value_spec) {
183    int property_enum_val = GetPropertyValueEnumCode(value_spec);
184    if (property_enum_val == -1) {
185        llvm::report_fatal_error("Extension Property " + UCD::property_full_name[the_property] +  ": unknown value: " + value_spec);
186    }
187    return GetCodepointSet(property_enum_val);
188}
189
190const UnicodeSet & ExtensionPropertyObject::GetCodepointSet(const int property_enum_val) const {
191    assert (property_enum_val >= 0);
192    return *(property_value_sets[property_enum_val]);
193}
194
195int ExtensionPropertyObject::GetPropertyValueEnumCode(const std::string & value_spec) {
196    return cast<EnumeratedPropertyObject>(property_object_table[base_property])->GetPropertyValueEnumCode(value_spec);
197}
198
199const std::string & ExtensionPropertyObject::GetPropertyValueGrepString() {
200    return property_object_table[base_property]->GetPropertyValueGrepString();
201}
202
203const UnicodeSet BinaryPropertyObject::GetCodepointSet(const std::string & value_spec) {
204    int property_enum_val = Binary_ns::Y;
205    if (value_spec.length() != 0) {
206        auto valit = Binary_ns::aliases_only_map.find(canonicalize_value_name(value_spec));
207        if (valit == Binary_ns::aliases_only_map.end()) {
208            llvm::report_fatal_error("Binary Property " + UCD::property_full_name[the_property] +  ": bad value: " + value_spec);
209        }
210        property_enum_val = valit->second;
211    }
212    return GetCodepointSet(property_enum_val);
213}
214
215const UnicodeSet & BinaryPropertyObject::GetCodepointSet(const int property_enum_val) {
216    if (property_enum_val == Binary_ns::Y) {
217        return mY;
218    }
219    if (mNoUninitialized) {
220        mN = ~mY;
221        mNoUninitialized = false;
222    }
223    return mN;
224}
225
226const UnicodeSet BinaryPropertyObject::GetCodepointSetMatchingPattern(re::RE * pattern) {
227    llvm::report_fatal_error("Enumerated Property GetCodepointSetMatchingPattern not yet implemented");
228}
229   
230const std::string & BinaryPropertyObject::GetPropertyValueGrepString() {
231    if (mPropertyValueGrepString.empty()) {
232        std::stringstream buffer;
233        for (const auto & prop : Binary_ns::aliases_only_map) {
234            buffer << std::get<0>(prop) + "\n";
235        }
236        mPropertyValueGrepString = buffer.str();
237    }
238    return mPropertyValueGrepString;
239}
240   
241const unsigned firstCodepointLengthAndVal(const std::string & s, codepoint_t & cp) {
242    size_t lgth = s.length();
243    if (lgth == 0) return 0;
244    unsigned char s0 = s[0];
245    cp = static_cast<codepoint_t>(s0);
246    if (s0 < 0x80) return 1;
247    if (lgth == 1) return 0;  // invalid UTF-8
248    cp = ((cp & 0x1F) << 6) | (s[1] & 0x3F);
249    if ((s0 >= 0xC2) && (s0 <= 0xDF)) return 2;
250    if (lgth == 2) return 0;  // invalid UTF-8
251    cp = ((cp & 0x3FFF) << 6) | (s[2] & 0x3F);
252    if ((s0 >= 0xE0) && (s0 <= 0xEF)) return 3;
253    if (lgth == 3) return 0;  // invalid UTF-8
254    cp = ((cp & 0x7FFF) << 6) | (s[3] & 0x3F);
255    if ((s0 >= 0xF0) && (s0 <= 0xF4)) return 4;
256    return 0;
257}
258   
259class SetByLineNumberAccumulator : public grep::MatchAccumulator {
260public:
261   
262    SetByLineNumberAccumulator(const std::vector<UCD::codepoint_t> & cps)
263    : mCodepointTableByLineNum(cps) {}
264   
265    void accumulate_match(const size_t lineNum, size_t line_start, size_t line_end) override;
266    UnicodeSet getAccumulatedSet() { return mAccumSet; }
267private:
268    const std::vector<UCD::codepoint_t> & mCodepointTableByLineNum;
269    UnicodeSet mAccumSet;
270};
271void SetByLineNumberAccumulator::accumulate_match(const size_t lineNum, size_t line_start, size_t line_end) {
272    assert (line_start <= line_end);
273    mAccumSet.insert(mCodepointTableByLineNum[lineNum]);
274}
275
276
277const UnicodeSet NumericPropertyObject::GetCodepointSet(const std::string & value_spec) {
278    if (value_spec == "NaN") return mNaNCodepointSet;
279    else {
280        UnicodeSet result_set;
281        unsigned val_bytes = value_spec.length();
282        const char * value_str = value_spec.c_str();
283        const char * search_str = mStringBuffer;
284        unsigned buffer_line = 0;
285        while (buffer_line < mExplicitCps.size()) {
286            const char * eol = strchr(search_str, '\n');
287            unsigned len = eol - search_str;
288            if ((len == val_bytes) && (memcmp(search_str, value_str, len) == 0)) {
289                result_set.insert(mExplicitCps[buffer_line]);
290            }
291            buffer_line++;
292            search_str = eol+1;
293        }
294        return result_set;
295    }
296}
297
298const UnicodeSet NumericPropertyObject::GetCodepointSetMatchingPattern(re::RE * pattern) {
299    UnicodeSet matched;
300    // TODO:  Should we allow matches to NaN???
301    SetByLineNumberAccumulator accum(mExplicitCps);
302    grepBuffer(pattern, mStringBuffer, mBufSize, & accum);
303    return matched + accum.getAccumulatedSet();
304}
305
306
307const UnicodeSet StringPropertyObject::GetCodepointSet(const std::string & value_spec) {
308    if (value_spec == "") return mNullCodepointSet;
309    else {
310        UnicodeSet result_set;
311        unsigned val_bytes = value_spec.length();
312        codepoint_t cp;
313        if (val_bytes == firstCodepointLengthAndVal(value_spec, cp)) {
314            if (mSelfCodepointSet.contains(cp)) {
315                result_set.insert(cp);
316            }
317        }
318        const char * value_str = value_spec.c_str();
319        const char * search_str = mStringBuffer;
320        unsigned buffer_line = 0;
321        while (buffer_line < mExplicitCps.size()) {
322            const char * eol = strchr(search_str, '\n');
323            unsigned len = eol - search_str;
324            if ((len == val_bytes) && (memcmp(search_str, value_str, len) == 0)) {
325                result_set.insert(mExplicitCps[buffer_line]);
326            }
327            buffer_line++;
328            search_str = eol+1;
329        }
330        return result_set;
331    }
332}
333
334const UnicodeSet StringPropertyObject::GetCodepointSetMatchingPattern(re::RE * pattern) {
335    UnicodeSet matched = *cast<UnicodeSet>(matchableCodepoints(pattern)) & mSelfCodepointSet;
336    if (re::matchesEmptyString(pattern)) {
337        matched = matched + mNullCodepointSet;
338    }
339    SetByLineNumberAccumulator accum(mExplicitCps);
340    grepBuffer(pattern, mStringBuffer, mBufSize, & accum);
341    return matched + accum.getAccumulatedSet();
342}
343   
344const UnicodeSet StringPropertyObject::GetReflexiveSet() {
345    return mSelfCodepointSet;
346}
347
348const UnicodeSet StringOverridePropertyObject::GetCodepointSet(const std::string & value_spec) {
349    // First step: get the codepoints from the base object and then remove any overridden ones.
350    UnicodeSet result_set = mBaseObject.GetCodepointSet(value_spec) - mOverriddenSet;
351    // Now search for additional entries.
352    unsigned val_bytes = value_spec.length();
353    const char * value_str = value_spec.c_str();
354    const char * search_str = mStringBuffer;
355    unsigned buffer_line = 0;
356    while (buffer_line < mExplicitCps.size()) {
357        const char * eol = strchr(search_str, '\n');
358        unsigned len = eol - search_str;
359        if ((len == val_bytes) && (memcmp(search_str, value_str, len) == 0)) {
360            result_set.insert(mExplicitCps[buffer_line]);
361        }
362        buffer_line++;
363        search_str = eol+1;
364    }
365    return result_set;
366}
367   
368   
369const UnicodeSet StringOverridePropertyObject::GetCodepointSetMatchingPattern(re::RE * pattern) {
370    UnicodeSet base_set = mBaseObject.GetCodepointSetMatchingPattern(pattern) - mOverriddenSet;
371    SetByLineNumberAccumulator accum(mExplicitCps);
372    grepBuffer(pattern, mStringBuffer, mBufSize, & accum);
373    return base_set + accum.getAccumulatedSet();
374}
375
376const UnicodeSet StringOverridePropertyObject::GetReflexiveSet() {
377    return mBaseObject.GetReflexiveSet() - mOverriddenSet;
378}
379
380
381const std::string & ObsoletePropertyObject::GetPropertyValueGrepString() {
382    llvm::report_fatal_error("Property " + UCD::property_full_name[the_property] + " is obsolete.");
383}
384
385const UnicodeSet ObsoletePropertyObject::GetCodepointSet(const std::string &) {
386    llvm::report_fatal_error("Property " + UCD::property_full_name[the_property] + " is obsolete.");
387}
388
389
390}
Note: See TracBrowser for help on using the repository browser.