mirror of
https://github.com/red0124/ssp.git
synced 2025-01-23 04:55:20 +01:00
Add ability to convert larger numbers without fast_float, write unit tests
This commit is contained in:
parent
b9d2c2aad9
commit
672b89b213
@ -1,13 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "type_traits.hpp"
|
#include "type_traits.hpp"
|
||||||
|
#include <charconv>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <charconv>
|
|
||||||
|
|
||||||
#ifndef SSP_DISABLE_FAST_FLOAT
|
#ifndef SSP_DISABLE_FAST_FLOAT
|
||||||
#include <fast_float/fast_float.h>
|
#include <fast_float/fast_float.h>
|
||||||
@ -42,17 +42,24 @@ std::enable_if_t<std::is_floating_point_v<T>, std::optional<T>> to_num(
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
std::enable_if_t<std::is_floating_point_v<T>, std::optional<T>> to_num(
|
std::enable_if_t<std::is_floating_point_v<T>, std::optional<T>> to_num(
|
||||||
const char* const begin, const char* const end) {
|
const char* const begin, const char* const end) {
|
||||||
|
static_assert(!std::is_same_v<T, long double>,
|
||||||
|
"Conversion to long double is disabled");
|
||||||
|
|
||||||
constexpr static auto buff_max = 64;
|
constexpr static auto buff_max = 64;
|
||||||
char buff[buff_max];
|
char short_buff[buff_max];
|
||||||
size_t string_range = std::distance(begin, end);
|
size_t string_range = std::distance(begin, end);
|
||||||
|
std::string long_buff;
|
||||||
|
|
||||||
|
char* buff;
|
||||||
if (string_range > buff_max) {
|
if (string_range > buff_max) {
|
||||||
return std::nullopt;
|
long_buff = std::string{begin, end};
|
||||||
|
buff = long_buff.data();
|
||||||
|
} else {
|
||||||
|
buff = short_buff;
|
||||||
|
buff[string_range] = '\0';
|
||||||
|
std::copy_n(begin, string_range, buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::copy_n(begin, string_range, buff);
|
|
||||||
buff[string_range] = '\0';
|
|
||||||
|
|
||||||
T ret;
|
T ret;
|
||||||
char* parse_end = nullptr;
|
char* parse_end = nullptr;
|
||||||
|
|
||||||
@ -60,8 +67,6 @@ std::enable_if_t<std::is_floating_point_v<T>, std::optional<T>> to_num(
|
|||||||
ret = std::strtof(buff, &parse_end);
|
ret = std::strtof(buff, &parse_end);
|
||||||
} else if constexpr (std::is_same_v<T, double>) {
|
} else if constexpr (std::is_same_v<T, double>) {
|
||||||
ret = std::strtod(buff, &parse_end);
|
ret = std::strtod(buff, &parse_end);
|
||||||
} else if constexpr (std::is_same_v<T, long double>) {
|
|
||||||
ret = std::strtold(buff, &parse_end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_end != buff + string_range) {
|
if (parse_end != buff + string_range) {
|
||||||
|
@ -63,11 +63,6 @@ TEST_CASE("extract test functions for numbers with invalid inputs") {
|
|||||||
// random input for float
|
// random input for float
|
||||||
CHECK_INVALID_CONVERSION("xxx1", float);
|
CHECK_INVALID_CONVERSION("xxx1", float);
|
||||||
|
|
||||||
// number too big
|
|
||||||
CHECK_INVALID_CONVERSION((std::string(40, '1') + "." +
|
|
||||||
std::string(40, '2')),
|
|
||||||
double);
|
|
||||||
|
|
||||||
// random input for int
|
// random input for int
|
||||||
CHECK_INVALID_CONVERSION("xxx1", int);
|
CHECK_INVALID_CONVERSION("xxx1", int);
|
||||||
|
|
||||||
@ -280,3 +275,20 @@ TEST_CASE("extract test functions for std::variant") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("extract test with long number string") {
|
||||||
|
{
|
||||||
|
std::string string_num =
|
||||||
|
std::string(20, '1') + "." + std::string(20, '2');
|
||||||
|
|
||||||
|
CHECK_FLOATING_CONVERSION_LONG_NUMBER(string_num, float, stof);
|
||||||
|
CHECK_FLOATING_CONVERSION_LONG_NUMBER(string_num, double, stod);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::string string_num =
|
||||||
|
std::string(50, '1') + "." + std::string(50, '2');
|
||||||
|
|
||||||
|
CHECK_FLOATING_CONVERSION_LONG_NUMBER(string_num, double, stod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -29,11 +29,6 @@ TEST_CASE("extract test functions for numbers with invalid inputs without fast "
|
|||||||
|
|
||||||
// random input for float
|
// random input for float
|
||||||
CHECK_INVALID_CONVERSION("xxx1", float);
|
CHECK_INVALID_CONVERSION("xxx1", float);
|
||||||
|
|
||||||
// number too big
|
|
||||||
CHECK_INVALID_CONVERSION((std::string(40, '1') + "." +
|
|
||||||
std::string(40, '2')),
|
|
||||||
double);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("extract test functions for std::variant without fast float") {
|
TEST_CASE("extract test functions for std::variant without fast float") {
|
||||||
@ -135,3 +130,20 @@ TEST_CASE("extract test functions for std::variant without fast float") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("extract test with long number string without fast float") {
|
||||||
|
{
|
||||||
|
std::string string_num =
|
||||||
|
std::string(20, '1') + "." + std::string(20, '2');
|
||||||
|
|
||||||
|
CHECK_FLOATING_CONVERSION_LONG_NUMBER(string_num, float, stof);
|
||||||
|
CHECK_FLOATING_CONVERSION_LONG_NUMBER(string_num, double, stod);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::string string_num =
|
||||||
|
std::string(50, '1') + "." + std::string(50, '2');
|
||||||
|
|
||||||
|
CHECK_FLOATING_CONVERSION_LONG_NUMBER(string_num, double, stod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <filesystem>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
#ifdef CMAKE_GITHUB_CI
|
#ifdef CMAKE_GITHUB_CI
|
||||||
#include <doctest/doctest.h>
|
#include <doctest/doctest.h>
|
||||||
@ -75,6 +75,18 @@ struct unique_file_name {
|
|||||||
CHECK_LT(std::abs(t.value() - type(-input)), eps); \
|
CHECK_LT(std::abs(t.value() - type(-input)), eps); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define CHECK_FLOATING_CONVERSION_LONG_NUMBER(STRING_NUMBER, TYPE, CONVERTER) \
|
||||||
|
{ \
|
||||||
|
auto begin = STRING_NUMBER.c_str(); \
|
||||||
|
auto end = begin + STRING_NUMBER.size(); \
|
||||||
|
\
|
||||||
|
auto number = ss::to_num<TYPE>(begin, end); \
|
||||||
|
REQUIRE(number.has_value()); \
|
||||||
|
\
|
||||||
|
auto expected_number = CONVERTER(STRING_NUMBER); \
|
||||||
|
CHECK_EQ(number.value(), expected_number); \
|
||||||
|
}
|
||||||
|
|
||||||
#define CHECK_INVALID_CONVERSION(input, type) \
|
#define CHECK_INVALID_CONVERSION(input, type) \
|
||||||
{ \
|
{ \
|
||||||
std::string s = input; \
|
std::string s = input; \
|
||||||
|
Loading…
Reference in New Issue
Block a user