38 tt_assume(nr_glyphs >= 0);
39 tt_assume(nr_glyphs < ssize(glyph_ids));
40 glyph_ids[nr_glyphs++] = rhs;
44 [[nodiscard]]
size_t hash()
const noexcept {
45 tt_assume(nr_glyphs > 3);
46 tt_assume(nr_glyphs < ssize(glyph_ids));
49 for (int8_t i = 0; i != nr_glyphs; ++i) {
57 tt_assume(lhs.nr_glyphs > 3);
58 tt_assume(rhs.nr_glyphs > 3);
59 tt_assume(lhs.nr_glyphs < ssize(lhs.glyph_ids));
60 tt_assume(rhs.nr_glyphs < ssize(rhs.glyph_ids));
62 if (lhs.nr_glyphs == rhs.nr_glyphs) {
63 for (int8_t i = 0; i != lhs.nr_glyphs; ++i) {
64 if (lhs.glyph_ids[i] != rhs.glyph_ids[i]) {
78 constexpr static uint64_t empty = 0xffff'ffff'ffff'ffff;
96 tt_force_inline
FontGlyphIDs() noexcept : value(empty) {}
99 if (rhs.has_pointer()) {
100 value = new_pointer(*(rhs.get_pointer()));
112 if (rhs.has_pointer()) {
113 value = new_pointer(*(rhs.get_pointer()));
122 swap(value, rhs.value);
131 void clear()
noexcept {
136 tt_force_inline
operator bool ()
const noexcept {
140 [[nodiscard]] tt_force_inline
FontID font_id()
const noexcept {
141 return FontID{value & FontID::mask};
144 tt_force_inline
void set_font_id(
FontID font_id)
noexcept {
145 value = (value & ~static_cast<uint64_t>(FontID::mask)) |
static_cast<uint64_t
>(font_id);
150 case 0: value = (value & 0xffff'ffff'0000'ffff) | (
static_cast<uint64_t
>(rhs) << 16);
break;
151 case 1: value = (value & 0xffff'0000'ffff'ffff) | (
static_cast<uint64_t
>(rhs) << 32);
break;
152 case 2: value = (value & 0x0000'ffff'ffff'ffff) | (
static_cast<uint64_t
>(rhs) << 48);
break;
154 value = (value & FontID::mask) | new_pointer((*
this)[0], (*this)[1], (*this)[2]);
157 *(get_pointer()) += rhs;
162 [[nodiscard]] tt_force_inline
GlyphID front()
const noexcept {
170 [[nodiscard]] tt_force_inline
GlyphID operator[](
size_t index)
const noexcept {
172 tt_assume(index < 18);
173 return get_pointer()->glyph_ids[index];
176 case 0:
return GlyphID{(value >> 16) & GlyphID::mask};
177 case 1:
return GlyphID{(value >> 32) & GlyphID::mask};
178 case 2:
return GlyphID{(value >> 48) & GlyphID::mask};
179 default: tt_no_default;
184 [[nodiscard]] tt_force_inline
size_t size()
const noexcept {
186 return get_pointer()->nr_glyphs;
187 }
else if (!(*
this)[0]) {
189 }
else if (!(*
this)[1]) {
191 }
else if (!(*
this)[2]) {
198 [[nodiscard]]
size_t hash()
const noexcept {
200 return get_pointer()->hash();
207 [[nodiscard]]
aarect getBoundingBox()
const noexcept;
210 [[nodiscard]] tt_force_inline
bool has_pointer()
const noexcept {
211 return (value & 0x8000) == 0;
214 [[nodiscard]] tt_force_inline
FontGlyphIDs_long const *get_pointer()
const noexcept {
215 tt_assume(has_pointer());
216 return std::launder(
reinterpret_cast<FontGlyphIDs_long const *
>(
static_cast<ptrdiff_t
>(value) >> 16));
220 tt_assume(has_pointer());
221 return std::launder(
reinterpret_cast<FontGlyphIDs_long *
>(
static_cast<ptrdiff_t
>(value) >> 16));
224 void delete_pointer()
noexcept {
226 delete get_pointer();
231 template<
typename... Args>
232 [[nodiscard]]
static uint64_t new_pointer(Args &&... args)
noexcept {
234 return static_cast<uint64_t
>(
reinterpret_cast<ptrdiff_t
>(ptr) << 16);
239 if (lhs.has_pointer() == rhs.has_pointer()) {
240 if (lhs.has_pointer()) {
241 return *(lhs.get_pointer()) == *(rhs.get_pointer());
243 return lhs.value == rhs.value;
246 tt_assume(lhs.size() != rhs.size());