From da0c73b1fa513f59c0c07061a8a515ccd415338a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 27 Mar 2020 13:50:42 -0700 Subject: [PATCH] add array convert --- src/pvxs/data.h | 2 +- src/pvxs/sharedArray.h | 47 ++++++ src/sharedarray.cpp | 374 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 422 insertions(+), 1 deletion(-) diff --git a/src/pvxs/data.h b/src/pvxs/data.h index d821656..042b14d 100644 --- a/src/pvxs/data.h +++ b/src/pvxs/data.h @@ -105,7 +105,7 @@ struct StoreTransform> { } static inline shared_array out(const shared_array& v) { - return v.template castTo(); + return v.template convertTo(); } }; diff --git a/src/pvxs/sharedArray.h b/src/pvxs/sharedArray.h index cedd561..2fa0fab 100644 --- a/src/pvxs/sharedArray.h +++ b/src/pvxs/sharedArray.h @@ -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 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 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(this->_data, this->_data.get(), this->_count); // implied cast to void* } + template{} && (std::is_const{} == std::is_const{}), int>::type =0> + shared_array + convertTo() const { + if(detail::CaptureBase::code==detail::CaptureBase::code) { + return castTo(); + } else { + shared_array ret(this->_count); + detail::convertArr(detail::CaptureBase::code, (void*)ret._data.get(), + detail::CaptureBase::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{} && (std::is_const{} == std::is_const{}), int>::type =0> + shared_array + convertTo() const { + if(detail::CaptureBase::code==_type) { + return castTo(); + } else { + shared_array ret(this->_count); + detail::convertArr(detail::CaptureBase::code, (void*)ret._data.get(), + _type, this->_data.get(), + this->_count); + return ret; + } + } + + template{} && (std::is_const{} == std::is_const{}), int>::type =0> + shared_array + convertTo() const { + return castTo(); + } + //! Provide options when rendering with std::ostream. detail::Limiter format() const { return detail::Limiter(this->_data.get(), diff --git a/src/sharedarray.cpp b/src/sharedarray.cpp index 183bc5f..11f97e1 100644 --- a/src/sharedarray.cpp +++ b/src/sharedarray.cpp @@ -4,8 +4,12 @@ * in file LICENSE that is included with this distribution. */ +#include + +#include #include +#include #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 "< +void convertCast(const void *sbase, void *dbase, size_t count) +{ + auto S = static_cast(sbase); + auto D = static_cast(dbase); + for(auto i : range(count)) + D[i] = S[i]; +} + +void printValue(std::string& dest, const bool& src) +{ + dest = src ? "true" : "false"; +} + +template +typename std::enable_if{}>::type +printValue(std::string& dest, const Src& src) +{ + std::ostringstream strm; + strm< +void convertToStr(const void *sbase, void *dbase, size_t count) +{ + auto S = static_cast(sbase); + auto D = static_cast(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 \""< +void convertFromStr(const void *sbase, void *dbase, size_t count) +{ + auto S = static_cast(sbase); + auto D = static_cast(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(sbase, dbase, count); return; + case ArrayType::Int16: + case ArrayType::UInt16: convertCast(sbase, dbase, count); return; + case ArrayType::Int32: + case ArrayType::UInt32: convertCast(sbase, dbase, count); return; + case ArrayType::Int64: + case ArrayType::UInt64: convertCast(sbase, dbase, count); return; + case ArrayType::Float32:convertCast(sbase, dbase, count); return; + case ArrayType::Float64:convertCast(sbase, dbase, count); return; + case ArrayType::String: convertToStr(sbase, dbase, count); return; + case ArrayType::Value: + case ArrayType::Null: break; // no convert + } + break; + case ArrayType::Int8: + switch(dtype) { + case ArrayType::Bool: convertCast(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(sbase, dbase, count); return; + case ArrayType::Int32: + case ArrayType::UInt32: convertCast(sbase, dbase, count); return; + case ArrayType::Int64: + case ArrayType::UInt64: convertCast(sbase, dbase, count); return; + case ArrayType::Float32:convertCast(sbase, dbase, count); return; + case ArrayType::Float64:convertCast(sbase, dbase, count); return; + case ArrayType::String: convertToStr(sbase, dbase, count); return; + case ArrayType::Value: + case ArrayType::Null: break; // no convert + } + break; + case ArrayType::Int16: + switch(dtype) { + case ArrayType::Bool: convertCast(sbase, dbase, count); return; + case ArrayType::Int8: + case ArrayType::UInt8: convertCast(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(sbase, dbase, count); return; + case ArrayType::Int64: + case ArrayType::UInt64: convertCast(sbase, dbase, count); return; + case ArrayType::Float32:convertCast(sbase, dbase, count); return; + case ArrayType::Float64:convertCast(sbase, dbase, count); return; + case ArrayType::String: convertToStr(sbase, dbase, count); return; + case ArrayType::Value: + case ArrayType::Null: break; // no convert + } + break; + case ArrayType::Int32: + switch(dtype) { + case ArrayType::Bool: convertCast(sbase, dbase, count); return; + case ArrayType::Int8: + case ArrayType::UInt8: convertCast(sbase, dbase, count); return; + case ArrayType::Int16: + case ArrayType::UInt16: convertCast(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(sbase, dbase, count); return; + case ArrayType::Float32:convertCast(sbase, dbase, count); return; + case ArrayType::Float64:convertCast(sbase, dbase, count); return; + case ArrayType::String: convertToStr(sbase, dbase, count); return; + case ArrayType::Value: + case ArrayType::Null: break; // no convert + } + break; + case ArrayType::Int64: + switch(dtype) { + case ArrayType::Bool: convertCast(sbase, dbase, count); return; + case ArrayType::Int8: + case ArrayType::UInt8: convertCast(sbase, dbase, count); return; + case ArrayType::Int16: + case ArrayType::UInt16: convertCast(sbase, dbase, count); return; + case ArrayType::Int32: + case ArrayType::UInt32: convertCast(sbase, dbase, count); return; + case ArrayType::Int64: + case ArrayType::UInt64: memcpy(dbase, sbase, count*sizeof(int64_t)); return; + case ArrayType::Float32:convertCast(sbase, dbase, count); return; + case ArrayType::Float64:convertCast(sbase, dbase, count); return; + case ArrayType::String: convertToStr(sbase, dbase, count); return; + case ArrayType::Value: + case ArrayType::Null: break; // no convert + } + break; + case ArrayType::UInt8: + switch(dtype) { + case ArrayType::Bool: convertCast(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(sbase, dbase, count); return; + case ArrayType::Int32: + case ArrayType::UInt32: convertCast(sbase, dbase, count); return; + case ArrayType::Int64: + case ArrayType::UInt64: convertCast(sbase, dbase, count); return; + case ArrayType::Float32:convertCast(sbase, dbase, count); return; + case ArrayType::Float64:convertCast(sbase, dbase, count); return; + case ArrayType::String: convertToStr(sbase, dbase, count); return; + case ArrayType::Value: + case ArrayType::Null: break; // no convert + } + break; + case ArrayType::UInt16: + switch(dtype) { + case ArrayType::Bool: convertCast(sbase, dbase, count); return; + case ArrayType::Int8: + case ArrayType::UInt8: convertCast(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(sbase, dbase, count); return; + case ArrayType::Int64: + case ArrayType::UInt64: convertCast(sbase, dbase, count); return; + case ArrayType::Float32:convertCast(sbase, dbase, count); return; + case ArrayType::Float64:convertCast(sbase, dbase, count); return; + case ArrayType::String: convertToStr(sbase, dbase, count); return; + case ArrayType::Value: + case ArrayType::Null: break; // no convert + } + break; + case ArrayType::UInt32: + switch(dtype) { + case ArrayType::Bool: convertCast(sbase, dbase, count); return; + case ArrayType::Int8: + case ArrayType::UInt8: convertCast(sbase, dbase, count); return; + case ArrayType::Int16: + case ArrayType::UInt16: convertCast(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(sbase, dbase, count); return; + case ArrayType::Float32:convertCast(sbase, dbase, count); return; + case ArrayType::Float64:convertCast(sbase, dbase, count); return; + case ArrayType::String: convertToStr(sbase, dbase, count); return; + case ArrayType::Value: + case ArrayType::Null: break; // no convert + } + break; + case ArrayType::UInt64: + switch(dtype) { + case ArrayType::Bool: convertCast(sbase, dbase, count); return; + case ArrayType::Int8: + case ArrayType::UInt8: convertCast(sbase, dbase, count); return; + case ArrayType::Int16: + case ArrayType::UInt16: convertCast(sbase, dbase, count); return; + case ArrayType::Int32: + case ArrayType::UInt32: convertCast(sbase, dbase, count); return; + case ArrayType::Int64: + case ArrayType::UInt64: memcpy(dbase, sbase, count*sizeof(uint64_t)); return; + case ArrayType::Float32:convertCast(sbase, dbase, count); return; + case ArrayType::Float64:convertCast(sbase, dbase, count); return; + case ArrayType::String: convertToStr(sbase, dbase, count); return; + case ArrayType::Value: + case ArrayType::Null: break; // no convert + } + break; + case ArrayType::Float32: + switch(dtype) { + case ArrayType::Bool: convertCast(sbase, dbase, count); return; + case ArrayType::Int8: + case ArrayType::UInt8: convertCast(sbase, dbase, count); return; + case ArrayType::Int16: + case ArrayType::UInt16: convertCast(sbase, dbase, count); return; + case ArrayType::Int32: + case ArrayType::UInt32: convertCast(sbase, dbase, count); return; + case ArrayType::Int64: + case ArrayType::UInt64: convertCast(sbase, dbase, count); return; + case ArrayType::Float32:memcpy(dbase, sbase, count*sizeof(float)); return; + case ArrayType::Float64:convertCast(sbase, dbase, count); return; + case ArrayType::String: convertToStr(sbase, dbase, count); return; + case ArrayType::Value: + case ArrayType::Null: break; // no convert + } + break; + case ArrayType::Float64: + switch(dtype) { + case ArrayType::Bool: convertCast(sbase, dbase, count); return; + case ArrayType::Int8: + case ArrayType::UInt8: convertCast(sbase, dbase, count); return; + case ArrayType::Int16: + case ArrayType::UInt16: convertCast(sbase, dbase, count); return; + case ArrayType::Int32: + case ArrayType::UInt32: convertCast(sbase, dbase, count); return; + case ArrayType::Int64: + case ArrayType::UInt64: convertCast(sbase, dbase, count); return; + case ArrayType::Float32:memcpy(dbase, sbase, count*sizeof(double)); return; + case ArrayType::Float64:convertCast(sbase, dbase, count); return; + case ArrayType::String: convertToStr(sbase, dbase, count); return; + case ArrayType::Value: + case ArrayType::Null: break; // no convert + } + break; + case ArrayType::String: + switch(dtype) { + case ArrayType::Bool: convertFromStr(sbase, dbase, count); return; + case ArrayType::Int8: convertFromStr(sbase, dbase, count); return; + case ArrayType::UInt8: convertFromStr(sbase, dbase, count); return; + case ArrayType::Int16: convertFromStr(sbase, dbase, count); return; + case ArrayType::UInt16: convertFromStr(sbase, dbase, count); return; + case ArrayType::Int32: convertFromStr(sbase, dbase, count); return; + case ArrayType::UInt32: convertFromStr(sbase, dbase, count); return; + case ArrayType::Int64: convertFromStr(sbase, dbase, count); return; + case ArrayType::UInt64: convertFromStr(sbase, dbase, count); return; + case ArrayType::Float32:convertFromStr(sbase, dbase, count); return; + case ArrayType::Float64:convertFromStr(sbase, dbase, count); return; + break; + case ArrayType::String: convertCast(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 copyAs(ArrayType dtype, ArrayType stype, const void *sbase, size_t count) +{ + shared_array ret; + switch(dtype) { +#define CASE(CODE, Type) case ArrayType::CODE: ret = shared_array(count).castTo(); 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