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

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

Performance bug fix

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