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

Last change on this file since 5892 was 5892, checked in by cameron, 12 months ago

Restructuring: integrating grep_engine and grep_pipeline

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