caseUnsafeV use switch instead of jump table

Change from jump table to switch.
reduces code size (~1k of 30k for rtems/mvme3100).
use indexed loop to help gcc vectorizer.

Helpfully won't fail to compile w/ gcc 4.1 (vxworks 6.6/6.7)
This commit is contained in:
Michael Davidsaver
2017-11-28 14:13:20 -06:00
parent cf624bc679
commit 6465ab3b6d

View File

@@ -6,6 +6,8 @@
#include <algorithm>
#include <sstream>
#include <string.h>
#include <epicsConvert.h>
#define epicsExportSharedSymbols
@@ -18,7 +20,7 @@ using std::string;
namespace {
static void noconvert(size_t, void*, const void*)
static void noconvert()
{
throw std::runtime_error("castUnsafeV: Conversion not supported");
}
@@ -31,12 +33,10 @@ static void castVTyped(size_t count, void *draw, const void *sraw)
//std::transform(src, src+count, dest, castUnsafe<TO,FROM>);
const FROM *last = src+count;
try {
while (src != last) {
*dest = castUnsafe<TO,FROM>(*src);
++dest; ++src;
}
for(size_t i=0; i<count; i++) {
dest[i] = castUnsafe<TO,FROM>(src[i]);
}
} catch (std::exception& ex) {
// do not report index for scalars (or arrays with one element)
if (count > 1)
@@ -59,182 +59,11 @@ static void copyV(size_t count, void *draw, const void *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] =
template<int N>
static void copyMem(size_t count, void *draw, const void *sraw)
{
// to pvBoolean
{ &copyV<epics::pvData::boolean>,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&castVTyped<epics::pvData::boolean, string>,
},
// to pvByte
{&noconvert,
&copyV<int8_t>,
&castVTyped<int8_t, int16_t>,
&castVTyped<int8_t, int32_t>,
&castVTyped<int8_t, int64_t>,
&castVTyped<int8_t, uint8_t>,
&castVTyped<int8_t, uint16_t>,
&castVTyped<int8_t, uint32_t>,
&castVTyped<int8_t, uint64_t>,
&castVTyped<int8_t, float>,
&castVTyped<int8_t, double>,
&castVTyped<int8_t, string>,
},
// to pvShort
{&noconvert,
&castVTyped<int16_t, int8_t>,
&copyV<int16_t>,
&castVTyped<int16_t, int32_t>,
&castVTyped<int16_t, int64_t>,
&castVTyped<int16_t, uint8_t>,
&castVTyped<int16_t, uint16_t>,
&castVTyped<int16_t, uint32_t>,
&castVTyped<int16_t, uint64_t>,
&castVTyped<int16_t, float>,
&castVTyped<int16_t, double>,
&castVTyped<int16_t, string>,
},
// to pvInt
{&noconvert,
&castVTyped<int32_t, int8_t>,
&castVTyped<int32_t, int16_t>,
&copyV<int32_t>,
&castVTyped<int32_t, int64_t>,
&castVTyped<int32_t, uint8_t>,
&castVTyped<int32_t, uint16_t>,
&castVTyped<int32_t, uint32_t>,
&castVTyped<int32_t, uint64_t>,
&castVTyped<int32_t, float>,
&castVTyped<int32_t, double>,
&castVTyped<int32_t, string>,
},
// to pvLong
{&noconvert,
&castVTyped<int64_t, int8_t>,
&castVTyped<int64_t, int16_t>,
&castVTyped<int64_t, int32_t>,
&copyV<int64_t>,
&castVTyped<int64_t, uint8_t>,
&castVTyped<int64_t, uint16_t>,
&castVTyped<int64_t, uint32_t>,
&castVTyped<int64_t, uint64_t>,
&castVTyped<int64_t, float>,
&castVTyped<int64_t, double>,
&castVTyped<int64_t, string>,
},
// to pvUByte
{&noconvert,
&castVTyped<uint8_t, int8_t>,
&castVTyped<uint8_t, int16_t>,
&castVTyped<uint8_t, int32_t>,
&castVTyped<uint8_t, uint64_t>,
&copyV<uint8_t>,
&castVTyped<uint8_t, uint16_t>,
&castVTyped<uint8_t, uint32_t>,
&castVTyped<uint8_t, uint64_t>,
&castVTyped<uint8_t, float>,
&castVTyped<uint8_t, double>,
&castVTyped<uint8_t, string>,
},
// to pvUShort
{&noconvert,
&castVTyped<uint16_t, int8_t>,
&castVTyped<uint16_t, int16_t>,
&castVTyped<uint16_t, int32_t>,
&castVTyped<uint16_t, uint64_t>,
&castVTyped<uint16_t, uint8_t>,
&copyV<uint16_t>,
&castVTyped<uint16_t, uint32_t>,
&castVTyped<uint16_t, uint64_t>,
&castVTyped<uint16_t, float>,
&castVTyped<uint16_t, double>,
&castVTyped<uint16_t, string>,
},
// to pvUInt
{&noconvert,
&castVTyped<uint32_t, int8_t>,
&castVTyped<uint32_t, int16_t>,
&castVTyped<uint32_t, int32_t>,
&castVTyped<uint32_t, uint64_t>,
&castVTyped<uint32_t, uint8_t>,
&castVTyped<uint32_t, uint16_t>,
&copyV<uint32_t>,
&castVTyped<uint32_t, uint64_t>,
&castVTyped<uint32_t, float>,
&castVTyped<uint32_t, double>,
&castVTyped<uint32_t, string>,
},
// to pvULong
{&noconvert,
&castVTyped<uint64_t, int8_t>,
&castVTyped<uint64_t, int16_t>,
&castVTyped<uint64_t, int32_t>,
&castVTyped<uint64_t, uint64_t>,
&castVTyped<uint64_t, uint8_t>,
&castVTyped<uint64_t, uint16_t>,
&castVTyped<uint64_t, uint32_t>,
&copyV<uint64_t>,
&castVTyped<uint64_t, float>,
&castVTyped<uint64_t, double>,
&castVTyped<uint64_t, string>,
},
// to pvFloat
{&noconvert,
&castVTyped<float, int8_t>,
&castVTyped<float, int16_t>,
&castVTyped<float, int32_t>,
&castVTyped<float, uint64_t>,
&castVTyped<float, uint8_t>,
&castVTyped<float, uint16_t>,
&castVTyped<float, uint32_t>,
&castVTyped<float, uint64_t>,
&copyV<float>,
&castVTyped<float, double>,
&castVTyped<float, string>,
},
// to pvDouble
{&noconvert,
&castVTyped<double, int8_t>,
&castVTyped<double, int16_t>,
&castVTyped<double, int32_t>,
&castVTyped<double, uint64_t>,
&castVTyped<double, uint8_t>,
&castVTyped<double, uint16_t>,
&castVTyped<double, uint32_t>,
&castVTyped<double, uint64_t>,
&castVTyped<double, float>,
&copyV<double>,
&castVTyped<double, string>,
},
// to pvString
{&castVTyped<string, epics::pvData::boolean>,
&castVTyped<string, int8_t>,
&castVTyped<string, int16_t>,
&castVTyped<string, int32_t>,
&castVTyped<string, uint64_t>,
&castVTyped<string, uint8_t>,
&castVTyped<string, uint16_t>,
&castVTyped<string, uint32_t>,
&castVTyped<string, uint64_t>,
&castVTyped<string, float>,
&castVTyped<string, double>,
&copyV<string>,
},
};
memcpy(draw, sraw, count*N);
}
} // end namespace
@@ -242,12 +71,207 @@ namespace epics { namespace pvData {
void castUnsafeV(size_t count, ScalarType to, void *dest, ScalarType from, const void *src)
{
unsigned int ito=to, ifrom=from;
#define COPYMEM(N) copyMem<N>(count, dest, src)
#define CAST(TO, FROM) castVTyped<TO, FROM>(count, dest, src)
if(ito>pvString || ifrom>pvString)
throw std::runtime_error("castUnsafeV: Invalid types");
switch(to) {
case pvBoolean:
switch(from) {
case pvBoolean: COPYMEM(1); return;
case pvString: CAST(boolean, std::string); return;
default: noconvert(); return;
}
break;
converters[ito][ifrom](count, dest, src);
case pvByte:
switch(from) {
case pvBoolean: noconvert(); return;
case pvByte:
case pvUByte: COPYMEM(1); return;
case pvShort: CAST(int8, int16); return;
case pvUShort: CAST(int8, uint16); return;
case pvInt: CAST(int8, int32); return;
case pvUInt: CAST(int8, uint32); return;
case pvLong: CAST(int8, int64); return;
case pvULong: CAST(int8, uint64); return;
case pvFloat: CAST(int8, float); return;
case pvDouble: CAST(int8, double); return;
case pvString: CAST(int8, std::string); return;
}
break;
case pvUByte:
switch(from) {
case pvBoolean: noconvert(); return;
case pvByte:
case pvUByte: COPYMEM(1); return;
case pvShort: CAST(uint8, int16); return;
case pvUShort: CAST(uint8, uint16); return;
case pvInt: CAST(uint8, int32); return;
case pvUInt: CAST(uint8, uint32); return;
case pvLong: CAST(uint8, int64); return;
case pvULong: CAST(uint8, uint64); return;
case pvFloat: CAST(uint8, float); return;
case pvDouble: CAST(uint8, double); return;
case pvString: CAST(uint8, std::string); return;
}
break;
case pvShort:
switch(from) {
case pvBoolean: noconvert(); return;
case pvByte: CAST(int16, int8); return;
case pvUByte: CAST(int16, uint8); return;
case pvShort:
case pvUShort: COPYMEM(2); return;
case pvInt: CAST(int16, int32); return;
case pvUInt: CAST(int16, uint32); return;
case pvLong: CAST(int16, int64); return;
case pvULong: CAST(int16, uint64); return;
case pvFloat: CAST(int16, float); return;
case pvDouble: CAST(int16, double); return;
case pvString: CAST(int16, std::string); return;
}
break;
case pvUShort:
switch(from) {
case pvBoolean: noconvert(); return;
case pvByte: CAST(uint16, int8); return;
case pvUByte: CAST(uint16, uint8); return;
case pvShort:
case pvUShort: COPYMEM(2); return;
case pvInt: CAST(uint16, int32); return;
case pvUInt: CAST(uint16, uint32); return;
case pvLong: CAST(uint16, int64); return;
case pvULong: CAST(uint16, uint64); return;
case pvFloat: CAST(uint16, float); return;
case pvDouble: CAST(uint16, double); return;
case pvString: CAST(uint16, std::string); return;
}
break;
case pvInt:
switch(from) {
case pvBoolean: noconvert(); return;
case pvByte: CAST(int32, int8); return;
case pvUByte: CAST(int32, uint8); return;
case pvShort: CAST(int32, int16); return;
case pvUShort: CAST(int32, uint16); return;
case pvInt:
case pvUInt: COPYMEM(4); return;
case pvLong: CAST(int32, int64); return;
case pvULong: CAST(int32, uint64); return;
case pvFloat: CAST(int32, float); return;
case pvDouble: CAST(int32, double); return;
case pvString: CAST(int32, std::string); return;
}
break;
case pvUInt:
switch(from) {
case pvBoolean: noconvert(); return;
case pvByte: CAST(uint32, int8); return;
case pvUByte: CAST(uint32, uint8); return;
case pvShort: CAST(uint32, int16); return;
case pvUShort: CAST(uint32, uint16); return;
case pvInt:
case pvUInt: COPYMEM(4); return;
case pvLong: CAST(uint32, int64); return;
case pvULong: CAST(uint32, uint64); return;
case pvFloat: CAST(uint32, float); return;
case pvDouble: CAST(uint32, double); return;
case pvString: CAST(uint32, std::string); return;
}
break;
case pvLong:
switch(from) {
case pvBoolean: noconvert(); return;
case pvByte: CAST(int64, int8); return;
case pvUByte: CAST(int64, uint8); return;
case pvShort: CAST(int64, int16); return;
case pvUShort: CAST(int64, uint16); return;
case pvInt: CAST(int64, int32); return;
case pvUInt: CAST(int64, uint32); return;
case pvLong:
case pvULong: COPYMEM(8); return;
case pvFloat: CAST(int64, float); return;
case pvDouble: CAST(int64, double); return;
case pvString: CAST(int64, std::string); return;
}
break;
case pvULong:
switch(from) {
case pvBoolean: noconvert(); return;
case pvByte: CAST(uint64, int8); return;
case pvUByte: CAST(uint64, uint8); return;
case pvShort: CAST(uint64, int16); return;
case pvUShort: CAST(uint64, uint16); return;
case pvInt: CAST(uint64, int32); return;
case pvUInt: CAST(uint64, uint32); return;
case pvLong:
case pvULong: COPYMEM(8); return;
case pvFloat: CAST(uint64, float); return;
case pvDouble: CAST(uint64, double); return;
case pvString: CAST(uint64, std::string); return;
}
break;
case pvFloat:
switch(from) {
case pvBoolean: noconvert(); return;
case pvByte: CAST(float, int8); return;
case pvUByte: CAST(float, uint8); return;
case pvShort: CAST(float, int16); return;
case pvUShort: CAST(float, uint16); return;
case pvInt: CAST(float, int32); return;
case pvUInt: CAST(float, uint32); return;
case pvLong: CAST(float, int64); return;
case pvULong: CAST(float, uint64); return;
case pvFloat: COPYMEM(4); return;
case pvDouble: CAST(float, double); return;
case pvString: CAST(float, std::string); return;
}
break;
case pvDouble:
switch(from) {
case pvBoolean: noconvert(); return;
case pvByte: CAST(double, int8); return;
case pvUByte: CAST(double, uint8); return;
case pvShort: CAST(double, int16); return;
case pvUShort: CAST(double, uint16); return;
case pvInt: CAST(double, int32); return;
case pvUInt: CAST(double, uint32); return;
case pvLong: CAST(double, int64); return;
case pvULong: CAST(double, uint64); return;
case pvFloat: CAST(double, float); return;
case pvDouble: COPYMEM(8); return;
case pvString: CAST(double, std::string); return;
}
break;
case pvString:
switch(from) {
case pvBoolean: CAST(std::string, boolean); return;
case pvByte: CAST(std::string, int8); return;
case pvUByte: CAST(std::string, uint8); return;
case pvShort: CAST(std::string, int16); return;
case pvUShort: CAST(std::string, uint16); return;
case pvInt: CAST(std::string, int32); return;
case pvUInt: CAST(std::string, uint32); return;
case pvLong: CAST(std::string, int64); return;
case pvULong: CAST(std::string, uint64); return;
case pvFloat: CAST(std::string, float); return;
case pvDouble: CAST(std::string, double); return;
case pvString: copyV<std::string>(count, dest, src); return;
}
break;
}
THROW_EXCEPTION2(std::logic_error, "Undefined cast");
}
}}