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