diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 718c1ce..d1442f4 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -10,6 +10,7 @@ #include "pv/sharedPtr.h" #include "pv/pvIntrospect.h" +#include "pv/typeCast.h" #include "pv/templateMeta.h" namespace epics { namespace pvData { @@ -540,27 +541,96 @@ public: }; namespace detail { - template struct shared_vector_caster {}; + template + struct shared_vector_caster {}; - template - struct shared_vector_caster { - static inline shared_vector op(const shared_vector& src) { - return shared_vector( - std::tr1::static_pointer_cast(src.dataPtr()), + // Cast from non-void to 'void' or 'const void' + template + struct shared_vector_caster, meta::is_not_void >::type + > + { + static inline shared_vector op(const shared_vector& src) { + return shared_vector( + std::tr1::static_pointer_cast(src.dataPtr()), src.dataOffset()*sizeof(FROM), - src.dataCount()*sizeof(FROM)); + src.dataCount()*sizeof(FROM)) + .set_original_type((ScalarType)ScalarTypeID::value); } }; - template - struct shared_vector_caster { - static inline shared_vector op(const shared_vector& src) { + // Cast from 'void' or 'const void' to non-void + template + struct shared_vector_caster, meta::is_void >::type + > + { + static inline shared_vector op(const shared_vector& src) { return shared_vector( std::tr1::static_pointer_cast(src.dataPtr()), src.dataOffset()/sizeof(TO), src.dataCount()/sizeof(TO)); } }; + + + // Default to type conversion using castUnsafe (C++ type casting) on each element + template + struct shared_vector_converter { + static inline shared_vector op(const shared_vector& src) + { + shared_vector ret(src.size()); + std::transform(src.begin(), src.end(), ret.begin(), castUnsafe); + return ret; + } + }; + + // copy reference when types are the same (excluding const qualifiers) + template + struct shared_vector_converter::type > { + static FORCE_INLINE shared_vector op(const shared_vector& src) { + return src; + } + }; + + // "convert" to 'void' or 'const void from non-void + // is an alias for shared_vector_cast() + template + struct shared_vector_converter, meta::is_not_void >::type + > + { + static FORCE_INLINE shared_vector op(const shared_vector& src) { + return shared_vector_caster::op(src); + } + }; + + // convert from void uses original type or throws an exception. + template + struct shared_vector_converter, meta::is_void >::type + > + { + static shared_vector op(const shared_vector& src) { + typedef typename meta::strip_const::type to_t; + ScalarType stype = src.original_type(), + dtype = (ScalarType)ScalarTypeID::value; + if(stype==dtype) { + // no convert needed + return shared_vector_caster::op(src); + } else { + // alloc and convert + shared_vector ret(src.size()/ScalarTypeFunc::elementSize(stype)); + castUnsafeV(ret.size(), + (ScalarType)ScalarTypeID::value, + static_cast(ret.data()), + stype, + static_cast(src.data())); + return ret; + } + } + }; + } /** @brief Allow casting of shared_vector between types @@ -578,6 +648,23 @@ static_shared_vector_cast(const shared_vector& src) return detail::shared_vector_caster::op(src); } +/** @brief Allow converting of shared_vector between types + * + * Conversion utilizes castUnsafe(). + * + * Converting to/from void is supported. Convert to void + * is an alias for static_shared_vector_cast(). + * Convert from void utilizes shared_vector::original_type() + * and throws std::runtime_error if this is not valid. + */ +template +static inline +shared_vector +shared_vector_convert(const shared_vector& src) +{ + return detail::shared_vector_converter::op(src); +} + //! Allows casting from const TYPE -> TYPE. template static inline