mirror of
https://github.com/enduro2d/enduro2d.git
synced 2026-01-05 01:51:02 +07:00
add strings::try_parse function for arithmetic types
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
@@ -34,9 +35,11 @@
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
#include <charconv>
|
||||
#include <iterator>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <system_error>
|
||||
|
||||
@@ -84,6 +84,21 @@ namespace e2d
|
||||
str32_hash make_hash(str32_view src) noexcept;
|
||||
}
|
||||
|
||||
namespace e2d::strings
|
||||
{
|
||||
template < typename T >
|
||||
std::enable_if_t<std::is_integral_v<T>, bool>
|
||||
try_parse(str_view src, T& dst) noexcept;
|
||||
|
||||
template < typename T >
|
||||
std::enable_if_t<std::is_same_v<T, f32>, T>
|
||||
try_parse(str_view src, T& dst) noexcept;
|
||||
|
||||
template < typename T >
|
||||
std::enable_if_t<std::is_same_v<T, f64>, T>
|
||||
try_parse(str_view src, T& dst) noexcept;
|
||||
}
|
||||
|
||||
namespace e2d::strings
|
||||
{
|
||||
class format_error;
|
||||
|
||||
@@ -180,6 +180,58 @@ namespace std
|
||||
};
|
||||
}
|
||||
|
||||
namespace e2d::strings
|
||||
{
|
||||
template < typename T >
|
||||
std::enable_if_t<std::is_integral_v<T>, bool>
|
||||
try_parse(str_view src, T& dst) noexcept {
|
||||
T tmp{0};
|
||||
std::from_chars_result res = std::from_chars(
|
||||
src.data(), src.data() + src.size(), tmp);
|
||||
if ( res.ptr != src.data() + src.size() || res.ec != std::errc() ) {
|
||||
return false;
|
||||
}
|
||||
dst = tmp;
|
||||
return true;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
std::enable_if_t<std::is_same_v<T, f32>, T>
|
||||
try_parse(str_view src, T& dst) noexcept {
|
||||
if ( src.size() >= 128 ) {
|
||||
return false;
|
||||
}
|
||||
char* str = static_cast<char*>(E2D_CLEAR_ALLOCA(src.size() + 1));
|
||||
std::memcpy(str, src.data(), src.size());
|
||||
errno = 0;
|
||||
char* end = nullptr;
|
||||
T tmp = std::strtof(str, &end);
|
||||
if ( end != str + src.size() || errno ) {
|
||||
return false;
|
||||
}
|
||||
dst = tmp;
|
||||
return true;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
std::enable_if_t<std::is_same_v<T, f64>, T>
|
||||
try_parse(str_view src, T& dst) noexcept {
|
||||
if ( src.size() >= 512 ) {
|
||||
return false;
|
||||
}
|
||||
char* str = static_cast<char*>(E2D_CLEAR_ALLOCA(src.size() + 1));
|
||||
std::memcpy(str, src.data(), src.size());
|
||||
errno = 0;
|
||||
char* end = nullptr;
|
||||
T tmp = std::strtod(str, &end);
|
||||
if ( end != str + src.size() || errno ) {
|
||||
return false;
|
||||
}
|
||||
dst = tmp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d::strings
|
||||
{
|
||||
//
|
||||
|
||||
@@ -99,6 +99,60 @@ TEST_CASE("strings") {
|
||||
REQUIRE(make_utf32(str16_view(null_utf16, 0)) == make_utf32(u""));
|
||||
REQUIRE(make_utf32(str32_view(null_utf32, 0)) == make_utf32(U""));
|
||||
}
|
||||
{
|
||||
using strings::try_parse;
|
||||
|
||||
{
|
||||
i8 v{111};
|
||||
REQUIRE((try_parse("42", v) && v == 42));
|
||||
REQUIRE((try_parse("127", v) && v == 127));
|
||||
REQUIRE((try_parse("0", v) && v == 0));
|
||||
REQUIRE((try_parse("-128", v) && v == -128));
|
||||
|
||||
u8 uv{111};
|
||||
REQUIRE((try_parse("42", uv) && uv == 42));
|
||||
REQUIRE((try_parse("255", uv) && uv == 255));
|
||||
REQUIRE((try_parse("0", uv) && uv == 0));
|
||||
}
|
||||
{
|
||||
i8 v{111};
|
||||
REQUIRE((!try_parse(str_view(), v) && v == 111));
|
||||
REQUIRE((!try_parse("", v) && v == 111));
|
||||
REQUIRE((!try_parse("42hello", v) && v == 111));
|
||||
REQUIRE((!try_parse("world42", v) && v == 111));
|
||||
REQUIRE((!try_parse("42 ", v) && v == 111));
|
||||
REQUIRE((!try_parse(" 42", v) && v == 111));
|
||||
REQUIRE((!try_parse("-129", v) && v == 111));
|
||||
REQUIRE((!try_parse("128", v) && v == 111));
|
||||
REQUIRE((!try_parse("4.2", v) && v == 111));
|
||||
}
|
||||
{
|
||||
f32 v32{11.22f};
|
||||
REQUIRE((try_parse("4.23E10", v32) && math::approximately(v32, 4.23E10f)));
|
||||
REQUIRE((try_parse("42", v32) && math::approximately(v32, 42.f)));
|
||||
REQUIRE((try_parse("-2.43", v32) && math::approximately(v32, -2.43f)));
|
||||
REQUIRE((try_parse("-24", v32) && math::approximately(v32, -24.f)));
|
||||
|
||||
f64 v64{11.22f};
|
||||
REQUIRE((try_parse("4.23E200", v64) && math::approximately(v64, 4.23e200)));
|
||||
REQUIRE((try_parse("42", v64) && math::approximately(v64, 42.)));
|
||||
REQUIRE((try_parse("-2.43", v64) && math::approximately(v64, -2.43)));
|
||||
REQUIRE((try_parse("-24", v64) && math::approximately(v64, -24.)));
|
||||
}
|
||||
{
|
||||
f32 v32{11.22f};
|
||||
REQUIRE((!try_parse("1.0E100", v32) && math::approximately(v32, 11.22f)));
|
||||
REQUIRE((!try_parse("1..4", v32) && math::approximately(v32, 11.22f)));
|
||||
REQUIRE((!try_parse("..14", v32) && math::approximately(v32, 11.22f)));
|
||||
REQUIRE((!try_parse("14..", v32) && math::approximately(v32, 11.22f)));
|
||||
|
||||
f64 v64{11.22};
|
||||
REQUIRE((!try_parse("1.0E400", v64) && math::approximately(v64, 11.22)));
|
||||
REQUIRE((!try_parse("1..4", v64) && math::approximately(v64, 11.22)));
|
||||
REQUIRE((!try_parse("..14", v64) && math::approximately(v64, 11.22)));
|
||||
REQUIRE((!try_parse("14..", v64) && math::approximately(v64, 11.22)));
|
||||
}
|
||||
}
|
||||
{
|
||||
using strings::wildcard_match;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user