source: icGREP/icgrep-devel/icgrep/utf8_encoder.cpp @ 4660

Last change on this file since 4660 was 4660, checked in by nmedfort, 4 years ago

Moved 'resolveProperties' into CC_NameMap as a single call for each unique Name.

File size: 5.1 KB
Line 
1/*
2 *  Copyright (c) 2014 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 *  icgrep is a trademark of International Characters.
5 */
6
7#include <utf8_encoder.h>
8#include <re/re_name.h>
9#include <re/re_seq.h>
10#include <re/re_alt.h>
11#include <re/re_rep.h>
12#include <cc/cc_namemap.hpp>
13#include <assert.h>
14#include <algorithm>
15#include <stdexcept>
16
17using namespace re;
18
19namespace cc {
20
21RE * UTF8_Encoder::toUTF8(CC_NameMap & nameMap, RE * ast) {
22    for (Name * name : nameMap) {
23        if (const CC * cc = dyn_cast_or_null<CC>(name->getDefinition())) {
24            if (cc->size() == 1) {
25                RE * def = rangeToUTF8(cc->front());
26                name->setDefinition(def);
27            }
28            else if (cc->size() > 1) {
29                std::vector<RE *> alt;
30                for (const interval_t & i : *cc) {
31                    alt.push_back(rangeToUTF8(i));
32                }
33                RE * def = makeAlt(alt.begin(), alt.end());
34                name->setDefinition(def);
35            }
36        }
37    }
38    nameMap.clear();
39    return nameMap.process(ast, ByteClass);
40}
41
42RE * UTF8_Encoder::rangeToUTF8(const interval_t & item) {
43    const auto min = length(lo_codepoint(item));
44    const auto max = length(hi_codepoint(item));
45    if (min < max) {
46        const auto m = maxCodePoint(min);
47        return makeAlt({rangeToUTF8(std::make_pair(lo_codepoint(item), m)), rangeToUTF8(std::make_pair(m + 1, hi_codepoint(item)))});
48    }
49    else {
50        return rangeToUTF8(lo_codepoint(item), hi_codepoint(item), 1, max);
51    }
52}
53
54RE * UTF8_Encoder::rangeToUTF8(const codepoint_t lo, const codepoint_t hi, const unsigned index, const unsigned max)
55{
56    const codepoint_t hbyte = encodingByte(hi, index);
57    const codepoint_t lbyte = encodingByte(lo, index);
58    if (index == max) {
59        return makeByteRange(lbyte, hbyte);
60    }
61    else if (hbyte == lbyte) {
62        return makeSeq({makeByteClass(hbyte), rangeToUTF8(lo, hi, index + 1, max)});
63    }
64    else {
65        const unsigned suffix_mask = (static_cast<unsigned>(1) << ((max - index) * 6)) - 1;
66        if ((hi & suffix_mask) != suffix_mask) {
67            const unsigned hi_floor = (~suffix_mask) & hi;
68            return makeAlt({rangeToUTF8(hi_floor, hi, index, max), rangeToUTF8(lo, hi_floor - 1, index, max)});
69        }
70        else if ((lo & suffix_mask) != 0) {
71            const unsigned low_ceil = lo | suffix_mask;
72            return makeAlt({rangeToUTF8(low_ceil + 1, hi, index, max), rangeToUTF8(lo, low_ceil, index, max)});
73        }
74        else {
75            return makeSeq({makeByteRange(lbyte, hbyte), rangeToUTF8(lo, hi, index + 1, max)});
76        }
77    }
78}
79
80bool UTF8_Encoder::isPrefix(const codepoint_t cp) {
81    return (cp >= 0xC2) && (cp <= 0xF4);
82}
83
84codepoint_t UTF8_Encoder::encodingByte(const codepoint_t cp, const unsigned n) {
85    codepoint_t retVal = 0;
86    const unsigned len = length(cp);
87    if (n == 1) {
88        switch (len) {
89            case 1: retVal = cp; break;
90            case 2: retVal = 0xC0 | (cp >> 6); break;
91            case 3: retVal = 0xE0 | (cp >> 12); break;
92            case 4: retVal = 0xF0 | (cp >> 18); break;
93        }
94    }
95    else {
96        retVal = 0x80 | ((cp >> (6 * (len - n))) & 0x3F);
97    }
98    return retVal;
99}
100
101unsigned UTF8_Encoder::length(const codepoint_t cp) {
102    if (cp <= 0x7F) {
103        return 1;
104    }
105    else if (cp <= 0x7FF) {
106        return 2;
107    }
108    else if (cp <= 0xFFFF) {
109        return 3;
110    }
111    else {
112        return 4;
113    }
114}
115
116codepoint_t UTF8_Encoder::maxCodePoint(const unsigned length) {
117    if (length == 1) {
118        return 0x7F;
119    }
120    else if (length == 2) {
121        return 0x7FF;
122    }
123    else if (length == 3) {
124        return 0xFFFF;
125    }
126    else if (length == 4) {
127        return 0x10FFFF;
128    }
129    throw std::runtime_error("Unexpected UTF8 Length: " + std::to_string(length));
130}
131
132bool UTF8_Encoder::isLowCodePointAfterByte(const codepoint_t cp, const unsigned n) {
133    const auto l = length(cp);
134    for (auto i = n; i != l; ++i) {
135        if (encodingByte(cp, i + 1) != 0x80) {
136            return false;
137        }
138    }
139    return true;
140}
141
142bool UTF8_Encoder::isHighCodePointAfterByte(const codepoint_t cp, const unsigned n) {
143    const auto l = length(cp);
144    for (auto i = n; i != l; ++i) {
145        if (encodingByte(cp, i + 1) != 0xBF) {
146            return false;
147        }
148    }
149    return true;
150}
151
152codepoint_t UTF8_Encoder::minCodePointWithCommonBytes(const re::codepoint_t cp, const unsigned n) {
153    const auto len = length(cp);
154    const auto mask = (static_cast<codepoint_t>(1) << (len - n) * 6) - 1;
155    const auto lo_cp = cp &~ mask;
156    return (lo_cp == 0) ? mask + 1 : lo_cp;
157}
158
159codepoint_t UTF8_Encoder::maxCodePointWithCommonBytes(const re::codepoint_t cp, const unsigned n) {
160    const auto len = length(cp);
161    const auto mask = (static_cast<codepoint_t>(1) << (len - n) * 6) - 1;
162    return cp | mask;
163}
164
165inline CC * UTF8_Encoder::makeByteRange(const codepoint_t lo, const codepoint_t hi) {
166    return makeCC(lo, hi);
167}
168
169inline CC * UTF8_Encoder::makeByteClass(const codepoint_t cp) {
170    return makeCC(cp, cp);
171}
172
173}
Note: See TracBrowser for help on using the repository browser.