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

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

Update scanmatch callback protocol to use line start/end pointers; add finalize callback for buffer end

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