156 lines
6.5 KiB
C++
156 lines
6.5 KiB
C++
/***************************************************************************
|
|
|
|
PUserFcnBase.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 <vector>
|
|
#include <fstream>
|
|
|
|
#include "PUserFcnBase.h"
|
|
|
|
ClassImp(PUserFcnBase)
|
|
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief Parses an XML file using buffer-based parsing for better compatibility.
|
|
*
|
|
* This function provides a replacement for TSAXParser::ParseFile() that works
|
|
* reliably across different environments. Some systems have issues with direct
|
|
* file parsing, but buffer-based parsing (ParseBuffer) works consistently.
|
|
*
|
|
* \section parsexml_usage Usage in User Functions
|
|
*
|
|
* User functions that need to read XML configuration files should use this
|
|
* function instead of TSAXParser::ParseFile():
|
|
*
|
|
* \code{.cpp}
|
|
* class TMyConfigurableFcn : public PUserFcnBase {
|
|
* private:
|
|
* MyConfigHandler fHandler; // Derived from TSAXParser callbacks
|
|
*
|
|
* public:
|
|
* Bool_t LoadConfig(const char* configFile) {
|
|
* TSAXParser parser;
|
|
* parser.ConnectToHandler("MyConfigHandler", &fHandler);
|
|
*
|
|
* Int_t status = parseXmlFile(&parser, configFile);
|
|
* if (status != 0) {
|
|
* std::cerr << "Failed to parse config: " << configFile << std::endl;
|
|
* return false;
|
|
* }
|
|
* return true;
|
|
* }
|
|
* };
|
|
* \endcode
|
|
*
|
|
* \section parsexml_algorithm Algorithm
|
|
*
|
|
* 1. Opens the file in binary mode, seeking to end
|
|
* 2. Determines file size from stream position
|
|
* 3. Allocates buffer and reads entire file
|
|
* 4. Passes buffer to TSAXParser::ParseBuffer()
|
|
* 5. Cleans up buffer memory
|
|
*
|
|
* \param saxParser Pointer to a configured TSAXParser object. The parser
|
|
* should have its handler connected before calling this function.
|
|
* \param startup_path_name Full filesystem path to the XML file to parse.
|
|
*
|
|
* \return Status code:
|
|
* - 0: Success - file parsed without errors
|
|
* - 1: File error - could not open or read the file
|
|
* - >1: XML parse error from TSAXParser::ParseBuffer()
|
|
*
|
|
* \see PStartupHandler for an example of XML parsing in musrfit
|
|
* \see TSAXParser for ROOT's SAX parser documentation
|
|
*/
|
|
Int_t parseXmlFile(TSAXParser *saxParser, const char *startup_path_name)
|
|
{
|
|
Int_t status;
|
|
std::fstream xmlFile;
|
|
UInt_t xmlSize = 0;
|
|
Char_t *xmlBuffer = nullptr;
|
|
|
|
xmlFile.open(startup_path_name, std::ios::in | std::ios::ate); // open file for reading and go to the end of the file
|
|
if (xmlFile.is_open()) { // check if file has been opened successfully
|
|
xmlSize = xmlFile.tellg(); // get the position within the stream == size of the file (since we are at the end)
|
|
xmlFile.seekg(0, std::ios::beg); // go back to the beginning of the stream
|
|
xmlBuffer = new Char_t[xmlSize]; // allocate buffer memory for the whole XML file
|
|
xmlFile.read(xmlBuffer, xmlSize); // read in the whole XML file into the buffer
|
|
xmlFile.close(); // close the XML file
|
|
}
|
|
if (!xmlBuffer) { // file has not been read into the buffer
|
|
status = 1;
|
|
} else {
|
|
status = saxParser->ParseBuffer(xmlBuffer, xmlSize); // parse buffer
|
|
delete[] xmlBuffer; // free the buffer memory
|
|
xmlBuffer = nullptr;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief Global storage for user function objects requiring persistent state.
|
|
*
|
|
* This vector provides a global container for user functions that need to
|
|
* maintain state across multiple evaluations or share data between runs.
|
|
* It is primarily used by user functions implementing the "global part"
|
|
* interface (NeedGlobalPart(), SetGlobalPart(), GlobalPartIsValid()).
|
|
*
|
|
* \section gGlobalUserFcn_usage Usage Pattern
|
|
*
|
|
* User functions with expensive initialization (lookup tables, precomputed
|
|
* grids, loaded data files) store their global objects here:
|
|
*
|
|
* \code{.cpp}
|
|
* // In user function's SetGlobalPart implementation:
|
|
* void TMyFcn::SetGlobalPart(std::vector<void*> &globalPart, UInt_t idx) {
|
|
* if (idx < globalPart.size() && globalPart[idx] != nullptr) {
|
|
* fGlobal = static_cast<MyGlobalData*>(globalPart[idx]);
|
|
* } else {
|
|
* fGlobal = new MyGlobalData();
|
|
* fGlobal->Initialize(); // Expensive one-time computation
|
|
* if (idx < globalPart.size())
|
|
* globalPart[idx] = fGlobal;
|
|
* else
|
|
* globalPart.push_back(fGlobal);
|
|
* }
|
|
* }
|
|
* \endcode
|
|
*
|
|
* \note The vector stores void pointers, so user functions must cast
|
|
* appropriately and manage memory for their specific data types.
|
|
*
|
|
* \warning User functions are responsible for proper cleanup of their
|
|
* global objects to avoid memory leaks.
|
|
*
|
|
* \see PUserFcnBase::SetGlobalPart() for the interface to populate this vector
|
|
* \see PTheory for how global parts are initialized during theory setup
|
|
*/
|
|
std::vector<void *> gGlobalUserFcn;
|