HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
glyph_ids.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 "glyph_id.hpp"
8#include "glyph_atlas_info.hpp"
9#include "../graphic_path.hpp"
10#include "../geometry/module.hpp"
11#include "../utility/module.hpp"
12#include <bit>
13#include <memory>
14#include <cstddef>
15#include <array>
16#include <cstdint>
17#include <functional>
18
19hi_warning_push();
20// C26401: Do not delete a raw pointer that is not an owner<T> (i.11).
21// False positive, ~glyph_ids::glyph_ids() is owner of glyphs_ids::_ptr.
22hi_warning_ignore_msvc(26401);
23// C26409: Avoid calling new and delete explicitly, use std::make_unique<T> instead (r.11).
24// glyph_ids implements a container.
25hi_warning_ignore_msvc(26409);
26
27namespace hi::inline v1 {
28class font;
29
30namespace detail {
31
33public:
34 constexpr glyph_ids_long(glyph_ids_long const&) noexcept = default;
35 constexpr glyph_ids_long(glyph_ids_long&&) noexcept = default;
36 constexpr glyph_ids_long& operator=(glyph_ids_long const&) noexcept = default;
37 constexpr glyph_ids_long& operator=(glyph_ids_long&&) noexcept = default;
38
44 constexpr glyph_ids_long(std::size_t value, glyph_id new_id) noexcept : _num_glyphs(), _num_graphemes(), _glyphs()
45 {
46 if constexpr (sizeof(std::size_t) == 4) {
47 _num_glyphs = 2;
48 _num_graphemes = (value >> 4) & 0xf;
49 std::get<0>(_glyphs) = glyph_id{(value >> 16) & 0xffff};
50 std::get<1>(_glyphs) = new_id;
51 } else {
52 _num_glyphs = 4;
53 _num_graphemes = (value >> 4) & 0xf;
54 std::get<0>(_glyphs) = glyph_id{(value >> 16) & 0xffff};
55 std::get<1>(_glyphs) = glyph_id{(value >> 32) & 0xffff};
56 std::get<2>(_glyphs) = glyph_id{(value >> 48) & 0xffff};
57 std::get<3>(_glyphs) = new_id;
58 }
59 }
60
61 [[nodiscard]] constexpr std::size_t num_glyphs() const noexcept
62 {
63 return _num_glyphs;
64 }
65
66 [[nodiscard]] constexpr std::size_t num_graphemes() const noexcept
67 {
68 return _num_graphemes;
69 }
70
71 constexpr void set_num_graphemes(std::size_t num_graphemes) noexcept
72 {
73 hi_axiom(num_graphemes <= 0xf);
74 _num_graphemes = narrow_cast<uint8_t>(num_graphemes);
75 }
76
77 [[nodiscard]] constexpr std::size_t hash() const noexcept
78 {
79 std::size_t r = 0;
80
81 for (auto i = 0_uz; i != _num_glyphs; ++i) {
82 r ^= *_glyphs[i];
83 r ^= std::rotl(r, 16);
84 }
85
86 return r;
87 }
88
89 constexpr glyph_ids_long& operator+=(glyph_id id) noexcept
90 {
91 // On overflow silently drop glyphs.
92 if (_num_glyphs < _glyphs.size()) {
93 _glyphs[_num_glyphs++] = id;
94 }
95 return *this;
96 }
97
98 [[nodiscard]] constexpr glyph_id const& operator[](std::size_t i) const noexcept
99 {
100 hi_axiom(i < _num_glyphs);
101 return _glyphs[i];
102 }
103
104 template<std::size_t I>
105 [[nodiscard]] constexpr friend glyph_id get(glyph_ids_long const& rhs) noexcept
106 {
107 hi_axiom(I < rhs._num_glyphs);
108 return std::get<I>(rhs._glyphs);
109 }
110
111 [[nodiscard]] constexpr friend bool operator==(glyph_ids_long const&, glyph_ids_long const&) noexcept = default;
112
113private:
114 uint8_t _num_glyphs;
115 uint8_t _num_graphemes;
116
117 // At least 18 glyphs to handle the maximum Unicode compatibility-decomposition.
118 // Given a 64 byte allocation chunk, 16 bytes overhead, 2 bytes for the _num_graphemes
119 // and _num_glyphs; we are left over with 46 bytes -> 23 glyphs.
121};
122
123} // namespace detail
124
135public:
136 constexpr ~glyph_ids()
137 {
138 if (is_long()) {
139 delete _ptr;
140 }
141 }
142
143 constexpr glyph_ids(glyph_ids const& other) noexcept : _font(other._font), _ptr(other._ptr)
144 {
145 if (is_long()) {
146 _ptr = new detail::glyph_ids_long(*_ptr);
147 }
148 }
149
150 constexpr glyph_ids& operator=(glyph_ids const& other) noexcept
151 {
152 hi_return_on_self_assignment(other);
153
154 _font = other._font;
155 if (is_long()) {
156 delete _ptr;
157 }
158 _ptr = other._ptr;
159 if (is_long()) {
160 _ptr = new detail::glyph_ids_long(*_ptr);
161 }
162 return *this;
163 }
164
165 constexpr glyph_ids(glyph_ids&& other) noexcept : _font(other._font), _ptr(std::exchange(other._ptr, make_ptr(1))) {}
166
167 constexpr glyph_ids& operator=(glyph_ids&& other) noexcept
168 {
169 _font = other._font;
170 std::swap(_ptr, other._ptr);
171 return *this;
172 }
173
179 constexpr glyph_ids() noexcept : _font(nullptr), _ptr(make_ptr(1)) {}
180
187 constexpr glyph_ids(hi::font const& font) noexcept : _font(&font), _ptr(make_ptr(1)) {}
188
191 [[nodiscard]] constexpr font const& font() const noexcept
192 {
193 hi_assert_not_null(_font);
194 return *_font;
195 }
196
199 void set_font(hi::font const& font) noexcept
200 {
201 _font = &font;
202 }
203
208 constexpr void clear() noexcept
209 {
210 if (is_long()) {
211 delete _ptr;
212 }
213 _ptr = make_ptr(1);
214 }
215
218 [[nodiscard]] constexpr bool empty() const noexcept
219 {
220 return _ptr == make_ptr(1);
221 }
222
225 constexpr operator bool() const noexcept
226 {
227 return not empty();
228 }
229
237 template<std::size_t N>
238 [[nodiscard]] constexpr bool has_num_glyphs() const noexcept
239 {
240 static_assert(N <= num_glyphs_mask);
241
242 constexpr std::size_t mask = (num_glyphs_mask << num_glyphs_shift) | 1;
243 constexpr std::size_t value = (N << num_glyphs_shift) | 1;
244 return (make_value(_ptr) & mask) == value;
245 }
246
249 [[nodiscard]] constexpr glyph_id get_single() const noexcept
250 {
251 hi_axiom(has_num_glyphs<1>());
252 return get_glyph(0);
253 }
254
257 [[nodiscard]] constexpr std::size_t num_glyphs() const noexcept
258 {
259 return is_long() ? _ptr->num_glyphs() : (make_value(_ptr) >> 1) & num_glyphs_mask;
260 }
261
262 [[nodiscard]] constexpr std::size_t num_graphemes() const noexcept
263 {
264 return is_long() ? _ptr->num_graphemes() : (make_value(_ptr) >> 4) & 0xf;
265 }
266
267 constexpr void set_num_graphemes(std::size_t num_graphemes) noexcept
268 {
269 if (is_long()) {
270 _ptr->set_num_graphemes(num_graphemes);
271 } else {
272 hi_axiom(num_graphemes <= num_graphemes_mask);
273 _ptr = make_ptr(
274 (make_value(_ptr) & ~(num_graphemes_mask << num_graphemes_shift)) | (num_graphemes << num_graphemes_shift));
275 }
276 }
277
280 [[nodiscard]] constexpr std::size_t hash() const noexcept
281 {
282 return is_long() ? _ptr->hash() : make_value(_ptr);
283 }
284
289 constexpr glyph_ids& operator+=(glyph_id id) noexcept
290 {
291 if (is_long()) {
292 *_ptr += id;
293
294 } else if (hilet index = short_num_glyphs(); index < num_glyphs_mask) {
295 increment_num_glyphs();
296 set_glyph(index, id);
297
298 } else {
299 _ptr = new detail::glyph_ids_long(make_value(_ptr), id);
300 }
301 return *this;
302 }
303
308 [[nodiscard]] constexpr glyph_id operator[](std::size_t index) const noexcept
309 {
310 hi_axiom(index < num_glyphs());
311
312 if (is_long()) {
313 return (*_ptr)[index];
314 } else {
315 return get_glyph(index);
316 }
317 }
318
319 template<std::size_t I>
320 [[nodiscard]] constexpr friend glyph_id get(glyph_ids const& rhs) noexcept
321 {
322 if (rhs.is_long()) {
323 return get<I>(*rhs._ptr);
324 } else {
325 constexpr std::size_t shift = (I + 1) * 16;
326 return glyph_id{(make_value(rhs._ptr) >> shift) & 0xffff};
327 }
328 }
329
330 [[nodiscard]] constexpr friend bool operator==(glyph_ids const& lhs, glyph_ids const& rhs) noexcept
331 {
332 hilet lhs_value = make_value(lhs._ptr);
333 hilet rhs_value = make_value(rhs._ptr);
334
335 if (lhs._font != rhs._font) {
336 return false;
337 } else if (lhs_value == rhs_value) {
338 return true;
339 } else {
340 return ((lhs_value | rhs_value) & 1) == 0 and *lhs._ptr == *rhs._ptr;
341 }
342 }
343
346 [[nodiscard]] glyph_atlas_info& atlas_info() const noexcept;
347
352 [[nodiscard]] std::pair<graphic_path, aarectangle> get_path_and_bounding_box() const noexcept;
353
358 [[nodiscard]] aarectangle get_bounding_box() const noexcept;
359
360private:
361 static_assert(sizeof(std::size_t) == sizeof(detail::glyph_ids_long *));
362
363 static constexpr std::size_t num_glyphs_shift = 1;
364 static constexpr std::size_t num_glyphs_mask = sizeof(std::size_t) == 4 ? 1 : 3;
365 static constexpr std::size_t num_graphemes_shift = 4;
366 static constexpr std::size_t num_graphemes_mask = 15;
367
368 hi::font const *_font;
369
381 detail::glyph_ids_long *_ptr;
382
383 constexpr void increment_num_glyphs() noexcept
384 {
385 hi_axiom(is_short());
386 hi_axiom(short_num_glyphs() < num_glyphs_mask);
387
388 _ptr = make_ptr(make_value(_ptr) + (1 << num_glyphs_shift));
389 }
390
391 [[nodiscard]] constexpr glyph_id get_glyph(std::size_t index) const noexcept
392 {
393 hi_axiom(is_short());
394
395 hilet shift = (index + 1) * 16;
396 return glyph_id{(make_value(_ptr) >> shift) & 0xffff};
397 }
398
399 constexpr void set_glyph(std::size_t i, glyph_id id) noexcept
400 {
401 hi_axiom(is_short());
402
403 hilet shift = (i + 1) * 16;
404 hilet mask = std::size_t{0xffff} << shift;
405 _ptr = make_ptr((make_value(_ptr) & ~mask) | (static_cast<std::size_t>(id) << shift));
406 }
407
408 [[nodiscard]] constexpr std::size_t short_num_glyphs() const noexcept
409 {
410 hi_axiom(is_short());
411 return (make_value(_ptr) >> num_glyphs_shift) & num_glyphs_mask;
412 }
413
414 [[nodiscard]] constexpr bool is_short() const noexcept
415 {
416 return to_bool(make_value(_ptr) & 1);
417 }
418
419 [[nodiscard]] constexpr bool is_long() const noexcept
420 {
421 return not is_short();
422 }
423
424 [[nodiscard]] static constexpr detail::glyph_ids_long *make_ptr(std::size_t value) noexcept
425 {
426 return std::bit_cast<detail::glyph_ids_long *>(value);
427 }
428
429 [[nodiscard]] static constexpr std::size_t make_value(detail::glyph_ids_long *ptr) noexcept
430 {
431 return std::bit_cast<std::size_t>(ptr);
432 }
433};
434
435} // namespace hi::inline v1
436
437template<>
438struct std::hash<hi::glyph_ids> {
439 [[nodiscard]] constexpr std::size_t operator()(hi::glyph_ids const& rhs) const noexcept
440 {
441 return rhs.hash();
442 }
443};
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:238
#define hi_assert_not_null(x,...)
Assert if an expression is not nullptr.
Definition assert.hpp:223
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
STL namespace.
DOXYGEN BUG.
Definition algorithm.hpp:13
@ shift
The shift key is being held.
geometry/margins.hpp
Definition cache.hpp:11
Definition font.hpp:31
Definition glyph_atlas_info.hpp:12
Definition glyph_ids.hpp:32
constexpr glyph_ids_long(std::size_t value, glyph_id new_id) noexcept
Construct a list of glyphs starting with a packed set of glyphs.
Definition glyph_ids.hpp:44
A set of glyph-ids of a font which composites into a single glyph.
Definition glyph_ids.hpp:134
glyph_atlas_info & atlas_info() const noexcept
Get information where the glyph is drawn in the atlas.
constexpr glyph_id get_single() const noexcept
Get the value of the single glyph.
Definition glyph_ids.hpp:249
constexpr std::size_t num_glyphs() const noexcept
Get the number of glyphs.
Definition glyph_ids.hpp:257
constexpr font const & font() const noexcept
Get the font for this glyph_ids object.
Definition glyph_ids.hpp:191
constexpr std::size_t hash() const noexcept
Get the hash value.
Definition glyph_ids.hpp:280
constexpr glyph_ids() noexcept
Create an empty glyph_ids object.
Definition glyph_ids.hpp:179
constexpr glyph_ids & operator+=(glyph_id id) noexcept
Add a glyph to this object.
Definition glyph_ids.hpp:289
constexpr bool has_num_glyphs() const noexcept
Check if this object contains a number of glyphs.
Definition glyph_ids.hpp:238
constexpr bool empty() const noexcept
Check if glyphs are attached.
Definition glyph_ids.hpp:218
constexpr glyph_id operator[](std::size_t index) const noexcept
Get a glyph.
Definition glyph_ids.hpp:308
constexpr void clear() noexcept
Clear the glyphs in this glyph_ids object.
Definition glyph_ids.hpp:208
void set_font(hi::font const &font) noexcept
Set the font for this glyph_ids object.
Definition glyph_ids.hpp:199
constexpr glyph_ids(hi::font const &font) noexcept
Create an empty glyph_ids for a font.
Definition glyph_ids.hpp:187
A path is a vector graphics object.
Definition graphic_path.hpp:26
T operator()(T... args)
T swap(T... args)