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

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

Replaced CharSetItem? with a std::pair.

File size: 4.5 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 = lenUTF8(lo_codepoint(item));
42    const auto max = lenUTF8(hi_codepoint(item));
43    if (min < max) {
44        const auto m = maxCodePoint(min);
45        return makeAlt({rangeToUTF8(interval_t(lo_codepoint(item), m)), rangeToUTF8(interval_t(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 = u8byte(hi, index);
55    const codepoint_t lbyte = u8byte(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
78inline bool UTF8_Encoder::isUTF8Prefix(const codepoint_t cp) {
79    return (cp >= 0xC2) && (cp <= 0xF4);
80}
81
82inline codepoint_t UTF8_Encoder::u8byte(const codepoint_t cp, const unsigned n) {
83    codepoint_t retVal = 0;
84    const unsigned len = lenUTF8(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
99inline unsigned UTF8_Encoder::lenUTF8(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
114inline codepoint_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
130inline bool UTF8_Encoder::isLowCodePointAfterByte(const codepoint_t cp, const unsigned index) {
131    const auto l = lenUTF8(cp);
132    for (auto i = index; i != l; ++i) {
133        if (u8byte(cp, i + 1) != 0x80) {
134            return false;
135        }
136    }
137    return true;
138}
139
140inline bool UTF8_Encoder::isHighCodePointAfterByte(const codepoint_t cp, const unsigned index) {
141    const auto l = lenUTF8(cp);
142    for (auto i = index; i != l; ++i) {
143        if (u8byte(cp, i + 1) != 0xBF) {
144            return false;
145        }
146    }
147    return true;
148}
149
150
151inline CC * UTF8_Encoder::makeByteRange(const codepoint_t lo, const codepoint_t hi) {
152    return makeCC(lo, hi);
153}
154
155inline CC * UTF8_Encoder::makeByteClass(const codepoint_t cp) {
156    return makeCC(cp, cp);
157}
158
159}
Note: See TracBrowser for help on using the repository browser.