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

Last change on this file since 5684 was 5684, checked in by cameron, 23 months ago

Regular expressions for extension property (scx)

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(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
76const 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 UnicodeSet ExtensionPropertyObject::GetCodepointSetMatchingPattern(re::RE * pattern) {
200    AlignedAllocator<char, 32> alloc;
201    std::vector<std::string> accumulatedValues;
202   
203    EnumeratedPropertyObject * baseObj = cast<EnumeratedPropertyObject>(property_object_table[base_property]);
204   
205    const std::string & str = baseObj->GetPropertyValueGrepString();
206   
207    const unsigned segmentSize = 8;
208    const auto n = str.length();
209    const auto w = 256 * segmentSize;
210    const auto m = w - (n % w);
211   
212    char * aligned = alloc.allocate(n + m, 0);
213    std::memcpy(aligned, str.data(), n);
214    std::memset(aligned + n, 0, m);
215   
216    PropertyValueAccumulator accum(aligned, accumulatedValues);
217    grepBuffer(pattern, aligned, n, & accum);
218    alloc.deallocate(aligned, 0);
219   
220    UnicodeSet a;
221    for (auto v : accumulatedValues) {
222        int e = baseObj->GetPropertyValueEnumCode(v);
223        a = a + GetCodepointSet(e);
224    }
225    return a;
226}
227
228
229const std::string & ExtensionPropertyObject::GetPropertyValueGrepString() {
230    return property_object_table[base_property]->GetPropertyValueGrepString();
231}
232
233const UnicodeSet BinaryPropertyObject::GetCodepointSet(const std::string & value_spec) {
234    int property_enum_val = Binary_ns::Y;
235    if (value_spec.length() != 0) {
236        auto valit = Binary_ns::aliases_only_map.find(canonicalize_value_name(value_spec));
237        if (valit == Binary_ns::aliases_only_map.end()) {
238            llvm::report_fatal_error("Binary Property " + UCD::property_full_name[the_property] +  ": bad value: " + value_spec);
239        }
240        property_enum_val = valit->second;
241    }
242    return GetCodepointSet(property_enum_val);
243}
244
245const UnicodeSet & BinaryPropertyObject::GetCodepointSet(const int property_enum_val) {
246    if (property_enum_val == Binary_ns::Y) {
247        return mY;
248    }
249    if (mNoUninitialized) {
250        mN = ~mY;
251        mNoUninitialized = false;
252    }
253    return mN;
254}
255
256const UnicodeSet BinaryPropertyObject::GetCodepointSetMatchingPattern(re::RE * pattern) {
257    llvm::report_fatal_error("Enumerated Property GetCodepointSetMatchingPattern not yet implemented");
258}
259   
260const std::string & BinaryPropertyObject::GetPropertyValueGrepString() {
261    if (mPropertyValueGrepString.empty()) {
262        std::stringstream buffer;
263        for (const auto & prop : Binary_ns::aliases_only_map) {
264            buffer << std::get<0>(prop) + "\n";
265        }
266        mPropertyValueGrepString = buffer.str();
267    }
268    return mPropertyValueGrepString;
269}
270   
271const unsigned firstCodepointLengthAndVal(const std::string & s, codepoint_t & cp) {
272    size_t lgth = s.length();
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)
293    : mCodepointTableByLineNum(cps) {}
294   
295    void accumulate_match(const size_t lineNum, size_t line_start, size_t line_end) override;
296    UnicodeSet getAccumulatedSet() { return mAccumSet; }
297private:
298    const std::vector<UCD::codepoint_t> & mCodepointTableByLineNum;
299    UnicodeSet mAccumSet;
300};
301void SetByLineNumberAccumulator::accumulate_match(const size_t lineNum, size_t line_start, size_t line_end) {
302    assert (line_start <= line_end);
303    mAccumSet.insert(mCodepointTableByLineNum[lineNum]);
304}
305
306
307const UnicodeSet NumericPropertyObject::GetCodepointSet(const std::string & value_spec) {
308    if (value_spec == "NaN") return mNaNCodepointSet;
309    else {
310        UnicodeSet result_set;
311        unsigned val_bytes = value_spec.length();
312        const char * value_str = value_spec.c_str();
313        const char * search_str = mStringBuffer;
314        unsigned buffer_line = 0;
315        while (buffer_line < mExplicitCps.size()) {
316            const char * eol = strchr(search_str, '\n');
317            unsigned len = eol - search_str;
318            if ((len == val_bytes) && (memcmp(search_str, value_str, len) == 0)) {
319                result_set.insert(mExplicitCps[buffer_line]);
320            }
321            buffer_line++;
322            search_str = eol+1;
323        }
324        return result_set;
325    }
326}
327
328const UnicodeSet NumericPropertyObject::GetCodepointSetMatchingPattern(re::RE * pattern) {
329    UnicodeSet matched;
330    // TODO:  Should we allow matches to NaN???
331    SetByLineNumberAccumulator accum(mExplicitCps);
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;
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);
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);
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.