From eabf0d62cf92923b5472bcdf136915694a691a4d Mon Sep 17 00:00:00 2001 From: Emily Boudreaux Date: Mon, 20 Jan 2025 07:49:01 -0500 Subject: [PATCH] feat(DObject): added stream operator and more friendly type managment Now getDataAs can be called to auto cast the data to a particular type --- src/dobj/private/DObject.cpp | 206 +++++++++++++++++++++++++++++++++++ src/dobj/public/DObject.h | 179 ++++++++++++++++++++++++++++++ 2 files changed, 385 insertions(+) create mode 100644 src/dobj/private/DObject.cpp create mode 100644 src/dobj/public/DObject.h diff --git a/src/dobj/private/DObject.cpp b/src/dobj/private/DObject.cpp new file mode 100644 index 0000000..c1b1746 --- /dev/null +++ b/src/dobj/private/DObject.cpp @@ -0,0 +1,206 @@ +#include "DObject.h" +#include +#include + +/** + * @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; + if constexpr (std::is_same_v) { + os << "EMPTY"; + } else if constexpr (std::is_same_v) { + os << value; + } else if constexpr (std::is_same_v) { + os << value; + } else if constexpr (std::is_same_v) { + os << value; + } else if constexpr (std::is_same_v) { + os << value; + } else if constexpr (std::is_same_v>) { + os << "["; + for (const auto& elem : value) { + os << elem << ", "; + } + os << "]"; + } else if constexpr (std::is_same_v>) { + os << "["; + for (const auto& elem : value) { + os << elem << ", "; + } + os << "]"; + } else if constexpr (std::is_same_v>) { + os << "["; + for (const auto& elem : value) { + os << elem << ", "; + } + os << "]"; + } else if constexpr (std::is_same_v>>) { + os << "\n["; + for (const auto& row : value) { + os << "["; + for (const auto& elem : row) { + os << elem << ", "; + } + os << "], "; + } + os << "]"; + } else if constexpr (std::is_same_v>>) { + os << "\n["; + for (const auto& row : value) { + os << "["; + for (const auto& elem : row) { + os << elem << ", "; + } + os << "], "; + } + os << "]"; + } else if constexpr (std::is_same_v>>) { + os << "\n["; + for (const auto& row : value) { + os << "["; + for (const auto& elem : row) { + os << elem << ", "; + } + os << "], "; + } + os << "]"; + } else if constexpr (std::is_same_v>>>) { + 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>>>) { + 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>>>) { + 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; +} \ No newline at end of file diff --git a/src/dobj/public/DObject.h b/src/dobj/public/DObject.h new file mode 100644 index 0000000..fee5951 --- /dev/null +++ b/src/dobj/public/DObject.h @@ -0,0 +1,179 @@ +#ifndef DOBJECT_H +#define DOBJECT_H + +#include +#include +#include +#include +#include +#include +#include + +/** + * @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, + std::vector, std::vector, std::vector, + std::vector>, std::vector>, + std::vector>, + std::vector>>, + std::vector>>, + std::vector>> + >; + + // Mapping of data types to their string representations + std::map 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"}, {10, "vector"}, {11, "vector"}, + {12, "vector"}, {13, "vector"}, + {14, "vector"}, {15, "vector"}, + {16, "vector>"}, {17, "vector>"}, + {18, "vector>"} + }; + + /** + * @brief Placeholder type for plugins. + * + * In the future, this will be replaced with a concrete interface. + */ + using Plugin = std::function; + + /** + * @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()`. + * + * @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() is not needed. + * + * @return Data as type T + */ + template + T getDataAs() const { + if (std::holds_alternative(data_)) { + return std::get(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 plugins_; ///< Registry for dynamically registered plugins. +}; + +#endif // DOBJECT_H