From 48ccbe39b4024190c2be362f800363ad5160f912 Mon Sep 17 00:00:00 2001 From: AsyaPronina <155jj@mail.ru> Date: Mon, 2 Nov 2020 18:54:19 +0300 Subject: [PATCH] Changed behaviour of cv::gapi::serialize, cv::gapi::deserialize for GCompileArgs - cv::gapi::serialize bypasses compile arguments which have no S11N specialization with serialize/deserialize callbacks for underlying types - cv::gapi::deserialize can accept arbitraty number of serialized compile args in a stream but will return only those which are requested by user via template parameter pack if they are presented in the stream. If some or all of them are not presented cv::gapi::deserialize will ignore and return only those which are presented - cv::gapi::deserialize can accept only types which can be deserialized (have S11N specialization with the user callbacks) - Added cv::gapi::s11n::detail::has_S11N_spec trait to separate compile arguments which have S11N specialization with the user callbacks --- modules/gapi/include/opencv2/gapi/gcommon.hpp | 13 +- modules/gapi/include/opencv2/gapi/s11n.hpp | 48 +++- .../gapi/include/opencv2/gapi/s11n/base.hpp | 16 +- .../src/backends/common/serialization.cpp | 7 +- modules/gapi/test/s11n/gapi_s11n_tests.cpp | 271 ++++++++++++++++-- 5 files changed, 310 insertions(+), 45 deletions(-) diff --git a/modules/gapi/include/opencv2/gapi/gcommon.hpp b/modules/gapi/include/opencv2/gapi/gcommon.hpp index 2b260ed07c..0242020f6a 100644 --- a/modules/gapi/include/opencv2/gapi/gcommon.hpp +++ b/modules/gapi/include/opencv2/gapi/gcommon.hpp @@ -161,7 +161,9 @@ public: template::value, int>::type = 0> explicit GCompileArg(T &&t) : tag(detail::CompileArgTag::type>::tag()) - , serializeF(&cv::gapi::s11n::detail::wrap_serialize::serialize) + , serializeF(cv::gapi::s11n::detail::has_S11N_spec::value ? + &cv::gapi::s11n::detail::wrap_serialize::serialize : + nullptr) , arg(t) { } @@ -178,7 +180,10 @@ public: void serialize(cv::gapi::s11n::IOStream& os) const { - serializeF(os, *this); + if (serializeF) + { + serializeF(os, *this); + } } private: @@ -222,8 +227,8 @@ template struct wrap_serialize { static void serialize(IOStream& os, const GCompileArg& arg) { - using decayed_type = typename std::decay::type; - S11N::serialize(os, arg.get()); + using DT = typename std::decay::type; + S11N
::serialize(os, arg.get
()); } }; } // namespace detail diff --git a/modules/gapi/include/opencv2/gapi/s11n.hpp b/modules/gapi/include/opencv2/gapi/s11n.hpp index 2fa4e51176..0e3e382328 100644 --- a/modules/gapi/include/opencv2/gapi/s11n.hpp +++ b/modules/gapi/include/opencv2/gapi/s11n.hpp @@ -265,23 +265,25 @@ void getRunArgByIdx (IIStream& is, cv::util::variant &v, uint32_t idx) { namespace detail { -template struct deserialize_arg; +template struct try_deserialize_comparg; -template<> struct deserialize_arg> { -static GCompileArg exec(cv::gapi::s11n::IIStream&, const std::string&) { - throw std::logic_error("Passed arg can't be deserialized!"); +template<> struct try_deserialize_comparg> { +static cv::util::optional exec(const std::string&, cv::gapi::s11n::IIStream&) { + return { }; } }; template -struct deserialize_arg> { -static GCompileArg exec(cv::gapi::s11n::IIStream& is, const std::string& tag) { +struct try_deserialize_comparg> { +static cv::util::optional exec(const std::string& tag, cv::gapi::s11n::IIStream& is) { if (tag == cv::detail::CompileArgTag::tag()) { - return GCompileArg { - cv::gapi::s11n::detail::S11N::deserialize(is) - }; + static_assert(cv::gapi::s11n::detail::has_S11N_spec::value, + "cv::gapi::deserialize expects Types to have S11N " + "specializations with deserialization callbacks!"); + return cv::util::optional( + GCompileArg { cv::gapi::s11n::detail::S11N::deserialize(is) }); } - return deserialize_arg>::exec(is, tag); + return try_deserialize_comparg>::exec(tag, is); } }; @@ -303,17 +305,35 @@ static GRunArg exec(cv::gapi::s11n::IIStream& is, uint32_t idx) { }; template -cv::GCompileArgs getCompileArgs(const std::vector &p) { - std::unique_ptr pIs = cv::gapi::s11n::detail::getInStream(p); - cv::gapi::s11n::IIStream& is = *pIs; +inline cv::util::optional tryDeserializeCompArg(const std::string& tag, + const std::vector& sArg) { + std::unique_ptr pArgIs = cv::gapi::s11n::detail::getInStream(sArg); + return try_deserialize_comparg>::exec(tag, *pArgIs); +} + +template +cv::GCompileArgs getCompileArgs(const std::vector &sArgs) { cv::GCompileArgs args; + std::unique_ptr pIs = cv::gapi::s11n::detail::getInStream(sArgs); + cv::gapi::s11n::IIStream& is = *pIs; + uint32_t sz = 0; is >> sz; for (uint32_t i = 0; i < sz; ++i) { std::string tag; is >> tag; - args.push_back(cv::gapi::detail::deserialize_arg>::exec(is, tag)); + + std::vector sArg; + is >> sArg; + + cv::util::optional dArg = + cv::gapi::detail::tryDeserializeCompArg(tag, sArg); + + if (dArg.has_value()) + { + args.push_back(dArg.value()); + } } return args; diff --git a/modules/gapi/include/opencv2/gapi/s11n/base.hpp b/modules/gapi/include/opencv2/gapi/s11n/base.hpp index 6bf5d5fb0f..d9335ee9f7 100644 --- a/modules/gapi/include/opencv2/gapi/s11n/base.hpp +++ b/modules/gapi/include/opencv2/gapi/s11n/base.hpp @@ -8,6 +8,7 @@ #define OPENCV_GAPI_S11N_BASE_HPP #include +#include namespace cv { namespace gapi { @@ -16,10 +17,14 @@ struct IOStream; struct IIStream; namespace detail { -// Will be used along with default types if possible in specific cases (compile args, etc) -// Note: actual implementation is defined by user + +struct NotImplemented { +}; + +// The default S11N for custom types is NotImplemented +// Don't! sublass from NotImplemented if you actually implement S11N. template -struct S11N { +struct S11N: public NotImplemented { static void serialize(IOStream &, const T &) { GAPI_Assert(false && "No serialization routine is provided!"); } @@ -28,6 +33,11 @@ struct S11N { } }; +template struct has_S11N_spec { + static constexpr bool value = !std::is_base_of::type>>::value; +}; + } // namespace detail } // namespace s11n } // namespace gapi diff --git a/modules/gapi/src/backends/common/serialization.cpp b/modules/gapi/src/backends/common/serialization.cpp index bb1864823f..592c03cfed 100644 --- a/modules/gapi/src/backends/common/serialization.cpp +++ b/modules/gapi/src/backends/common/serialization.cpp @@ -338,8 +338,13 @@ IIStream& operator>> (IIStream& is, cv::gapi::wip::draw::Line &l) { IOStream& operator<< (IOStream& os, const cv::GCompileArg& arg) { + ByteMemoryOutStream tmpS; + arg.serialize(tmpS); + std::vector data = tmpS.data(); + os << arg.tag; - arg.serialize(os); + os << data; + return os; } diff --git a/modules/gapi/test/s11n/gapi_s11n_tests.cpp b/modules/gapi/test/s11n/gapi_s11n_tests.cpp index 3fe632e449..2fc1e46253 100644 --- a/modules/gapi/test/s11n/gapi_s11n_tests.cpp +++ b/modules/gapi/test/s11n/gapi_s11n_tests.cpp @@ -4,32 +4,86 @@ #include namespace { - struct MyCustomType { - int val; - std::string name; - std::vector vec; - std::map mmap; - bool operator==(const MyCustomType& other) const { - return val == other.val && name == other.name && - vec == other.vec && mmap == other.mmap; - } - }; -} +struct EmptyCustomType { }; + +struct SimpleCustomType { + bool val; + bool operator==(const SimpleCustomType& other) const { + return val == other.val; + } +}; + +struct SimpleCustomType2 { + int id; + bool operator==(const SimpleCustomType2& other) const { + return id == other.id; + } +}; + +struct MyCustomType { + int val; + std::string name; + std::vector vec; + std::map mmap; + bool operator==(const MyCustomType& other) const { + return val == other.val && name == other.name && + vec == other.vec && mmap == other.mmap; + } +}; + +struct MyCustomTypeNoS11N { + char sym; + int id; + std::string name; + + bool operator==(const MyCustomTypeNoS11N& other) const { + return sym == other.sym && id == other.id && + name == other.name; + } +}; +} // anonymous namespace namespace cv { namespace gapi { namespace s11n { namespace detail { - template<> struct S11N { - static void serialize(IOStream &os, const MyCustomType &p) { - os << p.val << p.name << p.vec << p.mmap; - } - static MyCustomType deserialize(IIStream &is) { - MyCustomType p; - is >> p.val >> p.name >> p.vec >> p.mmap; - return p; - } - }; +template<> struct S11N { + static void serialize(IOStream &, const EmptyCustomType &) { } + static EmptyCustomType deserialize(IIStream &) { return EmptyCustomType { }; } +}; + +template<> struct S11N { + static void serialize(IOStream &os, const SimpleCustomType &p) { + os << p.val; + } + static SimpleCustomType deserialize(IIStream &is) { + SimpleCustomType p; + is >> p.val; + return p; + } +}; + +template<> struct S11N { + static void serialize(IOStream &os, const SimpleCustomType2 &p) { + os << p.id; + } + static SimpleCustomType2 deserialize(IIStream &is) { + SimpleCustomType2 p; + is >> p.id; + return p; + } +}; + +template<> struct S11N { + static void serialize(IOStream &os, const MyCustomType &p) { + os << p.val << p.name << p.vec << p.mmap; + } + static MyCustomType deserialize(IIStream &is) { + MyCustomType p; + is >> p.val >> p.name >> p.vec >> p.mmap; + return p; + } +}; } // namespace detail } // namespace s11n } // namespace gapi @@ -38,9 +92,33 @@ namespace detail { namespace cv { namespace detail { +template<> struct CompileArgTag { + static const char* tag() { + return "org.opencv.test.empty_custom_type"; + } +}; + +template<> struct CompileArgTag { + static const char* tag() { + return "org.opencv.test.simple_custom_type"; + } +}; + +template<> struct CompileArgTag { + static const char* tag() { + return "org.opencv.test.simple_custom_type_2"; + } +}; + template<> struct CompileArgTag { static const char* tag() { - return "org.opencv.test.mycustomtype"; + return "org.opencv.test.my_custom_type"; + } +}; + +template<> struct CompileArgTag { + static const char* tag() { + return "org.opencv.test.my_custom_type_no_s11n"; } }; } // namespace detail @@ -586,7 +664,7 @@ TEST_F(S11N_Basic, Test_Custom_Type) { EXPECT_EQ(var, new_var); } -TEST_F(S11N_Basic, Test_Custom_CompileArg) { +TEST_F(S11N_Basic, Test_CompileArg) { MyCustomType customVar{1248, "World", {1280, 720, 640, 480}, {{5, 32434142342}, {7, 34242432}}}; std::vector sArgs = cv::gapi::serialize(cv::compile_args(customVar)); @@ -596,4 +674,151 @@ TEST_F(S11N_Basic, Test_Custom_CompileArg) { MyCustomType dCustomVar = cv::gapi::getCompileArg(dArgs).value(); EXPECT_EQ(customVar, dCustomVar); } + +TEST_F(S11N_Basic, Test_CompileArg_Without_UserCallback) { + SimpleCustomType customVar1 { false }; + MyCustomTypeNoS11N customVar2 { 'z', 189, "Name" }; + MyCustomType customVar3 { 1248, "World", {1280, 720, 640, 480}, + {{5, 32434142342}, {7, 34242432}} }; + + EXPECT_NO_THROW(cv::gapi::serialize(cv::compile_args(customVar1, customVar2, customVar3))); + + std::vector sArgs = cv::gapi::serialize( + cv::compile_args(customVar1, customVar2, customVar3)); + + GCompileArgs dArgs = cv::gapi::deserialize(sArgs); + + SimpleCustomType dCustomVar1 = cv::gapi::getCompileArg(dArgs).value(); + MyCustomType dCustomVar3 = cv::gapi::getCompileArg(dArgs).value(); + + EXPECT_EQ(customVar1, dCustomVar1); + EXPECT_EQ(customVar3, dCustomVar3); +} + +TEST_F(S11N_Basic, Test_Deserialize_Only_Requested_CompileArgs) { + MyCustomType myCustomVar { 1248, "World", {1280, 720, 640, 480}, + {{5, 32434142342}, {7, 34242432}} }; + SimpleCustomType simpleCustomVar { false }; + + std::vector sArgs = cv::gapi::serialize(cv::compile_args(myCustomVar, simpleCustomVar)); + + GCompileArgs dArgs = cv::gapi::deserialize(sArgs); + EXPECT_EQ(1u, dArgs.size()); + EXPECT_EQ(myCustomVar, cv::gapi::getCompileArg(dArgs).value()); + + dArgs.clear(); + dArgs = cv::gapi::deserialize(sArgs); + EXPECT_EQ(1u, dArgs.size()); + EXPECT_EQ(simpleCustomVar, cv::gapi::getCompileArg(dArgs).value()); + + dArgs.clear(); + dArgs = cv::gapi::deserialize(sArgs); + EXPECT_EQ(0u, dArgs.size()); + + dArgs.clear(); + dArgs = cv::gapi::deserialize(sArgs); + EXPECT_EQ(2u, dArgs.size()); + EXPECT_EQ(myCustomVar, cv::gapi::getCompileArg(dArgs).value()); + EXPECT_EQ(simpleCustomVar, cv::gapi::getCompileArg(dArgs).value()); + + SimpleCustomType2 simpleCustomVar2 { 5 }; + std::vector sArgs2 = cv::gapi::serialize( + cv::compile_args(myCustomVar, simpleCustomVar, simpleCustomVar2)); + GCompileArgs dArgs2 = cv::gapi::deserialize(sArgs2); + EXPECT_EQ(2u, dArgs2.size()); + EXPECT_EQ(myCustomVar, cv::gapi::getCompileArg(dArgs2).value()); + EXPECT_EQ(simpleCustomVar2, cv::gapi::getCompileArg(dArgs2).value()); +} + +TEST_F(S11N_Basic, Test_Deserialize_CompileArgs_RandomOrder) { + SimpleCustomType simpleCustomVar { false }; + SimpleCustomType2 simpleCustomVar2 { 5 }; + + std::vector sArgs = cv::gapi::serialize( + cv::compile_args(simpleCustomVar, simpleCustomVar2)); + GCompileArgs dArgs = cv::gapi::deserialize(sArgs); + + EXPECT_EQ(simpleCustomVar, cv::gapi::getCompileArg(dArgs).value()); + EXPECT_EQ(simpleCustomVar2, cv::gapi::getCompileArg(dArgs).value()); +} + +TEST_F(S11N_Basic, Test_CompileArgs_With_EmptyCompileArg) { + MyCustomType myCustomVar { 1248, "World", {1280, 720, 640, 480}, + {{5, 32434142342}, {7, 34242432}} }; + SimpleCustomType simpleCustomVar { false }; + EmptyCustomType emptyCustomVar { }; + + //----{ emptyCustomVar, myCustomVar }---- + std::vector sArgs1 = cv::gapi::serialize(cv::compile_args(emptyCustomVar, myCustomVar)); + GCompileArgs dArgsEmptyVar1 = cv::gapi::deserialize(sArgs1); + GCompileArgs dArgsMyVar1 = cv::gapi::deserialize(sArgs1); + GCompileArgs dArgsEmptyAndMyVars1 = cv::gapi::deserialize(sArgs1); + EXPECT_EQ(1u, dArgsEmptyVar1.size()); + EXPECT_TRUE(cv::gapi::getCompileArg(dArgsEmptyVar1).has_value()); + EXPECT_EQ(1u, dArgsMyVar1.size()); + EXPECT_EQ(myCustomVar, cv::gapi::getCompileArg(dArgsMyVar1).value()); + EXPECT_EQ(2u, dArgsEmptyAndMyVars1.size()); + EXPECT_TRUE(cv::gapi::getCompileArg(dArgsEmptyAndMyVars1).has_value()); + EXPECT_EQ(myCustomVar, cv::gapi::getCompileArg(dArgsEmptyAndMyVars1).value()); + + //----{ myCustomVar, emptyCustomVar }---- + std::vector sArgs2 = cv::gapi::serialize(cv::compile_args(myCustomVar, emptyCustomVar)); + GCompileArgs dArgsMyVar2 = cv::gapi::deserialize(sArgs2); + GCompileArgs dArgsEmptyVar2 = cv::gapi::deserialize(sArgs2); + GCompileArgs dArgsMyAndEmptyVars2 = cv::gapi::deserialize(sArgs2); + EXPECT_EQ(1u, dArgsMyVar2.size()); + EXPECT_EQ(myCustomVar, cv::gapi::getCompileArg(dArgsMyVar2).value()); + EXPECT_EQ(1u, dArgsEmptyVar2.size()); + EXPECT_TRUE(cv::gapi::getCompileArg(dArgsEmptyVar2).has_value()); + EXPECT_EQ(2u, dArgsMyAndEmptyVars2.size()); + EXPECT_EQ(myCustomVar, cv::gapi::getCompileArg(dArgsMyAndEmptyVars2).value()); + EXPECT_TRUE(cv::gapi::getCompileArg(dArgsMyAndEmptyVars2).has_value()); + + //----{ myCustomVar, emptyCustomVar, simpleCustomVar }---- + std::vector sArgs3 = cv::gapi::serialize( + cv::compile_args(myCustomVar, emptyCustomVar, simpleCustomVar)); + GCompileArgs dArgsMyVar3 = cv::gapi::deserialize(sArgs3); + GCompileArgs dArgsEmptyVar3 = cv::gapi::deserialize(sArgs3); + GCompileArgs dArgsSimpleVar3 = cv::gapi::deserialize(sArgs3); + GCompileArgs dArgsMyAndSimpleVars3 = cv::gapi::deserialize(sArgs3); + GCompileArgs dArgs3 = cv::gapi::deserialize(sArgs3); + EXPECT_EQ(1u, dArgsMyVar3.size()); + EXPECT_EQ(myCustomVar, cv::gapi::getCompileArg(dArgsMyVar3).value()); + EXPECT_EQ(1u, dArgsEmptyVar3.size()); + EXPECT_TRUE(cv::gapi::getCompileArg(dArgsEmptyVar3).has_value()); + EXPECT_EQ(1u, dArgsSimpleVar3.size()); + EXPECT_EQ(simpleCustomVar, cv::gapi::getCompileArg(dArgsSimpleVar3).value()); + EXPECT_EQ(2u, dArgsMyAndSimpleVars3.size()); + EXPECT_EQ(myCustomVar, cv::gapi::getCompileArg(dArgsMyAndSimpleVars3).value()); + EXPECT_EQ(simpleCustomVar, + cv::gapi::getCompileArg(dArgsMyAndSimpleVars3).value()); + EXPECT_EQ(3u, dArgs3.size()); + EXPECT_EQ(myCustomVar, cv::gapi::getCompileArg(dArgs3).value()); + EXPECT_TRUE(cv::gapi::getCompileArg(dArgs3).has_value()); + EXPECT_EQ(simpleCustomVar, cv::gapi::getCompileArg(dArgs3).value()); + + //----{ emptyCustomVar }---- + std::vector sArgs4 = cv::gapi::serialize(cv::compile_args(emptyCustomVar)); + GCompileArgs dArgsEmptyVar4 = cv::gapi::deserialize(sArgs4); + EXPECT_EQ(1u, dArgsEmptyVar4.size()); + EXPECT_TRUE(cv::gapi::getCompileArg(dArgsEmptyVar4).has_value()); +} + } // namespace opencv_test