From e1537294a4241a95ec572aaf440bbbcb567d0725 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 8 Dec 2023 13:45:53 -0500 Subject: [PATCH] Add std::string conversions --- .../include/CesiumGltf/MetadataConversions.h | 107 ++++++++++++------ 1 file changed, 73 insertions(+), 34 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/MetadataConversions.h b/CesiumGltf/include/CesiumGltf/MetadataConversions.h index e3008e637..2657058d2 100644 --- a/CesiumGltf/include/CesiumGltf/MetadataConversions.h +++ b/CesiumGltf/include/CesiumGltf/MetadataConversions.h @@ -95,6 +95,26 @@ template <> struct MetadataConversions { } }; +/** + * @brief Converts from std::string to a bool. + */ +template <> struct MetadataConversions { +public: + /** + * @brief Converts the contents of a std::string to a boolean. + * + * "0", "false", and "no" (case-insensitive) are converted to false, while + * "1", "true", and "yes" are converted to true. All other strings will return + * std::nullopt. + * + * @param from The std::string to convert from. + */ + static std::optional convert(const std::string& from) { + return MetadataConversions::convert( + std::string_view(from.data(), from.size())); + } +}; + #pragma endregion #pragma region Conversions to integer @@ -152,48 +172,41 @@ struct MetadataConversions< }; /** - * @brief Converts from std::string_view to a signed integer. + * @brief Converts from std::string to a signed integer. */ template struct MetadataConversions< TTo, - std::string_view, + std::string, std::enable_if_t< CesiumGltf::IsMetadataInteger::value && std::is_signed_v>> { /** - * @brief Converts the contents of a std::string_view to a signed integer. - * This assumes that the entire std::string_view represents the number, not + * @brief Converts the contents of a std::string to a signed integer. + * This assumes that the entire std::string represents the number, not * just a part of it. * * This returns std::nullopt if no number is parsed from the string. * - * @param from The std::string_view to parse from. + * @param from The std::string to parse from. */ - static std::optional convert(const std::string_view& from) { + static std::optional convert(const std::string& from) { if (from.size() == 0) { // Return early. Otherwise, empty strings will be parsed as 0, which is // misleading. return std::nullopt; } - // Amazingly, C++ has no* string parsing functions that work with strings - // that might not be null-terminated. So we have to copy to a std::string - // (which _is_ guaranteed to be null terminated) before parsing. - // * except std::from_chars, but compiler/library support for the - // floating-point version of that method is spotty at best. - std::string temp(from); - char* pLastUsed; - int64_t parsedValue = std::strtoll(temp.c_str(), &pLastUsed, 10); - if (pLastUsed == temp.c_str() + temp.size()) { + int64_t parsedValue = std::strtoll(from.c_str(), &pLastUsed, 10); + if (pLastUsed == from.c_str() + from.size()) { // Successfully parsed the entire string as an integer of this type. return CesiumUtility::losslessNarrow(parsedValue); } // Failed to parse as an integer. Maybe we can parse as a double and // truncate it? - double parsedDouble = std::strtod(temp.c_str(), &pLastUsed); - if (pLastUsed == temp.c_str() + temp.size()) { + double parsedDouble = std::strtod(from.c_str(), &pLastUsed); + if (pLastUsed == from.c_str() + from.size()) { // Successfully parsed the entire string as a double. // Convert it to an integer if we can. double truncated = glm::trunc(parsedDouble); @@ -210,49 +223,42 @@ struct MetadataConversions< }; /** - * @brief Converts from std::string_view to an unsigned integer. + * @brief Converts from std::string to an unsigned integer. */ template struct MetadataConversions< TTo, - std::string_view, + std::string, std::enable_if_t< CesiumGltf::IsMetadataInteger::value && !std::is_signed_v>> { /** - * @brief Converts the contents of a std::string_view to an signed integer. - * This assumes that the entire std::string_view represents the number, not + * @brief Converts the contents of a std::string to an signed integer. + * This assumes that the entire std::string represents the number, not * just a part of it. * * This returns std::nullopt if no number is parsed from the string. * - * @param from The std::string_view to parse from. + * @param from The std::string to parse from. * @param defaultValue The default value to be returned if conversion fails. */ - static std::optional convert(const std::string_view& from) { + static std::optional convert(const std::string& from) { if (from.size() == 0) { // Return early. Otherwise, empty strings will be parsed as 0, which is // misleading. return std::nullopt; } - // Amazingly, C++ has no* string parsing functions that work with strings - // that might not be null-terminated. So we have to copy to a std::string - // (which _is_ guaranteed to be null terminated) before parsing. - // * except std::from_chars, but compiler/library support for the - // floating-point version of that method is spotty at best. - std::string temp(from); - char* pLastUsed; - uint64_t parsedValue = std::strtoull(temp.c_str(), &pLastUsed, 10); - if (pLastUsed == temp.c_str() + temp.size()) { + uint64_t parsedValue = std::strtoull(from.c_str(), &pLastUsed, 10); + if (pLastUsed == from.c_str() + from.size()) { // Successfully parsed the entire string as an integer of this type. return CesiumUtility::losslessNarrow(parsedValue); } // Failed to parse as an integer. Maybe we can parse as a double and // truncate it? - double parsedDouble = std::strtod(temp.c_str(), &pLastUsed); - if (pLastUsed == temp.c_str() + temp.size()) { + double parsedDouble = std::strtod(from.c_str(), &pLastUsed); + if (pLastUsed == from.c_str() + from.size()) { // Successfully parsed the entire string as a double. // Convert it to an integer if we can. double truncated = glm::trunc(parsedDouble); @@ -268,6 +274,39 @@ struct MetadataConversions< } }; +/** + * @brief Converts from std::string_view to an integer. + */ +template +struct MetadataConversions< + TTo, + std::string_view, + std::enable_if_t::value>> { + /** + * @brief Converts the contents of a std::string_view to an integer. + * This assumes that the entire std::string_view represents the number, not + * just a part of it. + * + * This returns std::nullopt if no number is parsed from the string. + * + * @param from The std::string_view to parse from. + */ + static std::optional convert(const std::string_view& from) { + if (from.size() == 0) { + // Return early. Otherwise, empty strings will be parsed as 0, which is + // misleading. + return std::nullopt; + } + + // Amazingly, C++ has no* string parsing functions that work with strings + // that might not be null-terminated. So we have to copy to a std::string + // (which _is_ guaranteed to be null terminated) before parsing. + // * except std::from_chars, but compiler/library support for the + // floating-point version of that method is spotty at best. + return MetadataConversions::convert(std::string(from)); + } +}; + /** * @brief Converts from a boolean to an integer type. */