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

thetic / mu.tiny / 24845382900

23 Apr 2026 04:00PM UTC coverage: 98.906% (+0.002%) from 98.904%
24845382900

Pull #88

github

web-flow
Merge 41cf0983a into ec56324d8
Pull Request #88: Use semantically correct integer types for counts and line numbers

54 of 54 new or added lines in 14 files covered. (100.0%)

11 existing lines in 4 files now uncovered.

5335 of 5394 relevant lines covered (98.91%)

3301.01 hits per line

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

98.01
/src/String.cpp
1
#include "mu/tiny/String.hpp"
2

3
#include "mu/tiny/StringView.hpp"
4
#include "mu/tiny/math.hpp"
5

6
#if MUTINY_USE_STD_CPP_LIB
7
#include <string>
8
#endif
9

10
#if MUTINY_USE_STD_STRING
11
#include <cctype>
12
#include <cstdlib>
13
#include <cstring>
14
#endif
15

16
#include <inttypes.h>
17
#include <limits.h>
18
#include <stdint.h>
19
#include <stdio.h>
20

21
namespace mu {
22
namespace tiny {
23

24
namespace {
25
constexpr int decimal_base{ 10 };
26

27
#if !MUTINY_USE_STD_STRING
28
char* str_n_cpy(char* s1, const char* s2, size_t n)
118,177✔
29
{
30
  char* result = s1;
118,177✔
31

32
  if ((nullptr == s1) || (0 == n)) {
118,177✔
33
    return result;
×
34
  }
35

36
  *s1 = *s2;
118,177✔
37
  while ((--n != 0) && (*s1 != 0)) {
1,974,742✔
38
    *++s1 = *++s2;
1,856,565✔
39
  }
40
  return result;
118,177✔
41
}
42

43
char* copy_to_new_buffer(const char* buffer_to_copy, size_t buffer_size)
77,734✔
44
{
45
  char* new_buffer = new char[buffer_size];
77,734✔
46
  str_n_cpy(new_buffer, buffer_to_copy, buffer_size);
77,734✔
47
  if (buffer_size > 0) {
77,734✔
48
    new_buffer[buffer_size - 1] = '\0';
77,734✔
49
  }
50
  return new_buffer;
77,734✔
51
}
52
#endif
53

54
#if !MUTINY_USE_STD_STRING
55
bool is_digit(char ch)
117✔
56
{
57
  return '0' <= ch && '9' >= ch;
117✔
58
}
59

60
bool is_space(char ch)
39✔
61
{
62
  constexpr char bs{ 0x08 };
39✔
63
  constexpr char so{ 0x0E };
39✔
64
  return (ch == ' ') || ((bs < ch) && (so > ch));
39✔
65
}
66

67
bool is_upper(char ch)
32✔
68
{
69
  return 'A' <= ch && 'Z' >= ch;
32✔
70
}
71

72
char* get_empty_string()
103✔
73
{
74
  char* buf = new char[1];
103✔
75
  buf[0] = '\0';
103✔
76
  return buf;
103✔
77
}
78
#endif
79
} // namespace
80

81
#if !MUTINY_USE_STD_STRING
82
void String::deallocate_internal_buffer()
168,417✔
83
{
84
  if (buffer_ != nullptr) {
168,417✔
85
    delete[] buffer_;
77,980✔
86
    buffer_ = nullptr;
77,980✔
87
    buffer_size_ = 0;
77,980✔
88
    size_ = 0;
77,980✔
89
  }
90
}
168,417✔
91

92
void String::set_internal_buffer_as_empty_string()
103✔
93
{
94
  deallocate_internal_buffer();
103✔
95

96
  buffer_size_ = 1;
103✔
97
  buffer_ = get_empty_string();
103✔
98
}
103✔
99

100
void String::copy_buffer_to_new_internal_buffer(
77,734✔
101
    const char* other_buffer,
102
    size_t buffer_size
103
)
104
{
105
  deallocate_internal_buffer();
77,734✔
106

107
  buffer_size_ = buffer_size;
77,734✔
108
  size_ = buffer_size_ - 1;
77,734✔
109
  buffer_ = copy_to_new_buffer(other_buffer, buffer_size_);
77,734✔
110
}
77,734✔
111

112
void String::reserve(size_t new_capacity)
295✔
113
{
114
  size_t needed = new_capacity + 1;
295✔
115
  if (needed <= buffer_size_) {
295✔
116
    return;
1✔
117
  }
118

119
  char* new_buffer = new char[needed];
294✔
120
  str_n_cpy(new_buffer, buffer_, buffer_size_);
294✔
121
  new_buffer[needed - 1] = '\0';
294✔
122
  delete[] buffer_;
294✔
123
  buffer_ = new_buffer;
294✔
124
  buffer_size_ = needed;
294✔
125
  // size_ is unchanged: the string content was preserved
126
}
127

128
void String::clear()
103✔
129
{
130
  set_internal_buffer_as_empty_string();
103✔
131
}
103✔
132

133
void String::copy_buffer_to_new_internal_buffer(const String& other_buffer)
197✔
134
{
135
  copy_buffer_to_new_internal_buffer(
197✔
136
      other_buffer.buffer_, other_buffer.size() + 1
197✔
137
  );
138
}
197✔
139

140
void String::copy_buffer_to_new_internal_buffer(const char* other_buffer)
74,504✔
141
{
142
  copy_buffer_to_new_internal_buffer(other_buffer, strlen(other_buffer) + 1);
74,504✔
143
}
74,504✔
144

145
String::String(const char* value)
72,145✔
146
  : buffer_(nullptr)
72,145✔
147
  , buffer_size_(0)
72,145✔
148
  , size_(0)
72,145✔
149
{
150
  if (value == nullptr) {
72,145✔
151
    set_internal_buffer_as_empty_string();
×
152
  } else {
153
    copy_buffer_to_new_internal_buffer(value);
72,145✔
154
  }
155
}
72,145✔
156

157
String::String(size_t count, char ch)
160✔
158
  : buffer_(nullptr)
160✔
159
  , buffer_size_(0)
160✔
160
  , size_(0)
160✔
161
{
162
  buffer_size_ = count + 1;
160✔
163
  size_ = count;
160✔
164
  buffer_ = new char[buffer_size_];
160✔
165
  for (size_t i = 0; i < count; i++) {
3,611✔
166
    buffer_[i] = ch;
3,451✔
167
  }
168
  buffer_[count] = '\0';
160✔
169
}
160✔
170

171
String::String(const String& other)
2,359✔
172
  : buffer_(nullptr)
2,359✔
173
  , buffer_size_(0)
2,359✔
174
  , size_(0)
2,359✔
175
{
176
  copy_buffer_to_new_internal_buffer(other.c_str());
2,359✔
177
}
2,359✔
178

179
String::String(String&& other) noexcept
1,737✔
180
  : buffer_(other.buffer_)
1,737✔
181
  , buffer_size_(other.buffer_size_)
1,737✔
182
  , size_(other.size_)
1,737✔
183
{
184
  other.buffer_ = nullptr;
1,737✔
185
  other.buffer_size_ = 0;
1,737✔
186
  other.size_ = 0;
1,737✔
187
}
1,737✔
188

189
String& String::operator=(String&& other) noexcept
11,273✔
190
{
191
  if (this != &other) {
11,273✔
192
    deallocate_internal_buffer();
11,273✔
193
    buffer_ = other.buffer_;
11,273✔
194
    buffer_size_ = other.buffer_size_;
11,273✔
195
    size_ = other.size_;
11,273✔
196
    other.buffer_ = nullptr;
11,273✔
197
    other.buffer_size_ = 0;
11,273✔
198
    other.size_ = 0;
11,273✔
199
  }
200
  return *this;
11,273✔
201
}
202

203
String& String::operator=(const String& other)
197✔
204
{
205
  if (this != &other) {
197✔
206
    copy_buffer_to_new_internal_buffer(other);
197✔
207
  }
208
  return *this;
197✔
209
}
210

211
const char* String::c_str() const
114,936✔
212
{
213
  return buffer_;
114,936✔
214
}
215

216
const char* String::data() const
1✔
217
{
218
  return buffer_;
1✔
219
}
220

221
char* String::data()
1,496✔
222
{
223
  return buffer_;
1,496✔
224
}
225

226
size_t String::size() const
5,976✔
227
{
228
  return size_;
5,976✔
229
}
230

231
bool String::empty() const
3,344✔
232
{
233
  return size_ == 0;
3,344✔
234
}
235

236
String::~String()
79,307✔
237
{
238
  deallocate_internal_buffer();
79,307✔
239
}
79,307✔
240

241
bool operator==(const String& left, const String& right)
45,428✔
242
{
243
  return 0 == strcmp(left.c_str(), right.c_str());
45,428✔
244
}
245

246
bool operator!=(const String& left, const String& right)
182✔
247
{
248
  return !(left == right);
182✔
249
}
250

251
String String::operator+(const String& rhs) const
623✔
252
{
253
  String t(c_str());
623✔
254
  t += rhs.c_str();
623✔
255
  return t;
623✔
256
}
×
257

258
String& String::operator+=(const String& rhs)
3,825✔
259
{
260
  return operator+=(rhs.c_str());
3,825✔
261
}
262

263
String& String::operator+=(const char* rhs)
25,795✔
264
{
265
  size_t rhs_len = strlen(rhs);
25,795✔
266
  size_t new_size = size_ + rhs_len;
25,795✔
267
  size_t needed = new_size + 1;
25,795✔
268
  if (needed <= buffer_size_) {
25,795✔
269
    str_n_cpy(buffer_ + size_, rhs, rhs_len + 1);
11,441✔
270
  } else {
271
    size_t new_cap = buffer_size_ * 2;
14,354✔
272
    if (new_cap < needed) {
14,354✔
273
      new_cap = needed;
3,869✔
274
    }
275
    char* nb = new char[new_cap];
14,354✔
276
    str_n_cpy(nb, buffer_, size_ + 1);
14,354✔
277
    str_n_cpy(nb + size_, rhs, rhs_len + 1);
14,354✔
278
    delete[] buffer_;
14,354✔
279
    buffer_ = nb;
14,354✔
280
    buffer_size_ = new_cap;
14,354✔
281
  }
282
  size_ = new_size;
25,795✔
283
  return *this;
25,795✔
284
}
285

286
String& String::operator+=(char ch)
7,458✔
287
{
288
  size_t needed = size_ + 2;
7,458✔
289
  if (needed <= buffer_size_) {
7,458✔
290
    buffer_[size_] = ch;
6,826✔
291
    buffer_[size_ + 1] = '\0';
6,826✔
292
    size_ += 1;
6,826✔
293
    return *this;
6,826✔
294
  }
295
  char tmp[2] = { ch, '\0' };
632✔
296
  return operator+=(tmp);
632✔
297
}
298

299
String::String(const char* value, size_t len)
3,033✔
300
  : buffer_(nullptr)
3,033✔
301
  , buffer_size_(0)
3,033✔
302
  , size_(0)
3,033✔
303
{
304
  copy_buffer_to_new_internal_buffer(value, len + 1);
3,033✔
305
}
3,033✔
306

307
String& String::operator+=(StringView sv)
1✔
308
{
309
  return operator+=(sv.c_str());
1✔
310
}
311

312
String::String(StringView value)
1✔
313
  : String(value.data(), value.size())
1✔
314
{
315
}
1✔
316

317
void String::resize(size_t new_size)
148✔
318
{
319
  reserve(new_size);
148✔
320
  buffer_[new_size] = '\0';
148✔
321
  size_ = new_size;
148✔
322
}
148✔
323

324
String String::substr(size_t begin_pos, size_t amount) const
153✔
325
{
326
  if (begin_pos > size() - 1) {
153✔
327
    return "";
6✔
328
  }
329

330
  String new_string = c_str() + begin_pos;
147✔
331

332
  if (new_string.size_ > amount) {
147✔
333
    new_string.buffer_[amount] = '\0';
114✔
334
    new_string.size_ = amount;
114✔
335
  }
336

337
  return new_string;
147✔
338
}
147✔
339

340
String String::substr(size_t begin_pos) const
33✔
341
{
342
  return substr(begin_pos, npos);
33✔
343
}
344

345
size_t String::find(char ch, size_t pos) const
18✔
346
{
347
  size_t len = size();
18✔
348
  for (size_t i = pos; i < len; i++) {
105✔
349
    if (c_str()[i] == ch) {
102✔
350
      return i;
15✔
351
    }
352
  }
353
  return npos;
3✔
354
}
355

356
size_t String::find(const char* s, size_t pos) const
330✔
357
{
358
  if (pos > size()) {
330✔
359
    return npos;
×
360
  }
361
  const char* found = strstr(c_str() + pos, s);
330✔
362
  if (found == nullptr) {
330✔
363
    return npos;
284✔
364
  }
365
  return static_cast<size_t>(found - c_str());
46✔
366
}
367

368
bool operator<(const String& left, const String& right)
3✔
369
{
370
  return strcmp(left.c_str(), right.c_str()) < 0;
3✔
371
}
372
#endif
373

374
bool string_contains(const String& str, const String& substr)
642✔
375
{
376
  return strstr(str.c_str(), substr.c_str()) != nullptr;
642✔
377
}
378

379
bool string_starts_with(const String& str, const String& prefix)
896✔
380
{
381
  if (prefix.empty()) {
896✔
382
    return true;
1✔
383
  }
384
  if (str.empty()) {
895✔
385
    return false;
1✔
386
  }
387
  return strstr(str.c_str(), prefix.c_str()) == str.c_str();
894✔
388
}
389

390
bool string_ends_with(const String& str, const String& suffix)
20✔
391
{
392
  size_t len = str.size();
20✔
393
  size_t other_len = suffix.size();
20✔
394

395
  if (other_len == 0) {
20✔
396
    return true;
1✔
397
  }
398
  if (len == 0) {
19✔
399
    return false;
1✔
400
  }
401
  if (len < other_len) {
18✔
402
    return false;
1✔
403
  }
404

405
  return strcmp(str.c_str() + len - other_len, suffix.c_str()) == 0;
17✔
406
}
407

408
void string_replace(String& str, char from, char to)
81✔
409
{
410
  size_t s = str.size();
81✔
411
  for (size_t i = 0; i < s; i++) {
1,111✔
412
    if (str[i] == from) {
1,030✔
413
      str[i] = to;
16✔
414
    }
415
  }
416
}
81✔
417

418
void string_replace(String& str, const char* from, const char* to)
283✔
419
{
420
  size_t fromlen = strlen(from);
283✔
421
  if (fromlen == 0) {
283✔
422
    return;
263✔
423
  }
424

425
  String result;
282✔
426
  size_t pos = 0;
282✔
427
  size_t found = str.find(from, pos);
282✔
428
  while (found != String::npos) {
320✔
429
    result += str.substr(pos, found - pos);
38✔
430
    result += to;
38✔
431
    pos = found + fromlen;
38✔
432
    found = str.find(from, pos);
38✔
433
  }
434
  if (pos == 0) {
282✔
435
    return;
262✔
436
  }
437
  result += str.substr(pos);
20✔
438
  str = result;
20✔
439
}
282✔
440

441
long strtol(const char* str)
12✔
442
{
443
#if MUTINY_USE_STD_STRING
444
  return std::strtol(str, nullptr, decimal_base);
445
#else
446
  while (is_space(*str)) {
16✔
447
    str++;
4✔
448
  }
449

450
  char first_char = *str;
12✔
451
  if (first_char == '-' || first_char == '+') {
12✔
452
    str++;
3✔
453
  }
454

455
  long result = 0;
12✔
456
  for (; is_digit(*str); str++) {
55✔
457
    result *= decimal_base;
43✔
458
    result += *str - '0';
43✔
459
  }
460
  return (first_char == '-') ? -result : result;
12✔
461
#endif
462
}
463

464
unsigned long strtoul(const char* str)
18✔
465
{
466
#if MUTINY_USE_STD_STRING
467
  return std::strtoul(str, nullptr, decimal_base);
468
#else
469
  while (is_space(*str)) {
23✔
470
    str++;
5✔
471
  }
472

473
  bool negative = (*str == '-');
18✔
474
  if (*str == '-' || *str == '+') {
18✔
475
    str++;
3✔
476
  }
477

478
  unsigned long result = 0;
18✔
479
  for (; is_digit(*str); str++) {
62✔
480
    result *= decimal_base;
44✔
481
    result += static_cast<unsigned long>(*str - '0');
44✔
482
  }
483
  return negative ? -result : result;
18✔
484
#endif
485
}
486

487
int strcmp(const char* s1, const char* s2)
46,478✔
488
{
489
#if MUTINY_USE_STD_STRING
490
  return std::strcmp(s1, s2);
491
#else
492
  while ((*s1 != 0) && *s1 == *s2) {
101,473✔
493
    ++s1;
54,995✔
494
    ++s2;
54,995✔
495
  }
496
  return *reinterpret_cast<const unsigned char*>(s1) -
46,478✔
497
         *reinterpret_cast<const unsigned char*>(s2);
46,478✔
498
#endif
499
}
500

501
size_t strlen(const char* str)
118,261✔
502
{
503
#if MUTINY_USE_STD_STRING
504
  return std::strlen(str);
505
#else
506
  auto n = static_cast<size_t>(-1);
118,261✔
507
  do {
508
    n++;
1,561,191✔
509
  } while (*str++ != 0);
1,561,191✔
510
  return n;
118,261✔
511
#endif
512
}
513

514
int strncmp(const char* s1, const char* s2, size_t n)
44,978✔
515
{
516
#if MUTINY_USE_STD_STRING
517
  return std::strncmp(s1, s2, n);
518
#else
519
  while ((n != 0U) && ((*s1) != 0) && *s1 == *s2) {
91,662✔
520
    --n;
46,684✔
521
    ++s1;
46,684✔
522
    ++s2;
46,684✔
523
  }
524
  return (n != 0U) ? *reinterpret_cast<const unsigned char*>(s1) -
44,978✔
525
                         *reinterpret_cast<const unsigned char*>(s2)
41,146✔
526
                   : 0;
44,978✔
527
#endif
528
}
529

530
const char* strstr(const char* s1, const char* s2)
1,882✔
531
{
532
#if MUTINY_USE_STD_STRING
533
  return std::strstr(s1, s2);
534
#else
535
  if (*s2 == 0) {
1,882✔
536
    return s1;
7✔
537
  }
538
  size_t s2_len = strlen(s2);
1,875✔
539
  for (; *s1 != 0; s1++) {
42,780✔
540
    if (strncmp(s1, s2, s2_len) == 0) {
41,721✔
541
      return s1;
816✔
542
    }
543
  }
544
  return nullptr;
1,059✔
545
#endif
546
}
547

548
char tolower(char ch)
32✔
549
{
550
#if MUTINY_USE_STD_STRING
551
  return static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
552
#else
553
  return is_upper(ch) ? static_cast<char>(static_cast<int>(ch) + ('a' - 'A'))
32✔
554
                      : ch;
32✔
555
#endif
556
}
557

558
int memcmp(const void* s1, const void* s2, size_t n)
20✔
559
{
560
#if MUTINY_USE_STD_STRING
561
  return std::memcmp(s1, s2, n);
562
#else
563
  const auto* p1 = static_cast<const unsigned char*>(s1);
20✔
564
  const auto* p2 = static_cast<const unsigned char*>(s2);
20✔
565

566
  while (n-- != 0U) {
65✔
567
    if (*p1 != *p2) {
55✔
568
      return *p1 - *p2;
10✔
569
    }
570
    ++p1;
45✔
571
    ++p2;
45✔
572
  }
573
  return 0;
10✔
574
#endif
575
}
576

577
bool iscntrl(char ch)
946✔
578
{
579
#if MUTINY_USE_STD_STRING
580
  return std::iscntrl(static_cast<unsigned char>(ch)) != 0;
581
#else
582
  constexpr char del{ 0x7F };
946✔
583
  return ch < ' ' || ch == del;
946✔
584
#endif
585
}
586

587
String string_from(bool value)
3✔
588
{
589
  return String(value ? "true" : "false");
3✔
590
}
591

592
String string_from(const char* value)
136✔
593
{
594
  return String(value);
136✔
595
}
596

597
String string_from_or_null(const char* value)
13✔
598
{
599
  return (value != nullptr) ? string_from(value) : string_from("(null)");
13✔
600
}
601

602
String string_from(int value)
76✔
603
{
604
  return string_from_format("%d", value);
76✔
605
}
606

607
String string_from(long value)
1,319✔
608
{
609
  return string_from_format("%ld", value);
1,319✔
610
}
611

612
String string_from(const void* value)
17✔
613
{
614
  return String("0x") + hex_string_from(value);
17✔
615
}
616

617
String string_from(void (*value)())
6✔
618
{
619
  return String("0x") + hex_string_from(value);
6✔
620
}
621

622
String hex_string_from(long value)
7✔
623
{
624
  return hex_string_from(static_cast<unsigned long>(value));
7✔
625
}
626

627
String hex_string_from(int value)
30✔
628
{
629
  return hex_string_from(static_cast<unsigned int>(value));
30✔
630
}
631

632
String hex_string_from(signed char value)
3✔
633
{
634
  String result = string_from_format("%x", value);
3✔
635
  if (value < 0) {
3✔
636
    size_t size = result.size();
1✔
637
    result = result.substr(size - (CHAR_BIT / 4));
1✔
638
  }
639
  return result;
3✔
UNCOV
640
}
×
641

642
String hex_string_from(unsigned long value)
12✔
643
{
644
  return string_from_format("%lx", value);
12✔
645
}
646

647
String hex_string_from(unsigned int value)
37✔
648
{
649
  return string_from_format("%x", value);
37✔
650
}
651

652
String brackets_formatted_hex_string_from(int value)
30✔
653
{
654
  return brackets_formatted_hex_string(hex_string_from(value));
30✔
655
}
656

657
String brackets_formatted_hex_string_from(unsigned int value)
7✔
658
{
659
  return brackets_formatted_hex_string(hex_string_from(value));
7✔
660
}
661

662
String brackets_formatted_hex_string_from(long value)
6✔
663
{
664
  return brackets_formatted_hex_string(hex_string_from(value));
6✔
665
}
666

667
String brackets_formatted_hex_string_from(unsigned long value)
5✔
668
{
669
  return brackets_formatted_hex_string(hex_string_from(value));
5✔
670
}
671

672
String brackets_formatted_hex_string_from(signed char value)
1✔
673
{
674
  return brackets_formatted_hex_string(hex_string_from(value));
1✔
675
}
676

677
String brackets_formatted_hex_string(const String& hex_string)
87✔
678
{
679
  return String("(0x") + hex_string + ")";
174✔
680
}
681

682
String string_from(decltype(nullptr) value)
1✔
683
{
684
  (void)value;
685
  return "(null)";
1✔
686
}
687

688
#if MUTINY_USE_STD_CPP_LIB
689

690
#if !MUTINY_USE_STD_STRING
691
String string_from(std::string const& str)
1✔
692
{
693
  return String(str.c_str());
1✔
694
}
695
#endif
696
#endif
697

698
String string_from(long long value)
22✔
699
{
700
  return string_from_format("%lld", value);
22✔
701
}
702

703
String string_from(unsigned long long value)
17✔
704
{
705
  return string_from_format("%llu", value);
17✔
706
}
707

708
String hex_string_from(long long value)
23✔
709
{
710
  return hex_string_from(static_cast<unsigned long long>(value));
23✔
711
}
712

713
String hex_string_from(unsigned long long value)
39✔
714
{
715
  return string_from_format("%llx", value);
39✔
716
}
717

718
String hex_string_from(const void* value)
18✔
719
{
720
  return string_from_format("%" PRIxPTR, reinterpret_cast<uintptr_t>(value));
18✔
721
}
722

723
String hex_string_from(void (*value)())
7✔
724
{
725
  return string_from_format("%" PRIxPTR, reinterpret_cast<uintptr_t>(value));
7✔
726
}
727

728
String brackets_formatted_hex_string_from(long long value)
22✔
729
{
730
  return brackets_formatted_hex_string(hex_string_from(value));
22✔
731
}
732

733
String brackets_formatted_hex_string_from(unsigned long long value)
16✔
734
{
735
  return brackets_formatted_hex_string(hex_string_from(value));
16✔
736
}
737

738
String string_from(float value, int precision)
17✔
739
{
740
  if (is_nan(value) != 0) {
17✔
741
    return "Nan - Not a number";
4✔
742
  }
743
  if (is_inf(value) != 0) {
13✔
744
    return "Inf - Infinity";
1✔
745
  }
746
  return string_from_format("%.*g", precision, value);
12✔
747
}
748

749
String string_from(double value, int precision)
51✔
750
{
751
  if (is_nan(value) != 0) {
51✔
752
    return "Nan - Not a number";
4✔
753
  }
754
  if (is_inf(value) != 0) {
47✔
755
    return "Inf - Infinity";
3✔
756
  }
757
  return string_from_format("%.*g", precision, value);
44✔
758
}
759

760
String string_from(char value)
21✔
761
{
762
  return String(1, value);
21✔
763
}
764

765
String string_from(const String& other)
1✔
766
{
767
  return String(other);
1✔
768
}
769

770
String string_from(StringView value)
1✔
771
{
772
  return String(value.data(), value.size());
1✔
773
}
774

775
String string_from_format(const char* format, ...)
4,754✔
776
{
777
  String result_string;
4,754✔
778
  va_list arguments;
779
  va_start(arguments, format);
4,754✔
780

781
  result_string = v_string_from_format(format, arguments);
4,754✔
782
  va_end(arguments);
4,754✔
783
  return result_string;
9,508✔
UNCOV
784
}
×
785

786
String string_from(unsigned int value)
12✔
787
{
788
  return string_from_format("%u", value);
12✔
789
}
790

791
String string_from(unsigned long value)
1,293✔
792
{
793
  return string_from_format("%lu", value);
1,293✔
794
}
795

796
String v_string_from_format(const char* format, va_list args)
4,754✔
797
{
798
  va_list args_copy;
799
  va_copy(args_copy, args);
4,754✔
800
  constexpr size_t size_ofdefault_buffer = 100;
4,754✔
801
  char default_buffer[size_ofdefault_buffer];
802
  String result_string;
4,754✔
803

804
  auto size = static_cast<size_t>(
805
      vsnprintf(default_buffer, size_ofdefault_buffer, format, args)
4,754✔
806
  );
4,754✔
807
  if (size < size_ofdefault_buffer) {
4,754✔
808
    result_string = String(default_buffer);
4,606✔
809
  } else {
810
#if !MUTINY_USE_STD_STRING
811
    result_string.resize(size);
148✔
812
    vsnprintf(result_string.data(), size + 1, format, args_copy);
148✔
813
#else
814
    size_t new_buffer_size = size + 1;
815
    char* new_buffer = new char[new_buffer_size];
816
    vsnprintf(new_buffer, new_buffer_size, format, args_copy);
817
    result_string = String(new_buffer);
818
    delete[] new_buffer;
819
#endif
820
  }
821
  va_end(args_copy);
4,754✔
822
  return result_string;
9,508✔
UNCOV
823
}
×
824

825
String string_from_binary(const unsigned char* value, size_t size)
41✔
826
{
827
  static const char hex_digits[] = "0123456789ABCDEF";
828
  String result;
41✔
829
  if (size == 0) {
41✔
830
    return result;
2✔
831
  }
832
  result.reserve((size * 3) - 1);
39✔
833
  for (size_t i = 0; i < size; i++) {
308✔
834
    constexpr char nibble_mask{ 0xF };
269✔
835
    if (i > 0) {
269✔
836
      result += ' ';
230✔
837
    }
838
    result += hex_digits[value[i] >> 4];
269✔
839
    result += hex_digits[value[i] & nibble_mask];
269✔
840
  }
841
  return result;
39✔
UNCOV
842
}
×
843

844
String string_from_binary_or_null(const unsigned char* value, size_t size)
44✔
845
{
846
  return (value != nullptr) ? string_from_binary(value, size)
44✔
847
                            : string_from("(null)");
44✔
848
}
849

850
String string_from_binary_with_size(const unsigned char* value, size_t size)
14✔
851
{
852
  String result = string_from_format(
853
      "Size = %u | HexContents = ", static_cast<unsigned>(size)
854
  );
14✔
855
  constexpr size_t max_display_size{ 128U };
14✔
856
  size_t displayed_size = ((size > max_display_size) ? max_display_size : size);
14✔
857
  result += string_from_binary_or_null(value, displayed_size);
14✔
858
  if (size > displayed_size) {
14✔
859
    result += " ...";
1✔
860
  }
861
  return result;
14✔
UNCOV
862
}
×
863

864
String string_from_binary_with_size_or_null(
12✔
865
    const unsigned char* value,
866
    size_t size
867
)
868
{
869
  return (value != nullptr) ? string_from_binary_with_size(value, size)
12✔
870
                            : string_from("(null)");
12✔
871
}
872

873
String string_from_ordinal_number(unsigned int number)
20✔
874
{
875
  const char* suffix = "th";
20✔
876

877
  constexpr unsigned int eleven{ 11 };
20✔
878
  constexpr unsigned int thirteen{ 13 };
20✔
879
  if ((number < eleven) || (number > thirteen)) {
20✔
880
    unsigned int const ones_digit = number % decimal_base;
17✔
881
    if (3 == ones_digit) {
17✔
882
      suffix = "rd";
2✔
883
    } else if (2 == ones_digit) {
15✔
884
      suffix = "nd";
4✔
885
    } else if (1 == ones_digit) {
11✔
886
      suffix = "st";
2✔
887
    }
888
  }
889

890
  return string_from_format("%u%s", number, suffix);
20✔
891
}
892

893
} // namespace tiny
894
} // namespace mu
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