Merge pull request #7 from tboudreaux/feature/constGlobal
Feature/const global
This commit is contained in:
@@ -12,6 +12,7 @@ libconst = library('const',
|
|||||||
const_sources,
|
const_sources,
|
||||||
include_directories: include_directories('public'),
|
include_directories: include_directories('public'),
|
||||||
cpp_args: ['-fvisibility=default'],
|
cpp_args: ['-fvisibility=default'],
|
||||||
|
dependencies: [const_dep],
|
||||||
install : true)
|
install : true)
|
||||||
|
|
||||||
# Make headers accessible
|
# Make headers accessible
|
||||||
|
|||||||
@@ -3,27 +3,22 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
|
||||||
#include "const.h"
|
#include "const.h"
|
||||||
|
#include "embedded_constants.h" // Generated at build time by meson
|
||||||
|
|
||||||
constants::constants() {
|
Constants::Constants() {
|
||||||
loaded_ = false;
|
loaded_ = initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
constants::constants(const std::string& filename) {
|
bool Constants::initialize() {
|
||||||
loaded_ = initialize(filename);
|
return load();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool constants::initialize(const std::string& filename) {
|
Constant Constants::get(const std::string& name) const {
|
||||||
return load(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
constant constants::get(const std::string& name) {
|
|
||||||
return constants_[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
constant constants::operator[](const std::string& name) const {
|
|
||||||
auto it = constants_.find(name);
|
auto it = constants_.find(name);
|
||||||
if (it != constants_.end()) {
|
if (it != constants_.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
@@ -32,11 +27,15 @@ constant constants::operator[](const std::string& name) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool constants::has(const std::string& name) const {
|
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();
|
return constants_.find(name) != constants_.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::string> constants::keys() const {
|
std::set<std::string> Constants::keys() const {
|
||||||
std::set<std::string> keys;
|
std::set<std::string> keys;
|
||||||
for (const auto& pair : constants_) {
|
for (const auto& pair : constants_) {
|
||||||
keys.insert(pair.first);
|
keys.insert(pair.first);
|
||||||
@@ -44,32 +43,28 @@ std::set<std::string> constants::keys() const {
|
|||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string constants::trim(const std::string& str) {
|
std::string Constants::trim(const std::string& str) {
|
||||||
size_t first = str.find_first_not_of(" \t");
|
size_t first = str.find_first_not_of(" \t");
|
||||||
if (first == std::string::npos) return "";
|
if (first == std::string::npos) return "";
|
||||||
size_t last = str.find_last_not_of(" \t");
|
size_t last = str.find_last_not_of(" \t");
|
||||||
return str.substr(first, last - first + 1);
|
return str.substr(first, last - first + 1);
|
||||||
}
|
}
|
||||||
bool constants::load(const std::string& filename) {
|
|
||||||
std::ifstream file(filename);
|
bool Constants::load() {
|
||||||
std::map<std::string, constant> constants_temp;
|
std::istringstream fileStream(embeddedConstants);
|
||||||
if (!file.is_open()) {
|
|
||||||
std::cerr << "Error: Unable to open file " << filename << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string line;
|
std::string line;
|
||||||
bool data_section = false;
|
bool data_section = false;
|
||||||
int line_count = 0;
|
int line_count = 0;
|
||||||
|
|
||||||
while (std::getline(file, line)) {
|
while (std::getline(fileStream, line)) {
|
||||||
line_count++;
|
line_count++;
|
||||||
|
|
||||||
// Detect start of data section (double divider line)
|
// Detect start of data section (double divider line)
|
||||||
if (!data_section) {
|
if (!data_section) {
|
||||||
if (line.find("Symbol") != std::string::npos) { // Find header row
|
if (line.find("Symbol") != std::string::npos) { // Find header row
|
||||||
std::getline(file, line); // Skip dashed divider
|
std::getline(fileStream, line); // Skip dashed divider
|
||||||
std::getline(file, line); // Skip second dashed divider
|
std::getline(fileStream, line); // Skip second dashed divider
|
||||||
data_section = true;
|
data_section = true;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -81,12 +76,12 @@ bool constants::load(const std::string& filename) {
|
|||||||
// Define exact column widths from Python script
|
// Define exact column widths from Python script
|
||||||
int start = 0;
|
int start = 0;
|
||||||
|
|
||||||
std::string symbol = trim(line.substr(start, col_widths_[0])); start += col_widths_[0];
|
const std::string symbol = trim(line.substr(start, col_widths_[0])); start += col_widths_[0];
|
||||||
std::string name = trim(line.substr(start, col_widths_[1])); start += col_widths_[1];
|
const std::string name = trim(line.substr(start, col_widths_[1])); start += col_widths_[1];
|
||||||
std::string valueStr = line.substr(start, col_widths_[2]); start += col_widths_[2];
|
const std::string valueStr = line.substr(start, col_widths_[2]); start += col_widths_[2];
|
||||||
std::string unit = trim(line.substr(start, col_widths_[3])); start += col_widths_[3]; // Only trim the unit
|
const std::string unit = trim(line.substr(start, col_widths_[3])); start += col_widths_[3]; // Only trim the unit
|
||||||
std::string uncertaintyStr = line.substr(start, col_widths_[4]); start += col_widths_[4];
|
const std::string uncertaintyStr = line.substr(start, col_widths_[4]); start += col_widths_[4];
|
||||||
std::string reference = trim(line.substr(start, col_widths_[5])); // Only trim reference
|
const std::string reference = trim(line.substr(start, col_widths_[5])); // Only trim reference
|
||||||
|
|
||||||
// Convert numerical fields safely
|
// Convert numerical fields safely
|
||||||
double value = 0.0, uncertainty = 0.0;
|
double value = 0.0, uncertainty = 0.0;
|
||||||
@@ -102,11 +97,8 @@ bool constants::load(const std::string& filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store in map
|
// Store in map
|
||||||
constants_temp[symbol] = {name, value, uncertainty, unit, reference};
|
constants_.emplace(symbol, Constant{name, value, uncertainty, unit, reference});
|
||||||
}
|
}
|
||||||
|
|
||||||
file.close();
|
|
||||||
constants_ = constants_temp;
|
|
||||||
loaded_ = true;
|
loaded_ = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,17 +10,28 @@
|
|||||||
/**
|
/**
|
||||||
* @brief Structure to hold a constant's details.
|
* @brief Structure to hold a constant's details.
|
||||||
*/
|
*/
|
||||||
struct constant {
|
struct Constant {
|
||||||
std::string name; ///< Name of the constant
|
const std::string name; ///< Name of the constant
|
||||||
double value; ///< Value of the constant
|
const double value; ///< Value of the constant
|
||||||
double uncertainty; ///< Uncertainty in the constant's value
|
const double uncertainty; ///< Uncertainty in the constant's value
|
||||||
std::string unit; ///< Unit of the constant
|
const std::string unit; ///< Unit of the constant
|
||||||
std::string reference; ///< Reference for the constant's value
|
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
|
* @brief overload the << operator for pretty printing
|
||||||
*/
|
*/
|
||||||
friend std::ostream& operator<<(std::ostream& os, const constant& c) {
|
friend std::ostream& operator<<(std::ostream& os, const Constant& c) {
|
||||||
os << "<" << c.name << ": ";
|
os << "<" << c.name << ": ";
|
||||||
os << c.value << "±" << c.uncertainty << " ";
|
os << c.value << "±" << c.uncertainty << " ";
|
||||||
os << c.unit << " (" << c.reference << ")>\n";
|
os << c.unit << " (" << c.reference << ")>\n";
|
||||||
@@ -31,18 +42,28 @@ struct constant {
|
|||||||
/**
|
/**
|
||||||
* @brief Class to manage a collection of constants.
|
* @brief Class to manage a collection of constants.
|
||||||
*/
|
*/
|
||||||
class constants {
|
class Constants {
|
||||||
private:
|
private:
|
||||||
bool loaded_ = false; ///< Flag to indicate if constants are loaded
|
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
|
const int col_widths_[6] = {25, 52, 20, 20, 17, 45}; // From the python script used to generate the constants file
|
||||||
std::map<std::string, constant> constants_; ///< Map to store constants by name
|
std::map<std::string, Constant> constants_; ///< Map to store constants by name
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Load constants from a file.
|
* @brief Default constructor. Private to avoid direct instantiation
|
||||||
* @param filename The name of the file to load constants from.
|
*/
|
||||||
|
Constants();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load constants from the embedded header file.
|
||||||
* @return True if loading was successful, false otherwise.
|
* @return True if loading was successful, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool load(const std::string& filename);
|
bool load();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize constants.
|
||||||
|
* @return True if initialization was successful, false otherwise.
|
||||||
|
*/
|
||||||
|
bool initialize();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Trim leading and trailing whitespace from a string.
|
* @brief Trim leading and trailing whitespace from a string.
|
||||||
@@ -52,36 +73,28 @@ private:
|
|||||||
std::string trim(const std::string& str);
|
std::string trim(const std::string& str);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
* @brief Default constructor.
|
|
||||||
*/
|
|
||||||
constants();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Constructor that initializes constants from a file.
|
* @brief get instance of constants singelton
|
||||||
* @param filename The name of the file to load constants from.
|
* @return instance of constants
|
||||||
*/
|
*/
|
||||||
constants(const std::string& filename);
|
static Constants& getInstance() {
|
||||||
|
static Constants instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if constants are loaded.
|
* @brief Check if constants are loaded.
|
||||||
* @return True if constants are loaded, false otherwise.
|
* @return True if constants are loaded, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool is_loaded() { return loaded_; }
|
bool isLoaded() { return loaded_; }
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initialize constants from a file.
|
|
||||||
* @param filename The name of the file to load constants from.
|
|
||||||
* @return True if initialization was successful, false otherwise.
|
|
||||||
*/
|
|
||||||
bool initialize(const std::string& filename);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get a constant by key.
|
* @brief Get a constant by key.
|
||||||
* @param key The name of the constant to retrieve.
|
* @param key The name of the constant to retrieve.
|
||||||
* @return The constant associated with the given key.
|
* @return The constant associated with the given key.
|
||||||
*/
|
*/
|
||||||
constant get(const std::string& key);
|
Constant get(const std::string& key) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Overloaded subscript operator to access constants by key.
|
* @brief Overloaded subscript operator to access constants by key.
|
||||||
@@ -89,7 +102,7 @@ public:
|
|||||||
* @return The constant associated with the given key.
|
* @return The constant associated with the given key.
|
||||||
* @throws std::out_of_range if the key is not found.
|
* @throws std::out_of_range if the key is not found.
|
||||||
*/
|
*/
|
||||||
constant operator[](const std::string& key) const;
|
Constant operator[](const std::string& key) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if a constant exists by key.
|
* @brief Check if a constant exists by key.
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
|
# Build resources first so that all the embedded resources are available to the other targets
|
||||||
|
subdir('resources')
|
||||||
|
|
||||||
|
# Build the main source code
|
||||||
subdir('dobj')
|
subdir('dobj')
|
||||||
subdir('const')
|
subdir('const')
|
||||||
10
src/resources/const/format.sh
Executable file
10
src/resources/const/format.sh
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
if [ "$#" -ne 2 ]; then
|
||||||
|
echo "Usage: $0 <input_file> <output_file>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
input_file="$1"
|
||||||
|
output_file="$2"
|
||||||
|
printf 'const char embeddedConstants[] = R"(' > "$output_file"
|
||||||
|
cat "$input_file" >> "$output_file"
|
||||||
|
printf ')";\n' >> "$output_file"
|
||||||
20
src/resources/const/meson.build
Normal file
20
src/resources/const/meson.build
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
data_file = files('const.dat')
|
||||||
|
command_file = files('format.sh')
|
||||||
|
output_file = meson.current_build_dir() + '/embedded_constants.h'
|
||||||
|
message('Data file absolute path: ' + data_file[0].full_path())
|
||||||
|
message('Meson source directory: ' + meson.current_source_dir())
|
||||||
|
message('Meson build directory: ' + meson.current_build_dir())
|
||||||
|
|
||||||
|
embedded_constants_h = custom_target('embed_constants',
|
||||||
|
input: data_file,
|
||||||
|
output: 'embedded_constants.h',
|
||||||
|
command: ['sh', '-c', command_file[0].full_path()+' @INPUT@ ' + output_file, '@INPUT@', '@OUTPUT@']
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure the generated header is included
|
||||||
|
const_header = include_directories('.')
|
||||||
|
|
||||||
|
const_dep = declare_dependency(
|
||||||
|
include_directories: const_header,
|
||||||
|
sources: embedded_constants_h
|
||||||
|
)
|
||||||
1
src/resources/meson.build
Normal file
1
src/resources/meson.build
Normal file
@@ -0,0 +1 @@
|
|||||||
|
subdir('const')
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
std::string RELATIVE_PATH = "../src/resources/const/const.dat";
|
|
||||||
/**
|
/**
|
||||||
* @file constTest.cpp
|
* @file constTest.cpp
|
||||||
* @brief Unit tests for the const class.
|
* @brief Unit tests for the const class.
|
||||||
@@ -17,12 +16,8 @@ std::string RELATIVE_PATH = "../src/resources/const/const.dat";
|
|||||||
*/
|
*/
|
||||||
class constTest : public ::testing::Test {
|
class constTest : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
constants physicalConstants;
|
|
||||||
constants initializedConstants;
|
|
||||||
|
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
// Create a DObject with initial data and metadata
|
Constants::getInstance();
|
||||||
constants initializedConstants(RELATIVE_PATH);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -30,23 +25,22 @@ protected:
|
|||||||
* @test Verify default constructor initializes correctly.
|
* @test Verify default constructor initializes correctly.
|
||||||
*/
|
*/
|
||||||
TEST_F(constTest, DefaultConstructor) {
|
TEST_F(constTest, DefaultConstructor) {
|
||||||
EXPECT_NO_THROW(constants());
|
EXPECT_NO_THROW(Constants::getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @test Verify constructor initializes with provided data and metadata.
|
* @test Verify constructor initializes with provided data and metadata.
|
||||||
*/
|
*/
|
||||||
TEST_F(constTest, ParameterizedConstructor) {
|
TEST_F(constTest, isLoaded) {
|
||||||
constants obj(RELATIVE_PATH);
|
|
||||||
|
|
||||||
EXPECT_NO_THROW(obj.is_loaded());
|
EXPECT_NO_THROW(Constants::getInstance().isLoaded());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @test Verify get method returns the correct constant.
|
* @test Verify get method returns the correct constant.
|
||||||
*/
|
*/
|
||||||
TEST_F(constTest, Get) {
|
TEST_F(constTest, GetMethod) {
|
||||||
constants obj(RELATIVE_PATH);
|
Constants& obj = Constants::getInstance();
|
||||||
EXPECT_DOUBLE_EQ(obj.get("c").value, 2.99792458e10);
|
EXPECT_DOUBLE_EQ(obj.get("c").value, 2.99792458e10);
|
||||||
EXPECT_EQ(obj.get("c").unit, "cm / s");
|
EXPECT_EQ(obj.get("c").unit, "cm / s");
|
||||||
EXPECT_DOUBLE_EQ(obj.get("c").uncertainty, 0.0);
|
EXPECT_DOUBLE_EQ(obj.get("c").uncertainty, 0.0);
|
||||||
@@ -56,8 +50,8 @@ TEST_F(constTest, Get) {
|
|||||||
/**
|
/**
|
||||||
* @test Verify [] opperators returns the correct constant.
|
* @test Verify [] opperators returns the correct constant.
|
||||||
*/
|
*/
|
||||||
TEST_F(constTest, Sub) {
|
TEST_F(constTest, SubscriptOperator) {
|
||||||
constants obj(RELATIVE_PATH);
|
Constants& obj = Constants::getInstance();
|
||||||
EXPECT_DOUBLE_EQ(obj["c"].value, 2.99792458e10);
|
EXPECT_DOUBLE_EQ(obj["c"].value, 2.99792458e10);
|
||||||
EXPECT_EQ(obj["c"].unit, "cm / s");
|
EXPECT_EQ(obj["c"].unit, "cm / s");
|
||||||
EXPECT_DOUBLE_EQ(obj["c"].uncertainty, 0.0);
|
EXPECT_DOUBLE_EQ(obj["c"].uncertainty, 0.0);
|
||||||
@@ -67,16 +61,16 @@ TEST_F(constTest, Sub) {
|
|||||||
/**
|
/**
|
||||||
* @test Verify that the has method returns the correct values
|
* @test Verify that the has method returns the correct values
|
||||||
*/
|
*/
|
||||||
TEST_F(constTest, Has) {
|
TEST_F(constTest, HasMethod) {
|
||||||
constants obj(RELATIVE_PATH);
|
Constants& obj = Constants::getInstance();
|
||||||
|
|
||||||
EXPECT_TRUE(obj.has("c"));
|
EXPECT_TRUE(obj.has("c"));
|
||||||
EXPECT_FALSE(obj.has("c4"));
|
EXPECT_FALSE(obj.has("c4"));
|
||||||
EXPECT_TRUE(obj.has("hbar"));
|
EXPECT_TRUE(obj.has("hbar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(constTest, Keys) {
|
TEST_F(constTest, KeysMethod) {
|
||||||
constants obj(RELATIVE_PATH);
|
Constants& obj = Constants::getInstance();
|
||||||
std::set<std::string> checkKeys;
|
std::set<std::string> checkKeys;
|
||||||
checkKeys.insert("c");
|
checkKeys.insert("c");
|
||||||
checkKeys.insert("wienK");
|
checkKeys.insert("wienK");
|
||||||
@@ -104,8 +98,8 @@ TEST_F(constTest, Keys) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(constTest, Output) {
|
TEST_F(constTest, StreamOperator) {
|
||||||
constants obj(RELATIVE_PATH);
|
Constants& obj = Constants::getInstance();
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
|
|
||||||
os << obj.get("c");
|
os << obj.get("c");
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ foreach test_file : test_sources
|
|||||||
test_exe = executable(
|
test_exe = executable(
|
||||||
exe_name,
|
exe_name,
|
||||||
test_file,
|
test_file,
|
||||||
dependencies: gtest_dep,
|
dependencies: [gtest_dep, const_dep],
|
||||||
include_directories: include_directories('../../src/const/public'),
|
include_directories: include_directories('../../src/const/public'),
|
||||||
link_with: libconst, # Link the dobj library
|
link_with: libconst, # Link the dobj library
|
||||||
install_rpath: '@loader_path/../../src' # Ensure runtime library path resolves correctly
|
install_rpath: '@loader_path/../../src' # Ensure runtime library path resolves correctly
|
||||||
|
|||||||
Reference in New Issue
Block a user