diff --git a/src/constants/meson.build b/src/constants/meson.build new file mode 100644 index 0000000..a955c7e --- /dev/null +++ b/src/constants/meson.build @@ -0,0 +1,24 @@ +# Define the library +const_sources = files( + 'private/const.cpp', +) + +const_headers = files( + 'public/const.h' +) + +# Define the libconst library so it can be linked against by other parts of the build system +libconst = library('const', + const_sources, + include_directories: include_directories('public'), + cpp_args: ['-fvisibility=default'], + dependencies: [const_data_dep], + install : true) + +const_dep = declare_dependency( + include_directories: include_directories('public'), + link_with: libconst, +) + +# Make headers accessible +install_headers(const_headers, subdir : '4DSSE/const') \ No newline at end of file diff --git a/src/constants/private/const.cpp b/src/constants/private/const.cpp new file mode 100644 index 0000000..ce38681 --- /dev/null +++ b/src/constants/private/const.cpp @@ -0,0 +1,126 @@ +/* *********************************************************************** +// +// Copyright (C) 2025 -- The 4D-STAR Collaboration +// File Author: Emily Boudreaux +// Last Modified: March 17, 2025 +// +// 4DSSE is free software; you can use it and/or modify +// it under the terms and restrictions the GNU General Library Public +// License version 3 (GPLv3) as published by the Free Software Foundation. +// +// 4DSSE 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 Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this software; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// *********************************************************************** */ +#include +#include +#include +#include +#include +#include +#include + + +#include "const.h" +#include "embedded_constants.h" // Generated at build time by meson + +namespace serif::constant { + Constants::Constants() { + loaded_ = initialize(); + } + + bool Constants::initialize() { + return load(); + } + + Constant Constants::get(const std::string& name) const { + auto it = constants_.find(name); + if (it != constants_.end()) { + return it->second; + } else { + throw std::out_of_range("Constant '" + name + "' not found."); + } + } + + Constant Constants::operator[](const std::string& name) const { + return this->get(name); + } + + bool Constants::has(const std::string& name) const { + return constants_.find(name) != constants_.end(); + } + + std::set Constants::keys() const { + std::set keys; + for (const auto& pair : constants_) { + keys.insert(pair.first); + } + return keys; + } + + std::string Constants::trim(const std::string& str) { + size_t first = str.find_first_not_of(" \t"); + if (first == std::string::npos) return ""; + size_t last = str.find_last_not_of(" \t"); + return str.substr(first, last - first + 1); + } + + bool Constants::load() { + std::istringstream fileStream(embeddedConstants); + + std::string line; + bool data_section = false; + int line_count = 0; + + while (std::getline(fileStream, line)) { + line_count++; + + // Detect start of data section (double divider line) + if (!data_section) { + if (line.find("Symbol") != std::string::npos) { // Find header row + std::getline(fileStream, line); // Skip dashed divider + std::getline(fileStream, line); // Skip second dashed divider + data_section = true; + } + continue; + } + + // Ensure the line is long enough to contain all fields + if (line.length() < 125) continue; + + // Define exact column widths from Python script + int start = 0; + + const std::string symbol = trim(line.substr(start, col_widths_[0])); start += col_widths_[0]; + const std::string name = trim(line.substr(start, col_widths_[1])); start += col_widths_[1]; + const std::string valueStr = line.substr(start, col_widths_[2]); start += col_widths_[2]; + const std::string unit = trim(line.substr(start, col_widths_[3])); start += col_widths_[3]; // Only trim the unit + const std::string uncertaintyStr = line.substr(start, col_widths_[4]); start += col_widths_[4]; + const std::string reference = trim(line.substr(start, col_widths_[5])); // Only trim reference + + // Convert numerical fields safely + double value = 0.0, uncertainty = 0.0; + try { + value = std::stod(valueStr); + } catch (...) { + std::cerr << "Warning: Invalid value in line " << line_count << ": " << valueStr << std::endl; + } + try { + uncertainty = std::stod(uncertaintyStr); + } catch (...) { + std::cerr << "Warning: Invalid uncertainty in line " << line_count << ": " << uncertaintyStr << std::endl; + } + + // Store in map + constants_.emplace(symbol, Constant{name, value, uncertainty, unit, reference}); + } + loaded_ = true; + return true; + } +} \ No newline at end of file diff --git a/src/constants/public/const.h b/src/constants/public/const.h new file mode 100644 index 0000000..910e851 --- /dev/null +++ b/src/constants/public/const.h @@ -0,0 +1,141 @@ +/* *********************************************************************** +// +// Copyright (C) 2025 -- The 4D-STAR Collaboration +// File Author: Emily Boudreaux +// Last Modified: March 17, 2025 +// +// 4DSSE is free software; you can use it and/or modify +// it under the terms and restrictions the GNU General Library Public +// License version 3 (GPLv3) as published by the Free Software Foundation. +// +// 4DSSE 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 Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this software; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// *********************************************************************** */ +#pragma once +#include +#include +#include +#include + +namespace serif::constant { +/** + * @brief Structure to hold a constant's details. + */ +struct Constant { + const std::string name; ///< Name of the constant + const double value; ///< Value of the constant + const double uncertainty; ///< Uncertainty in the constant's value + const std::string unit; ///< Unit of the constant + const std::string reference; ///< Reference for the constant's value + + /** + * @brief Parameterized constructor. + * @param name The name of the constant. + * @param value The value of the constant. + * @param uncertainty The uncertainty in the constant's value. + * @param unit The unit of the constant. + * @param reference The reference for the constant's value. + */ + Constant(const std::string& name, const double value, const double uncertainty, const std::string& unit, const std::string& reference) + : name(name), value(value), uncertainty(uncertainty), unit(unit), reference(reference) {} + + /** + * @brief overload the << operator for pretty printing + */ + friend std::ostream& operator<<(std::ostream& os, const Constant& c) { + os << "<" << c.name << ": "; + os << c.value << "±" << c.uncertainty << " "; + os << c.unit << " (" << c.reference << ")>\n"; + return os; + } +}; + +/** + * @brief Class to manage a collection of constants. + */ +class Constants { +private: + bool loaded_ = false; ///< Flag to indicate if constants are loaded + const int col_widths_[6] = {25, 52, 20, 20, 17, 45}; // From the python script used to generate the constants file + std::map constants_; ///< Map to store constants by name + + /** + * @brief Default constructor. Private to avoid direct instantiation + */ + Constants(); + + /** + * @brief Load constants from the embedded header file. + * @return True if loading was successful, false otherwise. + */ + bool load(); + + /** + * @brief Initialize constants. + * @return True if initialization was successful, false otherwise. + */ + bool initialize(); + + /** + * @brief Trim leading and trailing whitespace from a string. + * @param str The string to trim. + * @return The trimmed string. + */ + std::string trim(const std::string& str); + +public: + + /** + * @brief get instance of constants singleton + * @return instance of constants + */ + static Constants& getInstance() { + static Constants instance; + return instance; + } + + /** + * @brief Check if constants are loaded. + * @return True if constants are loaded, false otherwise. + */ + bool isLoaded() const { return loaded_; } + + /** + * @brief Get a constant by key. + * @param key The name of the constant to retrieve. + * @return The constant associated with the given key. + */ + Constant get(const std::string& key) const; + + /** + * @brief Overloaded subscript operator to access constants by key. + * @param key The name of the constant to retrieve. + * @return The constant associated with the given key. + * @throws std::out_of_range if the key is not found. + */ + Constant operator[](const std::string& key) const; + + /** + * @brief Check if a constant exists by key. + * @param key The name of the constant to check. + * @return True if the constant exists, false otherwise. + */ + bool has(const std::string& key) const; + + /** + * @brief Get a list of all constant keys. + * @return A vector of all constant keys. + */ + std::set keys() const; + +}; + +} // namespace serif::const +