diff --git a/CMakeLists.txt b/CMakeLists.txt index 409f8f634..2cb3527f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ set(AGENT_VERSION_MAJOR 2) set(AGENT_VERSION_MINOR 5) set(AGENT_VERSION_PATCH 0) -set(AGENT_VERSION_BUILD 9) +set(AGENT_VERSION_BUILD 10) set(AGENT_VERSION_RC "") # This minimum version is to support Visual Studio 2019 and C++ feature checking and FetchContent diff --git a/conanfile.py b/conanfile.py index 0a4bfd368..3a10a0633 100644 --- a/conanfile.py +++ b/conanfile.py @@ -115,7 +115,7 @@ def tool_requires_version(self, package, version): def build_requirements(self): self.tool_requires_version("cmake", [3, 26, 4]) if self.options.with_docs: - self.tool_requires_version("doxygen", [1, 9, 4]) + self.tool_requires_version("doxygen", [1, 14, 0]) def requirements(self): self.requires("boost/1.85.0", headers=True, libs=True, transitive_headers=True, transitive_libs=True) diff --git a/src/mtconnect/entity/data_set.hpp b/src/mtconnect/entity/data_set.hpp index abeb5f397..55e35631c 100644 --- a/src/mtconnect/entity/data_set.hpp +++ b/src/mtconnect/entity/data_set.hpp @@ -30,6 +30,144 @@ #include "mtconnect/utilities.hpp" namespace mtconnect::entity { + + /// @brief the namespace to hold the inner abstract templates of the data set + namespace data_set { + /// @brief Compares two values where the first is a variant and the second is a variant value + /// using == + /// @tparam T1 The variant type + /// @tparam T2 The value type + /// @param v1 The variant + /// @param v2 The value to match against + /// + /// This method should be overloaded in the data_set namespace to implement types that + /// do not have a simple `==` method. The method first makes sure the types are the same and + /// then compares using `==`. + template + inline bool SameValue(const T1 &v1, const T2 &v2) + { + return std::holds_alternative(v1) && std::get(v1) == v2; + } + + /// @brief One entry in a data set. Has necessary interface to be work with maps. + /// @tparam T The type of the underlying variant data + template + struct Entry + { + /// @brief Create an entry with a key and value + /// @param key the key + /// @param value the value as a string + /// @param removed `true` if the key has been removed + Entry(const std::string &key, std::string &value, bool removed = false) + : m_key(key), m_value(std::move(value)), m_removed(removed) + {} + + /// @brief Create an entry with a key and value + /// @param key the key + /// @param value the value as a string + /// @param removed `true` if the key has been removed + Entry(std::string &&key, std::string &value, bool removed = false) + : m_key(std::move(key)), m_value(std::move(value)), m_removed(removed) + {} + + /// @brief Create an entry for a table with a data set value + /// @param key the key + /// @param value the value as a DataSet + /// @param removed `true` if the key has been removed + Entry(const std::string &key, Entry &value, bool removed = false) + : m_key(key), m_value(std::move(value)), m_removed(removed) + {} + + /// @brief Create an entry for a data set + /// @param key the key + /// @param value the a data set variant + /// @param removed `true` if the key has been removed + Entry(const std::string &key, T value, bool removed = false) + : m_key(key), m_value(std::move(value)), m_removed(removed) + {} + /// @brief Create a data set entry with just a key (used for search) + /// @param key + Entry(const std::string &key) : m_key(key), m_removed(false) {} + Entry(const Entry &other) = default; + Entry() : m_removed(false) {} + + /// @brief copy a data set entry from another + Entry &operator=(const Entry &other) + { + m_key = other.m_key; + m_value = other.m_value; + m_removed = other.m_removed; + return *this; + } + + /// @brief only compares keys for equality + bool operator==(const Entry &other) const { return m_key == other.m_key; } + /// @brief only compares keys for less than + bool operator<(const Entry &other) const { return m_key < other.m_key; } + + /// @brief Compares the values of the entiry + /// @param other the other value to compare against `m_value` + /// @returns `true` if the values are the same + /// + /// Compares using the `SameValue` free function in the `data_set` namespace. It must be overloaded + /// for any special types required by the variant type T. + bool sameValue(const Entry &other) const + { + const auto &ov = other.m_value; + return std::visit([&ov](const auto &v) { return SameValue(ov, v); }, m_value); + } + + /// @brief compare a data entry ewith another + /// @param other the other entry to compare + bool same(const Entry &other) const + { + return m_key == other.m_key && m_removed == other.m_removed && sameValue(other); + } + + std::string m_key; ///< The key of the entry + T m_value; ///< The value of the entry + bool m_removed; ///< boolean indicator if this entry is removed. + }; + + /// @brief A set of data set entries + /// @tparam EV the entry type for the set, must have < operator. + template + class Set : public std::set + { + public: + using base = std::set; + using base::base; + + /// @brief Get a entry for a key + /// @tparam T the entry type + /// @param key the key + /// @return the typed value of the entry + template + const T &get(const std::string &key) const + { + auto v = base::find(ET(key)); + if (v == this->end()) + throw std::logic_error("DataSet get: key not found '" + key + "'"); + else + return std::get(v->m_value); + } + + /// @brief Get a entry for a key if it exists + /// @tparam T the entry type + /// @param key the key + /// @return optional typed value of the entry + template + const std::optional maybeGet(const std::string &key) const + { + auto v = base::find(ET(key)); + if (v == this->end()) + return std::nullopt; + else + return std::get(v->m_value); + } + }; + } // namespace data_set + /// @brief Data Set Value type enumeration enum class TabelCellType : std::uint16_t { @@ -42,115 +180,38 @@ namespace mtconnect::entity { /// @brief Table Cell value variant using TableCellValue = std::variant; - /// @brief One entry in a data set. Has necessary interface to be work with maps. - struct TableCell - { - /// @brief Create an entry with a key and value - /// @param key the key - /// @param value the value as a string - TableCell(std::string key, std::string &value, bool removed = false) - : m_key(std::move(key)), m_value(std::move(value)), m_removed(removed) - {} - - /// @brief Create an entry for a data set - /// @param key the key - /// @param value the a data set variant - TableCell(std::string key, TableCellValue value, bool removed = false) - : m_key(std::move(key)), m_value(std::move(value)), m_removed(removed) - {} + /// @brief A table cell which is an entry with table cell values + using TableCell = data_set::Entry; - /// @brief Create a data set entry with just a key (used for search) - /// @param key - TableCell(std::string key) : m_key(std::move(key)), m_value(std::string("")) {} - TableCell(const TableCell &other) = default; - TableCell() {} + /// @brief A table row as a data set of table cells + using TableRow = data_set::Set; - /// @brief copy another table cell - /// @param other the other cell - TableCell &operator=(const TableCell &other) + namespace data_set { + /// @brief Compare a data set entry against a table row + /// @tparam T1 The type of the other variant + /// @param v1 The value of the other variant + /// @param row The row we're comparing + template + inline bool SameValue(const T1 &v1, const TableRow &row) { - m_key = other.m_key; - m_value = other.m_value; - m_removed = other.m_removed; - return *this; - } + if (!std::holds_alternative(v1)) + return false; - /// @brief only compares keys for equality - bool operator==(const TableCell &other) const { return m_key == other.m_key; } - /// @brief only compares keys for less than - bool operator<(const TableCell &other) const { return m_key < other.m_key; } + const auto &orow = std::get(v1); - /// @brief helper visitor to compare variant values - struct SameValue - { - /// @brief Construct the with a cell value to compare - SameValue(const TableCellValue &o) : m_other(o) {} + if (row.size() != orow.size()) + return false; - /// @brief Compare the types are the same and the values are the same - /// @tparam T the data type - /// @param v the other value - /// @return `true` if they are the same - template - bool operator()(const T &v) + for (const auto &c1 : row) { - return std::holds_alternative(m_other) && std::get(m_other) == v; + const auto &c2 = orow.find(c1); + if (c2 == orow.end() || !c2->sameValue(c1)) + return false; } - /// @brief the other value to compare - const TableCellValue &m_other; - }; - - /// @brief compares two cell values - /// @param other the other cell value to compare - bool sameValue(const TableCell &other) const - { - auto &ov = other.m_value; - return std::visit(SameValue(ov), m_value); - } - - /// @brief Compares to cells - /// @param other the other cell - bool same(const TableCell &other) const - { - return m_key == other.m_key && m_removed == other.m_removed && sameValue(other); - } - - std::string m_key; - TableCellValue m_value; - bool m_removed {false}; - }; - - /// @brief A set of data set entries - class AGENT_LIB_API TableRow : public std::set - { - public: - using base = std::set; - using base::base; - - /// @brief Get a entry for a key - /// @tparam T the entry type - /// @param key the key - /// @return the typed value of the entry - template - const T &get(const std::string &key) const - { - return std::get(find(TableCell(key))->m_value); - } - - /// @brief Get a entry for a key if it exists - /// @tparam T the entry type - /// @param key the key - /// @return optional typed value of the entry - template - const std::optional maybeGet(const std::string &key) const - { - auto v = find(TableCell(key)); - if (v == end()) - return std::nullopt; - else - return std::get(v->m_value); + return true; } - }; + } // namespace data_set /// @brief Data Set Value type enumeration enum class DataSetValueType : std::uint16_t @@ -166,141 +227,17 @@ namespace mtconnect::entity { using DataSetValue = std::variant; /// @brief One entry in a data set. Has necessary interface to be work with maps. - struct DataSetEntry - { - /// @brief Create an entry with a key and value - /// @param key the key - /// @param value the value as a string - /// @param removed `true` if the key has been removed - DataSetEntry(std::string key, std::string &value, bool removed = false) - : m_key(std::move(key)), m_value(std::move(value)), m_removed(removed) - {} - - /// @brief Create an entry for a table with a data set value - /// @param key the key - /// @param value the value as a DataSet - /// @param removed `true` if the key has been removed - DataSetEntry(std::string key, TableRow &value, bool removed = false) - : m_key(std::move(key)), m_value(std::move(value)), m_removed(removed) - {} - - /// @brief Create an entry for a data set - /// @param key the key - /// @param value the a data set variant - /// @param removed `true` if the key has been removed - DataSetEntry(std::string key, DataSetValue value, bool removed = false) - : m_key(std::move(key)), m_value(std::move(value)), m_removed(removed) - {} - /// @brief Create a data set entry with just a key (used for search) - /// @param key - DataSetEntry(std::string key) - : m_key(std::move(key)), m_value(std::string("")), m_removed(false) - {} - DataSetEntry(const DataSetEntry &other) = default; - DataSetEntry() : m_removed(false) {} - - /// @brief copy a data set entry from another - DataSetEntry &operator=(const DataSetEntry &other) - { - m_key = other.m_key; - m_value = other.m_value; - m_removed = other.m_removed; - return *this; - } - - /// @brief only compares keys for equality - bool operator==(const DataSetEntry &other) const { return m_key == other.m_key; } - /// @brief only compares keys for less than - bool operator<(const DataSetEntry &other) const { return m_key < other.m_key; } - - /// @brief compare a data entry ewith another - bool same(const DataSetEntry &other) const; - - std::string m_key; - DataSetValue m_value; - bool m_removed; - }; + using DataSetEntry = data_set::Entry; /// @brief A set of data set entries - class AGENT_LIB_API DataSet : public std::set + class AGENT_LIB_API DataSet : public data_set::Set { public: - using base = std::set; + using base = data_set::Set; using base::base; - /// @brief Get a entry for a key - /// @tparam T the entry type - /// @param key the key - /// @return the typed value of the entry - template - const T &get(const std::string &key) const - { - return std::get(find(DataSetEntry(key))->m_value); - } - - /// @brief Get a entry for a key if it exists - /// @tparam T the entry type - /// @param key the key - /// @return optional typed value of the entry - template - const std::optional maybeGet(const std::string &key) const - { - auto v = find(DataSetEntry(key)); - if (v == end()) - return std::nullopt; - else - return std::get(v->m_value); - } - /// @brief Split the data set entries by space delimiters and account for the /// use of single and double quotes as well as curly braces bool parse(const std::string &s, bool table); }; - - /// @brief Equality visitor for a DataSetValue - struct DataSetValueSame - { - DataSetValueSame(const DataSetValue &other) : m_other(other) {} - - /// @brief Compare two table rows and see if the are the same - /// @param v The other value - /// @return `true ` if they are the same - bool operator()(const TableRow &v) - { - if (!std::holds_alternative(m_other)) - return false; - - const auto &oset = std::get(m_other); - - if (v.size() != oset.size()) - return false; - - for (const auto &e1 : v) - { - const auto &e2 = oset.find(e1); - if (e2 == oset.end() || !e2->sameValue(e1)) - return false; - } - - return true; - } - - /// @brief Compare the types are the same and the values are the same - /// @tparam T the data type - /// @param v the other value - /// @return `true` if they are the same - template - bool operator()(const T &v) - { - return std::holds_alternative(m_other) && std::get(m_other) == v; - } - - const DataSetValue &m_other; //! the other data set value - }; - - inline bool DataSetEntry::same(const DataSetEntry &other) const - { - return m_key == other.m_key && m_removed == other.m_removed && - std::visit(DataSetValueSame(other.m_value), m_value); - } } // namespace mtconnect::entity