Terminal++ 4.0.2.6
A C++ library for interacting with ANSI terminal windows
Loading...
Searching...
No Matches
glyph.hpp
1#pragma once
2
3#include "terminalpp/character_set.hpp"
4#include "terminalpp/core.hpp"
5#include "terminalpp/detail/ascii.hpp"
6
7#include <boost/container_hash/hash.hpp>
8
9#include <compare>
10#include <iosfwd>
11#include <cstddef>
12
13namespace terminalpp {
14
15//* =========================================================================
18//* =========================================================================
20{
21public:
22 //* =====================================================================
27 //* =====================================================================
28 constexpr glyph( // NOLINT
29 byte const character = detail::ascii::space,
30 character_set const charset = character_set()) noexcept
31 : character_(character), charset_(charset)
32 {
33 }
34
35 //* =====================================================================
37 //* =====================================================================
38 explicit constexpr glyph(byte const (&text)[2]) noexcept
39 : ucharacter_{text[0]}, charset_(terminalpp::charset::utf8)
40 {
41 }
42
43 //* =====================================================================
45 //* =====================================================================
46 explicit constexpr glyph(byte const (&text)[3]) noexcept
47 : ucharacter_{text[0], text[1]}, charset_(terminalpp::charset::utf8)
48 {
49 }
50
51 //* =====================================================================
53 //* =====================================================================
54 explicit constexpr glyph(byte const (&text)[4]) noexcept
55 : ucharacter_{text[0], text[1], text[2]},
56 charset_(terminalpp::charset::utf8)
57 {
58 }
59
60 //* =====================================================================
62 //* =====================================================================
63 explicit constexpr glyph(char8_t const (&text)[2]) noexcept
64 : ucharacter_{text[0]}, charset_(terminalpp::charset::utf8)
65 {
66 }
67
68 //* =====================================================================
70 //* =====================================================================
71 explicit constexpr glyph(char8_t const (&text)[3]) noexcept
72 : ucharacter_{text[0], text[1]}, charset_(terminalpp::charset::utf8)
73 {
74 }
75
76 //* =====================================================================
78 //* =====================================================================
79 explicit constexpr glyph(char8_t const (&text)[4]) noexcept
80 : ucharacter_{text[0], text[1], text[2]},
81 charset_(terminalpp::charset::utf8)
82 {
83 }
84
85 template <std::size_t N>
86 explicit glyph(byte const (&text)[N]) noexcept
87 requires(N > 5)
88 : ucharacter_{0}, charset_(terminalpp::charset::utf8)
89 {
90 assign_utf8_bytes(text, N - 1);
91 }
92
93 template <std::size_t N>
94 explicit glyph(char8_t const (&text)[N]) noexcept
95 requires(N > 5)
96 : ucharacter_{0}, charset_(terminalpp::charset::utf8)
97 {
98 assign_utf8_bytes(reinterpret_cast<byte const *>(text), N - 1);
99 }
100
101 //* =====================================================================
111 //* =====================================================================
112 template <class T = void> // This makes matching these parameters "worse"
113 // than any of the array matches above, and so
114 // avoids ambiguity.
115 explicit constexpr glyph(char const *ustr) noexcept
116 : ucharacter_{0}, charset_(terminalpp::charset::utf8)
117 {
118 for (size_t index = 0; index < sizeof(ucharacter_); ++index)
119 {
120 ucharacter_[index] = static_cast<byte>(ustr[index]);
121
122 if (!(ucharacter_[index] & 0x80))
123 {
124 break;
125 }
126 }
127 }
128
129 //* =====================================================================
131 //* =====================================================================
133 [[nodiscard]] constexpr friend auto operator<=>(
134 glyph const &lhs, glyph const &rhs) noexcept
135 {
136 if (lhs < rhs) return std::strong_ordering::less; // NOLINT
137 if (rhs < lhs) return std::strong_ordering::greater; // NOLINT
138 return std::strong_ordering::equal;
139 }
140
141 //* =====================================================================
143 //* =====================================================================
145 [[nodiscard]] constexpr friend bool operator==(
146 glyph const &lhs, glyph const &rhs) noexcept
147 {
148 if (lhs.charset_ == rhs.charset_)
149 {
150 if (lhs.charset_ == terminalpp::charset::utf8)
151 {
152 using std::begin;
153 using std::end;
154
155 // Re-implementing std::equal here for constexprness.
156 for (auto lch = begin(lhs.ucharacter_),
157 rch = begin(rhs.ucharacter_);
158 lch != end(lhs.ucharacter_);
159 ++lch, ++rch)
160 {
161 if (*lch != *rch)
162 {
163 return false;
164 }
165 }
166
167 return true;
168 }
169 else
170 {
171 return lhs.character_ == rhs.character_;
172 }
173 }
174
175 return false;
176 }
177
178 //* =====================================================================
180 //* =====================================================================
181 [[nodiscard]] constexpr friend bool operator<(
182 glyph const &lhs, glyph const &rhs) noexcept
183 {
184 if (lhs.charset_ < rhs.charset_)
185 {
186 return true;
187 }
188
189 if (lhs.charset_ == rhs.charset_)
190 {
191 if (lhs.charset_ == terminalpp::charset::utf8)
192 {
193 using std::begin;
194 using std::end;
195
196 // Reimplementing lexicographical_compare here for
197 // constexprness.
198 for (auto begin1 = begin(lhs.ucharacter_),
199 end1 = end(lhs.ucharacter_),
200 begin2 = begin(rhs.ucharacter_);
201 begin1 != end1;
202 ++begin1, ++begin2)
203 {
204 // We are expecting unicode characters to be ordered so that
205 // outside of the ASCII range is greater, so therefore we
206 // must remove the sign from these comparisons.
207 if (byte(*begin1) < byte(*begin2)) return true; // NOLINT
208 if (byte(*begin2) < byte(*begin1)) return false; // NOLINT
209 }
210
211 return false;
212 }
213
214 return lhs.character_ < rhs.character_;
215 }
216
217 return false;
218 }
219
220 //* =====================================================================
222 //* =====================================================================
223 [[nodiscard]] friend std::size_t hash_value(glyph const &gly) noexcept
224 {
225 std::size_t seed = 0;
226 boost::hash_combine(seed, gly.charset_);
227
228 if (gly.charset_ == terminalpp::charset::utf8)
229 {
230 for (auto ch : gly.ucharacter_)
231 {
232 boost::hash_combine(seed, ch);
233 }
234 }
235 else
236 {
237 boost::hash_combine(seed, gly.character_);
238 }
239
240 return seed;
241 }
242
243 union
244 {
245 byte character_;
246 byte ucharacter_[3];
247 };
248
249 character_set charset_;
250
251private:
252 void assign_utf8_bytes(byte const *text, std::size_t length) noexcept;
253
254 [[nodiscard]] constexpr bool uses_pooled_utf8() const noexcept
255 {
256 return charset_ == terminalpp::charset::utf8 && ucharacter_[0] == 0xFF;
257 }
258
259 friend TERMINALPP_EXPORT bytes utf8_bytes(glyph const &gly) noexcept;
260};
261
262//* =========================================================================
264//* =========================================================================
265TERMINALPP_EXPORT
266bool is_printable(glyph const &gly) noexcept;
267
268//* =========================================================================
271//* =========================================================================
272TERMINALPP_EXPORT
273std::ostream &operator<<(std::ostream &out, glyph const &gly);
274
275} // namespace terminalpp
276
277namespace std {
278
279template <>
280struct hash<terminalpp::glyph>
281{
283 using result_type = std::size_t;
284
285 [[nodiscard]] result_type operator()(
286 argument_type const &elem) const noexcept
287 {
288 return hash_value(elem);
289 }
290};
291
292} // namespace std
A structure that represents a character set.
Definition character_set.hpp:44
A structure representing an ANSI graphics effect (e.g. intensity, underlining)
Definition effect.hpp:27
constexpr effect() noexcept
Initialises the intensity to the default (normal) value.
Definition effect.hpp:31
A structure that carries around the character attributes of an ANSI element.
Definition glyph.hpp:20
friend std::size_t hash_value(glyph const &gly) noexcept
Hash function.
Definition glyph.hpp:223
constexpr glyph(byte const (&text)[4]) noexcept
Constructs a UTF-8 glyph from a char sequence.
Definition glyph.hpp:54
constexpr glyph(char8_t const (&text)[4]) noexcept
Constructs a UTF-8 glyph from a char sequence.
Definition glyph.hpp:79
constexpr glyph(char8_t const (&text)[2]) noexcept
Constructs a UTF-8 glyph from a char sequence.
Definition glyph.hpp:63
constexpr friend bool operator<(glyph const &lhs, glyph const &rhs) noexcept
Less-than operator.
Definition glyph.hpp:181
constexpr glyph(byte const (&text)[2]) noexcept
Constructs a UTF-8 glyph from a char sequence.
Definition glyph.hpp:38
constexpr glyph(char8_t const (&text)[3]) noexcept
Constructs a UTF-8 glyph from a char sequence.
Definition glyph.hpp:71
constexpr glyph(char const *ustr) noexcept
Constructs a UTF-8 glyph from a char sequence.
Definition glyph.hpp:115
constexpr glyph(byte const character=detail::ascii::space, character_set const charset=character_set()) noexcept
Default Constructor.
Definition glyph.hpp:28
constexpr glyph(byte const (&text)[3]) noexcept
Constructs a UTF-8 glyph from a char sequence.
Definition glyph.hpp:46
TERMINALPP_EXPORT constexpr friend bool operator==(glyph const &lhs, glyph const &rhs) noexcept
Equality operator.
Definition glyph.hpp:145
TERMINALPP_EXPORT constexpr friend auto operator<=>(glyph const &lhs, glyph const &rhs) noexcept
Relational operators for glyphs.
Definition glyph.hpp:133