HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
font_glyph_ids.hpp
1// Copyright Take Vos 2020-2021.
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 "glyph_id.hpp"
8#include "font_id.hpp"
9#include "../hash.hpp"
10#include "../tagged_id.hpp"
11#include "../geometry/axis_aligned_rectangle.hpp"
12#include <tuple>
13
14namespace tt {
15struct graphic_path;
16}
17
18namespace tt {
19
20// "Compatibility mappings are guaranteed to be no longer than 18 characters, although most consist of just a few characters."
21// https://unicode.org/reports/tr44/ (TR44 5.7.3)
23 int8_t nr_glyphs = 0;
25
26 font_glyph_ids_long() noexcept = delete;
27 font_glyph_ids_long(font_glyph_ids_long const &rhs) noexcept = default;
28 font_glyph_ids_long(font_glyph_ids_long &&rhs) noexcept = default;
29 font_glyph_ids_long &operator=(font_glyph_ids_long const &rhs) noexcept = default;
30 font_glyph_ids_long &operator=(font_glyph_ids_long &&rhs) noexcept = default;
31
32 font_glyph_ids_long(glyph_id g1, glyph_id g2, glyph_id g3) noexcept {
33 (*this) += g1;
34 (*this) += g2;
35 (*this) += g3;
36 }
37
38 font_glyph_ids_long operator+=(glyph_id rhs) noexcept {
39 tt_axiom(nr_glyphs >= 0);
40 tt_axiom(nr_glyphs < std::ssize(glyph_ids));
41 glyph_ids[nr_glyphs++] = rhs;
42 return *this;
43 }
44
45 [[nodiscard]] size_t hash() const noexcept {
46 tt_axiom(nr_glyphs > 3);
47 tt_axiom(nr_glyphs < std::ssize(glyph_ids));
48
49 uint64_t r = 0;
50 for (int8_t i = 0; i != nr_glyphs; ++i) {
51 r = hash_mix_two(r, std::hash<glyph_id>{}(glyph_ids[i]));
52 }
53
54 return r;
55 }
56
57 [[nodiscard]] friend bool operator==(font_glyph_ids_long const &lhs, font_glyph_ids_long const &rhs) noexcept {
58 tt_axiom(lhs.nr_glyphs > 3);
59 tt_axiom(rhs.nr_glyphs > 3);
60 tt_axiom(lhs.nr_glyphs < std::ssize(lhs.glyph_ids));
61 tt_axiom(rhs.nr_glyphs < std::ssize(rhs.glyph_ids));
62
63 if (lhs.nr_glyphs == rhs.nr_glyphs) {
64 for (int8_t i = 0; i != lhs.nr_glyphs; ++i) {
65 if (lhs.glyph_ids[i] != rhs.glyph_ids[i]) {
66 return false;
67 }
68 }
69 return true;
70 } else {
71 return false;
72 }
73 }
74
75 friend class font_glyph_ids;
76};
77
79 constexpr static uint64_t empty = 0xffff'ffff'ffff'ffff;
80
81 /*
82 * 0 to 3 glyph_ids, with or without a font_id.
83 * 63:48 glyph_id[2]
84 * 47:32 glyph_id[1]
85 * 31:16 glyph_id[0]
86 * 15 '1'
87 * 14: 0 font_id
88 *
89 * More than 3 glyphs
90 * 63:16 fontGlyphsIDs_long *
91 * 15 '0'
92 * 14: 0 font_id
93 */
94 uint64_t value;
95
96public:
97 font_glyph_ids() noexcept : value(empty) {}
98
99 font_glyph_ids(font_glyph_ids const &rhs) noexcept : value(rhs.value) {
100 if (rhs.has_pointer()) {
101 value = new_pointer(*(rhs.get_pointer()));
102 }
103 }
104
105 font_glyph_ids(font_glyph_ids &&rhs) noexcept : value(rhs.value) {
106 rhs.value = empty;
107 }
108
109 font_glyph_ids &operator=(font_glyph_ids const &rhs) noexcept {
110 if (this != &rhs) {
111 delete_pointer();
112 value = rhs.value;
113 if (rhs.has_pointer()) {
114 value = new_pointer(*(rhs.get_pointer()));
115 }
116 }
117 return *this;
118 }
119
120 font_glyph_ids &operator=(font_glyph_ids &&rhs) noexcept {
121 if (this != &rhs) {
122 using std::swap;
123 swap(value, rhs.value);
124 }
125 return *this;
126 }
127
128 ~font_glyph_ids() noexcept {
129 delete_pointer();
130 }
131
132 void clear() noexcept {
133 delete_pointer();
134 value = empty;
135 }
136
137 operator bool () const noexcept {
138 return size() > 0;
139 }
140
141 [[nodiscard]] tt::font_id font_id() const noexcept
142 {
143 return tt::font_id{value & font_id::mask};
144 }
145
146 void set_font_id(tt::font_id font_id) noexcept
147 {
148 value = (value & ~static_cast<uint64_t>(font_id::mask)) | static_cast<uint64_t>(font_id);
149 }
150
151 font_glyph_ids &operator+=(glyph_id rhs) noexcept {
152 switch (size()) {
153 case 0: value = (value & 0xffff'ffff'0000'ffff) | (static_cast<uint64_t>(rhs) << 16); break;
154 case 1: value = (value & 0xffff'0000'ffff'ffff) | (static_cast<uint64_t>(rhs) << 32); break;
155 case 2: value = (value & 0x0000'ffff'ffff'ffff) | (static_cast<uint64_t>(rhs) << 48); break;
156 case 3:
157 value = (value & font_id::mask) | new_pointer((*this)[0], (*this)[1], (*this)[2]);
158 [[fallthrough]];
159 default:
160 *(get_pointer()) += rhs;
161 }
162 return *this;
163 }
164
165 [[nodiscard]] glyph_id front() const noexcept {
166 if (size() == 0) {
167 return glyph_id{};
168 } else {
169 return (*this)[0];
170 }
171 }
172
173 [[nodiscard]] glyph_id operator[](size_t index) const noexcept {
174 if (has_pointer()) {
175 tt_axiom(index < 18);
176 return get_pointer()->glyph_ids[index];
177 } else {
178 switch (index) {
179 case 0: return glyph_id{(value >> 16) & glyph_id::mask};
180 case 1: return glyph_id{(value >> 32) & glyph_id::mask};
181 case 2: return glyph_id{(value >> 48) & glyph_id::mask};
182 default: tt_no_default();
183 }
184 }
185 }
186
187 [[nodiscard]] size_t size() const noexcept {
188 if (has_pointer()) {
189 return get_pointer()->nr_glyphs;
190 } else if (!(*this)[0]) {
191 return 0;
192 } else if (!(*this)[1]) {
193 return 1;
194 } else if (!(*this)[2]) {
195 return 2;
196 } else {
197 return 3;
198 }
199 }
200
201 [[nodiscard]] size_t hash() const noexcept {
202 if (has_pointer()) {
203 return get_pointer()->hash();
204 } else {
205 return std::hash<uint64_t>{}(value);
206 }
207 }
208
209 [[nodiscard]] std::pair<graphic_path,aarectangle> getPathAndBoundingBox() const noexcept;
210 [[nodiscard]] aarectangle getBoundingBox() const noexcept;
211
212private:
213 [[nodiscard]] bool has_pointer() const noexcept {
214 return (value & 0x8000) == 0;
215 }
216
217 [[nodiscard]] font_glyph_ids_long const *get_pointer() const noexcept {
218 tt_axiom(has_pointer());
219 return std::launder(reinterpret_cast<font_glyph_ids_long const *>(static_cast<ptrdiff_t>(value) >> 16));
220 }
221
222 [[nodiscard]] font_glyph_ids_long *get_pointer() noexcept {
223 tt_axiom(has_pointer());
224 return std::launder(reinterpret_cast<font_glyph_ids_long *>(static_cast<ptrdiff_t>(value) >> 16));
225 }
226
227 void delete_pointer() noexcept {
228 if (has_pointer()) {
229 delete get_pointer();
230 value = empty;
231 }
232 }
233
234 template<typename... Args>
235 [[nodiscard]] static uint64_t new_pointer(Args &&... args) noexcept {
236 auto *ptr = new font_glyph_ids_long(std::forward<Args>(args)...);
237 return static_cast<uint64_t>(reinterpret_cast<ptrdiff_t>(ptr) << 16);
238 }
239
240public:
241 [[nodiscard]] friend bool operator==(font_glyph_ids const &lhs, font_glyph_ids const &rhs) noexcept {
242 if (lhs.has_pointer() == rhs.has_pointer()) {
243 if (lhs.has_pointer()) {
244 return *(lhs.get_pointer()) == *(rhs.get_pointer());
245 } else {
246 return lhs.value == rhs.value;
247 }
248 } else {
249 tt_axiom(lhs.size() != rhs.size());
250 return false;
251 }
252 }
253};
254
255}
256
257namespace std {
258
259template<>
260struct hash<tt::font_glyph_ids> {
261 [[nodiscard]] size_t operator()(tt::font_glyph_ids const &rhs) const noexcept {
262 return rhs.hash();
263 }
264};
265
266}
STL namespace.
Class which represents an axis-aligned rectangle.
Definition axis_aligned_rectangle.hpp:18
Definition tagged_id.hpp:18
Definition font_glyph_ids.hpp:22
Definition font_glyph_ids.hpp:78
T operator()(T... args)
T swap(T... args)