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

Last change on this file since 5954 was 5954, checked in by cameron, 13 months ago

InternalSearchEngine?

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