From 79d63f53fe2880e8ef022a1b4118b937394726f4 Mon Sep 17 00:00:00 2001 From: Joel Rosdahl Date: Wed, 4 Aug 2021 21:39:08 +0200 Subject: [PATCH] enhance(util): Add parse_double function --- src/util/string.cpp | 20 ++++++++++++++++++++ src/util/string.hpp | 5 +++++ unittest/test_util_string.cpp | 13 +++++++++++++ 3 files changed, 38 insertions(+) diff --git a/src/util/string.cpp b/src/util/string.cpp index 87055605e..38df7d99a 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -25,6 +25,26 @@ namespace util { +nonstd::expected +parse_double(const std::string& value) +{ + size_t end; + double result; + bool failed = false; + try { + result = std::stod(value, &end); + } catch (const std::exception&) { + failed = true; + } + + if (failed || end != value.size()) { + return nonstd::make_unexpected( + FMT("invalid floating point: \"{}\"", value)); + } else { + return result; + } +} + nonstd::expected parse_signed(const std::string& value, const nonstd::optional min_value, diff --git a/src/util/string.hpp b/src/util/string.hpp index c3a15e881..62b0670bb 100644 --- a/src/util/string.hpp +++ b/src/util/string.hpp @@ -47,6 +47,11 @@ template std::string join(const T& begin, const T& end, const nonstd::string_view delimiter); +// Parse a string into a double. +// +// Returns an error string if `value` cannot be parsed as a double. +nonstd::expected parse_double(const std::string& value); + // Parse a string into a signed integer. // // Returns an error string if `value` cannot be parsed as an int64_t or if the diff --git a/unittest/test_util_string.cpp b/unittest/test_util_string.cpp index 294cdb1ea..275430413 100644 --- a/unittest/test_util_string.cpp +++ b/unittest/test_util_string.cpp @@ -72,6 +72,19 @@ TEST_CASE("util::join") } } +TEST_CASE("util::parse_double") +{ + CHECK(*util::parse_double("0") == doctest::Approx(0.0)); + CHECK(*util::parse_double(".0") == doctest::Approx(0.0)); + CHECK(*util::parse_double("0.") == doctest::Approx(0.0)); + CHECK(*util::parse_double("0.0") == doctest::Approx(0.0)); + CHECK(*util::parse_double("2.1") == doctest::Approx(2.1)); + CHECK(*util::parse_double("-42.789") == doctest::Approx(-42.789)); + + CHECK(util::parse_double("").error() == "invalid floating point: \"\""); + CHECK(util::parse_double("x").error() == "invalid floating point: \"x\""); +} + TEST_CASE("util::parse_signed") { CHECK(*util::parse_signed("0") == 0); -- 2.47.2