HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
unicode_mask.hpp
1// Copyright Take Vos 2021-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "../utility/module.hpp"
8#include "grapheme.hpp"
9#include <cstdint>
10#include <cstddef>
11
12namespace hi::inline v1 {
13namespace detail {
14
16public:
17 static constexpr std::size_t size_bit = 11;
18 static constexpr std::size_t size_mask = (1_uz << size_bit) - 1;
19
20 constexpr unicode_mask_entry() noexcept : _value(0) {}
21
22 constexpr unicode_mask_entry(char32_t first, char32_t last) noexcept :
23 _value(narrow_cast<uint32_t>((first << size_bit) | (last - first)))
24 {
25 hi_axiom(last >= first);
26 hi_axiom(last - first <= capacity());
27 }
28
29 constexpr unicode_mask_entry(unicode_mask_entry const &) noexcept = default;
30 constexpr unicode_mask_entry(unicode_mask_entry &&) noexcept = default;
31 constexpr unicode_mask_entry &operator=(unicode_mask_entry const &) noexcept = default;
32 constexpr unicode_mask_entry &operator=(unicode_mask_entry &&) noexcept = default;
33
34 [[nodiscard]] static constexpr std::size_t capacity() noexcept
35 {
36 return size_mask;
37 }
38
39 [[nodiscard]] constexpr std::size_t size() const noexcept
40 {
41 return narrow_cast<std::size_t>(_value & size_mask);
42 }
43
44 [[nodiscard]] constexpr bool empty() const noexcept
45 {
46 return size() == 0;
47 }
48
49 [[nodiscard]] constexpr bool full() const noexcept
50 {
51 return size() == capacity();
52 }
53
54 [[nodiscard]] constexpr std::size_t room() const noexcept
55 {
56 return capacity() - size();
57 }
58
59 [[nodiscard]] constexpr char32_t begin() const noexcept
60 {
61 return narrow_cast<char32_t>(_value >> size_bit);
62 }
63
64 [[nodiscard]] constexpr char32_t end() const noexcept
65 {
66 return begin() + narrow_cast<char32_t>(size());
67 }
68
69 constexpr unicode_mask_entry &add_back(std::size_t num_code_points) noexcept
70 {
71 return *this = unicode_mask_entry{begin(), narrow_cast<char32_t>(end() + num_code_points)};
72 }
73
74 constexpr unicode_mask_entry &remove_front(std::size_t num_code_points) noexcept
75 {
76 return *this = unicode_mask_entry{narrow_cast<char32_t>(begin() + num_code_points), end()};
77 }
78
79 [[nodiscard]] constexpr bool contains(char32_t rhs) const noexcept
80 {
81 return (begin() <= rhs) and (rhs < end());
82 }
83
84private:
85 uint32_t _value;
86};
87
88} // namespace detail
89
102public:
103 constexpr unicode_mask() noexcept {}
104 constexpr unicode_mask(unicode_mask const &) noexcept = default;
105 constexpr unicode_mask(unicode_mask &&) noexcept = default;
106 constexpr unicode_mask &operator=(unicode_mask const &) noexcept = default;
107 constexpr unicode_mask &operator=(unicode_mask &&) noexcept = default;
108
109 [[nodiscard]] constexpr std::size_t size() const noexcept
110 {
111 return _size;
112 }
113
116 [[nodiscard]] bool contains(char32_t c) const noexcept;
117
120 [[nodiscard]] bool contains_composed(grapheme g) const noexcept;
121
124 [[nodiscard]] bool contains_decomposed(grapheme g) const noexcept;
125
128 [[nodiscard]] bool contains(grapheme g) const noexcept;
129
132 [[nodiscard]] bool contains(unicode_mask const &other) const noexcept;
133
139 void add(char32_t first, char32_t last) noexcept;
140
143 [[nodiscard]] friend unicode_mask operator|(unicode_mask const &lhs, unicode_mask const &rhs) noexcept
144 {
145 auto r = unicode_mask{};
146 r._entries.reserve(lhs._entries.size() * 2 + rhs._entries.size() * 2);
147
148 auto lhs_it = begin(lhs._entries);
149 auto rhs_it = begin(rhs._entries);
150 hilet lhs_end = end(lhs._entries);
151 hilet rhs_end = end(rhs._entries);
152
153 while (lhs_it != lhs_end or rhs_it != rhs_end) {
154 // clang-format off
155 auto &it =
156 (lhs_it == lhs_end) ? rhs_it :
157 (rhs_it == rhs_end) ? lhs_it :
158 (lhs_it->begin() < rhs_it->begin()) ? lhs_it : rhs_it;
159 // clang-format on
160
161 hilet new_begin = r._entries.empty() ? it->begin() : std::max(r._entries.back().end(), it->begin());
162 hilet new_end = it->end();
163 if (new_begin < new_end) {
164 r._entries.emplace_back(new_begin, new_end);
165 r._size += new_end - new_begin;
166 }
167 ++it;
168 }
169
170 // r.optimize();
171 return r;
172 }
173
177 {
178 return *this = *this | rhs;
179 }
180
183 void optimize() noexcept;
184
185 void shrink_to_fit() noexcept;
186
189 [[nodiscard]] bool holds_invariant() const noexcept;
190
191private:
192 using entry_type = detail::unicode_mask_entry;
193 using entries_type = std::vector<entry_type>;
194 using iterator = typename entries_type::iterator;
195 using const_iterator = typename entries_type::const_iterator;
196
197 std::size_t _size = 0;
198 entries_type _entries = {};
199};
200
201} // namespace hi::inline v1
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:238
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
STL namespace.
DOXYGEN BUG.
Definition algorithm.hpp:13
A grapheme-cluster, what a user thinks a character is.
Definition grapheme.hpp:39
Definition unicode_mask.hpp:15
A mask of unicode code-points.
Definition unicode_mask.hpp:101
bool contains(char32_t c) const noexcept
Check if the given code point is covered by this mask.
bool contains_decomposed(grapheme g) const noexcept
Check if the full grapheme normalized to NFD is covered by this mask.
bool contains(unicode_mask const &other) const noexcept
Check if all the code-points in other are covered by this mask.
bool contains_composed(grapheme g) const noexcept
Check if the full grapheme normalized to NFC is covered by this mask.
void add(char32_t first, char32_t last) noexcept
Add a range of unicode code points to this mask.
friend unicode_mask operator|(unicode_mask const &lhs, unicode_mask const &rhs) noexcept
Combine two masks.
Definition unicode_mask.hpp:143
unicode_mask & operator|=(unicode_mask const &rhs) noexcept
Combine two masks.
Definition unicode_mask.hpp:176
bool contains(grapheme g) const noexcept
Check if the full grapheme is covered by this mask.
void optimize() noexcept
Optimize storage.
T max(T... args)
T reserve(T... args)