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

Last change on this file since 4532 was 4337, checked in by cameron, 4 years ago

Compile only byteclasses with cc_compiler; resolve CC/BC ambiguity

File size: 4.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                name->setDefinition(rangeToUTF8(cc->front()));
26            }
27            else if (cc->size() > 1) {
28                std::vector<RE *> alt;
29                for (const CharSetItem & item : *cc) {
30                    alt.push_back(rangeToUTF8(item));
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 CharSetItem & item) {
41    const auto min = lenUTF8(item.lo_codepoint);
42    const auto max = lenUTF8(item.hi_codepoint);
43    if (min < max) {
44        const auto m = maxCodePoint(min);
45        return makeAlt({rangeToUTF8(CharSetItem(item.lo_codepoint, m)), rangeToUTF8(CharSetItem(m + 1, item.hi_codepoint))});
46    }
47    else {
48        return rangeToUTF8(item.lo_codepoint, item.hi_codepoint, 1, max);
49    }
50}
51
52RE * UTF8_Encoder::rangeToUTF8(const CodePointType lo, const CodePointType hi, const unsigned index, const unsigned max)
53{
54    const CodePointType hbyte = u8byte(hi, index);
55    const CodePointType 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 unsigned cp) {
79    return (cp >= 0xC2) && (cp <= 0xF4);
80}
81
82inline CodePointType UTF8_Encoder::u8byte(const CodePointType codepoint, const unsigned n)
83{
84    CodePointType retVal = 0;
85
86    const unsigned len = lenUTF8(codepoint);
87
88    if (n == 1) {
89        switch (len) {
90            case 1: retVal = codepoint; break;
91            case 2: retVal = 0xC0 | (codepoint >> 6); break;
92            case 3: retVal = 0xE0 | (codepoint >> 12); break;
93            case 4: retVal = 0xF0 | (codepoint >> 18); break;
94        }
95    }
96    else {
97        retVal = 0x80 | ((codepoint >> (6 * (len - n))) & 0x3F);
98    }
99
100    return retVal;
101}
102
103inline unsigned UTF8_Encoder::lenUTF8(const unsigned cp) {
104    if (cp <= 0x7F) {
105        return 1;
106    }
107    else if (cp <= 0x7FF) {
108        return 2;
109    }
110    else if (cp <= 0xFFFF) {
111        return 3;
112    }
113    else {
114        return 4;
115    }
116}
117
118inline unsigned UTF8_Encoder::maxCodePoint(const unsigned length) {
119    if (length == 1) {
120        return 0x7F;
121    }
122    else if (length == 2) {
123        return 0x7FF;
124    }
125    else if (length == 3) {
126        return 0xFFFF;
127    }
128    else if (length == 4) {
129        return 0x10FFFF;
130    }
131    throw std::runtime_error("Unexpected UTF8 Length: " + std::to_string(length));
132}
133
134inline CC * UTF8_Encoder::makeByteRange(const CodePointType lo, const CodePointType hi) {
135    return makeCC(lo, hi);
136}
137
138inline CC * UTF8_Encoder::makeByteClass(const CodePointType cp) {
139    return makeCC(cp, cp);
140}
141
142}
Note: See TracBrowser for help on using the repository browser.