From 81cc7145979db6760d9e53f8a89a71308bf11864 Mon Sep 17 00:00:00 2001 From: Will Sobel Date: Wed, 4 Jun 2025 10:09:10 -0400 Subject: [PATCH 1/6] Checkpoint with a wrapper --- src/mtconnect/entity/data_set.hpp | 170 +++++++++++++------ src/mtconnect/entity/requirement.cpp | 4 +- src/mtconnect/entity/xml_parser.cpp | 2 +- src/mtconnect/pipeline/json_mapper.cpp | 2 +- src/mtconnect/pipeline/response_document.cpp | 4 +- src/mtconnect/ruby/ruby_entity.hpp | 2 +- test_package/data_item_mapping_test.cpp | 12 +- test_package/embedded_ruby_test.cpp | 4 +- test_package/entity_parser_test.cpp | 6 +- test_package/json_mapping_test.cpp | 10 +- test_package/response_document_test.cpp | 6 +- test_package/table_test.cpp | 22 +-- 12 files changed, 155 insertions(+), 89 deletions(-) diff --git a/src/mtconnect/entity/data_set.hpp b/src/mtconnect/entity/data_set.hpp index 0fdaa5983..01c9606fb 100644 --- a/src/mtconnect/entity/data_set.hpp +++ b/src/mtconnect/entity/data_set.hpp @@ -30,7 +30,84 @@ #include "mtconnect/utilities.hpp" namespace mtconnect::entity { - struct DataSetEntry; + /// @brief Forward declaration of DataSetEntry + class DataSet; + + class DataSetWrapper + { + public: + DataSetWrapper(const DataSet &entry); + DataSetWrapper(const DataSetWrapper &entry); + DataSetWrapper(); + ~DataSetWrapper() = default; + + DataSetWrapper &operator=(const DataSetWrapper &other); + + operator DataSet &() noexcept + { + return *m_storage; + } + + operator DataSet const &() const noexcept + { + return *m_storage; + } + + void swap(DataSetWrapper &other) noexcept { m_storage.swap(other.m_storage); } + + bool operator==(const DataSetWrapper &other) const noexcept; + + private: + std::unique_ptr m_storage; + }; + + /// @brief Data set value variant + 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, DataSet &value, bool removed = false) + : m_key(std::move(key)), m_value(DataSetWrapper(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) {} + + DataSetEntry &operator=(const DataSetEntry &other); + + bool operator==(const DataSetEntry &other) const { return m_key == other.m_key; } + bool operator<(const DataSetEntry &other) const { return m_key < other.m_key; } + + bool same(const DataSetEntry &other) const; + + std::string m_key; + DataSetValue m_value; + bool m_removed; + }; /// @brief A set of data set entries class AGENT_LIB_API DataSet : public std::set @@ -58,6 +135,37 @@ namespace mtconnect::entity { bool parse(const std::string &s, bool table); }; + inline DataSetWrapper::DataSetWrapper(const DataSet &entry) : m_storage(new DataSet(entry)) { ; } + inline DataSetWrapper::DataSetWrapper(const DataSetWrapper &entry) + : m_storage(new DataSet(*entry.m_storage)) + { + ; + } + inline DataSetWrapper::DataSetWrapper() : m_storage(new DataSet()) { ; } + + inline DataSetEntry &DataSetEntry::operator=(const DataSetEntry &other) + { + m_key = other.m_key; + m_value = other.m_value; + m_removed = other.m_removed; + return *this; + } + + inline bool DataSetWrapper::operator==(const DataSetWrapper &other) const noexcept + { + return *m_storage == *other.m_storage; + } + + inline DataSetWrapper &DataSetWrapper::operator=(const DataSetWrapper &other) + { + if (this != &other) + { + m_storage.reset(new DataSet(*other.m_storage)); + } + return *this; + } + + /// @brief Data Set Value type enumeration enum class DataSetValueType : std::uint16_t { @@ -68,9 +176,6 @@ namespace mtconnect::entity { DOUBLE = 0x4 ///< double }; - /// @brief Data set value variant - using DataSetValue = std::variant; - /// @brief Equality visitor for a DataSetValue struct DataSetValueSame { @@ -92,51 +197,6 @@ namespace mtconnect::entity { const DataSetValue &m_other; }; - /// @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, DataSet &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(""), m_removed(false) {} - DataSetEntry(const DataSetEntry &other) = default; - DataSetEntry() : m_removed(false) {} - - std::string m_key; - DataSetValue m_value; - bool m_removed; - - bool operator==(const DataSetEntry &other) const { return m_key == other.m_key; } - bool operator<(const DataSetEntry &other) const { return m_key < other.m_key; } - - bool same(const DataSetEntry &other) const - { - return m_key == other.m_key && m_removed == other.m_removed && - std::visit(DataSetValueSame(other.m_value), m_value); - } - }; - /// @brief Get a typed value from a data set /// @tparam T the data type /// @param key the key to search for @@ -164,10 +224,10 @@ namespace mtconnect::entity { inline bool DataSetValueSame::operator()(const DataSet &v) { - if (!std::holds_alternative(m_other)) + if (!std::holds_alternative(m_other)) return false; - const auto &oset = std::get(m_other); + const DataSet &oset = std::get(m_other); if (v.size() != oset.size()) return false; @@ -175,10 +235,16 @@ namespace mtconnect::entity { for (const auto &e1 : v) { const auto &e2 = oset.find(e1); - if (e2 == oset.end() || !visit(DataSetValueSame(e2->m_value), e1.m_value)) + if (e2 == oset.end() || !std::visit(DataSetValueSame(e2->m_value), e1.m_value)) return false; } return true; } + + 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 diff --git a/src/mtconnect/entity/requirement.cpp b/src/mtconnect/entity/requirement.cpp index 854fd7e17..8198a71ba 100644 --- a/src/mtconnect/entity/requirement.cpp +++ b/src/mtconnect/entity/requirement.cpp @@ -263,7 +263,7 @@ namespace mtconnect { void operator()(const int64_t arg, string &v) { v = to_string(arg); } void operator()(const int64_t arg, bool &v) { v = arg != 0; } void operator()(const int64_t arg, double &v) { v = double(arg); } - void operator()(const int64_t arg, Vector &v) { v.emplace_back(arg); } + void operator()(const int64_t arg, Vector &v) { v.emplace_back(double(arg)); } void operator()(const int64_t arg, Timestamp &v) { v = std::chrono::system_clock::from_time_t(arg); @@ -311,7 +311,7 @@ namespace mtconnect { void operator()(const Timestamp &arg, double &v) { v = arg.time_since_epoch().count(); } void operator()(const Timestamp &arg, Vector &v) { - v.emplace_back(arg.time_since_epoch().count()); + v.emplace_back(double(arg.time_since_epoch().count())); } template void operator()(const Timestamp &arg, T &) diff --git a/src/mtconnect/entity/xml_parser.cpp b/src/mtconnect/entity/xml_parser.cpp index 2dccd6069..7ed6daa5e 100644 --- a/src/mtconnect/entity/xml_parser.cpp +++ b/src/mtconnect/entity/xml_parser.cpp @@ -129,7 +129,7 @@ namespace mtconnect::entity { { if (table && !cell) { - DataSet &ds = value.emplace(); + DataSet &ds = value.emplace(); parseDataSet(child, ds, true, true); } else if (valueNode->type == XML_TEXT_NODE) diff --git a/src/mtconnect/pipeline/json_mapper.cpp b/src/mtconnect/pipeline/json_mapper.cpp index 0c05943f6..c92749eb3 100644 --- a/src/mtconnect/pipeline/json_mapper.cpp +++ b/src/mtconnect/pipeline/json_mapper.cpp @@ -358,7 +358,7 @@ namespace mtconnect::pipeline { if (m_expectation == Expectation::ROW) { // For tables, recurse down to read the entry data set - auto &row = m_entry.m_value.emplace(); + auto &row = m_entry.m_value.emplace(); DataSetHandler handler(row, nullopt, false); auto success = handler(reader, buff); if (!success) diff --git a/src/mtconnect/pipeline/response_document.cpp b/src/mtconnect/pipeline/response_document.cpp index 419d4e6eb..8798a63fe 100644 --- a/src/mtconnect/pipeline/response_document.cpp +++ b/src/mtconnect/pipeline/response_document.cpp @@ -259,8 +259,8 @@ namespace mtconnect::pipeline { if (table) { - entry.m_value.emplace(); - DataSet &row = get(entry.m_value); + entry.m_value.emplace(); + DataSet &row = get(entry.m_value); eachElement(n, "Cell", [&row](xmlNodePtr c) { row.emplace(attributeValue(c, "key"), type(text(c))); diff --git a/src/mtconnect/ruby/ruby_entity.hpp b/src/mtconnect/ruby/ruby_entity.hpp index 6302afe4d..47bf12738 100644 --- a/src/mtconnect/ruby/ruby_entity.hpp +++ b/src/mtconnect/ruby/ruby_entity.hpp @@ -111,7 +111,7 @@ namespace mtconnect::ruby { { DataSet inner; dataSetFromRuby(mrb, value, inner); - dsv.emplace(inner); + dsv.emplace(inner); break; } diff --git a/test_package/data_item_mapping_test.cpp b/test_package/data_item_mapping_test.cpp index f6bb107d6..349fc11e2 100644 --- a/test_package/data_item_mapping_test.cpp +++ b/test_package/data_item_mapping_test.cpp @@ -409,17 +409,17 @@ TEST_F(DataItemMappingTest, should_map_an_event_table) auto &ds = set->getValue(); ASSERT_EQ(3, ds.size()); - auto a = get(ds.find("a"_E)->m_value); + DataSet &a = (DataSet&)get(ds.find("a"_E)->m_value); ASSERT_EQ(2, a.size()); ASSERT_EQ(1, get(a.find("c"_E)->m_value)); ASSERT_EQ(3.0, get(a.find("n"_E)->m_value)); - auto b = get(ds.find("b"_E)->m_value); + DataSet &b = (DataSet &) get(ds.find("b"_E)->m_value); ASSERT_EQ(2, a.size()); ASSERT_EQ(2, get(b.find("d"_E)->m_value)); ASSERT_EQ(3, get(b.find("e"_E)->m_value)); - auto c = get(ds.find("c"_E)->m_value); + DataSet &c = (DataSet &) get(ds.find("c"_E)->m_value); ASSERT_EQ(2, c.size()); ASSERT_EQ("abc", get(c.find("x"_E)->m_value)); ASSERT_EQ("def", get(c.find("y"_E)->m_value)); @@ -445,17 +445,17 @@ TEST_F(DataItemMappingTest, should_map_an_sample_table) auto &ds = set->getValue(); ASSERT_EQ(3, ds.size()); - auto a = get(ds.find("a"_E)->m_value); + DataSet &a = (DataSet &) get(ds.find("a"_E)->m_value); ASSERT_EQ(2, a.size()); ASSERT_EQ(1, get(a.find("c"_E)->m_value)); ASSERT_EQ(3.0, get(a.find("n"_E)->m_value)); - auto b = get(ds.find("b"_E)->m_value); + DataSet &b = (DataSet &) get(ds.find("b"_E)->m_value); ASSERT_EQ(2, a.size()); ASSERT_EQ(2, get(b.find("d"_E)->m_value)); ASSERT_EQ(3, get(b.find("e"_E)->m_value)); - auto c = get(ds.find("c"_E)->m_value); + DataSet &c = (DataSet &) get(ds.find("c"_E)->m_value); ASSERT_EQ(2, c.size()); ASSERT_EQ("abc", get(c.find("x"_E)->m_value)); ASSERT_EQ("def", get(c.find("y"_E)->m_value)); diff --git a/test_package/embedded_ruby_test.cpp b/test_package/embedded_ruby_test.cpp index 8cffce101..46441cfe6 100644 --- a/test_package/embedded_ruby_test.cpp +++ b/test_package/embedded_ruby_test.cpp @@ -241,13 +241,13 @@ namespace { const DataSet &ds = cent1->getValue(); ASSERT_EQ(2, ds.size()); - const DataSet &row1 = ds.get("row1"); + const DataSet &row1 = ds.get("row1"); ASSERT_EQ(2, row1.size()); ASSERT_EQ("text1", row1.get("string")); ASSERT_NEAR(1.0, row1.get("float"), 0.000001); - const DataSet &row2 = ds.get("row2"); + const DataSet &row2 = ds.get("row2"); ASSERT_EQ(2, row2.size()); ASSERT_EQ("text2", row2.get("string")); diff --git a/test_package/entity_parser_test.cpp b/test_package/entity_parser_test.cpp index 8128915fd..813275c77 100644 --- a/test_package/entity_parser_test.cpp +++ b/test_package/entity_parser_test.cpp @@ -371,14 +371,14 @@ TEST_F(EntityParserTest, should_parse_tables) auto entity = parser.parse(root, doc, errors); ASSERT_EQ("Root", entity->getName()); - auto set = entity->get("Table"); - auto e1 = set.get("A"); + const DataSet &set = entity->get("Table"); + const DataSet &e1 = set.get("A"); ASSERT_EQ("abc", e1.get("text")); ASSERT_EQ(101, e1.get("int")); ASSERT_EQ(50.5, e1.get("double")); - auto e2 = set.get("B"); + const DataSet &e2 = set.get("B"); ASSERT_EQ("def", e2.get("text2")); ASSERT_EQ(102, e2.get("int2")); diff --git a/test_package/json_mapping_test.cpp b/test_package/json_mapping_test.cpp index d08c1d292..36bab3183 100644 --- a/test_package/json_mapping_test.cpp +++ b/test_package/json_mapping_test.cpp @@ -748,9 +748,9 @@ TEST_F(JsonMappingTest, should_parse_tables) auto dsi = set1.begin(); ASSERT_EQ("r1", dsi->m_key); - ASSERT_TRUE(holds_alternative(dsi->m_value)); + ASSERT_TRUE(holds_alternative(dsi->m_value)); - auto &row1 = get(dsi->m_value); + auto &row1 = (DataSet &) get(dsi->m_value); ASSERT_EQ(1, row1.size()); auto ri = row1.begin(); @@ -758,7 +758,7 @@ TEST_F(JsonMappingTest, should_parse_tables) ASSERT_EQ(123.45, get(ri->m_value)); dsi++; - auto &row2 = get(dsi->m_value); + auto &row2 = (DataSet &) get(dsi->m_value); ASSERT_EQ(2, row2.size()); ri = row2.begin(); @@ -783,9 +783,9 @@ TEST_F(JsonMappingTest, should_parse_tables) dsi = set2.begin(); ASSERT_EQ("r1", dsi->m_key); - ASSERT_TRUE(holds_alternative(dsi->m_value)); + ASSERT_TRUE(holds_alternative(dsi->m_value)); - auto &row3 = get(dsi->m_value); + auto &row3 = (DataSet &) get(dsi->m_value); ASSERT_EQ(2, row3.size()); ri = row3.begin(); diff --git a/test_package/response_document_test.cpp b/test_package/response_document_test.cpp index 5bd4896bc..c3a05208d 100644 --- a/test_package/response_document_test.cpp +++ b/test_package/response_document_test.cpp @@ -290,7 +290,7 @@ TEST_F(ResponseDocumentTest, should_parse_tables) ASSERT_EQ("W1", dse->m_key); ASSERT_FALSE(dse->m_removed); - const auto &v1 = get(dse->m_value); + const DataSet &v1 = get(dse->m_value); ASSERT_EQ(3, v1.size()); auto v1i = v1.begin(); @@ -307,7 +307,7 @@ TEST_F(ResponseDocumentTest, should_parse_tables) ASSERT_EQ("W2", dse->m_key); ASSERT_FALSE(dse->m_removed); - const auto &v2 = get(dse->m_value); + const DataSet &v2 = get(dse->m_value); ASSERT_EQ(3, v2.size()); auto v2i = v2.begin(); @@ -324,7 +324,7 @@ TEST_F(ResponseDocumentTest, should_parse_tables) ASSERT_EQ("W3", dse->m_key); ASSERT_FALSE(dse->m_removed); - const auto &v3 = get(dse->m_value); + const DataSet &v3 = get(dse->m_value); ASSERT_EQ(3, v3.size()); auto v3i = v3.begin(); diff --git a/test_package/table_test.cpp b/test_package/table_test.cpp index 215c8735c..6febe9c06 100644 --- a/test_package/table_test.cpp +++ b/test_package/table_test.cpp @@ -97,7 +97,7 @@ TEST_F(TableTest, test_simple_table_formats) ASSERT_TRUE(s1.parse("abc={a=1 b=2.0 c='abc'}", true)); ASSERT_EQ(1, s1.size()); - const DataSet &abc1 = get(s1.find("abc"_E)->m_value); + const DataSet &abc1 = get(s1.find("abc"_E)->m_value); ASSERT_EQ(3, abc1.size()); ASSERT_EQ(1, get(abc1.find("a"_E)->m_value)); ASSERT_EQ(2.0, get(abc1.find("b"_E)->m_value)); @@ -110,7 +110,7 @@ TEST_F(TableTest, test_simple_table_formats_with_whitespace) ASSERT_TRUE(s1.parse("abc={ a=1 b=2.0 c='abc' }", true)); ASSERT_EQ(1, s1.size()); - const DataSet &abc1 = get(s1.find("abc"_E)->m_value); + const DataSet &abc1 = get(s1.find("abc"_E)->m_value); ASSERT_EQ(3, abc1.size()); ASSERT_EQ(1, get(abc1.find("a"_E)->m_value)); ASSERT_EQ(2.0, get(abc1.find("b"_E)->m_value)); @@ -123,7 +123,7 @@ TEST_F(TableTest, test_simple_table_formats_with_quotes) ASSERT_TRUE(s1.parse("abc=' a=1 b=2.0 c='abc''", true)); ASSERT_EQ(1, s1.size()); - const DataSet &abc1 = get(s1.find("abc"_E)->m_value); + const DataSet &abc1 = get(s1.find("abc"_E)->m_value); ASSERT_EQ(3, abc1.size()); ASSERT_EQ(1, get(abc1.find("a"_E)->m_value)); ASSERT_EQ(2.0, get(abc1.find("b"_E)->m_value)); @@ -136,7 +136,7 @@ TEST_F(TableTest, test_simple_table_formats_with_double_quotes) ASSERT_TRUE(s1.parse("abc=\" a=1 b=2.0 c='abc'\"", true)); ASSERT_EQ(1, s1.size()); - const DataSet &abc1 = get(s1.find("abc"_E)->m_value); + const DataSet &abc1 = get(s1.find("abc"_E)->m_value); ASSERT_EQ(3, abc1.size()); ASSERT_EQ(1, get(abc1.find("a"_E)->m_value)); ASSERT_EQ(2.0, get(abc1.find("b"_E)->m_value)); @@ -149,7 +149,7 @@ TEST_F(TableTest, test_simple_table_formats_with_nested_braces) ASSERT_TRUE(s1.parse("abc={ a=1 b=2.0 c={abc}}", true)); ASSERT_EQ(1, s1.size()); - const DataSet &abc1 = get(s1.find("abc"_E)->m_value); + const DataSet &abc1 = get(s1.find("abc"_E)->m_value); ASSERT_EQ(3, abc1.size()); ASSERT_EQ(1, get(abc1.find("a"_E)->m_value)); ASSERT_EQ(2.0, get(abc1.find("b"_E)->m_value)); @@ -162,7 +162,7 @@ TEST_F(TableTest, test_simple_table_formats_with_removed_key) s1.parse("abc={ a=1 b=2.0 c={abc} d= e}", true); ASSERT_EQ(1, s1.size()); - const DataSet &abc1 = get(s1.find("abc"_E)->m_value); + const DataSet &abc1 = get(s1.find("abc"_E)->m_value); ASSERT_EQ(5, abc1.size()); ASSERT_EQ(1, get(abc1.find("a"_E)->m_value)); ASSERT_EQ(2.0, get(abc1.find("b"_E)->m_value)); @@ -177,7 +177,7 @@ TEST_F(TableTest, test_mulitple_entries) ASSERT_TRUE(s1.parse("abc={ a=1 b=2.0 c={abc} d= e} def={x=1.0 y=2.0}", true)); ASSERT_EQ(2, s1.size()); - const DataSet &abc = get(s1.find("abc"_E)->m_value); + const DataSet &abc = get(s1.find("abc"_E)->m_value); ASSERT_EQ(5, abc.size()); ASSERT_EQ(1, get(abc.find("a"_E)->m_value)); ASSERT_EQ(2.0, get(abc.find("b"_E)->m_value)); @@ -185,7 +185,7 @@ TEST_F(TableTest, test_mulitple_entries) ASSERT_TRUE(abc.find("d"_E)->m_removed); ASSERT_TRUE(abc.find("e"_E)->m_removed); - const DataSet &def = get(s1.find("def"_E)->m_value); + const DataSet &def = get(s1.find("def"_E)->m_value); ASSERT_EQ(2, def.size()); ASSERT_EQ(1.0, get(def.find("x"_E)->m_value)); ASSERT_EQ(2.0, get(def.find("y"_E)->m_value)); @@ -230,19 +230,19 @@ TEST_F(TableTest, InitialSet) ASSERT_EQ(3, set1.size()); ASSERT_EQ(3, ce->get("count")); - auto g531 = get(set1.find("G53.1"_E)->m_value); + const DataSet &g531 = get(set1.find("G53.1"_E)->m_value); ASSERT_EQ((size_t)3, g531.size()); ASSERT_EQ(1.0, get(g531.find("X"_E)->m_value)); ASSERT_EQ(2.0, get(g531.find("Y"_E)->m_value)); ASSERT_EQ(3.0, get(g531.find("Z"_E)->m_value)); - auto g532 = get(set1.find("G53.2"_E)->m_value); + const DataSet &g532 = get(set1.find("G53.2"_E)->m_value); ASSERT_EQ((size_t)3, g532.size()); ASSERT_EQ(4.0, get(g532.find("X"_E)->m_value)); ASSERT_EQ(5.0, get(g532.find("Y"_E)->m_value)); ASSERT_EQ(6.0, get(g532.find("Z"_E)->m_value)); - auto g533 = get(set1.find("G53.3"_E)->m_value); + const DataSet &g533 = get(set1.find("G53.3"_E)->m_value); ASSERT_EQ((size_t)4, g533.size()); ASSERT_EQ(7.0, get(g533.find("X"_E)->m_value)); ASSERT_EQ(8.0, get(g533.find("Y"_E)->m_value)); From be2b4b84b702c31fe0256131f058cb62d30aa146 Mon Sep 17 00:00:00 2001 From: Will Sobel Date: Wed, 4 Jun 2025 16:02:27 -0400 Subject: [PATCH 2/6] Refactored to use TableRow and TableCell types for Tables --- src/mtconnect/entity/data_set.cpp | 63 ++++- src/mtconnect/entity/data_set.hpp | 276 +++++++++++-------- src/mtconnect/entity/entity.cpp | 19 +- src/mtconnect/entity/entity.hpp | 1 + src/mtconnect/entity/json_printer.hpp | 35 ++- src/mtconnect/entity/xml_parser.cpp | 14 +- src/mtconnect/entity/xml_printer.cpp | 6 +- src/mtconnect/pipeline/json_mapper.cpp | 62 +++-- src/mtconnect/pipeline/response_document.cpp | 10 +- src/mtconnect/ruby/ruby_entity.hpp | 111 +++++++- test_package/data_item_mapping_test.cpp | 37 +-- test_package/embedded_ruby_test.cpp | 4 +- test_package/entity_parser_test.cpp | 4 +- test_package/json_mapping_test.cpp | 10 +- test_package/response_document_test.cpp | 6 +- test_package/table_test.cpp | 97 +++---- 16 files changed, 488 insertions(+), 267 deletions(-) diff --git a/src/mtconnect/entity/data_set.cpp b/src/mtconnect/entity/data_set.cpp index 016f5c302..d3101abeb 100644 --- a/src/mtconnect/entity/data_set.cpp +++ b/src/mtconnect/entity/data_set.cpp @@ -48,7 +48,7 @@ namespace std { [&s](const std::string &st) { s << "string(" << st << ")"; }, [&s](const int64_t &i) { s << "int(" << i << ")"; }, [&s](const double &d) { s << "double(" << d << ")"; }, - [&s](const DataSet &arg) { + [&s](const TableRow &arg) { s << "{"; for (const auto &v : arg) { @@ -65,6 +65,12 @@ namespace std { s << t.m_key << "=" << t.m_value << (t.m_removed ? ":removed" : ""); return s; } + + static inline ostream &operator<<(ostream &s, const mtconnect::observation::TableCell &t) + { + s << t.m_key << "=" << t.m_value; + return s; + } } // namespace std #endif @@ -75,6 +81,32 @@ namespace mtconnect::entity { /// @brief Functions called when parsing data sets namespace DataSetParserActions { inline static void add_entry_f(DataSet &ds, const DataSetEntry &entry) { ds.emplace(entry); } + + struct TableCellConverter { + TableCellConverter(TableCellValue &value) : m_value(value) { } + + void operator()(const TableRow &row) + { + LOG(error) << "Table row cannot recurse"; + } + + template + void operator()(const T &v) + { + m_value.emplace(v); + } + + TableCellValue &m_value; + }; + + inline static void add_cell_f(TableRow &row, const DataSetEntry &entry) + { + TableCell cell(entry.m_key); + cell.m_removed = entry.m_removed; + std::visit(TableCellConverter(cell.m_value), entry.m_value); + row.emplace(cell); + } + inline static void make_entry_f(DataSetEntry &entry, const string &key, const boost::optional &v) { @@ -85,7 +117,7 @@ namespace mtconnect::entity { entry.m_removed = true; } inline static void make_entry_f(DataSetEntry &entry, const string &key, - const boost::optional &v) + const boost::optional &v) { entry.m_key = key; if (v) @@ -95,6 +127,7 @@ namespace mtconnect::entity { } }; // namespace DataSetParserActions BOOST_PHOENIX_ADAPT_FUNCTION(void, add_entry, DataSetParserActions::add_entry_f, 2); + BOOST_PHOENIX_ADAPT_FUNCTION(void, add_cell, DataSetParserActions::add_cell_f, 2); BOOST_PHOENIX_ADAPT_FUNCTION(void, make_entry, DataSetParserActions::make_entry_f, 3); /// @brief Parser to turn adapter text in `key=value ...` or `key={col1=value ...}` syntax into a @@ -153,15 +186,15 @@ namespace mtconnect::entity { m_entry = (m_key >> -("=" >> -m_value))[make_entry(_val, _1, _2)]; // Table support with quoted and braced content - m_quotedDataSet = - (char_("\"'")[_a = _1] >> *space >> *(m_entry[add_entry(_val, _1)] >> *space)) > lit(_a); + m_quotedTableRow = + (char_("\"'")[_a = _1] >> *space >> *(m_entry[add_cell(_val, _1)] >> *space)) > lit(_a); - m_bracedDataSet = - (lit('{') >> *space >> *(m_entry[add_entry(_val, _1)] >> *space)) > lit('}'); + m_bracedTableRow = + (lit('{') >> *space >> *(m_entry[add_cell(_val, _1)] >> *space)) > lit('}'); - m_tableValue %= (m_quotedDataSet | m_bracedDataSet); + m_tableRow %= (m_quotedTableRow | m_bracedTableRow); m_tableEntry = (m_key >> -("=" > &(space | lit('{') | '\'' | '"') >> - -m_tableValue))[make_entry(_val, _1, _2)]; + -m_tableRow))[make_entry(_val, _1, _2)]; if (table) { @@ -173,7 +206,7 @@ namespace mtconnect::entity { } BOOST_SPIRIT_DEBUG_NODES(( - m_start)(m_quoted)(m_braced)(m_key)(m_value)(m_entry)(m_simple)(m_quoted)(m_tableValue)(m_quotedDataSet)(m_bracedDataSet)(m_tableEntry)); + m_start)(m_quoted)(m_braced)(m_key)(m_value)(m_entry)(m_simple)(m_quoted)(m_quotedTableRow)(m_bracedTableRow)(m_tableEntry)); m_start.name("top"); m_simple.name("simple"); @@ -183,9 +216,9 @@ namespace mtconnect::entity { m_simple.name("simple"); m_quoted.name("quoted"); - m_tableValue.name("table value"); - m_quotedDataSet.name("quoted data set"); - m_bracedDataSet.name("braced data set"); + m_tableEntry.name("table value"); + m_quotedTableRow.name("quoted table row"); + m_bracedTableRow.name("braced table row"); m_tableEntry.name("table entry"); using namespace boost::fusion; @@ -210,9 +243,9 @@ namespace mtconnect::entity { qi::rule m_value; qi::rule m_entry; - qi::rule> m_quotedDataSet; - qi::rule m_bracedDataSet; - qi::rule m_tableValue; + qi::rule> m_quotedTableRow; + qi::rule m_bracedTableRow; + qi::rule m_tableRow; qi::rule m_tableEntry; }; diff --git a/src/mtconnect/entity/data_set.hpp b/src/mtconnect/entity/data_set.hpp index 01c9606fb..d64760eb0 100644 --- a/src/mtconnect/entity/data_set.hpp +++ b/src/mtconnect/entity/data_set.hpp @@ -30,39 +30,132 @@ #include "mtconnect/utilities.hpp" namespace mtconnect::entity { - /// @brief Forward declaration of DataSetEntry - class DataSet; - - class DataSetWrapper + /// @brief Data Set Value type enumeration + enum class TabelCellType : std::uint16_t { - public: - DataSetWrapper(const DataSet &entry); - DataSetWrapper(const DataSetWrapper &entry); - DataSetWrapper(); - ~DataSetWrapper() = default; - - DataSetWrapper &operator=(const DataSetWrapper &other); - - operator DataSet &() noexcept + EMPTY = 0x0, ///< monostate for no value + STRING = 0x02, ///< string value + INTEGER = 0x3, ///< 64 bit integer + DOUBLE = 0x4 ///< double + }; + + /// @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 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() {} + + TableCell &operator=(const TableCell &other) { - return *m_storage; + m_key = other.m_key; + m_value = other.m_value; + m_removed = other.m_removed; + return *this; } - - operator DataSet const &() const noexcept + + bool operator==(const TableCell &other) const { return m_key == other.m_key; } + bool operator<(const TableCell &other) const { return m_key < other.m_key; } + + struct SameValue + { + SameValue(const TableCellValue &o) : m_other(o) {} + + /// @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 TableCellValue &m_other; + }; + + bool same(const TableCell &other) const { - return *m_storage; + const auto &ov = other.m_value; + return m_key == other.m_key && m_removed == other.m_removed && + std::visit(SameValue(ov), m_value); } + + bool sameValue(const TableCell &other) const + { + auto &ov = other.m_value; + return std::visit(SameValue(ov), m_value); + } + + std::string m_key; + TableCellValue m_value; + bool m_removed { false }; + }; - void swap(DataSetWrapper &other) noexcept { m_storage.swap(other.m_storage); } - - bool operator==(const DataSetWrapper &other) const noexcept; - private: - std::unique_ptr m_storage; + /// @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); + } + }; + + /// @brief Data Set Value type enumeration + enum class DataSetValueType : std::uint16_t + { + EMPTY = 0x0, ///< monostate for no value + TABLE_ROW = 0x01, ///< data set member for tables + STRING = 0x02, ///< string value + INTEGER = 0x3, ///< 64 bit integer + DOUBLE = 0x4 ///< double }; /// @brief Data set value variant - using DataSetValue = std::variant; + using DataSetValue = std::variant; /// @brief One entry in a data set. Has necessary interface to be work with maps. struct DataSetEntry @@ -79,8 +172,8 @@ namespace mtconnect::entity { /// @param key the key /// @param value the value as a DataSet /// @param removed `true` if the key has been removed - DataSetEntry(std::string key, DataSet &value, bool removed = false) - : m_key(std::move(key)), m_value(DataSetWrapper(value)), + DataSetEntry(std::string key, TableRow &value, bool removed = false) + : m_key(std::move(key)), m_value(std::move(value)), m_removed(removed) {} @@ -97,7 +190,13 @@ namespace mtconnect::entity { DataSetEntry(const DataSetEntry &other) = default; DataSetEntry() : m_removed(false) {} - DataSetEntry &operator=(const DataSetEntry &other); + DataSetEntry &operator=(const DataSetEntry &other) + { + m_key = other.m_key; + m_value = other.m_value; + m_removed = other.m_removed; + return *this; + } bool operator==(const DataSetEntry &other) const { return m_key == other.m_key; } bool operator<(const DataSetEntry &other) const { return m_key < other.m_key; } @@ -121,67 +220,57 @@ namespace mtconnect::entity { /// @param key the key /// @return the typed value of the entry template - const T &get(const std::string &key) const; + 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; + 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); }; - inline DataSetWrapper::DataSetWrapper(const DataSet &entry) : m_storage(new DataSet(entry)) { ; } - inline DataSetWrapper::DataSetWrapper(const DataSetWrapper &entry) - : m_storage(new DataSet(*entry.m_storage)) - { - ; - } - inline DataSetWrapper::DataSetWrapper() : m_storage(new DataSet()) { ; } - - inline DataSetEntry &DataSetEntry::operator=(const DataSetEntry &other) - { - m_key = other.m_key; - m_value = other.m_value; - m_removed = other.m_removed; - return *this; - } - - inline bool DataSetWrapper::operator==(const DataSetWrapper &other) const noexcept - { - return *m_storage == *other.m_storage; - } - - inline DataSetWrapper &DataSetWrapper::operator=(const DataSetWrapper &other) - { - if (this != &other) - { - m_storage.reset(new DataSet(*other.m_storage)); - } - return *this; - } - - - /// @brief Data Set Value type enumeration - enum class DataSetValueType : std::uint16_t - { - EMPTY = 0x0, ///< monostate for no value - DATA_SET = 0x01, ///< data set member for tables - STRING = 0x02, ///< string value - INTEGER = 0x3, ///< 64 bit integer - DOUBLE = 0x4 ///< double - }; - /// @brief Equality visitor for a DataSetValue struct DataSetValueSame { DataSetValueSame(const DataSetValue &other) : m_other(other) {} - bool operator()(const DataSet &v); + /// @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 @@ -190,58 +279,13 @@ namespace mtconnect::entity { template bool operator()(const T &v) { - return std::holds_alternative(m_other) && std::get(m_other) == v; + return std::holds_alternative(m_other) && std::get(m_other) == v; } private: const DataSetValue &m_other; }; - /// @brief Get a typed value from a data set - /// @tparam T the data type - /// @param key the key to search for - /// @return a typed value reference - /// @throws std::bad_variant_access when type is incorrect - template - const T &DataSet::get(const std::string &key) const - { - return std::get(find(DataSetEntry(key))->m_value); - } - - /// @brief Get a typed value if available - /// @tparam T they type - /// @param key the key to search for - /// @return an opton typed result - template - const std::optional DataSet::maybeGet(const std::string &key) const - { - auto v = find(DataSetEntry(key)); - if (v == end()) - return std::nullopt; - else - return std::get(v->m_value); - } - - inline bool DataSetValueSame::operator()(const DataSet &v) - { - if (!std::holds_alternative(m_other)) - return false; - - const DataSet &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() || !std::visit(DataSetValueSame(e2->m_value), e1.m_value)) - return false; - } - - return true; - } - inline bool DataSetEntry::same(const DataSetEntry &other) const { return m_key == other.m_key && m_removed == other.m_removed && diff --git a/src/mtconnect/entity/entity.cpp b/src/mtconnect/entity/entity.cpp index 99e0b409c..294d3abd5 100644 --- a/src/mtconnect/entity/entity.cpp +++ b/src/mtconnect/entity/entity.cpp @@ -76,7 +76,9 @@ namespace mtconnect::entity { } inline static void hash(boost::uuids::detail::sha1 &sha1, const DataSet &set); + inline static void hash(boost::uuids::detail::sha1 &sha1, const TableRow &set); + template struct HashVisitor { HashVisitor(boost::uuids::detail::sha1 &sha1) : m_sha1(sha1) {} @@ -102,7 +104,7 @@ namespace mtconnect::entity { auto c = arg.time_since_epoch().count(); m_sha1.process_bytes(&c, sizeof(c)); } - void operator()(const DataSet &arg) { hash(m_sha1, arg); } + void operator()(const ST &arg) { hash(m_sha1, arg); } void operator()(const std::nullptr_t &arg) { m_sha1.process_bytes("NULL", 4); } boost::uuids::detail::sha1 &m_sha1; @@ -119,11 +121,22 @@ namespace mtconnect::entity { } else { - HashVisitor visitor(sha1); + HashVisitor visitor(sha1); visit(visitor, e.m_value); } } } + + inline static void hash(boost::uuids::detail::sha1 &sha1, const TableRow &set) + { + for (auto &e : set) + { + sha1.process_bytes(e.m_key.c_str(), e.m_key.size()); + HashVisitor visitor(sha1); + visit(visitor, e.m_value); + } + } + void Entity::hash(boost::uuids::detail::sha1 &sha1, const boost::unordered_set &skip) const @@ -137,7 +150,7 @@ namespace mtconnect::entity { { const auto &value = e.second; sha1.process_bytes(e.first.c_str(), e.first.size()); - HashVisitor visitor(sha1); + HashVisitor visitor(sha1); visit(visitor, value); } } diff --git a/src/mtconnect/entity/entity.hpp b/src/mtconnect/entity/entity.hpp index d837667b0..2684e734a 100644 --- a/src/mtconnect/entity/entity.hpp +++ b/src/mtconnect/entity/entity.hpp @@ -415,6 +415,7 @@ namespace mtconnect { } protected: + template friend struct HashVisitor; /// @brief Computes the sha1 hash of the entity skipping properties in `skip` diff --git a/src/mtconnect/entity/json_printer.hpp b/src/mtconnect/entity/json_printer.hpp index 424b7617c..ba4746000 100644 --- a/src/mtconnect/entity/json_printer.hpp +++ b/src/mtconnect/entity/json_printer.hpp @@ -31,6 +31,11 @@ namespace mtconnect::entity { protected: struct PropertyVisitor { + PropertyVisitor(T &writer, JsonPrinter &printer, std::optional> &obj, + const EntityPtr &entity) + : m_obj(obj), m_printer(printer), m_entity(entity), m_writer(writer) + {} + void operator()(const EntityPtr &arg) { m_obj->Key(m_key->c_str()); @@ -88,11 +93,6 @@ namespace mtconnect::entity { m_obj->Add(arg); } - PropertyVisitor(T &writer, JsonPrinter &printer, std::optional> &obj, - const EntityPtr &entity) - : m_obj(obj), m_printer(printer), m_entity(entity), m_writer(writer) - {} - std::optional> &m_obj; JsonPrinter &m_printer; const EntityPtr &m_entity; @@ -222,26 +222,35 @@ namespace mtconnect::entity { struct DataSetVisitor { - void operator()(const std::monostate &) {} + DataSetVisitor(T &writer, JsonPrinter &printer, AutoJsonObject &obj) + : m_writer(writer), m_printer(printer), m_obj(obj) + {} + + void operator()(const std::monostate &) {} void operator()(const std::string &st) { m_obj.AddPairs(*m_key, st); } void operator()(const int64_t &i) { m_obj.AddPairs(*m_key, i); } void operator()(const double &d) { m_obj.AddPairs(*m_key, d); } - void operator()(const DataSet &arg) + void operator()(const TableRow &arg) { AutoJsonObject row(m_writer, *m_key); DataSetVisitor visitor(m_writer, m_printer, row); for (auto &c : arg) { - visitor.m_key = &c.m_key; - visit(visitor, c.m_value); + if (c.m_removed) + { + row.Key(c.m_key); + AutoJsonObject rem(m_writer); + rem.AddPairs("removed", true); + } + else + { + visitor.m_key = &c.m_key; + visit(visitor, c.m_value); + } } } - DataSetVisitor(T &writer, JsonPrinter &printer, AutoJsonObject &obj) - : m_writer(writer), m_printer(printer), m_obj(obj) - {} - T &m_writer; JsonPrinter &m_printer; AutoJsonObject &m_obj; diff --git a/src/mtconnect/entity/xml_parser.cpp b/src/mtconnect/entity/xml_parser.cpp index 7ed6daa5e..435fa1bd1 100644 --- a/src/mtconnect/entity/xml_parser.cpp +++ b/src/mtconnect/entity/xml_parser.cpp @@ -98,7 +98,8 @@ namespace mtconnect::entity { return boost::spirit::qi::parse(first, last, parser, value) && first == last; } - static void parseDataSet(xmlNodePtr node, DataSet &dataSet, bool table, bool cell = false) + template + static void parseDataSet(xmlNodePtr node, ST &dataSet, bool table, bool cell = false) { for (xmlNodePtr child = node->children; child; child = child->next) { @@ -123,14 +124,17 @@ namespace mtconnect::entity { } } - DataSetValue value; + VT value; auto valueNode = child->children; if (valueNode) { if (table && !cell) { - DataSet &ds = value.emplace(); - parseDataSet(child, ds, true, true); + if constexpr (std::is_same_v) + { + TableRow &row = value.template emplace(); + parseDataSet(child, row, true, true); + } } else if (valueNode->type == XML_TEXT_NODE) { @@ -245,7 +249,7 @@ namespace mtconnect::entity { if (ef->isDataSet(name)) { auto ds = &properties[name].emplace(); - parseDataSet(child, *ds, ef->isTable(name)); + parseDataSet(child, *ds, ef->isTable(name)); } else if (simple) { diff --git a/src/mtconnect/entity/xml_printer.cpp b/src/mtconnect/entity/xml_printer.cpp index 799cf2561..f12ae1cd0 100644 --- a/src/mtconnect/entity/xml_printer.cpp +++ b/src/mtconnect/entity/xml_printer.cpp @@ -102,13 +102,17 @@ namespace mtconnect { [&writer, &attrs](const double &d) { addSimpleElement(writer, "Entry", format(d), attrs); }, - [&writer, &attrs](const DataSet &row) { + [&writer, &attrs](const TableRow &row) { // Table AutoElement ele(writer, "Entry"); addAttributes(writer, attrs); for (auto &c : row) { map attrs = {{"key", c.m_key}}; + if (c.m_removed) + { + attrs["removed"] = "true"; + } visit(overloaded { [&writer, &attrs](const string &s) { addSimpleElement(writer, "Cell", s, attrs); diff --git a/src/mtconnect/pipeline/json_mapper.cpp b/src/mtconnect/pipeline/json_mapper.cpp index c92749eb3..38997fad3 100644 --- a/src/mtconnect/pipeline/json_mapper.cpp +++ b/src/mtconnect/pipeline/json_mapper.cpp @@ -41,6 +41,7 @@ using namespace std; namespace rj = ::rapidjson; namespace mtconnect::pipeline { + using namespace mtconnect::entity; enum class Expectation { NONE, @@ -232,10 +233,13 @@ namespace mtconnect::pipeline { int m_depth {0}; }; - /// @brief SAX Parser handler for JSON Parsing - struct DataSetHandler : rj::BaseReaderHandler, DataSetHandler> + /// @brief SAX Parser handler for JSON DataSet Parsing + template> + struct DataSetHandler : rj::BaseReaderHandler> { - DataSetHandler(entity::DataSet &set, optional key, bool table = false) + using Ch = typename Encoding::Ch; + + DataSetHandler(ST &set, optional key, bool table = false) : m_set(set), m_table(table) { if (key) @@ -255,7 +259,7 @@ namespace mtconnect::pipeline { if (m_expectation != Expectation::VALUE) return false; - m_entry.m_value.emplace(); + m_entry.m_value.template emplace(); m_entry.m_removed = true; return true; } @@ -269,7 +273,7 @@ namespace mtconnect::pipeline { if (m_expectation != Expectation::VALUE) return false; - m_entry.m_value.emplace(i); + m_entry.m_value.template emplace(i); return true; } bool Double(double d) @@ -277,7 +281,7 @@ namespace mtconnect::pipeline { if (m_expectation != Expectation::VALUE) return false; - m_entry.m_value.emplace(d); + m_entry.m_value.template emplace(d); return true; } bool RawNumber(const Ch *str, rj::SizeType length, bool copy) @@ -289,7 +293,7 @@ namespace mtconnect::pipeline { if (m_expectation != Expectation::VALUE) return false; - m_entry.m_value.emplace(str, length); + m_entry.m_value.template emplace((const char *) str, length); return true; } bool StartObject() @@ -313,7 +317,7 @@ namespace mtconnect::pipeline { { // Check for resetTriggered m_expectation = Expectation::VALUE; - m_entry.m_key = string(str, length); + m_entry.m_key = std::string((const char *) str, length); return true; } bool EndObject(rj::SizeType memberCount) @@ -344,10 +348,17 @@ namespace mtconnect::pipeline { if (m_expectation == Expectation::OBJECT) { - DataSetHandler handler(m_set, nullopt, m_table); - auto success = handler(reader, buff); - if (!success) - return success; + if constexpr (is_same_v) + { + DataSetHandler handler(m_set, nullopt, m_table); + auto success = handler(reader, buff); + if (!success) + return success; + } + else + { + return false; + } } else { @@ -358,12 +369,19 @@ namespace mtconnect::pipeline { if (m_expectation == Expectation::ROW) { // For tables, recurse down to read the entry data set - auto &row = m_entry.m_value.emplace(); - DataSetHandler handler(row, nullopt, false); - auto success = handler(reader, buff); - if (!success) - return success; - m_expectation = Expectation::VALUE; + if constexpr (std::is_same_v) + { + auto &row = m_entry.m_value.template emplace(); + DataSetHandler handler(row, nullopt, false); + auto success = handler(reader, buff); + if (!success) + return success; + m_expectation = Expectation::VALUE; + } + else + { + return false; + } } if (m_expectation == Expectation::VALUE) @@ -376,7 +394,7 @@ namespace mtconnect::pipeline { // Try again m_set.insert(m_entry); } - m_entry.m_value.emplace(); + m_entry.m_value.template emplace(); } } @@ -385,8 +403,8 @@ namespace mtconnect::pipeline { return true; } - entity::DataSet &m_set; - entity::DataSetEntry m_entry; + ST &m_set; + ET m_entry; optional m_resetTriggered; bool m_table {false}; bool m_done {false}; @@ -586,7 +604,7 @@ namespace mtconnect::pipeline { { auto &value = m_props["VALUE"]; DataSet &set = value.emplace(); - DataSetHandler handler(set, m_key, m_dataItem->isTable()); + DataSetHandler handler(set, m_key, m_dataItem->isTable()); if (!handler(reader, buff)) return false; m_expectation = Expectation::KEY; diff --git a/src/mtconnect/pipeline/response_document.cpp b/src/mtconnect/pipeline/response_document.cpp index 8798a63fe..a796c1ed8 100644 --- a/src/mtconnect/pipeline/response_document.cpp +++ b/src/mtconnect/pipeline/response_document.cpp @@ -221,7 +221,8 @@ namespace mtconnect::pipeline { return true; } - inline DataSetValue type(const string &s) + template + inline VT type(const string &s) { using namespace boost; if (s.empty()) @@ -259,11 +260,10 @@ namespace mtconnect::pipeline { if (table) { - entry.m_value.emplace(); - DataSet &row = get(entry.m_value); + TableRow &row = entry.m_value.emplace(); eachElement(n, "Cell", [&row](xmlNodePtr c) { - row.emplace(attributeValue(c, "key"), type(text(c))); + row.emplace(attributeValue(c, "key"), type(text(c))); return true; }); @@ -272,7 +272,7 @@ namespace mtconnect::pipeline { } else { - entry.m_value = type(text(n)); + entry.m_value = type(text(n)); } ds.insert(entry); diff --git a/src/mtconnect/ruby/ruby_entity.hpp b/src/mtconnect/ruby/ruby_entity.hpp index 47bf12738..c7f4ea49c 100644 --- a/src/mtconnect/ruby/ruby_entity.hpp +++ b/src/mtconnect/ruby/ruby_entity.hpp @@ -39,8 +39,50 @@ namespace mtconnect::ruby { using namespace data_item; using namespace entity; using namespace std; + + /// @brief Convert a table cell value to a ruby hash element. Recursive in the case of tables. + /// @param[in] mrb the mruby state + /// @param[in] value the data set value + /// @returns an mruby value + inline mrb_value toRuby(mrb_state *mrb, const TableCellValue &value) + { + mrb_value rv; + + rv = visit(overloaded {[](const std::monostate &v) -> mrb_value { return mrb_nil_value(); }, + [mrb](const std::string &v) -> mrb_value { + return mrb_str_new_cstr(mrb, v.c_str()); + }, + [mrb](const int64_t v) -> mrb_value { return mrb_int_value(mrb, v); }, + [mrb](const double v) -> mrb_value { return mrb_float_value(mrb, v); }}, + value); + + return rv; + } + + /// @brief Convert data set to ruby hash + /// + /// Recurses for tables. + /// + /// @param[in] mrb the mruby state + /// @param[in] value the data set + /// @returns an mruby value + inline mrb_value toRuby(mrb_state *mrb, const TableRow &set) + { + mrb_value hash = mrb_hash_new(mrb); + for (const auto &entry : set) + { + const auto &value = (entry.m_value); + + mrb_sym k = mrb_intern_cstr(mrb, entry.m_key.c_str()); + mrb_value v = toRuby(mrb, value); + + mrb_hash_set(mrb, hash, mrb_symbol_value(k), v); + } + + return hash; + } - inline mrb_value toRuby(mrb_state *mrb, const DataSet &value); + /// @brief Convert a data set value to a ruby hash element. Recursive in the case of tables. /// @param[in] mrb the mruby state /// @param[in] value the data set value @@ -53,7 +95,7 @@ namespace mtconnect::ruby { [mrb](const std::string &v) -> mrb_value { return mrb_str_new_cstr(mrb, v.c_str()); }, - [mrb](const entity::DataSet &v) -> mrb_value { return toRuby(mrb, v); }, + [mrb](const entity::TableRow &v) -> mrb_value { return toRuby(mrb, v); }, [mrb](const int64_t v) -> mrb_value { return mrb_int_value(mrb, v); }, [mrb](const double v) -> mrb_value { return mrb_float_value(mrb, v); }}, value); @@ -73,7 +115,7 @@ namespace mtconnect::ruby { mrb_value hash = mrb_hash_new(mrb); for (const auto &entry : set) { - auto value = (entry.m_value); + const auto &value = (entry.m_value); mrb_sym k = mrb_intern_cstr(mrb, entry.m_key.c_str()); mrb_value v = toRuby(mrb, value); @@ -83,8 +125,59 @@ namespace mtconnect::ruby { return hash; } - - inline void dataSetFromRuby(mrb_state *mrb, mrb_value value, DataSet &dataSet); + + /// @brief Convert a Ruby hash value to an MTConect DataSet + /// @param[in] mrb mruby state + /// @param[in] value the hash value to convert + /// @returns true if succesful + inline bool tableRowCellValueFromRuby(mrb_state *mrb, mrb_value value, TableCellValue &tcv) + { + bool res = true; + switch (mrb_type(value)) + { + case MRB_TT_SYMBOL: + case MRB_TT_STRING: + tcv.emplace(stringFromRuby(mrb, value)); + break; + + case MRB_TT_FIXNUM: + tcv.emplace(mrb_as_int(mrb, value)); + break; + + case MRB_TT_FLOAT: + tcv.emplace(mrb_as_float(mrb, value)); + break; + + default: + { + LOG(warning) << "DataSet cannot conver type: " + << stringFromRuby(mrb, mrb_inspect(mrb, value)); + res = false; + break; + } + } + return res; + } + + /// @brief convert a ruby hash table to a table row + inline void tableRowFromRuby(mrb_state *mrb, mrb_value value, TableRow &row) + { + auto hash = mrb_hash_ptr(value); + mrb_hash_foreach( + mrb, hash, + [](mrb_state *mrb, mrb_value key, mrb_value val, void *data) { + TableRow *row = static_cast(data); + string k = stringFromRuby(mrb, key); + TableCellValue tcv; + if (tableRowCellValueFromRuby(mrb, val, tcv)) + row->emplace(k, tcv); + + return 0; + }, + &row); + } + + /// @brief Convert a Ruby hash value to an MTConect DataSet /// @param[in] mrb mruby state /// @param[in] value the hash value to convert @@ -109,9 +202,9 @@ namespace mtconnect::ruby { case MRB_TT_HASH: { - DataSet inner; - dataSetFromRuby(mrb, value, inner); - dsv.emplace(inner); + TableRow inner; + tableRowFromRuby(mrb, value, inner); + dsv.emplace(inner); break; } @@ -126,7 +219,7 @@ namespace mtconnect::ruby { return res; } - /// @brief Convert a Ruby hash to an MTConect DataSet + /// @brief Convert a Ruby hash to an MTConnect DataSet /// @param[in] mrb mruby state /// @param[in] value the hash value to convert /// @param[out] dataSet the data set to populate diff --git a/test_package/data_item_mapping_test.cpp b/test_package/data_item_mapping_test.cpp index 349fc11e2..167cdcbdb 100644 --- a/test_package/data_item_mapping_test.cpp +++ b/test_package/data_item_mapping_test.cpp @@ -107,6 +107,7 @@ class DataItemMappingTest : public testing::Test }; inline DataSetEntry operator"" _E(const char *c, std::size_t) { return DataSetEntry(c); } +inline TableCell operator"" _C(const char *c, std::size_t) { return TableCell(c); } TEST_F(DataItemMappingTest, should_map_simple_sample) { @@ -409,20 +410,20 @@ TEST_F(DataItemMappingTest, should_map_an_event_table) auto &ds = set->getValue(); ASSERT_EQ(3, ds.size()); - DataSet &a = (DataSet&)get(ds.find("a"_E)->m_value); + const auto &a = get(ds.find("a"_E)->m_value); ASSERT_EQ(2, a.size()); - ASSERT_EQ(1, get(a.find("c"_E)->m_value)); - ASSERT_EQ(3.0, get(a.find("n"_E)->m_value)); + ASSERT_EQ(1, get(a.find("c"_C)->m_value)); + ASSERT_EQ(3.0, get(a.find("n"_C)->m_value)); - DataSet &b = (DataSet &) get(ds.find("b"_E)->m_value); + const auto &b = get(ds.find("b"_E)->m_value); ASSERT_EQ(2, a.size()); - ASSERT_EQ(2, get(b.find("d"_E)->m_value)); - ASSERT_EQ(3, get(b.find("e"_E)->m_value)); + ASSERT_EQ(2, get(b.find("d"_C)->m_value)); + ASSERT_EQ(3, get(b.find("e"_C)->m_value)); - DataSet &c = (DataSet &) get(ds.find("c"_E)->m_value); + const auto &c = get(ds.find("c"_E)->m_value); ASSERT_EQ(2, c.size()); - ASSERT_EQ("abc", get(c.find("x"_E)->m_value)); - ASSERT_EQ("def", get(c.find("y"_E)->m_value)); + ASSERT_EQ("abc", get(c.find("x"_C)->m_value)); + ASSERT_EQ("def", get(c.find("y"_C)->m_value)); } TEST_F(DataItemMappingTest, should_map_an_sample_table) @@ -445,20 +446,20 @@ TEST_F(DataItemMappingTest, should_map_an_sample_table) auto &ds = set->getValue(); ASSERT_EQ(3, ds.size()); - DataSet &a = (DataSet &) get(ds.find("a"_E)->m_value); + const auto &a = get(ds.find("a"_E)->m_value); ASSERT_EQ(2, a.size()); - ASSERT_EQ(1, get(a.find("c"_E)->m_value)); - ASSERT_EQ(3.0, get(a.find("n"_E)->m_value)); + ASSERT_EQ(1, get(a.find("c"_C)->m_value)); + ASSERT_EQ(3.0, get(a.find("n"_C)->m_value)); - DataSet &b = (DataSet &) get(ds.find("b"_E)->m_value); + const auto &b = get(ds.find("b"_E)->m_value); ASSERT_EQ(2, a.size()); - ASSERT_EQ(2, get(b.find("d"_E)->m_value)); - ASSERT_EQ(3, get(b.find("e"_E)->m_value)); + ASSERT_EQ(2, get(b.find("d"_C)->m_value)); + ASSERT_EQ(3, get(b.find("e"_C)->m_value)); - DataSet &c = (DataSet &) get(ds.find("c"_E)->m_value); + const auto &c = get(ds.find("c"_E)->m_value); ASSERT_EQ(2, c.size()); - ASSERT_EQ("abc", get(c.find("x"_E)->m_value)); - ASSERT_EQ("def", get(c.find("y"_E)->m_value)); + ASSERT_EQ("abc", get(c.find("x"_C)->m_value)); + ASSERT_EQ("def", get(c.find("y"_C)->m_value)); } TEST_F(DataItemMappingTest, should_handle_data_set_reset_trigger) diff --git a/test_package/embedded_ruby_test.cpp b/test_package/embedded_ruby_test.cpp index 46441cfe6..b83e4e24e 100644 --- a/test_package/embedded_ruby_test.cpp +++ b/test_package/embedded_ruby_test.cpp @@ -241,13 +241,13 @@ namespace { const DataSet &ds = cent1->getValue(); ASSERT_EQ(2, ds.size()); - const DataSet &row1 = ds.get("row1"); + const auto &row1 = ds.get("row1"); ASSERT_EQ(2, row1.size()); ASSERT_EQ("text1", row1.get("string")); ASSERT_NEAR(1.0, row1.get("float"), 0.000001); - const DataSet &row2 = ds.get("row2"); + const auto &row2 = ds.get("row2"); ASSERT_EQ(2, row2.size()); ASSERT_EQ("text2", row2.get("string")); diff --git a/test_package/entity_parser_test.cpp b/test_package/entity_parser_test.cpp index 813275c77..a5aa43e1e 100644 --- a/test_package/entity_parser_test.cpp +++ b/test_package/entity_parser_test.cpp @@ -372,13 +372,13 @@ TEST_F(EntityParserTest, should_parse_tables) auto entity = parser.parse(root, doc, errors); ASSERT_EQ("Root", entity->getName()); const DataSet &set = entity->get("Table"); - const DataSet &e1 = set.get("A"); + const auto &e1 = set.get("A"); ASSERT_EQ("abc", e1.get("text")); ASSERT_EQ(101, e1.get("int")); ASSERT_EQ(50.5, e1.get("double")); - const DataSet &e2 = set.get("B"); + const auto &e2 = set.get("B"); ASSERT_EQ("def", e2.get("text2")); ASSERT_EQ(102, e2.get("int2")); diff --git a/test_package/json_mapping_test.cpp b/test_package/json_mapping_test.cpp index 36bab3183..b4d06be49 100644 --- a/test_package/json_mapping_test.cpp +++ b/test_package/json_mapping_test.cpp @@ -748,9 +748,9 @@ TEST_F(JsonMappingTest, should_parse_tables) auto dsi = set1.begin(); ASSERT_EQ("r1", dsi->m_key); - ASSERT_TRUE(holds_alternative(dsi->m_value)); + ASSERT_TRUE(holds_alternative(dsi->m_value)); - auto &row1 = (DataSet &) get(dsi->m_value); + const auto &row1 = get(dsi->m_value); ASSERT_EQ(1, row1.size()); auto ri = row1.begin(); @@ -758,7 +758,7 @@ TEST_F(JsonMappingTest, should_parse_tables) ASSERT_EQ(123.45, get(ri->m_value)); dsi++; - auto &row2 = (DataSet &) get(dsi->m_value); + const auto &row2 = get(dsi->m_value); ASSERT_EQ(2, row2.size()); ri = row2.begin(); @@ -783,9 +783,9 @@ TEST_F(JsonMappingTest, should_parse_tables) dsi = set2.begin(); ASSERT_EQ("r1", dsi->m_key); - ASSERT_TRUE(holds_alternative(dsi->m_value)); + ASSERT_TRUE(holds_alternative(dsi->m_value)); - auto &row3 = (DataSet &) get(dsi->m_value); + const auto &row3 = get(dsi->m_value); ASSERT_EQ(2, row3.size()); ri = row3.begin(); diff --git a/test_package/response_document_test.cpp b/test_package/response_document_test.cpp index c3a05208d..f02f3f0db 100644 --- a/test_package/response_document_test.cpp +++ b/test_package/response_document_test.cpp @@ -290,7 +290,7 @@ TEST_F(ResponseDocumentTest, should_parse_tables) ASSERT_EQ("W1", dse->m_key); ASSERT_FALSE(dse->m_removed); - const DataSet &v1 = get(dse->m_value); + const auto &v1 = get(dse->m_value); ASSERT_EQ(3, v1.size()); auto v1i = v1.begin(); @@ -307,7 +307,7 @@ TEST_F(ResponseDocumentTest, should_parse_tables) ASSERT_EQ("W2", dse->m_key); ASSERT_FALSE(dse->m_removed); - const DataSet &v2 = get(dse->m_value); + const auto &v2 = get(dse->m_value); ASSERT_EQ(3, v2.size()); auto v2i = v2.begin(); @@ -324,7 +324,7 @@ TEST_F(ResponseDocumentTest, should_parse_tables) ASSERT_EQ("W3", dse->m_key); ASSERT_FALSE(dse->m_removed); - const DataSet &v3 = get(dse->m_value); + const auto &v3 = get(dse->m_value); ASSERT_EQ(3, v3.size()); auto v3i = v3.begin(); diff --git a/test_package/table_test.cpp b/test_package/table_test.cpp index 6febe9c06..abccd63b1 100644 --- a/test_package/table_test.cpp +++ b/test_package/table_test.cpp @@ -81,6 +81,7 @@ class TableTest : public testing::Test }; inline DataSetEntry operator"" _E(const char *c, std::size_t) { return DataSetEntry(c); } +inline TableCell operator"" _C(const char *c, std::size_t) { return TableCell(c); } TEST_F(TableTest, DataItem) { @@ -97,11 +98,11 @@ TEST_F(TableTest, test_simple_table_formats) ASSERT_TRUE(s1.parse("abc={a=1 b=2.0 c='abc'}", true)); ASSERT_EQ(1, s1.size()); - const DataSet &abc1 = get(s1.find("abc"_E)->m_value); + const auto &abc1 = get(s1.find("abc"_E)->m_value); ASSERT_EQ(3, abc1.size()); - ASSERT_EQ(1, get(abc1.find("a"_E)->m_value)); - ASSERT_EQ(2.0, get(abc1.find("b"_E)->m_value)); - ASSERT_EQ("abc", get(abc1.find("c"_E)->m_value)); + ASSERT_EQ(1, get(abc1.find("a"_C)->m_value)); + ASSERT_EQ(2.0, get(abc1.find("b"_C)->m_value)); + ASSERT_EQ("abc", get(abc1.find("c"_C)->m_value)); } TEST_F(TableTest, test_simple_table_formats_with_whitespace) @@ -110,11 +111,11 @@ TEST_F(TableTest, test_simple_table_formats_with_whitespace) ASSERT_TRUE(s1.parse("abc={ a=1 b=2.0 c='abc' }", true)); ASSERT_EQ(1, s1.size()); - const DataSet &abc1 = get(s1.find("abc"_E)->m_value); + const auto &abc1 = get(s1.find("abc"_E)->m_value); ASSERT_EQ(3, abc1.size()); - ASSERT_EQ(1, get(abc1.find("a"_E)->m_value)); - ASSERT_EQ(2.0, get(abc1.find("b"_E)->m_value)); - ASSERT_EQ("abc", get(abc1.find("c"_E)->m_value)); + ASSERT_EQ(1, get(abc1.find("a"_C)->m_value)); + ASSERT_EQ(2.0, get(abc1.find("b"_C)->m_value)); + ASSERT_EQ("abc", get(abc1.find("c"_C)->m_value)); } TEST_F(TableTest, test_simple_table_formats_with_quotes) @@ -123,11 +124,11 @@ TEST_F(TableTest, test_simple_table_formats_with_quotes) ASSERT_TRUE(s1.parse("abc=' a=1 b=2.0 c='abc''", true)); ASSERT_EQ(1, s1.size()); - const DataSet &abc1 = get(s1.find("abc"_E)->m_value); + const auto &abc1 = get(s1.find("abc"_E)->m_value); ASSERT_EQ(3, abc1.size()); - ASSERT_EQ(1, get(abc1.find("a"_E)->m_value)); - ASSERT_EQ(2.0, get(abc1.find("b"_E)->m_value)); - ASSERT_EQ("abc", get(abc1.find("c"_E)->m_value)); + ASSERT_EQ(1, get(abc1.find("a"_C)->m_value)); + ASSERT_EQ(2.0, get(abc1.find("b"_C)->m_value)); + ASSERT_EQ("abc", get(abc1.find("c"_C)->m_value)); } TEST_F(TableTest, test_simple_table_formats_with_double_quotes) @@ -136,11 +137,11 @@ TEST_F(TableTest, test_simple_table_formats_with_double_quotes) ASSERT_TRUE(s1.parse("abc=\" a=1 b=2.0 c='abc'\"", true)); ASSERT_EQ(1, s1.size()); - const DataSet &abc1 = get(s1.find("abc"_E)->m_value); + const auto &abc1 = get(s1.find("abc"_E)->m_value); ASSERT_EQ(3, abc1.size()); - ASSERT_EQ(1, get(abc1.find("a"_E)->m_value)); - ASSERT_EQ(2.0, get(abc1.find("b"_E)->m_value)); - ASSERT_EQ("abc", get(abc1.find("c"_E)->m_value)); + ASSERT_EQ(1, get(abc1.find("a"_C)->m_value)); + ASSERT_EQ(2.0, get(abc1.find("b"_C)->m_value)); + ASSERT_EQ("abc", get(abc1.find("c"_C)->m_value)); } TEST_F(TableTest, test_simple_table_formats_with_nested_braces) @@ -149,11 +150,11 @@ TEST_F(TableTest, test_simple_table_formats_with_nested_braces) ASSERT_TRUE(s1.parse("abc={ a=1 b=2.0 c={abc}}", true)); ASSERT_EQ(1, s1.size()); - const DataSet &abc1 = get(s1.find("abc"_E)->m_value); + const auto &abc1 = get(s1.find("abc"_E)->m_value); ASSERT_EQ(3, abc1.size()); - ASSERT_EQ(1, get(abc1.find("a"_E)->m_value)); - ASSERT_EQ(2.0, get(abc1.find("b"_E)->m_value)); - ASSERT_EQ("abc", get(abc1.find("c"_E)->m_value)); + ASSERT_EQ(1, get(abc1.find("a"_C)->m_value)); + ASSERT_EQ(2.0, get(abc1.find("b"_C)->m_value)); + ASSERT_EQ("abc", get(abc1.find("c"_C)->m_value)); } TEST_F(TableTest, test_simple_table_formats_with_removed_key) @@ -162,13 +163,13 @@ TEST_F(TableTest, test_simple_table_formats_with_removed_key) s1.parse("abc={ a=1 b=2.0 c={abc} d= e}", true); ASSERT_EQ(1, s1.size()); - const DataSet &abc1 = get(s1.find("abc"_E)->m_value); + const auto &abc1 = get(s1.find("abc"_E)->m_value); ASSERT_EQ(5, abc1.size()); - ASSERT_EQ(1, get(abc1.find("a"_E)->m_value)); - ASSERT_EQ(2.0, get(abc1.find("b"_E)->m_value)); - ASSERT_EQ("abc", get(abc1.find("c"_E)->m_value)); - ASSERT_TRUE(abc1.find("d"_E)->m_removed); - ASSERT_TRUE(abc1.find("e"_E)->m_removed); + ASSERT_EQ(1, get(abc1.find("a"_C)->m_value)); + ASSERT_EQ(2.0, get(abc1.find("b"_C)->m_value)); + ASSERT_EQ("abc", get(abc1.find("c"_C)->m_value)); + ASSERT_TRUE(abc1.find("d"_C)->m_removed); + ASSERT_TRUE(abc1.find("e"_C)->m_removed); } TEST_F(TableTest, test_mulitple_entries) @@ -177,18 +178,18 @@ TEST_F(TableTest, test_mulitple_entries) ASSERT_TRUE(s1.parse("abc={ a=1 b=2.0 c={abc} d= e} def={x=1.0 y=2.0}", true)); ASSERT_EQ(2, s1.size()); - const DataSet &abc = get(s1.find("abc"_E)->m_value); + const auto &abc = get(s1.find("abc"_E)->m_value); ASSERT_EQ(5, abc.size()); - ASSERT_EQ(1, get(abc.find("a"_E)->m_value)); - ASSERT_EQ(2.0, get(abc.find("b"_E)->m_value)); - ASSERT_EQ("abc", get(abc.find("c"_E)->m_value)); - ASSERT_TRUE(abc.find("d"_E)->m_removed); - ASSERT_TRUE(abc.find("e"_E)->m_removed); + ASSERT_EQ(1, get(abc.find("a"_C)->m_value)); + ASSERT_EQ(2.0, get(abc.find("b"_C)->m_value)); + ASSERT_EQ("abc", get(abc.find("c"_C)->m_value)); + ASSERT_TRUE(abc.find("d"_C)->m_removed); + ASSERT_TRUE(abc.find("e"_C)->m_removed); - const DataSet &def = get(s1.find("def"_E)->m_value); + const auto &def = get(s1.find("def"_E)->m_value); ASSERT_EQ(2, def.size()); - ASSERT_EQ(1.0, get(def.find("x"_E)->m_value)); - ASSERT_EQ(2.0, get(def.find("y"_E)->m_value)); + ASSERT_EQ(1.0, get(def.find("x"_C)->m_value)); + ASSERT_EQ(2.0, get(def.find("y"_C)->m_value)); } TEST_F(TableTest, test_removed_table_entry) @@ -230,24 +231,24 @@ TEST_F(TableTest, InitialSet) ASSERT_EQ(3, set1.size()); ASSERT_EQ(3, ce->get("count")); - const DataSet &g531 = get(set1.find("G53.1"_E)->m_value); + const auto &g531 = get(set1.find("G53.1"_E)->m_value); ASSERT_EQ((size_t)3, g531.size()); - ASSERT_EQ(1.0, get(g531.find("X"_E)->m_value)); - ASSERT_EQ(2.0, get(g531.find("Y"_E)->m_value)); - ASSERT_EQ(3.0, get(g531.find("Z"_E)->m_value)); + ASSERT_EQ(1.0, get(g531.find("X"_C)->m_value)); + ASSERT_EQ(2.0, get(g531.find("Y"_C)->m_value)); + ASSERT_EQ(3.0, get(g531.find("Z"_C)->m_value)); - const DataSet &g532 = get(set1.find("G53.2"_E)->m_value); + const auto &g532 = get(set1.find("G53.2"_E)->m_value); ASSERT_EQ((size_t)3, g532.size()); - ASSERT_EQ(4.0, get(g532.find("X"_E)->m_value)); - ASSERT_EQ(5.0, get(g532.find("Y"_E)->m_value)); - ASSERT_EQ(6.0, get(g532.find("Z"_E)->m_value)); + ASSERT_EQ(4.0, get(g532.find("X"_C)->m_value)); + ASSERT_EQ(5.0, get(g532.find("Y"_C)->m_value)); + ASSERT_EQ(6.0, get(g532.find("Z"_C)->m_value)); - const DataSet &g533 = get(set1.find("G53.3"_E)->m_value); + const auto &g533 = get(set1.find("G53.3"_E)->m_value); ASSERT_EQ((size_t)4, g533.size()); - ASSERT_EQ(7.0, get(g533.find("X"_E)->m_value)); - ASSERT_EQ(8.0, get(g533.find("Y"_E)->m_value)); - ASSERT_EQ(9, get(g533.find("Z"_E)->m_value)); - ASSERT_EQ(10.0, get(g533.find("U"_E)->m_value)); + ASSERT_EQ(7.0, get(g533.find("X"_C)->m_value)); + ASSERT_EQ(8.0, get(g533.find("Y"_C)->m_value)); + ASSERT_EQ(9, get(g533.find("Z"_C)->m_value)); + ASSERT_EQ(10.0, get(g533.find("U"_C)->m_value)); } #define ASSERT_TABLE_ENTRY(doc, var, key, cell, expected) \ From ea5c1e9ca1c1697975eb613c899d35c4ac948ca9 Mon Sep 17 00:00:00 2001 From: Will Sobel Date: Wed, 4 Jun 2025 16:42:46 -0400 Subject: [PATCH 3/6] Added additional docs to new code --- src/mtconnect/entity/data_set.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/mtconnect/entity/data_set.hpp b/src/mtconnect/entity/data_set.hpp index d64760eb0..3ccb51456 100644 --- a/src/mtconnect/entity/data_set.hpp +++ b/src/mtconnect/entity/data_set.hpp @@ -65,6 +65,8 @@ namespace mtconnect::entity { TableCell(const TableCell &other) = default; TableCell() {} + /// @brief copy another table cell + /// @param other the other cell TableCell &operator=(const TableCell &other) { m_key = other.m_key; @@ -76,8 +78,10 @@ namespace mtconnect::entity { bool operator==(const TableCell &other) const { return m_key == other.m_key; } bool operator<(const TableCell &other) const { return m_key < other.m_key; } + /// @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) {} /// @brief Compare the types are the same and the values are the same @@ -90,9 +94,12 @@ namespace mtconnect::entity { return std::holds_alternative(m_other) && std::get(m_other) == v; } + /// @brief the other value to compare const TableCellValue &m_other; }; + /// @brief Compares to cells + /// @param other the other cell bool same(const TableCell &other) const { const auto &ov = other.m_value; @@ -100,6 +107,8 @@ namespace mtconnect::entity { std::visit(SameValue(ov), m_value); } + /// @brief compares two cell values + /// @param other the other cell value to compare bool sameValue(const TableCell &other) const { auto &ov = other.m_value; @@ -190,6 +199,7 @@ namespace mtconnect::entity { 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; @@ -198,9 +208,12 @@ namespace mtconnect::entity { 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; From e1492eaa5ea80375abcaac06bda92111480b3e06 Mon Sep 17 00:00:00 2001 From: Will Sobel Date: Wed, 4 Jun 2025 16:47:34 -0400 Subject: [PATCH 4/6] Reformatted with clangformat --- src/mtconnect/entity/data_set.cpp | 24 +++---- src/mtconnect/entity/data_set.hpp | 74 ++++++++++---------- src/mtconnect/entity/entity.cpp | 5 +- src/mtconnect/entity/entity.hpp | 2 +- src/mtconnect/entity/json_printer.hpp | 10 +-- src/mtconnect/entity/xml_parser.cpp | 2 +- src/mtconnect/pipeline/json_mapper.cpp | 11 ++- src/mtconnect/pipeline/response_document.cpp | 2 +- src/mtconnect/ruby/ruby_entity.hpp | 62 ++++++++-------- 9 files changed, 93 insertions(+), 99 deletions(-) diff --git a/src/mtconnect/entity/data_set.cpp b/src/mtconnect/entity/data_set.cpp index d3101abeb..4358e762c 100644 --- a/src/mtconnect/entity/data_set.cpp +++ b/src/mtconnect/entity/data_set.cpp @@ -65,7 +65,7 @@ namespace std { s << t.m_key << "=" << t.m_value << (t.m_removed ? ":removed" : ""); return s; } - + static inline ostream &operator<<(ostream &s, const mtconnect::observation::TableCell &t) { s << t.m_key << "=" << t.m_value; @@ -81,24 +81,22 @@ namespace mtconnect::entity { /// @brief Functions called when parsing data sets namespace DataSetParserActions { inline static void add_entry_f(DataSet &ds, const DataSetEntry &entry) { ds.emplace(entry); } - - struct TableCellConverter { - TableCellConverter(TableCellValue &value) : m_value(value) { } - - void operator()(const TableRow &row) - { - LOG(error) << "Table row cannot recurse"; - } - - template + + struct TableCellConverter + { + TableCellConverter(TableCellValue &value) : m_value(value) {} + + void operator()(const TableRow &row) { LOG(error) << "Table row cannot recurse"; } + + template void operator()(const T &v) { m_value.emplace(v); } - + TableCellValue &m_value; }; - + inline static void add_cell_f(TableRow &row, const DataSetEntry &entry) { TableCell cell(entry.m_key); diff --git a/src/mtconnect/entity/data_set.hpp b/src/mtconnect/entity/data_set.hpp index 3ccb51456..c3b547fb9 100644 --- a/src/mtconnect/entity/data_set.hpp +++ b/src/mtconnect/entity/data_set.hpp @@ -33,15 +33,15 @@ namespace mtconnect::entity { /// @brief Data Set Value type enumeration enum class TabelCellType : std::uint16_t { - EMPTY = 0x0, ///< monostate for no value - STRING = 0x02, ///< string value - INTEGER = 0x3, ///< 64 bit integer - DOUBLE = 0x4 ///< double + EMPTY = 0x0, ///< monostate for no value + STRING = 0x02, ///< string value + INTEGER = 0x3, ///< 64 bit integer + DOUBLE = 0x4 ///< double }; - + /// @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 { @@ -49,22 +49,22 @@ namespace mtconnect::entity { /// @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) + : 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) + : 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 TableCell(std::string key) : m_key(std::move(key)), m_value(std::string("")) {} TableCell(const TableCell &other) = default; TableCell() {} - + /// @brief copy another table cell /// @param other the other cell TableCell &operator=(const TableCell &other) @@ -74,16 +74,16 @@ namespace mtconnect::entity { m_removed = other.m_removed; return *this; } - + bool operator==(const TableCell &other) const { return m_key == other.m_key; } bool operator<(const TableCell &other) const { return m_key < other.m_key; } - + /// @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) {} - + /// @brief Compare the types are the same and the values are the same /// @tparam T the data type /// @param v the other value @@ -91,22 +91,22 @@ namespace mtconnect::entity { template bool operator()(const T &v) { - return std::holds_alternative(m_other) && std::get(m_other) == v; + return std::holds_alternative(m_other) && std::get(m_other) == v; } - + /// @brief the other value to compare const TableCellValue &m_other; }; - + /// @brief Compares to cells /// @param other the other cell bool same(const TableCell &other) const { const auto &ov = other.m_value; return m_key == other.m_key && m_removed == other.m_removed && - std::visit(SameValue(ov), m_value); + std::visit(SameValue(ov), m_value); } - + /// @brief compares two cell values /// @param other the other cell value to compare bool sameValue(const TableCell &other) const @@ -114,20 +114,19 @@ namespace mtconnect::entity { auto &ov = other.m_value; return std::visit(SameValue(ov), m_value); } - + std::string m_key; TableCellValue m_value; - bool m_removed { false }; + 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 @@ -137,7 +136,7 @@ namespace mtconnect::entity { { 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 @@ -152,15 +151,15 @@ namespace mtconnect::entity { return std::get(v->m_value); } }; - + /// @brief Data Set Value type enumeration enum class DataSetValueType : std::uint16_t { - EMPTY = 0x0, ///< monostate for no value + EMPTY = 0x0, ///< monostate for no value TABLE_ROW = 0x01, ///< data set member for tables - STRING = 0x02, ///< string value - INTEGER = 0x3, ///< 64 bit integer - DOUBLE = 0x4 ///< double + STRING = 0x02, ///< string value + INTEGER = 0x3, ///< 64 bit integer + DOUBLE = 0x4 ///< double }; /// @brief Data set value variant @@ -182,8 +181,7 @@ namespace mtconnect::entity { /// @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) + : m_key(std::move(key)), m_value(std::move(value)), m_removed(removed) {} /// @brief Create an entry for a data set @@ -195,7 +193,9 @@ namespace mtconnect::entity { {} /// @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(std::string key) + : m_key(std::move(key)), m_value(std::string("")), m_removed(false) + {} DataSetEntry(const DataSetEntry &other) = default; DataSetEntry() : m_removed(false) {} @@ -269,19 +269,19 @@ namespace mtconnect::entity { { 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; } @@ -292,7 +292,7 @@ namespace mtconnect::entity { template bool operator()(const T &v) { - return std::holds_alternative(m_other) && std::get(m_other) == v; + return std::holds_alternative(m_other) && std::get(m_other) == v; } private: diff --git a/src/mtconnect/entity/entity.cpp b/src/mtconnect/entity/entity.cpp index 294d3abd5..9a55ca18f 100644 --- a/src/mtconnect/entity/entity.cpp +++ b/src/mtconnect/entity/entity.cpp @@ -78,7 +78,7 @@ namespace mtconnect::entity { inline static void hash(boost::uuids::detail::sha1 &sha1, const DataSet &set); inline static void hash(boost::uuids::detail::sha1 &sha1, const TableRow &set); - template + template struct HashVisitor { HashVisitor(boost::uuids::detail::sha1 &sha1) : m_sha1(sha1) {} @@ -126,7 +126,7 @@ namespace mtconnect::entity { } } } - + inline static void hash(boost::uuids::detail::sha1 &sha1, const TableRow &set) { for (auto &e : set) @@ -137,7 +137,6 @@ namespace mtconnect::entity { } } - void Entity::hash(boost::uuids::detail::sha1 &sha1, const boost::unordered_set &skip) const { diff --git a/src/mtconnect/entity/entity.hpp b/src/mtconnect/entity/entity.hpp index 2684e734a..aa6ac8a19 100644 --- a/src/mtconnect/entity/entity.hpp +++ b/src/mtconnect/entity/entity.hpp @@ -415,7 +415,7 @@ namespace mtconnect { } protected: - template + template friend struct HashVisitor; /// @brief Computes the sha1 hash of the entity skipping properties in `skip` diff --git a/src/mtconnect/entity/json_printer.hpp b/src/mtconnect/entity/json_printer.hpp index ba4746000..47e64f648 100644 --- a/src/mtconnect/entity/json_printer.hpp +++ b/src/mtconnect/entity/json_printer.hpp @@ -33,9 +33,9 @@ namespace mtconnect::entity { { PropertyVisitor(T &writer, JsonPrinter &printer, std::optional> &obj, const EntityPtr &entity) - : m_obj(obj), m_printer(printer), m_entity(entity), m_writer(writer) + : m_obj(obj), m_printer(printer), m_entity(entity), m_writer(writer) {} - + void operator()(const EntityPtr &arg) { m_obj->Key(m_key->c_str()); @@ -223,10 +223,10 @@ namespace mtconnect::entity { struct DataSetVisitor { DataSetVisitor(T &writer, JsonPrinter &printer, AutoJsonObject &obj) - : m_writer(writer), m_printer(printer), m_obj(obj) + : m_writer(writer), m_printer(printer), m_obj(obj) {} - - void operator()(const std::monostate &) {} + + void operator()(const std::monostate &) {} void operator()(const std::string &st) { m_obj.AddPairs(*m_key, st); } void operator()(const int64_t &i) { m_obj.AddPairs(*m_key, i); } void operator()(const double &d) { m_obj.AddPairs(*m_key, d); } diff --git a/src/mtconnect/entity/xml_parser.cpp b/src/mtconnect/entity/xml_parser.cpp index 435fa1bd1..395270874 100644 --- a/src/mtconnect/entity/xml_parser.cpp +++ b/src/mtconnect/entity/xml_parser.cpp @@ -98,7 +98,7 @@ namespace mtconnect::entity { return boost::spirit::qi::parse(first, last, parser, value) && first == last; } - template + template static void parseDataSet(xmlNodePtr node, ST &dataSet, bool table, bool cell = false) { for (xmlNodePtr child = node->children; child; child = child->next) diff --git a/src/mtconnect/pipeline/json_mapper.cpp b/src/mtconnect/pipeline/json_mapper.cpp index 38997fad3..6f4a072c4 100644 --- a/src/mtconnect/pipeline/json_mapper.cpp +++ b/src/mtconnect/pipeline/json_mapper.cpp @@ -234,13 +234,12 @@ namespace mtconnect::pipeline { }; /// @brief SAX Parser handler for JSON DataSet Parsing - template> + template > struct DataSetHandler : rj::BaseReaderHandler> { using Ch = typename Encoding::Ch; - - DataSetHandler(ST &set, optional key, bool table = false) - : m_set(set), m_table(table) + + DataSetHandler(ST &set, optional key, bool table = false) : m_set(set), m_table(table) { if (key) { @@ -293,7 +292,7 @@ namespace mtconnect::pipeline { if (m_expectation != Expectation::VALUE) return false; - m_entry.m_value.template emplace((const char *) str, length); + m_entry.m_value.template emplace((const char *)str, length); return true; } bool StartObject() @@ -317,7 +316,7 @@ namespace mtconnect::pipeline { { // Check for resetTriggered m_expectation = Expectation::VALUE; - m_entry.m_key = std::string((const char *) str, length); + m_entry.m_key = std::string((const char *)str, length); return true; } bool EndObject(rj::SizeType memberCount) diff --git a/src/mtconnect/pipeline/response_document.cpp b/src/mtconnect/pipeline/response_document.cpp index a796c1ed8..42f4e0e08 100644 --- a/src/mtconnect/pipeline/response_document.cpp +++ b/src/mtconnect/pipeline/response_document.cpp @@ -221,7 +221,7 @@ namespace mtconnect::pipeline { return true; } - template + template inline VT type(const string &s) { using namespace boost; diff --git a/src/mtconnect/ruby/ruby_entity.hpp b/src/mtconnect/ruby/ruby_entity.hpp index c7f4ea49c..3ad5fde06 100644 --- a/src/mtconnect/ruby/ruby_entity.hpp +++ b/src/mtconnect/ruby/ruby_entity.hpp @@ -39,7 +39,7 @@ namespace mtconnect::ruby { using namespace data_item; using namespace entity; using namespace std; - + /// @brief Convert a table cell value to a ruby hash element. Recursive in the case of tables. /// @param[in] mrb the mruby state /// @param[in] value the data set value @@ -47,18 +47,18 @@ namespace mtconnect::ruby { inline mrb_value toRuby(mrb_state *mrb, const TableCellValue &value) { mrb_value rv; - + rv = visit(overloaded {[](const std::monostate &v) -> mrb_value { return mrb_nil_value(); }, - [mrb](const std::string &v) -> mrb_value { - return mrb_str_new_cstr(mrb, v.c_str()); - }, - [mrb](const int64_t v) -> mrb_value { return mrb_int_value(mrb, v); }, - [mrb](const double v) -> mrb_value { return mrb_float_value(mrb, v); }}, + [mrb](const std::string &v) -> mrb_value { + return mrb_str_new_cstr(mrb, v.c_str()); + }, + [mrb](const int64_t v) -> mrb_value { return mrb_int_value(mrb, v); }, + [mrb](const double v) -> mrb_value { return mrb_float_value(mrb, v); }}, value); - + return rv; } - + /// @brief Convert data set to ruby hash /// /// Recurses for tables. @@ -72,17 +72,16 @@ namespace mtconnect::ruby { for (const auto &entry : set) { const auto &value = (entry.m_value); - + mrb_sym k = mrb_intern_cstr(mrb, entry.m_key.c_str()); mrb_value v = toRuby(mrb, value); - + mrb_hash_set(mrb, hash, mrb_symbol_value(k), v); } - + return hash; } - /// @brief Convert a data set value to a ruby hash element. Recursive in the case of tables. /// @param[in] mrb the mruby state /// @param[in] value the data set value @@ -125,7 +124,7 @@ namespace mtconnect::ruby { return hash; } - + /// @brief Convert a Ruby hash value to an MTConect DataSet /// @param[in] mrb mruby state /// @param[in] value the hash value to convert @@ -139,45 +138,44 @@ namespace mtconnect::ruby { case MRB_TT_STRING: tcv.emplace(stringFromRuby(mrb, value)); break; - + case MRB_TT_FIXNUM: tcv.emplace(mrb_as_int(mrb, value)); break; - + case MRB_TT_FLOAT: tcv.emplace(mrb_as_float(mrb, value)); break; - + default: { LOG(warning) << "DataSet cannot conver type: " - << stringFromRuby(mrb, mrb_inspect(mrb, value)); + << stringFromRuby(mrb, mrb_inspect(mrb, value)); res = false; break; } } return res; } - + /// @brief convert a ruby hash table to a table row inline void tableRowFromRuby(mrb_state *mrb, mrb_value value, TableRow &row) { auto hash = mrb_hash_ptr(value); mrb_hash_foreach( - mrb, hash, - [](mrb_state *mrb, mrb_value key, mrb_value val, void *data) { - TableRow *row = static_cast(data); - string k = stringFromRuby(mrb, key); - TableCellValue tcv; - if (tableRowCellValueFromRuby(mrb, val, tcv)) - row->emplace(k, tcv); - - return 0; - }, - &row); + mrb, hash, + [](mrb_state *mrb, mrb_value key, mrb_value val, void *data) { + TableRow *row = static_cast(data); + string k = stringFromRuby(mrb, key); + TableCellValue tcv; + if (tableRowCellValueFromRuby(mrb, val, tcv)) + row->emplace(k, tcv); + + return 0; + }, + &row); } - - + /// @brief Convert a Ruby hash value to an MTConect DataSet /// @param[in] mrb mruby state /// @param[in] value the hash value to convert From 59b495ff21b9031d3a742d380746a0459d250a68 Mon Sep 17 00:00:00 2001 From: Will Sobel Date: Wed, 4 Jun 2025 17:04:30 -0400 Subject: [PATCH 5/6] Changed name of ValidateTimestampTest to CorrectTimestampsTest --- test_package/correct_timestamp_test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test_package/correct_timestamp_test.cpp b/test_package/correct_timestamp_test.cpp index 814f19a6a..685b2c051 100644 --- a/test_package/correct_timestamp_test.cpp +++ b/test_package/correct_timestamp_test.cpp @@ -73,7 +73,7 @@ class MockPipelineContract : public PipelineContract std::map &m_dataItems; }; -class ValidateTimestampTest : public testing::Test +class CorrectTimestampTest : public testing::Test { protected: void SetUp() override @@ -115,7 +115,7 @@ class ValidateTimestampTest : public testing::Test ComponentPtr m_component; }; -TEST_F(ValidateTimestampTest, should_not_change_timestamp_if_time_is_moving_forward) +TEST_F(CorrectTimestampTest, should_not_change_timestamp_if_time_is_moving_forward) { makeDataItem({{"id", "a"s}, {"type", "EXECUTION"s}, {"category", "EVENT"s}}); @@ -140,7 +140,7 @@ TEST_F(ValidateTimestampTest, should_not_change_timestamp_if_time_is_moving_forw ASSERT_EQ(now + 1s, obs2->getTimestamp()); } -TEST_F(ValidateTimestampTest, should_change_timestamp_if_time_is_moving_backward) +TEST_F(CorrectTimestampTest, should_change_timestamp_if_time_is_moving_backward) { makeDataItem({{"id", "a"s}, {"type", "EXECUTION"s}, {"category", "EVENT"s}}); @@ -166,7 +166,7 @@ TEST_F(ValidateTimestampTest, should_change_timestamp_if_time_is_moving_backward ASSERT_LE(now, obs2->getTimestamp()); } -TEST_F(ValidateTimestampTest, should_handle_timestamp_in_the_future) +TEST_F(CorrectTimestampTest, should_handle_timestamp_in_the_future) { makeDataItem({{"id", "a"s}, {"type", "EXECUTION"s}, {"category", "EVENT"s}}); From 49178b9131d8d63833474cab2b28d4dcfce91ddd Mon Sep 17 00:00:00 2001 From: Will Sobel Date: Wed, 4 Jun 2025 18:02:16 -0400 Subject: [PATCH 6/6] Added some more docs --- src/mtconnect/entity/data_set.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mtconnect/entity/data_set.hpp b/src/mtconnect/entity/data_set.hpp index c3b547fb9..923ea9e10 100644 --- a/src/mtconnect/entity/data_set.hpp +++ b/src/mtconnect/entity/data_set.hpp @@ -75,7 +75,9 @@ namespace mtconnect::entity { return *this; } + /// @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; } /// @brief helper visitor to compare variant values @@ -295,8 +297,7 @@ namespace mtconnect::entity { return std::holds_alternative(m_other) && std::get(m_other) == v; } - private: - const DataSetValue &m_other; + const DataSetValue &m_other; //! the other data set value }; inline bool DataSetEntry::same(const DataSetEntry &other) const