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

Last change on this file since 5751 was 5751, checked in by cameron, 17 months ago

LLVM_ALIGNAS placement, eliminate std::move of temp objects to allow copy elision

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