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

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

Made pablo compiler reenterant through alternate compile method that takes a Module parameter.

File size: 5.0 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                name->setDefinition(rangeToUTF8(cc->front()));
26            }
27            else if (cc->size() > 1) {
28                std::vector<RE *> alt;
29                for (const interval_t & i : *cc) {
30                    alt.push_back(rangeToUTF8(i));
31                }
32                name->setDefinition(makeAlt(alt.begin(), alt.end()));
33            }
34        }
35    }
36    return nameMap.process(ast, ByteClass);
37}
38
39RE * UTF8_Encoder::rangeToUTF8(const interval_t & item) {
40    const auto min = length(lo_codepoint(item));
41    const auto max = length(hi_codepoint(item));
42    if (min < max) {
43        const auto m = maxCodePoint(min);
44        return makeAlt({rangeToUTF8(std::make_pair(lo_codepoint(item), m)), rangeToUTF8(std::make_pair(m + 1, hi_codepoint(item)))});
45    }
46    else {
47        return rangeToUTF8(lo_codepoint(item), hi_codepoint(item), 1, max);
48    }
49}
50
51RE * UTF8_Encoder::rangeToUTF8(const codepoint_t lo, const codepoint_t hi, const unsigned index, const unsigned max)
52{
53    const codepoint_t hbyte = encodingByte(hi, index);
54    const codepoint_t lbyte = encodingByte(lo, index);
55    if (index == max) {
56        return makeByteRange(lbyte, hbyte);
57    }
58    else if (hbyte == lbyte) {
59        return makeSeq({makeByteClass(hbyte), rangeToUTF8(lo, hi, index + 1, max)});
60    }
61    else {
62        const unsigned suffix_mask = (static_cast<unsigned>(1) << ((max - index) * 6)) - 1;
63        if ((hi & suffix_mask) != suffix_mask) {
64            const unsigned hi_floor = (~suffix_mask) & hi;
65            return makeAlt({rangeToUTF8(hi_floor, hi, index, max), rangeToUTF8(lo, hi_floor - 1, index, max)});
66        }
67        else if ((lo & suffix_mask) != 0) {
68            const unsigned low_ceil = lo | suffix_mask;
69            return makeAlt({rangeToUTF8(low_ceil + 1, hi, index, max), rangeToUTF8(lo, low_ceil, index, max)});
70        }
71        else {
72            return makeSeq({makeByteRange(lbyte, hbyte), rangeToUTF8(lo, hi, index + 1, max)});
73        }
74    }
75}
76
77bool UTF8_Encoder::isPrefix(const codepoint_t cp) {
78    return (cp >= 0xC2) && (cp <= 0xF4);
79}
80
81codepoint_t UTF8_Encoder::encodingByte(const codepoint_t cp, const unsigned n) {
82    codepoint_t retVal = 0;
83    const unsigned len = length(cp);
84    if (n == 1) {
85        switch (len) {
86            case 1: retVal = cp; break;
87            case 2: retVal = 0xC0 | (cp >> 6); break;
88            case 3: retVal = 0xE0 | (cp >> 12); break;
89            case 4: retVal = 0xF0 | (cp >> 18); break;
90        }
91    }
92    else {
93        retVal = 0x80 | ((cp >> (6 * (len - n))) & 0x3F);
94    }
95    return retVal;
96}
97
98unsigned UTF8_Encoder::length(const codepoint_t cp) {
99    if (cp <= 0x7F) {
100        return 1;
101    }
102    else if (cp <= 0x7FF) {
103        return 2;
104    }
105    else if (cp <= 0xFFFF) {
106        return 3;
107    }
108    else {
109        return 4;
110    }
111}
112
113codepoint_t UTF8_Encoder::maxCodePoint(const unsigned length) {
114    if (length == 1) {
115        return 0x7F;
116    }
117    else if (length == 2) {
118        return 0x7FF;
119    }
120    else if (length == 3) {
121        return 0xFFFF;
122    }
123    else if (length == 4) {
124        return 0x10FFFF;
125    }
126    throw std::runtime_error("Unexpected UTF8 Length: " + std::to_string(length));
127}
128
129bool UTF8_Encoder::isLowCodePointAfterByte(const codepoint_t cp, const unsigned n) {
130    const auto l = length(cp);
131    for (auto i = n; i != l; ++i) {
132        if (encodingByte(cp, i + 1) != 0x80) {
133            return false;
134        }
135    }
136    return true;
137}
138
139bool UTF8_Encoder::isHighCodePointAfterByte(const codepoint_t cp, const unsigned n) {
140    const auto l = length(cp);
141    for (auto i = n; i != l; ++i) {
142        if (encodingByte(cp, i + 1) != 0xBF) {
143            return false;
144        }
145    }
146    return true;
147}
148
149codepoint_t UTF8_Encoder::minCodePointWithCommonBytes(const re::codepoint_t cp, const unsigned n) {
150    const auto len = length(cp);
151    const auto mask = (static_cast<codepoint_t>(1) << (len - n) * 6) - 1;
152    const auto lo_cp = cp &~ mask;
153    return (lo_cp == 0) ? mask + 1 : lo_cp;
154}
155
156codepoint_t UTF8_Encoder::maxCodePointWithCommonBytes(const re::codepoint_t cp, const unsigned n) {
157    const auto len = length(cp);
158    const auto mask = (static_cast<codepoint_t>(1) << (len - n) * 6) - 1;
159    return cp | mask;
160}
161
162inline CC * UTF8_Encoder::makeByteRange(const codepoint_t lo, const codepoint_t hi) {
163    return makeCC(lo, hi);
164}
165
166inline CC * UTF8_Encoder::makeByteClass(const codepoint_t cp) {
167    return makeCC(cp, cp);
168}
169
170}
Note: See TracBrowser for help on using the repository browser.