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

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

Performance bug fix

File size: 4.6 KB
RevLine 
[3850]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
[4187]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"
[3850]16
[4187]17#include <assert.h>
[4203]18#include <algorithm>
[4187]19#include <stdexcept>
20
[4194]21using namespace re;
[3850]22
[4194]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);
[3850]27        }
28    }
[4194]29    else if (Seq * seq = dyn_cast<Seq>(re)) {
[4182]30        //If this is a previously encoded Unicode byte sequence.
[4194]31        if (seq->getType() == Seq::Type::Byte) {
[4187]32            throw std::runtime_error("Unexpected UTF Byte Sequence given to UTF8 Encoder.");
[4182]33        }
[4194]34        for (auto i = seq->begin(); i != seq->end(); ++i) {
35            *i = toUTF8(*i);
[3850]36        }
37    }
[4194]38    else if (CC * cc = dyn_cast<CC>(re)) {
39        if (cc->size() == 1) {
40            re = rangeToUTF8(cc->front());
[3850]41        }
[4194]42        else if (cc->size() > 1) {
[4203]43            std::vector<RE *> alt;
[4194]44            for (const CharSetItem & item : *cc) {
[4203]45                alt.push_back(rangeToUTF8(item));
[3850]46            }
[4203]47            re = makeAlt(alt.begin(), alt.end());
[3850]48        }
49    }
[4194]50    else if (Rep * rep = dyn_cast<Rep>(re)) {
51        rep->setRE(toUTF8(rep->getRE()));
[3935]52    }
[4194]53    return re;
[3850]54}
55
[4182]56RE * UTF8_Encoder::rangeToUTF8(const CharSetItem & item) {
[3850]57    int u8len_lo = u8len(item.lo_codepoint);
58    int u8len_hi = u8len(item.hi_codepoint);
[4194]59    if (u8len_lo < u8len_hi) {
[3850]60        int m = max_of_u8len(u8len_lo);
[4203]61        return makeAlt({rangeToUTF8(CharSetItem(item.lo_codepoint, m)), rangeToUTF8(CharSetItem(m + 1, item.hi_codepoint))});
[3850]62    }
[4194]63    else {
[3850]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    {
[4203]79        Seq* seq = makeSeq(u8Prefix(hbyte) ? Seq::Type::Byte : Seq::Type::Normal);
[4182]80        seq->push_back(makeByteClass(hbyte));
81        seq->push_back(rangeToUTF8_helper(lo, hi, n+1, hlen));
[3850]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;
[4203]91            return makeAlt({rangeToUTF8_helper(hi_floor, hi, n, hlen), rangeToUTF8_helper(lo, hi_floor - 1, n, hlen)});
[3850]92        }
93        else if ((lo & suffix_mask) != 0)
94        {
95            int low_ceil = lo | suffix_mask;
96
[4194]97            Alt* alt = makeAlt();
[4182]98            alt->push_back(rangeToUTF8_helper(low_ceil + 1, hi, n, hlen));
99            alt->push_back(rangeToUTF8_helper(lo, low_ceil, n, hlen));
[3850]100            return alt;
101        }
102        else
103        {
[4194]104            Seq* seq = makeSeq();
105            seq->setType((u8Prefix(hbyte) ? Seq::Type::Byte : Seq::Type::Normal));
[4182]106            seq->push_back(makeByteRange(lbyte, hbyte));
107            seq->push_back(rangeToUTF8_helper(lo, hi, n + 1, hlen));
[3850]108            return seq;
109        }
110    }
111}
112
[3961]113bool UTF8_Encoder::u8Prefix(int cp)
114{
[4003]115    return ((cp >= 0xC2) && (cp <= 0xF4));
[3961]116}
117
[3850]118CC* UTF8_Encoder::makeByteRange(int lo, int hi)
119{
[4194]120    return makeCC(lo, hi);
[3850]121}
122
123CC* UTF8_Encoder::makeByteClass(int byteval)
124{
[4194]125    return makeCC(byteval, byteval);
[3850]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    {
[3916]155        retVal = 0x80 | ((codepoint >> (6 * (len - n))) & 0x3F);
[3850]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.