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

Last change on this file since 5679 was 5679, checked in by cameron, 20 months ago

Refactoring progress: \N uses name property; delay resolution of recursive property expressions, property object regexp support

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