Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion src/iceberg/util/string_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
#pragma once

#include <algorithm>
#include <cerrno>
#include <charconv>
#include <ranges>
#include <string>
#include <string_view>
#include <type_traits>
#include <typeinfo>
#include <utility>

Expand All @@ -32,6 +34,9 @@

namespace iceberg {

template <typename T>
concept FromChars = requires(const char* p, T& v) { std::from_chars(p, p, v); };

class ICEBERG_EXPORT StringUtils {
public:
static std::string ToLower(std::string_view str) {
Expand Down Expand Up @@ -68,7 +73,7 @@ class ICEBERG_EXPORT StringUtils {
}

template <typename T>
requires std::is_arithmetic_v<T> && (!std::same_as<T, bool>)
requires std::is_arithmetic_v<T> && FromChars<T> && (!std::same_as<T, bool>)
static Result<T> ParseNumber(std::string_view str) {
T value = 0;
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), value);
Expand All @@ -85,6 +90,35 @@ class ICEBERG_EXPORT StringUtils {
}
std::unreachable();
}

template <typename T>
requires std::is_floating_point_v<T> && (!FromChars<T>)
static Result<T> ParseNumber(std::string_view str) {
T value{};
// strto* require null-terminated input; string_view does not guarantee it.
std::string owned(str);
const char* start = owned.c_str();
char* end = nullptr;
errno = 0;

if constexpr (std::same_as<T, float>) {
value = std::strtof(start, &end);
} else if constexpr (std::same_as<T, double>) {
value = std::strtod(start, &end);
} else {
value = std::strtold(start, &end);
}

if (end == start || end != start + static_cast<std::ptrdiff_t>(owned.size())) {
return InvalidArgument("Failed to parse {} from string '{}': invalid argument",
typeid(T).name(), str);
}
if (errno == ERANGE) {
return InvalidArgument("Failed to parse {} from string '{}': value out of range",
typeid(T).name(), str);
}
return value;
}
};

/// \brief Transparent hash function that supports std::string_view as lookup key
Expand Down
Loading