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<const void>.
This commit is contained in:
@@ -326,7 +326,7 @@ public:
|
||||
//! Internal for static_shared_vector_cast
|
||||
template<typename FROM>
|
||||
shared_vector(const shared_vector<FROM> &src,
|
||||
typename meta::is_void<FROM, detail::_shared_vector_cast_tag>::type)
|
||||
detail::_shared_vector_cast_tag)
|
||||
:base_t(std::tr1::static_pointer_cast<E>(src.dataPtr()),
|
||||
src.dataOffset()/sizeof(E),
|
||||
src.dataCount()/sizeof(E))
|
||||
@@ -566,7 +566,7 @@ public:
|
||||
//! Internal for static_shared_vector_cast
|
||||
template<typename FROM>
|
||||
shared_vector(const shared_vector<FROM> &src,
|
||||
typename meta::is_not_void<FROM, detail::_shared_vector_cast_tag>::type)
|
||||
detail::_shared_vector_cast_tag)
|
||||
:base_t(std::tr1::static_pointer_cast<E>(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<typename TO, typename FROM, class Enable = void>
|
||||
struct static_shared_vector_caster { /* no default */ };
|
||||
// from void to non-void with same const-ness
|
||||
template<typename TO>
|
||||
struct static_shared_vector_caster<TO, void,
|
||||
typename meta::_and<meta::same_const<TO,void>, meta::is_not_void<TO> >::type> {
|
||||
static inline shared_vector<TO> op(const shared_vector<void>& src) {
|
||||
return shared_vector<TO>(src, detail::_shared_vector_cast_tag());
|
||||
}
|
||||
};
|
||||
template<typename TO>
|
||||
struct static_shared_vector_caster<TO, const void,
|
||||
typename meta::_and<meta::same_const<TO,const void>, meta::is_not_void<TO> >::type> {
|
||||
static inline shared_vector<TO> op(const shared_vector<const void>& src) {
|
||||
return shared_vector<TO>(src, detail::_shared_vector_cast_tag());
|
||||
}
|
||||
};
|
||||
// from non-void to void with same const-ness
|
||||
template<typename FROM>
|
||||
struct static_shared_vector_caster<void, FROM,
|
||||
typename meta::_and<meta::same_const<void,FROM>, meta::is_not_void<FROM> >::type> {
|
||||
static FORCE_INLINE shared_vector<void> op(const shared_vector<FROM>& src) {
|
||||
return shared_vector<void>(src, detail::_shared_vector_cast_tag());
|
||||
}
|
||||
};
|
||||
template<typename FROM>
|
||||
struct static_shared_vector_caster<const void, FROM,
|
||||
typename meta::_and<meta::same_const<const void,FROM>, meta::is_not_void<FROM> >::type> {
|
||||
static FORCE_INLINE shared_vector<const void> op(const shared_vector<FROM>& src) {
|
||||
return shared_vector<const void>(src, detail::_shared_vector_cast_tag());
|
||||
}
|
||||
};
|
||||
|
||||
// cast to same type, no-op
|
||||
template<typename TOFRO>
|
||||
struct static_shared_vector_caster<TOFRO,TOFRO,void> {
|
||||
static FORCE_INLINE const shared_vector<TOFRO>& op(const shared_vector<TOFRO>& 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<typename TO, typename FROM>
|
||||
static FORCE_INLINE
|
||||
shared_vector<TO>
|
||||
static_shared_vector_cast(const shared_vector<FROM>& src)
|
||||
{
|
||||
return detail::static_shared_vector_caster<TO,FROM>::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<typename TO, typename FROM>
|
||||
static FORCE_INLINE
|
||||
shared_vector<TO>
|
||||
static_shared_vector_cast(const shared_vector<FROM>& src,
|
||||
typename meta::same_const<TO,FROM,int>::type = 0)
|
||||
{
|
||||
return shared_vector<TO>(src, detail::_shared_vector_cast_tag());
|
||||
}
|
||||
|
||||
/** @brief Allow converting of shared_vector between types
|
||||
*
|
||||
* Conversion utilizes castUnsafe<TO,FROM>().
|
||||
|
||||
@@ -360,17 +360,36 @@ static void testVoid()
|
||||
|
||||
epics::pvData::shared_vector<int32> typed(4);
|
||||
|
||||
epics::pvData::shared_vector<void> untyped2(epics::pvData::static_shared_vector_cast<void>(typed));
|
||||
epics::pvData::shared_vector<void> untyped(epics::pvData::static_shared_vector_cast<void>(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<int32>(untyped2);
|
||||
typed = epics::pvData::static_shared_vector_cast<int32>(untyped);
|
||||
|
||||
testOk1(typed.dataOffset()==1);
|
||||
testOk1(typed.size()==2);
|
||||
untyped.clear();
|
||||
|
||||
testDiag("Test vector cast to/from const void");
|
||||
|
||||
epics::pvData::shared_vector<const int32> ctyped(4);
|
||||
|
||||
epics::pvData::shared_vector<const void> cuntyped(epics::pvData::static_shared_vector_cast<const void>(ctyped));
|
||||
// case const void to const void
|
||||
epics::pvData::shared_vector<const void> cuntyped2(epics::pvData::static_shared_vector_cast<const void>(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<const int32>(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<int32>)=%lu",
|
||||
|
||||
@@ -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<PVIntArray>(getPVDataCreate()->createPVScalarArray(pvInt));
|
||||
|
||||
PVIntArray::const_svector idata(4, 1);
|
||||
iarr->PVScalarArray::putFrom(idata);
|
||||
idata.clear();
|
||||
|
||||
shared_vector<const void> cvbuf;
|
||||
iarr->PVScalarArray::getAs(cvbuf);
|
||||
|
||||
idata = static_shared_vector_cast<const PVIntArray::value_type>(cvbuf);
|
||||
testOk1(idata.size()==4);
|
||||
|
||||
iarr->PVScalarArray::putFrom(cvbuf);
|
||||
|
||||
testOk1(iarr->getLength()==4);
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
MAIN(testPVScalarArray)
|
||||
{
|
||||
testPlan(156);
|
||||
testPlan(158);
|
||||
testFactory();
|
||||
testBasic<PVByteArray>();
|
||||
testBasic<PVUByteArray>();
|
||||
@@ -189,5 +210,6 @@ MAIN(testPVScalarArray)
|
||||
testBasic<PVDoubleArray>();
|
||||
testBasic<PVStringArray>();
|
||||
testShare();
|
||||
testVoid();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user