add array convert

This commit is contained in:
Michael Davidsaver
2020-03-27 13:50:42 -07:00
parent ac1c987d3f
commit da0c73b1fa
3 changed files with 422 additions and 1 deletions
+1 -1
View File
@@ -105,7 +105,7 @@ struct StoreTransform<shared_array<const E>> {
}
static inline
shared_array<const E> out(const shared_array<const void>& v) {
return v.template castTo<const E>();
return v.template convertTo<const E>();
}
};
+47
View File
@@ -41,6 +41,11 @@ enum class ArrayType : uint8_t {
PVXS_API
std::ostream& operator<<(std::ostream& strm, ArrayType code);
//! Return storage size (aka. sizeof() ) for array element type
//! @throws std::logic_error for invalid types.
PVXS_API
size_t elementSize(ArrayType type);
namespace detail {
template<typename T>
struct CaptureCode;
@@ -192,6 +197,14 @@ std::ostream& operator<<(std::ostream& strm, const Limiter&);
PVXS_API
void _throw_bad_cast(ArrayType from, ArrayType to);
PVXS_API
void convertArr(ArrayType dtype, void *dbase,
ArrayType stype, const void *sbase,
size_t count);
PVXS_API
shared_array<void> copyAs(ArrayType dtype, ArrayType stype, const void *sbase, size_t count);
} // namespace detail
/** std::vector-like contigious array of items passed by reference.
@@ -438,6 +451,20 @@ public:
return shared_array<TO>(this->_data, this->_data.get(), this->_count); // implied cast to void*
}
template<typename TO, typename std::enable_if<!std::is_void<TO>{} && (std::is_const<E>{} == std::is_const<TO>{}), int>::type =0>
shared_array<TO>
convertTo() const {
if(detail::CaptureBase<TO>::code==detail::CaptureBase<E>::code) {
return castTo<TO>();
} else {
shared_array<TO> ret(this->_count);
detail::convertArr(detail::CaptureBase<TO>::code, (void*)ret._data.get(),
detail::CaptureBase<E>::code, this->_data.get(),
this->_count);
return ret;
}
}
//! Provide options when rendering with std::ostream.
detail::Limiter format() const {
return detail::Limiter(this->_data.get(),
@@ -586,6 +613,26 @@ public:
return *this;
}
template<typename TO, typename std::enable_if<!std::is_void<TO>{} && (std::is_const<E>{} == std::is_const<TO>{}), int>::type =0>
shared_array<TO>
convertTo() const {
if(detail::CaptureBase<TO>::code==_type) {
return castTo<TO>();
} else {
shared_array<TO> ret(this->_count);
detail::convertArr(detail::CaptureBase<TO>::code, (void*)ret._data.get(),
_type, this->_data.get(),
this->_count);
return ret;
}
}
template<typename TO, typename std::enable_if<std::is_void<TO>{} && (std::is_const<E>{} == std::is_const<TO>{}), int>::type =0>
shared_array<TO>
convertTo() const {
return castTo<TO>();
}
//! Provide options when rendering with std::ostream.
detail::Limiter format() const {
return detail::Limiter(this->_data.get(),
+374
View File
@@ -4,8 +4,12 @@
* in file LICENSE that is included with this distribution.
*/
#include <string.h>
#include <epicsStdlib.h>
#include <pvxs/sharedArray.h>
#include <pvxs/data.h>
#include "utilpvt.h"
namespace pvxs {
@@ -34,6 +38,30 @@ std::ostream& operator<<(std::ostream& strm, ArrayType code)
return strm;
}
size_t elementSize(ArrayType type)
{
switch(type) {
#define CASE(CODE, Type) case ArrayType::CODE: return sizeof(Type)
CASE(Bool, bool);
CASE(UInt8, uint8_t);
CASE(UInt16, uint16_t);
CASE(UInt32, uint32_t);
CASE(UInt64, uint64_t);
CASE(Int8, int8_t);
CASE(Int16, int16_t);
CASE(Int32, int32_t);
CASE(Int64, int64_t);
CASE(Float32, float);
CASE(Float64, double);
CASE(String, std::string);
CASE(Value, Value);
#undef CASE
case ArrayType::Null:
break;
}
throw std::logic_error("Invalid ArrayType");
}
namespace detail {
namespace {
@@ -90,6 +118,352 @@ void _throw_bad_cast(ArrayType from, ArrayType to)
throw std::logic_error(SB()<<"Unable to cast array from "<<from<<" to "<<to);
}
namespace {
template<typename Src, typename Dest>
void convertCast(const void *sbase, void *dbase, size_t count)
{
auto S = static_cast<const Src*>(sbase);
auto D = static_cast<Dest*>(dbase);
for(auto i : range(count))
D[i] = S[i];
}
void printValue(std::string& dest, const bool& src)
{
dest = src ? "true" : "false";
}
template<typename Src>
typename std::enable_if<!std::is_same<Src, bool>{}>::type
printValue(std::string& dest, const Src& src)
{
std::ostringstream strm;
strm<<src;
// no error check, we only print POD scalar types which are unambigious
dest = strm.str();
}
template<typename Src>
void convertToStr(const void *sbase, void *dbase, size_t count)
{
auto S = static_cast<const Src*>(sbase);
auto D = static_cast<std::string*>(dbase);
for(auto i : range(count))
printValue(D[i], S[i]);
}
void parseValue(bool& dest, const std::string& src)
{
if(src=="true")
dest = true;
else if(src=="false")
dest = false;
else
throw std::runtime_error(SB()<<"Expected \"true\" or \"false\", not \""<<escape(src)<<"\"");
}
#define CASE(ETYPE, TYPE) \
void parseValue(TYPE& dest, const std::string& src) { \
epics ## ETYPE temp; \
if(epicsParse ## ETYPE(src.c_str(), &temp, 0, nullptr)) \
throw std::runtime_error(SB()<<"Expected " #TYPE ", not \""<<escape(src)<<"\""); \
dest = temp; \
}
CASE(Int8, int8_t)
CASE(Int16, int16_t)
CASE(Int32, int32_t)
CASE(Int64, int64_t)
CASE(UInt8, uint8_t)
CASE(UInt16, uint16_t)
CASE(UInt32, uint32_t)
CASE(UInt64, uint64_t)
#undef CASE
#define CASE(ETYPE, TYPE) \
void parseValue(TYPE& dest, const std::string& src) { \
epics ## ETYPE temp; \
if(epicsParse ## ETYPE(src.c_str(), &temp, nullptr)) \
throw std::runtime_error(SB()<<"Expected " #TYPE ", not \""<<escape(src)<<"\""); \
dest = temp; \
}
CASE(Float32, float)
CASE(Float64, double)
#undef CASE
template<typename Dest>
void convertFromStr(const void *sbase, void *dbase, size_t count)
{
auto S = static_cast<const std::string*>(sbase);
auto D = static_cast<Dest*>(dbase);
for(auto i : range(count))
parseValue(D[i], S[i]);
}
} // namespace
void convertArr(ArrayType dtype, void *dbase,
ArrayType stype, const void *sbase,
size_t count)
{
switch (stype) {
case ArrayType::Bool:
switch(dtype) {
case ArrayType::Bool: memcpy(dbase, sbase, count*sizeof(bool)); return;
case ArrayType::Int8:
case ArrayType::UInt8: convertCast<bool, uint8_t>(sbase, dbase, count); return;
case ArrayType::Int16:
case ArrayType::UInt16: convertCast<bool, uint16_t>(sbase, dbase, count); return;
case ArrayType::Int32:
case ArrayType::UInt32: convertCast<bool, uint32_t>(sbase, dbase, count); return;
case ArrayType::Int64:
case ArrayType::UInt64: convertCast<bool, uint64_t>(sbase, dbase, count); return;
case ArrayType::Float32:convertCast<bool, float>(sbase, dbase, count); return;
case ArrayType::Float64:convertCast<bool, double>(sbase, dbase, count); return;
case ArrayType::String: convertToStr<bool>(sbase, dbase, count); return;
case ArrayType::Value:
case ArrayType::Null: break; // no convert
}
break;
case ArrayType::Int8:
switch(dtype) {
case ArrayType::Bool: convertCast<int8_t, bool>(sbase, dbase, count); return;
case ArrayType::Int8:
case ArrayType::UInt8: memcpy(dbase, sbase, count*sizeof(int8_t)); return;
// cast sint -> *int always sign extends
case ArrayType::Int16:
case ArrayType::UInt16: convertCast<int8_t, int16_t>(sbase, dbase, count); return;
case ArrayType::Int32:
case ArrayType::UInt32: convertCast<int8_t, int32_t>(sbase, dbase, count); return;
case ArrayType::Int64:
case ArrayType::UInt64: convertCast<int8_t, int64_t>(sbase, dbase, count); return;
case ArrayType::Float32:convertCast<int8_t, float>(sbase, dbase, count); return;
case ArrayType::Float64:convertCast<int8_t, double>(sbase, dbase, count); return;
case ArrayType::String: convertToStr<int8_t>(sbase, dbase, count); return;
case ArrayType::Value:
case ArrayType::Null: break; // no convert
}
break;
case ArrayType::Int16:
switch(dtype) {
case ArrayType::Bool: convertCast<int16_t, bool>(sbase, dbase, count); return;
case ArrayType::Int8:
case ArrayType::UInt8: convertCast<int16_t, int8_t>(sbase, dbase, count); return;
case ArrayType::Int16:
case ArrayType::UInt16: memcpy(dbase, sbase, count*sizeof(int16_t)); return;
case ArrayType::Int32:
case ArrayType::UInt32: convertCast<int16_t, int32_t>(sbase, dbase, count); return;
case ArrayType::Int64:
case ArrayType::UInt64: convertCast<int16_t, int64_t>(sbase, dbase, count); return;
case ArrayType::Float32:convertCast<int16_t, float>(sbase, dbase, count); return;
case ArrayType::Float64:convertCast<int16_t, double>(sbase, dbase, count); return;
case ArrayType::String: convertToStr<int16_t>(sbase, dbase, count); return;
case ArrayType::Value:
case ArrayType::Null: break; // no convert
}
break;
case ArrayType::Int32:
switch(dtype) {
case ArrayType::Bool: convertCast<int32_t, bool>(sbase, dbase, count); return;
case ArrayType::Int8:
case ArrayType::UInt8: convertCast<int32_t, int8_t>(sbase, dbase, count); return;
case ArrayType::Int16:
case ArrayType::UInt16: convertCast<int32_t, int16_t>(sbase, dbase, count); return;
case ArrayType::Int32:
case ArrayType::UInt32: memcpy(dbase, sbase, count*sizeof(int32_t)); return;
case ArrayType::Int64:
case ArrayType::UInt64: convertCast<int32_t, int64_t>(sbase, dbase, count); return;
case ArrayType::Float32:convertCast<int32_t, float>(sbase, dbase, count); return;
case ArrayType::Float64:convertCast<int32_t, double>(sbase, dbase, count); return;
case ArrayType::String: convertToStr<int32_t>(sbase, dbase, count); return;
case ArrayType::Value:
case ArrayType::Null: break; // no convert
}
break;
case ArrayType::Int64:
switch(dtype) {
case ArrayType::Bool: convertCast<int64_t, bool>(sbase, dbase, count); return;
case ArrayType::Int8:
case ArrayType::UInt8: convertCast<int64_t, int8_t>(sbase, dbase, count); return;
case ArrayType::Int16:
case ArrayType::UInt16: convertCast<int64_t, int16_t>(sbase, dbase, count); return;
case ArrayType::Int32:
case ArrayType::UInt32: convertCast<int64_t, int32_t>(sbase, dbase, count); return;
case ArrayType::Int64:
case ArrayType::UInt64: memcpy(dbase, sbase, count*sizeof(int64_t)); return;
case ArrayType::Float32:convertCast<int64_t, float>(sbase, dbase, count); return;
case ArrayType::Float64:convertCast<int64_t, double>(sbase, dbase, count); return;
case ArrayType::String: convertToStr<int64_t>(sbase, dbase, count); return;
case ArrayType::Value:
case ArrayType::Null: break; // no convert
}
break;
case ArrayType::UInt8:
switch(dtype) {
case ArrayType::Bool: convertCast<uint8_t, bool>(sbase, dbase, count); return;
case ArrayType::Int8:
case ArrayType::UInt8: memcpy(dbase, sbase, count*sizeof(uint8_t)); return;
//case uint -> *int never sign extends
case ArrayType::Int16:
case ArrayType::UInt16: convertCast<uint8_t, uint16_t>(sbase, dbase, count); return;
case ArrayType::Int32:
case ArrayType::UInt32: convertCast<uint8_t, uint32_t>(sbase, dbase, count); return;
case ArrayType::Int64:
case ArrayType::UInt64: convertCast<uint8_t, uint64_t>(sbase, dbase, count); return;
case ArrayType::Float32:convertCast<uint8_t, float>(sbase, dbase, count); return;
case ArrayType::Float64:convertCast<uint8_t, double>(sbase, dbase, count); return;
case ArrayType::String: convertToStr<uint8_t>(sbase, dbase, count); return;
case ArrayType::Value:
case ArrayType::Null: break; // no convert
}
break;
case ArrayType::UInt16:
switch(dtype) {
case ArrayType::Bool: convertCast<uint16_t, bool>(sbase, dbase, count); return;
case ArrayType::Int8:
case ArrayType::UInt8: convertCast<uint16_t, int8_t>(sbase, dbase, count); return;
case ArrayType::Int16:
case ArrayType::UInt16: memcpy(dbase, sbase, count*sizeof(uint16_t)); return;
case ArrayType::Int32:
case ArrayType::UInt32: convertCast<uint16_t, uint32_t>(sbase, dbase, count); return;
case ArrayType::Int64:
case ArrayType::UInt64: convertCast<uint16_t, uint64_t>(sbase, dbase, count); return;
case ArrayType::Float32:convertCast<uint16_t, float>(sbase, dbase, count); return;
case ArrayType::Float64:convertCast<uint16_t, double>(sbase, dbase, count); return;
case ArrayType::String: convertToStr<uint16_t>(sbase, dbase, count); return;
case ArrayType::Value:
case ArrayType::Null: break; // no convert
}
break;
case ArrayType::UInt32:
switch(dtype) {
case ArrayType::Bool: convertCast<uint32_t, bool>(sbase, dbase, count); return;
case ArrayType::Int8:
case ArrayType::UInt8: convertCast<uint32_t, int8_t>(sbase, dbase, count); return;
case ArrayType::Int16:
case ArrayType::UInt16: convertCast<uint32_t, int16_t>(sbase, dbase, count); return;
case ArrayType::Int32:
case ArrayType::UInt32: memcpy(dbase, sbase, count*sizeof(uint32_t)); return;
case ArrayType::Int64:
case ArrayType::UInt64: convertCast<uint32_t, int64_t>(sbase, dbase, count); return;
case ArrayType::Float32:convertCast<uint32_t, float>(sbase, dbase, count); return;
case ArrayType::Float64:convertCast<uint32_t, double>(sbase, dbase, count); return;
case ArrayType::String: convertToStr<uint32_t>(sbase, dbase, count); return;
case ArrayType::Value:
case ArrayType::Null: break; // no convert
}
break;
case ArrayType::UInt64:
switch(dtype) {
case ArrayType::Bool: convertCast<uint64_t, bool>(sbase, dbase, count); return;
case ArrayType::Int8:
case ArrayType::UInt8: convertCast<uint64_t, int8_t>(sbase, dbase, count); return;
case ArrayType::Int16:
case ArrayType::UInt16: convertCast<uint64_t, int16_t>(sbase, dbase, count); return;
case ArrayType::Int32:
case ArrayType::UInt32: convertCast<uint64_t, int32_t>(sbase, dbase, count); return;
case ArrayType::Int64:
case ArrayType::UInt64: memcpy(dbase, sbase, count*sizeof(uint64_t)); return;
case ArrayType::Float32:convertCast<uint64_t, float>(sbase, dbase, count); return;
case ArrayType::Float64:convertCast<uint64_t, double>(sbase, dbase, count); return;
case ArrayType::String: convertToStr<uint64_t>(sbase, dbase, count); return;
case ArrayType::Value:
case ArrayType::Null: break; // no convert
}
break;
case ArrayType::Float32:
switch(dtype) {
case ArrayType::Bool: convertCast<float, bool>(sbase, dbase, count); return;
case ArrayType::Int8:
case ArrayType::UInt8: convertCast<float, int8_t>(sbase, dbase, count); return;
case ArrayType::Int16:
case ArrayType::UInt16: convertCast<float, int16_t>(sbase, dbase, count); return;
case ArrayType::Int32:
case ArrayType::UInt32: convertCast<float, int32_t>(sbase, dbase, count); return;
case ArrayType::Int64:
case ArrayType::UInt64: convertCast<float, int64_t>(sbase, dbase, count); return;
case ArrayType::Float32:memcpy(dbase, sbase, count*sizeof(float)); return;
case ArrayType::Float64:convertCast<float, double>(sbase, dbase, count); return;
case ArrayType::String: convertToStr<float>(sbase, dbase, count); return;
case ArrayType::Value:
case ArrayType::Null: break; // no convert
}
break;
case ArrayType::Float64:
switch(dtype) {
case ArrayType::Bool: convertCast<double, bool>(sbase, dbase, count); return;
case ArrayType::Int8:
case ArrayType::UInt8: convertCast<double, int8_t>(sbase, dbase, count); return;
case ArrayType::Int16:
case ArrayType::UInt16: convertCast<double, int16_t>(sbase, dbase, count); return;
case ArrayType::Int32:
case ArrayType::UInt32: convertCast<double, int32_t>(sbase, dbase, count); return;
case ArrayType::Int64:
case ArrayType::UInt64: convertCast<double, int64_t>(sbase, dbase, count); return;
case ArrayType::Float32:memcpy(dbase, sbase, count*sizeof(double)); return;
case ArrayType::Float64:convertCast<double, double>(sbase, dbase, count); return;
case ArrayType::String: convertToStr<double>(sbase, dbase, count); return;
case ArrayType::Value:
case ArrayType::Null: break; // no convert
}
break;
case ArrayType::String:
switch(dtype) {
case ArrayType::Bool: convertFromStr<bool>(sbase, dbase, count); return;
case ArrayType::Int8: convertFromStr<int8_t>(sbase, dbase, count); return;
case ArrayType::UInt8: convertFromStr<uint8_t>(sbase, dbase, count); return;
case ArrayType::Int16: convertFromStr<int16_t>(sbase, dbase, count); return;
case ArrayType::UInt16: convertFromStr<uint16_t>(sbase, dbase, count); return;
case ArrayType::Int32: convertFromStr<int32_t>(sbase, dbase, count); return;
case ArrayType::UInt32: convertFromStr<uint32_t>(sbase, dbase, count); return;
case ArrayType::Int64: convertFromStr<int64_t>(sbase, dbase, count); return;
case ArrayType::UInt64: convertFromStr<uint64_t>(sbase, dbase, count); return;
case ArrayType::Float32:convertFromStr<float>(sbase, dbase, count); return;
case ArrayType::Float64:convertFromStr<double>(sbase, dbase, count); return;
break;
case ArrayType::String: convertCast<std::string, std::string>(sbase, dbase, count); return;
case ArrayType::Value:
case ArrayType::Null: break; // no convert
}
break;
case ArrayType::Value:
case ArrayType::Null:
break;
}
throw NoConvert();
}
shared_array<void> copyAs(ArrayType dtype, ArrayType stype, const void *sbase, size_t count)
{
shared_array<void> ret;
switch(dtype) {
#define CASE(CODE, Type) case ArrayType::CODE: ret = shared_array<Type>(count).castTo<void>(); break
CASE(Bool, bool);
CASE(UInt8, uint8_t);
CASE(UInt16, uint16_t);
CASE(UInt32, uint32_t);
CASE(UInt64, uint64_t);
CASE(Int8, int8_t);
CASE(Int16, int16_t);
CASE(Int32, int32_t);
CASE(Int64, int64_t);
CASE(Float32, float);
CASE(Float64, double);
CASE(String, std::string);
CASE(Value, Value);
#undef CASE
case ArrayType::Null:
break;
}
if(stype!=ArrayType::Null)
convertArr(dtype, ret.data(), stype, sbase, count);
return ret;
}
} // namespace detail
} // namespace pvxs