From 8093c25b72d1030ef26d10ed8d0e8219dc39a21c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 8 Apr 2018 14:46:59 -0700 Subject: [PATCH] typeCast.h: allow cast from C string to numeric w/o copy also re-enable compile test of string to int64 which was disabled for some reason... --- src/misc/parseToPOD.cpp | 32 +++++++++++----------- src/misc/pv/typeCast.h | 51 ++++++++++++++++++++++++++--------- testApp/misc/testTypeCast.cpp | 22 ++++++++++++--- 3 files changed, 74 insertions(+), 31 deletions(-) diff --git a/src/misc/parseToPOD.cpp b/src/misc/parseToPOD.cpp index 35a38d7..74afdcf 100644 --- a/src/misc/parseToPOD.cpp +++ b/src/misc/parseToPOD.cpp @@ -507,20 +507,20 @@ void handleParseError(int err) namespace epics { namespace pvData { namespace detail { -void parseToPOD(const string & in, boolean *out) +void parseToPOD(const char* in, boolean *out) { - if(epicsStrCaseCmp(in.c_str(),"true")==0) + if(epicsStrCaseCmp(in,"true")==0) *out = 1; - else if(epicsStrCaseCmp(in.c_str(),"false")==0) + else if(epicsStrCaseCmp(in,"false")==0) *out = 0; else throw std::runtime_error("parseToPOD: string no match true/false"); } #define INTFN(T, S) \ -void parseToPOD(const string& in, T *out) { \ +void parseToPOD(const char* in, T *out) { \ epics ## S temp; \ - int err = epicsParse ## S (in.c_str(), &temp, 0, NULL); \ + int err = epicsParse ## S (in, &temp, 0, NULL); \ if(err) handleParseError(err); \ else *out = temp; \ } @@ -532,31 +532,31 @@ INTFN(uint16_t, UInt16); INTFN(int32_t, Int32); INTFN(uint32_t, UInt32); -void parseToPOD(const string& in, int64_t *out) { +void parseToPOD(const char* in, int64_t *out) { #ifdef NEED_LONGLONG - int err = epicsParseLongLong(in.c_str(), out, 0, NULL); + int err = epicsParseLongLong(in, out, 0, NULL); #else - int err = epicsParseLong(in.c_str(), out, 0, NULL); + int err = epicsParseLong(in, out, 0, NULL); #endif if(err) handleParseError(err); } -void parseToPOD(const string& in, uint64_t *out) { +void parseToPOD(const char* in, uint64_t *out) { #ifdef NEED_LONGLONG - int err = epicsParseULongLong(in.c_str(), out, 0, NULL); + int err = epicsParseULongLong(in, out, 0, NULL); #else - int err = epicsParseULong(in.c_str(), out, 0, NULL); + int err = epicsParseULong(in, out, 0, NULL); #endif if(err) handleParseError(err); } -void parseToPOD(const string& in, float *out) { - int err = epicsParseFloat(in.c_str(), out, NULL); +void parseToPOD(const char* in, float *out) { + int err = epicsParseFloat(in, out, NULL); if(err) handleParseError(err); } -void parseToPOD(const string& in, double *out) { - int err = epicsParseDouble(in.c_str(), out, NULL); +void parseToPOD(const char* in, double *out) { + int err = epicsParseDouble(in, out, NULL); if(err) handleParseError(err); #if defined(vxWorks) /* vxWorks strtod returns [-]epicsINF when it should return ERANGE error. @@ -564,7 +564,7 @@ void parseToPOD(const string& in, double *out) { * this into an ERANGE error */ else if (*out == epicsINF || *out == -epicsINF) { - const char* s = in.c_str(); + const char* s = in; int c; /* skip spaces and the sign */ diff --git a/src/misc/pv/typeCast.h b/src/misc/pv/typeCast.h index 10d9287..cc31ca6 100644 --- a/src/misc/pv/typeCast.h +++ b/src/misc/pv/typeCast.h @@ -22,17 +22,29 @@ namespace epics { namespace pvData { 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); + epicsShareExtern void parseToPOD(const char*, boolean *out); + epicsShareExtern void parseToPOD(const char*, int8 *out); + epicsShareExtern void parseToPOD(const char*, uint8 *out); + epicsShareExtern void parseToPOD(const char*, int16_t *out); + epicsShareExtern void parseToPOD(const char*, uint16_t *out); + epicsShareExtern void parseToPOD(const char*, int32_t *out); + epicsShareExtern void parseToPOD(const char*, uint32_t *out); + epicsShareExtern void parseToPOD(const char*, int64_t *out); + epicsShareExtern void parseToPOD(const char*, uint64_t *out); + epicsShareExtern void parseToPOD(const char*, float *out); + epicsShareExtern void parseToPOD(const char*, double *out); + + static inline void parseToPOD(const std::string& str, boolean *out) { return parseToPOD(str.c_str(), out); } + static inline void parseToPOD(const std::string& str, int8 *out) { return parseToPOD(str.c_str(), out); } + static inline void parseToPOD(const std::string& str, uint8 *out) { return parseToPOD(str.c_str(), out); } + static inline void parseToPOD(const std::string& str, int16_t *out) { return parseToPOD(str.c_str(), out); } + static inline void parseToPOD(const std::string& str, uint16_t *out) { return parseToPOD(str.c_str(), out); } + static inline void parseToPOD(const std::string& str, int32_t *out) { return parseToPOD(str.c_str(), out); } + static inline void parseToPOD(const std::string& str, uint32_t *out) { return parseToPOD(str.c_str(), out); } + static inline void parseToPOD(const std::string& str, int64_t *out) { return parseToPOD(str.c_str(), out); } + static inline void parseToPOD(const std::string& str, uint64_t *out) { return parseToPOD(str.c_str(), out); } + static inline void parseToPOD(const std::string& str, float *out) { return parseToPOD(str.c_str(), out); } + static inline void parseToPOD(const std::string& str, double *out) { return parseToPOD(str.c_str(), out); } /* want to pass POD types by value, * and std::string by const reference @@ -108,13 +120,28 @@ namespace detail { } }; + // parse POD from C string + // TO!=const char* + template + struct cast_helper, + typename meta::not_same_type + >::type> { + static FORCE_INLINE TO op(const char* 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, std::string + * float, double, std::string, const char* (only FROM) * * As defined in pvType.h * diff --git a/testApp/misc/testTypeCast.cpp b/testApp/misc/testTypeCast.cpp index 03cdb43..85b34b7 100644 --- a/testApp/misc/testTypeCast.cpp +++ b/testApp/misc/testTypeCast.cpp @@ -123,7 +123,7 @@ namespace { MAIN(testTypeCast) { - testPlan(123); + testPlan(124); try { @@ -138,10 +138,12 @@ try { float xfloat=0.0; double xdouble=0.0; string xstring("0"); + const char* xcstring = "0"; typedef float float_t; typedef double double_t; typedef string string_t; + typedef const char* cstring_t; // force all possibilities to be compiled #define CHECK(M, N) x## M = ::epics::pvData::castUnsafe(x## N); \ @@ -158,6 +160,7 @@ try { CHECK(int8, float); CHECK(int8, double); CHECK(int8, string); + CHECK(int8, cstring); CHECK(uint8, int8); CHECK(uint8, uint8); @@ -170,6 +173,7 @@ try { CHECK(uint8, float); CHECK(uint8, double); CHECK(uint8, string); + CHECK(uint8, cstring); CHECK(int16, int8); CHECK(int16, uint8); @@ -182,6 +186,7 @@ try { CHECK(int16, float); CHECK(int16, double); CHECK(int16, string); + CHECK(int16, cstring); CHECK(uint16, int8); CHECK(uint16, uint8); @@ -194,6 +199,7 @@ try { CHECK(uint16, float); CHECK(uint16, double); CHECK(uint16, string); + CHECK(uint16, cstring); CHECK(int32, int8); CHECK(int32, uint8); @@ -206,6 +212,7 @@ try { CHECK(int32, float); CHECK(int32, double); CHECK(int32, string); + CHECK(int32, cstring); CHECK(uint32, int8); CHECK(uint32, uint8); @@ -218,6 +225,7 @@ try { CHECK(uint32, float); CHECK(uint32, double); CHECK(uint32, string); + CHECK(uint32, cstring); CHECK(int64, int8); CHECK(int64, uint8); @@ -229,7 +237,8 @@ try { CHECK(int64, uint64); CHECK(int64, float); CHECK(int64, double); - //CHECK(int64, string); + CHECK(int64, string); + CHECK(int64, cstring); CHECK(uint64, int8); CHECK(uint64, uint8); @@ -241,7 +250,8 @@ try { CHECK(uint64, uint64); CHECK(uint64, float); CHECK(uint64, double); - //CHECK(uint64, string); + CHECK(uint64, string); + CHECK(uint64, cstring); CHECK(float, int8); CHECK(float, uint8); @@ -254,6 +264,7 @@ try { CHECK(float, float); CHECK(float, double); CHECK(float, string); + CHECK(float, cstring); CHECK(double, int8); CHECK(double, uint8); @@ -266,6 +277,7 @@ try { CHECK(double, float); CHECK(double, double); CHECK(double, string); + CHECK(double, cstring); CHECK(string, int8); CHECK(string, uint8); @@ -278,6 +290,9 @@ try { CHECK(string, float); CHECK(string, double); CHECK(string, string); + CHECK(string, cstring); + + // cast to const char* not supported #undef CHECK testDiag("Integer signed <=> unsigned"); @@ -344,6 +359,7 @@ try { TEST2(string, "1.1e-100", double, 1.1e-100); TEST(double, 1.1e100, string, "1.1E+100"); + TEST(double, 1.1e100, const char*, "1.1E+100"); // any non-zero value is true TEST(string, "true", epics::pvData::boolean, 100);