diff options
50 files changed, 1664 insertions, 1295 deletions
diff --git a/slicer/db/Jamfile.jam b/slicer/db/Jamfile.jam index 73c05e5..a304b9e 100644 --- a/slicer/db/Jamfile.jam +++ b/slicer/db/Jamfile.jam @@ -4,6 +4,7 @@ import ../test/slicer.jam ; lib dbppcore : : : : <include>/usr/include/dbpp ; lib dbpp-postgresql : : : : <include>/usr/include/dbpp-postgresql ; lib stdc++fs ; +lib benchmark ; obj sqlExceptions : sqlExceptions.ice : <use>../slicer//slicer <toolset>tidy:<checker>none ; lib slicer-db : @@ -137,6 +138,40 @@ run testUpdate.cpp testUpdate ; +run + [ obj perf : testPerf.cpp : + <slicer>pure + <use>../test//types + <implicit-dependency>../test//types + <use>benchmark + <use>stdc++fs + <use>dbpp-postgresql + <use>dbppcore + <use>..//adhocutil + <use>../test//common + <use>../slicer//slicer + <implicit-dependency>../slicer//slicer + <use>testCommon + <implicit-dependency>testCommon + <use>slicer-db + ] + : : : + <library>benchmark + <library>stdc++fs + <library>dbpp-postgresql + <library>dbppcore + <library>../test//common + <library>../test//types + <library>../slicer//slicer + <implicit-dependency>../slicer//slicer + <library>slicer-db + <library>..//adhocutil + <library>testCommon + <implicit-dependency>testCommon + <variant>profile:<testing.execute>on + <testing.execute>off + : testPerf ; + alias install : install-lib install-slice ; explicit install ; explicit install-lib ; diff --git a/slicer/db/sqlBinder.h b/slicer/db/sqlBinder.h index 4f5437c..a4a9a93 100644 --- a/slicer/db/sqlBinder.h +++ b/slicer/db/sqlBinder.h @@ -6,6 +6,7 @@ #include <memory> #include <slicer/modelParts.h> #include <string> + namespace DB { class Command; } @@ -33,7 +34,6 @@ namespace Slicer { DB::Command & command; const unsigned int idx; }; - typedef std::shared_ptr<SqlBinder> SqlBinderPtr; } #endif diff --git a/slicer/db/sqlCommon.cpp b/slicer/db/sqlCommon.cpp index 40e43f7..0516f45 100644 --- a/slicer/db/sqlCommon.cpp +++ b/slicer/db/sqlCommon.cpp @@ -11,31 +11,31 @@ namespace Slicer { constexpr std::string_view md_global_ignore {"ignore"}; bool - isPKey(const HookCommon * h) + isPKey(const HookCommon * h) noexcept { return h->GetMetadata().flagSet(md_pkey) && isBind(h); } bool - isAuto(const HookCommon * h) + isAuto(const HookCommon * h) noexcept { return h->GetMetadata().flagSet(md_auto) && isBind(h); } bool - isNotAuto(const HookCommon * h) + isNotAuto(const HookCommon * h) noexcept { return h->GetMetadata().flagNotSet(md_auto) && isBind(h); } bool - isBind(const HookCommon * h) + isBind(const HookCommon * h) noexcept { return h->GetMetadata().flagNotSet(md_global_ignore) && h->GetMetadata().flagNotSet(md_ignore); } bool - isValue(const HookCommon * h) + isValue(const HookCommon * h) noexcept { return h->GetMetadata().flagNotSet(md_auto) && h->GetMetadata().flagNotSet(md_pkey) && isBind(h); } @@ -59,6 +59,7 @@ namespace Slicer { } AdHocFormatter(UnsuitableIdFieldTypeMsg, "Unsuitable id field type [%?]"); + void UnsuitableIdFieldType::ice_print(std::ostream & s) const { diff --git a/slicer/db/sqlCommon.h b/slicer/db/sqlCommon.h index acabc51..16cefac 100644 --- a/slicer/db/sqlCommon.h +++ b/slicer/db/sqlCommon.h @@ -4,11 +4,11 @@ namespace Slicer { class HookCommon; - bool isPKey(const HookCommon *); - bool isAuto(const HookCommon *); - bool isNotAuto(const HookCommon *); - bool isBind(const HookCommon *); - bool isValue(const HookCommon *); + [[nodiscard]] bool isPKey(const HookCommon *) noexcept; + [[nodiscard]] bool isAuto(const HookCommon *) noexcept; + [[nodiscard]] bool isNotAuto(const HookCommon *) noexcept; + [[nodiscard]] bool isBind(const HookCommon *) noexcept; + [[nodiscard]] bool isValue(const HookCommon *) noexcept; } #endif diff --git a/slicer/db/sqlInsertSerializer.cpp b/slicer/db/sqlInsertSerializer.cpp index 58e30e2..0881a1b 100644 --- a/slicer/db/sqlInsertSerializer.cpp +++ b/slicer/db/sqlInsertSerializer.cpp @@ -15,15 +15,13 @@ #include <utility> namespace Slicer { - using namespace std::placeholders; - SqlInsertSerializer::SqlInsertSerializer(DB::Connection * const c, std::string t) : connection(c), tableName(std::move(t)) { } void - SqlInsertSerializer::Serialize(Slicer::ModelPartForRootPtr mp) + SqlInsertSerializer::Serialize(ModelPartForRootParam mp) { switch (mp->GetType()) { case Slicer::ModelPartType::Sequence: @@ -42,23 +40,24 @@ namespace Slicer { } void - SqlInsertSerializer::SerializeObject(const Slicer::ModelPartPtr & mp) const + SqlInsertSerializer::SerializeObject(ModelPartParam mp) const { auto ins = createInsert(mp); bindObjectAndExecute(mp, ins.get()); } void - SqlInsertSerializer::SerializeSequence(const Slicer::ModelPartPtr & mp) const + SqlInsertSerializer::SerializeSequence(ModelPartParam mp) const { - auto ins = createInsert(mp->GetContainedModelPart()); - mp->OnEachChild([&ins, this](const std::string &, const ModelPartPtr & cmp, const HookCommon *) { - bindObjectAndExecute(cmp, ins.get()); + mp->OnContained([this, mp](auto && cmp) { + mp->OnEachChild([ins = createInsert(cmp), this](auto &&, auto && chmp, auto &&) { + bindObjectAndExecute(chmp, ins.get()); + }); }); } void - SqlInsertSerializer::bindObjectAndExecute(const Slicer::ModelPartPtr & cmp, DB::ModifyCommand * ins) const + SqlInsertSerializer::bindObjectAndExecute(ModelPartParam cmp, DB::ModifyCommand * ins) const { unsigned int paramNo = 0; cmp->OnEachChild([this, ¶mNo, ins](auto &&, auto && PH2, auto && PH3) { @@ -88,6 +87,7 @@ namespace Slicer { private: DB::Connection * const connection; + template<typename T> inline void doSet([[maybe_unused]] T & v, [[maybe_unused]] const char * Tname) const @@ -102,10 +102,10 @@ namespace Slicer { }; void - SqlFetchIdInsertSerializer::bindObjectAndExecute(const Slicer::ModelPartPtr & mp, DB::ModifyCommand * ins) const + SqlFetchIdInsertSerializer::bindObjectAndExecute(ModelPartParam mp, DB::ModifyCommand * ins) const { SqlAutoIdInsertSerializer::bindObjectAndExecute(mp, ins); - mp->OnEachChild([this](const std::string &, const ModelPartPtr & cmp, const HookCommon * h) { + mp->OnEachChild([this](auto &&, auto && cmp, auto && h) { if (isAuto(h)) { cmp->SetValue(IdSave(connection)); } @@ -113,8 +113,8 @@ namespace Slicer { } void - SqlInsertSerializer::bindObjectAndExecuteField(unsigned int & paramNo, DB::ModifyCommand * ins, - const Slicer::ModelPartPtr & cmp, const HookCommon * h) const + SqlInsertSerializer::bindObjectAndExecuteField( + unsigned int & paramNo, DB::ModifyCommand * ins, ModelPartParam cmp, const HookCommon * h) const { if (isBind(h)) { if (!cmp->GetValue(SqlBinder(*ins, paramNo))) { @@ -125,8 +125,8 @@ namespace Slicer { } void - SqlAutoIdInsertSerializer::bindObjectAndExecuteField(unsigned int & paramNo, DB::ModifyCommand * ins, - const Slicer::ModelPartPtr & cmp, const HookCommon * h) const + SqlAutoIdInsertSerializer::bindObjectAndExecuteField( + unsigned int & paramNo, DB::ModifyCommand * ins, ModelPartParam cmp, const HookCommon * h) const { if (isNotAuto(h)) { SqlInsertSerializer::bindObjectAndExecuteField(paramNo, ins, cmp, h); @@ -134,7 +134,7 @@ namespace Slicer { } DB::ModifyCommandPtr - SqlInsertSerializer::createInsert(const Slicer::ModelPartPtr & mp) const + SqlInsertSerializer::createInsert(ModelPartParam mp) const { using namespace AdHoc::literals; std::stringstream insert; diff --git a/slicer/db/sqlInsertSerializer.h b/slicer/db/sqlInsertSerializer.h index b6a0d27..36ecac3 100644 --- a/slicer/db/sqlInsertSerializer.h +++ b/slicer/db/sqlInsertSerializer.h @@ -7,6 +7,7 @@ #include <slicer/serializer.h> #include <string> #include <visibility.h> + namespace DB { class Connection; class ModifyCommand; @@ -17,17 +18,17 @@ namespace Slicer { public: SqlInsertSerializer(DB::Connection * const, std::string tableName); - void Serialize(Slicer::ModelPartForRootPtr) override; + void Serialize(ModelPartForRootParam) override; protected: - void SerializeObject(const Slicer::ModelPartPtr &) const; - void SerializeSequence(const Slicer::ModelPartPtr &) const; - DB::ModifyCommandPtr createInsert(const Slicer::ModelPartPtr &) const; + void SerializeObject(ModelPartParam) const; + void SerializeSequence(ModelPartParam) const; + [[nodiscard]] DB::ModifyCommandPtr createInsert(ModelPartParam) const; virtual void createInsertField( unsigned int & fieldNo, std::ostream & insert, const std::string & name, const HookCommon * h) const; - virtual void bindObjectAndExecute(const Slicer::ModelPartPtr &, DB::ModifyCommand *) const; + virtual void bindObjectAndExecute(ModelPartParam, DB::ModifyCommand *) const; virtual void bindObjectAndExecuteField( - unsigned int & paramNo, DB::ModifyCommand *, const Slicer::ModelPartPtr &, const HookCommon *) const; + unsigned int & paramNo, DB::ModifyCommand *, ModelPartParam, const HookCommon *) const; DB::Connection * const connection; const std::string tableName; @@ -35,27 +36,21 @@ namespace Slicer { class DLL_PUBLIC SqlAutoIdInsertSerializer : public SqlInsertSerializer { public: - template<typename... P> - explicit SqlAutoIdInsertSerializer(P &&... p) : SqlInsertSerializer(std::forward<P>(p)...) - { - } + using SqlInsertSerializer::SqlInsertSerializer; protected: - virtual void createInsertField(unsigned int & fieldNo, std::ostream & insert, const std::string & name, + void createInsertField(unsigned int & fieldNo, std::ostream & insert, const std::string & name, const HookCommon * h) const override; - virtual void bindObjectAndExecuteField(unsigned int & paramNo, DB::ModifyCommand *, - const Slicer::ModelPartPtr &, const HookCommon *) const override; + void bindObjectAndExecuteField( + unsigned int & paramNo, DB::ModifyCommand *, ModelPartParam, const HookCommon *) const override; }; class DLL_PUBLIC SqlFetchIdInsertSerializer : public SqlAutoIdInsertSerializer { public: - template<typename... P> - explicit SqlFetchIdInsertSerializer(P &&... p) : SqlAutoIdInsertSerializer(std::forward<P>(p)...) - { - } + using SqlAutoIdInsertSerializer::SqlAutoIdInsertSerializer; protected: - virtual void bindObjectAndExecute(const Slicer::ModelPartPtr &, DB::ModifyCommand *) const override; + void bindObjectAndExecute(ModelPartParam, DB::ModifyCommand *) const override; }; } diff --git a/slicer/db/sqlSelectDeserializer.cpp b/slicer/db/sqlSelectDeserializer.cpp index f3f3c07..8081d76 100644 --- a/slicer/db/sqlSelectDeserializer.cpp +++ b/slicer/db/sqlSelectDeserializer.cpp @@ -5,6 +5,7 @@ #include <memory> #include <selectcommand.h> #include <slicer/common.h> +#include <slicer/hookMap.h> #include <slicer/modelParts.h> #include <utility> @@ -15,7 +16,7 @@ namespace Slicer { } void - SqlSelectDeserializer::Deserialize(Slicer::ModelPartForRootPtr mp) + SqlSelectDeserializer::Deserialize(ModelPartForRootParam mp) { cmd->execute(); columnCount = cmd->columnCount(); @@ -38,7 +39,7 @@ namespace Slicer { } void - SqlSelectDeserializer::DeserializeSimple(const Slicer::ModelPartPtr & mp) + SqlSelectDeserializer::DeserializeSimple(ModelPartParam mp) { if (!cmd->fetch()) { if (!mp->IsOptional()) { @@ -47,10 +48,11 @@ namespace Slicer { return; } if (!(*cmd)[0].isNull()) { - auto fmp = mp->GetAnonChild(); - fmp->Create(); - fmp->SetValue(SqlSource((*cmd)[0])); - fmp->Complete(); + mp->OnAnonChild([this](auto && fmp, auto &&) { + fmp->Create(); + fmp->SetValue(SqlSource((*cmd)[0])); + fmp->Complete(); + }); } if (cmd->fetch()) { throw TooManyRowsReturned(); @@ -58,16 +60,60 @@ namespace Slicer { } void - SqlSelectDeserializer::DeserializeSequence(const Slicer::ModelPartPtr & omp) + SqlSelectDeserializer::fillLowerColumnNameCache() { - auto mp = omp->GetAnonChild(); - while (cmd->fetch()) { - DeserializeRow(mp); + BOOST_ASSERT(lowerColumnNames.empty()); + lowerColumnNames.reserve(columnCount); + orderedColumns.reserve(columnCount); + for (auto col = 0U; col < columnCount; col += 1) { + const DB::Column & c = (*cmd)[col]; + lowerColumnNames.emplace_back(to_lower_copy(c.name)); + } + } + + const DB::Column * + SqlSelectDeserializer::searchOrFilleColumnCache(size_t idx, const HookCommon * hook) + { + if (idx < orderedColumns.size()) { + return orderedColumns[idx]; + } + BOOST_ASSERT(idx == orderedColumns.size()); + if (const auto itr = std::find(lowerColumnNames.begin(), lowerColumnNames.end(), hook->nameLower); + itr != lowerColumnNames.end()) { + return orderedColumns.emplace_back(&(*cmd)[static_cast<unsigned int>(itr - lowerColumnNames.begin())]); + } + else { + return orderedColumns.emplace_back(nullptr); + } + } + + namespace { + void + assignFromColumn(ModelPartParam fmp, const DB::Column & c) + { + BOOST_ASSERT(fmp); + BOOST_ASSERT(!c.isNull()); + fmp->Create(); + fmp->SetValue(SqlSource(c)); + fmp->Complete(); } } void - SqlSelectDeserializer::DeserializeObject(const Slicer::ModelPartPtr & mp) + SqlSelectDeserializer::DeserializeSequence(ModelPartParam omp) + { + omp->OnAnonChild([this](auto && mp, auto &&) { + if (!typeIdColIdx && lowerColumnNames.empty()) { + fillLowerColumnNameCache(); + } + while (cmd->fetch()) { + DeserializeRow(mp); + } + }); + } + + void + SqlSelectDeserializer::DeserializeObject(ModelPartParam mp) { if (!cmd->fetch()) { if (!mp->IsOptional()) { @@ -83,43 +129,51 @@ namespace Slicer { } void - SqlSelectDeserializer::DeserializeRow(const Slicer::ModelPartPtr & mp) + SqlSelectDeserializer::DeserializeRow(ModelPartParam mp) { - auto rmp = mp->GetAnonChild(); - if (rmp) { + mp->OnAnonChild([this](auto && rmp, auto &&) { switch (rmp->GetType()) { case Slicer::ModelPartType::Complex: { + auto apply = [this](auto && rcmp) { + rcmp->Create(); + if (typeIdColIdx || lowerColumnNames.empty()) { + for (auto col = 0U; col < columnCount; col += 1) { + const DB::Column & c = (*cmd)[col]; + if (!c.isNull()) { + rcmp->OnChild( + [&c](auto && fmp, auto &&) { + assignFromColumn(fmp, c); + }, + c.name, nullptr, false); + } + } + } + else { + rcmp->OnEachChild([idx = 0U, this](auto &&, auto && fmp, auto && hook) mutable { + if (auto c = searchOrFilleColumnCache(idx, hook); c && !c->isNull()) { + assignFromColumn(fmp, *c); + } + ++idx; + }); + } + rcmp->Complete(); + }; if (typeIdColIdx) { std::string subclass; (*cmd)[*typeIdColIdx] >> subclass; - rmp = rmp->GetSubclassModelPart(subclass); - } - rmp->Create(); - for (auto col = 0U; col < columnCount; col += 1) { - const DB::Column & c = (*cmd)[col]; - if (!c.isNull()) { - auto fmpr = rmp->GetChildRef(c.name, nullptr, false); - if (fmpr) { - auto fmp = fmpr.Child(); - fmp->Create(); - fmp->SetValue(SqlSource(c)); - fmp->Complete(); - } - } + return rmp->OnSubclass(apply, subclass); } - rmp->Complete(); + apply(rmp); } break; case Slicer::ModelPartType::Simple: { - rmp->Create(); const DB::Column & c = (*cmd)[0]; if (!c.isNull()) { - rmp->SetValue(SqlSource(c)); + assignFromColumn(rmp, c); } - rmp->Complete(); } break; default: throw UnsupportedModelType(); } - } + }); } } diff --git a/slicer/db/sqlSelectDeserializer.h b/slicer/db/sqlSelectDeserializer.h index bf2b351..b911fb1 100644 --- a/slicer/db/sqlSelectDeserializer.h +++ b/slicer/db/sqlSelectDeserializer.h @@ -6,8 +6,10 @@ #include <slicer/serializer.h> #include <string> #include <visibility.h> + namespace DB { class SelectCommand; + class Column; } namespace Slicer { @@ -16,18 +18,22 @@ namespace Slicer { explicit SqlSelectDeserializer( DB::SelectCommand *, std::optional<std::string> typeIdCol = std::optional<std::string>()); - void Deserialize(Slicer::ModelPartForRootPtr) override; + void Deserialize(ModelPartForRootParam) override; protected: - void DLL_PRIVATE DeserializeSimple(const Slicer::ModelPartPtr &); - void DLL_PRIVATE DeserializeObject(const Slicer::ModelPartPtr &); - void DLL_PRIVATE DeserializeSequence(const Slicer::ModelPartPtr &); - void DLL_PRIVATE DeserializeRow(const Slicer::ModelPartPtr &); + DLL_PRIVATE void DeserializeSimple(ModelPartParam); + DLL_PRIVATE void DeserializeObject(ModelPartParam); + DLL_PRIVATE void DeserializeSequence(ModelPartParam); + DLL_PRIVATE void DeserializeRow(ModelPartParam); + DLL_PRIVATE void fillLowerColumnNameCache(); + DLL_PRIVATE inline const DB::Column * searchOrFilleColumnCache(size_t idx, const HookCommon * hook); DB::SelectCommand * cmd; unsigned int columnCount; std::optional<std::string> typeIdColName; std::optional<unsigned int> typeIdColIdx; + std::vector<std::string> lowerColumnNames; + std::vector<const DB::Column *> orderedColumns; }; } diff --git a/slicer/db/sqlSource.cpp b/slicer/db/sqlSource.cpp index 41b9c1c..ed14b3a 100644 --- a/slicer/db/sqlSource.cpp +++ b/slicer/db/sqlSource.cpp @@ -7,6 +7,17 @@ namespace Slicer { SqlSource::SqlSource(const DB::Column & c) : column(c) { } + namespace { + template<typename C, typename T> + void + numericSet(const DB::Column & column, T & b) + { + C cb {}; + column >> cb; + b = boost::numeric_cast<T>(cb); + } + } + bool SqlSource::isNull() const { @@ -34,47 +45,37 @@ namespace Slicer { void SqlSource::set(Ice::Byte & b) const { - int64_t cb; - column >> cb; - b = boost::numeric_cast<Ice::Byte>(cb); + numericSet<int64_t>(column, b); } void SqlSource::set(Ice::Short & b) const { - int64_t cb; - column >> cb; - b = boost::numeric_cast<Ice::Short>(cb); + numericSet<int64_t>(column, b); } void SqlSource::set(Ice::Int & b) const { - int64_t cb; - column >> cb; - b = boost::numeric_cast<Ice::Int>(cb); + numericSet<int64_t>(column, b); } void SqlSource::set(Ice::Long & b) const { - int64_t cb; - column >> cb; - b = boost::numeric_cast<Ice::Long>(cb); + numericSet<int64_t>(column, b); } void SqlSource::set(Ice::Float & b) const { - double cb; - column >> cb; - b = boost::numeric_cast<Ice::Float>(cb); + numericSet<double>(column, b); } void SqlSource::set(Ice::Double & b) const { - column >> b; + numericSet<double>(column, b); } void diff --git a/slicer/db/sqlSource.h b/slicer/db/sqlSource.h index 4b76974..78d9909 100644 --- a/slicer/db/sqlSource.h +++ b/slicer/db/sqlSource.h @@ -5,9 +5,11 @@ #include <Ice/Config.h> #include <memory> #include <string> + namespace DB { class Column; } + namespace boost::posix_time { class ptime; class time_duration; @@ -21,7 +23,7 @@ namespace Slicer { public: explicit SqlSource(const DB::Column & c); - bool isNull() const; + [[nodiscard]] bool isNull() const; void set(boost::posix_time::ptime & b) const override; void set(boost::posix_time::time_duration & b) const override; void set(bool & b) const override; @@ -36,7 +38,6 @@ namespace Slicer { private: const DB::Column & column; }; - typedef std::shared_ptr<SqlSource> SqlSourcePtr; } #endif diff --git a/slicer/db/sqlTablePatchSerializer.cpp b/slicer/db/sqlTablePatchSerializer.cpp index 3b73f05..ec0e344 100644 --- a/slicer/db/sqlTablePatchSerializer.cpp +++ b/slicer/db/sqlTablePatchSerializer.cpp @@ -11,6 +11,7 @@ namespace Slicer { AdHocFormatter(ttname, "slicer_tmp_%?"); + SqlTablePatchSerializer::SqlTablePatchSerializer(DB::Connection * const d, DB::TablePatch & tp) : db(d), tablePatch(tp) { @@ -18,7 +19,7 @@ namespace Slicer { } void - SqlTablePatchSerializer::Serialize(Slicer::ModelPartForRootPtr mpr) + SqlTablePatchSerializer::Serialize(ModelPartForRootParam mpr) { tablePatch.pk.clear(); tablePatch.cols.clear(); @@ -31,22 +32,22 @@ namespace Slicer { SqlInsertSerializer ins(db, tablePatch.src); ins.Serialize(mpr); - auto mp = mpr->GetContainedModelPart(); - mp->OnEachChild([this](const auto & name, const auto &, const auto & h) { - if (isPKey(h)) { - tablePatch.pk.insert(name); - } - }); - mp->OnEachChild([this](const auto & name, const auto &, const auto & h) { - if (isBind(h)) { - tablePatch.cols.insert(name); - } + mpr->OnContained([this](auto && mp) { + mp->OnEachChild([this](const auto & name, const auto &, const auto & h) { + if (isPKey(h)) { + tablePatch.pk.insert(name); + } + if (isBind(h)) { + tablePatch.cols.insert(name); + } + }); }); db->patchTable(&tablePatch); } AdHocFormatter(createTmpTable, "CREATE TEMPORARY TABLE %? AS SELECT * FROM %? WHERE 1 = 0"); + void SqlTablePatchSerializer::createTemporaryTable() { @@ -54,6 +55,7 @@ namespace Slicer { } AdHocFormatter(dropTmpTable, "DROP TABLE %?"); + void SqlTablePatchSerializer::dropTemporaryTable() { diff --git a/slicer/db/sqlTablePatchSerializer.h b/slicer/db/sqlTablePatchSerializer.h index 21c8b3d..1da29a6 100644 --- a/slicer/db/sqlTablePatchSerializer.h +++ b/slicer/db/sqlTablePatchSerializer.h @@ -4,6 +4,7 @@ #include <slicer/modelParts.h> #include <slicer/serializer.h> #include <visibility.h> + namespace DB { class Connection; class TablePatch; @@ -14,7 +15,7 @@ namespace Slicer { public: SqlTablePatchSerializer(DB::Connection * const, DB::TablePatch &); - void Serialize(Slicer::ModelPartForRootPtr) override; + void Serialize(ModelPartForRootParam) override; private: void createTemporaryTable(); diff --git a/slicer/db/sqlUpdateSerializer.cpp b/slicer/db/sqlUpdateSerializer.cpp index 038f28e..152c923 100644 --- a/slicer/db/sqlUpdateSerializer.cpp +++ b/slicer/db/sqlUpdateSerializer.cpp @@ -21,7 +21,7 @@ namespace Slicer { } void - SqlUpdateSerializer::Serialize(Slicer::ModelPartForRootPtr mp) + SqlUpdateSerializer::Serialize(ModelPartForRootParam mp) { switch (mp->GetType()) { case Slicer::ModelPartType::Sequence: @@ -40,26 +40,27 @@ namespace Slicer { } void - SqlUpdateSerializer::SerializeObject(const Slicer::ModelPartPtr & mp) const + SqlUpdateSerializer::SerializeObject(ModelPartParam mp) const { auto ins = createUpdate(mp); bindObjectAndExecute(mp, ins.get()); } void - SqlUpdateSerializer::SerializeSequence(const Slicer::ModelPartPtr & mp) const + SqlUpdateSerializer::SerializeSequence(ModelPartParam mp) const { - auto ins = createUpdate(mp->GetContainedModelPart()); - mp->OnEachChild([&ins](const std::string &, const ModelPartPtr & cmp, const HookCommon *) { - bindObjectAndExecute(cmp, ins.get()); + mp->OnContained([this, mp](auto && cmp) { + mp->OnEachChild([upd = createUpdate(cmp)](auto &&, auto && chmp, auto &&) { + bindObjectAndExecute(chmp, upd.get()); + }); }); } void - SqlUpdateSerializer::bindObjectAndExecute(const Slicer::ModelPartPtr & mp, DB::ModifyCommand * upd) + SqlUpdateSerializer::bindObjectAndExecute(ModelPartParam mp, DB::ModifyCommand * upd) { unsigned int paramNo = 0; - mp->OnEachChild([&upd, ¶mNo](const std::string &, const ModelPartPtr & cmp, const HookCommon * h) { + mp->OnEachChild([&upd, ¶mNo](auto &&, auto && cmp, auto && h) { if (isValue(h)) { if (!cmp->GetValue(SqlBinder(*upd, paramNo))) { upd->bindNull(paramNo); @@ -67,7 +68,7 @@ namespace Slicer { paramNo++; } }); - mp->OnEachChild([&upd, ¶mNo](const std::string &, const ModelPartPtr & cmp, const HookCommon * h) { + mp->OnEachChild([&upd, ¶mNo](auto &&, auto && cmp, auto && h) { if (isPKey(h)) { cmp->GetValue(SqlBinder(*upd, paramNo++)); } @@ -78,13 +79,13 @@ namespace Slicer { } DB::ModifyCommandPtr - SqlUpdateSerializer::createUpdate(const Slicer::ModelPartPtr & mp) const + SqlUpdateSerializer::createUpdate(ModelPartParam mp) const { using namespace AdHoc::literals; std::stringstream update; "UPDATE %? SET "_fmt(update, tableName); int fieldNo = 0; - mp->OnEachChild([&update, &fieldNo](const std::string & name, const ModelPartPtr &, const HookCommon * h) { + mp->OnEachChild([&update, &fieldNo](auto && name, auto &&, auto && h) { if (isValue(h)) { if (fieldNo++) { update << ", "; @@ -94,7 +95,7 @@ namespace Slicer { }); update << " WHERE "; fieldNo = 0; - mp->OnEachChild([&update, &fieldNo](const std::string & name, const ModelPartPtr &, const HookCommon * h) { + mp->OnEachChild([&update, &fieldNo](auto && name, auto &&, auto && h) { if (isPKey(h)) { if (fieldNo++) { update << " AND "; diff --git a/slicer/db/sqlUpdateSerializer.h b/slicer/db/sqlUpdateSerializer.h index 8707988..c634ff5 100644 --- a/slicer/db/sqlUpdateSerializer.h +++ b/slicer/db/sqlUpdateSerializer.h @@ -6,6 +6,7 @@ #include <slicer/serializer.h> #include <string> #include <visibility.h> + namespace DB { class Connection; class ModifyCommand; @@ -16,13 +17,13 @@ namespace Slicer { public: SqlUpdateSerializer(DB::Connection * const, std::string tableName); - void Serialize(Slicer::ModelPartForRootPtr) override; + void Serialize(ModelPartForRootParam) override; protected: - void SerializeObject(const Slicer::ModelPartPtr &) const; - void SerializeSequence(const Slicer::ModelPartPtr &) const; - DB::ModifyCommandPtr createUpdate(const Slicer::ModelPartPtr &) const; - static void bindObjectAndExecute(const Slicer::ModelPartPtr &, DB::ModifyCommand *); + void SerializeObject(ModelPartParam) const; + void SerializeSequence(ModelPartParam) const; + [[nodiscard]] DB::ModifyCommandPtr createUpdate(ModelPartParam) const; + static void bindObjectAndExecute(ModelPartParam, DB::ModifyCommand *); DB::Connection * const connection; const std::string tableName; diff --git a/slicer/db/testInsert.cpp b/slicer/db/testInsert.cpp index a9e42f1..24cae7e 100644 --- a/slicer/db/testInsert.cpp +++ b/slicer/db/testInsert.cpp @@ -25,6 +25,7 @@ using namespace std::literals; BOOST_TEST_DONT_PRINT_LOG_VALUE(TestModule::DateTime) BOOST_TEST_DONT_PRINT_LOG_VALUE(TestModule::IsoDate) BOOST_TEST_DONT_PRINT_LOG_VALUE(TestDatabase::Timespan) + // LCOV_EXCL_STOP namespace std { diff --git a/slicer/db/testMockCommon.h b/slicer/db/testMockCommon.h index e12d2c6..891fb74 100644 --- a/slicer/db/testMockCommon.h +++ b/slicer/db/testMockCommon.h @@ -5,6 +5,7 @@ #include <mockDatabase.h> #include <pq-mock.h> #include <visibility.h> + // IWYU pragma: no_forward_declare PQ::Mock namespace DB { class Connection; diff --git a/slicer/db/testPatch.cpp b/slicer/db/testPatch.cpp index 6db440a..3e8b1e4 100644 --- a/slicer/db/testPatch.cpp +++ b/slicer/db/testPatch.cpp @@ -11,9 +11,11 @@ #include <memory> #include <string> #include <tablepatch.h> + namespace TestDatabase { class Timespan; } + namespace TestModule { struct DateTime; struct IsoDate; diff --git a/slicer/db/testPerf.cpp b/slicer/db/testPerf.cpp new file mode 100644 index 0000000..bb2a4c3 --- /dev/null +++ b/slicer/db/testPerf.cpp @@ -0,0 +1,37 @@ +#include "sqlSelectDeserializer.h" +#include "testMockCommon.h" +#include <benchmark/benchmark.h> +#include <collections.h> +#include <connection.h> +#include <definedDirs.h> +#include <slicer/slicer.h> +#include <testModels.h> + +const StandardMockDatabase db; + +class CoreFixture : public benchmark::Fixture, public ConnectionFixture { +protected: + template<typename Out> + void + do_bulk_select_complex(benchmark::State & state) + { + auto sel = db->select(R"SQL( + SELECT s mint, CAST(s AS NUMERIC(7,1)) mdouble, CAST(s as text) mstring, s % 2 = 0 mbool + FROM GENERATE_SERIES(1, 10000) s)SQL"); + for (auto _ : state) { + benchmark::DoNotOptimize(Slicer::DeserializeAny<Slicer::SqlSelectDeserializer, Out>(sel.get())); + } + } +}; + +BENCHMARK_F(CoreFixture, bulk_select_complex)(benchmark::State & state) +{ + do_bulk_select_complex<TestDatabase::BuiltInSeq>(state); +} + +BENCHMARK_F(CoreFixture, bulk_select_complex_non_optional)(benchmark::State & state) +{ + do_bulk_select_complex<TestModule::BuiltInSeq>(state); +} + +BENCHMARK_MAIN(); diff --git a/slicer/ice/serializer.cpp b/slicer/ice/serializer.cpp index eacecf8..eb27729 100644 --- a/slicer/ice/serializer.cpp +++ b/slicer/ice/serializer.cpp @@ -22,7 +22,7 @@ namespace Slicer { } void - IceBlobSerializer::Serialize(ModelPartForRootPtr mp) + IceBlobSerializer::Serialize(ModelPartForRootParam mp) { Ice::OutputStream s(ic); mp->Write(s); @@ -32,7 +32,7 @@ namespace Slicer { IceStreamSerializer::IceStreamSerializer(std::ostream & os) : strm(os) { } void - IceStreamSerializer::Serialize(ModelPartForRootPtr mp) + IceStreamSerializer::Serialize(ModelPartForRootParam mp) { IceBlobSerializer::Serialize(mp); strm.write(reinterpret_cast<const char *>(blob.data()), static_cast<std::streamsize>(blob.size())); @@ -41,7 +41,7 @@ namespace Slicer { IceBlobDeserializer::IceBlobDeserializer(const Ice::ByteSeq & b) : refblob(b) { } void - IceBlobDeserializer::Deserialize(ModelPartForRootPtr mp) + IceBlobDeserializer::Deserialize(ModelPartForRootParam mp) { Ice::InputStream s(ic, refblob); mp->Read(s); @@ -50,7 +50,7 @@ namespace Slicer { IceStreamDeserializer::IceStreamDeserializer(std::istream & is) : IceBlobDeserializer(blob), strm(is) { } void - IceStreamDeserializer::Deserialize(ModelPartForRootPtr mp) + IceStreamDeserializer::Deserialize(ModelPartForRootParam mp) { blob.assign(std::istreambuf_iterator<char>(strm), std::istreambuf_iterator<char>()); IceBlobDeserializer::Deserialize(mp); diff --git a/slicer/ice/serializer.h b/slicer/ice/serializer.h index db467cd..8e8ff03 100644 --- a/slicer/ice/serializer.h +++ b/slicer/ice/serializer.h @@ -3,16 +3,19 @@ #include <Ice/BuiltinSequences.h> #include <Ice/CommunicatorF.h> +#include <c++11Helpers.h> #include <iosfwd> #include <slicer/modelParts.h> #include <slicer/serializer.h> #include <visibility.h> namespace Slicer { - class IceBase { + class DLL_PUBLIC IceBase { public: virtual ~IceBase(); + SPECIAL_MEMBERS_DELETE(IceBase); + protected: IceBase(); @@ -21,7 +24,7 @@ namespace Slicer { class DLL_PUBLIC IceBlobSerializer : public Serializer, protected IceBase { public: - void Serialize(ModelPartForRootPtr) override; + void Serialize(ModelPartForRootParam) override; protected: Ice::ByteSeq blob; @@ -31,7 +34,7 @@ namespace Slicer { public: explicit IceStreamSerializer(std::ostream &); - void Serialize(ModelPartForRootPtr) override; + void Serialize(ModelPartForRootParam) override; protected: std::ostream & strm; @@ -41,7 +44,7 @@ namespace Slicer { public: explicit IceBlobDeserializer(const Ice::ByteSeq &); - void Deserialize(ModelPartForRootPtr) override; + void Deserialize(ModelPartForRootParam) override; protected: const Ice::ByteSeq & refblob; @@ -51,7 +54,7 @@ namespace Slicer { public: explicit IceStreamDeserializer(std::istream &); - void Deserialize(ModelPartForRootPtr) override; + void Deserialize(ModelPartForRootParam) override; protected: std::istream & strm; diff --git a/slicer/ice/testSpecifics.cpp b/slicer/ice/testSpecifics.cpp index 2080993..6b6c0f0 100644 --- a/slicer/ice/testSpecifics.cpp +++ b/slicer/ice/testSpecifics.cpp @@ -18,6 +18,7 @@ // LCOV_EXCL_START // cppcheck-suppress unknownMacro BOOST_TEST_DONT_PRINT_LOG_VALUE(TestModule::IsoDate) + // LCOV_EXCL_STOP template<typename X> diff --git a/slicer/json/serializer.cpp b/slicer/json/serializer.cpp index e2db939..4070231 100644 --- a/slicer/json/serializer.cpp +++ b/slicer/json/serializer.cpp @@ -26,329 +26,323 @@ NAMEDFACTORY("application/json", Slicer::JsonStreamSerializer, Slicer::StreamSer NAMEDFACTORY("application/json", Slicer::JsonStreamDeserializer, Slicer::StreamDeserializerFactory) namespace Slicer { - constexpr std::string_view md_object {"json:object"}; - constexpr std::string_view keyName {"key"}; - constexpr std::string_view valueName {"value"}; + namespace { + constexpr std::string_view md_object {"json:object"}; + constexpr std::string_view keyName {"key"}; + constexpr std::string_view valueName {"value"}; - using namespace std::placeholders; + using namespace std::placeholders; - class JsonValueSource : public ValueSource { - public: - explicit JsonValueSource(const json::Value & s) : value(s) { } + class JsonValueSource : public ValueSource { + public: + explicit JsonValueSource(const json::Value & s) : value(s) { } - void - set(bool & v) const override - { - v = std::get<bool>(value); - } + void + set(bool & v) const override + { + v = std::get<bool>(value); + } - void - set(Ice::Byte & v) const override - { - v = boost::numeric_cast<Ice::Byte>(std::get<json::Number>(value)); - } + void + set(Ice::Byte & v) const override + { + v = boost::numeric_cast<Ice::Byte>(std::get<json::Number>(value)); + } - void - set(Ice::Short & v) const override - { - v = boost::numeric_cast<Ice::Short>(std::get<json::Number>(value)); - } + void + set(Ice::Short & v) const override + { + v = boost::numeric_cast<Ice::Short>(std::get<json::Number>(value)); + } - void - set(Ice::Int & v) const override - { - v = boost::numeric_cast<Ice::Int>(std::get<json::Number>(value)); - } + void + set(Ice::Int & v) const override + { + v = boost::numeric_cast<Ice::Int>(std::get<json::Number>(value)); + } - void - set(Ice::Long & v) const override - { - v = boost::numeric_cast<Ice::Long>(std::get<json::Number>(value)); - } + void + set(Ice::Long & v) const override + { + v = boost::numeric_cast<Ice::Long>(std::get<json::Number>(value)); + } - void - set(Ice::Float & v) const override - { - v = boost::numeric_cast<Ice::Float>(std::get<json::Number>(value)); - } + void + set(Ice::Float & v) const override + { + v = boost::numeric_cast<Ice::Float>(std::get<json::Number>(value)); + } - void - set(Ice::Double & v) const override - { - v = boost::numeric_cast<Ice::Double>(std::get<json::Number>(value)); - } + void + set(Ice::Double & v) const override + { + v = boost::numeric_cast<Ice::Double>(std::get<json::Number>(value)); + } - void - set(std::string & v) const override - { - v = std::get<json::String>(value); - } + void + set(std::string & v) const override + { + v = std::get<json::String>(value); + } - private: - const json::Value & value; - }; + private: + const json::Value & value; + }; - class JsonValueTarget : public ValueTarget { - public: - explicit JsonValueTarget(json::Value & t) : target(t) - { - target = json::Null(); - } + class JsonValueTarget : public ValueTarget { + public: + explicit JsonValueTarget(json::Value & t) : target(t) + { + target = json::Null(); + } - void - get(const bool & value) const override - { - target = value; - } + void + get(const bool & value) const override + { + target = value; + } - void - get(const Ice::Byte & value) const override - { - target = boost::numeric_cast<json::Number>(value); - } + void + get(const Ice::Byte & value) const override + { + target = boost::numeric_cast<json::Number>(value); + } - void - get(const Ice::Short & value) const override - { - target = boost::numeric_cast<json::Number>(value); - } + void + get(const Ice::Short & value) const override + { + target = boost::numeric_cast<json::Number>(value); + } - void - get(const Ice::Int & value) const override - { - target = boost::numeric_cast<json::Number>(value); - } + void + get(const Ice::Int & value) const override + { + target = boost::numeric_cast<json::Number>(value); + } - void - get(const Ice::Long & value) const override - { - target = boost::numeric_cast<json::Number>(value); - } + void + get(const Ice::Long & value) const override + { + target = boost::numeric_cast<json::Number>(value); + } - void - get(const Ice::Float & value) const override - { - target = boost::numeric_cast<json::Number>(value); - } + void + get(const Ice::Float & value) const override + { + target = boost::numeric_cast<json::Number>(value); + } - void - get(const Ice::Double & value) const override - { - target = boost::numeric_cast<json::Number>(value); - } + void + get(const Ice::Double & value) const override + { + target = boost::numeric_cast<json::Number>(value); + } - void - get(const std::string & value) const override - { - target = value; - } + void + get(const std::string & value) const override + { + target = value; + } - private: - json::Value & target; - }; + private: + json::Value & target; + }; - class DocumentTreeIterate { - public: - explicit DocumentTreeIterate(ModelPartPtr & mp) : modelPart(mp) { } - template<typename SimpleT> - void - operator()(const SimpleT & v) const - { - modelPart->Create(); - modelPart->SetValue(JsonValueSource(v)); - modelPart->Complete(); - } - void - operator()(const json::Null &) const - { - modelPart->Complete(); - } - void - operator()(const json::Object & o) const - { - if (auto typeIdName = modelPart->GetTypeIdProperty()) { - auto typeAttrItr = o.find(*typeIdName); - if (typeAttrItr != o.end() && std::holds_alternative<json::String>(typeAttrItr->second)) { - modelPart = modelPart->GetSubclassModelPart(std::get<json::String>(typeAttrItr->second)); - } + class DocumentTreeIterate { + public: + static void + visit(ModelPartParam mp, const json::Value & v) + { + std::visit(DocumentTreeIterate {mp}, v); + } + + template<typename SimpleT> + void + operator()(const SimpleT & v) const + { + modelPart->Create(); + modelPart->SetValue(JsonValueSource(v)); + modelPart->Complete(); + } + + void + operator()(const json::Null &) const + { + modelPart->Complete(); } - modelPart->Create(); - if (modelPart->GetMetadata().flagSet(md_object)) { - for (const auto & element : o) { - auto emp = modelPart->GetAnonChild(); - emp->Create(); - auto key = emp->GetChild(keyName); - auto value = emp->GetChild(valueName); - key->Create(); - key->SetValue(JsonValueSource(element.first)); - key->Complete(); - std::visit(DocumentTreeIterate(value), element.second); - emp->Complete(); + + void + operator()(const json::Object & o) const + { + auto apply = [&o](auto && objectModelPart) { + objectModelPart->Create(); + if (objectModelPart->GetMetadata().flagSet(md_object)) { + for (const auto & element : o) { + objectModelPart->OnAnonChild([&element](auto && emp, auto &&) { + emp->Create(); + emp->OnChild( + [&element](auto && key, auto &&) { + key->Create(); + key->SetValue(JsonValueSource(element.first)); + key->Complete(); + }, + keyName); + emp->OnChild( + [&element](auto && value, auto &&) { + visit(value, element.second); + }, + valueName); + emp->Complete(); + }); + } + } + else { + for (const auto & element : o) { + objectModelPart->OnChild( + [&element](auto && emp, auto &&) { + visit(emp, element.second); + emp->Complete(); + }, + element.first); + } + objectModelPart->Complete(); + } + }; + if (auto typeIdName = modelPart->GetTypeIdProperty()) { + auto typeAttrItr = o.find(*typeIdName); + if (typeAttrItr != o.end() && std::holds_alternative<json::String>(typeAttrItr->second)) { + return modelPart->OnSubclass(apply, std::get<json::String>(typeAttrItr->second)); + } } + apply(modelPart); } - else { - for (const auto & element : o) { - auto emp = modelPart->GetChild(element.first); - if (emp) { - std::visit(DocumentTreeIterate(emp), element.second); + + void + operator()(const json::Array & a) const + { + modelPart->Create(); + for (const auto & element : a) { + modelPart->OnAnonChild([&element](auto && emp, auto &&) { + visit(emp, element); emp->Complete(); - } + }); } modelPart->Complete(); } - } + + ModelPartParam modelPart; + }; + + void ModelTreeIterateTo(const std::function<json::Value &()> &, ModelPartParam mp); + void - operator()(const json::Array & a) const + ModelTreeIterateSeq(json::Array & a, ModelPartParam mp) { - modelPart->Create(); - for (const auto & element : a) { - auto emp = modelPart->GetAnonChild(); - if (emp) { - emp->Create(); - std::visit(DocumentTreeIterate(emp), element); - emp->Complete(); - } + if (!mp->HasValue()) { + return; } - modelPart->Complete(); - } - private: - ModelPartPtr & modelPart; - }; - - void - JsonSerializer::ModelTreeIterateSeq(json::Value * n, const ModelPartPtr & mp) - { - if (!mp->HasValue()) { - return; + ModelTreeIterateTo( + [&a]() -> json::Value & { + return a.emplace_back(); + }, + mp); } - auto arr = std::get_if<json::Array>(n); - arr->emplace_back(); - ModelTreeIterateRoot(&arr->back(), mp); - } - void - JsonSerializer::ModelTreeIterateDictObj(json::Value * n, const ModelPartPtr & mp) - { - if (!mp->HasValue()) { - return; + void + ModelTreeIterateDictObj(json::Object & d, ModelPartParam mp) + { + if (!mp->HasValue()) { + return; + } + mp->OnChild( + [&d, mp](auto && cmp, auto &&) { + ModelTreeIterateTo( + [&d, mp]() -> json::Value & { + json::Object::key_type k; + json::Value kv; + mp->OnChild( + [&kv](auto && emp, auto &&) { + emp->GetValue(JsonValueTarget(kv)); + }, + keyName); + JsonValueSource(kv).set(k); + return d[std::move(k)]; + }, + cmp); + }, + valueName); } - auto obj = std::get_if<json::Object>(n); - json::Object::key_type k; - json::Value v; - json::Value kv; - mp->GetChild(keyName)->GetValue(JsonValueTarget(kv)); - JsonValueSource s(kv); - s.set(k); - ModelTreeIterateRoot(&v, mp->GetChild(valueName)); - obj->insert({k, v}); - } - void - JsonSerializer::ModelTreeIterate(json::Value * n, const std::string & name, ModelPartPtr mp) - { - if (name.empty() || !n || !mp) { - return; - } - switch (mp->GetType()) { - case ModelPartType::Null: - std::get<json::Object>(*n).insert({name, json::Null()}); + void + ModelTreeIterate(json::Object & o, const std::string & name, ModelPartParam mp) + { + if (name.empty()) { return; - case ModelPartType::Simple: { - json::Value v; - if (mp->GetValue(JsonValueTarget(v))) { - std::get<json::Object>(*n).insert({name, v}); - } - break; } - case ModelPartType::Complex: - if (mp->HasValue()) { - json::Object nn; - if (auto typeIdName = mp->GetTypeIdProperty()) { - if (auto typeId = mp->GetTypeId()) { - nn.insert({*typeIdName, *typeId}); - mp = mp->GetSubclassModelPart(*typeId); + ModelTreeIterateTo( + [&o, &name]() -> json::Value & { + return o[name]; + }, + mp); + } + + void + ModelTreeIterateTo(const std::function<json::Value &()> & n, ModelPartParam mp) + { + if (mp) { + switch (mp->GetType()) { + case ModelPartType::Null: + n().emplace<json::Null>(); + break; + case ModelPartType::Simple: + if (json::Value v; mp->GetValue(JsonValueTarget(v))) { + n() = std::move(v); } - } - mp->OnEachChild([capture0 = &std::get<json::Object>(*n).insert({name, nn}).first->second]( - auto && PH1, auto && PH2, auto &&) { - return JsonSerializer::ModelTreeIterate(capture0, PH1, PH2); - }); - } - break; - case ModelPartType::Sequence: - if (mp->HasValue()) { - mp->OnEachChild( - [capture0 = &std::get<json::Object>(*n).insert({name, json::Array()}).first->second]( - auto &&, auto && PH2, auto &&) { - return JsonSerializer::ModelTreeIterateSeq(capture0, PH2); + break; + case ModelPartType::Complex: + if (mp->HasValue()) { + auto oec = [&n](const auto & lmp) { + auto & obj = n().emplace<json::Object>(); + lmp->OnEachChild([&obj](auto && PH1, auto && PH2, auto &&) { + return ModelTreeIterate(obj, PH1, PH2); + }); + return &obj; + }; + if (auto typeIdName = mp->GetTypeIdProperty()) { + if (auto typeId = mp->GetTypeId()) { + return mp->OnSubclass( + [&oec, &typeIdName, &typeId](auto && lmp) { + oec(lmp)->emplace(*typeIdName, *typeId); + }, + *typeId); + } + } + oec(mp); + } + break; + case ModelPartType::Sequence: + if (mp->HasValue()) { + mp->OnEachChild([&arr = n().emplace<json::Array>()](auto &&, auto && PH2, auto &&) { + return ModelTreeIterateSeq(arr, PH2); }); - } - break; - case ModelPartType::Dictionary: - if (mp->HasValue()) { - if (mp->GetMetadata().flagSet(md_object)) { - mp->OnEachChild( - [capture0 = &std::get<json::Object>(*n).insert({name, json::Object()}).first->second]( - auto &&, auto && PH2, auto &&) { - return JsonSerializer::ModelTreeIterateDictObj(capture0, PH2); + } + break; + case ModelPartType::Dictionary: + if (mp->HasValue()) { + if (mp->GetMetadata().flagSet(md_object)) { + mp->OnEachChild([&obj = n().emplace<json::Object>()](auto &&, auto && PH2, auto &&) { + return ModelTreeIterateDictObj(obj, PH2); }); - } - else { - mp->OnEachChild( - [capture0 = &std::get<json::Object>(*n).insert({name, json::Array()}).first->second]( - auto &&, auto && PH2, auto &&) { - return JsonSerializer::ModelTreeIterateSeq(capture0, PH2); + } + else { + mp->OnEachChild([&arr = n().emplace<json::Array>()](auto &&, auto && PH2, auto &&) { + return ModelTreeIterateSeq(arr, PH2); }); - } - } - break; - } - } - - void - JsonSerializer::ModelTreeIterateRoot(json::Value * n, ModelPartPtr mp) - { - if (mp) { - switch (mp->GetType()) { - case ModelPartType::Null: - *n = json::Null(); - return; - case ModelPartType::Simple: - mp->GetValue(JsonValueTarget(*n)); - break; - case ModelPartType::Complex: - *n = json::Object(); - if (auto typeIdName = mp->GetTypeIdProperty()) { - if (auto typeId = mp->GetTypeId()) { - std::get<json::Object>(*n).insert({*typeIdName, *typeId}); - mp = mp->GetSubclassModelPart(*typeId); + } } - } - mp->OnEachChild([n](auto && PH1, auto && PH2, auto &&) { - return JsonSerializer::ModelTreeIterate(n, PH1, PH2); - }); - break; - case ModelPartType::Sequence: - *n = json::Array(); - mp->OnEachChild([n](auto &&, auto && PH2, auto &&) { - return JsonSerializer::ModelTreeIterateSeq(n, PH2); - }); - break; - case ModelPartType::Dictionary: - if (mp->GetMetadata().flagSet(md_object)) { - *n = json::Object(); - mp->OnEachChild([n](auto &&, auto && PH2, auto &&) { - return JsonSerializer::ModelTreeIterateDictObj(n, PH2); - }); - } - else { - *n = json::Array(); - mp->OnEachChild([n](auto && PH1, auto && PH2, auto &&) { - return JsonSerializer::ModelTreeIterate(n, PH1, PH2); - }); - } - break; + break; + } } } } @@ -358,15 +352,17 @@ namespace Slicer { JsonStreamDeserializer::JsonStreamDeserializer(std::istream & s) : strm(s) { } void - JsonStreamDeserializer::Deserialize(ModelPartForRootPtr modelRoot) + JsonStreamDeserializer::Deserialize(ModelPartForRootParam modelRoot) { - json::Value obj = json::parseValue(strm); - auto mp = modelRoot->GetAnonChild(); - std::visit(DocumentTreeIterate(mp), obj); + modelRoot->OnAnonChild( + [this](auto && mp, auto &&) { + DocumentTreeIterate::visit(mp, json::parseValue(strm)); + }, + {}); } void - JsonStreamSerializer::Serialize(ModelPartForRootPtr modelRoot) + JsonStreamSerializer::Serialize(ModelPartForRootParam modelRoot) { JsonValueSerializer::Serialize(modelRoot); json::serializeValue(value, strm, "utf-8"); @@ -377,28 +373,39 @@ namespace Slicer { JsonFileDeserializer::JsonFileDeserializer(std::filesystem::path p) : path(std::move(p)) { } void - JsonFileDeserializer::Deserialize(ModelPartForRootPtr modelRoot) + JsonFileDeserializer::Deserialize(ModelPartForRootParam modelRoot) { std::ifstream inFile(path); - json::Value obj = json::parseValue(inFile); - auto mp = modelRoot->GetAnonChild(); - std::visit(DocumentTreeIterate(mp), obj); + modelRoot->OnAnonChild( + [&inFile](auto && mp, auto &&) { + DocumentTreeIterate::visit(mp, json::parseValue(inFile)); + }, + {}); } JsonValueDeserializer::JsonValueDeserializer(const json::Value & v) : value(v) { } void - JsonValueDeserializer::Deserialize(ModelPartForRootPtr modelRoot) + JsonValueDeserializer::Deserialize(ModelPartForRootParam modelRoot) { - auto mp = modelRoot->GetAnonChild(); - std::visit(DocumentTreeIterate(mp), value); + modelRoot->OnAnonChild( + [this](auto && mp, auto &&) { + DocumentTreeIterate::visit(mp, value); + }, + {}); } + JsonValueSerializer::~JsonValueSerializer() = default; + void - JsonValueSerializer::Serialize(ModelPartForRootPtr modelRoot) + JsonValueSerializer::Serialize(ModelPartForRootParam modelRoot) { modelRoot->OnEachChild([this](auto &&, auto && PH2, auto &&) { - return JsonSerializer::ModelTreeIterateRoot(&value, PH2); + return ModelTreeIterateTo( + [this]() -> json::Value & { + return value; + }, + PH2); }); } } diff --git a/slicer/json/serializer.h b/slicer/json/serializer.h index e2687ce..682ec27 100644 --- a/slicer/json/serializer.h +++ b/slicer/json/serializer.h @@ -11,17 +11,13 @@ #include <visibility.h> namespace Slicer { - class JsonSerializer : public Serializer { - protected: - static void ModelTreeIterate(json::Value *, const std::string &, ModelPartPtr mp); - static void ModelTreeIterateDictObj(json::Value *, const ModelPartPtr & mp); - static void ModelTreeIterateSeq(json::Value *, const ModelPartPtr & mp); - static void ModelTreeIterateRoot(json::Value *, ModelPartPtr mp); - }; - - class DLL_PUBLIC JsonValueSerializer : public JsonSerializer { + class DLL_PUBLIC JsonValueSerializer : public Serializer { public: - void Serialize(ModelPartForRootPtr) override; + JsonValueSerializer() = default; + ~JsonValueSerializer() override; + SPECIAL_MEMBERS_DEFAULT(JsonValueSerializer); + + void Serialize(ModelPartForRootParam) override; protected: json::Value value; @@ -31,7 +27,7 @@ namespace Slicer { public: explicit JsonStreamSerializer(std::ostream &); - void Serialize(ModelPartForRootPtr) override; + void Serialize(ModelPartForRootParam) override; protected: std::ostream & strm; @@ -49,7 +45,7 @@ namespace Slicer { public: explicit JsonStreamDeserializer(std::istream &); - void Deserialize(ModelPartForRootPtr) override; + void Deserialize(ModelPartForRootParam) override; protected: std::istream & strm; @@ -59,7 +55,7 @@ namespace Slicer { public: explicit JsonFileDeserializer(std::filesystem::path); - void Deserialize(ModelPartForRootPtr) override; + void Deserialize(ModelPartForRootParam) override; protected: const std::filesystem::path path; @@ -69,7 +65,7 @@ namespace Slicer { public: explicit JsonValueDeserializer(const json::Value &); - void Deserialize(ModelPartForRootPtr) override; + void Deserialize(ModelPartForRootParam) override; protected: const json::Value & value; diff --git a/slicer/slicer/any_ptr.h b/slicer/slicer/any_ptr.h new file mode 100644 index 0000000..14199c0 --- /dev/null +++ b/slicer/slicer/any_ptr.h @@ -0,0 +1,60 @@ +#pragma once + +#include <memory> +#include <vector> + +namespace Slicer { + template<typename T> struct any_ptr { + // cppcheck-suppress noExplicitConstructor + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline constexpr any_ptr(T * p) noexcept : ptr {p} { } + + // cppcheck-suppress noExplicitConstructor + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline constexpr any_ptr(T & p) noexcept : ptr {&p} { } + + // cppcheck-suppress noExplicitConstructor + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline constexpr any_ptr(T && p) noexcept : ptr {&p} { } + + template<typename S> + requires requires(S p) { p.get(); } + // cppcheck-suppress noExplicitConstructor + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline constexpr any_ptr(const S & p) noexcept : ptr {p.get()} + { + } + + inline constexpr auto + get() const noexcept + { + return ptr; + } + + inline constexpr auto + operator->() const noexcept + { + return ptr; + } + + inline constexpr auto & + operator*() const noexcept + { + return *ptr; + } + + inline constexpr explicit operator bool() const noexcept + { + return ptr; + } + + inline constexpr bool + operator!() const noexcept + { + return !ptr; + } + + private: + T * ptr; + }; +} diff --git a/slicer/slicer/enumMap.h b/slicer/slicer/enumMap.h index 4c50bd8..e076a0c 100644 --- a/slicer/slicer/enumMap.h +++ b/slicer/slicer/enumMap.h @@ -52,6 +52,7 @@ namespace Slicer { EnumMap<E>::begin = arr.begin(); EnumMap<E>::end = arr.end(); } + const Arr<N> arr; }; } diff --git a/slicer/slicer/hook-test.cpp b/slicer/slicer/hook-test.cpp index 3af28b4..2fa1b8b 100644 --- a/slicer/slicer/hook-test.cpp +++ b/slicer/slicer/hook-test.cpp @@ -15,6 +15,7 @@ namespace test { int AA; std::string b; }; + const std::string aa {"aa"}, aA {"aA"}, Aa {"Aa"}, AA {"AA"}, b {"b"}; using C = Slicer::ModelPartForComplex<S>; diff --git a/slicer/slicer/hookMap.cpp b/slicer/slicer/hookMap.cpp index 6e17a38..c32db2d 100644 --- a/slicer/slicer/hookMap.cpp +++ b/slicer/slicer/hookMap.cpp @@ -3,8 +3,14 @@ namespace Slicer { void - to_lower(std::string s) + to_lower(std::string & s) { boost::algorithm::to_lower(s); } + + std::string + to_lower_copy(const std::string & s) + { + return boost::algorithm::to_lower_copy(s); + } } diff --git a/slicer/slicer/hookMap.h b/slicer/slicer/hookMap.h index 92035de..3328ddd 100644 --- a/slicer/slicer/hookMap.h +++ b/slicer/slicer/hookMap.h @@ -10,9 +10,11 @@ #include <visibility.h> namespace Slicer { - void DLL_PUBLIC to_lower(std::string s); + void DLL_PUBLIC to_lower(std::string & s); + [[nodiscard]] std::string DLL_PUBLIC to_lower_copy(const std::string & s); template<typename T> class ModelPartForComplex; // IWYU pragma: keep + template<typename T> class Hooks { public: using HookPtr = const typename ModelPartForComplex<T>::HookBase *; @@ -27,6 +29,8 @@ namespace Slicer { using pointer = HookPtr *; using reference = HookPtr &; + [[nodiscard]] constexpr inline explicit iter(const eq * const r) : range(r), cur(r->e) { } + [[nodiscard]] constexpr inline iter(const eq * const r, const HookPtr * c) : range(r), cur(c) { moveMatch(); @@ -92,13 +96,13 @@ namespace Slicer { [[nodiscard]] constexpr inline iter begin() const { - return {this, b}; + return iter {this, b}; } [[nodiscard]] constexpr inline iter end() const { - return {this, e}; + return iter {this}; } std::string_view key {}; diff --git a/slicer/slicer/metadata.h b/slicer/slicer/metadata.h index 6b209ae..8f24edb 100644 --- a/slicer/slicer/metadata.h +++ b/slicer/slicer/metadata.h @@ -109,6 +109,7 @@ namespace Slicer { template<std::size_t N> class DLL_PUBLIC MetaDataImpl : public MetaData<> { public: using Arr = ContainerBase<N>; + constexpr inline explicit MetaDataImpl(const std::array<std::string_view, N> & a) : arr {[&a]() { Arr rtn; diff --git a/slicer/slicer/modelParts.cpp b/slicer/slicer/modelParts.cpp index 7a31b05..07b4095 100644 --- a/slicer/slicer/modelParts.cpp +++ b/slicer/slicer/modelParts.cpp @@ -11,10 +11,10 @@ namespace Slicer { { } - ModelPartPtr - ModelPart::GetSubclassModelPart(const std::string &) + void + ModelPart::OnSubclass(const ModelPartHandler &, const std::string &) { - return shared_from_this(); + throw std::logic_error {"OnSubclass not supported on this ModelPart"}; } TypeId @@ -46,30 +46,33 @@ namespace Slicer { return emptyMetadata; } - ModelPartPtr - ModelPart::GetAnonChild(const HookFilter & flt) + bool + ModelPart::IsOptional() const { - auto ref = GetAnonChildRef(flt); - return ref ? ref.Child() : ModelPartPtr(nullptr); + return false; } - ModelPartPtr - ModelPart::GetChild(std::string_view memberName, const HookFilter & flt) + void + ModelPart::OnEachChild(const ChildHandler &) { - auto ref = GetChildRef(memberName, flt); - return ref ? ref.Child() : ModelPartPtr(nullptr); } bool - ModelPart::IsOptional() const + ModelPart::OnAnonChild(const SubPartHandler &, const HookFilter &) { return false; } - ModelPartPtr - ModelPart::GetContainedModelPart() + bool + ModelPart::OnChild(const SubPartHandler &, const std::string_view, const HookFilter &, bool) + { + return false; + } + + void + ModelPart::OnContained(const ModelPartHandler &) { - return shared_from_this(); + throw std::logic_error {"OnContained not supported on this ModelPart"}; } bool @@ -79,7 +82,7 @@ namespace Slicer { } void - HookCommon::apply(const ChildHandler & ch, const ModelPartPtr & modelPart) const + HookCommon::apply(const ChildHandler & ch, ModelPartParam modelPart) const { ch(*this->nameStr, modelPart, this); } diff --git a/slicer/slicer/modelParts.h b/slicer/slicer/modelParts.h index 1986a95..8adc8f2 100644 --- a/slicer/slicer/modelParts.h +++ b/slicer/slicer/modelParts.h @@ -1,6 +1,7 @@ #ifndef SLICER_MODELPARTS_H #define SLICER_MODELPARTS_H +#include "any_ptr.h" #include "metadata.h" #include <Ice/Config.h> #include <c++11Helpers.h> @@ -24,6 +25,7 @@ namespace Slicer { virtual void get(const T &) const = 0; SPECIAL_MEMBERS_DEFAULT(TValueTarget); }; + class ValueTarget : public TValueTarget<bool>, public TValueTarget<Ice::Byte>, @@ -51,6 +53,7 @@ namespace Slicer { virtual void set(T &) const = 0; SPECIAL_MEMBERS_DEFAULT(TValueSource); }; + class ValueSource : public TValueSource<bool>, public TValueSource<Ice::Byte>, @@ -75,13 +78,16 @@ namespace Slicer { class ModelPartForRootBase; class HookCommon; - using ModelPartPtr = std::shared_ptr<ModelPart>; - using ModelPartForRootPtr = std::shared_ptr<ModelPartForRootBase>; + using ModelPartParam = any_ptr<ModelPart>; + using ModelPartForRootParam = any_ptr<ModelPartForRootBase>; using TypeId = std::optional<std::string>; - using ChildHandler = std::function<void(const std::string &, ModelPartPtr, const HookCommon *)>; - using ClassRef = std::function<ModelPartPtr(void *)>; - using HookFilter = std::function<bool(const HookCommon *)>; using Metadata = MetaData<>; + using ChildHandler = std::function<void(const std::string &, ModelPartParam, const HookCommon *)>; + using ModelPartHandler = std::function<void(ModelPartParam)>; + using ModelPartRootHandler = std::function<void(ModelPartForRootParam)>; + using SubPartHandler = std::function<void(ModelPartParam, const Metadata &)>; + using ClassRef = std::function<void(void *, const ModelPartHandler &)>; + using HookFilter = std::function<bool(const HookCommon *)>; constexpr Metadata emptyMetadata; enum class ModelPartType { @@ -98,32 +104,18 @@ namespace Slicer { Value, }; - class DLL_PUBLIC ChildRef { - public: - explicit ChildRef(); - explicit ChildRef(ModelPartPtr); - explicit ChildRef(ModelPartPtr, const Metadata &); - - [[nodiscard]] ModelPartPtr Child() const; - [[nodiscard]] const Metadata & ChildMetaData() const; - explicit operator bool() const; - - private: - ModelPartPtr mpp; - const Metadata & mdr; - }; - class DLL_PUBLIC HookCommon { public: constexpr HookCommon(std::string_view n, std::string_view nl, const std::string * ns) : name(n), nameLower(nl), nameStr(ns) { } + virtual ~HookCommon() = default; SPECIAL_MEMBERS_DEFAULT(HookCommon); [[nodiscard]] bool filter(const HookFilter & flt) const; - void apply(const ChildHandler & ch, const ModelPartPtr & modelPart) const; + void apply(const ChildHandler & ch, ModelPartParam modelPart) const; [[nodiscard]] virtual const Metadata & GetMetadata() const = 0; @@ -132,10 +124,9 @@ namespace Slicer { const std::string * nameStr; }; - template<typename T> struct DLL_PUBLIC Default { - }; + template<typename T> struct DLL_PUBLIC Default { }; - class DLL_PUBLIC ModelPart : public std::enable_shared_from_this<ModelPart> { + class DLL_PUBLIC ModelPart { public: ModelPart() = default; ModelPart(const ModelPart &) = delete; @@ -146,19 +137,16 @@ namespace Slicer { ModelPart & operator=(const ModelPart &) = delete; ModelPart & operator=(ModelPart &&) = delete; - template<typename MP> static ModelPartPtr Make(typename MP::element_type * t); - template<typename T> static ModelPartPtr CreateFor(T & t); - template<typename T> static ModelPartPtr CreateFor(Default<T> &&); - template<typename T> static ModelPartForRootPtr CreateRootFor(T & t); - - virtual void OnEachChild(const ChildHandler &) = 0; - ModelPartPtr GetAnonChild(const HookFilter & = HookFilter()); - ModelPartPtr GetChild(std::string_view memberName, const HookFilter & = HookFilter()); - virtual ChildRef GetAnonChildRef(const HookFilter & = HookFilter()) = 0; - virtual ChildRef GetChildRef( - std::string_view memberName, const HookFilter & = HookFilter(), bool matchCase = true) - = 0; - virtual ModelPartPtr GetSubclassModelPart(const std::string &); + template<typename MP> static void Make(typename MP::element_type * t, const ModelPartHandler &); + template<typename T> static void CreateFor(T & t, const ModelPartHandler &); + template<typename T> static void CreateFor(Default<T> &&, const ModelPartHandler &); + template<typename T> static void OnRootFor(T & t, const ModelPartRootHandler &); + + virtual void OnEachChild(const ChildHandler &); + virtual bool OnAnonChild(const SubPartHandler &, const HookFilter & = HookFilter()); + virtual bool OnChild(const SubPartHandler &, std::string_view memberName, const HookFilter & = HookFilter(), + bool matchCase = true); + virtual void OnSubclass(const ModelPartHandler &, const std::string &); virtual TypeId GetTypeId() const; virtual std::optional<std::string> GetTypeIdProperty() const; virtual ModelPartType GetType() const = 0; @@ -169,30 +157,31 @@ namespace Slicer { virtual bool HasValue() const = 0; virtual const Metadata & GetMetadata() const; virtual bool IsOptional() const; - virtual ModelPartPtr GetContainedModelPart(); + virtual void OnContained(const ModelPartHandler &); }; template<typename T> class DLL_PUBLIC ModelPartModel { public: explicit ModelPartModel(T * m = nullptr) : Model(m) { } + T * Model; }; class DLL_PUBLIC ModelPartForRootBase : public ModelPart { public: - explicit ModelPartForRootBase(ModelPartPtr mp); + explicit ModelPartForRootBase(ModelPartParam mp); virtual const std::string & GetRootName() const = 0; - ChildRef GetAnonChildRef(const HookFilter &) override; - ChildRef GetChildRef(std::string_view name, const HookFilter &, bool matchCase = true) override; + bool OnAnonChild(const SubPartHandler &, const HookFilter &) override; + bool OnChild(const SubPartHandler &, std::string_view name, const HookFilter &, bool matchCase = true) override; void OnEachChild(const ChildHandler & ch) override; ModelPartType GetType() const override; bool IsOptional() const override; virtual void Write(::Ice::OutputStream &) const = 0; virtual void Read(::Ice::InputStream &) = 0; - ModelPartPtr GetContainedModelPart() override; + void OnContained(const ModelPartHandler &) override; - ModelPartPtr mp; + ModelPartParam mp; }; } diff --git a/slicer/slicer/modelPartsTypes.cpp b/slicer/slicer/modelPartsTypes.cpp index 47543a6..673265e 100644 --- a/slicer/slicer/modelPartsTypes.cpp +++ b/slicer/slicer/modelPartsTypes.cpp @@ -17,6 +17,7 @@ #include <string> #include <string_view> #include <utility> + // IWYU pragma: no_forward_declare boost::multi_index::member // IWYU pragma: no_include <boost/operators.hpp> @@ -37,45 +38,26 @@ namespace Slicer { boost::multi_index::member<ClassNamePair, const std::string, &ClassNamePair::second>, std::less<>>>>; - static void createClassMaps() __attribute__((constructor(208))); - static void deleteClassMaps() __attribute__((destructor(208))); - static ClassNameMap * names; - static ClassRefMap * refs; - - void - createClassMaps() - { - names = new ClassNameMap(); - refs = new ClassRefMap(); - } - - static void - deleteClassMaps() - { - delete names; - delete refs; - names = nullptr; - refs = nullptr; - } + namespace { + constinit std::unique_ptr<ClassNameMap> names; + constinit std::unique_ptr<ClassRefMap> refs; - ClassNameMap * - classNameMap() - { - return names; - } + void createClassMaps() __attribute__((constructor(208))); - ClassRefMap * - classRefMap() - { - return refs; + void + createClassMaps() + { + names = std::make_unique<ClassNameMap>(); + refs = std::make_unique<ClassRefMap>(); + } } const std::string & ModelPartForComplexBase::ToModelTypeName(const std::string & name) { - auto & right = classNameMap()->get<1>(); - auto mapped = right.find(name); - if (mapped != right.end()) { + const auto & right = names->get<1>(); + + if (const auto mapped = right.find(name); mapped != right.end()) { return mapped->first; } return name; @@ -84,9 +66,9 @@ namespace Slicer { const std::string & ModelPartForComplexBase::ToExchangeTypeName(const std::string & name) { - auto & left = classNameMap()->get<0>(); - auto mapped = left.find(name); - if (mapped != left.end()) { + const auto & left = names->get<0>(); + + if (const auto mapped = left.find(name); mapped != left.end()) { return mapped->second; } return name; @@ -126,22 +108,24 @@ namespace Slicer { } // ModelPartForRootBase - ModelPartForRootBase::ModelPartForRootBase(ModelPartPtr m) : mp(std::move(m)) { } + ModelPartForRootBase::ModelPartForRootBase(ModelPartParam m) : mp(m) { } - ChildRef - ModelPartForRootBase::GetAnonChildRef(const HookFilter &) + bool + ModelPartForRootBase::OnAnonChild(const SubPartHandler & h, const HookFilter &) { mp->Create(); - return ChildRef(mp); + h(mp, emptyMetadata); + return true; } - ChildRef - ModelPartForRootBase::GetChildRef(std::string_view name, const HookFilter & hf, bool matchCase) + bool + ModelPartForRootBase::OnChild( + const SubPartHandler & h, std::string_view name, const HookFilter & hf, bool matchCase) { if (!optionalCaseEq(name, GetRootName(), matchCase)) { throw IncorrectElementName(std::string {name}); } - return GetAnonChildRef(hf); + return OnAnonChild(h, hf); } void @@ -162,67 +146,44 @@ namespace Slicer { return mp->IsOptional(); } - ModelPartPtr - ModelPartForRootBase::GetContainedModelPart() - { - return mp->GetContainedModelPart(); - } - void - ModelPartForSimpleBase::OnEachChild(const ChildHandler &) - { - } - ChildRef - ModelPartForSimpleBase::GetAnonChildRef(const HookFilter &) - { - return ChildRef(); - } - ChildRef - ModelPartForSimpleBase::GetChildRef(std::string_view, const HookFilter &, bool) + ModelPartForRootBase::OnContained(const ModelPartHandler & h) { - return ChildRef(); + return mp->OnContained(h); } + bool ModelPartForSimpleBase::HasValue() const { return true; } + ModelPartType ModelPartForSimpleBase::GetType() const { return type; } + const ModelPartType ModelPartForSimpleBase::type = ModelPartType::Simple; - void - ModelPartForConvertedBase::OnEachChild(const ChildHandler &) - { - } - ChildRef - ModelPartForConvertedBase::GetAnonChildRef(const HookFilter &) - { - return ChildRef(); - } - ChildRef - ModelPartForConvertedBase::GetChildRef(std::string_view, const HookFilter &, bool) - { - return ChildRef(); - } bool ModelPartForConvertedBase::HasValue() const { return true; } + ModelPartType ModelPartForConvertedBase::GetType() const { return type; } + void ModelPartForConvertedBase::conversion_fail(std::string_view typeName) { throw NoConversionFound(std::string {typeName}); } + const ModelPartType ModelPartForConvertedBase::type = ModelPartType::Simple; ModelPartType @@ -230,33 +191,37 @@ namespace Slicer { { return type; } + const ModelPartType ModelPartForComplexBase::type = ModelPartType::Complex; + void ModelPartForComplexBase::registerClass( const std::string & className, const std::string * typeName, const ClassRef & cr) { - Slicer::classRefMap()->insert({className, cr}); + refs->emplace(className, cr); if (typeName) { - Slicer::classNameMap()->insert({className, *typeName}); + names->emplace(className, *typeName); } } + void ModelPartForComplexBase::unregisterClass(const std::string & className, const std::string * typeName) { - Slicer::classRefMap()->erase(className); + refs->erase(className); if (typeName) { - classNameMap()->get<0>().erase(className); + names->get<0>().erase(className); } } - ModelPartPtr - ModelPartForComplexBase::getSubclassModelPart(const std::string & name, void * m) + + void + ModelPartForComplexBase::onSubclass(const std::string & name, void * m, const ModelPartHandler & h) { - auto ref = classRefMap()->find(ToModelTypeName(name)); - if (ref == classRefMap()->end()) { - throw UnknownType(name); + if (const auto ref = refs->find(ToModelTypeName(name)); ref != refs->end()) { + return ref->second(m, h); } - return ref->second(m); + throw UnknownType(name); } + TypeId ModelPartForComplexBase::getTypeId(const std::string & id, const std::string & className) { @@ -287,22 +252,23 @@ namespace Slicer { } } - ChildRef - ModelPartForOptionalBase::GetAnonChildRef(const HookFilter & flt) + bool + ModelPartForOptionalBase::OnAnonChild(const SubPartHandler & h, const HookFilter & flt) { if (this->hasModel()) { - return modelPart->GetAnonChildRef(flt); + return modelPart->OnAnonChild(h, flt); } - return ChildRef(); + return false; } - ChildRef - ModelPartForOptionalBase::GetChildRef(std::string_view name, const HookFilter & flt, bool matchCase) + bool + ModelPartForOptionalBase::OnChild( + const SubPartHandler & h, std::string_view name, const HookFilter & flt, bool matchCase) { if (this->hasModel()) { - return modelPart->GetChildRef(name, flt, matchCase); + return modelPart->OnChild(h, name, flt, matchCase); } - return ChildRef(); + return false; } void @@ -331,30 +297,18 @@ namespace Slicer { return modelPart->GetMetadata(); } - void - ModelPartForEnumBase::OnEachChild(const ChildHandler &) - { - } - ChildRef - ModelPartForEnumBase::GetAnonChildRef(const HookFilter &) - { - return ChildRef(); - } - ChildRef - ModelPartForEnumBase::GetChildRef(std::string_view, const HookFilter &, bool) - { - return ChildRef(); - } bool ModelPartForEnumBase::HasValue() const { return true; } + ModelPartType ModelPartForEnumBase::GetType() const { return type; } + const ModelPartType ModelPartForEnumBase::type = ModelPartType::Simple; bool @@ -362,19 +316,23 @@ namespace Slicer { { return true; } + ModelPartType ModelPartForSequenceBase::GetType() const { return type; } - ChildRef - ModelPartForSequenceBase::GetChildRef(std::string_view name, const HookFilter & flt, bool matchCase) + + bool + ModelPartForSequenceBase::OnChild( + const SubPartHandler & h, std::string_view name, const HookFilter & flt, bool matchCase) { if (!name.empty() && !optionalCaseEq(name, GetElementName(), matchCase)) { throw IncorrectElementName(std::string {name}); } - return GetAnonChildRef(flt); + return OnAnonChild(h, flt); } + const ModelPartType ModelPartForSequenceBase::type = ModelPartType::Sequence; bool @@ -382,55 +340,48 @@ namespace Slicer { { return true; } + ModelPartType ModelPartForDictionaryBase::GetType() const { return type; } + const ModelPartType ModelPartForDictionaryBase::type = ModelPartType::Dictionary; // Streams - // NOLINTNEXTLINE(hicpp-no-array-decay) - ChildRef - ModelPartForStreamBase::GetAnonChildRef(const Slicer::HookFilter &) - { - throw InvalidStreamOperation(__FUNCTION__); - } - // NOLINTNEXTLINE(hicpp-no-array-decay) - ChildRef - ModelPartForStreamBase::GetChildRef(std::string_view, const Slicer::HookFilter &, bool) - { - throw InvalidStreamOperation(__FUNCTION__); - } ModelPartType ModelPartForStreamBase::GetType() const { return ModelPartType::Sequence; } + bool ModelPartForStreamBase::HasValue() const { return true; } - // Stream Roots - ModelPartForStreamRootBase::ModelPartForStreamRootBase(const ModelPartPtr & m) : ModelPartForRootBase(m) { } + // NOLINTNEXTLINE(hicpp-no-array-decay) void ModelPartForStreamRootBase::Write(Ice::OutputStream &) const { throw InvalidStreamOperation(__FUNCTION__); } + // NOLINTNEXTLINE(hicpp-no-array-decay) void ModelPartForStreamRootBase::Read(Ice::InputStream &) { throw InvalidStreamOperation(__FUNCTION__); } + bool ModelPartForStreamRootBase::HasValue() const { return mp->HasValue(); } + void ModelPartForStreamRootBase::OnEachChild(const ChildHandler & ch) { diff --git a/slicer/slicer/modelPartsTypes.h b/slicer/slicer/modelPartsTypes.h index 0355c62..2079195 100644 --- a/slicer/slicer/modelPartsTypes.h +++ b/slicer/slicer/modelPartsTypes.h @@ -26,7 +26,7 @@ namespace Slicer { template<typename T> class ModelPartForRoot : public ModelPartForRootBase { public: - explicit ModelPartForRoot(T * o); + explicit ModelPartForRoot(T * o, ModelPartParam mp); const std::string & GetRootName() const override; bool HasValue() const override; @@ -41,9 +41,6 @@ namespace Slicer { class DLL_PUBLIC ModelPartForSimpleBase : public ModelPart { public: - void OnEachChild(const ChildHandler &) override; - ChildRef GetAnonChildRef(const HookFilter &) override; - ChildRef GetChildRef(std::string_view, const HookFilter &, bool matchCase = true) override; bool HasValue() const override; ModelPartType GetType() const override; static const ModelPartType type; @@ -62,9 +59,6 @@ namespace Slicer { class DLL_PUBLIC ModelPartForConvertedBase : public ModelPart { public: - void OnEachChild(const ChildHandler &) override; - ChildRef GetAnonChildRef(const HookFilter &) override; - ChildRef GetChildRef(std::string_view, const HookFilter &, bool matchCase = true) override; bool HasValue() const override; ModelPartType GetType() const override; static const ModelPartType type; @@ -109,8 +103,9 @@ namespace Slicer { public: void OnEachChild(const ChildHandler & ch) override; void Complete() override; - ChildRef GetAnonChildRef(const HookFilter & flt) override; - ChildRef GetChildRef(std::string_view name, const HookFilter & flt, bool matchCase = true) override; + bool OnAnonChild(const SubPartHandler &, const HookFilter & flt) override; + bool OnChild( + const SubPartHandler &, std::string_view name, const HookFilter & flt, bool matchCase = true) override; void SetValue(ValueSource && s) override; bool HasValue() const override; bool IsOptional() const override; @@ -118,7 +113,7 @@ namespace Slicer { protected: virtual bool hasModel() const = 0; - ModelPartPtr modelPart; + ModelPart * modelPart; }; template<typename T> @@ -134,6 +129,7 @@ namespace Slicer { protected: bool hasModel() const override; + std::optional<T> modelPartOwner; }; class DLL_PUBLIC ModelPartForComplexBase : public ModelPart { @@ -142,7 +138,7 @@ namespace Slicer { static const ModelPartType type; protected: - ModelPartPtr getSubclassModelPart(const std::string & name, void * m); + void onSubclass(const std::string & name, void * m, const ModelPartHandler &); static void registerClass(const std::string & className, const std::string * typeName, const ClassRef &); static void unregisterClass(const std::string & className, const std::string * typeName); @@ -154,6 +150,7 @@ namespace Slicer { }; template<typename T> class Hooks; + template<typename T> class ModelPartForComplex : public ModelPartForComplexBase { public: class HookBase; @@ -162,15 +159,16 @@ namespace Slicer { void OnEachChild(const ChildHandler & ch) override; - ChildRef GetAnonChildRef(const HookFilter & flt) override; - ChildRef GetChildRef(std::string_view name, const HookFilter & flt, bool matchCase = true) override; + bool OnAnonChild(const SubPartHandler &, const HookFilter & flt) override; + bool OnChild( + const SubPartHandler &, std::string_view name, const HookFilter & flt, bool matchCase = true) override; const Metadata & GetMetadata() const override; virtual T * GetModel() = 0; protected: - template<typename R> ChildRef GetChildRefFromRange(const R & range, const HookFilter & flt); + template<typename R> bool OnChildFromRange(const SubPartHandler &, const R & range, const HookFilter & flt); static const Hooks<T> & hooks(); }; @@ -186,7 +184,7 @@ namespace Slicer { T * GetModel() override; - ModelPartPtr GetSubclassModelPart(const std::string & name) override; + void OnSubclass(const ModelPartHandler &, const std::string & name) override; [[nodiscard]] bool HasValue() const override; @@ -198,7 +196,7 @@ namespace Slicer { static const std::string * className; static const std::string * typeName; - static ModelPartPtr CreateModelPart(void *); + static void CreateModelPart(void *, const ModelPartHandler &); private: static void initClassName(); @@ -220,9 +218,6 @@ namespace Slicer { class DLL_PUBLIC ModelPartForEnumBase : public ModelPart { public: - void OnEachChild(const ChildHandler &) override; - ChildRef GetAnonChildRef(const HookFilter &) override; - ChildRef GetChildRef(std::string_view, const HookFilter &, bool matchCase = true) override; bool HasValue() const override; ModelPartType GetType() const override; static const ModelPartType type; @@ -251,7 +246,7 @@ namespace Slicer { public: bool HasValue() const override; ModelPartType GetType() const override; - ChildRef GetChildRef(std::string_view, const HookFilter &, bool matchCase = true) override; + bool OnChild(const SubPartHandler &, std::string_view, const HookFilter &, bool matchCase = true) override; virtual const std::string & GetElementName() const = 0; static const ModelPartType type; @@ -265,19 +260,16 @@ namespace Slicer { void OnEachChild(const ChildHandler & ch) override; - ChildRef GetAnonChildRef(const HookFilter &) override; + bool OnAnonChild(const SubPartHandler &, const HookFilter &) override; const std::string & GetElementName() const override; const Metadata & GetMetadata() const override; - ModelPartPtr GetContainedModelPart() override; + void OnContained(const ModelPartHandler &) override; static const Metadata metadata; static const std::string elementName; - - private: - ModelPartPtr elementModelPart(typename T::value_type &) const; }; template<typename T> @@ -308,13 +300,13 @@ namespace Slicer { void OnEachChild(const ChildHandler & ch) override; - ChildRef GetAnonChildRef(const HookFilter &) override; + bool OnAnonChild(const SubPartHandler &, const HookFilter &) override; - ChildRef GetChildRef(std::string_view name, const HookFilter &, bool matchCase = true) override; + bool OnChild(const SubPartHandler &, std::string_view name, const HookFilter &, bool matchCase = true) override; const Metadata & GetMetadata() const override; - ModelPartPtr GetContainedModelPart() override; + void OnContained(const ModelPartHandler &) override; static const Metadata metadata; static const std::string pairName; @@ -336,10 +328,8 @@ namespace Slicer { public: ModelPartType GetType() const override; bool HasValue() const override; - ChildRef GetAnonChildRef(const HookFilter &) override; - ChildRef GetChildRef(std::string_view, const HookFilter &, bool matchCase = true) override; - ModelPartPtr GetContainedModelPart() override = 0; + void OnContained(const ModelPartHandler &) override = 0; void OnEachChild(const ChildHandler & ch) override = 0; }; @@ -347,13 +337,13 @@ namespace Slicer { public: using ModelPartModel<Stream<T>>::ModelPartModel; - ModelPartPtr GetContainedModelPart() override; + void OnContained(const ModelPartHandler &) override; void OnEachChild(const ChildHandler & ch) override; }; class DLL_PUBLIC ModelPartForStreamRootBase : public ModelPartForRootBase { public: - explicit ModelPartForStreamRootBase(const ModelPartPtr & mp); + using ModelPartForRootBase::ModelPartForRootBase; void Write(Ice::OutputStream &) const override; void Read(Ice::InputStream &) override; @@ -364,7 +354,7 @@ namespace Slicer { template<typename T> class ModelPartForStreamRoot : public ModelPartForStreamRootBase { public: - explicit ModelPartForStreamRoot(Stream<T> * s); + using ModelPartForStreamRootBase::ModelPartForStreamRootBase; const std::string & GetRootName() const override; }; diff --git a/slicer/slicer/modelPartsTypes.impl.h b/slicer/slicer/modelPartsTypes.impl.h index 5423152..ad1a90f 100644 --- a/slicer/slicer/modelPartsTypes.impl.h +++ b/slicer/slicer/modelPartsTypes.impl.h @@ -26,61 +26,68 @@ #include <utility> #include <vector> #include <visibility.h> + // IWYU pragma: no_forward_declare Slicer::EnumMap namespace Ice { class Object; } #define CUSTOMMODELPARTFOR(Type, BaseModelPart, ModelPartType) \ - template<> DLL_PUBLIC ModelPartPtr ModelPart::Make<ModelPartType>(typename ModelPartType::element_type * t) \ + template<> \ + DLL_PUBLIC void ModelPart::Make<ModelPartType>( \ + typename ModelPartType::element_type * t, const ModelPartHandler & h) \ { \ - return std::make_shared<ModelPartType>(t); \ + h(ModelPartType(t)); \ } \ template<> \ - DLL_PUBLIC ModelPartPtr ModelPart::Make<ModelPartForOptional<ModelPartType>>( \ - Ice::optional<typename ModelPartType::element_type> * t) \ + DLL_PUBLIC void ModelPart::Make<ModelPartForOptional<ModelPartType>>( \ + Ice::optional<typename ModelPartType::element_type> * t, const ModelPartHandler & h) \ { \ - return std::make_shared<ModelPartForOptional<ModelPartType>>(t); \ + h(ModelPartForOptional<ModelPartType>(t)); \ } \ - template<> DLL_PUBLIC ModelPartPtr ModelPart::CreateFor(Default<Type> &&) \ + template<> DLL_PUBLIC void ModelPart::CreateFor(Default<Type> &&, const ModelPartHandler & h) \ { \ - return Make<ModelPartType>(nullptr); \ + return Make<ModelPartType>(nullptr, h); \ } \ - template<> DLL_PUBLIC ModelPartPtr ModelPart::CreateFor(Default<Ice::optional<Type>> &&) \ + template<> DLL_PUBLIC void ModelPart::CreateFor(Default<Ice::optional<Type>> &&, const ModelPartHandler & h) \ { \ - return Make<ModelPartForOptional<ModelPartType>>(nullptr); \ + return Make<ModelPartForOptional<ModelPartType>>(nullptr, h); \ } \ - template<> DLL_PUBLIC ModelPartPtr ModelPart::CreateFor(Type & s) \ + template<> DLL_PUBLIC void ModelPart::CreateFor(Type & s, const ModelPartHandler & h) \ { \ - return Make<ModelPartType>(&s); \ + return Make<ModelPartType>(&s, h); \ } \ - template<> DLL_PUBLIC ModelPartPtr ModelPart::CreateFor(const Type & s) \ + template<> DLL_PUBLIC void ModelPart::CreateFor(const Type & s, const ModelPartHandler & h) \ { \ - return CreateFor(const_cast<Type &>(s)); \ + return CreateFor(const_cast<Type &>(s), h); \ } \ - template<> DLL_PUBLIC ModelPartPtr ModelPart::CreateFor(Ice::optional<Type> & s) \ + template<> DLL_PUBLIC void ModelPart::CreateFor(Ice::optional<Type> & s, const ModelPartHandler & h) \ { \ - return Make<ModelPartForOptional<ModelPartType>>(&s); \ + return Make<ModelPartForOptional<ModelPartType>>(&s, h); \ } \ - template<> DLL_PUBLIC ModelPartPtr ModelPart::CreateFor(const Ice::optional<Type> & s) \ + template<> DLL_PUBLIC void ModelPart::CreateFor(const Ice::optional<Type> & s, const ModelPartHandler & h) \ { \ - return CreateFor(const_cast<Ice::optional<Type> &>(s)); \ + return CreateFor(const_cast<Ice::optional<Type> &>(s), h); \ } \ - template<> DLL_PUBLIC ModelPartForRootPtr ModelPart::CreateRootFor(Type & s) \ + template<> DLL_PUBLIC void ModelPart::OnRootFor(Type & s, const ModelPartRootHandler & h) \ { \ - return std::make_shared<ModelPartForRoot<Type>>(&s); \ + return CreateFor(s, [&s, &h](auto && mp) { \ + h(ModelPartForRoot<Type>(&s, mp)); \ + }); \ } \ - template<> DLL_PUBLIC ModelPartForRootPtr ModelPart::CreateRootFor(Ice::optional<Type> & s) \ + template<> DLL_PUBLIC void ModelPart::OnRootFor(Ice::optional<Type> & s, const ModelPartRootHandler & h) \ { \ - return std::make_shared<ModelPartForRoot<Ice::optional<Type>>>(&s); \ + return CreateFor(s, [&s, &h](auto && mp) { \ + h(ModelPartForRoot<Ice::optional<Type>>(&s, mp)); \ + }); \ } \ - template<> DLL_PUBLIC ModelPartForRootPtr ModelPart::CreateRootFor(const Type & s) \ + template<> DLL_PUBLIC void ModelPart::OnRootFor(const Type & s, const ModelPartRootHandler & h) \ { \ - return CreateRootFor(const_cast<Type &>(s)); \ + return OnRootFor(const_cast<Type &>(s), h); \ } \ - template<> DLL_PUBLIC ModelPartForRootPtr ModelPart::CreateRootFor(const Ice::optional<Type> & s) \ + template<> DLL_PUBLIC void ModelPart::OnRootFor(const Ice::optional<Type> & s, const ModelPartRootHandler & h) \ { \ - return CreateRootFor(const_cast<Ice::optional<Type> &>(s)); \ + return OnRootFor(const_cast<Ice::optional<Type> &>(s), h); \ } \ template class BaseModelPart; \ template class ModelPartForRoot<Type>; \ @@ -90,11 +97,11 @@ namespace Ice { #define MODELPARTFORSTREAM(StreamImpl) \ namespace Slicer { \ template<> \ - DLL_PUBLIC ModelPartForRootPtr \ - ModelPart::CreateRootFor(const StreamImpl & stream) \ + DLL_PUBLIC void \ + ModelPart::OnRootFor(const StreamImpl & stream, const ModelPartRootHandler & h) \ { \ - return std::make_shared<ModelPartForStreamRoot<typename StreamImpl::element_type>>( \ - const_cast<StreamImpl *>(&stream)); \ + ModelPartForStream<typename StreamImpl::element_type> strm(const_cast<StreamImpl *>(&stream)); \ + h(ModelPartForStreamRoot<typename StreamImpl::element_type>(strm)); \ } \ } @@ -111,7 +118,7 @@ namespace Ice { namespace Slicer { // ModelPartForRoot template<typename T> - ModelPartForRoot<T>::ModelPartForRoot(T * o) : ModelPartForRootBase(ModelPart::CreateFor(*o)), ModelObject(o) + ModelPartForRoot<T>::ModelPartForRoot(T * o, ModelPartParam omp) : ModelPartForRootBase(omp), ModelObject(o) { } @@ -299,7 +306,7 @@ namespace Slicer { ModelPartModel<Ice::optional<typename T::element_type>>(h) { if (this->Model && *this->Model) { - modelPart = std::make_shared<T>(&**this->Model); + modelPart = &modelPartOwner.emplace(&**this->Model); } } @@ -318,7 +325,7 @@ namespace Slicer { BOOST_ASSERT(this->Model); if (!*this->Model) { *this->Model = typename T::element_type(); - modelPart = std::make_shared<T>(&**this->Model); + modelPart = &modelPartOwner.emplace(&**this->Model); modelPart->Create(); } } @@ -347,44 +354,49 @@ namespace Slicer { ModelPartForComplex<T>::OnEachChild(const ChildHandler & ch) { for (const auto & h : hooks()) { - h->apply(ch, h->Get(GetModel())); + h->On(GetModel(), [h, &ch](auto && mp) { + h->apply(ch, mp); + }); } } template<typename T> template<typename R> - ChildRef - ModelPartForComplex<T>::GetChildRefFromRange(const R & range, const HookFilter & flt) + bool + ModelPartForComplex<T>::OnChildFromRange(const SubPartHandler & ch, const R & range, const HookFilter & flt) { const auto itr = std::find_if(range.begin(), range.end(), [&flt](auto && h) { return h->filter(flt); }); if (itr != range.end()) { const auto & h = *itr; - auto model = GetModel(); - return ChildRef(h->Get(model), h->GetMetadata()); + h->On(GetModel(), [h, &ch](auto && mp) { + ch(mp, h->GetMetadata()); + }); + return true; } - return ChildRef(); + return false; } template<typename T> - ChildRef - ModelPartForComplex<T>::GetAnonChildRef(const HookFilter & flt) + bool + ModelPartForComplex<T>::OnAnonChild(const SubPartHandler & ch, const HookFilter & flt) { - return GetChildRefFromRange(hooks(), flt); + return OnChildFromRange(ch, hooks(), flt); } template<typename T> - ChildRef - ModelPartForComplex<T>::GetChildRef(std::string_view name, const HookFilter & flt, bool matchCase) + bool + ModelPartForComplex<T>::OnChild( + const SubPartHandler & ch, std::string_view name, const HookFilter & flt, bool matchCase) { if (matchCase) { - return GetChildRefFromRange(hooks().equal_range(name), flt); + return OnChildFromRange(ch, hooks().equal_range(name), flt); } else { std::string i {name}; to_lower(i); - return GetChildRefFromRange(hooks().equal_range_lower(i), flt); + return OnChildFromRange(ch, hooks().equal_range_lower(i), flt); } } @@ -392,7 +404,7 @@ namespace Slicer { public: using HookCommon::HookCommon; - virtual ModelPartPtr Get(T * t) const = 0; + virtual void On(T * t, const ModelPartHandler &) const = 0; }; template<typename T> @@ -405,6 +417,7 @@ namespace Slicer { { static_assert(sizeof...(MD) == N, "Wrong amount of metadata"); } + ~Hook() override = default; SPECIAL_MEMBERS_DEFAULT(Hook); @@ -414,13 +427,13 @@ namespace Slicer { return hookMetadata; } - ModelPartPtr - Get(T * t) const override + void + On(T * t, const ModelPartHandler & h) const override { if (t) { - return Make<MP>(&(t->*member)); + return Make<MP>(&(t->*member), h); } - return Make<MP>(nullptr); + return Make<MP>(nullptr, h); } private: @@ -451,11 +464,11 @@ namespace Slicer { } template<typename T> - ModelPartPtr - ModelPartForClass<T>::GetSubclassModelPart(const std::string & name) + void + ModelPartForClass<T>::OnSubclass(const ModelPartHandler & h, const std::string & name) { BOOST_ASSERT(this->Model); - return ModelPartForComplexBase::getSubclassModelPart(name, this->Model); + return ModelPartForComplexBase::onSubclass(name, this->Model, h); } template<typename T> @@ -474,10 +487,10 @@ namespace Slicer { } template<typename T> - ModelPartPtr - ModelPartForClass<T>::CreateModelPart(void * p) + void + ModelPartForClass<T>::CreateModelPart(void * p, const ModelPartHandler & h) { - return ::Slicer::ModelPart::CreateFor(*static_cast<element_type *>(p)); + return ::Slicer::ModelPart::CreateFor(*static_cast<element_type *>(p), h); } template<typename T> @@ -596,17 +609,21 @@ namespace Slicer { { BOOST_ASSERT(this->Model); for (auto & element : *this->Model) { - ch(elementName, elementModelPart(element), NULL); + ModelPart::CreateFor(element, [&ch](auto && mp) { + ch(elementName, mp, nullptr); + }); } } template<typename T> - ChildRef - ModelPartForSequence<T>::GetAnonChildRef(const HookFilter &) + bool + ModelPartForSequence<T>::OnAnonChild(const SubPartHandler & ch, const HookFilter &) { BOOST_ASSERT(this->Model); - this->Model->push_back(typename element_type::value_type()); - return ChildRef(ModelPart::CreateFor(this->Model->back())); + ModelPart::CreateFor(this->Model->emplace_back(), [&ch](auto && mp) { + ch(mp, emptyMetadata); + }); + return true; } template<typename T> @@ -624,17 +641,10 @@ namespace Slicer { } template<typename T> - ModelPartPtr - ModelPartForSequence<T>::elementModelPart(typename T::value_type & e) const - { - return ModelPart::CreateFor(e); - } - - template<typename T> - ModelPartPtr - ModelPartForSequence<T>::GetContainedModelPart() + void + ModelPartForSequence<T>::OnContained(const ModelPartHandler & h) { - return ModelPart::CreateFor(Default<typename T::value_type> {}); + return ModelPart::CreateFor(Default<typename T::value_type> {}, h); } // ModelPartForDictionaryElementInserter @@ -658,27 +668,30 @@ namespace Slicer { { BOOST_ASSERT(this->Model); for (auto & pair : *this->Model) { - ch(pairName, std::make_shared<ModelPartForStruct<typename T::value_type>>(&pair), nullptr); + ch(pairName, ModelPartForStruct<typename T::value_type>(&pair), nullptr); } } template<typename T> - ChildRef - ModelPartForDictionary<T>::GetAnonChildRef(const HookFilter &) + bool + ModelPartForDictionary<T>::OnAnonChild(const SubPartHandler & ch, const HookFilter &) { BOOST_ASSERT(this->Model); - return ChildRef(std::make_shared<ModelPartForDictionaryElementInserter<T>>(this->Model)); + ch(ModelPartForDictionaryElementInserter<T>(this->Model), emptyMetadata); + return true; } template<typename T> - ChildRef - ModelPartForDictionary<T>::GetChildRef(std::string_view name, const HookFilter &, bool matchCase) + bool + ModelPartForDictionary<T>::OnChild( + const SubPartHandler & ch, std::string_view name, const HookFilter &, bool matchCase) { BOOST_ASSERT(this->Model); if (!optionalCaseEq(name, pairName, matchCase)) { throw IncorrectElementName(std::string {name}); } - return ChildRef(std::make_shared<ModelPartForDictionaryElementInserter<T>>(this->Model)); + ch(ModelPartForDictionaryElementInserter<T>(this->Model), emptyMetadata); + return true; } template<typename T> @@ -689,18 +702,18 @@ namespace Slicer { } template<typename T> - ModelPartPtr - ModelPartForDictionary<T>::GetContainedModelPart() + void + ModelPartForDictionary<T>::OnContained(const ModelPartHandler & h) { - return std::make_shared<ModelPartForStruct<typename T::value_type>>(nullptr); + return h(ModelPartForStruct<typename T::value_type>(nullptr)); } // ModelPartForStream template<typename T> - ModelPartPtr - ModelPartForStream<T>::GetContainedModelPart() + void + ModelPartForStream<T>::OnContained(const ModelPartHandler & h) { - return ModelPart::CreateFor(Default<T> {}); + ModelPart::CreateFor(Default<T> {}, h); } template<typename T> @@ -709,17 +722,13 @@ namespace Slicer { { BOOST_ASSERT(this->Model); this->Model->Produce([&ch](const T & element) { - ch(ModelPartForSequence<std::vector<T>>::elementName, ModelPart::CreateFor(element), NULL); + ModelPart::CreateFor(element, [&ch](auto && mp) { + ch(ModelPartForSequence<std::vector<T>>::elementName, mp, nullptr); + }); }); } template<typename T> - ModelPartForStreamRoot<T>::ModelPartForStreamRoot(Stream<T> * s) : - ModelPartForStreamRootBase(std::make_shared<ModelPartForStream<T>>(s)) - { - } - - template<typename T> const std::string & ModelPartForStreamRoot<T>::GetRootName() const { diff --git a/slicer/slicer/serializer.h b/slicer/slicer/serializer.h index 27d70a6..653e61a 100644 --- a/slicer/slicer/serializer.h +++ b/slicer/slicer/serializer.h @@ -8,6 +8,7 @@ #include <memory> #include <slicer/modelParts.h> #include <visibility.h> + // IWYU pragma: no_include "factory.impl.h" namespace Slicer { @@ -18,8 +19,9 @@ namespace Slicer { virtual ~Serializer() = default; - virtual void Serialize(ModelPartForRootPtr) = 0; + virtual void Serialize(ModelPartForRootParam) = 0; }; + using SerializerPtr = std::shared_ptr<Serializer>; class DLL_PUBLIC Deserializer { @@ -29,8 +31,9 @@ namespace Slicer { virtual ~Deserializer() = default; - virtual void Deserialize(ModelPartForRootPtr) = 0; + virtual void Deserialize(ModelPartForRootParam) = 0; }; + using DeserializerPtr = std::shared_ptr<Deserializer>; using StreamSerializerFactory = AdHoc::Factory<Serializer, std::ostream &>; diff --git a/slicer/slicer/slicer.cpp b/slicer/slicer/slicer.cpp index b36d6c6..ff9a948 100644 --- a/slicer/slicer/slicer.cpp +++ b/slicer/slicer/slicer.cpp @@ -5,30 +5,8 @@ #include <utility> namespace Slicer { - Slicer::ChildRef::ChildRef() : mpp(), mdr(emptyMetadata) { } - - Slicer::ChildRef::ChildRef(ModelPartPtr m) : mpp(std::move(m)), mdr(emptyMetadata) { } - - Slicer::ChildRef::ChildRef(Slicer::ModelPartPtr mp, const Slicer::Metadata & md) : mpp(std::move(mp)), mdr(md) { } - - ModelPartPtr - Slicer::ChildRef::Child() const - { - return mpp; - } - - Slicer::ChildRef::operator bool() const - { - return !!mpp; - } - - const Metadata & - Slicer::ChildRef::ChildMetaData() const - { - return mdr; - } - AdHocFormatter(InvalidEnumerationSymbolMsg, "Invalid enumeration symbol [%?] for type [%?]"); + void InvalidEnumerationSymbol::ice_print(std::ostream & s) const { @@ -36,6 +14,7 @@ namespace Slicer { } AdHocFormatter(InvalidEnumerationValueMsg, "Invalid enumeration symbol [%?] for type [%?]"); + void InvalidEnumerationValue::ice_print(std::ostream & s) const { @@ -43,6 +22,7 @@ namespace Slicer { } AdHocFormatter(UnknownTypeMsg, "Unknown type [%?]"); + void UnknownType::ice_print(std::ostream & s) const { @@ -50,6 +30,7 @@ namespace Slicer { } AdHocFormatter(NoConversionFoundMsg, "No conversion found for type [%?]"); + void NoConversionFound::ice_print(std::ostream & s) const { @@ -69,6 +50,7 @@ namespace Slicer { } AdHocFormatter(IncorrectElementNameMsg, "Incorrect element name [%?]"); + void IncorrectElementName::ice_print(std::ostream & s) const { @@ -94,6 +76,7 @@ namespace Slicer { } AdHocFormatter(CompilerErrorMsg, "Slicer compiler: %?"); + void CompilerError::ice_print(std::ostream & s) const { @@ -101,6 +84,7 @@ namespace Slicer { } AdHocFormatter(InvalidStreamOperationMsg, "%? is not valid on streams"); + void InvalidStreamOperation::ice_print(std::ostream & s) const { @@ -108,6 +92,7 @@ namespace Slicer { } AdHocFormatter(AbstractClassExceptionMsg, "%? is an abstract class"); + void AbstractClassException::ice_print(std::ostream & s) const { diff --git a/slicer/slicer/slicer.h b/slicer/slicer/slicer.h index ce7e037..cb15af2 100644 --- a/slicer/slicer/slicer.h +++ b/slicer/slicer/slicer.h @@ -8,10 +8,12 @@ namespace Slicer { template<typename Object> Object - DeserializeAnyWith(const DeserializerPtr & deserializer) + DeserializeAnyWith(any_ptr<Deserializer> deserializer) { Object object {}; - deserializer->Deserialize(ModelPart::CreateRootFor<Object>(object)); + ModelPart::OnRootFor<Object>(object, [deserializer](auto && mp) { + deserializer->Deserialize(mp); + }); return object; } @@ -19,21 +21,23 @@ namespace Slicer { Object DeserializeAny(SerializerParams &&... sp) { - return DeserializeAnyWith<Object>(std::make_shared<Deserializer>(std::forward<SerializerParams>(sp)...)); + return DeserializeAnyWith<Object>(Deserializer(std::forward<SerializerParams>(sp)...)); } template<typename Object> void - SerializeAnyWith(const Object & object, const SerializerPtr & serializer) + SerializeAnyWith(const Object & object, any_ptr<Serializer> serializer) { - serializer->Serialize(ModelPart::CreateRootFor<const Object>(object)); + ModelPart::OnRootFor<const Object>(object, [serializer](auto && mp) { + serializer->Serialize(mp); + }); } template<typename Serializer, typename Object, typename... SerializerParams> void SerializeAny(const Object & object, SerializerParams &&... sp) { - SerializeAnyWith(object, std::make_shared<Serializer>(std::forward<SerializerParams>(sp)...)); + SerializeAnyWith(object, Serializer(std::forward<SerializerParams>(sp)...)); } } diff --git a/slicer/test/Jamfile.jam b/slicer/test/Jamfile.jam index 8fd70a5..6fcffa0 100644 --- a/slicer/test/Jamfile.jam +++ b/slicer/test/Jamfile.jam @@ -3,6 +3,7 @@ import ./slicer.jam ; lib dl ; lib stdc++fs ; lib boost_date_time ; +lib benchmark ; lib icetypes : [ glob *.ice ] @@ -111,3 +112,31 @@ run streams.cpp <library>../json//slicer-json ; +run + [ obj perf : perf.cpp : + <slicer>pure + <define>ROOT=\"$(me)\" + <use>types + <implicit-dependency>types + <use>benchmark + <use>stdc++fs + <use>..//adhocutil + <use>common + <use>../slicer//slicer + <implicit-dependency>../slicer//slicer + <use>../xml//slicer-xml + <use>../json//slicer-json + ] + : : : + <library>benchmark + <library>stdc++fs + <library>common + <library>types + <library>../slicer//slicer + <implicit-dependency>../slicer//slicer + <library>../xml//slicer-xml + <library>../json//slicer-json + <library>..//adhocutil + <variant>profile:<testing.execute>on + <testing.execute>off + : perf ; diff --git a/slicer/test/compilation.cpp b/slicer/test/compilation.cpp index 2920e99..14bf1d9 100644 --- a/slicer/test/compilation.cpp +++ b/slicer/test/compilation.cpp @@ -23,77 +23,88 @@ BOOST_TEST_DONT_PRINT_LOG_VALUE(std::type_info) BOOST_TEST_DONT_PRINT_LOG_VALUE(Slicer::ModelPartType) // LCOV_EXCL_STOP -#define TypeTest(Var, Expr, Explicit, Expected) \ +#define TypeTest(Var, Expr, Explicit, Expected, ...) \ Var obj = Expr; \ - Slicer::ModelPartPtr mpp = Slicer::ModelPart::CreateFor(obj); \ - BOOST_REQUIRE_EQUAL(Slicer::Expected, mpp->GetType()); \ + Slicer::ModelPart::CreateFor(obj, [](auto && mpp) { \ + BOOST_REQUIRE_EQUAL(Slicer::Expected, mpp->GetType()); \ \ - BOOST_TEST_CONTEXT(#Var) { \ - auto mppvalue = mpp.get(); \ - auto amppvalue = mpp.get(); \ - auto apmppvalue = mpp.get(); \ - BOOST_TEST_CONTEXT(typeid(*mppvalue).name()) { \ - BOOST_REQUIRE_EQUAL(typeid(*mppvalue), typeid(*amppvalue)); \ - BOOST_REQUIRE_EQUAL(typeid(*mppvalue), typeid(*apmppvalue)); \ + BOOST_TEST_CONTEXT(#Var) { \ + auto mppvalue = mpp.get(); \ + auto amppvalue = mpp.get(); \ + auto apmppvalue = mpp.get(); \ + BOOST_TEST_CONTEXT(typeid(*mppvalue).name()) { \ + BOOST_REQUIRE_EQUAL(typeid(*mppvalue), typeid(*amppvalue)); \ + BOOST_REQUIRE_EQUAL(typeid(*mppvalue), typeid(*apmppvalue)); \ + } \ } \ - } + __VA_ARGS__ \ + }); + +#define StackTypeTest(Var, Explicit, Expected, ...) TypeTest(Var, Var(), Explicit, Expected, __VA_ARGS__) -#define StackTypeTest(Var, Explicit, Expected) TypeTest(Var, Var(), Explicit, Expected) +constexpr auto DontCall = [](auto &&...) { + BOOST_ERROR("Shouldn't be called"); +}; BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_class) { TypeTest(TestModule::BuiltInsPtr, std::make_shared<TestModule::BuiltIns>(), ModelPartForClass, - ModelPartType::Complex); - BOOST_REQUIRE_EQUAL(mpp.get(), mpp->GetContainedModelPart().get()); + ModelPartType::Complex, { BOOST_CHECK_THROW(mpp->OnContained(DontCall), std::logic_error); }); } static void -hookHandler(std::vector<std::string> * names, const std::string & name, const Slicer::ModelPartPtr & mpp, +hookHandler(std::vector<std::string> * names, const std::string & name, Slicer::ModelPartParam mpp, const Slicer::HookCommon * h) { names->push_back(name); BOOST_REQUIRE(mpp); - BOOST_REQUIRE(mpp->GetContainedModelPart()); + BOOST_CHECK_THROW(mpp->OnContained(DontCall), std::logic_error); BOOST_REQUIRE(h); BOOST_REQUIRE_EQUAL(h->name, name); } BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_sequenceclasses) { - StackTypeTest(TestModule::Classes, ModelPartForSequence, ModelPartType::Sequence); - auto cmpp = mpp->GetContainedModelPart(); - BOOST_REQUIRE(cmpp); - BOOST_REQUIRE_EQUAL(Slicer::ModelPartType::Complex, cmpp->GetType()); - std::vector<std::string> names; - cmpp->OnEachChild([&](auto && PH1, auto && PH2, auto && PH3) { - hookHandler(&names, PH1, PH2, PH3); + StackTypeTest(TestModule::Classes, ModelPartForSequence, ModelPartType::Sequence, { + mpp->OnContained([](auto && cmpp) { + BOOST_REQUIRE(cmpp); + BOOST_REQUIRE_EQUAL(Slicer::ModelPartType::Complex, cmpp->GetType()); + std::vector<std::string> names; + cmpp->OnEachChild([&](auto && PH1, auto && PH2, auto && PH3) { + hookHandler(&names, PH1, PH2, PH3); + }); + BOOST_REQUIRE_EQUAL(2, names.size()); + BOOST_REQUIRE_EQUAL("a", names.front()); + BOOST_REQUIRE_EQUAL("b", names.back()); + }); }); - BOOST_REQUIRE_EQUAL(2, names.size()); - BOOST_REQUIRE_EQUAL("a", names.front()); - BOOST_REQUIRE_EQUAL("b", names.back()); } BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_sequencestructs) { - StackTypeTest(TestModule::Structs, ModelPartForSequence, ModelPartType::Sequence); - auto cmpp = mpp->GetContainedModelPart(); - BOOST_REQUIRE(cmpp); - BOOST_REQUIRE_EQUAL(Slicer::ModelPartType::Complex, cmpp->GetType()); - std::vector<std::string> names; - cmpp->OnEachChild([&](auto && PH1, auto && PH2, auto && PH3) { - hookHandler(&names, PH1, PH2, PH3); + StackTypeTest(TestModule::Structs, ModelPartForSequence, ModelPartType::Sequence, { + mpp->OnContained([](auto && cmpp) { + BOOST_REQUIRE(cmpp); + BOOST_REQUIRE_EQUAL(Slicer::ModelPartType::Complex, cmpp->GetType()); + std::vector<std::string> names; + cmpp->OnEachChild([&](auto && PH1, auto && PH2, auto && PH3) { + hookHandler(&names, PH1, PH2, PH3); + }); + BOOST_REQUIRE_EQUAL(2, names.size()); + BOOST_REQUIRE_EQUAL("a", names.front()); + BOOST_REQUIRE_EQUAL("b", names.back()); + }); }); - BOOST_REQUIRE_EQUAL(2, names.size()); - BOOST_REQUIRE_EQUAL("a", names.front()); - BOOST_REQUIRE_EQUAL("b", names.back()); } BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_mapclasses) { - StackTypeTest(TestModule::ClassMap, ModelPartForDictionary, ModelPartType::Dictionary); - auto cmpp = mpp->GetContainedModelPart(); - BOOST_REQUIRE(cmpp); - BOOST_REQUIRE_EQUAL(Slicer::ModelPartType::Complex, cmpp->GetType()); + StackTypeTest(TestModule::ClassMap, ModelPartForDictionary, ModelPartType::Dictionary, { + mpp->OnContained([](auto && cmpp) { + BOOST_REQUIRE(cmpp); + BOOST_REQUIRE_EQUAL(Slicer::ModelPartType::Complex, cmpp->GetType()); + }); + }); } BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_mapstructs) @@ -103,124 +114,130 @@ BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_mapstructs) BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_bi_string) { - StackTypeTest(std::string, ModelPartForSimple, ModelPartType::Simple); - BOOST_REQUIRE_EQUAL(mpp.get(), mpp->GetContainedModelPart().get()); + StackTypeTest(std::string, ModelPartForSimple, ModelPartType::Simple, + { BOOST_CHECK_THROW(mpp->OnContained(DontCall), std::logic_error); }); } BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_bi_bool) { - StackTypeTest(bool, ModelPartForSimple, ModelPartType::Simple); - BOOST_REQUIRE_EQUAL(mpp.get(), mpp->GetContainedModelPart().get()); + StackTypeTest(bool, ModelPartForSimple, ModelPartType::Simple, + { BOOST_CHECK_THROW(mpp->OnContained(DontCall), std::logic_error); }); } BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_bi_float) { - StackTypeTest(Ice::Float, ModelPartForSimple, ModelPartType::Simple); - BOOST_REQUIRE_EQUAL(mpp.get(), mpp->GetContainedModelPart().get()); + StackTypeTest(Ice::Float, ModelPartForSimple, ModelPartType::Simple, + { BOOST_CHECK_THROW(mpp->OnContained(DontCall), std::logic_error); }); } BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_bi_double) { - StackTypeTest(Ice::Double, ModelPartForSimple, ModelPartType::Simple); - BOOST_REQUIRE_EQUAL(mpp.get(), mpp->GetContainedModelPart().get()); + StackTypeTest(Ice::Double, ModelPartForSimple, ModelPartType::Simple, + { BOOST_CHECK_THROW(mpp->OnContained(DontCall), std::logic_error); }); } BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_bi_byte) { - StackTypeTest(Ice::Byte, ModelPartForSimple, ModelPartType::Simple); - BOOST_REQUIRE_EQUAL(mpp.get(), mpp->GetContainedModelPart().get()); + StackTypeTest(Ice::Byte, ModelPartForSimple, ModelPartType::Simple, + { BOOST_CHECK_THROW(mpp->OnContained(DontCall), std::logic_error); }); } BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_bi_short) { - StackTypeTest(Ice::Short, ModelPartForSimple, ModelPartType::Simple); - BOOST_REQUIRE_EQUAL(mpp.get(), mpp->GetContainedModelPart().get()); + StackTypeTest(Ice::Short, ModelPartForSimple, ModelPartType::Simple, + { BOOST_CHECK_THROW(mpp->OnContained(DontCall), std::logic_error); }); } BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_bi_int) { - StackTypeTest(Ice::Int, ModelPartForSimple, ModelPartType::Simple); - BOOST_REQUIRE_EQUAL(mpp.get(), mpp->GetContainedModelPart().get()); + StackTypeTest(Ice::Int, ModelPartForSimple, ModelPartType::Simple, + { BOOST_CHECK_THROW(mpp->OnContained(DontCall), std::logic_error); }); } BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_bi_long) { - StackTypeTest(Ice::Long, ModelPartForSimple, ModelPartType::Simple); - BOOST_REQUIRE_EQUAL(mpp.get(), mpp->GetContainedModelPart().get()); + StackTypeTest(Ice::Long, ModelPartForSimple, ModelPartType::Simple, + { BOOST_CHECK_THROW(mpp->OnContained(DontCall), std::logic_error); }); } BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_struct) { - StackTypeTest(TestModule::StructType, ModelPartForStruct, ModelPartType::Complex); - BOOST_REQUIRE_EQUAL(mpp.get(), mpp->GetContainedModelPart().get()); + StackTypeTest(TestModule::StructType, ModelPartForStruct, ModelPartType::Complex, + { BOOST_CHECK_THROW(mpp->OnContained(DontCall), std::logic_error); }); } BOOST_AUTO_TEST_CASE(compile_auto_modelpart_type_enum) { - StackTypeTest(TestModule::SomeNumbers, ModelPartForEnum, ModelPartType::Simple); - BOOST_REQUIRE_EQUAL(mpp.get(), mpp->GetContainedModelPart().get()); + StackTypeTest(TestModule::SomeNumbers, ModelPartForEnum, ModelPartType::Simple, + { BOOST_CHECK_THROW(mpp->OnContained(DontCall), std::logic_error); }); } BOOST_AUTO_TEST_CASE(normalClassTypeId) { TestModule::BasePtr base = std::make_shared<TestModule::Base>(1); BOOST_REQUIRE(base); - auto a = Slicer::ModelPart::CreateFor(base); - BOOST_REQUIRE(a); - auto baseType = a->GetTypeId(); - BOOST_REQUIRE(!baseType); + Slicer::ModelPart::CreateFor(base, [](auto && a) { + BOOST_REQUIRE(a); + auto baseType = a->GetTypeId(); + BOOST_REQUIRE(!baseType); + }); } BOOST_AUTO_TEST_CASE(normalSubClassTypeId) { TestModule::BasePtr base = std::make_shared<TestModule::D1>(1, 2); BOOST_REQUIRE(base); - auto a = Slicer::ModelPart::CreateFor(base); - BOOST_REQUIRE(a); - auto baseType = a->GetTypeId(); - BOOST_REQUIRE(baseType); - BOOST_REQUIRE_EQUAL(*baseType, "::TestModule::D1"); + Slicer::ModelPart::CreateFor(base, [](auto && a) { + BOOST_REQUIRE(a); + auto baseType = a->GetTypeId(); + BOOST_REQUIRE(baseType); + BOOST_REQUIRE_EQUAL(*baseType, "::TestModule::D1"); + }); } BOOST_AUTO_TEST_CASE(normalSubSubClassTypeId) { TestModule::BasePtr base = std::make_shared<TestModule::D3>(1, 2, 3); BOOST_REQUIRE(base); - auto a = Slicer::ModelPart::CreateFor(base); - BOOST_REQUIRE(a); - auto baseType = a->GetTypeId(); - BOOST_REQUIRE(baseType); - BOOST_REQUIRE_EQUAL(*baseType, "::TestModule::D3"); + Slicer::ModelPart::CreateFor(base, [](auto && a) { + BOOST_REQUIRE(a); + auto baseType = a->GetTypeId(); + BOOST_REQUIRE(baseType); + BOOST_REQUIRE_EQUAL(*baseType, "::TestModule::D3"); + }); } BOOST_AUTO_TEST_CASE(localClassTypeId) { Locals::LocalClassPtr base = std::make_shared<Locals::LocalClass>(1, "One"); BOOST_REQUIRE(base); - auto a = Slicer::ModelPart::CreateFor(base); - BOOST_REQUIRE(a); - auto baseType = a->GetTypeId(); - BOOST_REQUIRE(!baseType); + Slicer::ModelPart::CreateFor(base, [](auto && a) { + BOOST_REQUIRE(a); + auto baseType = a->GetTypeId(); + BOOST_REQUIRE(!baseType); + }); } BOOST_AUTO_TEST_CASE(localSubClassTypeId) { Locals::LocalClassPtr base = std::make_shared<Locals::LocalSubClass>(1, "One", 3.1); BOOST_REQUIRE(base); - auto a = Slicer::ModelPart::CreateFor(base); - BOOST_REQUIRE(a); - auto baseType = a->GetTypeId(); - BOOST_REQUIRE(baseType); - BOOST_REQUIRE_EQUAL(*baseType, "::Locals::LocalSubClass"); + Slicer::ModelPart::CreateFor(base, [](auto && a) { + BOOST_REQUIRE(a); + auto baseType = a->GetTypeId(); + BOOST_REQUIRE(baseType); + BOOST_REQUIRE_EQUAL(*baseType, "::Locals::LocalSubClass"); + }); } BOOST_AUTO_TEST_CASE(localSubSubClassTypeId) { Locals::LocalClassPtr base = std::make_shared<Locals::LocalSub2Class>(1, "One", 3.1, 1); BOOST_REQUIRE(base); - auto a = Slicer::ModelPart::CreateFor(base); - BOOST_REQUIRE(a); - auto baseType = a->GetTypeId(); - BOOST_REQUIRE(baseType); - BOOST_REQUIRE_EQUAL(*baseType, "::Locals::LocalSub2Class"); + Slicer::ModelPart::CreateFor(base, [](auto && a) { + BOOST_REQUIRE(a); + auto baseType = a->GetTypeId(); + BOOST_REQUIRE(baseType); + BOOST_REQUIRE_EQUAL(*baseType, "::Locals::LocalSub2Class"); + }); } diff --git a/slicer/test/conversions.cpp b/slicer/test/conversions.cpp index 6e74e26..193cd4f 100644 --- a/slicer/test/conversions.cpp +++ b/slicer/test/conversions.cpp @@ -13,6 +13,7 @@ #include <visibility.h> #define SHORT(x) boost::numeric_cast<::Ice::Short, int64_t>(x) + inline auto USHORT(std::integral auto x) { @@ -40,8 +41,8 @@ namespace Slicer { std::string isoDateToString(const ::TestModule::IsoDate & in) { - struct tm tm { - }; + struct tm tm { }; + tm.tm_mday = in.day; tm.tm_mon = in.month - 1; tm.tm_year = in.year - 1900; @@ -56,8 +57,8 @@ namespace Slicer { ::TestModule::IsoDate stringToIsoDate(const std::string & in) { - struct tm tm { - }; + struct tm tm { }; + auto end = strptime(in.c_str(), "%Y-%m-%d", &tm); if (!end || *end) { // LCOV_EXCL_START @@ -71,8 +72,8 @@ namespace Slicer { std::string dateTimeToString(const ::TestModule::DateTime & in) { - struct tm tm { - }; + struct tm tm { }; + tm.tm_sec = in.second; tm.tm_min = in.minute; tm.tm_hour = in.hour; @@ -91,8 +92,8 @@ namespace Slicer { ::TestModule::DateTime stringToDateTime(const std::string & in) { - struct tm tm { - }; + struct tm tm { }; + auto end = strptime(in.c_str(), "%Y-%b-%d %H:%M:%S", &tm); if (!end || *end) { // LCOV_EXCL_START @@ -171,11 +172,12 @@ namespace TestModule { completions += 1; } } + namespace Slicer { template<> - DLL_PUBLIC ModelPartPtr - ModelPart::Make<TestModule::MonthValidator>(::Ice::Short * m) + DLL_PUBLIC void + ModelPart::Make<TestModule::MonthValidator>(::Ice::Short * m, const ModelPartHandler & h) { - return std::make_shared<TestModule::MonthValidator>(m); + return h(TestModule::MonthValidator(m)); } } diff --git a/slicer/test/conversions.h b/slicer/test/conversions.h index cb46b93..bfa1c4b 100644 --- a/slicer/test/conversions.h +++ b/slicer/test/conversions.h @@ -28,6 +28,7 @@ namespace TestModule { void Complete() override; }; } + namespace Slicer { DLL_PUBLIC ::TestModule::DateTime stringToDateTime(const std::string & in); diff --git a/slicer/test/perf.cpp b/slicer/test/perf.cpp new file mode 100644 index 0000000..0ea775b --- /dev/null +++ b/slicer/test/perf.cpp @@ -0,0 +1,81 @@ +#include <benchmark/benchmark.h> +#include <definedDirs.h> +#include <enums.h> +#include <json.h> +#include <json/serializer.h> +#include <locals.h> +#include <optionals.h> +#include <slicer/slicer.h> +#include <xml.h> +#include <xml/serializer.h> +// Must go last +#include <libxml++/parsers/domparser.h> + +class CoreFixture : public benchmark::Fixture { +protected: + template<typename Deserializer, typename T, typename... Args> + void + runDeserialize(benchmark::State & state, Args &&... args) + { + for (auto _ : state) { + benchmark::DoNotOptimize(Slicer::DeserializeAny<Deserializer, T>(std::forward<Args>(args)...)); + } + } +}; + +struct JsonValueFromFile : public json::Value { + explicit JsonValueFromFile(const std::filesystem::path & path) : + json::Value {[&path] { + std::ifstream in {path}; + return json::parseValue(in); + }()} + { + } +}; + +#define DESERIALIZE_TEST(name, type, ds, ext, obj, suf) \ + BENCHMARK_F(CoreFixture, name##_##ext)(benchmark::State & state) \ + { \ + obj dom {rootDir / "initial/" #name "." #ext}; \ + runDeserialize<ds, type>(state, dom suf); \ + } + +#define XML_DESERIALIZE_TEST(name, type) \ + DESERIALIZE_TEST(name, type, Slicer::XmlDocumentDeserializer, xml, xmlpp::DomParser, .get_document()) +XML_DESERIALIZE_TEST(attributemap, TestXml::Maps); +XML_DESERIALIZE_TEST(bare, TestXml::BareContainers); +XML_DESERIALIZE_TEST(someenums, TestModule::SomeEnumsPtr); +XML_DESERIALIZE_TEST(enum, TestModule::SomeNumbers); +XML_DESERIALIZE_TEST(elementmap, TestXml::Maps); +XML_DESERIALIZE_TEST(builtins, TestModule::BuiltInsPtr); +XML_DESERIALIZE_TEST(entityref, TestXml::EntityRef); +XML_DESERIALIZE_TEST(int, int); +XML_DESERIALIZE_TEST(isodate, TestModule::IsoDate); +XML_DESERIALIZE_TEST(seqOfClass, TestModule::Classes); +XML_DESERIALIZE_TEST(simpleArray2, TestModule::SimpleSeq); +XML_DESERIALIZE_TEST(string, std::string); +XML_DESERIALIZE_TEST(struct, TestModule::StructType); +XML_DESERIALIZE_TEST(xmlattr, TestModule::ClassClassPtr); +#undef XML_DESERIALIZE_TEST + +#define JSON_DESERIALIZE_TEST(name, type) \ + DESERIALIZE_TEST(name, type, Slicer::JsonValueDeserializer, json, JsonValueFromFile, ) +JSON_DESERIALIZE_TEST(builtins2, TestModule::BuiltInsPtr); +JSON_DESERIALIZE_TEST(builtins3, TestModule::BuiltInsPtr); +JSON_DESERIALIZE_TEST(localClass, Locals::LocalClassPtr); +JSON_DESERIALIZE_TEST(localSubClass, Locals::LocalSubClassPtr); +JSON_DESERIALIZE_TEST(localSub2Class, Locals::LocalSub2ClassPtr); +JSON_DESERIALIZE_TEST(objectmap, TestJson::Properties); +JSON_DESERIALIZE_TEST(objectmapMember, TestJson::HasProperitiesPtr); +JSON_DESERIALIZE_TEST(optionals2, TestModule::Optionals2Ptr); +JSON_DESERIALIZE_TEST(optionals3, TestModule::Optionals2Ptr); +JSON_DESERIALIZE_TEST(optionals5, TestModule::Optionals2Ptr); +JSON_DESERIALIZE_TEST(seqOfClass2, TestModule::Classes); +JSON_DESERIALIZE_TEST(simpleArray1, TestModule::SimpleSeq); +JSON_DESERIALIZE_TEST(string2, std::string); +JSON_DESERIALIZE_TEST(struct2, TestModule::StructType); +#undef JSON_DESERIALIZE_TEST + +#undef DESERIALIZE_TEST + +BENCHMARK_MAIN(); diff --git a/slicer/test/serializers.cpp b/slicer/test/serializers.cpp index 6efc02b..f02dbaf 100644 --- a/slicer/test/serializers.cpp +++ b/slicer/test/serializers.cpp @@ -50,6 +50,7 @@ namespace fs = std::filesystem; // LCOV_EXCL_START BOOST_TEST_DONT_PRINT_LOG_VALUE(TestModule::ClassMap::iterator) BOOST_TEST_DONT_PRINT_LOG_VALUE(TestModule::SomeNumbers) + namespace std { template<typename T> ostream & @@ -58,6 +59,7 @@ namespace std { return s; } } + // LCOV_EXCL_STOP class FileBased { @@ -587,11 +589,11 @@ BOOST_AUTO_TEST_CASE(xml_streams) BOOST_AUTO_TEST_CASE(invalid_enum) { - auto jdeserializer = std::make_shared<Slicer::JsonFileDeserializer>(rootDir / "initial" / "invalidEnum.json"); + Slicer::JsonFileDeserializer jdeserializer {rootDir / "initial" / "invalidEnum.json"}; BOOST_REQUIRE_THROW( Slicer::DeserializeAnyWith<TestModule::SomeNumbers>(jdeserializer), Slicer::InvalidEnumerationSymbol); - auto xdeserializer = std::make_shared<Slicer::XmlFileDeserializer>(rootDir / "initial" / "invalidEnum.xml"); + Slicer::XmlFileDeserializer xdeserializer {rootDir / "initial" / "invalidEnum.xml"}; BOOST_REQUIRE_THROW( Slicer::DeserializeAnyWith<TestModule::SomeNumbers>(xdeserializer), Slicer::InvalidEnumerationSymbol); } @@ -672,6 +674,18 @@ BOOST_AUTO_TEST_CASE(DeserializeXmlAbstractImpl) BOOST_CHECK_EQUAL("value", impl->testVal); } +BOOST_AUTO_TEST_CASE(SerializeJsonClassMap) +{ + TestModule::ClassMap d; + d[1] = std::make_shared<TestModule::ClassType>(1, 2); + d[2] = std::make_shared<TestModule::ClassType>(3, 4); + d[3] = std::make_shared<TestModule::ClassType>(5, 6); + std::stringstream out; + Slicer::SerializeAnyWith(d, Slicer::JsonStreamSerializer {out}); + BOOST_CHECK_EQUAL(out.view(), + R"([{"key":1,"value":{"a":1,"b":2}},{"key":2,"value":{"a":3,"b":4}},{"key":3,"value":{"a":5,"b":6}}])"); +} + BOOST_AUTO_TEST_CASE(DeserializeXmlIncorrectSeqElementName) { std::stringstream in(R"X( @@ -696,6 +710,8 @@ BOOST_AUTO_TEST_CASE(enum_lookups) BOOST_AUTO_TEST_CASE(sequence_element_in_same_slice_link_bug) { // Link error when sequence element type defined in same slice. - BOOST_CHECK(Slicer::ModelPart::Make<Slicer::ModelPartForSequence<TestModule::Classes>>(nullptr)); - BOOST_CHECK(Slicer::ModelPart::Make<Slicer::ModelPartForSequence<TestModule::Dates>>(nullptr)); + BOOST_CHECK_NO_THROW( + Slicer::ModelPart::Make<Slicer::ModelPartForSequence<TestModule::Classes>>(nullptr, [](auto &&) {})); + BOOST_CHECK_NO_THROW( + Slicer::ModelPart::Make<Slicer::ModelPartForSequence<TestModule::Dates>>(nullptr, [](auto &&) {})); } diff --git a/slicer/tool/icemetadata.cpp b/slicer/tool/icemetadata.cpp index cecf703..4804542 100644 --- a/slicer/tool/icemetadata.cpp +++ b/slicer/tool/icemetadata.cpp @@ -1,6 +1,7 @@ #include "icemetadata.h" #include <algorithm> #include <slicer/metadata.h> + // IWYU pragma: no_include <list> namespace Slicer { diff --git a/slicer/tool/parser.cpp b/slicer/tool/parser.cpp index ec94a43..55a06fe 100644 --- a/slicer/tool/parser.cpp +++ b/slicer/tool/parser.cpp @@ -53,26 +53,31 @@ namespace Slicer { { return countIfUsed(c, classes, !c->isInterface()); } + [[nodiscard]] bool visitStructStart(const Slice::StructPtr & s) override { return countIfUsed(s, structs); } + void visitSequence(const Slice::SequencePtr & s) override { countIfUsed(s, sequences); } + void visitDictionary(const Slice::DictionaryPtr & d) override { countIfUsed(d, dictionaries); } + void visitEnum(const Slice::EnumPtr & e) override { countIfUsed(e, enums); } + [[nodiscard]] auto complexes() const { @@ -233,13 +238,13 @@ namespace Slicer { fprintbf(cpp, "\tconversion_fail(\"%s\");\n", Slice::typeToString(type)); fprintbf(cpp, "}\n\n"); - fprintbf(cpp, "\ttemplate<> DLL_PUBLIC ModelPartPtr ModelPart::Make<"); + fprintbf(cpp, "\ttemplate<> DLL_PUBLIC void ModelPart::Make<"); createModelPartForConverted(type, c->scoped(), dm); fprintbf(cpp, ">(typename "); createModelPartForConverted(type, c->scoped(), dm); - fprintbf(cpp, "::element_type * t) { return std::make_shared<"); + fprintbf(cpp, "::element_type * t, const ModelPartHandler & h) { return h("); createModelPartForConverted(type, c->scoped(), dm); - fprintbf(cpp, ">(t); } \n"); + fprintbf(cpp, "(t)); } \n"); } } @@ -439,9 +444,9 @@ namespace Slicer { if (auto cmp = md.value("slicer:custommodelpart:")) { fprintbf(cpp, "CUSTOMMODELPARTFOR(%s, %s< %s >, %s)\n\n", Slice::typeToString(decl), getBasicModelPart(decl), c->scoped(), CppName {*cmp}); - fprintbf(cpp, "\ttemplate<> DLL_PUBLIC ModelPartPtr ModelPart::Make<%s<%s> >(%s * t)", + fprintbf(cpp, "\ttemplate<> DLL_PUBLIC void ModelPart::Make<%s<%s> >(%s * t, const ModelPartHandler & h)", getBasicModelPart(decl), c->scoped(), Slice::typeToString(decl)); - fprintbf(cpp, "{ return std::make_shared<%s>(t); } \n", CppName {*cmp}); + fprintbf(cpp, "{ return h(%s(t)); } \n", CppName {*cmp}); } else { fprintbf(cpp, "CUSTOMMODELPARTFOR(%s, ModelPartForClass<%s>, ModelPartForClass<%s>)\n\n", @@ -759,9 +764,9 @@ namespace Slicer { if (auto cmp = metadata.value("slicer:custommodelpart:")) { fprintbf(cpp, "CUSTOMMODELPARTFOR(%s, %s< %s >, %s)\n\n", type, getBasicModelPart(stype), type, CppName {*cmp}); - fprintbf(cpp, "\ttemplate<> DLL_PUBLIC ModelPartPtr ModelPart::Make<%s<%s>>(%s * t)", + fprintbf(cpp, "\ttemplate<> DLL_PUBLIC void ModelPart::Make<%s<%s>>(%s * t, const ModelPartHandler & h)", getBasicModelPart(stype), type, type); - fprintbf(cpp, "{ return std::make_shared<%s>(t); } \n", CppName {*cmp}); + fprintbf(cpp, "{ return h(%s(t)); } \n", CppName {*cmp}); } else { fprintbf(cpp, "MODELPARTFOR(%s, %s)\n\n", type, getBasicModelPart(stype)); diff --git a/slicer/tool/parser.h b/slicer/tool/parser.h index a784d7a..e56c90a 100644 --- a/slicer/tool/parser.h +++ b/slicer/tool/parser.h @@ -10,6 +10,7 @@ #include <string_view> #include <vector> #include <visibility.h> + // IWYU pragma: no_include <boost/iterator/transform_iterator.hpp> namespace Slicer { @@ -27,6 +28,7 @@ namespace Slicer { public: struct Args : public SplitString { explicit inline Args(std::string_view in) : SplitString {in, ","} { } + using SplitString::SplitString; }; diff --git a/slicer/xml/serializer.cpp b/slicer/xml/serializer.cpp index 96c1a9f..8e351b6 100644 --- a/slicer/xml/serializer.cpp +++ b/slicer/xml/serializer.cpp @@ -1,5 +1,5 @@ #include "serializer.h" -#include <boost/lexical_cast.hpp> +#include <charconv> #include <compileTimeFormatter.h> #include <functional> #pragma GCC diagnostic push @@ -10,16 +10,16 @@ #endif #include <glibmm/ustring.h> #include <libxml++/attribute.h> +#include <libxml++/document.h> #include <libxml++/nodes/contentnode.h> #include <libxml++/nodes/element.h> #include <libxml++/nodes/node.h> +#include <libxml++/parsers/domparser.h> #pragma GCC diagnostic pop #include <Ice/Config.h> #include <boost/numeric/conversion/cast.hpp> #include <factory.h> #include <lazyPointer.h> -#include <libxml++/document.h> -#include <libxml++/parsers/domparser.h> #include <list> #include <memory> #include <optional> @@ -37,327 +37,365 @@ NAMEDFACTORY("application/xml", Slicer::XmlStreamSerializer, Slicer::StreamSeria NAMEDFACTORY("application/xml", Slicer::XmlStreamDeserializer, Slicer::StreamDeserializerFactory) namespace Slicer { - constexpr std::string_view md_attribute {"xml:attribute"}; - constexpr std::string_view md_text {"xml:text"}; - constexpr std::string_view md_bare {"xml:bare"}; - constexpr std::string_view md_attributes {"xml:attributes"}; - constexpr std::string_view md_elements {"xml:elements"}; - constexpr std::string_view keyName {"key"}; - constexpr std::string_view valueName {"value"}; + namespace { + constexpr std::string_view md_attribute {"xml:attribute"}; + constexpr std::string_view md_text {"xml:text"}; + constexpr std::string_view md_bare {"xml:bare"}; + constexpr std::string_view md_attributes {"xml:attributes"}; + constexpr std::string_view md_elements {"xml:elements"}; + constexpr std::string_view keyName {"key"}; + constexpr std::string_view valueName {"value"}; - constexpr auto defaultElementCreator = [](auto && element, auto && name) { - return element->add_child_element(name); - }; + using CurrentElementCreator = ::AdHoc::LazyPointer<xmlpp::Element, xmlpp::Element *>; + using ElementCreator = std::function<xmlpp::Element *(xmlpp::Element *, const Glib::ustring &)>; - static const Glib::ustring TrueText("true"); - static const Glib::ustring FalseText("false"); + constexpr auto defaultElementCreator = [](auto && element, auto && name) { + return element->add_child_element(name); + }; - class XmlValueSource : public ValueSource { - public: - explicit XmlValueSource(Glib::ustring s) : value(std::move(s)) { } + const Glib::ustring TrueText("true"); + const Glib::ustring FalseText("false"); - void - set(bool & v) const override - { - if (value == TrueText) { - v = true; - return; + class XmlValueSource : public ValueSource { + public: + explicit XmlValueSource() = default; + + explicit XmlValueSource(Glib::ustring s) : value(std::move(s)) { } + + explicit XmlValueSource(const xmlpp::ContentNode * c) : value(c->get_content()) { } + + explicit XmlValueSource(const xmlpp::Attribute * a) : value(a->get_value()) { } + + void + set(bool & v) const override + { + if (value == TrueText) { + v = true; + return; + } + if (value == FalseText) { + v = false; + return; + } + throw BadBooleanValue(value); } - if (value == FalseText) { - v = false; - return; + + void + set(Ice::Byte & v) const override + { + from_chars(v); } - throw BadBooleanValue(value); - } - void - set(Ice::Byte & v) const override - { - v = boost::numeric_cast<Ice::Byte>(boost::lexical_cast<int>(value)); - } + void + set(Ice::Short & v) const override + { + from_chars(v); + } - void - set(Ice::Short & v) const override - { - v = boost::lexical_cast<Ice::Short>(value); - } + void + set(Ice::Int & v) const override + { + from_chars(v); + } - void - set(Ice::Int & v) const override - { - v = boost::lexical_cast<Ice::Int>(value); - } + void + set(Ice::Long & v) const override + { + from_chars(v); + } - void - set(Ice::Long & v) const override - { - v = boost::lexical_cast<Ice::Long>(value); - } + void + set(Ice::Float & v) const override + { + from_chars(v); + } - void - set(Ice::Float & v) const override - { - v = boost::lexical_cast<Ice::Float>(value); - } + void + set(Ice::Double & v) const override + { + from_chars(v); + } - void - set(Ice::Double & v) const override - { - v = boost::lexical_cast<Ice::Double>(value); - } + void + set(std::string & v) const override + { + v = value.raw(); + } - void - set(std::string & v) const override - { - v = value.raw(); - } + private: + template<typename T> + void + from_chars(T & v) const + { + std::string_view raw {value.raw()}; + if (std::from_chars(raw.begin(), raw.end(), v).ec != std::errc {}) { + throw BadNumericValue(value); + } + } - private: - const Glib::ustring value; - }; + const Glib::ustring value; + }; - class XmlContentValueSource : public XmlValueSource { - public: - explicit XmlContentValueSource() : XmlValueSource(Glib::ustring()) { } - explicit XmlContentValueSource(const xmlpp::ContentNode * c) : XmlValueSource(c->get_content()) { } - }; + class XmlValueTarget : public ValueTarget { + public: + using ApplyFunction = std::function<void(const Glib::ustring &)>; - class XmlAttributeValueSource : public XmlValueSource { - public: - explicit XmlAttributeValueSource(const xmlpp::Attribute * a) : XmlValueSource(a->get_value()) { } - }; + explicit XmlValueTarget(ApplyFunction a) : apply(std::move(a)) { } - class XmlValueTarget : public ValueTarget { - public: - explicit XmlValueTarget(std::function<void(const Glib::ustring &)> a) : apply(std::move(a)) { } + explicit XmlValueTarget(xmlpp::Element * p, const std::string & n) : + apply([p, n](auto && PH1) { + p->set_attribute(n, PH1); + }) + { + } - void - get(const bool & value) const override - { - if (value) { - apply(TrueText); + explicit XmlValueTarget(xmlpp::Element * p) : + apply([p](auto && PH1) { + p->set_first_child_text(PH1); + }) + { } - else { - apply(FalseText); + + explicit XmlValueTarget(const CurrentElementCreator & cec) : + apply([&](auto && PH1) { + cec->set_first_child_text(PH1); + }) + { } - } - void - get(const Ice::Byte & value) const override - { - apply(boost::lexical_cast<Glib::ustring, int>(value)); - } + void + get(const bool & value) const override + { + if (value) { + apply(TrueText); + } + else { + apply(FalseText); + } + } - void - get(const Ice::Short & value) const override - { - apply(boost::lexical_cast<Glib::ustring>(value)); - } + void + get(const Ice::Byte & value) const override + { + apply(Glib::ustring::format(value)); + } + + void + get(const Ice::Short & value) const override + { + apply(Glib::ustring::format(value)); + } + + void + get(const Ice::Int & value) const override + { + apply(Glib::ustring::format(value)); + } + + void + get(const Ice::Long & value) const override + { + apply(Glib::ustring::format(value)); + } + + void + get(const Ice::Float & value) const override + { + apply(Glib::ustring::format(value)); + } + + void + get(const Ice::Double & value) const override + { + apply(Glib::ustring::format(value)); + } + + void + get(const std::string & value) const override + { + apply(value); + } + + private: + const ApplyFunction apply; + }; + + void DocumentTreeIterate(const xmlpp::Node * node, ModelPartParam mp); + void DocumentTreeIterateElement(const xmlpp::Element * element, ModelPartParam mp, const Metadata & md); + void DocumentTreeIterate(const xmlpp::Document * doc, ModelPartParam mp); + void DocumentTreeIterateDictAttrs(const xmlpp::Element::const_AttributeList & attrs, ModelPartParam dict); + void DocumentTreeIterateDictElements(const xmlpp::Element * parent, ModelPartParam dict); void - get(const Ice::Int & value) const override + DocumentTreeIterateDictAttrs(const xmlpp::Element::const_AttributeList & attrs, ModelPartParam dict) { - apply(boost::lexical_cast<Glib::ustring>(value)); + for (const auto & attr : attrs) { + dict->OnAnonChild([&attr](auto && emp, auto &&) { + emp->Create(); + emp->OnChild( + [&attr](auto && child, auto &&) { + child->SetValue(XmlValueSource(attr->get_name())); + child->Complete(); + }, + keyName); + emp->OnChild( + [&attr](auto && value, auto &&) { + value->SetValue(XmlValueSource(attr->get_value())); + value->Complete(); + }, + valueName); + emp->Complete(); + }); + } } void - get(const Ice::Long & value) const override + DocumentTreeIterateDictElements(const xmlpp::Element * element, ModelPartParam dict) { - apply(boost::lexical_cast<Glib::ustring>(value)); + auto node = element->get_first_child(); + while (node) { + if (auto childElement = dynamic_cast<const xmlpp::Element *>(node)) { + dict->OnAnonChild([childElement](auto && emp, auto &&) { + emp->Create(); + emp->OnChild( + [childElement](auto && child, auto &&) { + child->SetValue(XmlValueSource(childElement->get_name())); + child->Complete(); + }, + keyName); + emp->OnChild( + [childElement](auto && value, auto && md) { + DocumentTreeIterateElement(childElement, value, md); + }, + valueName); + emp->Complete(); + }); + } + node = node->get_next_sibling(); + } } void - get(const Ice::Float & value) const override + DocumentTreeIterateElement(const xmlpp::Element * element, ModelPartParam smp, const Metadata & md) { - apply(boost::lexical_cast<Glib::ustring>(value)); + auto oec = [&md, element](const auto & lmp) { + lmp->Create(); + if (md.flagSet(md_attributes)) { + auto attrs(element->get_attributes()); + if (!attrs.empty()) { + DocumentTreeIterateDictAttrs(attrs, lmp); + } + } + else if (md.flagSet(md_elements)) { + DocumentTreeIterateDictElements(element, lmp); + } + else { + auto attrs(element->get_attributes()); + if (!attrs.empty()) { + DocumentTreeIterate(attrs.front(), lmp); + } + auto firstChild = element->get_first_child(); + if (firstChild) { + DocumentTreeIterate(firstChild, lmp); + } + else { + lmp->SetValue(XmlValueSource()); + } + } + lmp->Complete(); + }; + if (auto typeIdPropName = smp->GetTypeIdProperty()) { + if (auto typeAttr = element->get_attribute(*typeIdPropName)) { + return smp->OnSubclass(oec, typeAttr->get_value()); + } + } + oec(smp); } void - get(const Ice::Double & value) const override + DocumentTreeIterate(const xmlpp::Node * node, ModelPartParam mp) { - apply(boost::lexical_cast<Glib::ustring>(value)); + while (node) { + if (auto element = dynamic_cast<const xmlpp::Element *>(node)) { + mp->OnChild( + [element](auto && smp, auto && md) { + if (md.flagSet(md_bare)) { + smp->OnAnonChild([element](auto && bmp, auto && bmd) { + DocumentTreeIterateElement(element, bmp, bmd); + }); + return; + } + DocumentTreeIterateElement(element, smp, md); + }, + element->get_name().raw(), + [](const auto & h) { + return h->GetMetadata().flagNotSet(md_attribute); + }); + } + else if (auto attribute = dynamic_cast<const xmlpp::Attribute *>(node)) { + mp->OnChild( + [attribute](auto && smp, auto &&) { + smp->Create(); + smp->SetValue(XmlValueSource(attribute)); + smp->Complete(); + }, + attribute->get_name().raw(), + [](const auto & h) { + return h->GetMetadata().flagSet(md_attribute); + }); + } + else if (auto content = dynamic_cast<const xmlpp::ContentNode *>(node)) { + bool bare = false; + if (!content->is_white_space()) { + bare = (mp->OnAnonChild( + [content](auto && smp, auto &&) { + smp->SetValue(XmlValueSource(content)); + }, + [](const auto & h) { + return h->GetMetadata().flagSet(md_text); + })); + } + if (!bare) { + mp->SetValue(XmlValueSource(content)); + } + } + node = node->get_next_sibling(); + } } void - get(const std::string & value) const override + DocumentTreeIterate(const xmlpp::Document * doc, ModelPartParam mp) { - apply(value); + DocumentTreeIterate(doc->get_root_node(), mp); } - private: - const std::function<void(const Glib::ustring &)> apply; - }; - - class XmlAttributeValueTarget : public XmlValueTarget { - public: - explicit XmlAttributeValueTarget(xmlpp::Element * p, const std::string & n) : - XmlValueTarget([p, n](auto && PH1) { - p->set_attribute(n, PH1); - }) - { - } - }; - - class XmlContentValueTarget : public XmlValueTarget { - public: - explicit XmlContentValueTarget(xmlpp::Element * p) : - XmlValueTarget([p](auto && PH1) { - p->set_first_child_text(PH1); - }) - { - } + void ModelTreeIterate(xmlpp::Element *, const std::string &, ModelPartParam mp, const HookCommon * hp, + const ElementCreator &); + void ModelTreeIterateRoot(xmlpp::Document *, const std::string &, ModelPartParam mp); + void ModelTreeProcessElement(const CurrentElementCreator &, ModelPartParam mp, const ElementCreator &); + void ModelTreeIterateDictAttrs(xmlpp::Element * element, ModelPartParam dict); + void ModelTreeIterateDictElements(xmlpp::Element * element, ModelPartParam dict); - explicit XmlContentValueTarget(const CurrentElementCreator & cec) : - XmlValueTarget([&](auto && PH1) { - cec->set_first_child_text(PH1); - }) + void + ModelTreeIterate(xmlpp::Element * n, const std::string & name, ModelPartParam mp, const HookCommon * hp, + const ElementCreator & ec) { - } - }; - - void - XmlDeserializer::DocumentTreeIterateDictAttrs( - const xmlpp::Element::const_AttributeList & attrs, const ModelPartPtr & dict) - { - for (const auto & attr : attrs) { - auto emp = dict->GetAnonChild(); - emp->Create(); - auto key = emp->GetChild(keyName); - auto value = emp->GetChild(valueName); - key->SetValue(XmlValueSource(attr->get_name())); - key->Complete(); - value->SetValue(XmlValueSource(attr->get_value())); - value->Complete(); - emp->Complete(); - } - } - - void - XmlDeserializer::DocumentTreeIterateDictElements(const xmlpp::Element * element, const ModelPartPtr & dict) - { - auto node = element->get_first_child(); - while (node) { - if (auto childElement = dynamic_cast<const xmlpp::Element *>(node)) { - auto emp = dict->GetAnonChild(); - emp->Create(); - auto key = emp->GetChild(keyName); - auto value = emp->GetChildRef(valueName); - key->SetValue(XmlValueSource(childElement->get_name())); - key->Complete(); - DocumentTreeIterateElement(childElement, value.Child(), value); - emp->Complete(); - } - node = node->get_next_sibling(); - } - } - - void - XmlDeserializer::DocumentTreeIterateElement(const xmlpp::Element * element, ModelPartPtr smp, const ChildRef & smpr) - { - if (auto typeIdPropName = smp->GetTypeIdProperty()) { - if (auto typeAttr = element->get_attribute(*typeIdPropName)) { - smp = smp->GetSubclassModelPart(typeAttr->get_value()); - } - } - smp->Create(); - if (smpr.ChildMetaData().flagSet(md_attributes)) { - auto attrs(element->get_attributes()); - if (!attrs.empty()) { - DocumentTreeIterateDictAttrs(attrs, smp); - } - } - else if (smpr.ChildMetaData().flagSet(md_elements)) { - DocumentTreeIterateDictElements(element, smp); - } - else { - auto attrs(element->get_attributes()); - if (!attrs.empty()) { - DocumentTreeIterate(attrs.front(), smp); - } - auto firstChild = element->get_first_child(); - if (firstChild) { - DocumentTreeIterate(firstChild, smp); + if (name.empty()) { + return; } - else { - smp->SetValue(XmlContentValueSource()); + if (hp && hp->GetMetadata().flagSet(md_attribute)) { + mp->GetValue(XmlValueTarget(n, name)); } - } - smp->Complete(); - } - - void - XmlDeserializer::DocumentTreeIterate(const xmlpp::Node * node, const ModelPartPtr & mp) - { - while (node) { - if (auto element = dynamic_cast<const xmlpp::Element *>(node)) { - auto smpr = mp->GetChildRef(element->get_name().raw(), [](const auto & h) { - return h->GetMetadata().flagNotSet(md_attribute); - }); - if (smpr) { - auto smp = smpr.Child(); - if (smpr.ChildMetaData().flagSet(md_bare)) { - smp = smp->GetAnonChild(); - } - if (smp) { - DocumentTreeIterateElement(element, smp, smpr); - } - } + else if (hp && hp->GetMetadata().flagSet(md_text)) { + mp->GetValue(XmlValueTarget(n)); } - else if (auto attribute = dynamic_cast<const xmlpp::Attribute *>(node)) { - auto smp = mp->GetChild(attribute->get_name().raw(), [](const auto & h) { - return h->GetMetadata().flagSet(md_attribute); - }); - if (smp) { - smp->Create(); - smp->SetValue(XmlAttributeValueSource(attribute)); - smp->Complete(); - } + else if (hp && hp->GetMetadata().flagSet(md_attributes)) { + ModelTreeIterateDictAttrs(n->add_child_element(name), mp); } - else if (auto content = dynamic_cast<const xmlpp::ContentNode *>(node)) { - ModelPartPtr smp; - if (!content->is_white_space()) { - smp = mp->GetAnonChild([](const auto & h) { - return h->GetMetadata().flagSet(md_text); - }); - } - if (smp) { - smp->SetValue(XmlContentValueSource(content)); - } - else { - mp->SetValue(XmlContentValueSource(content)); - } + else if (hp && hp->GetMetadata().flagSet(md_elements)) { + ModelTreeIterateDictElements(n->add_child_element(name), mp); } - node = node->get_next_sibling(); - } - } - - void - XmlDeserializer::DocumentTreeIterate(const xmlpp::Document * doc, const ModelPartPtr & mp) - { - DocumentTreeIterate(doc->get_root_node(), mp); - } - - void - XmlSerializer::ModelTreeIterate(xmlpp::Element * n, const std::string & name, const ModelPartPtr & mp, - const HookCommon * hp, const ElementCreator & ec) - { - if (name.empty()) { - return; - } - if (hp && hp->GetMetadata().flagSet(md_attribute)) { - mp->GetValue(XmlAttributeValueTarget(n, name)); - } - else if (hp && hp->GetMetadata().flagSet(md_text)) { - mp->GetValue(XmlContentValueTarget(n)); - } - else if (hp && hp->GetMetadata().flagSet(md_attributes)) { - ModelTreeIterateDictAttrs(n->add_child_element(name), mp); - } - else if (hp && hp->GetMetadata().flagSet(md_elements)) { - ModelTreeIterateDictElements(n->add_child_element(name), mp); - } - else { - if (hp && hp->GetMetadata().flagSet(md_bare)) { + else if (hp && hp->GetMetadata().flagSet(md_bare)) { ModelTreeProcessElement(n, mp, [name](auto && PH1, auto &&) { return PH1->add_child_element(name); }); @@ -369,60 +407,81 @@ namespace Slicer { ModelTreeProcessElement(cec, mp, defaultElementCreator); } } - } - void - XmlSerializer::ModelTreeIterateDictAttrs(xmlpp::Element * element, const ModelPartPtr & dict) - { - dict->OnEachChild([element](const auto &, const auto & mp, const auto &) { - if (mp->HasValue()) { - mp->GetChild(keyName)->GetValue(XmlValueTarget([&mp, element](const auto & name) { - mp->GetChild(valueName)->GetValue(XmlAttributeValueTarget(element, name)); - })); - } - }); - } + void + ModelTreeIterateDictAttrs(xmlpp::Element * element, ModelPartParam dict) + { + dict->OnEachChild([element](const auto &, const auto & mp, const auto &) { + if (mp->HasValue()) { + mp->OnChild( + [mp, element](auto && key, auto &&) { + key->GetValue(XmlValueTarget([mp, element](const auto & name) { + mp->OnChild( + [element, &name](auto && value, auto &&) { + value->GetValue(XmlValueTarget(element, name)); + }, + valueName); + })); + }, + keyName); + } + }); + } - void - XmlSerializer::ModelTreeIterateDictElements(xmlpp::Element * element, const ModelPartPtr & dict) - { - dict->OnEachChild([element](const auto &, const auto & mp, const auto &) { - if (mp->HasValue()) { - mp->GetChild(keyName)->GetValue(XmlValueTarget([&mp, element](const auto & name) { - CurrentElementCreator cec([&element, &name]() { - return element->add_child_element(name); + void + ModelTreeIterateDictElements(xmlpp::Element * element, ModelPartParam dict) + { + dict->OnEachChild([element](const auto &, const auto & mp, const auto &) { + if (mp->HasValue()) { + mp->OnChild( + [mp, element](auto && key, auto &&) { + key->GetValue(XmlValueTarget([mp, element](const auto & name) { + CurrentElementCreator cec([&element, &name]() { + return element->add_child_element(name); + }); + mp->OnChild( + [&cec](auto && value, auto &&) { + ModelTreeProcessElement(cec, value, defaultElementCreator); + }, + valueName); + })); + }, + keyName); + } + }); + } + + void + ModelTreeProcessElement(const CurrentElementCreator & cec, ModelPartParam mp, const ElementCreator & ec) + { + if (mp->GetType() == ModelPartType::Simple) { + mp->GetValue(XmlValueTarget(cec)); + } + else if (mp->HasValue()) { + auto oec = [element = cec.get(), &ec](const auto & lmp) { + lmp->OnEachChild([element, &ec](auto && PH1, auto && PH2, auto && PH3) { + return ModelTreeIterate(element, PH1, PH2, PH3, ec); }); - ModelTreeProcessElement(cec, mp->GetChild(valueName), defaultElementCreator); - })); + return element; + }; + if (auto typeIdPropName = mp->GetTypeIdProperty()) { + if (auto typeId = mp->GetTypeId()) { + return mp->OnSubclass( + [oec, &typeIdPropName, &typeId](auto && smp) { + oec(smp)->set_attribute(*typeIdPropName, *typeId); + }, + *typeId); + } + } + oec(mp); } - }); - } - - void - XmlSerializer::ModelTreeProcessElement( - const CurrentElementCreator & cec, ModelPartPtr mp, const ElementCreator & ec) - { - if (mp->GetType() == ModelPartType::Simple) { - mp->GetValue(XmlContentValueTarget(cec)); - } - else if (mp->HasValue()) { - auto typeIdPropName = mp->GetTypeIdProperty(); - auto typeId = mp->GetTypeId(); - auto element = cec.get(); - if (typeId && typeIdPropName) { - element->set_attribute(*typeIdPropName, *typeId); - mp = mp->GetSubclassModelPart(*typeId); - } - mp->OnEachChild([element, ec](auto && PH1, auto && PH2, auto && PH3) { - return XmlSerializer::ModelTreeIterate(element, PH1, PH2, PH3, ec); - }); } - } - void - XmlSerializer::ModelTreeIterateRoot(xmlpp::Document * doc, const std::string & name, const ModelPartPtr & mp) - { - ModelTreeProcessElement(doc->create_root_node(name), mp, defaultElementCreator); + void + ModelTreeIterateRoot(xmlpp::Document * doc, const std::string & name, ModelPartParam mp) + { + ModelTreeProcessElement(doc->create_root_node(name), mp, defaultElementCreator); + } } XmlStreamSerializer::XmlStreamSerializer(std::ostream & s) : strm(s) { } @@ -430,7 +489,7 @@ namespace Slicer { XmlStreamDeserializer::XmlStreamDeserializer(std::istream & s) : strm(s) { } void - XmlStreamDeserializer::Deserialize(ModelPartForRootPtr modelRoot) + XmlStreamDeserializer::Deserialize(ModelPartForRootParam modelRoot) { xmlpp::DomParser dom; dom.parse_stream(strm); @@ -439,7 +498,7 @@ namespace Slicer { } void - XmlStreamSerializer::Serialize(ModelPartForRootPtr modelRoot) + XmlStreamSerializer::Serialize(ModelPartForRootParam modelRoot) { XmlDocumentSerializer::Serialize(modelRoot); doc.write_to_stream(strm); @@ -450,7 +509,7 @@ namespace Slicer { XmlFileDeserializer::XmlFileDeserializer(std::filesystem::path p) : path(std::move(p)) { } void - XmlFileDeserializer::Deserialize(ModelPartForRootPtr modelRoot) + XmlFileDeserializer::Deserialize(ModelPartForRootParam modelRoot) { xmlpp::DomParser dom(path); auto doc = dom.get_document(); @@ -460,23 +519,32 @@ namespace Slicer { XmlDocumentDeserializer::XmlDocumentDeserializer(const xmlpp::Document * d) : doc(d) { } void - XmlDocumentDeserializer::Deserialize(ModelPartForRootPtr modelRoot) + XmlDocumentDeserializer::Deserialize(ModelPartForRootParam modelRoot) { DocumentTreeIterate(doc, modelRoot); } void - XmlDocumentSerializer::Serialize(ModelPartForRootPtr modelRoot) + XmlDocumentSerializer::Serialize(ModelPartForRootParam modelRoot) { modelRoot->OnEachChild([this](auto && PH1, auto && PH2, auto &&) { - return XmlSerializer::ModelTreeIterateRoot(&doc, PH1, PH2); + return ModelTreeIterateRoot(&doc, PH1, PH2); }); } AdHocFormatter(BadBooleanValueMsg, "Bad boolean value [%?]"); + void BadBooleanValue::ice_print(std::ostream & s) const { BadBooleanValueMsg::write(s, text); } + + AdHocFormatter(BadNumericValueMsg, "Bad numeric value [%?]"); + + void + BadNumericValue::ice_print(std::ostream & s) const + { + BadNumericValueMsg::write(s, text); + } } diff --git a/slicer/xml/serializer.h b/slicer/xml/serializer.h index d07a77e..9c6e1ae 100644 --- a/slicer/xml/serializer.h +++ b/slicer/xml/serializer.h @@ -1,7 +1,6 @@ #ifndef SLICER_XML_H #define SLICER_XML_H -#include <lazyPointer.h> #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #pragma GCC diagnostic ignored "-Wsign-conversion" @@ -9,39 +8,22 @@ # pragma GCC diagnostic ignored "-Wuseless-cast" #endif #include <libxml++/document.h> -#include <libxml++/nodes/element.h> #pragma GCC diagnostic pop #include <filesystem> #include <fstream> -#include <functional> -#include <iosfwd> #include <slicer/modelParts.h> #include <slicer/serializer.h> #include <string> #include <visibility.h> + namespace Glib { class ustring; } namespace Slicer { - using CurrentElementCreator = ::AdHoc::LazyPointer<xmlpp::Element, xmlpp::Element *>; - - class DLL_PUBLIC XmlSerializer : public Serializer { - protected: - using ElementCreator = std::function<xmlpp::Element *(xmlpp::Element *, const Glib::ustring &)>; - static void ModelTreeIterate(xmlpp::Element *, const std::string &, const ModelPartPtr & mp, - const HookCommon * hp, const ElementCreator &); - static void ModelTreeIterateRoot(xmlpp::Document *, const std::string &, const ModelPartPtr & mp); - - protected: - static void ModelTreeProcessElement(const CurrentElementCreator &, ModelPartPtr mp, const ElementCreator &); - static void ModelTreeIterateDictAttrs(xmlpp::Element * element, const ModelPartPtr & dict); - static void ModelTreeIterateDictElements(xmlpp::Element * element, const ModelPartPtr & dict); - }; - - class DLL_PUBLIC XmlDocumentSerializer : public XmlSerializer { + class DLL_PUBLIC XmlDocumentSerializer : public Serializer { public: - void Serialize(ModelPartForRootPtr) override; + void Serialize(ModelPartForRootParam) override; protected: xmlpp::Document doc; @@ -51,7 +33,7 @@ namespace Slicer { public: explicit XmlStreamSerializer(std::ostream &); - void Serialize(ModelPartForRootPtr) override; + void Serialize(ModelPartForRootParam) override; protected: std::ostream & strm; @@ -65,41 +47,31 @@ namespace Slicer { std::ofstream strm; }; - class DLL_PUBLIC XmlDeserializer : public Deserializer { - protected: - static void DocumentTreeIterate(const xmlpp::Node * node, const ModelPartPtr & mp); - static void DocumentTreeIterateElement(const xmlpp::Element * element, ModelPartPtr mp, const ChildRef & c); - static void DocumentTreeIterate(const xmlpp::Document * doc, const ModelPartPtr & mp); - static void DocumentTreeIterateDictAttrs( - const xmlpp::Element::const_AttributeList & attrs, const ModelPartPtr & dict); - static void DocumentTreeIterateDictElements(const xmlpp::Element * parent, const ModelPartPtr & dict); - }; - - class DLL_PUBLIC XmlStreamDeserializer : public XmlDeserializer { + class DLL_PUBLIC XmlStreamDeserializer : public Deserializer { public: explicit XmlStreamDeserializer(std::istream &); - void Deserialize(ModelPartForRootPtr) override; + void Deserialize(ModelPartForRootParam) override; protected: std::istream & strm; }; - class DLL_PUBLIC XmlFileDeserializer : public XmlDeserializer { + class DLL_PUBLIC XmlFileDeserializer : public Deserializer { public: explicit XmlFileDeserializer(std::filesystem::path); - void Deserialize(ModelPartForRootPtr) override; + void Deserialize(ModelPartForRootParam) override; protected: const std::filesystem::path path; }; - class DLL_PUBLIC XmlDocumentDeserializer : public XmlDeserializer { + class DLL_PUBLIC XmlDocumentDeserializer : public Deserializer { public: explicit XmlDocumentDeserializer(const xmlpp::Document *); - void Deserialize(ModelPartForRootPtr) override; + void Deserialize(ModelPartForRootParam) override; protected: const xmlpp::Document * doc; diff --git a/slicer/xml/testSpecifics.cpp b/slicer/xml/testSpecifics.cpp index e2d7691..6f94ed4 100644 --- a/slicer/xml/testSpecifics.cpp +++ b/slicer/xml/testSpecifics.cpp @@ -1,4 +1,5 @@ #define BOOST_TEST_MODULE xml_specifics +#include <boost/test/data/test_case.hpp> #include <boost/test/unit_test.hpp> #include "serializer.h" @@ -16,50 +17,67 @@ #include <slicer/slicer.h> #include <typeinfo> #include <xmlExceptions.h> + // IWYU pragma: no_forward_declare Slicer::BadBooleanValue // IWYU pragma: no_forward_declare Slicer::XmlDocumentDeserializer -template<typename T, typename... P> -T -BoostThrowWrapperHelper(P &&... p) +template<typename T> +const auto BoostThrowWrapperHelper + = Slicer::DeserializeAny<Slicer::XmlDocumentDeserializer, T, const xmlpp::Document *>; + +template<typename out> using data = std::tuple<const char *, out>; +BOOST_FIXTURE_TEST_SUITE(doc, xmlpp::DomParser) + +BOOST_DATA_TEST_CASE(good_boolean_values, + boost::unit_test::data::make<data<bool>>({ + {"<Boolean>true</Boolean>", true}, + {"<Boolean>false</Boolean>", false}, + }), + in, exp) { - return Slicer::DeserializeAny<Slicer::XmlDocumentDeserializer, T>(std::forward<P>(p)...); + parse_memory(in); + BOOST_CHECK_EQUAL(exp, BoostThrowWrapperHelper<bool>(get_document())); } -BOOST_AUTO_TEST_CASE(boolean_values) +BOOST_DATA_TEST_CASE(bad_boolean_values, + boost::unit_test::data::make({ + "<Boolean>nonsense</Boolean>", + "<Boolean> </Boolean>", + "<Boolean></Boolean>", + }), + in) { - xmlpp::DomParser doc; - doc.parse_memory("<Boolean>true</Boolean>"); - BOOST_REQUIRE_EQUAL(true, BoostThrowWrapperHelper<bool>(doc.get_document())); - doc.parse_memory("<Boolean>false</Boolean>"); - BOOST_REQUIRE_EQUAL(false, BoostThrowWrapperHelper<bool>(doc.get_document())); - doc.parse_memory("<Boolean>nonsense</Boolean>"); - BOOST_REQUIRE_THROW(BoostThrowWrapperHelper<bool>(doc.get_document()), Slicer::BadBooleanValue); - doc.parse_memory("<Boolean> </Boolean>"); - BOOST_REQUIRE_THROW(BoostThrowWrapperHelper<bool>(doc.get_document()), Slicer::BadBooleanValue); - doc.parse_memory("<Boolean></Boolean>"); - BOOST_REQUIRE_THROW(BoostThrowWrapperHelper<bool>(doc.get_document()), Slicer::BadBooleanValue); + parse_memory(in); + BOOST_CHECK_THROW(BoostThrowWrapperHelper<bool>(get_document()), Slicer::BadBooleanValue); } -BOOST_AUTO_TEST_CASE(int_values) +BOOST_DATA_TEST_CASE(good_integer_values, + boost::unit_test::data::make<data<Ice::Int>>({ + {"<Int>13</Int>", 13}, + {"<Int>84</Int>", 84}, + {"<Int>0</Int>", 0}, + {"<Int>-4</Int>", -4}, + }), + in, exp) { - xmlpp::DomParser doc; - doc.parse_memory("<Int>13</Int>"); - BOOST_REQUIRE_EQUAL(13, BoostThrowWrapperHelper<Ice::Int>(doc.get_document())); - doc.parse_memory("<Int>84</Int>"); - BOOST_REQUIRE_EQUAL(84, BoostThrowWrapperHelper<Ice::Int>(doc.get_document())); - doc.parse_memory("<Int>0</Int>"); - BOOST_REQUIRE_EQUAL(0, BoostThrowWrapperHelper<Ice::Int>(doc.get_document())); - doc.parse_memory("<Int>-4</Int>"); - BOOST_REQUIRE_EQUAL(-4, BoostThrowWrapperHelper<Ice::Int>(doc.get_document())); - doc.parse_memory("<Int> </Int>"); - BOOST_REQUIRE_THROW(BoostThrowWrapperHelper<Ice::Int>(doc.get_document()), std::bad_cast); - doc.parse_memory("<Int>notanint</Int>"); - BOOST_REQUIRE_THROW(BoostThrowWrapperHelper<Ice::Int>(doc.get_document()), std::bad_cast); - doc.parse_memory("<Int></Int>"); - BOOST_REQUIRE_THROW(BoostThrowWrapperHelper<Ice::Int>(doc.get_document()), std::bad_cast); + parse_memory(in); + BOOST_CHECK_EQUAL(exp, BoostThrowWrapperHelper<Ice::Int>(get_document())); } +BOOST_DATA_TEST_CASE(bad_integer_values, + boost::unit_test::data::make({ + "<Int> </Int>", + "<Int>notanint</Int>", + "<Int></Int>", + }), + in) +{ + parse_memory(in); + BOOST_CHECK_THROW(BoostThrowWrapperHelper<Ice::Int>(get_document()), Slicer::BadNumericValue); +} + +BOOST_AUTO_TEST_SUITE_END() + BOOST_AUTO_TEST_CASE(factories) { BOOST_REQUIRE(Slicer::FileSerializerFactory::createNew(".xml", "/some.xml")); diff --git a/slicer/xml/xmlExceptions.ice b/slicer/xml/xmlExceptions.ice index 390f458..26d8aa2 100644 --- a/slicer/xml/xmlExceptions.ice +++ b/slicer/xml/xmlExceptions.ice @@ -8,6 +8,10 @@ module Slicer { exception BadBooleanValue extends DeserializerError { string text; }; + ["cpp:ice_print"] + exception BadNumericValue extends DeserializerError { + string text; + }; }; #endif |