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

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

Modified RE module to use a LLVM-like dyn_cast system; added 'make' functions to hide RE constructors.

File size: 4.8 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
9#include "re/re_name.h"
10#include "re/re_start.h"
11#include "re/re_end.h"
12#include "re/re_seq.h"
13#include "re/re_alt.h"
14#include "re/re_rep.h"
15#include "re/re_simplifier.h"
16
17#include <assert.h>
18#include <stdexcept>
19
20using namespace re;
21
22RE * UTF8_Encoder::toUTF8(RE* re) {
23    if (Alt * alt = dyn_cast<Alt>(re)) {
24        for (auto i = alt->begin(); i != alt->end(); ++i) {
25            *i = toUTF8(*i);
26        }
27    }
28    else if (Seq * seq = dyn_cast<Seq>(re)) {
29        //If this is a previously encoded Unicode byte sequence.
30        if (seq->getType() == Seq::Type::Byte) {
31            throw std::runtime_error("Unexpected UTF Byte Sequence given to UTF8 Encoder.");
32        }
33        for (auto i = seq->begin(); i != seq->end(); ++i) {
34            *i = toUTF8(*i);
35        }
36    }
37    else if (CC * cc = dyn_cast<CC>(re)) {
38        if (cc->size() == 1) {
39            re = rangeToUTF8(cc->front());
40            delete cc;
41        }
42        else if (cc->size() > 1) {
43            Alt * alt = makeAlt();
44            for (const CharSetItem & item : *cc) {
45                alt->push_back(rangeToUTF8(item));
46            }
47            re = RE_Simplifier::simplify(alt);
48            delete cc;
49        }
50    }
51    else if (Rep * rep = dyn_cast<Rep>(re)) {
52        rep->setRE(toUTF8(rep->getRE()));
53    }
54    return re;
55}
56
57RE * UTF8_Encoder::rangeToUTF8(const CharSetItem & item) {
58    int u8len_lo = u8len(item.lo_codepoint);
59    int u8len_hi = u8len(item.hi_codepoint);
60    if (u8len_lo < u8len_hi) {
61        int m = max_of_u8len(u8len_lo);
62        Alt* alt = makeAlt();
63        alt->push_back(rangeToUTF8(CharSetItem(item.lo_codepoint, m)));
64        alt->push_back(rangeToUTF8(CharSetItem(m + 1, item.hi_codepoint)));
65        return alt;
66    }
67    else {
68        return rangeToUTF8_helper(item.lo_codepoint, item.hi_codepoint, 1, u8len_hi);
69    }
70}
71
72RE* UTF8_Encoder::rangeToUTF8_helper(int lo, int hi, int n, int hlen)
73{
74    int hbyte = u8byte(hi, n);
75    int lbyte = u8byte(lo, n);
76
77    if (n == hlen)
78    {
79        return makeByteRange(lbyte, hbyte);
80    }
81    else if (hbyte == lbyte)
82    {
83        Seq* seq = makeSeq();
84        seq->setType((u8Prefix(hbyte) ? Seq::Type::Byte : Seq::Type::Normal));
85        seq->push_back(makeByteClass(hbyte));
86        seq->push_back(rangeToUTF8_helper(lo, hi, n+1, hlen));
87        return seq;
88    }
89    else
90    {
91        int suffix_mask = (1 << ((hlen - n) * 6)) - 1;
92
93        if ((hi & suffix_mask) != suffix_mask)
94        {
95            int hi_floor = (~suffix_mask) & hi;
96
97            Alt* alt = makeAlt();
98            alt->push_back(rangeToUTF8_helper(hi_floor, hi, n, hlen));
99            alt->push_back(rangeToUTF8_helper(lo, hi_floor - 1, n, hlen));
100            return alt;
101        }
102        else if ((lo & suffix_mask) != 0)
103        {
104            int low_ceil = lo | suffix_mask;
105
106            Alt* alt = makeAlt();
107            alt->push_back(rangeToUTF8_helper(low_ceil + 1, hi, n, hlen));
108            alt->push_back(rangeToUTF8_helper(lo, low_ceil, n, hlen));
109            return alt;
110        }
111        else
112        {
113            Seq* seq = makeSeq();
114            seq->setType((u8Prefix(hbyte) ? Seq::Type::Byte : Seq::Type::Normal));
115            seq->push_back(makeByteRange(lbyte, hbyte));
116            seq->push_back(rangeToUTF8_helper(lo, hi, n + 1, hlen));
117            return seq;
118        }
119    }
120}
121
122bool UTF8_Encoder::u8Prefix(int cp)
123{
124    return ((cp >= 0xC2) && (cp <= 0xF4));
125}
126
127CC* UTF8_Encoder::makeByteRange(int lo, int hi)
128{
129    return makeCC(lo, hi);
130}
131
132CC* UTF8_Encoder::makeByteClass(int byteval)
133{
134    return makeCC(byteval, byteval);
135}
136
137int UTF8_Encoder::u8byte(int codepoint, int n)
138{
139    int retVal = 0;
140
141    int len = u8len(codepoint);
142
143    if (n == 1)
144    {
145        if (len == 1)
146        {
147            retVal = codepoint;
148        }
149        else if (len == 2)
150        {
151            retVal = 0xC0 | (codepoint >> 6);
152        }
153        else if (len == 3)
154        {
155            retVal = 0xE0 | (codepoint >> 12);
156        }
157        else
158        {
159            retVal = 0xF0 | (codepoint >> 18);
160        }
161    }
162    else
163    {
164        retVal = 0x80 | ((codepoint >> (6 * (len - n))) & 0x3F);
165    }
166
167    return retVal;
168}
169
170int UTF8_Encoder::u8len(int cp)
171{
172    if (cp <= 0x7F)
173    {
174        return 1;
175    }
176    else if (cp <= 0x7FF)
177    {
178        return 2;
179    }
180    else if (cp <= 0xFFFF)
181    {
182        return 3;
183    }
184    else
185    {
186        return 4;
187    }
188}
189
190int UTF8_Encoder::max_of_u8len(int lgth)
191{
192    if (lgth == 1)
193    {
194        return 0x7F;
195    }
196    else if (lgth == 2)
197    {
198        return 0x7FF;
199    }
200    else if (lgth == 3)
201    {
202        return 0xFFFF;
203    }
204    else if (lgth == 4)
205    {
206        return 0x10FFFF;
207    }
208    else
209    {
210        return -1;
211    }
212}
213
Note: See TracBrowser for help on using the repository browser.