diff --git a/src/mtconnect/entity/data_set.cpp b/src/mtconnect/entity/data_set.cpp index 016f5c302..4358e762c 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) { @@ -66,6 +66,12 @@ namespace std { 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,30 @@ 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 +115,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 +125,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 +184,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 +204,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 +214,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 +241,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 0fdaa5983..923ea9e10 100644 --- a/src/mtconnect/entity/data_set.hpp +++ b/src/mtconnect/entity/data_set.hpp @@ -30,13 +30,103 @@ #include "mtconnect/utilities.hpp" namespace mtconnect::entity { - struct DataSetEntry; + /// @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 + }; + + /// @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() {} + + /// @brief copy another table cell + /// @param other the other cell + TableCell &operator=(const TableCell &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 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 + 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 + /// @return `true` if they are the same + template + bool operator()(const T &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); + } + + /// @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); + } + + std::string m_key; + TableCellValue m_value; + bool m_removed {false}; + }; /// @brief A set of data set entries - class AGENT_LIB_API DataSet : public std::set + class AGENT_LIB_API TableRow : public std::set { public: - using base = std::set; + using base = std::set; using base::base; /// @brief Get a entry for a key @@ -44,53 +134,38 @@ 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(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; - - /// @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); + 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 - DATA_SET = 0x01, ///< data set member for tables - STRING = 0x02, ///< string value - INTEGER = 0x3, ///< 64 bit integer - DOUBLE = 0x4 ///< double + 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; - - /// @brief Equality visitor for a DataSetValue - struct DataSetValueSame - { - DataSetValueSame(const DataSetValue &other) : m_other(other) {} - - bool operator()(const DataSet &v); - - /// @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; - } - - private: - const DataSetValue &m_other; - }; + using DataSetValue = std::variant; /// @brief One entry in a data set. Has necessary interface to be work with maps. struct DataSetEntry @@ -107,9 +182,10 @@ 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) + 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 @@ -119,66 +195,114 @@ 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(""), 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) {} + /// @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; + }; - bool operator==(const DataSetEntry &other) const { return m_key == other.m_key; } - bool operator<(const DataSetEntry &other) const { return m_key < other.m_key; } + /// @brief A set of data set entries + class AGENT_LIB_API DataSet : public std::set + { + public: + using base = std::set; + using base::base; - bool same(const DataSetEntry &other) const + /// @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 m_key == other.m_key && m_removed == other.m_removed && - std::visit(DataSetValueSame(other.m_value), m_value); + 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 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 + /// @brief Equality visitor for a DataSetValue + struct DataSetValueSame { - return std::get(find(DataSetEntry(key))->m_value); - } + DataSetValueSame(const DataSetValue &other) : m_other(other) {} - /// @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); - } + /// @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; - inline bool DataSetValueSame::operator()(const DataSet &v) - { - if (!std::holds_alternative(m_other)) - return false; + const auto &oset = std::get(m_other); + + if (v.size() != oset.size()) + return false; - const auto &oset = std::get(m_other); + for (const auto &e1 : v) + { + const auto &e2 = oset.find(e1); + if (e2 == oset.end() || e2->sameValue(e1)) + return false; + } - if (v.size() != oset.size()) - return false; + return true; + } - for (const auto &e1 : v) + /// @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) { - const auto &e2 = oset.find(e1); - if (e2 == oset.end() || !visit(DataSetValueSame(e2->m_value), e1.m_value)) - return false; + return std::holds_alternative(m_other) && std::get(m_other) == v; } - return true; + 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 diff --git a/src/mtconnect/entity/entity.cpp b/src/mtconnect/entity/entity.cpp index 99e0b409c..9a55ca18f 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,12 +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 +149,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..aa6ac8a19 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..47e64f648 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 { + 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/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..395270874 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 0c05943f6..6f4a072c4 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,11 +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) - : m_set(set), m_table(table) + using Ch = typename Encoding::Ch; + + DataSetHandler(ST &set, optional key, bool table = false) : m_set(set), m_table(table) { if (key) { @@ -255,7 +258,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 +272,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 +280,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 +292,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 +316,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 +347,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 +368,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 +393,7 @@ namespace mtconnect::pipeline { // Try again m_set.insert(m_entry); } - m_entry.m_value.emplace(); + m_entry.m_value.template emplace(); } } @@ -385,8 +402,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 +603,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 419d4e6eb..42f4e0e08 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 6302afe4d..3ad5fde06 100644 --- a/src/mtconnect/ruby/ruby_entity.hpp +++ b/src/mtconnect/ruby/ruby_entity.hpp @@ -40,7 +40,48 @@ namespace mtconnect::ruby { using namespace entity; using namespace std; - inline mrb_value toRuby(mrb_state *mrb, const DataSet &value); + /// @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; + } + /// @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 +94,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 +114,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); @@ -84,7 +125,57 @@ 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 +200,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 +217,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/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}}); diff --git a/test_package/data_item_mapping_test.cpp b/test_package/data_item_mapping_test.cpp index f6bb107d6..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()); - auto a = 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)); - auto b = 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)); - auto c = 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()); - auto a = 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)); - auto b = 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)); - auto c = 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 8cffce101..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 8128915fd..a5aa43e1e 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 auto &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 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 d08c1d292..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 = 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 = 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 = 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 5bd4896bc..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 auto &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 auto &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 auto &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 215c8735c..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")); - auto 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)); - auto 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)); - auto 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) \