Skip to content

Commit 9393129

Browse files
committed
fix: use strtod for double parsing on macOS, bump to 1.1.2
macOS libc++ does not support std::from_chars for floating-point types. Replace with strtod using a stack buffer for typical numeric values.
1 parent 2d64331 commit 9393129

3 files changed

Lines changed: 45 additions & 8 deletions

File tree

CITATION.cff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
cff-version: 1.2.0
22
message: "If you use this software, please cite it."
33
title: "VCFX: A Minimalist, Modular Toolkit for Streamlined Variant Analysis"
4-
version: "1.1.1"
4+
version: "1.1.2"
55
authors:
66
- family-names: Silva
77
given-names: Jorge Miguel

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
33
# Set version information
44
set(VCFX_VERSION_MAJOR 1)
55
set(VCFX_VERSION_MINOR 1)
6-
set(VCFX_VERSION_PATCH 1)
6+
set(VCFX_VERSION_PATCH 2)
77
set(VCFX_VERSION "${VCFX_VERSION_MAJOR}.${VCFX_VERSION_MINOR}.${VCFX_VERSION_PATCH}")
88

99
add_compile_definitions(VCFX_VERSION="${VCFX_VERSION}")

src/VCFX_record_filter/VCFX_record_filter.cpp

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,24 @@ static bool parseSingleCriterion(std::string_view token, FilterCriterion& crit)
140140
crit.target = TargetField::INFO_KEY;
141141
}
142142

143-
// Try to parse as numeric using fast charconv
143+
// Try to parse as numeric using strtod (from_chars for double unavailable on macOS)
144144
double d;
145-
auto result = std::from_chars(valPart.data(), valPart.data() + valPart.size(), d);
146-
if (result.ec == std::errc{} && result.ptr == valPart.data() + valPart.size()) {
145+
char buf[64];
146+
bool isNumeric = false;
147+
if (valPart.size() < sizeof(buf)) {
148+
std::memcpy(buf, valPart.data(), valPart.size());
149+
buf[valPart.size()] = '\0';
150+
char* endptr;
151+
d = std::strtod(buf, &endptr);
152+
isNumeric = (endptr == buf + valPart.size());
153+
} else {
154+
std::string tmp(valPart);
155+
char* endptr;
156+
d = std::strtod(tmp.c_str(), &endptr);
157+
isNumeric = (endptr == tmp.c_str() + tmp.size());
158+
}
159+
160+
if (isNumeric) {
147161
crit.fieldType = FieldType::NUMERIC;
148162
crit.numericValue = d;
149163
crit.stringValue.clear();
@@ -253,12 +267,35 @@ bool VCFXRecordFilter::extractInfoValue(std::string_view info, std::string_view
253267
}
254268

255269
// ============================================================================
256-
// Fast numeric parsing using std::from_chars (no exceptions, no allocations)
270+
// Fast numeric parsing - uses strtod with careful bounds checking
271+
// (std::from_chars for double is not available on macOS libc++)
257272
// ============================================================================
258273
bool VCFXRecordFilter::parseDouble(std::string_view sv, double& out) {
259274
if (sv.empty()) return false;
260-
auto result = std::from_chars(sv.data(), sv.data() + sv.size(), out);
261-
return result.ec == std::errc{} && result.ptr == sv.data() + sv.size();
275+
276+
// Fast path: check if the string_view is null-terminated or followed by
277+
// a non-numeric character (common case for VCF parsing)
278+
const char* start = sv.data();
279+
const char* end = start + sv.size();
280+
281+
// Need a null-terminated string for strtod
282+
// Use a small stack buffer for typical numeric values
283+
char buf[64];
284+
if (sv.size() < sizeof(buf)) {
285+
std::memcpy(buf, start, sv.size());
286+
buf[sv.size()] = '\0';
287+
start = buf;
288+
} else {
289+
// Unlikely: very long numeric string
290+
std::string tmp(sv);
291+
char* endptr;
292+
out = std::strtod(tmp.c_str(), &endptr);
293+
return endptr == tmp.c_str() + tmp.size();
294+
}
295+
296+
char* endptr;
297+
out = std::strtod(start, &endptr);
298+
return endptr == start + sv.size();
262299
}
263300

264301
bool VCFXRecordFilter::parseInt(std::string_view sv, int64_t& out) {

0 commit comments

Comments
 (0)