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

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

Minor changes in preperation for adding multiplexing.

File size: 4.7 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 = lenUTF8(item.lo_codepoint);
58    int u8len_hi = lenUTF8(item.hi_codepoint);
59    if (u8len_lo < u8len_hi) {
60        int m = maxUTF8Len(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(isUTF8Prefix(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((isUTF8Prefix(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
113inline bool UTF8_Encoder::isUTF8Prefix(const int cp) {
114    return ((cp >= 0xC2) && (cp <= 0xF4));
115}
116
117CC* UTF8_Encoder::makeByteRange(int lo, int hi)
118{
119    return makeCC(lo, hi);
120}
121
122CC* UTF8_Encoder::makeByteClass(int byteval)
123{
124    return makeCC(byteval, byteval);
125}
126
127inline int UTF8_Encoder::u8byte(int codepoint, int n)
128{
129    int retVal = 0;
130
131    int len = lenUTF8(codepoint);
132
133    if (n == 1)
134    {
135        if (len == 1)
136        {
137            retVal = codepoint;
138        }
139        else if (len == 2)
140        {
141            retVal = 0xC0 | (codepoint >> 6);
142        }
143        else if (len == 3)
144        {
145            retVal = 0xE0 | (codepoint >> 12);
146        }
147        else
148        {
149            retVal = 0xF0 | (codepoint >> 18);
150        }
151    }
152    else
153    {
154        retVal = 0x80 | ((codepoint >> (6 * (len - n))) & 0x3F);
155    }
156
157    return retVal;
158}
159
160inline int UTF8_Encoder::lenUTF8(const int cp)
161{
162    if (cp <= 0x7F)
163    {
164        return 1;
165    }
166    else if (cp <= 0x7FF)
167    {
168        return 2;
169    }
170    else if (cp <= 0xFFFF)
171    {
172        return 3;
173    }
174    else
175    {
176        return 4;
177    }
178}
179
180inline int UTF8_Encoder::maxUTF8Len(int lgth)
181{
182    if (lgth == 1)
183    {
184        return 0x7F;
185    }
186    else if (lgth == 2)
187    {
188        return 0x7FF;
189    }
190    else if (lgth == 3)
191    {
192        return 0xFFFF;
193    }
194    else if (lgth == 4)
195    {
196        return 0x10FFFF;
197    }
198    else
199    {
200        return -1;
201    }
202}
203
Note: See TracBrowser for help on using the repository browser.