From dc94b26e50bee25610e3b000f415a2a36463e10f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 24 Feb 2016 10:18:47 -0500 Subject: [PATCH] fix static_shared_vector_cast<>() no-op casting Turns out that Enablers as typically used for member functions don't work to select constructors. Move this selection logic to struct detail::static_shared_vector_caster<> to correctly allow no-op casts (eg. void to void). Previously this would not compile. Allows PVScalarArray getAs() and putFrom() using shared_vector. --- src/misc/pv/sharedVector.h | 78 ++++++++++++++++++++++++------- testApp/misc/testSharedVector.cpp | 31 +++++++++--- testApp/pv/testPVScalarArray.cpp | 24 +++++++++- 3 files changed, 108 insertions(+), 25 deletions(-) diff --git a/src/misc/pv/sharedVector.h b/src/misc/pv/sharedVector.h index e3da8d9..6efcad2 100644 --- a/src/misc/pv/sharedVector.h +++ b/src/misc/pv/sharedVector.h @@ -326,7 +326,7 @@ public: //! Internal for static_shared_vector_cast template shared_vector(const shared_vector &src, - typename meta::is_void::type) + detail::_shared_vector_cast_tag) :base_t(std::tr1::static_pointer_cast(src.dataPtr()), src.dataOffset()/sizeof(E), src.dataCount()/sizeof(E)) @@ -566,7 +566,7 @@ public: //! Internal for static_shared_vector_cast template shared_vector(const shared_vector &src, - typename meta::is_not_void::type) + detail::_shared_vector_cast_tag) :base_t(std::tr1::static_pointer_cast(src.dataPtr()), src.dataOffset()*sizeof(FROM), src.dataCount()*sizeof(FROM)) @@ -602,6 +602,64 @@ public: ScalarType original_type() const {return m_vtype;} }; +namespace detail { + template + struct static_shared_vector_caster { /* no default */ }; + // from void to non-void with same const-ness + template + struct static_shared_vector_caster, meta::is_not_void >::type> { + static inline shared_vector op(const shared_vector& src) { + return shared_vector(src, detail::_shared_vector_cast_tag()); + } + }; + template + struct static_shared_vector_caster, meta::is_not_void >::type> { + static inline shared_vector op(const shared_vector& src) { + return shared_vector(src, detail::_shared_vector_cast_tag()); + } + }; + // from non-void to void with same const-ness + template + struct static_shared_vector_caster, meta::is_not_void >::type> { + static FORCE_INLINE shared_vector op(const shared_vector& src) { + return shared_vector(src, detail::_shared_vector_cast_tag()); + } + }; + template + struct static_shared_vector_caster, meta::is_not_void >::type> { + static FORCE_INLINE shared_vector op(const shared_vector& src) { + return shared_vector(src, detail::_shared_vector_cast_tag()); + } + }; + + // cast to same type, no-op + template + struct static_shared_vector_caster { + static FORCE_INLINE const shared_vector& op(const shared_vector& src) { + return src; + } + }; +} // namespace detail + +/** @brief Allow casting of shared_vector between types + * + * Currently only to/from void is implemented. + * + @warning Casting from void is undefined unless the offset and length + * are integer multiples of the size of the destination type. + */ +template +static FORCE_INLINE +shared_vector +static_shared_vector_cast(const shared_vector& src) +{ + return detail::static_shared_vector_caster::op(src); +} + namespace detail { // Default to type conversion using castUnsafe (C++ type casting) on each element @@ -662,22 +720,6 @@ namespace detail { }; } -/** @brief Allow casting of shared_vector between types - * - * Currently only to/from void is implemented. - * - @warning Casting from void is undefined unless the offset and length - * are integer multiples of the size of the destination type. - */ -template -static FORCE_INLINE -shared_vector -static_shared_vector_cast(const shared_vector& src, - typename meta::same_const::type = 0) -{ - return shared_vector(src, detail::_shared_vector_cast_tag()); -} - /** @brief Allow converting of shared_vector between types * * Conversion utilizes castUnsafe(). diff --git a/testApp/misc/testSharedVector.cpp b/testApp/misc/testSharedVector.cpp index 414e28a..d12ce85 100644 --- a/testApp/misc/testSharedVector.cpp +++ b/testApp/misc/testSharedVector.cpp @@ -360,17 +360,36 @@ static void testVoid() epics::pvData::shared_vector typed(4); - epics::pvData::shared_vector untyped2(epics::pvData::static_shared_vector_cast(typed)); + epics::pvData::shared_vector untyped(epics::pvData::static_shared_vector_cast(typed)); - testOk1(typed.dataPtr().get()==untyped2.dataPtr().get()); - testOk1(typed.size()*sizeof(int)==untyped2.size()); + testOk1(typed.dataPtr().get()==untyped.dataPtr().get()); + testOk1(typed.size()*sizeof(int)==untyped.size()); - untyped2.slice(sizeof(int), 2*sizeof(int)); + untyped.slice(sizeof(int), 2*sizeof(int)); - typed = epics::pvData::static_shared_vector_cast(untyped2); + typed = epics::pvData::static_shared_vector_cast(untyped); testOk1(typed.dataOffset()==1); testOk1(typed.size()==2); + untyped.clear(); + + testDiag("Test vector cast to/from const void"); + + epics::pvData::shared_vector ctyped(4); + + epics::pvData::shared_vector cuntyped(epics::pvData::static_shared_vector_cast(ctyped)); + // case const void to const void + epics::pvData::shared_vector cuntyped2(epics::pvData::static_shared_vector_cast(cuntyped)); + + testOk1(ctyped.dataPtr().get()==cuntyped2.dataPtr().get()); + testOk1(ctyped.size()*sizeof(int)==cuntyped2.size()); + + cuntyped2.slice(sizeof(int), 2*sizeof(int)); + + ctyped = epics::pvData::static_shared_vector_cast(cuntyped2); + + testOk1(ctyped.dataOffset()==1); + testOk1(ctyped.size()==2); } struct dummyStruct {}; @@ -539,7 +558,7 @@ static void testICE() MAIN(testSharedVector) { - testPlan(163); + testPlan(167); testDiag("Tests for shared_vector"); testDiag("sizeof(shared_vector)=%lu", diff --git a/testApp/pv/testPVScalarArray.cpp b/testApp/pv/testPVScalarArray.cpp index 084266e..7085f67 100644 --- a/testApp/pv/testPVScalarArray.cpp +++ b/testApp/pv/testPVScalarArray.cpp @@ -177,11 +177,32 @@ static void testShare() testOk1(!cdata.unique()); } +static void testVoid() +{ + testDiag("Check PVScalarArray put/get from void"); + + PVIntArrayPtr iarr = static_pointer_cast(getPVDataCreate()->createPVScalarArray(pvInt)); + + PVIntArray::const_svector idata(4, 1); + iarr->PVScalarArray::putFrom(idata); + idata.clear(); + + shared_vector cvbuf; + iarr->PVScalarArray::getAs(cvbuf); + + idata = static_shared_vector_cast(cvbuf); + testOk1(idata.size()==4); + + iarr->PVScalarArray::putFrom(cvbuf); + + testOk1(iarr->getLength()==4); +} + } // end namespace MAIN(testPVScalarArray) { - testPlan(156); + testPlan(158); testFactory(); testBasic(); testBasic(); @@ -189,5 +210,6 @@ MAIN(testPVScalarArray) testBasic(); testBasic(); testShare(); + testVoid(); return testDone(); }