feat(DObject): added stream operator and more friendly type managment

Now getDataAs can be called to auto cast the data to a particular type
This commit is contained in:
2025-01-20 07:49:01 -05:00
parent 8ee319a8e8
commit eabf0d62cf
2 changed files with 385 additions and 0 deletions

View File

@@ -0,0 +1,206 @@
#include "DObject.h"
#include <iostream>
#include <stdexcept>
/**
* @file DObject.cpp
* @brief Implementation of the DObject class.
*
* Provides the implementation for a universal data container with plugin support.
*/
// Default constructor
DObject::DObject() : data_(std::monostate()), debugEnabled_(false) {
// The data is initialized to an empty state using std::monostate (a variant placeholder).
}
/**
* @brief Constructor to initialize a DObject with data.
*/
DObject::DObject(const DataType& data)
: data_(data), debugEnabled_(false) {}
/**
* @brief Retrieves the data stored in the DObject.
*/
const DObject::DataType& DObject::getData() const noexcept {
return data_;
}
/**
* @brief Sets the data for the DObject.
*/
void DObject::setData(const DataType& data) {
data_ = data;
}
/**
* @brief Enables or disables debugging and tracing for the DObject.
*/
void DObject::setDebugging(bool enableDebug) {
debugEnabled_ = enableDebug;
}
/**
* @brief Checks if debugging is enabled for the DObject.
*/
bool DObject::isDebuggingEnabled() const noexcept {
return debugEnabled_;
}
/**
* @brief Registers a plugin with the DObject.
*/
void DObject::registerPlugin(const std::string& id, Plugin plugin) {
if (plugins_.find(id) != plugins_.end()) {
throw std::runtime_error("Plugin with ID '" + id + "' already exists.");
}
plugins_[id] = std::move(plugin);
}
/**
* @brief Unregisters a plugin by its identifier.
*/
void DObject::unregisterPlugin(const std::string& id) {
if (plugins_.erase(id) == 0) {
throw std::runtime_error("Plugin with ID '" + id + "' not found.");
}
}
/**
* @brief Executes a plugin by its identifier.
*/
void DObject::runPlugin(const std::string& id) {
auto it = plugins_.find(id);
if (it == plugins_.end()) {
throw std::runtime_error("Plugin with ID '" + id + "' not found.");
}
it->second(*this); // Invoke the plugin, passing this DObject as a reference.
}
/**
* @brief Executes all registered plugins in the registry.
*/
void DObject::runAllPlugins() {
for (auto& [id, plugin] : plugins_) {
plugin(*this); // Invoke each plugin, passing this DObject as a reference.
}
}
/**
* @brief Provides a human-readable summary of the DObject.
*/
std::ostream& operator<<(std::ostream& os, const DObject& obj) {
os << "DObject Summary:\n";
os << " Debugging Enabled: " << (obj.debugEnabled_ ? "Yes" : "No") << "\n";
os << " Data: ";
std::visit([&os](const auto& value) {
using T = std::decay_t<decltype(value)>;
if constexpr (std::is_same_v<T, std::monostate>) {
os << "EMPTY";
} else if constexpr (std::is_same_v<T, int>) {
os << value;
} else if constexpr (std::is_same_v<T, float>) {
os << value;
} else if constexpr (std::is_same_v<T, double>) {
os << value;
} else if constexpr (std::is_same_v<T, std::string>) {
os << value;
} else if constexpr (std::is_same_v<T, std::vector<int>>) {
os << "[";
for (const auto& elem : value) {
os << elem << ", ";
}
os << "]";
} else if constexpr (std::is_same_v<T, std::vector<float>>) {
os << "[";
for (const auto& elem : value) {
os << elem << ", ";
}
os << "]";
} else if constexpr (std::is_same_v<T, std::vector<double>>) {
os << "[";
for (const auto& elem : value) {
os << elem << ", ";
}
os << "]";
} else if constexpr (std::is_same_v<T, std::vector<std::vector<int>>>) {
os << "\n[";
for (const auto& row : value) {
os << "[";
for (const auto& elem : row) {
os << elem << ", ";
}
os << "], ";
}
os << "]";
} else if constexpr (std::is_same_v<T, std::vector<std::vector<float>>>) {
os << "\n[";
for (const auto& row : value) {
os << "[";
for (const auto& elem : row) {
os << elem << ", ";
}
os << "], ";
}
os << "]";
} else if constexpr (std::is_same_v<T, std::vector<std::vector<double>>>) {
os << "\n[";
for (const auto& row : value) {
os << "[";
for (const auto& elem : row) {
os << elem << ", ";
}
os << "], ";
}
os << "]";
} else if constexpr (std::is_same_v<T, std::vector<std::vector<std::vector<int>>>>) {
os << "\n[";
for (const auto& plane : value) {
os << "[";
for (const auto& row : plane) {
os << "[";
for (const auto& elem : row) {
os << elem << ", ";
}
os << "], ";
}
os << "], ";
}
os << "]";
} else if constexpr (std::is_same_v<T, std::vector<std::vector<std::vector<float>>>>) {
os << "\n[";
for (const auto& plane : value) {
os << "[";
for (const auto& row : plane) {
os << "[";
for (const auto& elem : row) {
os << elem << ", ";
}
os << "], ";
}
os << "], ";
}
os << "]";
} else if constexpr (std::is_same_v<T, std::vector<std::vector<std::vector<double>>>>) {
os << "\n[";
for (const auto& plane : value) {
os << "[";
for (const auto& row : plane) {
os << "[";
for (const auto& elem : row) {
os << elem << ", ";
}
os << "], ";
}
os << "], ";
}
os << "]";
} else {
os << "UNKNOWN";
}
}, obj.data_);
os << "\n Data Type: " << obj.dataTypeMap.at(obj.data_.index());
os << "\n Plugins Registered: " << obj.plugins_.size() << "\n";
return os;
}

