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

Last change on this file since 6134 was 6134, checked in by cameron, 15 months ago

GetStringValue? method for string properties

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