summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--slicer/db/Jamfile.jam35
-rw-r--r--slicer/db/sqlBinder.h2
-rw-r--r--slicer/db/sqlCommon.cpp11
-rw-r--r--slicer/db/sqlCommon.h10
-rw-r--r--slicer/db/sqlInsertSerializer.cpp32
-rw-r--r--slicer/db/sqlInsertSerializer.h31
-rw-r--r--slicer/db/sqlSelectDeserializer.cpp120
-rw-r--r--slicer/db/sqlSelectDeserializer.h16
-rw-r--r--slicer/db/sqlSource.cpp33
-rw-r--r--slicer/db/sqlSource.h5
-rw-r--r--slicer/db/sqlTablePatchSerializer.cpp24
-rw-r--r--slicer/db/sqlTablePatchSerializer.h3
-rw-r--r--slicer/db/sqlUpdateSerializer.cpp25
-rw-r--r--slicer/db/sqlUpdateSerializer.h11
-rw-r--r--slicer/db/testInsert.cpp1
-rw-r--r--slicer/db/testMockCommon.h1
-rw-r--r--slicer/db/testPatch.cpp2
-rw-r--r--slicer/db/testPerf.cpp37
-rw-r--r--slicer/ice/serializer.cpp8
-rw-r--r--slicer/ice/serializer.h13
-rw-r--r--slicer/ice/testSpecifics.cpp1
-rw-r--r--slicer/json/serializer.cpp593
-rw-r--r--slicer/json/serializer.h24
-rw-r--r--slicer/slicer/any_ptr.h60
-rw-r--r--slicer/slicer/enumMap.h1
-rw-r--r--slicer/slicer/hook-test.cpp1
-rw-r--r--slicer/slicer/hookMap.cpp8
-rw-r--r--slicer/slicer/hookMap.h10
-rw-r--r--slicer/slicer/metadata.h1
-rw-r--r--slicer/slicer/modelParts.cpp35
-rw-r--r--slicer/slicer/modelParts.h75
-rw-r--r--slicer/slicer/modelPartsTypes.cpp195
-rw-r--r--slicer/slicer/modelPartsTypes.h58
-rw-r--r--slicer/slicer/modelPartsTypes.impl.h191
-rw-r--r--slicer/slicer/serializer.h7
-rw-r--r--slicer/slicer/slicer.cpp31
-rw-r--r--slicer/slicer/slicer.h16
-rw-r--r--slicer/test/Jamfile.jam29
-rw-r--r--slicer/test/compilation.cpp193
-rw-r--r--slicer/test/conversions.cpp24
-rw-r--r--slicer/test/conversions.h1
-rw-r--r--slicer/test/perf.cpp81
-rw-r--r--slicer/test/serializers.cpp24
-rw-r--r--slicer/tool/icemetadata.cpp1
-rw-r--r--slicer/tool/parser.cpp19
-rw-r--r--slicer/tool/parser.h2
-rw-r--r--slicer/xml/serializer.cpp724
-rw-r--r--slicer/xml/serializer.h48
-rw-r--r--slicer/xml/testSpecifics.cpp82
-rw-r--r--slicer/xml/xmlExceptions.ice4
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, &paramNo, 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, &paramNo](const std::string &, const ModelPartPtr & cmp, const HookCommon * h) {
+ mp->OnEachChild([&upd, &paramNo](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, &paramNo](const std::string &, const ModelPartPtr & cmp, const HookCommon * h) {
+ mp->OnEachChild([&upd, &paramNo](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