179
src/dobj/public/DObject.h Normal file
View File

@@ -0,0 +1,179 @@
#ifndef DOBJECT_H
#define DOBJECT_H
#include <variant>
#include <memory>
#include <vector>
#include <string>
#include <mutex>
#include <map>
#include <functional>
/**
* @file DObject.h
* @brief Defines the DObject class, a universal data container for the project.
*
* The DObject class encapsulates arbitrary data and its associated metadata,
* providing a consistent interface for public-facing functions. It includes
* support for dynamically registered plugins.
*/
/**
* @class DObject
* @brief A universal data container class.
*
* The DObject class is designed to store arbitrary data alongside descriptive metadata.
* It supports plugin registration to allow extensible functionality.
*/
class DObject {
public:
/**
* @brief Supported data types for the DObject.
*
* This type alias uses `std::variant` to store different types of data,
* ensuring type safety and flexibility.
*/
using DataType = std::variant<
bool, short int, int, long int, float, double,
long double, std::string, std::monostate, std::vector<int>,
std::vector<float>, std::vector<double>, std::vector<std::string>,
std::vector<std::vector<int>>, std::vector<std::vector<float>>,
std::vector<std::vector<double>>,
std::vector<std::vector<std::vector<int>>>,
std::vector<std::vector<std::vector<float>>>,
std::vector<std::vector<std::vector<double>>>
>;
// Mapping of data types to their string representations
std::map<int, std::string> dataTypeMap = {
{0, "bool"}, {1, "short int"}, {2, "int"}, {3, "long int"}, {4, "float"},
{5, "double"}, {6, "long double"}, {7, "string"}, {8, "std::monostate"},
{9, "vector<int>"}, {10, "vector<float>"}, {11, "vector<double>"},
{12, "vector<string>"}, {13, "vector<vector<int>"},
{14, "vector<vector<float>"}, {15, "vector<vector<double>"},
{16, "vector<vector<vector<int>>"}, {17, "vector<vector<vector<float>>"},
{18, "vector<vector<vector<double>>"}
};
/**
* @brief Placeholder type for plugins.
*
* In the future, this will be replaced with a concrete interface.
*/
using Plugin = std::function<void(DObject&)>;
/**
* @brief Default constructor.
*
* Creates an empty DObject.
*/
DObject();
/**
* @brief Constructor to initialize a DObject with data.
*
* @param data The data to be stored in the DObject.
*/
DObject(const DataType& data);
/**
* @brief Retrieves the data stored in the DObject.
*
* Use the appropriate type (matching the stored data) with `std::get<T>()`.
*
* @return A constant reference to the stored data.
*/
const DataType& getData() const noexcept;
/**
* @brief Retrieves the data stored in the DObject as a typed object so that std::get<T>() is not needed.
*
* @return Data as type T
*/
template <typename T>
T getDataAs() const {
if (std::holds_alternative<T>(data_)) {
return std::get<T>(data_);
} else {
throw std::bad_variant_access();
}
}
/**
* @brief Sets the data for the DObject.
*
* Updates the stored data and optionally updates metadata.
*
* @param data The new data to store in the DObject.
*/
void setData(const DataType& data);
/**
* @brief Enables or disables debugging and tracing for the DObject.
*
* When debugging is enabled, the DObject tracks creation and modification history.
*
* @param enableDebug True to enable debugging, false to disable it.
*/
void setDebugging(bool enableDebug);
/**
* @brief Checks if debugging is enabled for the DObject.
*
* @return True if debugging is enabled, false otherwise.
*/
bool isDebuggingEnabled() const noexcept;
/**
* @brief Registers a plugin with the DObject.
*
* Plugins are stored in a registry and can add custom functionality to the DObject.
*
* @param id A unique identifier for the plugin.
* @param plugin The plugin function to register.
*/
void registerPlugin(const std::string& id, Plugin plugin);
/**
* @brief Unregisters a plugin by its identifier.
*
* Removes the plugin from the registry if it exists.
*
* @param id The unique identifier of the plugin to unregister.
*/
void unregisterPlugin(const std::string& id);
/**
* @brief Executes a plugin by its identifier.
*
* Invokes the registered plugin function. If the plugin is not found, no action is taken.
*
* @param id The unique identifier of the plugin to execute.
*/
void runPlugin(const std::string& id);
/**
* @brief Executes all registered plugins in the registry.
*
* Iterates through all plugins and invokes them on the current DObject.
*/
void runAllPlugins();
/**
* @brief Provides a human-readable summary of the DObject.
*
* Useful for quick inspection or logging during debugging sessions.
*
* @param os The output stream to write to.
* @param obj The DObject to summarize.
* @return A reference to the output stream.
*/
friend std::ostream& operator<<(std::ostream& os, const DObject& obj);
private:
DataType data_; ///< The main data stored in the DObject.
bool debugEnabled_ = false; ///< Indicates whether debugging is enabled.
std::map<std::string, Plugin> plugins_; ///< Registry for dynamically registered plugins.
};
#endif // DOBJECT_H