PStringUtils::ToInt: signal conversion errors via from_chars

ToInt() previously wrapped strtol() with a nullptr endptr, so a failed
conversion was indistinguishable from a legitimate 0 (matching the old
TString::Atoi() behaviour). Switch the implementation to std::from_chars
and add an optional `bool *ok` out-parameter that reports success: it is
set to false on a non-numeric string or an out-of-range value, true
otherwise. Leading whitespace is skipped and trailing characters are
ignored, preserving the Atoi-like prefix semantics. The parameter
defaults to nullptr, so existing call sites keep compiling unchanged.

Convert the parse-validation call sites in PMsrHandler to the single
-parse ToInt(token, &ok) form, replacing the IsInt() guard + separate
ToInt() (which parsed every token twice). All downstream >0 / >=0 /
range / enum checks are preserved.

Left untouched the call sites where IsInt() acts as a structural
discriminator rather than a numeric validator (write path, xy-data
index-vs-label, fParamInUse usage scans) and the IsFloat-guarded ToInt
offsets, where switching to ToInt(&ok) would change parsing semantics.

All 85 integration tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 09:30:23 +02:00
co-authored by Claude Opus 4.8
parent a6c887e059
commit 3f5765fe46
2 changed files with 0 additions and 228 deletions
-210
View File
@@ -3670,21 +3670,11 @@ Bool_t PMsrHandler::HandleRunEntry(PMsrLines &lines)
error = true;
} else {
for (UInt_t i=1; i<tokens.size(); i++) {
<<<<<<< HEAD
bool ok = false;
ival = PStringUtils::ToInt(tokens[i], &ok);
if (ok && ival > 0)
param.SetDataRange(ival, i-1);
else
=======
if (PStringUtils::IsInt(tokens[i])) {
ival = PStringUtils::ToInt(tokens[i]);
if (ival > 0)
param.SetDataRange(ival, i-1);
else
error = true;
} else {
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
error = true;
}
}
@@ -3699,21 +3689,11 @@ Bool_t PMsrHandler::HandleRunEntry(PMsrLines &lines)
error = true;
} else {
for (UInt_t i=1; i<tokens.size(); i++) {
<<<<<<< HEAD
bool ok = false;
dval = PStringUtils::ToDouble(tokens[i], &ok);
if (ok && dval >= 0.0)
param.SetT0Bin(dval);
else
=======
if (PStringUtils::IsFloat(tokens[i])) {
dval = PStringUtils::ToDouble(tokens[i]);
if (dval >= 0.0)
param.SetT0Bin(dval);
else
error = true;
} else {
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
error = true;
}
}
@@ -3728,21 +3708,11 @@ Bool_t PMsrHandler::HandleRunEntry(PMsrLines &lines)
error = true;
} else {
for (UInt_t i=1; i<tokens.size(); i++) {
<<<<<<< HEAD
bool ok = false;
dval = PStringUtils::ToDouble(tokens[i], &ok);
if (ok && dval >= 0.0)
param.SetAddT0Bin(dval, addT0Counter, i-1);
else
=======
if (PStringUtils::IsFloat(tokens[i])) {
dval = PStringUtils::ToDouble(tokens[i]);
if (dval >= 0.0)
param.SetAddT0Bin(dval, addT0Counter, i-1);
else
error = true;
} else {
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
error = true;
}
}
@@ -3790,15 +3760,10 @@ Bool_t PMsrHandler::HandleRunEntry(PMsrLines &lines)
param.SetFitRangeInBins(true);
} else { // fit given in time, i.e. fit <start> <end>, where <start>, <end> are given as doubles
for (UInt_t i=1; i<3; i++) {
<<<<<<< HEAD
bool ok = false;
const double range = PStringUtils::ToDouble(tokens[i], &ok);
if (ok)
param.SetFitRange(range, i-1);
=======
if (PStringUtils::IsFloat(tokens[i]))
param.SetFitRange(PStringUtils::ToDouble(tokens[i]), i-1);
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
else
error = true;
}
@@ -3814,21 +3779,11 @@ Bool_t PMsrHandler::HandleRunEntry(PMsrLines &lines)
if (tokens.size() != 2) {
error = true;
} else {
<<<<<<< HEAD
bool ok = false;
ival = PStringUtils::ToInt(tokens[1], &ok);
if (ok && ival > 0)
param.SetPacking(ival);
else
=======
if (PStringUtils::IsInt(tokens[1])) {
ival = PStringUtils::ToInt(tokens[1]);
if (ival > 0)
param.SetPacking(ival);
else
error = true;
} else {
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
error = true;
}
}
@@ -4050,15 +4005,10 @@ Bool_t PMsrHandler::ParseFourierPhaseValueVector(PMsrFourierStructure &fourier,
// convert all acceptable tokens
for (UInt_t i=1; i<tok.size(); i++) {
<<<<<<< HEAD
bool ok = false;
const double phase = PStringUtils::ToDouble(tok[i], &ok);
if (ok) {
fourier.fPhase.push_back(phase);
=======
if (PStringUtils::IsFloat(tok[i])) {
fourier.fPhase.push_back(PStringUtils::ToDouble(tok[i]));
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
} else {
result = false;
if (i>1) { // make sure that no 'phase val, parX' mixture is present
@@ -4146,19 +4096,12 @@ Bool_t PMsrHandler::ParseFourierPhaseParVector(PMsrFourierStructure &fourier, co
rmNoOf++;
}
sstr = sstr.substr(rmNoOf); // remove 'par' of 'parR' part. Rest should be an integer
<<<<<<< HEAD
bool ok = false;
Int_t val = PStringUtils::ToInt(sstr, &ok);
if (ok) {
if (rmNoOf == 4) // parR
fourier.fPhaseRef = val;
fourier.fPhaseParamNo.push_back(val);
=======
if (PStringUtils::IsInt(sstr)) {
if (rmNoOf == 4) // parR
fourier.fPhaseRef = PStringUtils::ToInt(sstr);
fourier.fPhaseParamNo.push_back(PStringUtils::ToInt(sstr));
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
} else {
fLastErrorMsg.str("");
fLastErrorMsg.clear();
@@ -4242,15 +4185,9 @@ Bool_t PMsrHandler::ParseFourierPhaseParIterVector(PMsrFourierStructure &fourier
Int_t x0, offset, noParam;
// get X0
<<<<<<< HEAD
bool ok = false;
x0 = PStringUtils::ToInt(tok[0], &ok);
if (!ok) {
=======
if (PStringUtils::IsInt(tok[0])) {
x0 = PStringUtils::ToInt(tok[0]);
} else {
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
fLastErrorMsg.str("");
fLastErrorMsg.clear();
fLastErrorMsg << ">> PMsrHandler::ParseFourierPhaseParIterVector: **ERROR** X0='" << tok[0] << "' is not an integer.\n";
@@ -4260,14 +4197,8 @@ Bool_t PMsrHandler::ParseFourierPhaseParIterVector(PMsrFourierStructure &fourier
}
// get offset
<<<<<<< HEAD
offset = PStringUtils::ToInt(tok[1], &ok);
if (!ok) {
=======
if (PStringUtils::IsInt(tok[1])) {
offset = PStringUtils::ToInt(tok[1]);
} else {
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
fLastErrorMsg.str("");
fLastErrorMsg.clear();
fLastErrorMsg << ">> PMsrHandler::ParseFourierPhaseParIterVector: **ERROR** offset='" << tok[1] << "' is not an integer.\n";
@@ -4277,14 +4208,8 @@ Bool_t PMsrHandler::ParseFourierPhaseParIterVector(PMsrFourierStructure &fourier
}
// get noParam
<<<<<<< HEAD
noParam = PStringUtils::ToInt(tok[2], &ok);
if (!ok) {
=======
if (PStringUtils::IsInt(tok[2])) {
noParam = PStringUtils::ToInt(tok[2]);
} else {
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
fLastErrorMsg.str("");
fLastErrorMsg.clear();
fLastErrorMsg << ">> PMsrHandler::ParseFourierPhaseParIterVector: **ERROR** #Param='" << tok[2] << "' is not an integer.\n";
@@ -4365,23 +4290,11 @@ Bool_t PMsrHandler::HandleFourierEntry(PMsrLines &lines)
error = true;
continue;
} else {
<<<<<<< HEAD
bool ok = false;
ival = PStringUtils::ToInt(tokens[1], &ok);
if (ok && (ival >= 0) && (ival <= 20)) {
fourier.fFourierPower = ival;
} else { // fourier power not a number or out of range
=======
if (PStringUtils::IsInt(tokens[1])) {
ival = PStringUtils::ToInt(tokens[1]);
if ((ival >= 0) && (ival <= 20)) {
fourier.fFourierPower = ival;
} else { // fourier power out of range
error = true;
continue;
}
} else { // fourier power not a number
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
error = true;
continue;
}
@@ -4517,15 +4430,9 @@ Bool_t PMsrHandler::HandleFourierEntry(PMsrLines &lines)
continue;
} else {
for (UInt_t i=0; i<2; i++) {
<<<<<<< HEAD
bool ok = false;
fourier.fPlotRange[i] = PStringUtils::ToDouble(tokens[i+1], &ok);
if (!ok) {
=======
if (PStringUtils::IsFloat(tokens[i+1])) {
fourier.fPlotRange[i] = PStringUtils::ToDouble(tokens[i+1]);
} else {
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
error = true;
continue;
}
@@ -4556,15 +4463,9 @@ Bool_t PMsrHandler::HandleFourierEntry(PMsrLines &lines)
break;
case 3:
for (UInt_t i=0; i<2; i++) {
<<<<<<< HEAD
bool ok = false;
fourier.fRangeForPhaseCorrection[i] = PStringUtils::ToDouble(tokens[i+1], &ok);
if (!ok)
=======
if (PStringUtils::IsFloat(tokens[i+1])) {
fourier.fRangeForPhaseCorrection[i] = PStringUtils::ToDouble(tokens[i+1]);
} else {
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
error = true;
}
break;
@@ -4671,15 +4572,9 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
if (tokens.size() < 2) { // plot type missing
error = true;
} else {
<<<<<<< HEAD
bool ok = false;
param.fPlotType = PStringUtils::ToInt(tokens[1], &ok);
if (!ok)
=======
if (PStringUtils::IsInt(tokens[1]))
param.fPlotType = PStringUtils::ToInt(tokens[1]);
else
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
error = true;
}
} else if (line.Contains("lifetimecorrection", TString::kIgnoreCase)) {
@@ -4734,53 +4629,33 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
} else {
// handle t_min
<<<<<<< HEAD
bool ok = false;
const double tmin = PStringUtils::ToDouble(tokens[1], &ok);
if (ok)
param.fTmin.push_back(tmin);
=======
if (PStringUtils::IsFloat(tokens[1]))
param.fTmin.push_back(PStringUtils::ToDouble(tokens[1]));
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
else
error = true;
// handle t_max
<<<<<<< HEAD
const double tmax = PStringUtils::ToDouble(tokens[2], &ok);
if (ok)
param.fTmax.push_back(tmax);
=======
if (PStringUtils::IsFloat(tokens[2]))
param.fTmax.push_back(PStringUtils::ToDouble(tokens[2]));
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
else
error = true;
if (tokens.size() == 5) { // y-axis interval given as well
// handle y_min
<<<<<<< HEAD
const double ymin = PStringUtils::ToDouble(tokens[3], &ok);
if (ok)
param.fYmin.push_back(ymin);
=======
if (PStringUtils::IsFloat(tokens[3]))
param.fYmin.push_back(PStringUtils::ToDouble(tokens[3]));
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
else
error = true;
// handle y_max
<<<<<<< HEAD
const double ymax = PStringUtils::ToDouble(tokens[4], &ok);
if (ok)
param.fYmax.push_back(ymax);
=======
if (PStringUtils::IsFloat(tokens[4]))
param.fYmax.push_back(PStringUtils::ToDouble(tokens[4]));
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
else
error = true;
}
@@ -4800,27 +4675,17 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
for (UInt_t i=0; i<param.fRuns.size(); i++) {
// handle t_min
<<<<<<< HEAD
bool ok = false;
const double tmin = PStringUtils::ToDouble(tokens[2*i+1], &ok);
if (ok)
param.fTmin.push_back(tmin);
=======
if (PStringUtils::IsFloat(tokens[2*i+1]))
param.fTmin.push_back(PStringUtils::ToDouble(tokens[2*i+1]));
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
else
error = true;
// handle t_max
<<<<<<< HEAD
const double tmax = PStringUtils::ToDouble(tokens[2*i+2], &ok);
if (ok)
param.fTmax.push_back(tmax);
=======
if (PStringUtils::IsFloat(tokens[2*i+2]))
param.fTmax.push_back(PStringUtils::ToDouble(tokens[2*i+2]));
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
else
error = true;
}
@@ -4829,27 +4694,17 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
if (tokens.size() == 2*param.fRuns.size() + 3) {
// handle y_min
<<<<<<< HEAD
bool ok = false;
const double ymin = PStringUtils::ToDouble(tokens[2*param.fRuns.size()+1], &ok);
if (ok)
param.fYmin.push_back(ymin);
=======
if (PStringUtils::IsFloat(tokens[2*param.fRuns.size()+1]))
param.fYmin.push_back(PStringUtils::ToDouble(tokens[2*param.fRuns.size()+1]));
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
else
error = true;
// handle y_max
<<<<<<< HEAD
const double ymax = PStringUtils::ToDouble(tokens[2*param.fRuns.size()+2], &ok);
if (ok)
param.fYmax.push_back(ymax);
=======
if (PStringUtils::IsFloat(tokens[2*param.fRuns.size()+2]))
param.fYmax.push_back(PStringUtils::ToDouble(tokens[2*param.fRuns.size()+2]));
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
else
error = true;
}
@@ -4862,27 +4717,17 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
if (tokens.size() == 3) { // i.e. use_fit_ranges ymin ymax
// handle y_min
<<<<<<< HEAD
bool ok = false;
const double ymin = PStringUtils::ToDouble(tokens[1], &ok);
if (ok)
param.fYmin.push_back(ymin);
=======
if (PStringUtils::IsFloat(tokens[1]))
param.fYmin.push_back(PStringUtils::ToDouble(tokens[1]));
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
else
error = true;
// handle y_max
<<<<<<< HEAD
const double ymax = PStringUtils::ToDouble(tokens[2], &ok);
if (ok)
param.fYmax.push_back(ymax);
=======
if (PStringUtils::IsFloat(tokens[2]))
param.fYmax.push_back(PStringUtils::ToDouble(tokens[2]));
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
else
error = true;
}
@@ -4904,24 +4749,12 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
if (tokens.size() != 2) {
error = true;
} else {
<<<<<<< HEAD
bool ok = false;
Int_t val = PStringUtils::ToInt(tokens[1], &ok);
if (ok && val > 0)
param.fViewPacking = val;
else
error = true;
=======
if (PStringUtils::IsInt(tokens[1])) {
Int_t val = PStringUtils::ToInt(tokens[1]);
if (val > 0)
param.fViewPacking = val;
else
error = true;
} else {
error = true;
}
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
}
} else if (iter1->fLine.Contains("rrf_freq", TString::kIgnoreCase)) {
// expected entry: rrf_freq value unit
@@ -4931,15 +4764,9 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
error = true;
} else {
// get rrf frequency
<<<<<<< HEAD
bool ok = false;
param.fRRFFreq = PStringUtils::ToDouble(tokens[1], &ok);
if (!ok)
=======
if (PStringUtils::IsFloat(tokens[1])) {
param.fRRFFreq = PStringUtils::ToDouble(tokens[1]);
} else {
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
error = true;
// get unit
if (PStringUtils::ContainsNoCase(tokens[2], "kHz"))
@@ -4963,7 +4790,6 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
error = true;
} else {
// get rrf phase
<<<<<<< HEAD
bool ok = false;
const double rrfPhase = PStringUtils::ToDouble(tokens[1], &ok);
if (ok) {
@@ -4979,44 +4805,10 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
param.fRRFPhaseParamNo = no;
// get parameter value
param.fRRFPhase = fParam[no-1].fValue;
=======
if (PStringUtils::IsFloat(tokens[1])) {
param.fRRFPhase = PStringUtils::ToDouble(tokens[1]);
} else {
if (PStringUtils::BeginsWithNoCase(tokens[1], "par")) { // parameter value
Int_t no = 0;
if (FilterNumber(tokens[1].c_str(), "par", 0, no)) {
// check that the parameter is in range
if (static_cast<Int_t>(fParam.size()) < no) {
error = true;
} else {
// keep the parameter number in case parX was used
param.fRRFPhaseParamNo = no;
// get parameter value
param.fRRFPhase = fParam[no-1].fValue;
}
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
}
}
<<<<<<< HEAD
=======
}
}
} else if (iter1->fLine.Contains("rrf_packing", TString::kIgnoreCase)) {
// expected entry: rrf_phase value. value given in units of degree
tokens = PStringUtils::Split(iter1->fLine.Data(), " \t");
if (tokens.size() != 2) {
error = true;
} else {
// get rrf packing
if (PStringUtils::IsInt(tokens[1])) {
param.fRRFPacking = PStringUtils::ToInt(tokens[1]);
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
} else {
error = true;
}
}
<<<<<<< HEAD
} else if (iter1->fLine.Contains("rrf_packing", TString::kIgnoreCase)) {
// expected entry: rrf_phase value. value given in units of degree
tokens = PStringUtils::Split(iter1->fLine.Data(), " \t");
@@ -5029,8 +4821,6 @@ Bool_t PMsrHandler::HandlePlotEntry(PMsrLines &lines)
if (!ok)
error = true;
}
=======
>>>>>>> b072a481 (PMsrHandler: replace ROOT tokenizer machinery with C++17 PStringUtils)
} else {
error = true;
}