Address review: fix AppleClang builds by adding from_chars float fallback

AppleClang's libc++ does not support std::from_chars for floating-point
types. Add a compile-time detection macro (CHAISCRIPT_HAS_FLOAT_FROM_CHARS)
and fall back to strtod/strtof/strtold on libc++ platforms. Centralize the
fallback in parse_num and route bootstrap.hpp and json.hpp through it to
keep the workaround in one place.

Requested by @lefticus in PR #669 review.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
leftibot 2026-04-12 17:10:40 -06:00
parent da7a1e043b
commit 9d4ec82475
3 changed files with 30 additions and 13 deletions

View File

@ -72,6 +72,16 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#include <charconv>
#include <memory>
#include <string>
#include <type_traits>
// libc++ (AppleClang, Emscripten) may not support floating-point std::from_chars
#if !defined(CHAISCRIPT_LIBCPP)
#define CHAISCRIPT_HAS_FLOAT_FROM_CHARS 1
#endif
#ifndef CHAISCRIPT_HAS_FLOAT_FROM_CHARS
#include <cstdlib>
#endif
namespace chaiscript {
constexpr static const int version_major = 7;
@ -125,7 +135,22 @@ namespace chaiscript {
template<typename T>
[[nodiscard]] auto parse_num(const std::string_view t_str) {
T t{};
std::from_chars(t_str.data(), t_str.data() + t_str.size(), t);
if constexpr (std::is_floating_point_v<T>) {
#ifdef CHAISCRIPT_HAS_FLOAT_FROM_CHARS
std::from_chars(t_str.data(), t_str.data() + t_str.size(), t);
#else
const std::string tmp(t_str);
if constexpr (std::is_same_v<T, float>) {
t = std::strtof(tmp.c_str(), nullptr);
} else if constexpr (std::is_same_v<T, long double>) {
t = std::strtold(tmp.c_str(), nullptr);
} else {
t = std::strtod(tmp.c_str(), nullptr);
}
#endif
} else {
std::from_chars(t_str.data(), t_str.data() + t_str.size(), t);
}
return t;
}

View File

@ -10,8 +10,6 @@
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_
#define CHAISCRIPT_BOOTSTRAP_HPP_
#include <charconv>
#include "../utility/utility.hpp"
#include "register_function.hpp"
@ -98,9 +96,7 @@ namespace chaiscript::bootstrap {
if constexpr (std::is_same_v<Input, wchar_t> || std::is_same_v<Input, char16_t> || std::is_same_v<Input, char32_t>) {
throw std::runtime_error("Parsing of wide characters is not yet supported");
} else if constexpr (std::is_arithmetic_v<Input> && !std::is_same_v<Input, char>) {
Input t{};
std::from_chars(i.data(), i.data() + i.size(), t);
return t;
return parse_num<Input>(i);
} else {
std::stringstream ss(i);
Input t;

View File

@ -8,7 +8,6 @@
#include "../chaiscript_defines.hpp"
#include "quick_flat_map.hpp"
#include <cctype>
#include <charconv>
#include <cstdint>
#include <initializer_list>
#include <iostream>
@ -536,14 +535,11 @@ namespace chaiscript::json {
const auto *const first = str.data() + start;
const auto *const last = str.data() + offset;
const auto numstr = std::string_view(first, static_cast<std::string_view::size_type>(last - first));
if (isDouble) {
double val = 0;
std::from_chars(first, last, val);
return JSON(val);
return JSON(chaiscript::parse_num<double>(numstr));
} else {
std::int64_t val = 0;
std::from_chars(first, last, val);
return JSON(val);
return JSON(chaiscript::parse_num<std::int64_t>(numstr));
}
}