/* * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; 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, see . */ #ifndef TRINITY_STRINGCONVERT_H #define TRINITY_STRINGCONVERT_H #include "Define.h" #include "Errors.h" #include "Optional.h" #include "Types.h" #include "Util.h" #include #include #include #include namespace Trinity::Impl::StringConvertImpl { template struct For { static_assert(Trinity::dependant_false_v, "Unsupported type used for ToString or StringTo"); /* static Optional FromString(std::string_view str, ...); static std::string ToString(T&& val, ...); */ }; // @todo relax this once proper std::from_chars support exists template struct For && !std::is_same_v>> { static Optional FromString(std::string_view str, int base = 10) { if (base == 0) { if (StringEqualI(str.substr(0, 2), "0x")) { base = 16; str.remove_prefix(2); } else if (StringEqualI(str.substr(0, 2), "0b")) { base = 2; str.remove_prefix(2); } else base = 10; if (str.empty()) return std::nullopt; } char const* const start = str.data(); char const* const end = (start + str.length()); T val; std::from_chars_result const res = std::from_chars(start, end, val, base); if ((res.ptr == end) && (res.ec == std::errc())) return val; else return std::nullopt; } static std::string ToString(T val) { std::string buf(20,'\0'); /* 2^64 is 20 decimal characters, -(2^63) is 20 including the sign */ char* const start = buf.data(); char* const end = (start + buf.length()); std::to_chars_result const res = std::to_chars(start, end, val); ASSERT(res.ec == std::errc()); buf.resize(res.ptr - start); return buf; } }; #ifdef TRINITY_NEED_CHARCONV_WORKAROUND /* If this is defined, std::from_chars will cause linkage errors for 64-bit types. (This is a bug in clang-7.) If the clang requirement is bumped to >= clang-8, remove this ifdef block and its associated check in cmake/compiler/clang/settings.cmake */ template <> struct For { static Optional FromString(std::string_view str, int base = 10) { if (str.empty()) return std::nullopt; try { size_t n; uint64 val = std::stoull(std::string(str), &n, base); if (n != str.length()) return std::nullopt; return val; } catch (...) { return std::nullopt; } } static std::string ToString(uint64 val) { return std::to_string(val); } }; template <> struct For { static Optional FromString(std::string_view str, int base = 10) { try { if (str.empty()) return std::nullopt; size_t n; int64 val = std::stoll(std::string(str), &n, base); if (n != str.length()) return std::nullopt; return val; } catch (...) { return std::nullopt; } } static std::string ToString(int64 val) { return std::to_string(val); } }; #endif template <> struct For { static Optional FromString(std::string_view str, int strict = 0) /* this is int to match the signature for "proper" integral types */ { if (strict) { if (str == "1") return true; if (str == "0") return false; return std::nullopt; } else { if ((str == "1") || StringEqualI(str, "y") || StringEqualI(str, "on") || StringEqualI(str, "yes") || StringEqualI(str, "true")) return true; if ((str == "0") || StringEqualI(str, "n") || StringEqualI(str, "off") || StringEqualI(str, "no") || StringEqualI(str, "false")) return false; return std::nullopt; } } static std::string ToString(bool val) { return (val ? "1" : "0"); } }; } namespace Trinity { template Optional StringTo(std::string_view str, Params&&... params) { return Trinity::Impl::StringConvertImpl::For::FromString(str, std::forward(params)...); } template std::string ToString(Type&& val, Params&&... params) { return Trinity::Impl::StringConvertImpl::For>::ToString(std::forward(val), std::forward(params)...); } } #endif