[Utility] Add std::string_view overloads for std::from_chars (#2392)

* Add std::string_view overloads for std::from_chars

std::from_chars floating point support is still pour, so we provide some
fall backs. These fall backs currently lack error handling.

(since GCC 11 and MSVC 2019 16.4 FP support is added, clang with libc++
still doesn't support FP)

GCC's floating point support is still rather pour (performance) and
probably shouldn't be used, but we have support to if people want to
now.

Probably need more test cases ...

* Fix issue with std::chars_format define lacking

My test case for lacking FP support was clang with libc++ which defined
this enum anyways.
This commit is contained in:
Michael Cook (mackal) 2022-08-31 00:13:59 -04:00 committed by GitHub
parent 786a7e2169
commit edda5ef811
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 119 additions and 0 deletions

View File

@ -1,3 +1,4 @@
// for folly stuff
/*
* Copyright 2013 Facebook, Inc.
*
@ -13,6 +14,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// for our stuff
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2022 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "strings.h"
#include <fmt/format.h>

View File

@ -1,3 +1,4 @@
// for folly stuff
/*
* Copyright 2013 Facebook, Inc.
*
@ -13,14 +14,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// for our stuff
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2022 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _STRINGUTIL_H_
#define _STRINGUTIL_H_
#include <charconv>
#include <sstream>
#include <string.h>
#include <string_view>
#include <vector>
#include <cstdarg>
#include <tuple>
#include <type_traits>
#ifndef _WIN32
// this doesn't appear to affect linux-based systems..need feedback for _WIN64
@ -36,6 +58,29 @@
#include "types.h"
namespace detail {
// template magic to check if std::from_chars floating point functions exist
template <typename T, typename = void>
struct has_from_chars_float : std::false_type { };
// basically it "uses" this template if they do exist because reasons
template <typename T>
struct has_from_chars_float < T,
std::void_t<decltype(std::from_chars(std::declval<const char *>(), std::declval<const char *>(),
std::declval<T &>()))>> : std::true_type { };
}; // namespace detail
namespace EQ {
// lame -- older GCC's didn't define this, clang's libc++ however does, even though they lack FP support
#if defined(__GNUC__) && (__GNUC__ < 11) && !defined(__clang__)
enum class chars_format {
scientific = 1, fixed = 2, hex = 4, general = fixed | scientific
};
#else
using chars_format = std::chars_format;
#endif
}; // namespace EQ
class Strings {
public:
static bool Contains(std::vector<std::string> container, std::string element);
@ -79,6 +124,45 @@ public:
output.resize(output.size() - glue.size());
return output;
}
// basic string_view overloads that just use std stuff since they work!
template <typename T>
std::enable_if_t<std::is_floating_point_v<T> && detail::has_from_chars_float<T>::value, std::from_chars_result>
static from_chars(std::string_view str, T& value, EQ::chars_format fmt = EQ::chars_format::general)
{
return std::from_chars(str.data(), str.data() + str.size(), value, fmt);
}
template <typename T>
std::enable_if_t<std::is_integral_v<T>, std::from_chars_result>
static from_chars(std::string_view str, T& value, int base = 10)
{
return std::from_chars(str.data(), str.data() + str.size(), value, base);
}
// fallback versions of floating point in case they're not implemented
// TODO: add error handling ...
// This does have to allocate since from_chars doesn't need a null terminated string and neither does string_view
template <typename T>
std::enable_if_t<std::is_floating_point_v<T> && !detail::has_from_chars_float<T>::value && std::is_same_v<T, float>, std::from_chars_result>
static from_chars(std::string_view str, T& value, EQ::chars_format fmt = EQ::chars_format::general)
{
std::from_chars_result res{};
std::string tmp_str(str.data(), str.size());
value = strtof(tmp_str.data(), nullptr);
return res;
}
template <typename T>
std::enable_if_t<std::is_floating_point_v<T> && !detail::has_from_chars_float<T>::value && std::is_same_v<T, double>, std::from_chars_result>
static from_chars(std::string_view str, T& value, EQ::chars_format fmt = EQ::chars_format::general)
{
std::from_chars_result res{};
std::string tmp_str(str.data(), str.size());
value = strtod(tmp_str.data(), nullptr);
return res;
}
};
const std::string StringFormat(const char *format, ...);

View File

@ -30,6 +30,7 @@ public:
TEST_ADD(StringUtilTest::EscapeStringTest);
TEST_ADD(StringUtilTest::SearchDeliminatedStringTest);
TEST_ADD(StringUtilTest::SplitStringTest);
TEST_ADD(StringUtilTest::FromCharsTest);
}
~StringUtilTest() {
@ -100,6 +101,21 @@ public:
TEST_ASSERT(v[1] == "456");
TEST_ASSERT(v[2] == "789");
}
void FromCharsTest() {
char int_chars[] = "123";
int int_value = 0;
char float_chars[] = "3.14";
float float_value = 0.0f;
Strings::from_chars(int_chars, int_value);
TEST_ASSERT(int_value == 123);
Strings::from_chars(float_chars, float_value);
TEST_ASSERT(float_value == 3.14f);
}
};
#endif