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

Last change on this file since 4251 was 4249, checked in by nmedfort, 5 years ago

Big update to use CC_NameMap; removed CharClass? and RE_Reducer.

File size: 4.3 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->getCC())) {
24            if (cc->size() == 1) {
25                name->setCC(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->setCC(makeAlt(alt.begin(), alt.end()));
33            }
34        }
35    }
36    ast = nameMap.process(ast);
37    // Build our list of predefined characters.
38    nameMap.addPredefined("UTF8-SingleByte", makeCC(0x00, 0x7F));
39    nameMap.addPredefined("UTF8-Prefix2", makeCC(0xC2, 0xDF));
40    nameMap.addPredefined("UTF8-Prefix3", makeCC(0xE0, 0xEF));
41    nameMap.addPredefined("UTF8-Prefix4", makeCC(0xF0, 0xF4));
42    return ast;
43}
44
45RE * UTF8_Encoder::rangeToUTF8(const CharSetItem & item) {
46    const auto min = lenUTF8(item.lo_codepoint);
47    const auto max = lenUTF8(item.hi_codepoint);
48    if (min < max) {
49        const auto m = maxCodePoint(min);
50        return makeAlt({rangeToUTF8(CharSetItem(item.lo_codepoint, m)), rangeToUTF8(CharSetItem(m + 1, item.hi_codepoint))});
51    }
52    else {
53        return rangeToUTF8(item.lo_codepoint, item.hi_codepoint, 1, max);
54    }
55}
56
57RE * UTF8_Encoder::rangeToUTF8(const CodePointType lo, const CodePointType hi, const unsigned index, const unsigned max)
58{
59    const CodePointType hbyte = u8byte(hi, index);
60    const CodePointType lbyte = u8byte(lo, index);
61    if (index == max) {
62        return makeByteRange(lbyte, hbyte);
63    }
64    else if (hbyte == lbyte) {
65        return makeSeq({makeByteClass(hbyte), rangeToUTF8(lo, hi, index + 1, max)});
66    }
67    else {
68        const unsigned suffix_mask = (static_cast<unsigned>(1) << ((max - index) * 6)) - 1;
69        if ((hi & suffix_mask) != suffix_mask) {
70            const unsigned hi_floor = (~suffix_mask) & hi;
71            return makeAlt({rangeToUTF8(hi_floor, hi, index, max), rangeToUTF8(lo, hi_floor - 1, index, max)});
72        }
73        else if ((lo & suffix_mask) != 0) {
74            const unsigned low_ceil = lo | suffix_mask;
75            return makeAlt({rangeToUTF8(low_ceil + 1, hi, index, max), rangeToUTF8(lo, low_ceil, index, max)});
76        }
77        else {
78            return makeSeq({makeByteRange(lbyte, hbyte), rangeToUTF8(lo, hi, index + 1, max)});
79        }
80    }
81}
82
83inline bool UTF8_Encoder::isUTF8Prefix(const unsigned cp) {
84    return (cp >= 0xC2) && (cp <= 0xF4);
85}
86
87inline CodePointType UTF8_Encoder::u8byte(const CodePointType codepoint, const unsigned n)
88{
89    CodePointType retVal = 0;
90
91    const unsigned len = lenUTF8(codepoint);
92
93    if (n == 1) {
94        switch (len) {
95            case 1: retVal = codepoint; break;
96            case 2: retVal = 0xC0 | (codepoint >> 6); break;
97            case 3: retVal = 0xE0 | (codepoint >> 12); break;
98            case 4: retVal = 0xF0 | (codepoint >> 18); break;
99        }
100    }
101    else {
102        retVal = 0x80 | ((codepoint >> (6 * (len - n))) & 0x3F);
103    }
104
105    return retVal;
106}
107
108inline unsigned UTF8_Encoder::lenUTF8(const unsigned cp) {
109    if (cp <= 0x7F) {
110        return 1;
111    }
112    else if (cp <= 0x7FF) {
113        return 2;
114    }
115    else if (cp <= 0xFFFF) {
116        return 3;
117    }
118    else {
119        return 4;
120    }
121}
122
123inline unsigned UTF8_Encoder::maxCodePoint(const unsigned length) {
124    if (length == 1) {
125        return 0x7F;
126    }
127    else if (length == 2) {
128        return 0x7FF;
129    }
130    else if (length == 3) {
131        return 0xFFFF;
132    }
133    else if (length == 4) {
134        return 0x10FFFF;
135    }
136    throw std::runtime_error("Unexpected UTF8 Length: " + std::to_string(length));
137}
138
139inline CC * UTF8_Encoder::makeByteRange(const CodePointType lo, const CodePointType hi) {
140    return makeCC(lo, hi);
141}
142
143inline CC * UTF8_Encoder::makeByteClass(const CodePointType cp) {
144    return makeCC(cp, cp);
145}
146
147}
Note: See TracBrowser for help on using the repository browser.