Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5bbcb37370 | |||
| 66aa847b58 | |||
| 76070f2098 | |||
| e7af0a781e | |||
| 8cdbb24929 | |||
| b2db41194f | |||
| e3e84a6e56 | |||
| 1a85444763 | |||
| 07f9c744b3 | |||
| aa5cdf8d6a | |||
| bb32426005 | |||
| 4319b4ad69 | |||
| b072a481ba | |||
| dd604d4bf6 |
+1
-1
@@ -6,7 +6,7 @@ if (CMAKE_VERSION GREATER_EQUAL "3.3")
|
||||
cmake_policy(SET CMP0167 NEW)
|
||||
endif ()
|
||||
|
||||
project(musrfit VERSION 1.10.0 LANGUAGES C CXX)
|
||||
project(musrfit VERSION 1.11.0 LANGUAGES C CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
@@ -12,6 +12,13 @@ or
|
||||
|
||||
https://bitbucket.org/muonspin/musrfit
|
||||
|
||||
Release of V1.11.0, 2026/05/28
|
||||
==============================
|
||||
|
||||
add to the mupp/Qt6 version the option to handle variables not only via the
|
||||
Spirit/X3 interface, but also via Python3. It requires that ROOT is compiled
|
||||
with Python support. For details see the musrfit-manual section mupp.
|
||||
|
||||
Release of V1.10.0, 2026/02/21
|
||||
==============================
|
||||
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ target_include_directories(msr2data
|
||||
)
|
||||
target_link_libraries(msr2data ${ROOT_LIBRARIES} ${MUSRFIT_LIBS})
|
||||
|
||||
add_executable(msr2msr msr2msr.cpp)
|
||||
add_executable(msr2msr msr2msr.cpp classes/PStringUtils.cpp)
|
||||
target_link_libraries(msr2msr ${ROOT_LIBRARIES})
|
||||
|
||||
add_executable(musrfit musrfit.cpp)
|
||||
|
||||
@@ -106,6 +106,7 @@ add_library(PMusr SHARED
|
||||
PMsgBoxDict.cxx
|
||||
PMsr2Data.cpp
|
||||
PMsrHandler.cpp
|
||||
PStringUtils.cpp
|
||||
PMusrCanvas.cpp
|
||||
PMusrCanvasDict.cxx
|
||||
PMusr.cpp
|
||||
@@ -270,6 +271,7 @@ install(
|
||||
${MUSRFIT_INC}/PRunSingleHisto.h
|
||||
${MUSRFIT_INC}/PRunSingleHistoRRF.h
|
||||
${MUSRFIT_INC}/PStartupHandler.h
|
||||
${MUSRFIT_INC}/PStringUtils.h
|
||||
${MUSRFIT_INC}/PTheory.h
|
||||
${MUSRFIT_INC}/PUserFcnBase.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
|
||||
+61
-239
@@ -64,10 +64,9 @@
|
||||
#include <TFile.h>
|
||||
#include <TDatime.h>
|
||||
#include <TString.h>
|
||||
#include <TObjArray.h>
|
||||
#include <TObjString.h>
|
||||
|
||||
#include "PFitter.h"
|
||||
#include "PStringUtils.h"
|
||||
|
||||
|
||||
//+++ PSectorChisq class +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@@ -397,8 +396,6 @@ void PFitter::GetPhaseParams()
|
||||
// default functions:
|
||||
// user functions cannot be checked!
|
||||
PMsrLines *theo = fRunInfo->GetMsrTheory();
|
||||
TObjArray *tok = nullptr;
|
||||
TObjString *ostr = nullptr;
|
||||
TString str;
|
||||
int pos = -1;
|
||||
for (unsigned int i=0; i<theo->size(); i++) {
|
||||
@@ -423,18 +420,10 @@ void PFitter::GetPhaseParams()
|
||||
continue;
|
||||
|
||||
// extract phase token
|
||||
tok = line.Tokenize(" \t");
|
||||
if (tok == nullptr) {
|
||||
std::cerr << "PFitter::GetPhaseParams(): **ERROR** couldn't tokenize theory line string." << std::endl;
|
||||
return;
|
||||
std::vector<std::string> tok = PStringUtils::Split(line.Data(), " \t");
|
||||
if (static_cast<int>(tok.size()) > pos) {
|
||||
str = tok[pos].c_str();
|
||||
}
|
||||
if (tok->GetEntries() > pos) {
|
||||
ostr = dynamic_cast<TObjString*>(tok->At(pos));
|
||||
str = ostr->GetString();
|
||||
}
|
||||
// clean up
|
||||
delete tok;
|
||||
tok = nullptr;
|
||||
|
||||
// decode phase token. It can be funX, mapX, or a number
|
||||
if (str.Contains("fun")) { // function
|
||||
@@ -491,22 +480,15 @@ PIntVector PFitter::GetParFromFun(const TString funStr)
|
||||
PIntVector parVec;
|
||||
|
||||
PMsrLines *funList = fRunInfo->GetMsrFunctions();
|
||||
TObjArray *tok = nullptr;
|
||||
TObjString *ostr = nullptr;
|
||||
TString str;
|
||||
|
||||
for (int i=0; i<funList->size(); i++) {
|
||||
if (funList->at(i).fLine.Contains(funStr)) {
|
||||
// tokenize function string
|
||||
tok = funList->at(i).fLine.Tokenize(" =+-*/");
|
||||
if (tok == nullptr) {
|
||||
std::cerr << "PFitter::GetParFromFun(): **ERROR** couldn't tokenize function string." << std::endl;
|
||||
return parVec;
|
||||
}
|
||||
std::vector<std::string> tok = PStringUtils::Split(funList->at(i).fLine.Data(), " =+-*/");
|
||||
|
||||
for (int j=1; j<tok->GetEntries(); j++) {
|
||||
ostr = dynamic_cast<TObjString*>(tok->At(j));
|
||||
str = ostr->GetString();
|
||||
for (int j=1; j<static_cast<int>(tok.size()); j++) {
|
||||
str = tok[j].c_str();
|
||||
// parse tok for parX
|
||||
if (str.Contains("par")) {
|
||||
// find start idx of par in token
|
||||
@@ -533,10 +515,6 @@ PIntVector PFitter::GetParFromFun(const TString funStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clean up
|
||||
delete tok;
|
||||
tok = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,16 +974,14 @@ Bool_t PFitter::CheckCommands()
|
||||
cmd.second = cmdLineNo;
|
||||
fCmdList.push_back(cmd);
|
||||
// filter out possible parameters for scan
|
||||
TObjArray *tokens = nullptr;
|
||||
TObjString *ostr;
|
||||
std::vector<std::string> tokens;
|
||||
TString str;
|
||||
UInt_t ival;
|
||||
|
||||
tokens = line.Tokenize(", \t");
|
||||
tokens = PStringUtils::Split(line.Data(), ", \t");
|
||||
|
||||
for (Int_t i=0; i<tokens->GetEntries(); i++) {
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
str = ostr->GetString();
|
||||
for (Int_t i=0; i<static_cast<int>(tokens.size()); i++) {
|
||||
str = tokens[i].c_str();
|
||||
|
||||
if ((i==1) || (i==2)) { // parX / parY
|
||||
// check that token is a UInt_t
|
||||
@@ -1016,10 +992,6 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]";
|
||||
std::cerr << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ival = str.Atoi();
|
||||
@@ -1031,10 +1003,6 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]";
|
||||
std::cerr << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// keep parameter
|
||||
@@ -1051,10 +1019,6 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]";
|
||||
std::cerr << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ival = str.Atoi();
|
||||
@@ -1065,20 +1029,12 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]";
|
||||
std::cerr << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fScanNoPoints = ival;
|
||||
}
|
||||
}
|
||||
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
} else if (line.Contains("EIGEN", TString::kIgnoreCase)) {
|
||||
cmd.first = PMN_EIGEN;
|
||||
cmd.second = cmdLineNo;
|
||||
@@ -1090,15 +1046,13 @@ Bool_t PFitter::CheckCommands()
|
||||
// (iii) FIT_RANGE start1 end1 start2 end2 ... startN endN
|
||||
// (iv) FIT_RANGE fgb+n0 lgb-n1
|
||||
// (v) FIT_RANGE fgb+n00 lgb-n01 fgb+n10 lgb-n11 ... fgb+nN0 lgb-nN1
|
||||
TObjArray *tokens = nullptr;
|
||||
TObjString *ostr;
|
||||
std::vector<std::string> tokens;
|
||||
TString str;
|
||||
|
||||
tokens = line.Tokenize(", \t");
|
||||
tokens = PStringUtils::Split(line.Data(), ", \t");
|
||||
|
||||
if (tokens->GetEntries() == 2) { // should only be RESET
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(1));
|
||||
str = ostr->GetString();
|
||||
if (static_cast<int>(tokens.size()) == 2) { // should only be RESET
|
||||
str = tokens[1].c_str();
|
||||
if (str.Contains("RESET", TString::kIgnoreCase)) {
|
||||
cmd.first = PMN_FIT_RANGE;
|
||||
cmd.second = cmdLineNo;
|
||||
@@ -1110,32 +1064,23 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> with N the number of runs in the msr-file." << std::endl;
|
||||
std::cerr << std::endl << ">> Found " << str.Data() << ", instead of RESET" << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if ((tokens->GetEntries() > 1) && (static_cast<UInt_t>(tokens->GetEntries()) % 2) == 1) {
|
||||
if ((tokens->GetEntries() > 3) && ((static_cast<UInt_t>(tokens->GetEntries())-1)) != 2*fRunInfo->GetMsrRunList()->size()) {
|
||||
} else if ((static_cast<int>(tokens.size()) > 1) && (static_cast<UInt_t>(static_cast<int>(tokens.size())) % 2) == 1) {
|
||||
if ((static_cast<int>(tokens.size()) > 3) && ((static_cast<UInt_t>(static_cast<int>(tokens.size()))-1)) != 2*fRunInfo->GetMsrRunList()->size()) {
|
||||
std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
|
||||
std::cerr << std::endl << ">> " << line.Data();
|
||||
std::cerr << std::endl << ">> Syntax: FIT_RANGE RESET | FIT_RANGE <start> <end> | FIT_RANGE <s1> <e1> <s2> <e2> .. <sN> <eN> |";
|
||||
std::cerr << std::endl << ">> FIT_RANGE fgb+<n0> lgb-<n1> | FIT_RANGE fgb+<n00> lgb-<n01> fgb+<n10> lgb-<n11> ... fgb+<nN0> lgb-<nN1>,";
|
||||
std::cerr << std::endl << ">> with N the number of runs in the msr-file.";
|
||||
std::cerr << std::endl << ">> Found N=" << (tokens->GetEntries()-1)/2 << ", # runs in msr-file=" << fRunInfo->GetMsrRunList()->size() << std::endl;
|
||||
std::cerr << std::endl << ">> Found N=" << (static_cast<int>(tokens.size())-1)/2 << ", # runs in msr-file=" << fRunInfo->GetMsrRunList()->size() << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
// check that all range entries are numbers or fgb+n0 / lgb-n1
|
||||
Bool_t ok = true;
|
||||
for (Int_t n=1; n<tokens->GetEntries(); n++) {
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(n));
|
||||
str = ostr->GetString();
|
||||
for (Int_t n=1; n<static_cast<int>(tokens.size()); n++) {
|
||||
str = tokens[n].c_str();
|
||||
if (!str.IsFloat()) {
|
||||
if ((n%2 == 1) && (!str.Contains("fgb", TString::kIgnoreCase)))
|
||||
ok = false;
|
||||
@@ -1158,10 +1103,6 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> with N the number of runs in the msr-file.";
|
||||
std::cerr << std::endl << ">> Found token '" << str.Data() << "', which is not a floating point number." << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1172,29 +1113,19 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> FIT_RANGE fgb+<n0> lgb-<n1> | FIT_RANGE fgb+<n00> lgb-<n01> fgb+<n10> lgb-<n11> ... fgb+<nN0> lgb-<nN1>,";
|
||||
std::cerr << std::endl << ">> with N the number of runs in the msr-file.";
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
} else if (line.Contains("FIX", TString::kIgnoreCase)) {
|
||||
// check if the given set of parameters (number or names) is present
|
||||
TObjArray *tokens = nullptr;
|
||||
TObjString *ostr;
|
||||
std::vector<std::string> tokens;
|
||||
TString str;
|
||||
UInt_t ival;
|
||||
|
||||
tokens = line.Tokenize(", \t");
|
||||
tokens = PStringUtils::Split(line.Data(), ", \t");
|
||||
|
||||
for (Int_t i=1; i<tokens->GetEntries(); i++) {
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
str = ostr->GetString();
|
||||
for (Int_t i=1; i<static_cast<int>(tokens.size()); i++) {
|
||||
str = tokens[i].c_str();
|
||||
|
||||
if (str.IsDigit()) { // token might be a parameter number
|
||||
ival = str.Atoi();
|
||||
@@ -1205,10 +1136,6 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> Parameter " << ival << " is out of the Parameter Range [1," << fParams.size() << "]";
|
||||
std::cerr << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else { // token might be a parameter name
|
||||
@@ -1226,19 +1153,11 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> Parameter '" << str.Data() << "' is NOT present as a parameter name";
|
||||
std::cerr << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
|
||||
// everything looks fine, feed the command list
|
||||
cmd.first = PMN_FIX;
|
||||
@@ -1278,16 +1197,14 @@ Bool_t PFitter::CheckCommands()
|
||||
fCmdList.push_back(cmd);
|
||||
} else if (line.Contains("RELEASE", TString::kIgnoreCase)) {
|
||||
// check if the given set of parameters (number or names) is present
|
||||
TObjArray *tokens = nullptr;
|
||||
TObjString *ostr;
|
||||
std::vector<std::string> tokens;
|
||||
TString str;
|
||||
UInt_t ival;
|
||||
|
||||
tokens = line.Tokenize(", \t");
|
||||
tokens = PStringUtils::Split(line.Data(), ", \t");
|
||||
|
||||
for (Int_t i=1; i<tokens->GetEntries(); i++) {
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
str = ostr->GetString();
|
||||
for (Int_t i=1; i<static_cast<int>(tokens.size()); i++) {
|
||||
str = tokens[i].c_str();
|
||||
|
||||
if (str.IsDigit()) { // token might be a parameter number
|
||||
ival = str.Atoi();
|
||||
@@ -1298,10 +1215,6 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> Parameter " << ival << " is out of the Parameter Range [1," << fParams.size() << "]";
|
||||
std::cerr << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else { // token might be a parameter name
|
||||
@@ -1319,19 +1232,11 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> Parameter '" << str.Data() << "' is NOT present as a parameter name";
|
||||
std::cerr << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
cmd.first = PMN_RELEASE;
|
||||
cmd.second = cmdLineNo;
|
||||
fCmdList.push_back(cmd);
|
||||
@@ -1348,16 +1253,14 @@ Bool_t PFitter::CheckCommands()
|
||||
cmd.second = cmdLineNo;
|
||||
fCmdList.push_back(cmd);
|
||||
// filter out possible parameters for scan
|
||||
TObjArray *tokens = nullptr;
|
||||
TObjString *ostr;
|
||||
std::vector<std::string> tokens;
|
||||
TString str;
|
||||
UInt_t ival;
|
||||
|
||||
tokens = line.Tokenize(", \t");
|
||||
tokens = PStringUtils::Split(line.Data(), ", \t");
|
||||
|
||||
for (Int_t i=0; i<tokens->GetEntries(); i++) {
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
str = ostr->GetString();
|
||||
for (Int_t i=0; i<static_cast<int>(tokens.size()); i++) {
|
||||
str = tokens[i].c_str();
|
||||
if (i==1) { // get parameter number
|
||||
// check that token is a UInt_t
|
||||
if (!str.IsDigit()) {
|
||||
@@ -1367,10 +1270,6 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]";
|
||||
std::cerr << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ival = str.Atoi();
|
||||
@@ -1382,10 +1281,6 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]";
|
||||
std::cerr << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// keep parameter
|
||||
@@ -1402,10 +1297,6 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]";
|
||||
std::cerr << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ival = str.Atoi();
|
||||
@@ -1416,10 +1307,6 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]";
|
||||
std::cerr << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fScanNoPoints = ival;
|
||||
@@ -1434,10 +1321,6 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]";
|
||||
std::cerr << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fScanLow = str.Atof();
|
||||
@@ -1452,33 +1335,23 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]";
|
||||
std::cerr << std::endl;
|
||||
fIsValid = false;
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fScanHigh = str.Atof();
|
||||
}
|
||||
}
|
||||
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
} else if (line.Contains("SIMPLEX", TString::kIgnoreCase)) {
|
||||
cmd.first = PMN_SIMPLEX;
|
||||
cmd.second = cmdLineNo;
|
||||
fCmdList.push_back(cmd);
|
||||
} else if (line.Contains("STRATEGY", TString::kIgnoreCase)) {
|
||||
TObjArray *tokens = nullptr;
|
||||
TObjString *ostr;
|
||||
std::vector<std::string> tokens;
|
||||
TString str;
|
||||
|
||||
tokens = line.Tokenize(" \t");
|
||||
if (tokens->GetEntries() == 2) {
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(1));
|
||||
str = ostr->GetString();
|
||||
tokens = PStringUtils::Split(line.Data(), " \t");
|
||||
if (static_cast<int>(tokens.size()) == 2) {
|
||||
str = tokens[1].c_str();
|
||||
if (str.CompareTo("0") == 0) { // low
|
||||
fStrategy = 0;
|
||||
} else if (str.CompareTo("1") == 0) { // default
|
||||
@@ -1494,10 +1367,6 @@ Bool_t PFitter::CheckCommands()
|
||||
}
|
||||
}
|
||||
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
} else if (line.Contains("USER_COVARIANCE", TString::kIgnoreCase)) {
|
||||
cmd.first = PMN_USER_COVARIANCE;
|
||||
cmd.second = cmdLineNo;
|
||||
@@ -1513,35 +1382,28 @@ Bool_t PFitter::CheckCommands()
|
||||
fCmdList.push_back(cmd);
|
||||
|
||||
// check if the given sector arguments are valid time stamps, i.e. doubles and value < lgb time stamp
|
||||
TObjArray *tokens = nullptr;
|
||||
TObjString *ostr;
|
||||
std::vector<std::string> tokens;
|
||||
TString str;
|
||||
|
||||
tokens = line.Tokenize(" ,\t");
|
||||
tokens = PStringUtils::Split(line.Data(), " ,\t");
|
||||
|
||||
if (tokens->GetEntries() == 1) { // no sector time stamps given -> issue an error
|
||||
if (static_cast<int>(tokens.size()) == 1) { // no sector time stamps given -> issue an error
|
||||
std::cerr << std::endl << ">> PFitter::CheckCommands(): **FATAL ERROR** in line " << it->fLineNo;
|
||||
std::cerr << std::endl << ">> " << line.Data();
|
||||
std::cerr << std::endl << ">> At least one sector time stamp is expected.";
|
||||
std::cerr << std::endl << ">> Will stop ...";
|
||||
std::cerr << std::endl;
|
||||
// cleanup
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
fIsValid = false;
|
||||
fSectorFlag = false;
|
||||
break;
|
||||
}
|
||||
|
||||
Double_t dval;
|
||||
for (Int_t i=1; i<tokens->GetEntries(); i++) {
|
||||
for (Int_t i=1; i<static_cast<int>(tokens.size()); i++) {
|
||||
// keep time range of sector
|
||||
PSectorChisq sec(fRunInfo->GetNoOfRuns());
|
||||
// get parse tokens
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
str = ostr->GetString();
|
||||
str = tokens[i].c_str();
|
||||
if (str.IsFloat()) {
|
||||
dval = str.Atof();
|
||||
// check that the sector time stamp is smaller than all lgb time stamps
|
||||
@@ -1552,11 +1414,6 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> The sector time stamp " << dval << " is > as the lgb time stamp (" << fOriginalFitRange[j].second << ") of run " << j << ".";
|
||||
std::cerr << std::endl << ">> Will stop ...";
|
||||
std::cerr << std::endl;
|
||||
// cleanup
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
fIsValid = false;
|
||||
fSectorFlag = false;
|
||||
return fIsValid;
|
||||
@@ -1571,21 +1428,12 @@ Bool_t PFitter::CheckCommands()
|
||||
std::cerr << std::endl << ">> The sector time stamp '" << str << "' is not a number.";
|
||||
std::cerr << std::endl << ">> Will stop ...";
|
||||
std::cerr << std::endl;
|
||||
// cleanup
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
fIsValid = false;
|
||||
fSectorFlag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
} else { // unkown command
|
||||
std::cerr << std::endl << ">> PFitter::CheckCommands(): **FATAL ERROR** in line " << it->fLineNo << " an unkown command is found:";
|
||||
std::cerr << std::endl << ">> " << line.Data();
|
||||
@@ -1729,27 +1577,24 @@ Bool_t PFitter::ExecuteFitRange(UInt_t lineNo)
|
||||
return true;
|
||||
}
|
||||
|
||||
TObjArray *tokens = nullptr;
|
||||
TObjString *ostr;
|
||||
std::vector<std::string> tokens;
|
||||
TString str;
|
||||
|
||||
tokens = fCmdLines[lineNo].fLine.Tokenize(", \t");
|
||||
tokens = PStringUtils::Split(fCmdLines[lineNo].fLine.Data(), ", \t");
|
||||
|
||||
PMsrRunList *runList = fRunInfo->GetMsrRunList();
|
||||
|
||||
// execute command, no error checking needed since this has been already carried out in CheckCommands()
|
||||
if (tokens->GetEntries() == 2) { // reset command
|
||||
if (static_cast<int>(tokens.size()) == 2) { // reset command
|
||||
fRunListCollection->SetFitRange(fOriginalFitRange);
|
||||
} else if (tokens->GetEntries() == 3) { // single fit range for all runs
|
||||
} else if (static_cast<int>(tokens.size()) == 3) { // single fit range for all runs
|
||||
Double_t start = 0.0, end = 0.0;
|
||||
PDoublePair fitRange;
|
||||
PDoublePairVector fitRangeVector;
|
||||
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(1));
|
||||
str = ostr->GetString();
|
||||
str = tokens[1].c_str();
|
||||
start = str.Atof();
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(2));
|
||||
str = ostr->GetString();
|
||||
str = tokens[2].c_str();
|
||||
end = str.Atof();
|
||||
|
||||
fitRange.first = start;
|
||||
@@ -1763,11 +1608,9 @@ Bool_t PFitter::ExecuteFitRange(UInt_t lineNo)
|
||||
PDoublePairVector fitRangeVector;
|
||||
|
||||
for (UInt_t i=0; i<runList->size(); i++) {
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(2*i+1));
|
||||
str = ostr->GetString();
|
||||
str = tokens[2*i+1].c_str();
|
||||
start = str.Atof();
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(2*i+2));
|
||||
str = ostr->GetString();
|
||||
str = tokens[2*i+2].c_str();
|
||||
end = str.Atof();
|
||||
|
||||
fitRange.first = start;
|
||||
@@ -1795,15 +1638,13 @@ Bool_t PFitter::ExecuteFix(UInt_t lineNo)
|
||||
{
|
||||
std::cout << ">> PFitter::ExecuteFix(): " << fCmdLines[lineNo].fLine.Data() << std::endl;
|
||||
|
||||
TObjArray *tokens = nullptr;
|
||||
TObjString *ostr;
|
||||
std::vector<std::string> tokens;
|
||||
TString str;
|
||||
|
||||
tokens = fCmdLines[lineNo].fLine.Tokenize(", \t");
|
||||
tokens = PStringUtils::Split(fCmdLines[lineNo].fLine.Data(), ", \t");
|
||||
|
||||
for (Int_t i=1; i<tokens->GetEntries(); i++) {
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
str = ostr->GetString();
|
||||
for (Int_t i=1; i<static_cast<int>(tokens.size()); i++) {
|
||||
str = tokens[i].c_str();
|
||||
|
||||
if (str.IsDigit()) { // token is a parameter number
|
||||
fMnUserParams.Fix(static_cast<UInt_t>(str.Atoi())-1);
|
||||
@@ -1812,11 +1653,6 @@ Bool_t PFitter::ExecuteFix(UInt_t lineNo)
|
||||
}
|
||||
}
|
||||
|
||||
// clean up
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2124,19 +1960,17 @@ Bool_t PFitter::ExecutePrintLevel(UInt_t lineNo)
|
||||
{
|
||||
std::cout << ">> PFitter::ExecutePrintLevel(): " << fCmdLines[lineNo].fLine.Data() << std::endl;
|
||||
|
||||
TObjArray *tokens = nullptr;
|
||||
TObjString *ostr;
|
||||
std::vector<std::string> tokens;
|
||||
TString str;
|
||||
|
||||
tokens = fCmdLines[lineNo].fLine.Tokenize(", \t");
|
||||
tokens = PStringUtils::Split(fCmdLines[lineNo].fLine.Data(), ", \t");
|
||||
|
||||
if (tokens->GetEntries() < 2) {
|
||||
if (static_cast<int>(tokens.size()) < 2) {
|
||||
std::cerr << std::endl << "**ERROR** from PFitter::ExecutePrintLevel(): SYNTAX: PRINT_LEVEL <N>, where <N>=0-3" << std::endl << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ostr = (TObjString*)tokens->At(1);
|
||||
str = ostr->GetString();
|
||||
str = tokens[1].c_str();
|
||||
|
||||
Int_t ival;
|
||||
if (str.IsDigit()) {
|
||||
@@ -2159,11 +1993,6 @@ Bool_t PFitter::ExecutePrintLevel(UInt_t lineNo)
|
||||
ROOT::Minuit2::MnPrint::SetLevel(fPrintLevel);
|
||||
#endif
|
||||
|
||||
// clean up
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2180,17 +2009,15 @@ Bool_t PFitter::ExecutePrintLevel(UInt_t lineNo)
|
||||
*/
|
||||
Bool_t PFitter::ExecuteRelease(UInt_t lineNo)
|
||||
{
|
||||
TObjArray *tokens = nullptr;
|
||||
TObjString *ostr;
|
||||
std::vector<std::string> tokens;
|
||||
TString str;
|
||||
|
||||
tokens = fCmdLines[lineNo].fLine.Tokenize(", \t");
|
||||
tokens = PStringUtils::Split(fCmdLines[lineNo].fLine.Data(), ", \t");
|
||||
|
||||
std::cout << ">> PFitter::ExecuteRelease(): " << fCmdLines[lineNo].fLine.Data() << std::endl;
|
||||
|
||||
for (Int_t i=1; i<tokens->GetEntries(); i++) {
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
str = ostr->GetString();
|
||||
for (Int_t i=1; i<static_cast<int>(tokens.size()); i++) {
|
||||
str = tokens[i].c_str();
|
||||
|
||||
if (str.IsDigit()) { // token is a parameter number
|
||||
fMnUserParams.Release(static_cast<UInt_t>(str.Atoi())-1);
|
||||
@@ -2203,11 +2030,6 @@ Bool_t PFitter::ExecuteRelease(UInt_t lineNo)
|
||||
}
|
||||
}
|
||||
|
||||
// clean up
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+494
-981
File diff suppressed because it is too large
Load Diff
@@ -34,11 +34,11 @@
|
||||
#include <TColor.h>
|
||||
#include <TRandom.h>
|
||||
#include <TROOT.h>
|
||||
#include <TObjString.h>
|
||||
#include <TGFileDialog.h>
|
||||
|
||||
#include "PMusrCanvas.h"
|
||||
#include "PFourier.h"
|
||||
#include "PStringUtils.h"
|
||||
|
||||
static const char *gFiletypes[] = { "Data files", "*.dat",
|
||||
"All files", "*",
|
||||
@@ -6408,23 +6408,15 @@ Bool_t PMusrCanvas::IsScaleN0AndBkg()
|
||||
PMsrLines *cmd = fMsrHandler->GetMsrCommands();
|
||||
for (UInt_t i=0; i<cmd->size(); i++) {
|
||||
if (cmd->at(i).fLine.Contains("SCALE_N0_BKG", TString::kIgnoreCase)) {
|
||||
TObjArray *tokens = nullptr;
|
||||
TObjString *ostr = nullptr;
|
||||
TString str;
|
||||
tokens = cmd->at(i).fLine.Tokenize(" \t");
|
||||
if (tokens->GetEntries() != 2) {
|
||||
std::vector<std::string> tokens = PStringUtils::Split(cmd->at(i).fLine.Data(), " \t");
|
||||
if (tokens.size() != 2) {
|
||||
std::cerr << std::endl << ">> PRunSingleHisto::IsScaleN0AndBkg(): **WARNING** Found uncorrect 'SCALE_N0_BKG' command, will ignore it.";
|
||||
std::cerr << std::endl << ">> Allowed commands: SCALE_N0_BKG TRUE | FALSE" << std::endl;
|
||||
return willScale;
|
||||
}
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(1));
|
||||
str = ostr->GetString();
|
||||
if (!str.CompareTo("FALSE", TString::kIgnoreCase)) {
|
||||
if (PStringUtils::IsEqualNoCase(tokens[1], "FALSE")) {
|
||||
willScale = false;
|
||||
}
|
||||
// clean up
|
||||
if (tokens)
|
||||
delete tokens;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -383,7 +383,7 @@ Double_t PRunMuMinus::CalcMaxLikelihood(const std::vector<Double_t>& par)
|
||||
Int_t chunk = (fEndTimeBin - fStartTimeBin)/omp_get_num_procs();
|
||||
if (chunk < 10)
|
||||
chunk = 10;
|
||||
#pragma omp parallel for default(shared) private(i,time,theo,data) schedule(dynamic,chunk) reduction(-:mllh)
|
||||
#pragma omp parallel for default(shared) private(i,time,theo,data) schedule(dynamic,chunk) reduction(+:mllh)
|
||||
#endif
|
||||
for (i=fStartTimeBin; i < fEndTimeBin; ++i) {
|
||||
time = fData.GetDataTimeStart() + static_cast<Double_t>(i)*fData.GetDataTimeStep();
|
||||
|
||||
@@ -439,7 +439,7 @@ Double_t PRunSingleHisto::CalcChiSquareExpected(const std::vector<Double_t>& par
|
||||
* <b>OpenMP Parallelization:</b>
|
||||
* - Dynamic scheduling with chunk size = (N_bins / N_processors), minimum 10
|
||||
* - Private variables per thread: i, time, theo, data
|
||||
* - Reduction performed on mllh sum (note: reduction(-:mllh) for subtraction)
|
||||
* - Reduction performed on mllh sum (reduction(+:mllh))
|
||||
*
|
||||
* <b>When to Use Maximum Likelihood vs. χ²:</b>
|
||||
* - <b>Use likelihood:</b> Low count rates (< 100 counts/bin), asymmetric errors
|
||||
@@ -515,7 +515,7 @@ Double_t PRunSingleHisto::CalcMaxLikelihood(const std::vector<Double_t>& par)
|
||||
Int_t chunk = (fEndTimeBin - fStartTimeBin)/omp_get_num_procs();
|
||||
if (chunk < 10)
|
||||
chunk = 10;
|
||||
#pragma omp parallel for default(shared) private(i,time,theo,data) schedule(dynamic,chunk) reduction(-:mllh)
|
||||
#pragma omp parallel for default(shared) private(i,time,theo,data) schedule(dynamic,chunk) reduction(+:mllh)
|
||||
#endif
|
||||
for (i=fStartTimeBin; i<fEndTimeBin; ++i) {
|
||||
time = fData.GetDataTimeStart() + static_cast<Double_t>(i)*fData.GetDataTimeStep();
|
||||
@@ -650,7 +650,7 @@ Double_t PRunSingleHisto::CalcMaxLikelihoodExpected(const std::vector<Double_t>&
|
||||
Int_t chunk = (fEndTimeBin - fStartTimeBin)/omp_get_num_procs();
|
||||
if (chunk < 10)
|
||||
chunk = 10;
|
||||
#pragma omp parallel for default(shared) private(i,time,theo,data) schedule(dynamic,chunk) reduction(-:mllh)
|
||||
#pragma omp parallel for default(shared) private(i,time,theo,data) schedule(dynamic,chunk) reduction(+:mllh)
|
||||
#endif
|
||||
for (i=fStartTimeBin; i<fEndTimeBin; ++i) {
|
||||
time = fData.GetDataTimeStart() + static_cast<Double_t>(i)*fData.GetDataTimeStep();
|
||||
|
||||
@@ -34,13 +34,12 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <TObjArray.h>
|
||||
#include <TObjString.h>
|
||||
#include <TColor.h>
|
||||
#include <TList.h>
|
||||
#include <TXMLAttr.h>
|
||||
|
||||
#include "PStartupHandler.h"
|
||||
#include "PStringUtils.h"
|
||||
|
||||
ClassImpQ(PStartupHandler)
|
||||
|
||||
@@ -451,8 +450,6 @@ void PStartupHandler::OnEndElement(const Char_t *str)
|
||||
*/
|
||||
void PStartupHandler::OnCharacters(const Char_t *str)
|
||||
{
|
||||
TObjArray *tokens;
|
||||
TObjString *ostr;
|
||||
TString tstr;
|
||||
Int_t color, r, g, b, ival;
|
||||
|
||||
@@ -481,60 +478,44 @@ void PStartupHandler::OnCharacters(const Char_t *str)
|
||||
}
|
||||
break;
|
||||
case eColor:
|
||||
// check that str is a rbg code
|
||||
tstr = TString(str);
|
||||
tokens = tstr.Tokenize(",");
|
||||
// check that there any tokens
|
||||
if (!tokens) {
|
||||
std::cerr << std::endl << "PStartupHandler **WARNING** '" << str << "' is not a rbg code, will ignore it";
|
||||
std::cerr << std::endl;
|
||||
return;
|
||||
{
|
||||
// check that str is a rbg code
|
||||
std::vector<std::string> rgb = PStringUtils::Split(str, ",");
|
||||
// check there is the right number of tokens
|
||||
if (rgb.size() != 3) {
|
||||
std::cerr << std::endl << "PStartupHandler **WARNING** '" << str << "' is not a rbg code, will ignore it";
|
||||
std::cerr << std::endl;
|
||||
return;
|
||||
}
|
||||
// get r
|
||||
if (PStringUtils::IsInt(rgb[0])) {
|
||||
r = PStringUtils::ToInt(rgb[0]);
|
||||
} else {
|
||||
std::cerr << std::endl << "PStartupHandler **WARNING** r within the rgb code is not a number, will ignore it";
|
||||
std::cerr << std::endl;
|
||||
return;
|
||||
}
|
||||
// get g
|
||||
if (PStringUtils::IsInt(rgb[1])) {
|
||||
g = PStringUtils::ToInt(rgb[1]);
|
||||
} else {
|
||||
std::cerr << std::endl << "PStartupHandler **WARNING** g within the rgb code is not a number, will ignore it";
|
||||
std::cerr << std::endl;
|
||||
return;
|
||||
}
|
||||
// get b
|
||||
if (PStringUtils::IsInt(rgb[2])) {
|
||||
b = PStringUtils::ToInt(rgb[2]);
|
||||
} else {
|
||||
std::cerr << std::endl << "PStartupHandler **WARNING** b within the rgb code is not a number, will ignore it";
|
||||
std::cerr << std::endl;
|
||||
return;
|
||||
}
|
||||
// generate the ROOT color code based on str
|
||||
color = TColor::GetColor(r,g,b);
|
||||
// add the color code to the color list
|
||||
fColorList.push_back(color);
|
||||
}
|
||||
// check there is the right number of tokens
|
||||
if (tokens->GetEntries() != 3) {
|
||||
std::cerr << std::endl << "PStartupHandler **WARNING** '" << str << "' is not a rbg code, will ignore it";
|
||||
std::cerr << std::endl;
|
||||
return;
|
||||
}
|
||||
// get r
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(0));
|
||||
tstr = ostr->GetString();
|
||||
if (tstr.IsDigit()) {
|
||||
r = tstr.Atoi();
|
||||
} else {
|
||||
std::cerr << std::endl << "PStartupHandler **WARNING** r within the rgb code is not a number, will ignore it";
|
||||
std::cerr << std::endl;
|
||||
return;
|
||||
}
|
||||
// get g
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(1));
|
||||
tstr = ostr->GetString();
|
||||
if (tstr.IsDigit()) {
|
||||
g = tstr.Atoi();
|
||||
} else {
|
||||
std::cerr << std::endl << "PStartupHandler **WARNING** g within the rgb code is not a number, will ignore it";
|
||||
std::cerr << std::endl;
|
||||
return;
|
||||
}
|
||||
// get b
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(2));
|
||||
tstr = ostr->GetString();
|
||||
if (tstr.IsDigit()) {
|
||||
b = tstr.Atoi();
|
||||
} else {
|
||||
std::cerr << std::endl << "PStartupHandler **WARNING** b within the rgb code is not a number, will ignore it";
|
||||
std::cerr << std::endl;
|
||||
return;
|
||||
}
|
||||
// clean up tokens
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
// generate the ROOT color code based on str
|
||||
color = TColor::GetColor(r,g,b);
|
||||
// add the color code to the color list
|
||||
fColorList.push_back(color);
|
||||
break;
|
||||
case eUnits:
|
||||
tstr = TString(str);
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
/***************************************************************************
|
||||
|
||||
PStringUtils.cpp
|
||||
|
||||
Author: Andreas Suter
|
||||
e-mail: andreas.suter@psi.ch
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007-2026 by Andreas Suter *
|
||||
* andreas.suter@psi.ch *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <charconv>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "PStringUtils.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Split (static)
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* <p>Splits a string into tokens on any character contained in delimiters,
|
||||
* skipping empty tokens. Mirrors the semantics of TString::Tokenize().
|
||||
*
|
||||
* \param str input string to be tokenized
|
||||
* \param delimiters set of delimiter characters
|
||||
* \return vector of tokens (without the delimiters)
|
||||
*/
|
||||
std::vector<std::string> PStringUtils::Split(const std::string &str, const std::string &delimiters)
|
||||
{
|
||||
std::vector<std::string> tokens;
|
||||
std::string::size_type start = str.find_first_not_of(delimiters);
|
||||
while (start != std::string::npos) {
|
||||
std::string::size_type end = str.find_first_of(delimiters, start);
|
||||
if (end == std::string::npos) {
|
||||
tokens.push_back(str.substr(start));
|
||||
break;
|
||||
}
|
||||
tokens.push_back(str.substr(start, end - start));
|
||||
start = str.find_first_not_of(delimiters, end);
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// IsInt (static)
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* <p>Returns true if the string is an integer literal, i.e. a non-empty
|
||||
* sequence of decimal digits with an optional single leading sign (+/-).
|
||||
* This is slightly more permissive than TString::IsDigit(), which rejects a
|
||||
* sign, so that negative/positive integers such as "-5" or "+42" are also
|
||||
* recognised.
|
||||
*
|
||||
* \param str string to be checked
|
||||
* \return true if str is a (possibly signed) integer
|
||||
*/
|
||||
bool PStringUtils::IsInt(const std::string &str)
|
||||
{
|
||||
// all characters must be digits or whitespace, with an optional single
|
||||
// leading sign (+/-) preceding the digits, and there must be at least one
|
||||
// digit (surrounding/embedded whitespace is tolerated, e.g. for tokens
|
||||
// split on ',' or ';' only).
|
||||
bool hasDigit = false;
|
||||
bool hasSign = false;
|
||||
for (char c : str) {
|
||||
if (std::isdigit(static_cast<unsigned char>(c))) {
|
||||
hasDigit = true;
|
||||
} else if (c == '+' || c == '-') {
|
||||
// a sign is only valid before any digit and may appear at most once
|
||||
if (hasDigit || hasSign)
|
||||
return false;
|
||||
hasSign = true;
|
||||
} else if (!std::isspace(static_cast<unsigned char>(c))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return hasDigit;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// IsFloat (static)
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* <p>Returns true if the string is a complete integer or floating point
|
||||
* literal (optionally signed, with decimal point and/or exponent). Mirrors
|
||||
* the semantics of TString::IsFloat() for the relevant cases.
|
||||
*
|
||||
* \param str string to be checked
|
||||
* \return true if str is a valid number
|
||||
*/
|
||||
bool PStringUtils::IsFloat(const std::string &str)
|
||||
{
|
||||
// mirror TString::IsFloat(): surrounding whitespace is ignored (e.g. for
|
||||
// tokens split on ',' or ';' only), then a complete number is required.
|
||||
const std::string ws(" \t\n\r\f\v");
|
||||
std::string::size_type b = str.find_first_not_of(ws);
|
||||
if (b == std::string::npos)
|
||||
return false;
|
||||
std::string::size_type e = str.find_last_not_of(ws);
|
||||
const std::string t = str.substr(b, e - b + 1);
|
||||
|
||||
std::string::size_type i = 0;
|
||||
if (t[i] == '+' || t[i] == '-')
|
||||
++i;
|
||||
// reject things like "inf"/"nan" which strtod would otherwise accept
|
||||
if (i >= t.size() || !(std::isdigit(static_cast<unsigned char>(t[i])) || t[i] == '.'))
|
||||
return false;
|
||||
const char *begin = t.c_str();
|
||||
char *end = nullptr;
|
||||
std::strtod(begin, &end);
|
||||
return end == begin + t.size();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// ToInt (static)
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* <p>Converts the leading part of the string to an int (base 10), mirroring
|
||||
* TString::Atoi(). Returns 0 if no conversion is possible.
|
||||
*
|
||||
* <p>Uses std::from_chars so that conversion errors can be reported through
|
||||
* the optional \a ok out-parameter: it is set to true when a valid integer
|
||||
* was parsed (leading whitespace is skipped) and to false otherwise (no
|
||||
* digits present, or the value is out of int range). Trailing non-numeric
|
||||
* characters are ignored, as with TString::Atoi(). A null \a ok preserves the
|
||||
* historic fire-and-forget behaviour.
|
||||
*
|
||||
* \param str string to be converted
|
||||
* \param ok optional out-parameter signalling conversion success
|
||||
* \return converted integer value (0 on error)
|
||||
*/
|
||||
int PStringUtils::ToInt(const std::string &str, bool *ok)
|
||||
{
|
||||
// mirror TString::Atoi(): skip leading whitespace, then parse the leading
|
||||
// integer (a possible sign followed by decimal digits).
|
||||
const char *begin = str.c_str();
|
||||
const char *end = begin + str.size();
|
||||
while (begin != end && std::isspace(static_cast<unsigned char>(*begin)))
|
||||
++begin;
|
||||
|
||||
int value = 0;
|
||||
const std::from_chars_result res = std::from_chars(begin, end, value);
|
||||
if (ok != nullptr)
|
||||
*ok = (res.ec == std::errc{});
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// ToDouble (static)
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* <p>Converts the leading part of the string to a double, mirroring
|
||||
* TString::Atof(). Returns 0.0 if no conversion is possible.
|
||||
*
|
||||
* <p>Like ToInt(), conversion errors can be reported through the optional
|
||||
* \a ok out-parameter: it is set to true when a value was parsed and to
|
||||
* false otherwise (no number present, or the value is out of range). This
|
||||
* lets callers distinguish a legitimate 0.0 from a failed conversion.
|
||||
* strtod() (rather than std::from_chars) is used so that the accepted input
|
||||
* set stays identical to TString::Atof() (leading whitespace is skipped, a
|
||||
* leading '+' is honoured, trailing characters are ignored). A null \a ok
|
||||
* preserves the historic fire-and-forget behaviour.
|
||||
*
|
||||
* \param str string to be converted
|
||||
* \param ok optional out-parameter signalling conversion success
|
||||
* \return converted double value (0.0 on error)
|
||||
*/
|
||||
double PStringUtils::ToDouble(const std::string &str, bool *ok)
|
||||
{
|
||||
const char *begin = str.c_str();
|
||||
char *end = nullptr;
|
||||
errno = 0;
|
||||
const double value = std::strtod(begin, &end);
|
||||
if (ok != nullptr)
|
||||
*ok = (end != begin) && (errno != ERANGE);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// IsEqualNoCase (static)
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* <p>Case-insensitive full-string equality, mirroring
|
||||
* TString::CompareTo(..., TString::kIgnoreCase) == 0.
|
||||
*
|
||||
* \param a first string
|
||||
* \param b second string
|
||||
* \return true if a and b are equal ignoring case
|
||||
*/
|
||||
bool PStringUtils::IsEqualNoCase(const std::string &a, const std::string &b)
|
||||
{
|
||||
if (a.size() != b.size())
|
||||
return false;
|
||||
for (std::string::size_type i = 0; i < a.size(); ++i) {
|
||||
if (std::tolower(static_cast<unsigned char>(a[i])) !=
|
||||
std::tolower(static_cast<unsigned char>(b[i])))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// ContainsNoCase (static)
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* <p>Case-insensitive substring search, mirroring
|
||||
* TString::Contains(..., TString::kIgnoreCase).
|
||||
*
|
||||
* \param haystack string to be searched in
|
||||
* \param needle substring to be searched for
|
||||
* \return true if needle is contained in haystack ignoring case
|
||||
*/
|
||||
bool PStringUtils::ContainsNoCase(const std::string &haystack, const std::string &needle)
|
||||
{
|
||||
if (needle.empty())
|
||||
return true;
|
||||
if (needle.size() > haystack.size())
|
||||
return false;
|
||||
auto toLower = [](unsigned char c) { return std::tolower(c); };
|
||||
for (std::string::size_type i = 0; i + needle.size() <= haystack.size(); ++i) {
|
||||
std::string::size_type j = 0;
|
||||
for (; j < needle.size(); ++j) {
|
||||
if (toLower(haystack[i+j]) != toLower(needle[j]))
|
||||
break;
|
||||
}
|
||||
if (j == needle.size())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// BeginsWithNoCase (static)
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* <p>Case-insensitive prefix test, mirroring
|
||||
* TString::BeginsWith(..., TString::kIgnoreCase).
|
||||
*
|
||||
* \param str string to be tested
|
||||
* \param prefix prefix to be searched for
|
||||
* \return true if str starts with prefix ignoring case
|
||||
*/
|
||||
bool PStringUtils::BeginsWithNoCase(const std::string &str, const std::string &prefix)
|
||||
{
|
||||
if (prefix.size() > str.size())
|
||||
return false;
|
||||
for (std::string::size_type i = 0; i < prefix.size(); ++i) {
|
||||
if (std::tolower(static_cast<unsigned char>(str[i])) !=
|
||||
std::tolower(static_cast<unsigned char>(prefix[i])))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
+2
-1
@@ -102,7 +102,8 @@ static inline void SobolIni(This *t)
|
||||
int inibits = -1, bit;
|
||||
for( j = powers; j; j >>= 1 ) ++inibits;
|
||||
|
||||
memcpy(pv, pini, inibits*sizeof *pini);
|
||||
if( inibits > 0 )
|
||||
memcpy(pv, pini, inibits*sizeof *pini);
|
||||
pini += 8;
|
||||
|
||||
for( bit = inibits; bit <= nbits; ++bit ) {
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/***************************************************************************
|
||||
|
||||
PStringUtils.h
|
||||
|
||||
Author: Andreas Suter
|
||||
e-mail: andreas.suter@psi.ch
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007-2026 by Andreas Suter *
|
||||
* andreas.suter@psi.ch *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _PSTRINGUTILS_H_
|
||||
#define _PSTRINGUTILS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
//-------------------------------------------------------------
|
||||
/**
|
||||
* \brief Lightweight, dependency-free string utilities (pure C++17).
|
||||
*
|
||||
* PStringUtils collects small string helpers used throughout the musrfit
|
||||
* suite, in particular for tokenizing and parsing the plain-text MSR file
|
||||
* format. The implementation deliberately relies only on the C++ standard
|
||||
* library (no ROOT) so that it can be reused freely.
|
||||
*
|
||||
* The provided helpers replicate the semantics of the corresponding
|
||||
* ROOT TString methods that were previously used:
|
||||
* - Split replaces TString::Tokenize() (+ TObjArray/TObjString)
|
||||
* - IsInt replaces TString::IsDigit()
|
||||
* - IsFloat replaces TString::IsFloat()
|
||||
* - ToInt replaces TString::Atoi()
|
||||
* - ToDouble replaces TString::Atof()
|
||||
* - IsEqualNoCase replaces TString::CompareTo(..., TString::kIgnoreCase)
|
||||
*
|
||||
* All methods are static; the class is a pure namespace-like utility.
|
||||
*/
|
||||
class PStringUtils
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* <p>Splits a string into tokens on any character contained in
|
||||
* delimiters, skipping empty tokens. Mirrors TString::Tokenize().
|
||||
*
|
||||
* @param str input string to be tokenized
|
||||
* @param delimiters set of delimiter characters
|
||||
* @return vector of tokens (without the delimiters)
|
||||
*/
|
||||
static std::vector<std::string> Split(const std::string &str, const std::string &delimiters);
|
||||
|
||||
/**
|
||||
* <p>Returns true if the string is a (possibly signed) integer literal,
|
||||
* i.e. a non-empty sequence of decimal digits with an optional single
|
||||
* leading sign (+/-). Slightly more permissive than TString::IsDigit(),
|
||||
* which rejects a sign, so that e.g. "-5" is also recognised.
|
||||
*
|
||||
* @param str string to be checked
|
||||
* @return true if str is a (possibly signed) integer
|
||||
*/
|
||||
static bool IsInt(const std::string &str);
|
||||
|
||||
/**
|
||||
* <p>Returns true if the string is a complete integer or floating point
|
||||
* literal (optionally signed, with decimal point and/or exponent).
|
||||
* Mirrors TString::IsFloat() for the relevant cases.
|
||||
*
|
||||
* @param str string to be checked
|
||||
* @return true if str is a valid number
|
||||
*/
|
||||
static bool IsFloat(const std::string &str);
|
||||
|
||||
/**
|
||||
* <p>Converts the leading part of the string to an int (base 10).
|
||||
* Mirrors TString::Atoi(). Returns 0 if no conversion is possible.
|
||||
*
|
||||
* <p>If \a ok is non-null it is set to true when a valid integer was
|
||||
* parsed and to false on error (no digits, or value out of int range).
|
||||
* This allows callers to distinguish a legitimate 0 from a failed
|
||||
* conversion, which the bare return value cannot express.
|
||||
*
|
||||
* @param str string to be converted
|
||||
* @param ok optional out-parameter signalling conversion success
|
||||
* @return converted integer value (0 on error)
|
||||
*/
|
||||
static int ToInt(const std::string &str, bool *ok = nullptr);
|
||||
|
||||
/**
|
||||
* <p>Converts the leading part of the string to a double.
|
||||
* Mirrors TString::Atof(). Returns 0.0 if no conversion is possible.
|
||||
*
|
||||
* <p>If \a ok is non-null it is set to true when a value was parsed and
|
||||
* to false on error (no number, or value out of range), allowing callers
|
||||
* to distinguish a legitimate 0.0 from a failed conversion.
|
||||
*
|
||||
* @param str string to be converted
|
||||
* @param ok optional out-parameter signalling conversion success
|
||||
* @return converted double value (0.0 on error)
|
||||
*/
|
||||
static double ToDouble(const std::string &str, bool *ok = nullptr);
|
||||
|
||||
/**
|
||||
* <p>Case-insensitive full-string equality.
|
||||
* Mirrors TString::CompareTo(..., TString::kIgnoreCase) == 0.
|
||||
*
|
||||
* @param a first string
|
||||
* @param b second string
|
||||
* @return true if a and b are equal ignoring case
|
||||
*/
|
||||
static bool IsEqualNoCase(const std::string &a, const std::string &b);
|
||||
|
||||
/**
|
||||
* <p>Case-insensitive substring search.
|
||||
* Mirrors TString::Contains(..., TString::kIgnoreCase).
|
||||
*
|
||||
* @param haystack string to be searched in
|
||||
* @param needle substring to be searched for
|
||||
* @return true if needle is contained in haystack ignoring case
|
||||
*/
|
||||
static bool ContainsNoCase(const std::string &haystack, const std::string &needle);
|
||||
|
||||
/**
|
||||
* <p>Case-insensitive prefix test.
|
||||
* Mirrors TString::BeginsWith(..., TString::kIgnoreCase).
|
||||
*
|
||||
* @param str string to be tested
|
||||
* @param prefix prefix to be searched for
|
||||
* @return true if str starts with prefix ignoring case
|
||||
*/
|
||||
static bool BeginsWithNoCase(const std::string &str, const std::string &prefix);
|
||||
};
|
||||
|
||||
#endif // _PSTRINGUTILS_H_
|
||||
+52
-86
@@ -35,8 +35,8 @@
|
||||
#include <cstdlib>
|
||||
|
||||
#include <TString.h>
|
||||
#include <TObjArray.h>
|
||||
#include <TObjString.h>
|
||||
|
||||
#include "PStringUtils.h"
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// msr block header tags
|
||||
@@ -88,8 +88,6 @@ bool msr2msr_run(char *str, const std::size_t size)
|
||||
|
||||
TString run(str);
|
||||
TString line(str);
|
||||
TObjArray *tokens;
|
||||
TObjString *ostr[2];
|
||||
|
||||
// for filtering
|
||||
run.ToUpper();
|
||||
@@ -100,8 +98,8 @@ bool msr2msr_run(char *str, const std::size_t size)
|
||||
line.Remove(idx);
|
||||
|
||||
// tokenize run
|
||||
tokens = line.Tokenize(" \t");
|
||||
if (tokens->GetEntries() < 4) {
|
||||
std::vector<std::string> tokens = PStringUtils::Split(line.Data(), " \t");
|
||||
if (tokens.size() < 4) {
|
||||
std::cout << std::endl << "**ERROR**: Something is wrong with the RUN block header:";
|
||||
std::cout << std::endl << " >> " << str;
|
||||
std::cout << std::endl << " >> no <msr-file-out> is created";
|
||||
@@ -109,35 +107,22 @@ bool msr2msr_run(char *str, const std::size_t size)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tokens->GetEntries() == 5) { // already a new msr file, do only add the proper run comment
|
||||
if (tokens.size() == 5) { // already a new msr file, do only add the proper run comment
|
||||
snprintf(str, size, "%s (name beamline institute data-file-format)", line.Data());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (run.Contains("NEMU")) {
|
||||
ostr[0] = dynamic_cast<TObjString*>(tokens->At(1)); // file name
|
||||
snprintf(str, size, "RUN %s MUE4 PSI WKM (name beamline institute data-file-format)", ostr[0]->GetString().Data());
|
||||
snprintf(str, size, "RUN %s MUE4 PSI WKM (name beamline institute data-file-format)", tokens[1].c_str());
|
||||
} else if (run.Contains("PSI")) {
|
||||
ostr[0] = dynamic_cast<TObjString*>(tokens->At(1)); // file name
|
||||
ostr[1] = dynamic_cast<TObjString*>(tokens->At(2)); // beamline
|
||||
snprintf(str, size, "RUN %s %s PSI PSI-BIN (name beamline institute data-file-format)",
|
||||
ostr[0]->GetString().Data(), ostr[1]->GetString().Data());
|
||||
tokens[1].c_str(), tokens[2].c_str());
|
||||
} else if (run.Contains("TRIUMF")) {
|
||||
ostr[0] = dynamic_cast<TObjString*>(tokens->At(1)); // file name
|
||||
ostr[1] = dynamic_cast<TObjString*>(tokens->At(2)); // beamline
|
||||
snprintf(str, size, "RUN %s %s TRIUMF MUD (name beamline institute data-file-format)",
|
||||
ostr[0]->GetString().Data(), ostr[1]->GetString().Data());
|
||||
tokens[1].c_str(), tokens[2].c_str());
|
||||
} else if (run.Contains("RAL")) {
|
||||
ostr[0] = dynamic_cast<TObjString*>(tokens->At(1)); // file name
|
||||
ostr[1] = dynamic_cast<TObjString*>(tokens->At(2)); // beamline
|
||||
snprintf(str, size, "RUN %s %s RAL NEXUS (name beamline institute data-file-format)",
|
||||
ostr[0]->GetString().Data(), ostr[1]->GetString().Data());
|
||||
}
|
||||
|
||||
// clean up
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
tokens[1].c_str(), tokens[2].c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -165,38 +150,34 @@ bool msr2msr_param(char *str)
|
||||
|
||||
// handle parameter line
|
||||
TString line(str);
|
||||
TObjArray *tokens;
|
||||
TObjString *ostr[6];
|
||||
char sstr[256];
|
||||
char spaces[256];
|
||||
|
||||
tokens = line.Tokenize(" \t");
|
||||
Int_t noTokens = tokens->GetEntries();
|
||||
std::vector<std::string> tokens = PStringUtils::Split(line.Data(), " \t");
|
||||
std::size_t noTokens = tokens.size();
|
||||
if (noTokens == 4) {
|
||||
for (unsigned int i=0; i<4; i++)
|
||||
ostr[i] = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
// number
|
||||
snprintf(sstr, sizeof(sstr), "%10s", ostr[0]->GetString().Data());
|
||||
snprintf(sstr, sizeof(sstr), "%10s", tokens[0].c_str());
|
||||
// name
|
||||
strcat(sstr, " ");
|
||||
strcat(sstr, ostr[1]->GetString().Data());
|
||||
strcat(sstr, tokens[1].c_str());
|
||||
memset(spaces, 0, sizeof(spaces));
|
||||
memset(spaces, ' ', 12-strlen(ostr[1]->GetString().Data()));
|
||||
memset(spaces, ' ', 12-strlen(tokens[1].c_str()));
|
||||
strcat(sstr, spaces);
|
||||
// value
|
||||
strcat(sstr, ostr[2]->GetString().Data());
|
||||
if (strlen(ostr[2]->GetString().Data()) < 10) {
|
||||
strcat(sstr, tokens[2].c_str());
|
||||
if (strlen(tokens[2].c_str()) < 10) {
|
||||
memset(spaces, 0, sizeof(spaces));
|
||||
memset(spaces, ' ', 10-strlen(ostr[2]->GetString().Data()));
|
||||
memset(spaces, ' ', 10-strlen(tokens[2].c_str()));
|
||||
strcat(sstr, spaces);
|
||||
} else {
|
||||
strcat(sstr, " ");
|
||||
}
|
||||
// step
|
||||
strcat(sstr, ostr[3]->GetString().Data());
|
||||
if (strlen(ostr[3]->GetString().Data()) < 12) {
|
||||
strcat(sstr, tokens[3].c_str());
|
||||
if (strlen(tokens[3].c_str()) < 12) {
|
||||
memset(spaces, 0, sizeof(spaces));
|
||||
memset(spaces, ' ', 12-strlen(ostr[3]->GetString().Data()));
|
||||
memset(spaces, ' ', 12-strlen(tokens[3].c_str()));
|
||||
strcat(sstr, spaces);
|
||||
} else {
|
||||
strcat(sstr, " ");
|
||||
@@ -204,30 +185,28 @@ bool msr2msr_param(char *str)
|
||||
strcat(sstr, "none");
|
||||
strcpy(str, sstr);
|
||||
} else if (noTokens == 6) {
|
||||
for (unsigned int i=0; i<6; i++)
|
||||
ostr[i] = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
// number
|
||||
snprintf(sstr, sizeof(sstr), "%10s", ostr[0]->GetString().Data());
|
||||
snprintf(sstr, sizeof(sstr), "%10s", tokens[0].c_str());
|
||||
// name
|
||||
strcat(sstr, " ");
|
||||
strcat(sstr, ostr[1]->GetString().Data());
|
||||
strcat(sstr, tokens[1].c_str());
|
||||
memset(spaces, 0, sizeof(spaces));
|
||||
memset(spaces, ' ', 12-strlen(ostr[1]->GetString().Data()));
|
||||
memset(spaces, ' ', 12-strlen(tokens[1].c_str()));
|
||||
strcat(sstr, spaces);
|
||||
// value
|
||||
strcat(sstr, ostr[2]->GetString().Data());
|
||||
if (strlen(ostr[2]->GetString().Data()) < 10) {
|
||||
strcat(sstr, tokens[2].c_str());
|
||||
if (strlen(tokens[2].c_str()) < 10) {
|
||||
memset(spaces, 0, sizeof(spaces));
|
||||
memset(spaces, ' ', 10-strlen(ostr[2]->GetString().Data()));
|
||||
memset(spaces, ' ', 10-strlen(tokens[2].c_str()));
|
||||
strcat(sstr, spaces);
|
||||
} else {
|
||||
strcat(sstr, " ");
|
||||
}
|
||||
// step
|
||||
strcat(sstr, ostr[3]->GetString().Data());
|
||||
if (strlen(ostr[3]->GetString().Data()) < 12) {
|
||||
strcat(sstr, tokens[3].c_str());
|
||||
if (strlen(tokens[3].c_str()) < 12) {
|
||||
memset(spaces, 0, sizeof(spaces));
|
||||
memset(spaces, ' ', 12-strlen(ostr[3]->GetString().Data()));
|
||||
memset(spaces, ' ', 12-strlen(tokens[3].c_str()));
|
||||
strcat(sstr, spaces);
|
||||
} else {
|
||||
strcat(sstr, " ");
|
||||
@@ -235,25 +214,19 @@ bool msr2msr_param(char *str)
|
||||
// pos. error
|
||||
strcat(sstr, "none ");
|
||||
// lower boundary
|
||||
strcat(sstr, ostr[4]->GetString().Data());
|
||||
if (strlen(ostr[4]->GetString().Data()) < 8) {
|
||||
strcat(sstr, tokens[4].c_str());
|
||||
if (strlen(tokens[4].c_str()) < 8) {
|
||||
memset(spaces, 0, sizeof(spaces));
|
||||
memset(spaces, ' ', 8-strlen(ostr[4]->GetString().Data()));
|
||||
memset(spaces, ' ', 8-strlen(tokens[4].c_str()));
|
||||
strcat(sstr, spaces);
|
||||
} else {
|
||||
strcat(sstr, " ");
|
||||
}
|
||||
// upper boundary
|
||||
strcat(sstr, ostr[5]->GetString().Data());
|
||||
strcat(sstr, tokens[5].c_str());
|
||||
strcpy(str, sstr);
|
||||
}
|
||||
|
||||
// clean up
|
||||
if (tokens) {
|
||||
delete tokens;
|
||||
tokens = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -274,8 +247,7 @@ bool msr2msr_theory(char *str, int &tag, int &noOfAddionalParams)
|
||||
{
|
||||
// handle theory line
|
||||
TString line(str);
|
||||
TObjArray *tokens;
|
||||
TObjString *ostr;
|
||||
std::vector<std::string> tokens;
|
||||
char sstr[256];
|
||||
|
||||
if ((line.Contains("sktt") || line.Contains("statKTTab")) && line.Contains("glf")) { // static Gauss KT LF table
|
||||
@@ -283,8 +255,8 @@ bool msr2msr_theory(char *str, int &tag, int &noOfAddionalParams)
|
||||
strcpy(sstr, "statGssKTLF ");
|
||||
|
||||
// tokenize the rest and extract the first two parameters
|
||||
tokens = line.Tokenize(" \t");
|
||||
Int_t noTokens = tokens->GetEntries();
|
||||
tokens = PStringUtils::Split(line.Data(), " \t");
|
||||
std::size_t noTokens = tokens.size();
|
||||
if (noTokens < 3) {
|
||||
std::cout << std::endl << "**ERROR** in THEORY block";
|
||||
std::cout << std::endl << " Line: '" << str << "' is not a valid statKTTab statement.";
|
||||
@@ -293,8 +265,7 @@ bool msr2msr_theory(char *str, int &tag, int &noOfAddionalParams)
|
||||
}
|
||||
for (Int_t i=1; i<3; i++) {
|
||||
strcat(sstr, " ");
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
strcat(sstr, ostr->GetString().Data());
|
||||
strcat(sstr, tokens[i].c_str());
|
||||
}
|
||||
strcat(sstr, " (frequency damping)");
|
||||
strcpy(str, sstr);
|
||||
@@ -303,8 +274,8 @@ bool msr2msr_theory(char *str, int &tag, int &noOfAddionalParams)
|
||||
strcpy(sstr, "statExpKTLF ");
|
||||
|
||||
// tokenize the rest and extract the first two parameters
|
||||
tokens = line.Tokenize(" \t");
|
||||
Int_t noTokens = tokens->GetEntries();
|
||||
tokens = PStringUtils::Split(line.Data(), " \t");
|
||||
std::size_t noTokens = tokens.size();
|
||||
if (noTokens < 3) {
|
||||
std::cout << std::endl << "**ERROR** in THEORY block";
|
||||
std::cout << std::endl << " Line: '" << str << "' is not a valid statKTTab statement.";
|
||||
@@ -313,8 +284,7 @@ bool msr2msr_theory(char *str, int &tag, int &noOfAddionalParams)
|
||||
}
|
||||
for (Int_t i=1; i<3; i++) {
|
||||
strcat(sstr, " ");
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
strcat(sstr, ostr->GetString().Data());
|
||||
strcat(sstr, tokens[i].c_str());
|
||||
}
|
||||
strcat(sstr, " (frequency damping)");
|
||||
strcpy(str, sstr);
|
||||
@@ -323,8 +293,8 @@ bool msr2msr_theory(char *str, int &tag, int &noOfAddionalParams)
|
||||
strcpy(sstr, "dynGssKTLF ");
|
||||
|
||||
// tokenize the rest and extract the first three parameters
|
||||
tokens = line.Tokenize(" \t");
|
||||
Int_t noTokens = tokens->GetEntries();
|
||||
tokens = PStringUtils::Split(line.Data(), " \t");
|
||||
std::size_t noTokens = tokens.size();
|
||||
if (noTokens < 4) {
|
||||
std::cout << std::endl << "**ERROR** in THEORY block";
|
||||
std::cout << std::endl << " Line: '" << str << "' is not a valid dynmKTTab statement.";
|
||||
@@ -333,8 +303,7 @@ bool msr2msr_theory(char *str, int &tag, int &noOfAddionalParams)
|
||||
}
|
||||
for (Int_t i=1; i<4; i++) {
|
||||
strcat(sstr, " ");
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
strcat(sstr, ostr->GetString().Data());
|
||||
strcat(sstr, tokens[i].c_str());
|
||||
}
|
||||
strcat(sstr, " (frequency damping hopping-rate)");
|
||||
strcpy(str, sstr);
|
||||
@@ -343,8 +312,8 @@ bool msr2msr_theory(char *str, int &tag, int &noOfAddionalParams)
|
||||
strcpy(sstr, "dynExpKTLF ");
|
||||
|
||||
// tokenize the rest and extract the first three parameters
|
||||
tokens = line.Tokenize(" \t");
|
||||
Int_t noTokens = tokens->GetEntries();
|
||||
tokens = PStringUtils::Split(line.Data(), " \t");
|
||||
std::size_t noTokens = tokens.size();
|
||||
if (noTokens < 4) {
|
||||
std::cout << std::endl << "**ERROR** in THEORY block";
|
||||
std::cout << std::endl << " Line: '" << str << "' is not a valid dynmKTTab statement.";
|
||||
@@ -353,8 +322,7 @@ bool msr2msr_theory(char *str, int &tag, int &noOfAddionalParams)
|
||||
}
|
||||
for (Int_t i=1; i<4; i++) {
|
||||
strcat(sstr, " ");
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
strcat(sstr, ostr->GetString().Data());
|
||||
strcat(sstr, tokens[i].c_str());
|
||||
}
|
||||
strcat(sstr, " (frequency damping hopping-rate)");
|
||||
strcpy(str, sstr);
|
||||
@@ -366,8 +334,8 @@ bool msr2msr_theory(char *str, int &tag, int &noOfAddionalParams)
|
||||
strcpy(sstr, "internFld ");
|
||||
|
||||
// tokenize the rest and extract the first three parameters
|
||||
tokens = line.Tokenize(" \t");
|
||||
Int_t noTokens = tokens->GetEntries();
|
||||
tokens = PStringUtils::Split(line.Data(), " \t");
|
||||
std::size_t noTokens = tokens.size();
|
||||
if (noTokens < 4) {
|
||||
std::cout << std::endl << "**ERROR** in THEORY block";
|
||||
std::cout << std::endl << " Line: '" << str << "' is not a valid internFld statement.";
|
||||
@@ -377,8 +345,7 @@ bool msr2msr_theory(char *str, int &tag, int &noOfAddionalParams)
|
||||
strcat(sstr, " _x_");
|
||||
for (Int_t i=1; i<4; i++) {
|
||||
strcat(sstr, " ");
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
strcat(sstr, ostr->GetString().Data());
|
||||
strcat(sstr, tokens[i].c_str());
|
||||
}
|
||||
strcat(sstr, " (fraction phase frequency Trate Lrate)");
|
||||
strcpy(str, sstr);
|
||||
@@ -390,8 +357,8 @@ bool msr2msr_theory(char *str, int &tag, int &noOfAddionalParams)
|
||||
strcpy(sstr, "internBsl ");
|
||||
|
||||
// tokenize the rest and extract the first three parameters
|
||||
tokens = line.Tokenize(" \t");
|
||||
Int_t noTokens = tokens->GetEntries();
|
||||
tokens = PStringUtils::Split(line.Data(), " \t");
|
||||
std::size_t noTokens = tokens.size();
|
||||
if (noTokens < 4) {
|
||||
std::cout << std::endl << "**ERROR** in THEORY block";
|
||||
std::cout << std::endl << " Line: '" << str << "' is not a valid internBsl statement.";
|
||||
@@ -401,8 +368,7 @@ bool msr2msr_theory(char *str, int &tag, int &noOfAddionalParams)
|
||||
strcat(sstr, " _x_");
|
||||
for (Int_t i=1; i<4; i++) {
|
||||
strcat(sstr, " ");
|
||||
ostr = dynamic_cast<TObjString*>(tokens->At(i));
|
||||
strcat(sstr, ostr->GetString().Data());
|
||||
strcat(sstr, tokens[i].c_str());
|
||||
}
|
||||
strcat(sstr, " (fraction phase frequency Trate Lrate)");
|
||||
strcpy(str, sstr);
|
||||
|
||||
@@ -2046,7 +2046,7 @@ void PTextEdit::musrWiz()
|
||||
|
||||
// handle return status of musrWiz
|
||||
connect(proc, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||
[=](int exitCode, QProcess::ExitStatus exitStatus){ exitStatusMusrWiz(exitCode, exitStatus); });
|
||||
[=, this](int exitCode, QProcess::ExitStatus exitStatus){ exitStatusMusrWiz(exitCode, exitStatus); });
|
||||
|
||||
// make sure that the system environment variables are properly set
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
@@ -2761,7 +2761,7 @@ void PTextEdit::musrT0()
|
||||
proc->setWorkingDirectory(workDir);
|
||||
|
||||
connect(proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
[=](int exitCode, QProcess::ExitStatus exitStatus){ fileReload(); });
|
||||
[=, this](int exitCode, QProcess::ExitStatus exitStatus){ fileReload(); });
|
||||
|
||||
proc->start(cmd, arg);
|
||||
if (!proc->waitForStarted()) {
|
||||
@@ -2921,7 +2921,7 @@ void PTextEdit::musrSetSteps()
|
||||
|
||||
// handle return status of musrStep
|
||||
connect(proc, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||
[=](int exitCode, QProcess::ExitStatus exitStatus){ exitStatusMusrSetSteps(exitCode, exitStatus); });
|
||||
[=, this](int exitCode, QProcess::ExitStatus exitStatus){ exitStatusMusrSetSteps(exitCode, exitStatus); });
|
||||
|
||||
// make sure that the system environment variables are properly set
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
|
||||
@@ -2160,7 +2160,7 @@ void PTextEdit::musrWiz()
|
||||
|
||||
// handle return status of musrWiz
|
||||
connect(proc, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||
[=](int exitCode, QProcess::ExitStatus exitStatus){ exitStatusMusrWiz(exitCode, exitStatus); });
|
||||
[=, this](int exitCode, QProcess::ExitStatus exitStatus){ exitStatusMusrWiz(exitCode, exitStatus); });
|
||||
|
||||
// make sure that the system environment variables are properly set
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
@@ -2868,7 +2868,7 @@ void PTextEdit::musrT0()
|
||||
proc->setWorkingDirectory(workDir);
|
||||
|
||||
connect(proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
[=](int exitCode, QProcess::ExitStatus exitStatus){ fileReload(); });
|
||||
[=, this](int exitCode, QProcess::ExitStatus exitStatus){ fileReload(); });
|
||||
|
||||
proc->start(cmd, arg);
|
||||
if (!proc->waitForStarted()) {
|
||||
@@ -3022,7 +3022,7 @@ void PTextEdit::musrSetSteps()
|
||||
|
||||
// handle return status of musrStep
|
||||
connect(proc, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||
[=](int exitCode, QProcess::ExitStatus exitStatus){ exitStatusMusrSetSteps(exitCode, exitStatus); });
|
||||
[=, this](int exitCode, QProcess::ExitStatus exitStatus){ exitStatusMusrSetSteps(exitCode, exitStatus); });
|
||||
|
||||
// make sure that the system environment variables are properly set
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#------------------------------------------------------
|
||||
# CMakeLists.txt for strToNum
|
||||
#
|
||||
# little stand-alone test driver for the dependency-free
|
||||
# PStringUtils class (pure C++17, no ROOT needed).
|
||||
#
|
||||
# build (stand-alone):
|
||||
# cmake -S . -B build
|
||||
# cmake --build build
|
||||
# ./build/strToNum
|
||||
#
|
||||
# Andreas Suter, 2026/06/06
|
||||
#------------------------------------------------------
|
||||
cmake_minimum_required(VERSION 3.9)
|
||||
|
||||
project(strToNum VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
endif (NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
#--- the class under test lives in src/classes, its header in src/include -----
|
||||
set(MUSRFIT_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../classes)
|
||||
set(MUSRFIT_INC ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
|
||||
|
||||
add_executable(strToNum
|
||||
strToNum.cpp
|
||||
${MUSRFIT_SRC}/PStringUtils.cpp
|
||||
)
|
||||
|
||||
target_include_directories(strToNum
|
||||
PRIVATE ${MUSRFIT_INC}
|
||||
)
|
||||
@@ -0,0 +1,304 @@
|
||||
/***************************************************************************
|
||||
|
||||
strToNum.cpp
|
||||
|
||||
Author: Andreas Suter
|
||||
e-mail: andreas.suter@psi.ch
|
||||
|
||||
Little stand-alone test driver for the PStringUtils class. It exercises
|
||||
Split / IsInt / IsFloat / ToInt / ToDouble / IsEqualNoCase /
|
||||
ContainsNoCase / BeginsWithNoCase and reports a pass/fail summary.
|
||||
|
||||
Usage:
|
||||
strToNum -> run the built-in test suite
|
||||
strToNum <string> -> show what PStringUtils makes of the given
|
||||
string(s) on the command line (ad-hoc checks)
|
||||
strToNum -i -> interactive mode: type a string at the prompt
|
||||
and see the result of every PStringUtils method
|
||||
(empty line or 'quit' to leave)
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007-2026 by Andreas Suter *
|
||||
* andreas.suter@psi.ch *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "PStringUtils.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// tiny test bookkeeping
|
||||
//--------------------------------------------------------------------------
|
||||
static int gPassed = 0;
|
||||
static int gFailed = 0;
|
||||
|
||||
static void check(const std::string &what, bool ok)
|
||||
{
|
||||
if (ok) {
|
||||
++gPassed;
|
||||
std::cout << " [ ok ] " << what << std::endl;
|
||||
} else {
|
||||
++gFailed;
|
||||
std::cout << " [FAIL] " << what << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static std::string vecToStr(const std::vector<std::string> &v)
|
||||
{
|
||||
std::string s = "{";
|
||||
for (std::vector<std::string>::size_type i = 0; i < v.size(); ++i) {
|
||||
s += "'" + v[i] + "'";
|
||||
if (i + 1 < v.size())
|
||||
s += ", ";
|
||||
}
|
||||
s += "}";
|
||||
return s;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void testSplit()
|
||||
{
|
||||
std::cout << "Split:" << std::endl;
|
||||
|
||||
std::vector<std::string> r = PStringUtils::Split("alpha beta gamma", " ");
|
||||
std::cout << " input: 'alpha beta gamma', delim: ' '" << std::endl;
|
||||
check("3 tokens on single space delimiter",
|
||||
r.size() == 3 && r[0] == "alpha" && r[1] == "beta" && r[2] == "gamma");
|
||||
std::cout << "----" << std::endl;
|
||||
r = PStringUtils::Split(" , 1 , 2 ,, 3 ,", " ,");
|
||||
std::cout << " input: ' , 1 , 2 ,, 3 ,', delim: ' ,'" << std::endl;
|
||||
std::cout << " -> ";
|
||||
for (auto i: r)
|
||||
std::cout << i << ", ";
|
||||
std::cout << std::endl;
|
||||
check("mixed/repeated delimiters, empty tokens skipped",
|
||||
r.size() == 3 && r[0] == "1" && r[1] == "2" && r[2] == "3");
|
||||
std::cout << "----" << std::endl;
|
||||
|
||||
r = PStringUtils::Split("", " ");
|
||||
check("empty input -> no tokens", r.empty());
|
||||
|
||||
r = PStringUtils::Split(" ", " ");
|
||||
check("delimiters only -> no tokens", r.empty());
|
||||
|
||||
r = PStringUtils::Split("nodelim", ",;");
|
||||
check("no delimiter present -> single token",
|
||||
r.size() == 1 && r[0] == "nodelim");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void testIsInt()
|
||||
{
|
||||
std::cout << "IsInt:" << std::endl;
|
||||
|
||||
check("'12345' is int", PStringUtils::IsInt("12345"));
|
||||
check("' 42 ' (surrounding ws) is int", PStringUtils::IsInt(" 42 "));
|
||||
check("'-5' is int (negative)", PStringUtils::IsInt("-5"));
|
||||
check("'+42' is int (positive sign)", PStringUtils::IsInt("+42"));
|
||||
check("'' is not int", !PStringUtils::IsInt(""));
|
||||
check("' ' (ws only) is not int", !PStringUtils::IsInt(" "));
|
||||
check("'-' (sign only) is not int", !PStringUtils::IsInt("-"));
|
||||
check("'+-5' (double sign) is not int", !PStringUtils::IsInt("+-5"));
|
||||
check("'5-3' (sign after digit) is not int", !PStringUtils::IsInt("5-3"));
|
||||
check("'3.14' is not int", !PStringUtils::IsInt("3.14"));
|
||||
check("'12a' is not int", !PStringUtils::IsInt("12a"));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void testIsFloat()
|
||||
{
|
||||
std::cout << "IsFloat:" << std::endl;
|
||||
|
||||
check("'3.14' is float", PStringUtils::IsFloat("3.14"));
|
||||
check("'-1.2e-3' is float", PStringUtils::IsFloat("-1.2e-3"));
|
||||
check("'+42' is float", PStringUtils::IsFloat("+42"));
|
||||
check("'.5' is float", PStringUtils::IsFloat(".5"));
|
||||
check("' 6.022e23 ' (surrounding ws) is float",
|
||||
PStringUtils::IsFloat(" 6.022e23 "));
|
||||
check("'' is not float", !PStringUtils::IsFloat(""));
|
||||
check("'nan' is not float", !PStringUtils::IsFloat("nan"));
|
||||
check("'inf' is not float", !PStringUtils::IsFloat("inf"));
|
||||
check("'1.2.3' is not float", !PStringUtils::IsFloat("1.2.3"));
|
||||
check("'12abc' is not float", !PStringUtils::IsFloat("12abc"));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void testToInt()
|
||||
{
|
||||
std::cout << "ToInt:" << std::endl;
|
||||
|
||||
bool ok = false;
|
||||
check("'42' -> 42, ok", PStringUtils::ToInt("42", &ok) == 42 && ok);
|
||||
check("' -7' -> -7, ok", PStringUtils::ToInt(" -7", &ok) == -7 && ok);
|
||||
check("'123abc' -> 123, ok (trailing ignored)",
|
||||
PStringUtils::ToInt("123abc", &ok) == 123 && ok);
|
||||
check("'abc' -> 0, !ok", PStringUtils::ToInt("abc", &ok) == 0 && !ok);
|
||||
check("'' -> 0, !ok", PStringUtils::ToInt("", &ok) == 0 && !ok);
|
||||
check("'99999999999999999999' -> out of range, !ok",
|
||||
(PStringUtils::ToInt("99999999999999999999", &ok), !ok));
|
||||
check("null ok pointer is tolerated", PStringUtils::ToInt("17") == 17);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void testToDouble()
|
||||
{
|
||||
std::cout << "ToDouble:" << std::endl;
|
||||
|
||||
bool ok = false;
|
||||
check("'3.14' -> 3.14, ok",
|
||||
std::fabs(PStringUtils::ToDouble("3.14", &ok) - 3.14) < 1e-12 && ok);
|
||||
check("' +1.5e2' -> 150, ok",
|
||||
std::fabs(PStringUtils::ToDouble(" +1.5e2", &ok) - 150.0) < 1e-9 && ok);
|
||||
check("'2.5xyz' -> 2.5, ok (trailing ignored)",
|
||||
std::fabs(PStringUtils::ToDouble("2.5xyz", &ok) - 2.5) < 1e-12 && ok);
|
||||
check("'abc' -> 0.0, !ok", PStringUtils::ToDouble("abc", &ok) == 0.0 && !ok);
|
||||
check("'' -> 0.0, !ok", PStringUtils::ToDouble("", &ok) == 0.0 && !ok);
|
||||
check("'1e400' -> out of range, !ok",
|
||||
(PStringUtils::ToDouble("1e400", &ok), !ok));
|
||||
check("null ok pointer is tolerated",
|
||||
std::fabs(PStringUtils::ToDouble("0.25") - 0.25) < 1e-12);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void testCaseHelpers()
|
||||
{
|
||||
std::cout << "IsEqualNoCase / ContainsNoCase / BeginsWithNoCase:" << std::endl;
|
||||
|
||||
check("'Fit' == 'fIT' (no case)", PStringUtils::IsEqualNoCase("Fit", "fIT"));
|
||||
check("'Fit' != 'Fits'", !PStringUtils::IsEqualNoCase("Fit", "Fits"));
|
||||
check("'' == ''", PStringUtils::IsEqualNoCase("", ""));
|
||||
|
||||
check("'Hello World' contains 'LO WO' (no case)",
|
||||
PStringUtils::ContainsNoCase("Hello World", "LO WO"));
|
||||
check("empty needle is contained",
|
||||
PStringUtils::ContainsNoCase("abc", ""));
|
||||
check("needle longer than haystack is not contained",
|
||||
!PStringUtils::ContainsNoCase("ab", "abc"));
|
||||
|
||||
check("'THEORY' begins with 'the' (no case)",
|
||||
PStringUtils::BeginsWithNoCase("THEORY", "the"));
|
||||
check("'THEORY' does not begin with 'ory'",
|
||||
!PStringUtils::BeginsWithNoCase("THEORY", "ory"));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void inspect(const std::string &str)
|
||||
{
|
||||
std::cout << "Inspecting '" << str << "':" << std::endl;
|
||||
std::cout << " Split(' \\t,;') = "
|
||||
<< vecToStr(PStringUtils::Split(str, " \t,;")) << std::endl;
|
||||
std::cout << " IsInt = " << (PStringUtils::IsInt(str) ? "true" : "false") << std::endl;
|
||||
std::cout << " IsFloat = " << (PStringUtils::IsFloat(str) ? "true" : "false") << std::endl;
|
||||
|
||||
bool ok = false;
|
||||
int i = PStringUtils::ToInt(str, &ok);
|
||||
std::cout << " ToInt = " << i << " (ok=" << (ok ? "true" : "false") << ")" << std::endl;
|
||||
double d = PStringUtils::ToDouble(str, &ok);
|
||||
std::cout << " ToDouble = " << d << " (ok=" << (ok ? "true" : "false") << ")" << std::endl;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void usage(const char *prog)
|
||||
{
|
||||
std::cout
|
||||
<< "usage: " << prog << " [options] [string ...]\n"
|
||||
<< "\n"
|
||||
<< "Little stand-alone test driver for the PStringUtils class. It exercises\n"
|
||||
<< "Split / IsInt / IsFloat / ToInt / ToDouble / IsEqualNoCase /\n"
|
||||
<< "ContainsNoCase / BeginsWithNoCase.\n"
|
||||
<< "\n"
|
||||
<< "options:\n"
|
||||
<< " -h, --help show this help and exit\n"
|
||||
<< " -i, --interactive interactive mode: type a string at the prompt and\n"
|
||||
<< " see the result of every PStringUtils method\n"
|
||||
<< " (empty line, 'quit'/'exit' or Ctrl-D leaves)\n"
|
||||
<< "\n"
|
||||
<< "arguments:\n"
|
||||
<< " string ... one or more strings to inspect; the result of every\n"
|
||||
<< " PStringUtils method is printed for each of them\n"
|
||||
<< "\n"
|
||||
<< "with no options and no arguments the built-in test suite is run; the exit\n"
|
||||
<< "code is 0 if all checks pass and 1 otherwise.\n"
|
||||
<< "\n"
|
||||
<< "examples:\n"
|
||||
<< " " << prog << " run the built-in test suite\n"
|
||||
<< " " << prog << " \" -42xyz\" 1.5e-3 inspect the given strings\n"
|
||||
<< " " << prog << " -i interactive mode\n";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void interactive()
|
||||
{
|
||||
std::cout << "==== PStringUtils interactive mode ====" << std::endl;
|
||||
std::cout << "Enter a string to test the methods on it." << std::endl;
|
||||
std::cout << "An empty line or 'quit' leaves." << std::endl << std::endl;
|
||||
|
||||
std::string line;
|
||||
while (true) {
|
||||
std::cout << "strToNum> " << std::flush;
|
||||
if (!std::getline(std::cin, line)) // EOF (e.g. Ctrl-D)
|
||||
break;
|
||||
if (line.empty() || line == "quit" || line == "exit")
|
||||
break;
|
||||
inspect(line);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc > 1) {
|
||||
const std::string arg1 = argv[1];
|
||||
if (arg1 == "-h" || arg1 == "--help") {
|
||||
usage(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
if (arg1 == "-i" || arg1 == "--interactive") {
|
||||
interactive();
|
||||
return 0;
|
||||
}
|
||||
// ad-hoc mode: inspect the strings given on the command line
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
inspect(argv[i]);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::cout << "==== PStringUtils test suite ====" << std::endl << std::endl;
|
||||
|
||||
testSplit();
|
||||
testIsInt();
|
||||
testIsFloat();
|
||||
testToInt();
|
||||
testToDouble();
|
||||
testCaseHelpers();
|
||||
|
||||
std::cout << std::endl
|
||||
<< "==== summary: " << gPassed << " passed, "
|
||||
<< gFailed << " failed ====" << std::endl;
|
||||
|
||||
return (gFailed == 0) ? 0 : 1;
|
||||
}
|
||||
Reference in New Issue
Block a user