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:
Michael Davidsaver
2016-02-24 10:18:47 -05:00
parent 4f499aed01
commit dc94b26e50
3 changed files with 108 additions and 25 deletions

View File

@@ -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>().

View File

@@ -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",

View File

@@ -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();
}