diff --git a/common/strings.cpp b/common/strings.cpp index 238ed89e0..5e288e722 100644 --- a/common/strings.cpp +++ b/common/strings.cpp @@ -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 diff --git a/common/strings.h b/common/strings.h index d251405cf..471f02e32 100644 --- a/common/strings.h +++ b/common/strings.h @@ -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 #include #include +#include #include #include #include +#include #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 + struct has_from_chars_float : std::false_type { }; + + // basically it "uses" this template if they do exist because reasons + template + struct has_from_chars_float < T, + std::void_t(), std::declval(), + std::declval()))>> : 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 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 + std::enable_if_t && detail::has_from_chars_float::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 + std::enable_if_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 + std::enable_if_t && !detail::has_from_chars_float::value && std::is_same_v, 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 + std::enable_if_t && !detail::has_from_chars_float::value && std::is_same_v, 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, ...); diff --git a/tests/string_util_test.h b/tests/string_util_test.h index 2914b0306..5d8a3a956 100644 --- a/tests/string_util_test.h +++ b/tests/string_util_test.h @@ -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