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

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

Temporary check-in

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