Skip to content

Commit b4e6dc8

Browse files
committed
reworked ftoa and itoa functions
1 parent f465ee7 commit b4e6dc8

2 files changed

Lines changed: 76 additions & 43 deletions

File tree

klib/comm/streams/ostream.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ namespace klib {
146146
char buf[Digits + (sizeof(T) * 8) + sizeof(" ")] = {};
147147

148148
// convert the value to a string
149-
string::stoa<Digits>(v, buf);
149+
string::ftoa<Digits>(v, buf);
150150

151151
// write the buffer to the stream
152152
str << buf;

klib/string.hpp

Lines changed: 75 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -425,17 +425,17 @@ namespace klib::string::detail {
425425
typename T = int,
426426
typename = std::enable_if_t<std::is_integral_v<T>>
427427
>
428-
constexpr void itoa_impl(T value, char *const str) {
428+
constexpr uint32_t itoa_impl(T value, char *const str) {
429429
// handle the boolalpha case first
430430
if constexpr (BoolAlpha) {
431431
if (!value) {
432432
strcpy(str, "false");
433+
return strlen("false");
433434
}
434435
else {
435436
strcpy(str, "true");
437+
return strlen("true");
436438
}
437-
438-
return;
439439
}
440440

441441
// Handle 0 explicitly, otherwise 0 is not printed
@@ -444,12 +444,10 @@ namespace klib::string::detail {
444444
const auto added = add_prefix<B>(str);
445445

446446
// add 0 after the prefix
447-
str[added] = '0';
448-
449-
// add the null terminator
450-
str[added + 1] = '\0';
447+
strcat(str, "0");
451448

452-
return;
449+
// return the string length
450+
return strlen("0") + added;
453451
}
454452

455453
uint32_t index = 0;
@@ -463,7 +461,7 @@ namespace klib::string::detail {
463461
// add a minus sign
464462
str[index] = '-';
465463

466-
// go to the next character
464+
// go to the next position
467465
index++;
468466
}
469467
}
@@ -494,59 +492,92 @@ namespace klib::string::detail {
494492
value /= b;
495493
}
496494

495+
const uint32_t pos = index + count;
496+
497497
// add a null terminator
498498
str[index + count] = '\0';
499+
500+
return pos;
499501
}
500502

501503
template <uint32_t Digits, typename T = int>
502-
constexpr void stoa_impl(T value, char *const str) {
504+
constexpr uint32_t ftoa_impl(T value, char *const str) {
505+
// handle the special cases and return
503506
if (klib::isnan(value)) {
504507
strcpy(str, "NaN");
508+
return strlen("NaN");
505509
}
506510
else if (klib::isinf(value)) {
507511
strcpy(str, "Inf");
512+
return strlen("Inf");
508513
}
509514
else if (value == static_cast<T>(0.f)) {
510515
strcpy(str, "0");
516+
return strlen("0");
511517
}
512-
else {
513-
int i = 0, k = 0;
514518

515-
// handle negative values
516-
if (value < static_cast<T>(0.f)) {
517-
str[k++] = '-';
518-
value *= -1;
519-
}
519+
uint32_t index = 0;
520520

521-
do {
522-
value /= 10;
523-
i++;
524-
}
525-
while (static_cast<int>(value) > 0);
521+
// handle negative values
522+
if (value < static_cast<T>(0.f)) {
523+
str[index++] = '-';
524+
value *= -1;
525+
}
526526

527-
// add the decimal seperator
528-
*(str + k + i) = '.';
527+
uint32_t count = 0;
528+
T tmp = value;
529529

530-
value *= 10;
531-
auto n = static_cast<int>(value);
532-
value -= n;
530+
// count the characters needed without the
531+
// fractional part
532+
do {
533+
tmp /= 10;
534+
count++;
535+
}
536+
while (static_cast<int>(tmp) > 0);
533537

534-
while ((k - i) <= static_cast<int>(Digits)) {
535-
if (k == i) {
536-
k++;
537-
}
538+
// save the fractional part before modifying
539+
// the value
540+
T frac = value - klib::floor(value);
538541

539-
*(str + k) = '0' + n;
542+
// write the integer digits using the original
543+
// value
544+
for (int p = 0; p < count; p++) {
545+
// get the current digit
546+
const auto digit = static_cast<uint32_t>(value) % 10;
540547

541-
value *= 10;
542-
n = static_cast<int>(value);
543-
value -= n;
544-
k++;
545-
}
548+
// store the digit
549+
str[index + (count - p - 1)] = '0' + digit;
546550

547-
// Null-terminate the string
548-
*(str + k) = '\0';
551+
// remove the digit from the value
552+
value /= 10;
549553
}
554+
555+
// increment the index with the digit count
556+
index += count;
557+
558+
// check if we need to add a seperator and
559+
// the fractional values
560+
if constexpr (Digits) {
561+
// add the decimal separator
562+
str[index++] = '.';
563+
564+
// add all the digits after the seperator
565+
for (uint32_t d = 0; d < Digits; d++) {
566+
// get the first digit after the seperator, store
567+
// it and remove it from the value
568+
frac *= 10;
569+
const auto n = static_cast<int>(frac);
570+
frac -= n;
571+
572+
// store the digit
573+
str[index++] = '0' + n;
574+
}
575+
}
576+
577+
// Null-terminate the string
578+
str[index] = '\0';
579+
580+
return index;
550581
}
551582
}
552583

@@ -573,12 +604,13 @@ namespace klib::string {
573604
* @tparam typename
574605
* @param value
575606
* @param str
607+
* @return characters in buffer
576608
*/
577609
template <
578610
base B = _default_base, bool Boolalpha = _default_boolalpha,
579611
typename T = int, typename = std::enable_if_t<std::is_integral_v<T>>
580612
>
581-
constexpr void itoa(const T value, char *const str) {
613+
constexpr uint32_t itoa(const T value, char *const str) {
582614
// return the implementation
583615
return detail::itoa_impl<B, Boolalpha, T>(value, str);
584616
}
@@ -592,14 +624,15 @@ namespace klib::string {
592624
* typename
593625
* @param value
594626
* @param str
627+
* @return characters in buffer
595628
*/
596629
template <
597630
uint32_t Digits = 5, typename T = float,
598631
typename = std::enable_if_t<std::is_floating_point_v<T>>
599632
>
600-
constexpr void stoa(const T value, char *const str) {
633+
constexpr uint32_t ftoa(const T value, char *const str) {
601634
// return the implementation
602-
return detail::stoa_impl<Digits, T>(value, str);
635+
return detail::ftoa_impl<Digits, T>(value, str);
603636
}
604637
}
605638

0 commit comments

Comments
 (0)