source: icGREP/icgrep-devel/icgrep/UCD/unicode_set.cpp @ 4818

Last change on this file since 4818 was 4818, checked in by nmedfort, 4 years ago

GCC fix + misc. changes

File size: 26.2 KB
Line 
1//
2// unicode_set.cpp - representing and manipulating sets of Unicode
3// characters, based on data from UCD - the Unicode Character Database
4//
5// Robert D. Cameron
6// September 18, 2014
7//
8// Licensed under Open Software License 3.0.
9//
10// Unicode Sparse Bitset Representation
11//
12// The Unicode Sparse Bitset representation is based on
13// (a) Dividing the Unicode codepoint space into groups of 2^k codepoints called quads.
14// (b) Specifying the quads using a run-length encoding, in which each run
15//     is Empty (quads contain no members), Mixed (quads contain some members and
16//     some nonmembers) or Full (all codepoints in each quad are members of the set).
17// (c) Explicitly listing all the quads of Mixed type.
18//
19
20#include "unicode_set.h"
21#include "assert.h"
22#include <string>
23#include <llvm/Support/raw_ostream.h>
24#include <llvm/Support/Format.h>
25#include <include/simd-lib/builtins.hpp>
26
27namespace UCD {
28
29using bitquad_t = UnicodeSet::bitquad_t;
30using run_t = UnicodeSet::run_t;
31using RunVector = UnicodeSet::RunVector;
32using QuadVector = UnicodeSet::QuadVector;
33
34const size_t QUAD_BITS = (8 * sizeof(bitquad_t));
35const size_t MOD_QUAD_BIT_MASK = QUAD_BITS - 1;
36const size_t UNICODE_QUAD_COUNT = (UNICODE_MAX + 1) / QUAD_BITS;
37const bitquad_t FULL_QUAD_MASK = -1;
38
39inline run_type_t typeOf(const run_t & run) {
40    return run.first;
41}
42
43inline UnicodeSet::length_t lengthOf(const run_t & run) {
44    return run.second;
45}
46
47/** ------------------------------------------------------------------------------------------------------------- *
48 * @brief append_run
49 ** ------------------------------------------------------------------------------------------------------------- */
50inline void append_run(const run_type_t type, const unsigned length, RunVector & runs) {
51    if (LLVM_UNLIKELY(length == 0)) {
52        return;
53    }
54    else if (!runs.empty() && typeOf(runs.back()) == type) {
55        std::get<1>(runs.back()) += length;
56        return;
57    }
58    runs.emplace_back(type, length);
59}
60
61/** ------------------------------------------------------------------------------------------------------------- *
62 * @brief append_quad
63 ** ------------------------------------------------------------------------------------------------------------- */
64inline void append_quad(const bitquad_t quad, QuadVector & quads, RunVector & runs) {
65    run_type_t type = Empty;
66    if (LLVM_UNLIKELY(quad == 0)) {
67        type = Empty;
68    }
69    else if (LLVM_UNLIKELY(quad == FULL_QUAD_MASK)) {
70        type = Full;
71    }
72    else {
73        quads.emplace_back(quad);
74        type = Mixed;
75    }
76    append_run(type, 1, runs);
77}
78
79#ifndef NDEBUG
80/** ------------------------------------------------------------------------------------------------------------- *
81 * @brief runLengthSumsUpToUnicodeQuadCount
82 *
83 * Sanity check for each function that constructs a new UnicodeSet
84 ** ------------------------------------------------------------------------------------------------------------- */
85inline bool runLengthSumsUpToUnicodeQuadCount(const RunVector & runs) {
86    unsigned sum = 0;
87    for (auto & run : runs) {
88        sum += lengthOf(run);
89    }
90    return sum == UNICODE_QUAD_COUNT;
91}
92#endif
93
94/** ------------------------------------------------------------------------------------------------------------- *
95 * @brief empty
96 ** ------------------------------------------------------------------------------------------------------------- */
97bool UnicodeSet::empty() const {
98    return (mRuns.size() == 1) && typeOf(mRuns.front()) == Empty;
99}
100
101/** ------------------------------------------------------------------------------------------------------------- *
102 * @brief size
103 ** ------------------------------------------------------------------------------------------------------------- */
104UnicodeSet::size_type UnicodeSet::size() const {
105    return std::distance(begin(), end());
106}
107
108/** ------------------------------------------------------------------------------------------------------------- *
109 * @brief front
110 ** ------------------------------------------------------------------------------------------------------------- */
111UnicodeSet::interval_t UnicodeSet::front() const {
112    return *begin();
113}
114
115/** ------------------------------------------------------------------------------------------------------------- *
116 * @brief back
117 ** ------------------------------------------------------------------------------------------------------------- */
118UnicodeSet::interval_t UnicodeSet::back() const {
119    auto back = begin();
120    for (auto i = back; i != end(); back = i++);
121    return *back;
122}
123
124/** ------------------------------------------------------------------------------------------------------------- *
125 * @brief dump
126 ** ------------------------------------------------------------------------------------------------------------- */
127void UnicodeSet::dump(llvm::raw_ostream & out) const {
128    auto qi = mQuads.cbegin();
129    for (const run_t & run : mRuns) {
130        if (typeOf(run) == Empty) {
131            out << "Empty(" << lengthOf(run) << ")\n";
132        }
133        else if (typeOf(run) == Full) {
134            out << "Full(" << lengthOf(run) << ")\n";
135        }
136        else {
137            for (const auto qi_end = qi + lengthOf(run); qi != qi_end; ++qi) {
138                assert (qi != mQuads.cend());
139                out << "Mixed(" << llvm::format("%08x", *qi) << ")\n";
140            }
141        }
142    }
143}
144
145/** ------------------------------------------------------------------------------------------------------------- *
146 * @brief complement
147 ** ------------------------------------------------------------------------------------------------------------- */
148UnicodeSet UnicodeSet::operator~() const {
149    RunVector runs;
150    QuadVector quads;
151    runs.reserve(mRuns.size());
152    quads.reserve(mQuads.size());
153    auto qi = quads.cbegin();
154    for (const run_t & run : mRuns) {
155        if (typeOf(run) == Empty) {
156            append_run(Full, lengthOf(run), runs);
157        }
158        else if (typeOf(run) == Full) {
159            append_run(Empty, lengthOf(run), runs);
160        }
161        else {
162            for (const auto qi_end = qi + lengthOf(run); qi != qi_end; ++qi) {
163                assert (qi != quads.cend());
164                append_quad(FULL_QUAD_MASK ^ *qi, quads, runs);
165            }
166        }
167    }
168    assert (runLengthSumsUpToUnicodeQuadCount(runs));
169    return UnicodeSet(std::move(runs), std::move(quads));
170}
171
172/** ------------------------------------------------------------------------------------------------------------- *
173 * @brief intersection
174 ** ------------------------------------------------------------------------------------------------------------- */
175UnicodeSet UnicodeSet::operator&(const UnicodeSet & other) const {
176    RunVector runs;
177    QuadVector quads;
178    const auto e1 = quad_end();
179    const auto e2 = other.quad_end();
180    for (auto i1 = quad_begin(), i2 = other.quad_begin(); i1 != e1 && i2 != e2; ) {
181        const auto n = std::min(i1.length(), i2.length());
182        if (i1.type() == i2.type() && i1.type() != Mixed) {
183            append_run(i1.type(), n, runs);
184            i1 += n;
185            i2 += n;
186        }
187        else if (i1.type() == Full) {
188            for (unsigned i = 0; i != n; ++i, ++i2) {
189                append_quad(i2.quad(), quads, runs);
190            }
191            i1 += n;
192        }
193        else if (i2.type() == Full) {
194            for (unsigned i = 0; i != n; ++i, ++i1) {
195                append_quad(i1.quad(), quads, runs);
196            }
197            i2 += n;
198        }
199        else {
200            for (unsigned i = 0; i != n; ++i, ++i1, ++i2) {
201                append_quad(i1.quad() & i2.quad(), quads, runs);
202            }
203        }
204    }
205    assert (runLengthSumsUpToUnicodeQuadCount(runs));
206    return UnicodeSet(std::move(runs), std::move(quads));
207}
208
209/** ------------------------------------------------------------------------------------------------------------- *
210 * @brief union
211 ** ------------------------------------------------------------------------------------------------------------- */
212UnicodeSet UnicodeSet::operator+(const UnicodeSet & other) const {
213    RunVector runs;
214    QuadVector quads;
215    const auto e1 = quad_end();
216    const auto e2 = other.quad_end();
217    auto i1 = quad_begin(), i2 = other.quad_begin();
218    for (; i1 != e1 && i2 != e2; ) {
219        const auto n = std::min(i1.length(), i2.length());
220        if ((i1.type() == Empty) && (i2.type() == Empty)) {
221            append_run(Empty, n, runs);
222            i1 += n;
223            i2 += n;
224        }
225        else if ((i1.type() == Full) || (i2.type() == Full)) {
226            append_run(Full, n, runs);
227            i1 += n;
228            i2 += n;
229        }
230        else if (i1.type() == Empty) {
231            for (unsigned i = 0; i != n; ++i, ++i2) {
232                append_quad(i2.quad(), quads, runs);
233            }
234            i1 += n;
235        }
236        else if (i2.type() == Empty) {
237            for (unsigned i = 0; i != n; ++i, ++i1) {
238                append_quad(i1.quad(), quads, runs);
239            }
240            i2 += n;
241        }
242        else {
243            for (unsigned i = 0; i < n; ++i, ++i1, ++i2) {
244                append_quad(i1.quad() | i2.quad(), quads, runs);
245            }
246        }
247    }
248    assert (runLengthSumsUpToUnicodeQuadCount(runs));
249    return UnicodeSet(std::move(runs), std::move(quads));
250}
251
252/** ------------------------------------------------------------------------------------------------------------- *
253 * @brief difference
254 ** ------------------------------------------------------------------------------------------------------------- */
255UnicodeSet UnicodeSet::operator-(const UnicodeSet & other) const {
256    RunVector runs;
257    QuadVector quads;
258    const auto e1 = quad_end();
259    const auto e2 = other.quad_end();
260    for (auto i1 = quad_begin(), i2 = other.quad_begin(); i1 != e1 && i2 != e2; ) {
261        unsigned n = std::min(i1.length(), i2.length());
262        if ((i1.type() == Empty) || (i2.type() == Full) || (i1.type() == Full && i2.type() == Empty)) {
263            append_run(i1.type(), n, runs);
264            i1 += n;
265            i2 += n;
266        }
267        else if (i1.type() == Full) {
268            for (unsigned i = 0; i != n; ++i, ++i2) {
269                append_quad(FULL_QUAD_MASK ^ i2.quad(), quads, runs);
270            }
271            i1 += n;
272        }
273        else if (i2.type() == Empty) {
274            for (unsigned i = 0; i != n; ++i, ++i1) {
275                append_quad(i1.quad(), quads, runs);
276            }
277            i2 += n;
278        }
279        else {
280            for (unsigned i = 0; i != n; ++i, ++i1, ++i2) {
281                append_quad(i1.quad() &~ i2.quad(), quads, runs);
282            }
283        }
284    }
285    assert (runLengthSumsUpToUnicodeQuadCount(runs));
286    return UnicodeSet(std::move(runs), std::move(quads));
287}
288
289/** ------------------------------------------------------------------------------------------------------------- *
290 * @brief symmetric difference
291 ** ------------------------------------------------------------------------------------------------------------- */
292UnicodeSet UnicodeSet::operator^(const UnicodeSet & other) const {
293    RunVector runs;
294    QuadVector quads;
295    const auto e1 = quad_end();
296    const auto e2 = other.quad_end();
297    for (auto i1 = quad_begin(), i2 = other.quad_begin(); i1 != e1 && i2 != e2; ) {
298        unsigned n = std::min(i1.length(), i2.length());
299        if (i1.type() != Mixed && i2.type() != Mixed) {
300            append_run(i1.type() == i2.type() ? Empty : Full, n, runs);
301            i1 += n;
302            i2 += n;
303        }
304        else if (i1.type() == Empty) {
305            for (unsigned i = 0; i < n; ++i, ++i2) {
306                append_quad(i2.quad(), quads, runs);
307            }
308            i1 += n;
309        }
310        else if (i2.type() == Empty) {
311            for (unsigned i = 0; i < n; ++i, ++i1) {
312                append_quad(i1.quad(), quads, runs);
313            }
314            i2 += n;
315        }
316        else if (i1.type() == Full) {
317            for (unsigned i = 0; i < n; ++i, ++i2) {
318                append_quad(FULL_QUAD_MASK ^ i2.quad(), quads, runs);
319            }
320            i1 += n;
321        }
322        else if (i2.type() == Empty) {
323            for (unsigned i = 0; i < n; ++i, ++i1) {
324                append_quad(FULL_QUAD_MASK ^ i1.quad(), quads, runs);
325            }
326            i2 += n;
327        }
328        else {
329            for (unsigned i = 0; i != n; ++i, ++i1, ++i2) {
330                append_quad(i1.quad() ^ i2.quad(), quads, runs);
331            }
332        }
333    }
334    assert (runLengthSumsUpToUnicodeQuadCount(runs));
335    return UnicodeSet(std::move(runs), std::move(quads));
336}
337
338/** ------------------------------------------------------------------------------------------------------------- *
339 * @brief equality
340 ** ------------------------------------------------------------------------------------------------------------- */
341bool UnicodeSet::operator==(const UnicodeSet & other) const {
342    if (mRuns.size() != other.mRuns.size() || mQuads.size() != other.mQuads.size()) {
343        return false;
344    }
345    for (auto i = mQuads.begin(), j = other.mQuads.begin(); i != mQuads.end(); ++i, ++j) {
346        if (*i != *j) return false;
347    }
348    for (auto i = mRuns.begin(), j = other.mRuns.begin(); i != mRuns.end(); ++i, ++j) {
349        if (*i != *j) return false;
350    }
351    return true;
352}
353
354/** ------------------------------------------------------------------------------------------------------------- *
355 * @brief less operator
356 ** ------------------------------------------------------------------------------------------------------------- */
357bool UnicodeSet::operator<(const UnicodeSet & other) const {
358    if (LLVM_LIKELY(mRuns.size() != other.mRuns.size())) {
359        return mRuns.size() < other.mRuns.size();
360    } else if (LLVM_LIKELY(mQuads.size() != other.mQuads.size())) {
361        return (mQuads.size() < other.mQuads.size());
362    } else { // equal run and quad lengths; test their individual values
363        for (auto ri = mRuns.cbegin(), end = mRuns.cend(), rj = other.mRuns.cbegin(); ri != end; ++ri, ++rj) {
364            if (*ri < *rj) {
365                return true;
366            } else if (*ri > *rj) {
367                return false;
368            }
369        }
370        for (auto qi = mQuads.cbegin(), end = mQuads.cend(), qj = other.mQuads.cbegin(); qi != end; ++qi, ++qj) {
371            if (*qi < *qj) {
372                return true;
373            } else if (*qi > *qj) {
374                return false;
375            }
376        }
377        return false;
378    }
379}
380
381///** ------------------------------------------------------------------------------------------------------------- *
382// * @brief insert_range
383// ** ------------------------------------------------------------------------------------------------------------- */
384//void UnicodeSet::insert_range(const codepoint_t lo, const codepoint_t hi)  {
385
386//    if (LLVM_UNLIKELY(lo > hi)) {
387//        throw std::runtime_error('[' + std::to_string(lo) + ',' + std::to_string(hi) + "] is an illegal codepoint range!");
388//    } else if (LLVM_UNLIKELY(hi >= 0x110000)) {
389//        throw std::runtime_error(std::to_string(hi) + " exceeds maximum code point.");
390//    }
391
392//    auto r = mRuns.begin();
393//    auto q = mQuads.begin();
394//    unsigned offset = 0;
395
396//    auto lo_quad_no = lo / QUAD_BITS;
397//    auto lo_offset = lo & MOD_QUAD_BIT_MASK;
398
399//    auto hi_quad_no = hi / QUAD_BITS;
400//    auto hi_offset = hi & MOD_QUAD_BIT_MASK;
401
402//    // Scan up to the lo codepoint
403//    for (;;) {
404//        assert (r != mRuns.end());
405//        const auto l = lengthOf(*r);
406//        if ((offset + l) > lo_quad_no) {
407//            break;
408//        }
409//        if (typeOf(*r) == Mixed) {
410//            q += lengthOf(*r);
411//        }
412//        offset += l;
413//        ++r;
414//    }
415
416//    // Test whether the range is already 'full' and skip ahead to the first empty or mixed quad.
417//    // If the entire [lo,hi] range is already covered by a Full run, abort.
418//    while (typeOf(*r) == Full) {
419//        const auto l = lengthOf(*r);
420//        lo_quad_no += l;
421//        offset = lo_quad_no;
422//        lo_offset = 0;
423//        if (lo_quad_no > hi_quad_no) {
424//            return;
425//        }
426//        ++r;
427//    }
428
429//    // Otherwise, some portion of this range has to be inserted into the current sparse set.
430//    // Begin by inserting the initial (potentially) partial lo quad.
431//    const bitquad_t lo_quad = (FULL_QUAD_MASK << lo_offset);
432//    const bitquad_t hi_quad = (FULL_QUAD_MASK >> (QUAD_BITS - 1 - hi_offset));
433//    bitquad_t quad = (lo_quad_no == hi_quad_no) ? (lo_quad & hi_quad) : lo_quad;
434//    run_type_t newType = (quad == FULL_QUAD_MASK) ? Full : ((quad == 0) ? Empty : Mixed);
435//    run_type_t runType = typeOf(*r);
436//    // If the original run is Mixed, we may be able to simply update the quad accordingly.
437//    if (runType == Mixed) {
438//        q += (lo_quad_no - offset);
439//        quad |= *q;
440//        if (LLVM_LIKELY(quad != FULL_QUAD_MASK)) {
441//            *q = quad;
442//            if (lo_quad_no == hi_quad_no) {
443//                return;
444//            }
445//        } else { // we filled a Mixed quad
446//            mQuads.erase(q);
447//        }
448//        newType = Full;
449//    }
450//    auto length = lengthOf(*r);
451//    auto splitAt = length - (lo_quad_no - offset) - 1;
452//    if (splitAt) {
453//        // reduce the original run length
454//        lengthOf(*r) = splitAt;
455//        // and add in a new quad
456//        r = mRuns.emplace(r, newType, 1);
457//    } else { // we're inserting this quad at the beginning of the run
458//        typeOf(*r) = newType;
459//        lengthOf(*r) = 1;
460//    }
461//    if (newType == Mixed) {
462//        q = mQuads.emplace(q, quad);
463//    }
464//    length -= splitAt + 1;
465//    auto remaining = (hi_quad_no - lo_quad_no);
466//    // We're inserting a Full run so if the original run type was Full and exceeds the
467//    // length of what we're inserting, we can abort without considering the hi_quad
468//    if (runType == Full && length > remaining) {
469//        return;
470//    }
471//    if (remaining) {
472//        r = mRuns.emplace(r, Full, remaining);
473
474
475
476//    }
477
478//}
479
480
481
482/** ------------------------------------------------------------------------------------------------------------- *
483 * @brief contains
484 * @param codepoint
485 *
486 * Return whether this UnicodeSet contains the specified code point
487 ** ------------------------------------------------------------------------------------------------------------- */
488bool UnicodeSet::contains(const codepoint_t codepoint) const {
489    auto n = codepoint / QUAD_BITS;
490    auto qi = mQuads.cbegin();
491    for (const auto & r : mRuns) {
492        if (lengthOf(r) >= n) {
493            if (typeOf(r) == Mixed) {
494                qi += n - 1;
495                return (*qi & (static_cast<bitquad_t>(1) << (codepoint & MOD_QUAD_BIT_MASK))) != 0;
496            }
497            return (typeOf(r) == Full);
498        }
499        if (typeOf(r) == Mixed) {
500            qi += lengthOf(r);
501        }       
502        n -= lengthOf(r);
503    }
504    return false;
505}
506
507/** ------------------------------------------------------------------------------------------------------------- *
508 * @brief intersects
509 * @param lo_codepoint
510 * @param hi_codepoint
511 *
512 * Return true if this UnicodeSet contains any code point(s) between lo and hi (inclusive)
513 ** ------------------------------------------------------------------------------------------------------------- */
514bool UnicodeSet::intersects(const codepoint_t lo, const codepoint_t hi) const {
515    for (auto range : *this) {
516        if (range.second < lo) {
517            continue;
518        }
519        if (range.first > hi) {
520            break;
521        }
522        return true;
523    }
524    return false;
525}
526
527/** ------------------------------------------------------------------------------------------------------------- *
528 * @brief UnicodeSet::quad_iterator::advance
529 ** ------------------------------------------------------------------------------------------------------------- */
530void UnicodeSet::quad_iterator::advance(unsigned n) {
531    while (n > 0) {
532        const unsigned remain = lengthOf(*mRunIterator) - mOffset;
533        if (remain > n) {
534            if (typeOf(*mRunIterator) == Mixed) {
535                mQuadIterator += n;
536            }
537            mOffset += n;
538            break;
539        }
540        if (typeOf(*mRunIterator) == Mixed) {
541            mQuadIterator += remain;
542        }
543        ++mRunIterator;
544        mOffset = 0;
545        n -= remain;
546    }
547}
548
549/** ------------------------------------------------------------------------------------------------------------- *
550 * @brief UnicodeSet::iterator::advance
551 ** ------------------------------------------------------------------------------------------------------------- */
552void UnicodeSet::iterator::advance(const unsigned n) {
553
554    assert (n == 1);
555
556    if (LLVM_UNLIKELY(mMinCodePoint >= 0x110000)) {
557        throw std::runtime_error("UnicodeSet iterator exceeded maximum code point.");
558    }
559
560    bool found = false;
561    // Find the start of our interval
562    while ( mBaseCodePoint < 0x110000 ) {
563        // Find the first non-empty block
564        if (typeOf(*mRunIterator) != Mixed) {           
565            // If we found a full run, this must be the start of our interval.
566            const auto baseCodePoint = mBaseCodePoint;
567            const auto type = typeOf(*mRunIterator);
568            mBaseCodePoint += lengthOf(*mRunIterator++) * QUAD_BITS;
569            if (type == Full) {
570                mMinCodePoint = baseCodePoint;
571                found = true;
572                break;
573            }
574        } else { // if (typeOf(t) == Mixed)
575            while (mMixedRunIndex != lengthOf(*mRunIterator)) {
576                const bitquad_t m = (*mQuadIterator) & (FULL_QUAD_MASK << mQuadOffset);
577                // If we found a marker in m, it marks the beginning of our current interval.
578                // Find it and break out of the loop.
579                if (m) {
580                    mQuadOffset = scan_forward_zeroes(m);
581                    mMinCodePoint = mBaseCodePoint + mQuadOffset;
582                    found = true;
583                    break;
584                }
585                mBaseCodePoint += QUAD_BITS;
586                ++mQuadIterator;
587                ++mMixedRunIndex;
588                mQuadOffset = 0;
589            }
590            if (found) break;
591            ++mRunIterator;
592            mQuadOffset = 0;
593            mMixedRunIndex = 0;
594        }
595    }
596
597    if (!found) {
598        assert (mBaseCodePoint == 0x110000);
599        mMinCodePoint = 0x110000;
600        return;
601    }
602
603    // at this stage, the max code point is the previous max code point (initially 0)
604    assert (mMaxCodePoint <= mMinCodePoint);
605    found = false;
606    // Find the end of our interval
607    while ( mBaseCodePoint < 0x110000 ) {
608
609        // Find the first non-Full block
610        if (typeOf(*mRunIterator) != Mixed) {
611            // If this run is Empty, the max code point is the last computed base code point - 1.
612            const auto baseCodePoint = mBaseCodePoint;
613            const auto type = typeOf(*mRunIterator);
614            mBaseCodePoint += lengthOf(*mRunIterator++) * QUAD_BITS;
615            if (type == Empty) {
616                mMaxCodePoint = baseCodePoint - 1;
617                found = true;
618                break;
619            }
620        } else { // if (typeOf(t) == Mixed)
621            while (mMixedRunIndex != lengthOf(*mRunIterator)) {
622                const bitquad_t m = ((~(*mQuadIterator)) & FULL_QUAD_MASK) & (FULL_QUAD_MASK << mQuadOffset);
623
624                // If we found a marker in m, it marks the end of our current interval.
625                // Find it and break out of the loop.
626                if (m) {
627                    mQuadOffset = scan_forward_zeroes(m);
628                    mMaxCodePoint = mBaseCodePoint + mQuadOffset - 1;
629                    found = true;
630                    break;
631                }
632                mBaseCodePoint += QUAD_BITS;
633                ++mQuadIterator;
634                ++mMixedRunIndex;
635                mQuadOffset = 0;
636            }
637            if (found) break;
638            ++mRunIterator;
639            mQuadOffset = 0;
640            mMixedRunIndex = 0;
641        }
642    }
643    // if the very last block is a mixed block and we go past it, the last code point of the range is 0x10FFFF
644    if (!found) {
645        assert (mBaseCodePoint == 0x110000);
646        mMaxCodePoint = 0x10FFFF;
647    }
648
649    assert (mMinCodePoint <= mMaxCodePoint);
650}
651
652/** ------------------------------------------------------------------------------------------------------------- *
653 * @brief Empty Set Constructor
654 ** ------------------------------------------------------------------------------------------------------------- */
655UnicodeSet::UnicodeSet() : mRuns({{{Empty, UNICODE_QUAD_COUNT}}}) { }
656
657/** ------------------------------------------------------------------------------------------------------------- *
658 * @brief Singleton Set Constructor
659 ** ------------------------------------------------------------------------------------------------------------- */
660UnicodeSet::UnicodeSet(const codepoint_t codepoint) {
661    const codepoint_t quad_no = codepoint / QUAD_BITS;
662    if (quad_no > 0) {
663        append_run(Empty, quad_no, mRuns);
664    }
665    append_quad(static_cast<bitquad_t>(1) << (codepoint & MOD_QUAD_BIT_MASK), mQuads, mRuns);
666    if (quad_no < UNICODE_QUAD_COUNT - 1) {
667        append_run(Empty, UNICODE_QUAD_COUNT - (quad_no + 1), mRuns);
668    }
669    assert (runLengthSumsUpToUnicodeQuadCount(mRuns));
670}
671
672/** ------------------------------------------------------------------------------------------------------------- *
673 * @brief Range Set Constructor
674 ** ------------------------------------------------------------------------------------------------------------- */
675UnicodeSet::UnicodeSet(const codepoint_t lo_codepoint, const codepoint_t hi_codepoint) {
676    const codepoint_t lo_quad_no = lo_codepoint / QUAD_BITS;
677    const codepoint_t hi_quad_no = hi_codepoint / QUAD_BITS;
678    const codepoint_t lo_offset = lo_codepoint & MOD_QUAD_BIT_MASK;
679    const codepoint_t hi_offset = hi_codepoint & MOD_QUAD_BIT_MASK;
680    const bitquad_t lo_quad = (FULL_QUAD_MASK << lo_offset);
681    const bitquad_t hi_quad = (FULL_QUAD_MASK >> (QUAD_BITS - 1 - hi_offset));
682    append_run(Empty, lo_quad_no, mRuns);
683    if (lo_quad_no == hi_quad_no) {       
684        append_quad(lo_quad & hi_quad, mQuads, mRuns);
685    }
686    else {
687        append_quad(lo_quad, mQuads, mRuns);
688        append_run(Full, hi_quad_no - (lo_quad_no + 1), mRuns);
689        append_quad(hi_quad, mQuads, mRuns);
690    }
691    if (hi_quad_no < UNICODE_QUAD_COUNT - 1) {
692        append_run(Empty, UNICODE_QUAD_COUNT - (hi_quad_no + 1), mRuns);
693    }
694    assert (runLengthSumsUpToUnicodeQuadCount(mRuns));
695}
696
697}
Note: See TracBrowser for help on using the repository browser.