Skip to content

Commit aae105d

Browse files
[strings] Start from_floating_point
1 parent 1c941a9 commit aae105d

File tree

4 files changed

+116
-0
lines changed

4 files changed

+116
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// SPDX-License-Identifier: BSL-1.0
2+
3+
#ifndef TETL_STRINGS_FROM_FLOATING_POINT_HPP
4+
#define TETL_STRINGS_FROM_FLOATING_POINT_HPP
5+
6+
#include <etl/_algorithm/reverse.hpp>
7+
#include <etl/_concepts/floating_point.hpp>
8+
#include <etl/_math/ipow.hpp>
9+
#include <etl/_span/span.hpp>
10+
#include <etl/_type_traits/conditional.hpp>
11+
12+
namespace etl::strings {
13+
14+
struct from_floating_point_options {
15+
bool terminate_with_null = true;
16+
};
17+
18+
enum struct from_floating_point_error : unsigned char {
19+
none,
20+
overflow,
21+
};
22+
23+
struct from_floating_point_result {
24+
char* end{nullptr};
25+
from_floating_point_error error{from_floating_point_error::none};
26+
};
27+
28+
template <floating_point Float, from_floating_point_options Options = from_floating_point_options{}>
29+
[[nodiscard]] constexpr auto from_floating_point(Float val, span<char> out, int precision) -> from_floating_point_result
30+
{
31+
using int_type = conditional_t<(sizeof(Float) > 4), long long, long>;
32+
33+
constexpr auto toString = [](int_type x, char* str, int numDigits) -> int {
34+
int i = 0;
35+
while (x) {
36+
str[i++] = (x % 10) + '0';
37+
x = x / 10;
38+
}
39+
40+
// If number of digits required is more, then
41+
// add 0s at the beginning
42+
while (i < numDigits) {
43+
str[i++] = '0';
44+
}
45+
46+
etl::reverse(str, str + i);
47+
str[i] = '\0';
48+
return i;
49+
};
50+
51+
auto* res = out.data();
52+
53+
auto const whole = static_cast<int_type>(val);
54+
auto const frac = val - static_cast<Float>(whole);
55+
auto const pos = toString(whole, res, 0);
56+
57+
if (precision == 0) {
58+
return {};
59+
}
60+
61+
// Get the value of fraction part upto given no.
62+
// of points after dot. The third parameter
63+
// is needed to handle cases like 233.007
64+
auto part = static_cast<int_type>(frac * static_cast<Float>(etl::ipow<10>(precision)));
65+
res[pos] = '.';
66+
toString(part, res + pos + 1, precision);
67+
68+
return {.end = res + pos};
69+
}
70+
71+
} // namespace etl::strings
72+
73+
#endif // TETL_STRINGS_FROM_FLOATING_POINT_HPP

include/etl/strings.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
/// Non-standard extensions
1717
#include <etl/_strings/find.hpp>
18+
#include <etl/_strings/from_floating_point.hpp>
1819
#include <etl/_strings/from_integer.hpp>
1920
#include <etl/_strings/rfind.hpp>
2021
#include <etl/_strings/to_floating_point.hpp>

tests/strings/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
project("strings")
22

3+
tetl_add_test(${PROJECT_NAME} from_floating_point)
34
tetl_add_test(${PROJECT_NAME} from_integer)
45
tetl_add_test(${PROJECT_NAME} to_floating_point)
56
tetl_add_test(${PROJECT_NAME} to_integer)
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// SPDX-License-Identifier: BSL-1.0
2+
3+
#include <etl/strings.hpp>
4+
5+
#include <etl/array.hpp>
6+
#include <etl/iterator.hpp>
7+
#include <etl/string_view.hpp>
8+
9+
#include "testing/approx.hpp"
10+
#include "testing/testing.hpp"
11+
12+
template <typename Float>
13+
constexpr auto test() -> bool
14+
{
15+
using namespace etl::strings;
16+
using namespace etl::string_view_literals;
17+
18+
auto test = [](Float in, auto precision, auto out) -> bool {
19+
auto buf = etl::array<char, 12>{};
20+
auto res = from_floating_point(in, buf, precision);
21+
CHECK(res.error == from_floating_point_error::none);
22+
CHECK(etl::string_view{buf.data()} == out);
23+
return true;
24+
};
25+
26+
CHECK(test(Float(233.007), 0, "233"_sv));
27+
CHECK(test(Float(233.007), 1, "233.0"_sv));
28+
CHECK(test(Float(233.007), 2, "233.00"_sv));
29+
CHECK(test(Float(233.007), 3, "233.007"_sv));
30+
CHECK(test(Float(233.007), 4, "233.0070"_sv));
31+
32+
return true;
33+
}
34+
35+
auto main() -> int
36+
{
37+
STATIC_CHECK(test<float>());
38+
STATIC_CHECK(test<double>());
39+
STATIC_CHECK(test<long double>());
40+
return 0;
41+
}

0 commit comments

Comments
 (0)