• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

KazDragon / terminalpp / 15773611171

20 Jun 2025 07:23AM UTC coverage: 97.867% (-0.2%) from 98.078%
15773611171

push

github

KazDragon
refactor: trimmed down virtual key test

1652 of 1688 relevant lines covered (97.87%)

146.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.98
/include/terminalpp/string.hpp
1
#pragma once
2

3
#include "terminalpp/element.hpp"
4

5
#include <boost/container_hash/hash.hpp>
6

7
#include <algorithm>
8
#include <concepts>  // IWYU pragma: keep
9
#include <initializer_list>
10
#include <string>
11
#include <vector>
12
#include <cstddef>
13

14
namespace terminalpp {
15

16
//* =========================================================================
17
/// \brief A class that represents strings of elements.
18
/// \par
19
/// Note: models an STL container.
20
//* =========================================================================
21
class TERMINALPP_EXPORT string
22
{
23
    using elements_storage = std::vector<element>;
24

25
public:
26
    //* =====================================================================
27
    /// Container Typedefs
28
    //* =====================================================================
29
    using value_type = element;
30
    using reference = value_type &;
31
    using const_reference = value_type const &;
32
    using pointer = element *;
33
    using const_pointer = element const *;
34
    using iterator = elements_storage::iterator;
35
    using const_iterator = elements_storage::const_iterator;
36
    using reverse_iterator = elements_storage::reverse_iterator;
37
    using const_reverse_iterator = elements_storage::const_reverse_iterator;
38
    using difference_type = std::ptrdiff_t;
39
    using size_type = std::size_t;
40

41
    //* =====================================================================
42
    /// \brief Constructor
43
    //* =====================================================================
44
    constexpr string() = default;
3✔
45

46
    //* =====================================================================
47
    /// \brief Range Constructor
48
    //* =====================================================================
49
    template <std::forward_iterator ForwardIterator>
50
    constexpr string(ForwardIterator &&begin, ForwardIterator &&end)
28✔
51
      : elements_{begin, end}
56✔
52
    {
53
    }
28✔
54

55
    //* =====================================================================
56
    /// \brief Initializer List Constructor
57
    //* =====================================================================
58
    constexpr string(std::initializer_list<element> const &ilist)
28✔
59
      : string{ilist.begin(), ilist.end()}
28✔
60
    {
61
    }
28✔
62

63
    //* =====================================================================
64
    /// \brief Constructor
65
    /// \param text the text to build this string around.
66
    /// Results in a string with the passed text, with all attributes
67
    /// their default values.
68
    //* =====================================================================
69
    constexpr string(char const *text)  // NOLINT
53✔
70
      : string{text, std::char_traits<char>::length(text)}
53✔
71
    {
72
    }
53✔
73

74
    //* =====================================================================
75
    /// \brief Constructor
76
    /// \param text the text to build this string around.
77
    /// \param len the length of text.
78
    /// Results in a string of length len with the passed text, with all
79
    /// attributes their default values.
80
    //* =====================================================================
81
    constexpr string(char const *text, size_type len)
61✔
82
      : elements_{text, text + len}
122✔
83
    {
84
    }
61✔
85

86
    //* =====================================================================
87
    /// \brief Constructor
88
    /// \param text the text to build this string around
89
    /// Results in a string with the passed text, with all attributes
90
    /// their default values.
91
    //* =====================================================================
92
    constexpr string(std::string const &text)  // NOLINT
3✔
93
      : string{text.data(), text.size()}
3✔
94
    {
95
    }
3✔
96

97
    //* =====================================================================
98
    /// \brief Constructor
99
    /// \param text the text to build this string around.
100
    /// \param attr the attribute to apply to each new element of the string.
101
    //* =====================================================================
102
    constexpr string(std::string const &text, terminalpp::attribute const &attr)
2✔
103
      : string{text}
2✔
104
    {
105
        std::ranges::for_each(
2✔
106
            elements_, [&attr](auto &elem) { elem.attribute_ = attr; });
2✔
107
    }
2✔
108

109
    //* =====================================================================
110
    /// \brief Construct a string of a number of identical elements.
111
    /// \param size the size of the string to construct.
112
    /// \param elem a prototype element to fill the string with
113
    //* =====================================================================
114
    constexpr string(size_type size, terminalpp::element const &elem)
2✔
115
      : elements_(size, elem)
4✔
116
    {
117
    }
2✔
118

119
    //* =====================================================================
120
    /// \brief Returns the number of elements in the string.
121
    //* =====================================================================
122
    [[nodiscard]] constexpr size_type size() const noexcept
5✔
123
    {
124
        return elements_.size();
5✔
125
    }
126

127
    //* =====================================================================
128
    /// \brief Returns an iterator to the beginning of the string.
129
    //* =====================================================================
130
    [[nodiscard]] constexpr iterator begin() noexcept
14✔
131
    {
132
        return elements_.begin();
14✔
133
    }
134

135
    //* =====================================================================
136
    /// \brief Returns an iterator to the beginning of the string.
137
    //* =====================================================================
138
    [[nodiscard]] constexpr const_iterator begin() const noexcept
513✔
139
    {
140
        return elements_.begin();
513✔
141
    }
142

143
    //* =====================================================================
144
    /// \brief Returns a reverse iterator to the reverse beginning of the
145
    /// string.
146
    //* =====================================================================
147
    [[nodiscard]] constexpr reverse_iterator rbegin() noexcept
733✔
148
    {
149
        return elements_.rbegin();
733✔
150
    }
151

152
    //* =====================================================================
153
    /// \brief Returns a reverse iterator to the reverse beginning of the
154
    /// string.
155
    //* =====================================================================
156
    [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept
1✔
157
    {
158
        return elements_.rbegin();
1✔
159
    }
160

161
    //* =====================================================================
162
    /// \brief Returns an iterator to the end of the string.
163
    //* =====================================================================
164
    [[nodiscard]] constexpr iterator end() noexcept
9✔
165
    {
166
        return elements_.end();
9✔
167
    }
168

169
    //* =====================================================================
170
    /// \brief Returns an iterator to the end of the string.
171
    //* =====================================================================
172
    [[nodiscard]] constexpr const_iterator end() const noexcept
513✔
173
    {
174
        return elements_.end();
513✔
175
    }
176

177
    //* =====================================================================
178
    /// \brief Returns a reverse iterator to the reverse end of the string
179
    //* =====================================================================
180
    [[nodiscard]] constexpr reverse_iterator rend() noexcept
1✔
181
    {
182
        return elements_.rend();
1✔
183
    }
184

185
    //* =====================================================================
186
    /// \brief Returns a reverse iterator to the reverse end of the string
187
    //* =====================================================================
188
    [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept
1✔
189
    {
190
        return elements_.rend();
1✔
191
    }
192

193
    //* =====================================================================
194
    /// \brief Returns an iterator to the beginning of the string.
195
    //* =====================================================================
196
    [[nodiscard]] constexpr const_iterator cbegin() noexcept
197
    {
198
        return elements_.cbegin();
199
    }
200

201
    //* =====================================================================
202
    /// \brief Returns an iterator to the end of the string.
203
    //* =====================================================================
204
    [[nodiscard]] constexpr const_iterator cend() noexcept
205
    {
206
        return elements_.cend();
207
    }
208

209
    //* =====================================================================
210
    /// \brief Swaps the contents of this and another string.
211
    //* =====================================================================
212
    constexpr void swap(string &other) noexcept
213
    {
214
        std::swap(elements_, other.elements_);
215
    }
216

217
    //* =====================================================================
218
    /// \brief Returns the maximum size of the string allowed.
219
    //* =====================================================================
220
    [[nodiscard]] constexpr size_type max_size() const noexcept
1✔
221
    {
222
        return std::numeric_limits<size_type>::max();
1✔
223
    }
224

225
    //* =====================================================================
226
    /// \brief Returns whether the string is empty or not.
227
    //* =====================================================================
228
    [[nodiscard]] constexpr bool empty() const noexcept
2✔
229
    {
230
        return elements_.empty();
2✔
231
    }
232

233
    //* =====================================================================
234
    /// \brief Array access operator
235
    //* =====================================================================
236
    [[nodiscard]] constexpr reference operator[](size_type index) noexcept
8✔
237
    {
238
        return elements_[index];
8✔
239
    }
240

241
    //* =====================================================================
242
    /// \brief Array access operator
243
    //* =====================================================================
244
    [[nodiscard]] constexpr const_reference operator[](
245
        size_type index) const noexcept
246
    {
247
        return elements_[index];
248
    }
249

250
    //* =====================================================================
251
    /// \brief Append operator
252
    //* =====================================================================
253
    constexpr string &operator+=(element const &elem)
770✔
254
    {
255
        elements_.insert(elements_.end(), elem);
770✔
256
        return *this;
770✔
257
    }
258

259
    //* =====================================================================
260
    /// \brief Append operator
261
    //* =====================================================================
262
    [[nodiscard]] friend string operator+(string lhs, element const &rhs)
263
    {
264
        return lhs += rhs;
265
    }
266

267
    //* =====================================================================
268
    /// \brief Append operator
269
    //* =====================================================================
270
    constexpr string &operator+=(string const &rhs)
3✔
271
    {
272
        elements_.insert(elements_.end(), rhs.begin(), rhs.end());
3✔
273
        return *this;
3✔
274
    }
275

276
    //* =====================================================================
277
    /// \brief Append operator
278
    //* =====================================================================
279
    [[nodiscard]] friend string operator+(string lhs, string const &rhs)
280
    {
281
        return lhs += rhs;
282
    }
283

284
    //* =====================================================================
285
    /// \brief Inserts an element at the iterator position.
286
    //* =====================================================================
287
    constexpr void insert(iterator pos, element const &elem)
10✔
288
    {
289
        elements_.insert(pos, elem);
10✔
290
    }
10✔
291

292
    //* =====================================================================
293
    /// \brief Inserts a range of elements at the iterator position.
294
    //* =====================================================================
295
    template <class InputIterator>
296
    constexpr void insert(
5✔
297
        iterator pos, InputIterator range_begin, InputIterator range_end)
298
    {
299
        elements_.insert(pos, range_begin, range_end);
5✔
300
    }
5✔
301

302
    //* =====================================================================
303
    /// \brief Erase
304
    //* =====================================================================
305
    constexpr void erase()
2✔
306
    {
307
        elements_.clear();
2✔
308
    }
2✔
309

310
    //* =====================================================================
311
    /// \brief Erase
312
    //* =====================================================================
313
    constexpr void erase(iterator range_begin)
4✔
314
    {
315
        elements_.erase(range_begin, elements_.end());
4✔
316
    }
4✔
317

318
    //* =====================================================================
319
    /// \brief Erase
320
    //* =====================================================================
321
    constexpr void erase(iterator range_begin, iterator range_end)
1✔
322
    {
323
        elements_.erase(range_begin, range_end);
1✔
324
    }
1✔
325

326
    //* =====================================================================
327
    /// \brief Relational operators for strings
328
    //* =====================================================================
329
    [[nodiscard]] constexpr friend auto operator<=>(
356✔
330
        string const &lhs, string const &rhs) noexcept = default;
331

332
    //* =====================================================================
333
    /// \brief Equality operator
334
    //* =====================================================================
335
    TERMINALPP_EXPORT
336
    constexpr friend bool operator==(
233✔
337
        string const &lhs, string const &rhs) noexcept = default;
338

339
    //* =====================================================================
340
    /// \brief Hash function
341
    //* =====================================================================
342
    [[nodiscard]] friend std::size_t hash_value(string const &str) noexcept
1✔
343
    {
344
        return boost::hash_range(str.elements_.begin(), str.elements_.end());
1✔
345
    }
346

347
private:
348
    elements_storage elements_;
525✔
349
};
350

351
//* =========================================================================
352
/// \brief Streaming output operator for strings.  Prints the text out
353
/// element by element so that it is readable.  Note: NOT rendered as if
354
/// to a terminal.
355
//* =========================================================================
356
TERMINALPP_EXPORT
357
std::ostream &operator<<(std::ostream &out, string const &text);
358

359
//* =========================================================================
360
/// \brief Convert a terminalpp::string to a std::string by removing all
361
/// attributes and charset information.
362
//* =========================================================================
363
TERMINALPP_EXPORT
364
[[nodiscard]] constexpr ::std::string to_string(terminalpp::string const &tstr)
3✔
365
{
366
    std::string result;
3✔
367

368
    for (auto const &elem : tstr)
24✔
369
    {
370
        if (elem.glyph_.charset_ == charset::utf8)
21✔
371
        {
372
            for (auto const &ch : elem.glyph_.ucharacter_)
3✔
373
            {
374
                if (ch == 0)
3✔
375
                {
376
                    break;
1✔
377
                }
378

379
                result += static_cast<char>(ch);
2✔
380
            }
381
        }
382
        else
383
        {
384
            result += static_cast<char>(elem.glyph_.character_);
20✔
385
        }
386
    }
387

388
    return result;
3✔
389
}
×
390

391
//* =========================================================================
392
/// \brief A function that converts a std::string into a terminalpp::string,
393
/// parsing its contents according to the String To Elements protocol.
394
//* =========================================================================
395
TERMINALPP_EXPORT
396
constexpr terminalpp::string encode(std::span<char const> text)
433✔
397
{
398
    string result;
433✔
399
    element prev_element;
433✔
400

401
    while (!text.empty())
1,165✔
402
    {
403
        result += detail::parse_element(text, prev_element);
732✔
404
        prev_element = *result.rbegin();
732✔
405
    }
406

407
    return result;
866✔
408
}
×
409

410
inline namespace literals {
411
inline namespace string_literals {
412

413
//* =========================================================================
414
/// \brief Construct an string from literals using "foo"_ts;
415
//* =========================================================================
416
TERMINALPP_EXPORT
417
[[nodiscard]] constexpr ::terminalpp::string operator""_ts(
5✔
418
    char const *text, ::terminalpp::string::size_type length)
419
{
420
    return {text, length};
5✔
421
}
422

423
//* =========================================================================
424
/// \brief Construct an encoded string from literals using "foo"_ets;
425
//* =========================================================================
426
TERMINALPP_EXPORT
427
[[nodiscard]] constexpr ::terminalpp::string operator""_ets(
404✔
428
    char const *text, ::terminalpp::string::size_type length)
429
{
430
    return encode(std::span{text, length});
404✔
431
}
432

433
}  // namespace string_literals
434
}  // namespace literals
435
}  // namespace terminalpp
436

437
namespace std {
438

439
template <>
440
struct hash<terminalpp::string>
441
{
442
    using argument_type = terminalpp::string;
443
    using result_type = std::size_t;
444

445
    [[nodiscard]] result_type operator()(
1✔
446
        argument_type const &str) const noexcept
447
    {
448
        return hash_value(str);
1✔
449
    }
450
};
451

452
}  // namespace std
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc