/** * 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 */ #ifndef PVTYPECAST_H #define PVTYPECAST_H #include #include #ifdef epicsExportSharedSymbols #define typeCastepicsExportSharedSymbols #undef epicsExportSharedSymbols #endif #include #ifdef typeCastepicsExportSharedSymbols #define epicsExportSharedSymbols #undef typeCastepicsExportSharedSymbols #endif #include #include #include #include namespace epics { namespace pvData { typedef std::string String; namespace detail { // parseToPOD wraps the epicsParse*() functions in one name // and throws exceptions epicsShareExtern void parseToPOD(const std::string&, boolean *out); epicsShareExtern void parseToPOD(const std::string&, int8 *out); epicsShareExtern void parseToPOD(const std::string&, uint8 *out); epicsShareExtern void parseToPOD(const std::string&, int16_t *out); epicsShareExtern void parseToPOD(const std::string&, uint16_t *out); epicsShareExtern void parseToPOD(const std::string&, int32_t *out); epicsShareExtern void parseToPOD(const std::string&, uint32_t *out); epicsShareExtern void parseToPOD(const std::string&, int64_t *out); epicsShareExtern void parseToPOD(const std::string&, uint64_t *out); epicsShareExtern void parseToPOD(const std::string&, float *out); epicsShareExtern void parseToPOD(const std::string&, double *out); /* want to pass POD types by value, * and String by const reference */ template struct cast_arg { typedef ARG arg; }; template<> struct cast_arg { typedef const String& arg; }; // Handle mangling of type/value when printing template struct print_convolute { typedef T return_t; static FORCE_INLINE return_t op(const T& i) { return i; } }; // trick std::ostream into treating char's as numbers // by promoting char to int template<> struct print_convolute { typedef signed int return_t; static FORCE_INLINE return_t op(int8 i) { return i; } }; template<> struct print_convolute { typedef unsigned int return_t; static FORCE_INLINE return_t op(uint8 i) { return i; } }; // Turn boolean into a string template<> struct print_convolute { typedef const char* return_t; static FORCE_INLINE return_t op(boolean i) { return i ? "true" : "false"; } }; // default to C++ type casting template struct cast_helper { static FORCE_INLINE TO op(FROM from) { return static_cast(from); } }; // special handling when down-casting double to float template<> struct cast_helper { static FORCE_INLINE float op(double from) { return epicsConvertDoubleToFloat(from); } }; // print POD to string // when String!=FROM template struct cast_helper::type> { static String op(FROM from) { std::ostringstream strm; strm << print_convolute::op(from); if(strm.fail()) throw std::runtime_error("Cast to string failed"); return strm.str(); } }; // parse POD from string // TO!=String template struct cast_helper::type> { static FORCE_INLINE TO op(const String& from) { TO ret; parseToPOD(from, &ret); return ret; } }; } // end detail /** @brief Casting/converting between supported scalar types. * * Supported types: uint8_t, int8_t, uint16_t, int16_t, * uint32_t, int32_t, uint64_t, int64_t, * float, double, String * * As defined in pvType.h * @throws std::runtime_error when the cast is not possible. @throws std::bad_alloc when the cast is not possible. * @section convertg Conversion Guarantees * * Conversions which always produce a correct result. * * - signed integer -> larger signed integer * - unsigned integer -> larger unsigned integer * - integer -> float or double (where sizeof(integer) double * * Conversions where out of range inputs always produce * a defined result, but may not be reversable. * * - double -> float. When abs(value) is outside the range * [FLT_MIN, FLT_MAX] the value is clipped to FLT_MIN or FLT_MAX * with the sign preserved. * * Conversions where invalid or out of range inputs result * in an exception. * * - non-String -> String * - String -> non-String * - String -> String (throws only std::bad_alloc) * * Conversions where out of range inputs produce undefined * results. * * - signed integer -> smaller signed integer * - unsigned integer -> smaller unsigned integer * - signed integer <-> unsigned integer * - integer -> float or double (where sizeof(integer)>=sizeof(floating)) * - float or double -> integer. The floating point value * is rounded towards zero. However, the result for values * too large to be represented by the integer type * is not defined. * @section stringf String formats * * - Numbers beginning with 1-9 are parsed as base-10. * - Numbers beginning with '0x' are parsed as base-16 * - Numbers beginning with '0' are parsed as base-8. * - Hex numbers are case insensitive. * - Exponential numbers may use either 'e' or 'E'. */ template static FORCE_INLINE TO castUnsafe(const FROM& from) { return detail::cast_helper::op(from); } epicsShareExtern void castUnsafeV(size_t count, ScalarType to, void *dest, ScalarType from, const void *src); //! Cast value to printable type //! A no-op except for int8 and uint8, which are cast to int //! so that they are printed as numbers std::ostream operators, //! and boolean which is transformed into a const char* template static FORCE_INLINE typename detail::print_convolute::return_t print_cast(const T& v) { return detail::print_convolute::op(v); } }} // end namespace #endif // PVTYPECAST_H