diff --git a/pvDataApp/Makefile b/pvDataApp/Makefile index c496310..88e54e7 100644 --- a/pvDataApp/Makefile +++ b/pvDataApp/Makefile @@ -38,6 +38,7 @@ LIBSRCS += timer.cpp LIBSRCS += status.cpp LIBSRCS += messageQueue.cpp LIBSRCS += localStaticLock.cpp +LIBSRCS += typeCast.cpp LIBSRCS += parseToPOD.cpp SRC_DIRS += $(PVDATA)/pv diff --git a/pvDataApp/misc/typeCast.cpp b/pvDataApp/misc/typeCast.cpp new file mode 100644 index 0000000..6b5ba2a --- /dev/null +++ b/pvDataApp/misc/typeCast.cpp @@ -0,0 +1,230 @@ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/* Author: Michael Davidsaver */ +#include + +#include "typeCast.h" + +using epics::pvData::castUnsafe; +using epics::pvData::String; +using epics::pvData::ScalarType; +using epics::pvData::pvString; + +namespace { + +static void noconvert(size_t, void*, const void*) +{ + throw std::runtime_error("castUnsafeV: Conversion not supported"); +} + +template +static void castVTyped(size_t count, void *draw, const void *sraw) +{ + TO *dest=(TO*)draw; + const FROM *src=(FROM*)sraw; + std::transform(src, src+count, dest, castUnsafe); +} + +template +static void copyV(size_t count, void *draw, const void *sraw) +{ + T *dest=(T*)draw; + const T *src=(T*)sraw; + std::copy(src, src+count, dest); +} + +typedef void (*convertfn)(size_t, void*, const void*); + +/* lookup table of converter functions. + * first dimension is TO, second is FROM + */ +static convertfn converters[pvString+1][pvString+1] = +{ + // to pvBoolean + { &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert + }, + // to pvByte + {&noconvert, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvShort + {&noconvert, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvInt + {&noconvert, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvLong + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvUByte + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvUShort + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvUInt + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvULong + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvFloat + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + }, + // to pvDouble + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + }, + // to pvString + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + }, +}; + +} // end namespace + +namespace epics { namespace pvData { + +void castUnsafeV(size_t count, ScalarType to, void *dest, ScalarType from, const void *src) +{ + unsigned int ito=to, ifrom=from; + + if(ito>pvString || ifrom>pvString) + throw std::runtime_error("castUnsafeV: Invalid types"); + + converters[ito][ifrom](count, dest, src); +} + +}} diff --git a/pvDataApp/misc/typeCast.h b/pvDataApp/misc/typeCast.h index b49fcb8..e27c585 100644 --- a/pvDataApp/misc/typeCast.h +++ b/pvDataApp/misc/typeCast.h @@ -13,6 +13,7 @@ #include #include +#include // gently nudge the compiler to inline our wrappers #if defined(__GNUC__) && __GNUC__>=3 @@ -170,6 +171,8 @@ static FORCE_INLINE TO castUnsafe(const FROM& from) return detail::cast_helper::op(from); } +void castUnsafeV(size_t count, ScalarType to, void *dest, ScalarType from, const void *src); + }} // end namespace #undef FORCE_INLINE diff --git a/testApp/misc/testTypeCast.cpp b/testApp/misc/testTypeCast.cpp index 376da1c..d258edc 100644 --- a/testApp/misc/testTypeCast.cpp +++ b/testApp/misc/testTypeCast.cpp @@ -384,8 +384,22 @@ int main(int argc,char *argv[]) TEST(float, FLT_MIN, double, 1e-300); TEST(float, -FLT_MIN, double, -1e-300); xfloat = ::epics::pvData::castUnsafe(epicsNAN); - *out << "Cast double NAN to float NAN yields: "< String\n"; + epics::pvData::castUnsafeV(3, epics::pvData::pvString, (void*)result, + epics::pvData::pvInt, (void*)in); + *out << "Yields "<