From c435f71592c62c7b9fc48d61f4cfbfe971d67de5 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 12 Apr 2013 18:43:53 -0400 Subject: [PATCH 001/103] testOperators: avoid warning --- testApp/pv/testOperators.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testApp/pv/testOperators.cpp b/testApp/pv/testOperators.cpp index 3cc3fb6..6512d20 100644 --- a/testApp/pv/testOperators.cpp +++ b/testApp/pv/testOperators.cpp @@ -20,7 +20,7 @@ static PVDataCreatePtr pvDataCreate = getPVDataCreate(); static StandardFieldPtr standardField = getStandardField(); static StandardPVFieldPtr standardPVField = getStandardPVField(); -int main(int, char*) +int main(int, char**) { PVStructurePtr pvStructure = standardPVField->scalar(pvDouble, "alarm,timeStamp,display,control,valueAlarm"); From d7eada7216b7bff9316dfb9ba4b0ddae9364891a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 15 Apr 2013 14:39:42 -0400 Subject: [PATCH 002/103] type casting with castUnsafe(FROM val) --- pvDataApp/Makefile | 2 + pvDataApp/misc/parseToPOD.cpp | 373 +++++++++++++++++++++++++++++++++ pvDataApp/misc/typeCast.h | 177 ++++++++++++++++ testApp/misc/Makefile | 5 + testApp/misc/testTypeCast.cpp | 376 ++++++++++++++++++++++++++++++++++ 5 files changed, 933 insertions(+) create mode 100644 pvDataApp/misc/parseToPOD.cpp create mode 100644 pvDataApp/misc/typeCast.h create mode 100644 testApp/misc/testTypeCast.cpp diff --git a/pvDataApp/Makefile b/pvDataApp/Makefile index 0acf9b9..c496310 100644 --- a/pvDataApp/Makefile +++ b/pvDataApp/Makefile @@ -24,6 +24,7 @@ INC += destroyable.h INC += status.h INC += sharedPtr.h INC += localStaticLock.h +INC += typeCast.h LIBSRCS += byteBuffer.cpp LIBSRCS += bitSet.cpp @@ -37,6 +38,7 @@ LIBSRCS += timer.cpp LIBSRCS += status.cpp LIBSRCS += messageQueue.cpp LIBSRCS += localStaticLock.cpp +LIBSRCS += parseToPOD.cpp SRC_DIRS += $(PVDATA)/pv diff --git a/pvDataApp/misc/parseToPOD.cpp b/pvDataApp/misc/parseToPOD.cpp new file mode 100644 index 0000000..a047348 --- /dev/null +++ b/pvDataApp/misc/parseToPOD.cpp @@ -0,0 +1,373 @@ +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "typeCast.h" + +#ifndef EPICS_VERSION_INT +#define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P)) +#define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL) +#endif + +#if EPICS_VERSION_INT < VERSION_INT(3,15,0,1) +/* integer conversion primatives added to epicsStdlib.c in 3.15.0.1 */ + +#define S_stdlib_noConversion 1 /* No digits to convert */ +#define S_stdlib_extraneous 2 /* Extraneous characters */ +#define S_stdlib_underflow 3 /* Too small to represent */ +#define S_stdlib_overflow 4 /* Too large to represent */ +#define S_stdlib_badBase 5 /* Number base not supported */ + +static int +epicsParseLong(const char *str, long *to, int base, char **units) +{ + int c; + char *endp; + long value; + + while ((c = *str) && isspace(c)) + ++str; + + errno = 0; + value = strtol(str, &endp, base); + + if (endp == str) + return S_stdlib_noConversion; + if (errno == EINVAL) /* Not universally supported */ + return S_stdlib_badBase; + if (errno == ERANGE) + return S_stdlib_overflow; + + while ((c = *endp) && isspace(c)) + ++endp; + if (c && !units) + return S_stdlib_extraneous; + + *to = value; + if (units) + *units = endp; + return 0; +} + +static int +epicsParseULong(const char *str, unsigned long *to, int base, char **units) +{ + int c; + char *endp; + unsigned long value; + + while ((c = *str) && isspace(c)) + ++str; + + errno = 0; + value = strtoul(str, &endp, base); + + if (endp == str) + return S_stdlib_noConversion; + if (errno == EINVAL) /* Not universally supported */ + return S_stdlib_badBase; + if (errno == ERANGE) + return S_stdlib_overflow; + + while ((c = *endp) && isspace(c)) + ++endp; + if (c && !units) + return S_stdlib_extraneous; + + *to = value; + if (units) + *units = endp; + return 0; +} + +static int +epicsParseDouble(const char *str, double *to, char **units) +{ + int c; + char *endp; + double value; + + while ((c = *str) && isspace(c)) + ++str; + + errno = 0; + value = epicsStrtod(str, &endp); + + if (endp == str) + return S_stdlib_noConversion; + if (errno == ERANGE) + return (value == 0) ? S_stdlib_underflow : S_stdlib_overflow; + + while ((c = *endp) && isspace(c)) + ++endp; + if (c && !units) + return S_stdlib_extraneous; + + *to = value; + if (units) + *units = endp; + return 0; +} + + +/* These call the primitives */ + +static int +epicsParseInt8(const char *str, epicsInt8 *to, int base, char **units) +{ + long value; + int status = epicsParseLong(str, &value, base, units); + + if (status) + return status; + + if (value < -0x80 || value > 0x7f) + return S_stdlib_overflow; + + *to = value; + return 0; +} + +static int +epicsParseUInt8(const char *str, epicsUInt8 *to, int base, char **units) +{ + unsigned long value; + int status = epicsParseULong(str, &value, base, units); + + if (status) + return status; + + if (value > 0xff && value <= ~0xffUL) + return S_stdlib_overflow; + + *to = value; + return 0; +} + +static int +epicsParseInt16(const char *str, epicsInt16 *to, int base, char **units) +{ + long value; + int status = epicsParseLong(str, &value, base, units); + + if (status) + return status; + + if (value < -0x8000 || value > 0x7fff) + return S_stdlib_overflow; + + *to = value; + return 0; +} + +static int +epicsParseUInt16(const char *str, epicsUInt16 *to, int base, char **units) +{ + unsigned long value; + int status = epicsParseULong(str, &value, base, units); + + if (status) + return status; + + if (value > 0xffff && value <= ~0xffffUL) + return S_stdlib_overflow; + + *to = value; + return 0; +} + +static int +epicsParseInt32(const char *str, epicsInt32 *to, int base, char **units) +{ + long value; + int status = epicsParseLong(str, &value, base, units); + + if (status) + return status; + +#if (LONG_MAX > 0x7fffffff) + if (value < -0x80000000L || value > 0x7fffffffL) + return S_stdlib_overflow; +#endif + + *to = value; + return 0; +} + +static int +epicsParseUInt32(const char *str, epicsUInt32 *to, int base, char **units) +{ + unsigned long value; + int status = epicsParseULong(str, &value, base, units); + + if (status) + return status; + +#if (ULONG_MAX > 0xffffffff) + if (value > 0xffffffffUL && value <= ~0xffffffffUL) + return S_stdlib_overflow; +#endif + + *to = value; + return 0; +} + +static int +epicsParseFloat(const char *str, float *to, char **units) +{ + double value, abs; + int status = epicsParseDouble(str, &value, units); + + if (status) + return status; + + abs = fabs(value); + if (value > 0 && abs <= FLT_MIN) + return S_stdlib_underflow; + if (finite(value) && abs >= FLT_MAX) + return S_stdlib_overflow; + + *to = value; + return 0; +} +#endif + +/* do we need long long? */ +#if INT_MAX == LONG_MAX +static int +epicsParseLongLong(const char *str, long long *to, int base, char **units) +{ + int c; + char *endp; + long long value; + + while ((c = *str) && isspace(c)) + ++str; + + errno = 0; + value = strtoll(str, &endp, base); + + if (endp == str) + return S_stdlib_noConversion; + if (errno == EINVAL) /* Not universally supported */ + return S_stdlib_badBase; + if (errno == ERANGE) + return S_stdlib_overflow; + + while ((c = *endp) && isspace(c)) + ++endp; + if (c && !units) + return S_stdlib_extraneous; + + *to = value; + if (units) + *units = endp; + return 0; +} + +static int +epicsParseULongLong(const char *str, unsigned long long *to, int base, char **units) +{ + int c; + char *endp; + unsigned long long value; + + while ((c = *str) && isspace(c)) + ++str; + + errno = 0; + value = strtoull(str, &endp, base); + + if (endp == str) + return S_stdlib_noConversion; + if (errno == EINVAL) /* Not universally supported */ + return S_stdlib_badBase; + if (errno == ERANGE) + return S_stdlib_overflow; + + while ((c = *endp) && isspace(c)) + ++endp; + if (c && !units) + return S_stdlib_extraneous; + + *to = value; + if (units) + *units = endp; + return 0; +} +#endif + +static +void handleParseError(int err) +{ + switch(err) { + case 0: break; + case S_stdlib_noConversion: throw std::runtime_error("parseToPOD: No digits to convert"); + case S_stdlib_extraneous: throw std::runtime_error("parseToPOD: Extraneous characters"); + case S_stdlib_underflow: throw std::runtime_error("parseToPOD: Too small to represent"); + case S_stdlib_overflow: throw std::runtime_error("parseToPOD: Too large to represent"); + case S_stdlib_badBase: throw std::runtime_error("parseToPOD: Number base not supported"); + default: + throw std::runtime_error("parseToPOD: unknown error"); + } +} + +namespace epics { namespace pvData { namespace detail { + +void parseToPOD(const std::string& in, int8 *out) { + epicsInt8 temp; + int err = epicsParseInt8(in.c_str(), &temp, 0, NULL); + if(err) handleParseError(err); + else *out = temp; +} + +#define INTFN(T, S) \ +void parseToPOD(const std::string& in, T *out) { \ + int err = epicsParse ## S(in.c_str(), out, 0, NULL); \ + if(err) handleParseError(err); \ +} + +INTFN(char, Int8); +INTFN(uint8_t, UInt8); +INTFN(int16_t, Int16); +INTFN(uint16_t, UInt16); +INTFN(int32_t, Int32); +INTFN(uint32_t, UInt32); + +void parseToPOD(const std::string& in, int64_t *out) { +#if INT_MAX == LONG_MAX + int err = epicsParseLongLong(in.c_str(), out, 0, NULL); +#else + int err = epicsParseLong(in.c_str(), out, 0, NULL); +#endif + if(err) handleParseError(err); +} + +void parseToPOD(const std::string& in, uint64_t *out) { +#if INT_MAX == LONG_MAX + int err = epicsParseULongLong(in.c_str(), out, 0, NULL); +#else + int err = epicsParseULong(in.c_str(), out, 0, NULL); +#endif + if(err) handleParseError(err); +} + +void parseToPOD(const std::string& in, float *out) { + int err = epicsParseFloat(in.c_str(), out, NULL); + if(err) handleParseError(err); +} + +void parseToPOD(const std::string& in, double *out) { + int err = epicsParseDouble(in.c_str(), out, NULL); + if(err) handleParseError(err); +} + +}}} diff --git a/pvDataApp/misc/typeCast.h b/pvDataApp/misc/typeCast.h new file mode 100644 index 0000000..dbf8b1a --- /dev/null +++ b/pvDataApp/misc/typeCast.h @@ -0,0 +1,177 @@ +/** + * 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 + +#include + +#include + +// gently nudge the compiler to inline our wrappers +#if defined(__GNUC__) +# define FORCE_INLINE __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +# define FORCE_INLINE __forceinline +#else +# define FORCE_INLINE inline +#endif + +namespace epics { namespace pvData { + +typedef std::string String; + +namespace detail { + // parseToPOD wraps the epicsParse*() functions in one name + // and throws exceptions + void parseToPOD(const std::string&, char *out); + void parseToPOD(const std::string&, int8_t *out); + void parseToPOD(const std::string&, uint8_t *out); + void parseToPOD(const std::string&, int16_t *out); + void parseToPOD(const std::string&, uint16_t *out); + void parseToPOD(const std::string&, int32_t *out); + void parseToPOD(const std::string&, uint32_t *out); + void parseToPOD(const std::string&, int64_t *out); + void parseToPOD(const std::string&, uint64_t *out); + void parseToPOD(const std::string&, float *out); + 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; }; + + // test to allow specialization only when A!=B + template + struct not_same_type {typedef R type;}; + template + struct not_same_type {}; + + // trick std::ostream into treating char's as numbers + // by promoting char to int + template + struct print_cast { typedef T type; }; + template<> + struct print_cast { typedef int type; }; + template<> + struct print_cast { typedef signed int type; }; + template<> + struct print_cast { typedef unsigned int type; }; + + // 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) { + typedef typename print_cast::type ptype; + std::ostringstream strm; + strm << (ptype)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); +} + +}} // end namespace + +#undef FORCE_INLINE + +#endif // PVTYPECAST_H diff --git a/testApp/misc/Makefile b/testApp/misc/Makefile index 077f4eb..4e2cf83 100644 --- a/testApp/misc/Makefile +++ b/testApp/misc/Makefile @@ -42,6 +42,11 @@ PROD_HOST += testMessageQueue testMessageQueue_SRCS += testMessageQueue.cpp testMessageQueue_LIBS += pvData Com +PROD_HOST += testTypeCast +testTypeCast_SRCS += testTypeCast.cpp +testTypeCast_LIBS += pvData Com + + include $(TOP)/configure/RULES #---------------------------------------- # ADD RULES AFTER THIS LINE diff --git a/testApp/misc/testTypeCast.cpp b/testApp/misc/testTypeCast.cpp new file mode 100644 index 0000000..239bf70 --- /dev/null +++ b/testApp/misc/testTypeCast.cpp @@ -0,0 +1,376 @@ +/** + * 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 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "pv/typeCast.h" + +#include + +using epics::pvData::String; + +namespace { + + template + struct testequal { + static bool op(T A, T B) {return A==B; } + }; + template<> + struct testequal { + static bool op(double A, double B) {return fabs(A-B)<1e-300; } + }; + template<> + struct testequal { + static bool op(float A, float B) {return fabs(A-B)<1e-30; } + }; + + template + struct testcase { + static bool op(std::ostream& msg, TO expect, FROM inp) + { + TO actual; + try { + actual = ::epics::pvData::castUnsafe(inp); + //actual = ::epics::pvData::detail::cast_helper::op(inp); + } catch(std::runtime_error& e) { + msg<<"Failed to cast " + < " + <::op(actual, expect)) { + msg<<"Failed cast gives unexpected value " + < " + < " + < + struct testfail { + static bool op(std::ostream& msg, FROM inp) + { + TO actual; + try { + actual = ::epics::pvData::castUnsafe(inp); + msg<<"Failed to generate expected error " + < (" + < (" + <::op(*out, VTO, VFRO) + +// Test cast and reverse +#define TEST2(TTO, VTO, TFRO, VFRO) TEST(TTO, VTO, TFRO, VFRO); TEST(TFRO, VFRO, TTO, VTO) + +#define FAIL(TTO, TFRO, VFRO) fail |= !testfail::op(*out, VFRO) + +} // end namespace + + +int main(int argc,char *argv[]) +{ + std::ostream *out = &std::cerr; + std::ofstream outf; + if(argc>1){ + outf.open(argv[1]); + if(!outf.good()) { + std::cerr<<"Failed to open "<(x## N) +//#define CHECK(M, N) x## M = ::epics::pvData::detail::cast_helper::op(x## N) + CHECK(int8, int8); + CHECK(int8, uint8); + CHECK(int8, int16); + CHECK(int8, uint16); + CHECK(int8, int32); + CHECK(int8, uint32); + CHECK(int8, int64); + CHECK(int8, uint64); + CHECK(int8, float); + CHECK(int8, double); + CHECK(int8, String); + + CHECK(uint8, int8); + CHECK(uint8, uint8); + CHECK(uint8, int16); + CHECK(uint8, uint16); + CHECK(uint8, int32); + CHECK(uint8, uint32); + CHECK(uint8, int64); + CHECK(uint8, uint64); + CHECK(uint8, float); + CHECK(uint8, double); + CHECK(uint8, String); + + CHECK(int16, int8); + CHECK(int16, uint8); + CHECK(int16, int16); + CHECK(int16, uint16); + CHECK(int16, int32); + CHECK(int16, uint32); + CHECK(int16, int64); + CHECK(int16, uint64); + CHECK(int16, float); + CHECK(int16, double); + CHECK(int16, String); + + CHECK(uint16, int8); + CHECK(uint16, uint8); + CHECK(uint16, int16); + CHECK(uint16, uint16); + CHECK(uint16, int32); + CHECK(uint16, uint32); + CHECK(uint16, int64); + CHECK(uint16, uint64); + CHECK(uint16, float); + CHECK(uint16, double); + CHECK(uint16, String); + + CHECK(int32, int8); + CHECK(int32, uint8); + CHECK(int32, int16); + CHECK(int32, uint16); + CHECK(int32, int32); + CHECK(int32, uint32); + CHECK(int32, int64); + CHECK(int32, uint64); + CHECK(int32, float); + CHECK(int32, double); + CHECK(int32, String); + + CHECK(uint32, int8); + CHECK(uint32, uint8); + CHECK(uint32, int16); + CHECK(uint32, uint16); + CHECK(uint32, int32); + CHECK(uint32, uint32); + CHECK(uint32, int64); + CHECK(uint32, uint64); + CHECK(uint32, float); + CHECK(uint32, double); + CHECK(uint32, String); + + CHECK(int64, int8); + CHECK(int64, uint8); + CHECK(int64, int16); + CHECK(int64, uint16); + CHECK(int64, int32); + CHECK(int64, uint32); + CHECK(int64, int64); + CHECK(int64, uint64); + CHECK(int64, float); + CHECK(int64, double); + //CHECK(int64, String); + + CHECK(uint64, int8); + CHECK(uint64, uint8); + CHECK(uint64, int16); + CHECK(uint64, uint16); + CHECK(uint64, int32); + CHECK(uint64, uint32); + CHECK(uint64, int64); + CHECK(uint64, uint64); + CHECK(uint64, float); + CHECK(uint64, double); + //CHECK(uint64, String); + + CHECK(float, int8); + CHECK(float, uint8); + CHECK(float, int16); + CHECK(float, uint16); + CHECK(float, int32); + CHECK(float, uint32); + CHECK(float, int64); + CHECK(float, uint64); + CHECK(float, float); + CHECK(float, double); + CHECK(float, String); + + CHECK(double, int8); + CHECK(double, uint8); + CHECK(double, int16); + CHECK(double, uint16); + CHECK(double, int32); + CHECK(double, uint32); + CHECK(double, int64); + CHECK(double, uint64); + CHECK(double, float); + CHECK(double, double); + CHECK(double, String); + + CHECK(String, int8); + CHECK(String, uint8); + CHECK(String, int16); + CHECK(String, uint16); + CHECK(String, int32); + CHECK(String, uint32); + CHECK(String, int64); + CHECK(String, uint64); + CHECK(String, float); + CHECK(String, double); + CHECK(String, String); +#undef CHECK + + *out << "Integer signed <=> unsigned\n"; + + TEST2(uint8_t, std::numeric_limits::max(), int8_t, -1); + TEST2(uint16_t, std::numeric_limits::max(), int8_t, -1); + TEST2(uint32_t, std::numeric_limits::max(), int8_t, -1); + TEST2(uint64_t, std::numeric_limits::max(), int8_t, -1); + + *out << "Integer unsigned promote (and demote when in range)\n"; + + TEST2(uint16_t, 0xff, uint8_t, 0xff); + TEST2(uint32_t, 0xffff, uint16_t, 0xffff); + TEST2(uint64_t, 0xffffffffu, uint32_t, 0xffffffffu); + + TEST2(int16_t, 0x7f, int8_t, 0x7f); + TEST2(int32_t, 0x7fff, int16_t, 0x7fff); + TEST2(int64_t, 0x7fffffff, int32_t, 0x7fffffff); + + *out << "Double to int w/ round towards zero (aka truncation)\n"; + + TEST(int32_t, 2, double, 2.1); + TEST(int32_t, 2, double, 2.5); + TEST(int32_t, 2, double, 2.7); + TEST(int32_t, -2, double, -2.1); + TEST(int32_t, -2, double, -2.5); + TEST(int32_t, -2, double, -2.7); + + *out << "Float to int w/ round towards zero (aka truncation)\n"; + + TEST(int32_t, 2, float, 2.1); + TEST(int32_t, 2, float, 2.5); + TEST(int32_t, 2, float, 2.7); + TEST(int32_t, -2, float, -2.1); + TEST(int32_t, -2, float, -2.5); + TEST(int32_t, -2, float, -2.7); + + *out << "String Printing/parsing\n"; + + TEST2(String, "1", int32_t, 1); + TEST2(String, "-1", int32_t, -1); + TEST2(String, "1", int8_t, 1); + TEST2(String, "-1", int8_t, -1); + TEST2(String, "1", uint8_t, 1); + TEST2(String, "-1", char, -1); + + TEST2(String, "127", int32_t, std::numeric_limits::max()); + TEST2(String, "-128", int32_t, std::numeric_limits::min()); + TEST2(String, "255", int32_t, std::numeric_limits::max()); + + TEST2(String, "32767", int32_t, std::numeric_limits::max()); + TEST2(String, "-32768", int32_t, std::numeric_limits::min()); + TEST2(String, "65535", int32_t, std::numeric_limits::max()); + + TEST2(String, "2147483647", int32_t, std::numeric_limits::max()); + TEST2(String, "-2147483648", int32_t, std::numeric_limits::min()); + TEST2(String, "4294967295", uint32_t, std::numeric_limits::max()); + + TEST2(String, "9223372036854775807", int64_t, std::numeric_limits::max()); + TEST2(String, "-9223372036854775808", int64_t, std::numeric_limits::min()); + TEST2(String, "18446744073709551615", uint64_t, std::numeric_limits::max()); + + TEST2(String, "1.1", double, 1.1); + TEST2(String, "1.1e+100", double, 1.1e100); + TEST2(String, "1.1e-100", double, 1.1e-100); + + TEST(double, 1.1e100, String, "1.1E+100"); + + *out << "String Parsing\n"; + + TEST(int32_t, 15, String, "0xf"); + TEST(int32_t, 15, String, "0xF"); + TEST(int32_t, -15, String, "-0xF"); + TEST(int32_t, 16, String, "0x10"); + TEST(int32_t, -16, String, "-0x10"); + + TEST(int32_t, 7, String, "07"); + TEST(int32_t, 8, String, "010"); + TEST(int32_t, -7, String, "-07"); + TEST(int32_t, -8, String, "-010"); + + *out << "String parsing errors\n"; + + FAIL(int32_t, String, "hello!"); + FAIL(int32_t, String, "42 is the answer"); + FAIL(double, String, "hello!"); + FAIL(double, String, "42 is the answer"); + + FAIL(int8_t, String, "1000"); + FAIL(int8_t, String, "-1000"); + + FAIL(double, String, "1e+10000000"); + + *out << "Floating point overflows\n"; + + TEST(float, FLT_MAX, double, 1e300); + TEST(float, -FLT_MAX, double, -1e300); + TEST(float, FLT_MIN, double, 1e-300); + TEST(float, -FLT_MIN, double, -1e-300); + xfloat = ::epics::pvData::castUnsafe(epicsNAN); + *out << "Cast double NAN to float NAN yields: "< Date: Thu, 18 Apr 2013 13:53:19 -0400 Subject: [PATCH 003/103] parseToPOD: fix 64-bit Try again to detect if uint16_t is long or long long. --- pvDataApp/misc/parseToPOD.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pvDataApp/misc/parseToPOD.cpp b/pvDataApp/misc/parseToPOD.cpp index a047348..4a3efcc 100644 --- a/pvDataApp/misc/parseToPOD.cpp +++ b/pvDataApp/misc/parseToPOD.cpp @@ -12,6 +12,11 @@ #include "typeCast.h" +// need to use "long long" when sizeof(int)==sizeof(long) +#if ULONG_MAX == 0xfffffffful +#define NEED_LONGLONG +#endif + #ifndef EPICS_VERSION_INT #define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P)) #define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL) @@ -241,7 +246,7 @@ epicsParseFloat(const char *str, float *to, char **units) #endif /* do we need long long? */ -#if INT_MAX == LONG_MAX +#ifdef NEED_LONGLONG static int epicsParseLongLong(const char *str, long long *to, int base, char **units) { @@ -343,7 +348,7 @@ INTFN(int32_t, Int32); INTFN(uint32_t, UInt32); void parseToPOD(const std::string& in, int64_t *out) { -#if INT_MAX == LONG_MAX +#ifdef NEED_LONGLONG int err = epicsParseLongLong(in.c_str(), out, 0, NULL); #else int err = epicsParseLong(in.c_str(), out, 0, NULL); @@ -352,7 +357,7 @@ void parseToPOD(const std::string& in, int64_t *out) { } void parseToPOD(const std::string& in, uint64_t *out) { -#if INT_MAX == LONG_MAX +#ifdef NEED_LONGLONG int err = epicsParseULongLong(in.c_str(), out, 0, NULL); #else int err = epicsParseULong(in.c_str(), out, 0, NULL); From 0e57391b4dd1384ccea408d73687841fb25ffc9e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 22 Apr 2013 11:56:38 -0400 Subject: [PATCH 004/103] vxWorks compatibility --- pvDataApp/misc/parseToPOD.cpp | 93 +++++++++++++++++++++++++++++++++++ pvDataApp/misc/typeCast.h | 2 +- pvDataApp/pv/pvType.h | 2 + testApp/misc/testTypeCast.cpp | 13 +++++ 4 files changed, 109 insertions(+), 1 deletion(-) diff --git a/pvDataApp/misc/parseToPOD.cpp b/pvDataApp/misc/parseToPOD.cpp index 4a3efcc..6fad99f 100644 --- a/pvDataApp/misc/parseToPOD.cpp +++ b/pvDataApp/misc/parseToPOD.cpp @@ -245,6 +245,99 @@ epicsParseFloat(const char *str, float *to, char **units) } #endif +#if defined(NEED_LONGLONG) && defined(__vxworks) +static +long long strtoll(const char *ptr, char ** endp, int base) +{ + size_t inlen = strlen(ptr); + long long result; + unsigned char offset=0; + + assert(base==0); + + if(ptr[0]=='-') + offset=1; + + try { + std::istringstream strm(ptr); + + assert(strm.rdbuf()->in_avail()>=0 + && inlen==(size_t)strm.rdbuf()->in_avail()); + + if(ptr[offset]=='0') { + if(ptr[offset+1]=='x') + strm >> std::hex; + else + strm >> std::oct; + } + + strm >> result; + if(strm.fail()) + goto noconvert; + + assert(strm.rdbuf()->in_avail()>=0 + && inlen>=(size_t)strm.rdbuf()->in_avail()); + + size_t consumed = inlen - strm.rdbuf()->in_avail(); + *endp = (char*)ptr + consumed; + + return result; + + } catch(...) { + goto noconvert; + } + + return result; +noconvert: + *endp = (char*)ptr; + return 0; +} + +static +unsigned long long strtoull(const char *ptr, char ** endp, int base) +{ + size_t inlen = strlen(ptr); + unsigned long long result; + + assert(base==0); + + try { + std::istringstream strm(ptr); + + assert(strm.rdbuf()->in_avail()>=0 + && inlen==(size_t)strm.rdbuf()->in_avail()); + + if(ptr[0]=='0') { + if(ptr[1]=='x') + strm >> std::hex; + else + strm >> std::oct; + } + + strm >> result; + if(strm.fail()) + goto noconvert; + + assert(strm.rdbuf()->in_avail()>=0 + && inlen>=(size_t)strm.rdbuf()->in_avail()); + + size_t consumed = inlen - strm.rdbuf()->in_avail(); + *endp = (char*)ptr + consumed; + + return result; + + } catch(...) { + goto noconvert; + } + + return result; +noconvert: + *endp = (char*)ptr; + return 0; +} + +#endif + /* do we need long long? */ #ifdef NEED_LONGLONG static int diff --git a/pvDataApp/misc/typeCast.h b/pvDataApp/misc/typeCast.h index dbf8b1a..b49fcb8 100644 --- a/pvDataApp/misc/typeCast.h +++ b/pvDataApp/misc/typeCast.h @@ -15,7 +15,7 @@ #include // gently nudge the compiler to inline our wrappers -#if defined(__GNUC__) +#if defined(__GNUC__) && __GNUC__>=3 # define FORCE_INLINE __attribute__((always_inline)) inline #elif defined(_MSC_VER) # define FORCE_INLINE __forceinline diff --git a/pvDataApp/pv/pvType.h b/pvDataApp/pv/pvType.h index 93eb1f2..b9ffce7 100644 --- a/pvDataApp/pv/pvType.h +++ b/pvDataApp/pv/pvType.h @@ -20,8 +20,10 @@ #ifdef __vxworks typedef int intptr_t; typedef unsigned int uintptr_t; +#ifndef INT64_MAX #define INT64_MAX (0x7fffffffffffffffLL) #define UINT64_MAX (0xffffffffffffffffLL) +#endif #else #include #endif diff --git a/testApp/misc/testTypeCast.cpp b/testApp/misc/testTypeCast.cpp index 239bf70..a7ca746 100644 --- a/testApp/misc/testTypeCast.cpp +++ b/testApp/misc/testTypeCast.cpp @@ -350,10 +350,23 @@ int main(int argc,char *argv[]) TEST(int32_t, -7, String, "-07"); TEST(int32_t, -8, String, "-010"); + TEST(int64_t, 15, String, "0xf"); + TEST(int64_t, 15, String, "0xF"); + TEST(int64_t, -15, String, "-0xF"); + TEST(int64_t, 16, String, "0x10"); + TEST(int64_t, -16, String, "-0x10"); + + TEST(int64_t, 7, String, "07"); + TEST(int64_t, 8, String, "010"); + TEST(int64_t, -7, String, "-07"); + TEST(int64_t, -8, String, "-010"); + *out << "String parsing errors\n"; FAIL(int32_t, String, "hello!"); FAIL(int32_t, String, "42 is the answer"); + FAIL(int64_t, String, "hello!"); + FAIL(int64_t, String, "42 is the answer"); FAIL(double, String, "hello!"); FAIL(double, String, "42 is the answer"); From b0c57e7ae347104116b00fa9daca3ffc19621c86 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 15 Apr 2013 15:25:54 -0400 Subject: [PATCH 005/103] test castUnsafe w/ transform() --- testApp/misc/testTypeCast.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/testApp/misc/testTypeCast.cpp b/testApp/misc/testTypeCast.cpp index a7ca746..376da1c 100644 --- a/testApp/misc/testTypeCast.cpp +++ b/testApp/misc/testTypeCast.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -136,7 +137,8 @@ int main(int argc,char *argv[]) typedef epics::pvData::String String_t; // force all possibilities to be compiled -#define CHECK(M, N) x## M = ::epics::pvData::castUnsafe(x## N) +#define CHECK(M, N) x## M = ::epics::pvData::castUnsafe(x## N); \ + std::transform(&x ## N, &x ## N+1, &x ## M, ::epics::pvData::castUnsafe) //#define CHECK(M, N) x## M = ::epics::pvData::detail::cast_helper::op(x## N) CHECK(int8, int8); CHECK(int8, uint8); From 2f8c43442974ed71f313a9bde58e5a0907104cc8 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 15 Apr 2013 16:18:45 -0400 Subject: [PATCH 006/103] add castUnsafeV non-template version of castUnsafe(FROM v)). --- pvDataApp/Makefile | 1 + pvDataApp/misc/typeCast.cpp | 230 ++++++++++++++++++++++++++++++++++ pvDataApp/misc/typeCast.h | 3 + testApp/misc/testTypeCast.cpp | 16 ++- 4 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 pvDataApp/misc/typeCast.cpp diff --git a/pvDataApp/Makefile b/pvDataApp/Makefile index c496310..88e54e7 100644 --- a/pvDataApp/Makefile +++ b/pvDataApp/Makefile @@ -38,6 +38,7 @@ LIBSRCS += timer.cpp LIBSRCS += status.cpp LIBSRCS += messageQueue.cpp LIBSRCS += localStaticLock.cpp +LIBSRCS += typeCast.cpp LIBSRCS += parseToPOD.cpp SRC_DIRS += $(PVDATA)/pv diff --git a/pvDataApp/misc/typeCast.cpp b/pvDataApp/misc/typeCast.cpp new file mode 100644 index 0000000..6b5ba2a --- /dev/null +++ b/pvDataApp/misc/typeCast.cpp @@ -0,0 +1,230 @@ +/** + * 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 */ +#include + +#include "typeCast.h" + +using epics::pvData::castUnsafe; +using epics::pvData::String; +using epics::pvData::ScalarType; +using epics::pvData::pvString; + +namespace { + +static void noconvert(size_t, void*, const void*) +{ + throw std::runtime_error("castUnsafeV: Conversion not supported"); +} + +template +static void castVTyped(size_t count, void *draw, const void *sraw) +{ + TO *dest=(TO*)draw; + const FROM *src=(FROM*)sraw; + std::transform(src, src+count, dest, castUnsafe); +} + +template +static void copyV(size_t count, void *draw, const void *sraw) +{ + T *dest=(T*)draw; + const T *src=(T*)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] = +{ + // to pvBoolean + { &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert + }, + // to pvByte + {&noconvert, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvShort + {&noconvert, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvInt + {&noconvert, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvLong + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvUByte + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvUShort + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvUInt + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvULong + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvFloat + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + }, + // to pvDouble + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + }, + // to pvString + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + }, +}; + +} // end namespace + +namespace epics { namespace pvData { + +void castUnsafeV(size_t count, ScalarType to, void *dest, ScalarType from, const void *src) +{ + unsigned int ito=to, ifrom=from; + + if(ito>pvString || ifrom>pvString) + throw std::runtime_error("castUnsafeV: Invalid types"); + + converters[ito][ifrom](count, dest, src); +} + +}} diff --git a/pvDataApp/misc/typeCast.h b/pvDataApp/misc/typeCast.h index b49fcb8..e27c585 100644 --- a/pvDataApp/misc/typeCast.h +++ b/pvDataApp/misc/typeCast.h @@ -13,6 +13,7 @@ #include #include +#include // gently nudge the compiler to inline our wrappers #if defined(__GNUC__) && __GNUC__>=3 @@ -170,6 +171,8 @@ static FORCE_INLINE TO castUnsafe(const FROM& from) return detail::cast_helper::op(from); } +void castUnsafeV(size_t count, ScalarType to, void *dest, ScalarType from, const void *src); + }} // end namespace #undef FORCE_INLINE diff --git a/testApp/misc/testTypeCast.cpp b/testApp/misc/testTypeCast.cpp index 376da1c..d258edc 100644 --- a/testApp/misc/testTypeCast.cpp +++ b/testApp/misc/testTypeCast.cpp @@ -384,8 +384,22 @@ int main(int argc,char *argv[]) TEST(float, FLT_MIN, double, 1e-300); TEST(float, -FLT_MIN, double, -1e-300); xfloat = ::epics::pvData::castUnsafe(epicsNAN); - *out << "Cast double NAN to float NAN yields: "< String\n"; + epics::pvData::castUnsafeV(3, epics::pvData::pvString, (void*)result, + epics::pvData::pvInt, (void*)in); + *out << "Yields "< Date: Mon, 22 Apr 2013 14:48:59 -0400 Subject: [PATCH 007/103] Convert::getFullName becomes PVField::getFullName Compatibility wrapper using current Convert API Allow PVField::getFieldName to be inline'd Avoid multiple resize and copy operations on result String. --- pvDataApp/factory/Convert.cpp | 15 --------------- pvDataApp/factory/PVField.cpp | 30 +++++++++++++++++++++++++----- pvDataApp/pv/convert.h | 6 +++++- pvDataApp/pv/pvData.h | 9 ++++++++- 4 files changed, 38 insertions(+), 22 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index 40aa52a..0414622 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -421,21 +421,6 @@ Convert::Convert() Convert::~Convert(){} -void Convert::getFullName(StringBuilder buf,PVFieldPtr const & pvField) -{ - buf->empty(); - *buf += pvField->getFieldName(); - PVStructure *parent; - while((parent=pvField->getParent())!=0) { - parent = pvField->getParent(); - String name = parent->getFieldName(); - if(name.length()>0) { - buf->insert(0,"."); - buf->insert(0,name); - } - } -} - bool Convert::equals(PVFieldPtr const &a,PVFieldPtr const &b) { return convertEquals(a.get(),b.get()); diff --git a/pvDataApp/factory/PVField.cpp b/pvDataApp/factory/PVField.cpp index e4574d9..577ccb8 100644 --- a/pvDataApp/factory/PVField.cpp +++ b/pvDataApp/factory/PVField.cpp @@ -64,11 +64,6 @@ void PVField::message(String message,MessageType messageType) PVField::message(message,messageType,""); } -String PVField::getFieldName() const -{ - return fieldName; -} - void PVField::setRequester(RequesterPtr const &req) { if(parent!=NULL) { @@ -223,6 +218,31 @@ namespace format } }; +String PVField::getFullName() const +{ + size_t size=fieldName.size(); + + for(PVField *fld=getParent(); fld; fld=fld->getParent()) + { + size+=fld->fieldName.size()+1; + } + + String ret(size, '.'); + size_t pos=size - fieldName.size(); + + ret.replace(pos, String::npos, fieldName); + + for(PVField *fld=getParent(); fld; fld=fld->getParent()) + { + const String& nref = fld->fieldName; + assert(pos >= nref.size()+1); + pos -= nref.size()+1; + ret.replace(pos, String::npos, nref); + } + assert(pos==0); + return ret; +} + void PVField::computeOffset(const PVField * pvField) { const PVStructure * pvTop = pvField->getParent(); if(pvTop==NULL) { diff --git a/pvDataApp/pv/convert.h b/pvDataApp/pv/convert.h index 266aab2..1fd83dd 100644 --- a/pvDataApp/pv/convert.h +++ b/pvDataApp/pv/convert.h @@ -77,7 +77,11 @@ public: * @param builder The builder that will have the result. * @param pvField The pvField. */ - void getFullName(StringBuilder buf,PVFieldPtr const & pvField); + void getFullName(StringBuilder buf,PVFieldPtr const & pvField) + { + *buf = pvField->getFullName(); + } + /** * Do fields have the same definition. * diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index 4f15742..45098ab 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -244,7 +244,13 @@ public: * Get the fieldName for this field. * @return The name or empty string if top level field. */ - String getFieldName() const ; + inline const String& getFieldName() const {return fieldName;} + /** + * Fully expand the name of this field using the + * names of its parent fields with a dot '.' seperating + * each name. + */ + String getFullName() const; /** * Register the message requester. * At most one requester can be registered. @@ -343,6 +349,7 @@ public: */ virtual std::ostream& dumpValue(std::ostream& o) const = 0; + protected: PVField::shared_pointer getPtrSelf() { From f72c5dba841253ecbb0082ed20f9cdc5244e0ec5 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 22 Apr 2013 15:47:51 -0400 Subject: [PATCH 008/103] PVStructure compare typo --- pvDataApp/factory/Convert.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index 0414622..6093dbe 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -1633,7 +1633,7 @@ static bool structureArrayEquals(PVStructureArray *a,PVStructureArray *b) static bool structureEquals(PVStructure *a,PVStructure *b) { StructureConstPtr aStructure = a->getStructure(); - StructureConstPtr bStructure = a->getStructure(); + StructureConstPtr bStructure = b->getStructure(); size_t length = aStructure->getNumberFields(); if(length!=bStructure->getNumberFields()) return false; PVFieldPtrArray const & aFields = a->getPVFields(); From c1b6d26b8e1f5d8e0b61b011645214a5d062f336 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 22 Apr 2013 16:12:03 -0400 Subject: [PATCH 009/103] Convert::equals: move to operator==(PVField&,PVField&) --- pvDataApp/factory/Compare.cpp | 145 +++++++++++++- pvDataApp/factory/Convert.cpp | 346 ---------------------------------- pvDataApp/pv/convert.h | 12 +- 3 files changed, 146 insertions(+), 357 deletions(-) diff --git a/pvDataApp/factory/Compare.cpp b/pvDataApp/factory/Compare.cpp index 9830478..73f928a 100644 --- a/pvDataApp/factory/Compare.cpp +++ b/pvDataApp/factory/Compare.cpp @@ -15,13 +15,6 @@ namespace epics { namespace pvData { -// PVXXX object comparison - -bool operator==(PVField& left, PVField& right) -{ - return getConvert()->equals(left,right); -} - // Introspection object comparision /** Field equality conditions: @@ -101,8 +94,142 @@ bool operator==(const StructureArray& a, const StructureArray& b) return *(a.getStructure().get())==*(b.getStructure().get()); } -namespace nconvert { +// PVXXX object comparison -} // namespace nconvert +namespace { + +// fully typed comparisons + +template +bool compareScalar(PVScalarValue* left, PVScalarValue* right) +{ + return left->get()==right->get(); +} + +template +bool compareArray(PVValueArray* left, PVValueArray* right) +{ + return std::equal(left->get(), left->get()+left->getLength(), right->get()); +} + +// partially typed comparisons + +bool compareField(PVScalar* left, PVScalar* right) +{ + ScalarType lht = left->getScalar()->getScalarType(); + if(lht != right->getScalar()->getScalarType()) + return false; + switch(lht) { +#define OP(ENUM, TYPE) case ENUM: return compareScalar(static_cast*>(left), static_cast*>(right)) + OP(pvBoolean, uint8); + OP(pvUByte, uint8); + OP(pvByte, int8); + OP(pvUShort, uint16); + OP(pvShort, int16); + OP(pvUInt, uint32); + OP(pvInt, int32); + OP(pvULong, uint64); + OP(pvLong, int64); + OP(pvFloat, float); + OP(pvDouble, double); +#undef OP + case pvString: { + PVString *a=static_cast(left), *b=static_cast(right); + return a->get()==b->get(); + } + } + throw std::logic_error("PVScalar with invalid scalar type!"); +} + +bool compareField(PVScalarArray* left, PVScalarArray* right) +{ + ScalarType lht = left->getScalarArray()->getElementType(); + if(lht != right->getScalarArray()->getElementType()) + return false; + + if(left->getLength()!=right->getLength()) + return false; + + switch(lht) { +#define OP(ENUM, TYPE) case ENUM: return compareArray(static_cast*>(left), static_cast*>(right)) + OP(pvBoolean, uint8); + OP(pvUByte, uint8); + OP(pvByte, int8); + OP(pvUShort, uint16); + OP(pvShort, int16); + OP(pvUInt, uint32); + OP(pvInt, int32); + OP(pvULong, uint64); + OP(pvLong, int64); + OP(pvFloat, float); + OP(pvDouble, double); + OP(pvString, String); +#undef OP + } + throw std::logic_error("PVScalarArray with invalid element type!"); +} + +bool compareField(PVStructure* left, PVStructure* right) +{ + if(left->getStructure()!=right->getStructure()) + return false; + + const PVFieldPtrArray& lf = left->getPVFields(); + const PVFieldPtrArray& rf = right->getPVFields(); + + for(size_t i=0, nfld=left->getNumberFields(); igetLength()!=right->getLength()) + return false; + + StructureConstPtr ls = left->getStructureArray()->getStructure(); + + if(*ls!=*right->getStructureArray()->getStructure()) + return false; + + const PVStructureArray::pointer ld=left->get(), rd=right->get(); + + for(size_t i=0, ilen=left->getLength(); igetPVFields(); + const PVFieldPtrArray& rf = rd[i]->getPVFields(); + + for(size_t k=0, klen=ls->getNumberFields(); kgetType(); + if(lht != right.getField()->getType()) + return false; + + switch(lht) { + case scalar: return compareField(static_cast(&left), static_cast(&right)); + case scalarArray: return compareField(static_cast(&left), static_cast(&right)); + case structure: return compareField(static_cast(&left), static_cast(&right)); + case structureArray: return compareField(static_cast(&left), static_cast(&right)); + } + throw std::logic_error("PVField with invalid type!"); +} }} // namespace epics::pvData diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index 6093dbe..420bd48 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -330,7 +330,6 @@ void Convert::fromDouble(PVScalarPtr const &pv, double from) } -static bool convertEquals(PVField *a,PVField *b); static size_t convertFromByteArray(PVScalarArray * pv, size_t offset, size_t len,const int8 from[], size_t fromOffset); static size_t convertToByteArray(PVScalarArray *pv, size_t offset, @@ -421,16 +420,6 @@ Convert::Convert() Convert::~Convert(){} -bool Convert::equals(PVFieldPtr const &a,PVFieldPtr const &b) -{ - return convertEquals(a.get(),b.get()); -} - -bool Convert::equals(PVField &a,PVField &b) -{ - return convertEquals(&a,&b); -} - void Convert::getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel) { convertToString(buf,pvField.get(),indentLevel); @@ -1329,341 +1318,6 @@ void Convert::newLine(StringBuilder buffer, int indentLevel) newLineImpl(buffer,indentLevel); } -static bool scalarEquals(PVScalar *a,PVScalar *b) -{ - ScalarType ascalarType = a->getScalar()->getScalarType(); - ScalarType bscalarType = b->getScalar()->getScalarType(); - if(ascalarType!=bscalarType) return false; - switch(ascalarType) { - case pvBoolean: { - PVBoolean *pa = static_cast(a); - PVBoolean *pb = static_cast(b); - bool avalue = pa->get(); - bool bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvByte: { - PVByte *pa = static_cast(a); - PVByte *pb = static_cast(b); - int8 avalue = pa->get(); - int8 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvShort: { - PVShort *pa = static_cast(a); - PVShort *pb = static_cast(b); - int16 avalue = pa->get(); - int16 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvInt: { - PVInt *pa = static_cast(a); - PVInt *pb = static_cast(b); - int32 avalue = pa->get(); - int32 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvLong: { - PVLong *pa = static_cast(a); - PVLong *pb = static_cast(b); - int64 avalue = pa->get(); - int64 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvUByte: { - PVUByte *pa = static_cast(a); - PVUByte *pb = static_cast(b); - uint8 avalue = pa->get(); - uint8 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvUShort: { - PVUShort *pa = static_cast(a); - PVUShort *pb = static_cast(b); - uint16 avalue = pa->get(); - uint16 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvUInt: { - PVUInt *pa = static_cast(a); - PVUInt *pb = static_cast(b); - uint32 avalue = pa->get(); - uint32 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvULong: { - PVULong *pa = static_cast(a); - PVULong *pb = static_cast(b); - uint64 avalue = pa->get(); - uint64 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvFloat: { - PVFloat *pa = static_cast(a); - PVFloat *pb = static_cast(b); - float avalue = pa->get(); - float bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvDouble: { - PVDouble *pa = static_cast(a); - PVDouble *pb = static_cast(b); - double avalue = pa->get(); - double bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvString: { - PVString *pa = static_cast(a); - PVString *pb = static_cast(b); - String avalue = pa->get(); - String bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - } - String message("should not get here"); - throw std::logic_error(message); -} - -static bool arrayEquals(PVScalarArray *a,PVScalarArray *b) -{ - if(a==b) return true; - ScalarType aType = a->getScalarArray()->getElementType(); - ScalarType bType = b->getScalarArray()->getElementType(); - if(aType!=bType) return false; - if(a->getLength()!=b->getLength()) return false; - size_t length = a->getLength(); - switch(aType) { - case pvBoolean: { - PVBooleanArray *aarray = static_cast(a); - PVBooleanArray *barray = static_cast(b); - BooleanArrayData adata; - BooleanArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - BooleanArray & avalue = adata.data; - BooleanArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVByteArray *barray = static_cast(b); - ByteArrayData adata; - ByteArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - ByteArray & avalue = adata.data; - ByteArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVShortArray *barray = static_cast(b); - ShortArrayData adata; - ShortArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - ShortArray & avalue = adata.data; - ShortArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVIntArray *barray = static_cast(b); - IntArrayData adata; - IntArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - IntArray & avalue = adata.data; - IntArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVLongArray *barray = static_cast(b); - LongArrayData adata; - LongArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - LongArray & avalue = adata.data; - LongArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVUByteArray *barray = static_cast(b); - UByteArrayData adata; - UByteArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - UByteArray & avalue = adata.data; - UByteArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVUShortArray *barray = static_cast(b); - UShortArrayData adata; - UShortArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - UShortArray & avalue = adata.data; - UShortArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVUIntArray *barray = static_cast(b); - UIntArrayData adata; - UIntArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - UIntArray & avalue = adata.data; - UIntArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVULongArray *barray = static_cast(b); - ULongArrayData adata; - ULongArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - ULongArray & avalue = adata.data; - ULongArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVFloatArray *barray = static_cast(b); - FloatArrayData adata; - FloatArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - FloatArray & avalue = adata.data; - FloatArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVDoubleArray *barray = static_cast(b); - DoubleArrayData adata; - DoubleArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - DoubleArray & avalue = adata.data; - DoubleArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVStringArray *barray = static_cast(b); - StringArrayData adata; - StringArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - StringArray & avalue = adata.data; - StringArray & bvalue = bdata.data; - for(size_t i=0; igetStructureArray()->getStructure(); - StructureConstPtr bStructure = b->getStructureArray()->getStructure(); - if(aStructure!=bStructure) return false; - if(a->getLength()!=b->getLength()) return false; - StructureArrayData aData = StructureArrayData(); - StructureArrayData bData = StructureArrayData(); - size_t length = a->getLength(); - PVStructurePtrArray & aArray = aData.data; - PVStructurePtrArray & bArray = bData.data; - if(aArray==bArray) return true; - for(size_t i=0; igetStructure(); - StructureConstPtr bStructure = b->getStructure(); - size_t length = aStructure->getNumberFields(); - if(length!=bStructure->getNumberFields()) return false; - PVFieldPtrArray const & aFields = a->getPVFields(); - PVFieldPtrArray const & bFields = b->getPVFields(); - for(size_t i=0; i(a); - void * bvoid = static_cast(b); - if(avoid==bvoid) return true; - Type atype = a->getField()->getType(); - Type btype = b->getField()->getType(); - if(atype!=btype) return false; - if(atype==scalar) return scalarEquals( - static_cast(a),static_cast(b)); - if(atype==scalarArray) return arrayEquals( - static_cast(a),static_cast(b)); - if(atype==structureArray) return structureArrayEquals( - static_cast(a),static_cast(b)); - if(atype==structure) return structureEquals( - static_cast(a),static_cast(b)); - String message("should not get here"); - throw std::logic_error(message); -} - template size_t convertFromScalarArray(PVScalarArray *pv, size_t offset, size_t len,const T from[], size_t fromOffset) diff --git a/pvDataApp/pv/convert.h b/pvDataApp/pv/convert.h index 1fd83dd..3df3325 100644 --- a/pvDataApp/pv/convert.h +++ b/pvDataApp/pv/convert.h @@ -89,7 +89,11 @@ public: * @param Second field * @return (false, true) if the fields (are not, are) the same. */ - bool equals(PVFieldPtr const &a,PVFieldPtr const &b); + bool equals(PVFieldPtr const &a,PVFieldPtr const &b) + { + return *a==*b; + } + /** * Do fields have the same definition. * @@ -97,7 +101,11 @@ public: * @param Second field * @return (false, true) if the fields (are not, are) the same. */ - bool equals(PVField &a,PVField &b); + bool equals(PVField &a,PVField &b) + { + return a==b; + } + /** * Convert a PVField to a string. * @param buf buffer for the result From 5e689f94f4d2e1eb78d62b1b277991f91bada89a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 26 Apr 2013 15:44:05 -0400 Subject: [PATCH 010/103] add PVScalar::getAs and PVScalar::putFrom Allow get/put to a scalar without knowledge of ScalarType Currently won't work correctly for PVBoolean --- pvDataApp/factory/PVDataCreateFactory.cpp | 13 ++++++ pvDataApp/pv/pvData.h | 51 +++++++++++++++++++++++ pvDataApp/pv/pvIntrospect.h | 24 +++++++++++ 3 files changed, 88 insertions(+) diff --git a/pvDataApp/factory/PVDataCreateFactory.cpp b/pvDataApp/factory/PVDataCreateFactory.cpp index baf1047..a3fe68b 100644 --- a/pvDataApp/factory/PVDataCreateFactory.cpp +++ b/pvDataApp/factory/PVDataCreateFactory.cpp @@ -28,6 +28,19 @@ using std::min; namespace epics { namespace pvData { +//template<> const ScalarType PVBoolean::typeCode = pvBoolean; +template<> const ScalarType PVByte::typeCode = pvByte; +template<> const ScalarType PVShort::typeCode = pvShort; +template<> const ScalarType PVInt::typeCode = pvInt; +template<> const ScalarType PVLong::typeCode = pvLong; +template<> const ScalarType PVUByte::typeCode = pvUByte; +template<> const ScalarType PVUShort::typeCode = pvUShort; +template<> const ScalarType PVUInt::typeCode = pvUInt; +template<> const ScalarType PVULong::typeCode = pvULong; +template<> const ScalarType PVFloat::typeCode = pvFloat; +template<> const ScalarType PVDouble::typeCode = pvDouble; +template<> const ScalarType PVScalarValue::typeCode = pvString; + /** Default storage for scalar values */ template diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index 45098ab..418bc43 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -18,6 +18,7 @@ #include #include #include +#include namespace epics { namespace pvData { @@ -396,6 +397,41 @@ public: * @return the interface. */ const ScalarConstPtr getScalar() const ; + + /** + * Convert and return the scalar value in the requested type. + * Result type is determined from the function template argument + * which must be one of the ScalarType enums. + * Uses castUnsafe() for value conversion. + @code + PVScalar* pv = ...; + uint32 val = pv->getAs(); + @endcode + */ + template + inline typename ScalarTypeTraits::type getAs() const { + typename ScalarTypeTraits::type result; + this->getAs((void*)&result, ID); + return result; + } + virtual void getAs(void *, ScalarType) const = 0; + + /** + * Convert and assign the provided value. + * The value type is determined from the function template argument + * which must be one of the ScalarType enums. + * Uses castUnsafe() for value conversion. + @code + PVScalar* pv = ...; + pv->putFrom((int32)42); + @endcode + */ + template + inline void putFrom(typename ScalarTypeTraits::type val) { + this->putFrom((const void*)&val, ID); + } + virtual void putFrom(const void *, ScalarType) = 0; + protected: PVScalar(ScalarConstPtr const & scalar); }; @@ -410,6 +446,9 @@ public: typedef T value_type; typedef T* pointer; typedef const T* const_pointer; + + static const ScalarType typeCode; + /** * Destructor */ @@ -447,6 +486,18 @@ public: protected: PVScalarValue(ScalarConstPtr const & scalar) : PVScalar(scalar) {} + virtual void getAs(void * result, ScalarType rtype) const + { + const T src = get(); + castUnsafeV(1, rtype, result, typeCode, (const void*)&src); + } + virtual void putFrom(const void *src, ScalarType stype) + { + T result; + castUnsafeV(1, typeCode, (void*)&result, stype, src); + put(result); + } + private: friend class PVDataCreate; }; diff --git a/pvDataApp/pv/pvIntrospect.h b/pvDataApp/pv/pvIntrospect.h index defd954..9f3179d 100644 --- a/pvDataApp/pv/pvIntrospect.h +++ b/pvDataApp/pv/pvIntrospect.h @@ -555,5 +555,29 @@ private: */ extern FieldCreatePtr getFieldCreate(); +/** + * Static mapping from ScalarType enum to value type. + @code + typename ScalarTypeTraits::type value = 4; + @endcode + */ +template +struct ScalarTypeTraits {}; + +#define OP(ENUM, TYPE) template<> struct ScalarTypeTraits {typedef TYPE type;} +OP(pvBoolean, boolean); +OP(pvByte, int8); +OP(pvShort, int16); +OP(pvInt, int32); +OP(pvLong, int64); +OP(pvUByte, uint8); +OP(pvUShort, uint16); +OP(pvUInt, uint32); +OP(pvULong, uint64); +OP(pvFloat, float); +OP(pvDouble, double); +OP(pvString, String); +#undef OP + }} #endif /* PVINTROSPECT_H */ From e6e1434fc1bc3f5108c3a654b70d2b73fe55fb17 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 26 Apr 2013 15:54:39 -0400 Subject: [PATCH 011/103] Add PrinterPlain --- pvDataApp/Makefile | 2 + pvDataApp/factory/printer.cpp | 138 ++++++++++++++++++++++++++++++++++ pvDataApp/pv/printer.h | 60 +++++++++++++++ 3 files changed, 200 insertions(+) create mode 100644 pvDataApp/factory/printer.cpp create mode 100644 pvDataApp/pv/printer.h diff --git a/pvDataApp/Makefile b/pvDataApp/Makefile index 88e54e7..bd628a4 100644 --- a/pvDataApp/Makefile +++ b/pvDataApp/Makefile @@ -25,6 +25,7 @@ INC += status.h INC += sharedPtr.h INC += localStaticLock.h INC += typeCast.h +INC += printer.h LIBSRCS += byteBuffer.cpp LIBSRCS += bitSet.cpp @@ -67,6 +68,7 @@ LIBSRCS += Convert.cpp LIBSRCS += Compare.cpp LIBSRCS += StandardField.cpp LIBSRCS += StandardPVField.cpp +LIBSRCS += printer.cpp SRC_DIRS += $(PVDATA)/property diff --git a/pvDataApp/factory/printer.cpp b/pvDataApp/factory/printer.cpp new file mode 100644 index 0000000..1b39ecc --- /dev/null +++ b/pvDataApp/factory/printer.cpp @@ -0,0 +1,138 @@ + +#include "pv/printer.h" + +namespace { + +void indentN(std::ostream& strm, size_t N) +{ + while(N--) + strm.put(' '); +} + +} + +namespace epics { namespace pvData { + +PrinterBase::PrinterBase() + :strm(NULL) +{} + +PrinterBase::~PrinterBase() {} + +void PrinterBase::setStream(std::ostream& s) +{ + strm = &s; +} + +void PrinterBase::clearStream() +{ + strm = NULL; +} + +void PrinterBase::print(const PVField& pv) +{ + if(!strm) + throw std::runtime_error("No stream set for PV Printer"); + impl_print(pv); +} + +void PrinterBase::beginStructure(const PVStructure&) {} +void PrinterBase::endStructure(const PVStructure&) {} + +void PrinterBase::beginStructureArray(const PVStructureArray&) {} +void PrinterBase::endStructureArray(const PVStructureArray&) {} + +void PrinterBase::encodeScalar(const PVScalar& pv) {} + +void PrinterBase::encodeArray(const PVScalarArray&) {} + +void PrinterBase::abortField(const PVField&) {} + +void PrinterBase::impl_print(const PVField& pv) +{ + try { + switch(pv.getField()->getType()) { + case scalar: encodeScalar(static_cast(pv)); return; + case scalarArray: encodeArray(static_cast(pv)); return; + case structure: { + const PVStructure &fld = static_cast(pv); + const PVFieldPtrArray& vals = fld.getPVFields(); + + beginStructure(fld); + for(size_t i=0, nfld=fld.getNumberFields(); iprint(*vals[i]); + endStructure(fld); + } + case structureArray: { + const PVStructureArray &fld = static_cast(pv); + const PVStructureArray::pointer vals = fld.get(); + + beginStructureArray(fld); + for(size_t i=0, nfld=fld.getLength(); iprint(*vals[i]); + endStructureArray(fld); + } + } + } catch(...) { + abortField(pv); + throw; + } +} + + +PrinterPlain::PrinterPlain() + :PrinterBase() + ,ilvl(0) +{} + +PrinterPlain::~PrinterPlain() {} + +void PrinterPlain::beginStructure(const PVStructure& pv) +{ + indentN(S(), ilvl); + S() << pv.getStructure()->getID() << " " << pv.getFieldName(); + String ename(pv.getExtendsStructureName()); + if(!ename.empty()) + S() << " extends " << ename; + S() << std::endl; + ilvl++; +} + +void PrinterPlain::endStructure(const PVStructure&) {ilvl--;} + +void PrinterPlain::beginStructureArray(const PVStructureArray& pv) +{ + indentN(S(), ilvl); + S() << pv.getStructureArray()->getID() << " " + << pv.getFieldName() << " "; + ilvl++; +} + +void PrinterPlain::endStructureArray(const PVStructureArray&) {ilvl--;} + +void PrinterPlain::encodeScalar(const PVScalar& pv) +{ + indentN(S(), ilvl); + S() << pv.getScalar()->getID() << " " + << pv.getFieldName() << " " + << pv.getAs() << std::endl; +} + +void PrinterPlain::encodeArray(const PVScalarArray& pv) +{ + indentN(S(), ilvl); + StringArray temp(pv.getLength()); // TODO: no copy + pv.getAs(&temp[0], temp.size()); + + S() << pv.getScalarArray()->getID() << " " + << pv.getFieldName() << " ["; + for(size_t i=0, len=pv.getLength(); i + +#include "pvData.h" + +namespace epics { namespace pvData { + +class PrinterBase +{ +public: + virtual void setStream(std::ostream&); + virtual void clearStream(); + + virtual void print(const PVField&); + +protected: + PrinterBase(); + virtual ~PrinterBase()=0; + + virtual void beginStructure(const PVStructure&); + virtual void endStructure(const PVStructure&); + + virtual void beginStructureArray(const PVStructureArray&); + virtual void endStructureArray(const PVStructureArray&); + + virtual void encodeScalar(const PVScalar&); + virtual void encodeArray(const PVScalarArray&); + + virtual void abortField(const PVField&); + + inline std::ostream& S() { return *strm; } + + void impl_print(const PVField&); +private: + std::ostream *strm; +}; + +class PrinterPlain : public PrinterBase +{ + size_t ilvl; +protected: + virtual void beginStructure(const PVStructure&); + virtual void endStructure(const PVStructure&); + + virtual void beginStructureArray(const PVStructureArray&); + virtual void endStructureArray(const PVStructureArray&); + + virtual void encodeScalar(const PVScalar&); + virtual void encodeArray(const PVScalarArray&); + +public: + PrinterPlain(); + virtual ~PrinterPlain(); +}; + +}} + +#endif // PRINTER_H From 4d92bbe541a79ea38b24a1978983f1ae09eda3a2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 26 Apr 2013 15:55:04 -0400 Subject: [PATCH 012/103] Use PrinterPlain in Convert --- pvDataApp/factory/Convert.cpp | 432 +--------------------------------- pvDataApp/pv/convert.h | 9 +- 2 files changed, 13 insertions(+), 428 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index 420bd48..16f8828 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -16,6 +16,7 @@ #include #include #include +#include using std::tr1::static_pointer_cast; using std::size_t; @@ -375,14 +376,6 @@ static size_t convertFromStringArray(PVScalarArray *pv, size_t offset, static size_t convertToStringArray(PVScalarArray *pv, size_t offset, size_t len,StringArray & to, size_t toOffset); -static void convertToString(StringBuilder buffer, - PVField const *pv,int indentLevel); -static void convertStructure(StringBuilder buffer, - PVStructure const *data,int indentLevel); -static void convertArray(StringBuilder buffer, - PVScalarArray const* pv,int indentLevel); -static void convertStructureArray(StringBuilder buffer, - PVStructureArray const * pvdata,int indentLevel); static size_t copyArrayDataReference(PVScalarArray *from,PVArray *to); static size_t copyNumericArray(PVScalarArray *from, size_t offset, PVScalarArray *to, size_t toOffset, size_t len); @@ -420,25 +413,16 @@ Convert::Convert() Convert::~Convert(){} -void Convert::getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel) -{ - convertToString(buf,pvField.get(),indentLevel); -} - -void Convert::getString(StringBuilder buf,PVFieldPtr const & pvField) -{ - convertToString(buf,pvField.get(),0); -} - void Convert::getString(StringBuilder buf,PVField const *pvField,int indentLevel) { - convertToString(buf,pvField,indentLevel); + // TODO indextLevel ignored + std::ostringstream strm; + PrinterPlain p; + p.setStream(strm); + p.print(*pvField); + strm.str().swap(*buf); } -void Convert::getString(StringBuilder buf,PVField const *pvField) -{ - convertToString(buf,pvField,0); -} size_t Convert::fromString(PVStructurePtr const &pvStructure, StringArray const & from, size_t fromStartIndex) { @@ -2227,408 +2211,6 @@ size_t convertToStringArray(PVScalarArray *pv, return ncopy; } - -void convertToString(StringBuilder buffer,PVField const * pv,int indentLevel) -{ - Type type = pv->getField()->getType(); - if(type==scalarArray) { - convertArray(buffer,static_cast(pv),indentLevel); - return; - } - if(type==structure) { - convertStructure(buffer,static_cast(pv),indentLevel); - return; - } - if(type==structureArray) { - convertStructureArray( - buffer,static_cast(pv),indentLevel); - return; - } - PVScalar const *pvScalar = static_cast(pv); - const ScalarConstPtr & pscalar = pvScalar->getScalar(); - ScalarType scalarType = pscalar->getScalarType(); - *buffer += pscalar->getID(); - *buffer += " "; - *buffer += pv->getFieldName(); - *buffer += " "; - switch(scalarType) { - case pvBoolean: { - PVBoolean const *data = static_cast(pv); - bool value = data->get(); - if(value) { - *buffer += "true"; - } else { - *buffer += "false"; - } - } - return; - case pvByte: { - PVByte const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%d",(int)data->get()); - *buffer += xxx; - } - return; - case pvShort: { - PVShort const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%d",(int)data->get()); - *buffer += xxx; - } - return; - case pvInt: { - PVInt const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%d",(int)data->get()); - *buffer += xxx; - } - return; - case pvLong: { - PVLong const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%lld",(long long)data->get()); - *buffer += xxx; - } - return; - case pvUByte: { - PVUByte const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%u",(unsigned int)data->get()); - *buffer += xxx; - } - return; - case pvUShort: { - PVUShort const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%u",(unsigned int)data->get()); - *buffer += xxx; - } - return; - case pvUInt: { - PVUInt const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%u",(unsigned int)data->get()); - *buffer += xxx; - } - return; - case pvULong: { - PVULong const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%llu",(unsigned long long)data->get()); - *buffer += xxx; - } - return; - case pvFloat: { - PVFloat const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%g",data->get()); - *buffer += xxx; - } - return; - case pvDouble: { - PVDouble const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%g",data->get()); - *buffer += xxx; - } - return; - case pvString: { - PVString const *data = static_cast(pv); - *buffer += data->get(); - } - return; - default: - *buffer += "unknown ScalarType"; - } -} - -void convertStructure(StringBuilder buffer,PVStructure const *data,int indentLevel) -{ - *buffer += data->getStructure()->getID() + " " + data->getFieldName(); - String extendsName = data->getExtendsStructureName(); - if(extendsName.length()>0) { - *buffer += " extends " + extendsName; - } - PVFieldPtrArray const & fieldsData = data->getPVFields(); - if (fieldsData.size() != 0) { - int length = data->getStructure()->getNumberFields(); - for(int i=0; itoString(buffer,indentLevel + 1); - } - } -} - -void convertArray(StringBuilder buffer,PVScalarArray const * xxx,int /*indentLevel*/) -{ - PVScalarArray *pv = const_cast(xxx); - ScalarArrayConstPtr array = pv->getScalarArray(); - ScalarType type = array->getElementType(); - *buffer += array->getID() + " " + pv->getFieldName() + " "; - switch(type) { - case pvBoolean: { - PVBooleanArray *pvdata = static_cast(pv); - BooleanArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ","; - size_t num = pvdata->get(i,1,data); - if(num==1) { - BooleanArray & value = data.data; - if(value[data.offset]) { - *buffer += "true"; - } else { - *buffer += "false"; - } - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvByte: { - PVByteArray *pvdata = static_cast(pv); - ByteArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ","; - size_t num = pvdata->get(i,1,data); - if(num==1) { - int val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%d",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvShort: { - PVShortArray *pvdata = static_cast(pv); - ShortArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - int val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%d",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvInt: { - PVIntArray *pvdata = static_cast(pv); - IntArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - int val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%d",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvLong: { - PVLongArray *pvdata = static_cast(pv); - LongArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - int64 val = data.data[data.offset]; - char buf[32]; - sprintf(buf,"%lld",(long long)val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvUByte: { - PVUByteArray *pvdata = static_cast(pv); - UByteArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ","; - size_t num = pvdata->get(i,1,data); - if(num==1) { - unsigned int val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%u",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvUShort: { - PVUShortArray *pvdata = static_cast(pv); - UShortArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - unsigned int val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%u",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvUInt: { - PVUIntArray *pvdata = static_cast(pv); - UIntArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - unsigned int val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%u",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvULong: { - PVULongArray *pvdata = static_cast(pv); - ULongArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - uint64 val = data.data[data.offset]; - char buf[32]; - sprintf(buf,"%llu",(unsigned long long)val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvFloat: { - PVFloatArray *pvdata = static_cast(pv); - FloatArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - float val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%g",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvDouble: { - PVDoubleArray *pvdata = static_cast(pv); - DoubleArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - double val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%g",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += ("]"); - break; - } - case pvString: { - PVStringArray *pvdata = static_cast(pv); - StringArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ","; - size_t num = pvdata->get(i,1,data); - StringArray & value = data.data; - if(num==1) { - if(value[data.offset].length()>0) { - *buffer += value[data.offset].c_str(); - } else { - *buffer += "null"; - } - } else { - *buffer += "null"; - } - } - *buffer += "]"; - break; - } - default: - *buffer += " array element is unknown ScalarType"; - } - if(pv->isImmutable()) { - *buffer += " immutable "; - } -} - -void convertStructureArray(StringBuilder buffer, - PVStructureArray const * xxx,int indentLevel) -{ - PVStructureArray *pvdata = const_cast(xxx); - *buffer += pvdata->getStructureArray()->getID() + " " + pvdata->getFieldName() + " "; - size_t length = pvdata->getLength(); - if(length<=0) { - return; - } - StructureArrayData data = StructureArrayData(); - pvdata->get(0, length, data); - for (size_t i = 0; i < length; i++) { - newLineImpl(buffer, indentLevel + 1); - PVStructurePtr & pvStructure = data.data[i]; - if (pvStructure.get() == 0) { - *buffer += "null"; - } else { - pvStructure->toString(buffer,indentLevel+1); - } - } -} - size_t copyArrayDataReference(PVScalarArray *from,PVArray *to) { ScalarType scalarType = from->getScalarArray()->getElementType(); diff --git a/pvDataApp/pv/convert.h b/pvDataApp/pv/convert.h index 3df3325..b66c073 100644 --- a/pvDataApp/pv/convert.h +++ b/pvDataApp/pv/convert.h @@ -113,14 +113,16 @@ public: * If a PVField is a structure or array be prepared for a very long string. * @param indentLevel indentation level */ - void getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel); + void getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel) + {getString(buf, pvField.get(), indentLevel);} /** * Convert a PVField to a string. * param buf buffer for the result * @param pv The PVField to convert to a string. * If the PVField is a structure or array be prepared for a very long string. */ - void getString(StringBuilder buf,PVFieldPtr const & pvField); + inline void getString(StringBuilder buf,PVFieldPtr const & pvField) + {getString(buf, pvField.get(), 0);} /** * Convert a PVField to a string. * @param buf buffer for the result @@ -135,7 +137,8 @@ public: * @param pv The PVField to convert to a string. * If the PVField is a structure or array be prepared for a very long string. */ - void getString(StringBuilder buf,PVField const * pvField); + void getString(StringBuilder buf,PVField const * pvField) + {getString(buf, pvField, 0);} /** * Convert from an array of String to a PVScalar * @param pv The PV. From f2635c7fdc6474c7b5dddbb84bbc0ec43bf034de Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 26 Apr 2013 17:20:29 -0400 Subject: [PATCH 013/103] Convert::fromString with castUnsafe --- pvDataApp/factory/Convert.cpp | 111 +--------------------------------- pvDataApp/pv/convert.h | 10 ++- 2 files changed, 9 insertions(+), 112 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index 16f8828..1949ba9 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -464,122 +464,15 @@ size_t Convert::fromString(PVStructurePtr const &pvStructure, StringArray const return processed; } - -void Convert::fromString(PVScalarPtr const &pvScalar, String const & from) -{ - ScalarConstPtr scalar = pvScalar->getScalar(); - ScalarType scalarType = scalar->getScalarType(); - switch(scalarType) { - case pvBoolean: { - PVBooleanPtr pv = static_pointer_cast(pvScalar); - bool value = - ((from.compare("true")==0) ? true : false); - pv->put(value); - return; - } - case pvByte : { - PVBytePtr pv = static_pointer_cast(pvScalar); - int ival; - sscanf(from.c_str(),"%d",&ival); - int8 value = ival; - pv->put(value); - return; - } - case pvShort : { - PVShortPtr pv = static_pointer_cast(pvScalar); - int ival; - sscanf(from.c_str(),"%d",&ival); - int16 value = ival; - pv->put(value); - return; - } - case pvInt : { - PVIntPtr pv = static_pointer_cast(pvScalar); - int ival; - sscanf(from.c_str(),"%d",&ival); - int32 value = ival; - pv->put(value); - return; - } - case pvLong : { - PVLongPtr pv = static_pointer_cast(pvScalar); - int64 ival; - sscanf(from.c_str(),"%lld",(long long *)&ival); - int64 value = ival; - pv->put(value); - return; - } - case pvUByte : { - PVUBytePtr pv = static_pointer_cast(pvScalar); - unsigned int ival; - sscanf(from.c_str(),"%u",&ival); - uint8 value = ival; - pv->put(value); - return; - } - case pvUShort : { - PVUShortPtr pv = static_pointer_cast(pvScalar); - unsigned int ival; - sscanf(from.c_str(),"%u",&ival); - uint16 value = ival; - pv->put(value); - return; - } - case pvUInt : { - PVUIntPtr pv = static_pointer_cast(pvScalar); - unsigned int ival; - sscanf(from.c_str(),"%u",&ival); - uint32 value = ival; - pv->put(value); - return; - } - case pvULong : { - PVULongPtr pv = static_pointer_cast(pvScalar); - unsigned long long ival; - sscanf(from.c_str(),"%llu",(long long unsigned int *)&ival); - uint64 value = ival; - pv->put(value); - return; - } - case pvFloat : { - PVFloatPtr pv = static_pointer_cast(pvScalar); - float value; - sscanf(from.c_str(),"%f",&value); - pv->put(value); - return; - } - case pvDouble : { - PVDoublePtr pv = static_pointer_cast(pvScalar); - double value; - sscanf(from.c_str(),"%lf",&value); - pv->put(value); - return; - } - case pvString: { - PVStringPtr value = static_pointer_cast(pvScalar); - value->put(from); - return; - } - } - String message("Convert::fromString unknown scalarType "); - ScalarTypeFunc::toString(&message,scalarType); - throw std::logic_error(message); -} - size_t Convert::fromString(PVScalarArrayPtr const &pv, String from) { if(from[0]=='[' && from[from.length()]==']') { size_t offset = from.rfind(']'); from = from.substr(1, offset); } - std::vector valueList = split(from); + std::vector valueList(split(from)); size_t length = valueList.size(); - StringArray valueArray = StringArray(length); - for(size_t i=0; isetLength(length); return length; diff --git a/pvDataApp/pv/convert.h b/pvDataApp/pv/convert.h index b66c073..a54c258 100644 --- a/pvDataApp/pv/convert.h +++ b/pvDataApp/pv/convert.h @@ -113,7 +113,7 @@ public: * If a PVField is a structure or array be prepared for a very long string. * @param indentLevel indentation level */ - void getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel) + inline void getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel) {getString(buf, pvField.get(), indentLevel);} /** * Convert a PVField to a string. @@ -137,7 +137,7 @@ public: * @param pv The PVField to convert to a string. * If the PVField is a structure or array be prepared for a very long string. */ - void getString(StringBuilder buf,PVField const * pvField) + inline void getString(StringBuilder buf,PVField const * pvField) {getString(buf, pvField, 0);} /** * Convert from an array of String to a PVScalar @@ -156,7 +156,11 @@ public: * @param from The String value to convert and put into a PV. * @throws std::logic_error if the String does not have a valid value. */ - void fromString(PVScalarPtr const & pv, String const & from); + void fromString(PVScalarPtr const & pv, String const & from) + { + pv->putFrom(from); + } + /** * Convert from a String to a PVScalarArray. * The String must be a comma separated set of values optionally enclosed in [] From 0e0ab66d454c262368eed2d6cde8d8c673ac4cb0 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 26 Apr 2013 17:29:22 -0400 Subject: [PATCH 014/103] add PVScalarArray::getAs and PVScalarArray::putFrom --- pvDataApp/factory/PVDataCreateFactory.cpp | 13 +++++++++++ pvDataApp/pv/pvData.h | 27 +++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/pvDataApp/factory/PVDataCreateFactory.cpp b/pvDataApp/factory/PVDataCreateFactory.cpp index a3fe68b..b32d493 100644 --- a/pvDataApp/factory/PVDataCreateFactory.cpp +++ b/pvDataApp/factory/PVDataCreateFactory.cpp @@ -41,6 +41,19 @@ template<> const ScalarType PVFloat::typeCode = pvFloat; template<> const ScalarType PVDouble::typeCode = pvDouble; template<> const ScalarType PVScalarValue::typeCode = pvString; +//template<> const ScalarType PVBooleanArray::typeCode = pvBoolean; +template<> const ScalarType PVByteArray::typeCode = pvByte; +template<> const ScalarType PVShortArray::typeCode = pvShort; +template<> const ScalarType PVIntArray::typeCode = pvInt; +template<> const ScalarType PVLongArray::typeCode = pvLong; +template<> const ScalarType PVUByteArray::typeCode = pvUByte; +template<> const ScalarType PVUShortArray::typeCode = pvUShort; +template<> const ScalarType PVUIntArray::typeCode = pvUInt; +template<> const ScalarType PVULongArray::typeCode = pvULong; +template<> const ScalarType PVFloatArray::typeCode = pvFloat; +template<> const ScalarType PVDoubleArray::typeCode = pvDouble; +template<> const ScalarType PVStringArray::typeCode = pvString; + /** Default storage for scalar values */ template diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index 418bc43..5cd597a 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -646,8 +646,24 @@ public: */ const ScalarArrayConstPtr getScalarArray() const ; + template + inline void getAs(typename ScalarTypeTraits::type* ptr, + size_t count, size_t offset = 0) const + { + getAs(ID, (void*)ptr, count, offset); + } + + template + inline void putFrom(const typename ScalarTypeTraits::type* ptr, + size_t count, size_t offset = 0) + { + putFrom(ID, (const void*)ptr, count, offset); + } + protected: PVScalarArray(ScalarArrayConstPtr const & scalarArray); + virtual void getAs(ScalarType, void*, size_t, size_t) const = 0; + virtual void putFrom(ScalarType, const void*, size_t ,size_t) = 0; private: friend class PVDataCreate; }; @@ -1001,6 +1017,8 @@ public: typedef PVValueArray & reference; typedef const PVValueArray & const_reference; + static const ScalarType typeCode; + /** * Destructor */ @@ -1065,6 +1083,15 @@ protected: PVValueArray(ScalarArrayConstPtr const & scalar) : PVScalarArray(scalar) {} friend class PVDataCreate; + + virtual void getAs(ScalarType dtype, void* ptr, size_t count, size_t offset) const + { + castUnsafeV(count, dtype, ptr, typeCode, (const void*)(get()+offset)); + } + virtual void putFrom(ScalarType dtype, const void*ptr, size_t count, size_t offset) + { + castUnsafeV(count, typeCode, (void*)(get()+offset), dtype, ptr); + } }; template From e85d10c6d90b39a19525e4b7c41b18e283a4164b Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 26 Apr 2013 17:29:52 -0400 Subject: [PATCH 015/103] Convert::fromStringArray with castUnsafe --- pvDataApp/factory/Convert.cpp | 224 ++-------------------------------- 1 file changed, 10 insertions(+), 214 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index 1949ba9..c86c075 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -371,8 +371,6 @@ static size_t convertFromDoubleArray(PVScalarArray *pv, size_t offset, size_t len,const double from[], size_t fromOffset); static size_t convertToDoubleArray(PVScalarArray *pv, size_t offset, size_t len,double to[], size_t toOffset); -static size_t convertFromStringArray(PVScalarArray *pv, size_t offset, - size_t len,const StringArray & from, size_t fromOffset); static size_t convertToStringArray(PVScalarArray *pv, size_t offset, size_t len,StringArray & to, size_t toOffset); @@ -478,10 +476,17 @@ size_t Convert::fromString(PVScalarArrayPtr const &pv, String from) return length; } -size_t Convert::fromStringArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - StringArray const & from, size_t fromOffset) +size_t Convert::fromStringArray(PVScalarArrayPtr const &pv, + size_t offset, size_t length, + StringArray const & from, + size_t fromOffset) { - return convertFromStringArray(pv.get(),offset,length,from,fromOffset); + size_t alen = pv->getLength(); + if(fromOffset>alen) return 0; + alen -= fromOffset; + if(length>alen) length=alen; + pv->putFrom(&from[fromOffset], length, offset); + return length; } size_t Convert::toStringArray(PVScalarArrayPtr const & pv, size_t offset, size_t length, @@ -1683,215 +1688,6 @@ size_t convertToDoubleArray(PVScalarArray * pv, return convertToScalarArray(pv,offset,len,to,toOffset); } -size_t convertFromStringArray(PVScalarArray *pv, - size_t offset, size_t len,const StringArray & from, size_t fromOffset) -{ - ScalarType elemType = pv->getScalarArray()->getElementType(); - size_t ntransfered = 0; - switch (elemType) { - case pvBoolean: { - PVBooleanArray *pvdata = static_cast(pv); - boolean data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - data[0] = (fromString.compare("true")==0) ? true : false; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvByte: { - PVByteArray *pvdata = static_cast(pv); - int8 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - int ival; - sscanf(fromString.c_str(),"%d",&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvShort: { - PVShortArray *pvdata = static_cast(pv); - int16 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - int ival; - sscanf(fromString.c_str(),"%d",&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvInt: { - PVIntArray *pvdata = static_cast(pv); - int32 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - int ival; - sscanf(fromString.c_str(),"%d",&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvLong: { - PVLongArray *pvdata = static_cast(pv); - int64 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - int64 ival; - sscanf(fromString.c_str(),"%lld",(long long int *)&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvUByte: { - PVUByteArray *pvdata = static_cast(pv); - uint8 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - unsigned int ival; - sscanf(fromString.c_str(),"%u",&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvUShort: { - PVUShortArray *pvdata = static_cast(pv); - uint16 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - unsigned int ival; - sscanf(fromString.c_str(),"%u",&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvUInt: { - PVUIntArray *pvdata = static_cast(pv); - uint32 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - unsigned int ival; - sscanf(fromString.c_str(),"%u",&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvULong: { - PVULongArray *pvdata = static_cast(pv); - uint64 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - uint64 ival; - sscanf(fromString.c_str(),"%lld",(unsigned long long int *)&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvFloat: { - PVFloatArray *pvdata = static_cast(pv); - float data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - float fval; - sscanf(fromString.c_str(),"%f",&fval); - data[0] = fval; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvDouble: { - PVDoubleArray *pvdata = static_cast(pv); - double data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - double fval; - sscanf(fromString.c_str(),"%lf",&fval); - data[0] = fval; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvString: - PVStringArray *pvdata = static_cast(pv); - while (len > 0) { - String * xxx = const_cast(get(from)); - size_t n = pvdata->put(offset, len, xxx, fromOffset); - if (n == 0) - break; - len -= n; - offset += n; - fromOffset += n; - ntransfered += n; - } - return ntransfered; - } - String message("Convert::convertFromStringArray should never get here"); - throw std::logic_error(message); -} - size_t convertToStringArray(PVScalarArray *pv, size_t offset, size_t len,StringArray & xxx, size_t toOffset) { From 2062cc5d1079a4d510225ec3a80aa49d65b36174 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 26 Apr 2013 17:36:37 -0400 Subject: [PATCH 016/103] Convert::toStringArray with castUnsafe --- pvDataApp/factory/Convert.cpp | 226 ++-------------------------------- 1 file changed, 9 insertions(+), 217 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index c86c075..0d8dc07 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -371,8 +371,6 @@ static size_t convertFromDoubleArray(PVScalarArray *pv, size_t offset, size_t len,const double from[], size_t fromOffset); static size_t convertToDoubleArray(PVScalarArray *pv, size_t offset, size_t len,double to[], size_t toOffset); -static size_t convertToStringArray(PVScalarArray *pv, size_t offset, - size_t len,StringArray & to, size_t toOffset); static size_t copyArrayDataReference(PVScalarArray *from,PVArray *to); static size_t copyNumericArray(PVScalarArray *from, @@ -489,10 +487,16 @@ size_t Convert::fromStringArray(PVScalarArrayPtr const &pv, return length; } -size_t Convert::toStringArray(PVScalarArrayPtr const & pv, size_t offset, size_t length, - StringArray &to, size_t toOffset) +size_t Convert::toStringArray(PVScalarArrayPtr const & pv, + size_t offset, size_t length, + StringArray &to, size_t toOffset) { - return convertToStringArray(pv.get(),offset,length,to,toOffset); + size_t alen = pv->getLength(); + if(offset>alen) return 0; + alen -= offset; + if(length>alen) length=alen; + pv->getAs(&to[toOffset], length, offset); + return length; } bool Convert::isCopyCompatible(FieldConstPtr const &from, FieldConstPtr const &to) @@ -1688,218 +1692,6 @@ size_t convertToDoubleArray(PVScalarArray * pv, return convertToScalarArray(pv,offset,len,to,toOffset); } -size_t convertToStringArray(PVScalarArray *pv, - size_t offset, size_t len,StringArray & xxx, size_t toOffset) -{ - String *to = &xxx[0]; - ScalarType elementType = pv->getScalarArray()->getElementType(); - size_t ncopy = pv->getLength(); - if (ncopy > len) ncopy = len; - size_t num = ncopy; - switch (elementType) { - case pvBoolean: { - PVBooleanArray *pvdata = static_cast(pv); - BooleanArrayData data; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - BooleanArray & dataArray = data.data; - bool value = dataArray[data.offset]; - to[toOffset + i] = value ? "true" : "false"; - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvByte: { - PVByteArray *pvdata = static_cast(pv); - ByteArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - ByteArray & dataArray = data.data; - int ival = dataArray[data.offset]; - sprintf(cr,"%d",ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvShort: { - PVShortArray *pvdata = static_cast(pv); - ShortArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - ShortArray & dataArray = data.data; - int ival = dataArray[data.offset]; - sprintf(cr,"%d",ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvInt: { - PVIntArray *pvdata = static_cast(pv); - IntArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - IntArray & dataArray = data.data; - int ival = dataArray[data.offset]; - sprintf(cr,"%d",ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvLong: { - PVLongArray *pvdata = static_cast(pv); - LongArrayData data = LongArrayData(); - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - LongArray & dataArray = data.data; - int64 ival = dataArray[data.offset]; - sprintf(cr,"%lld",(long long)ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvUByte: { - PVUByteArray *pvdata = static_cast(pv); - UByteArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - UByteArray & dataArray = data.data; - unsigned int ival = dataArray[data.offset]; - sprintf(cr,"%u",ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvUShort: { - PVUShortArray *pvdata = static_cast(pv); - UShortArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - UShortArray & dataArray = data.data; - unsigned int ival = dataArray[data.offset]; - sprintf(cr,"%u",ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvUInt: { - PVUIntArray *pvdata = static_cast(pv); - UIntArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - UIntArray & dataArray = data.data; - unsigned int ival = dataArray[data.offset]; - sprintf(cr,"%u",ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvULong: { - PVULongArray *pvdata = static_cast(pv); - ULongArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - ULongArray & dataArray = data.data; - uint64 ival = dataArray[data.offset]; - sprintf(cr,"%llu",(unsigned long long)ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvFloat: { - PVFloatArray *pvdata = static_cast(pv); - FloatArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - FloatArray & dataArray = data.data; - float fval = dataArray[data.offset]; - sprintf(cr,"%g",fval); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvDouble: { - PVDoubleArray *pvdata = static_cast(pv); - DoubleArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - DoubleArray & dataArray = data.data; - double fval = dataArray[data.offset]; - sprintf(cr,"%g",fval); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvString: { - PVStringArray *pvdata = static_cast(pv); - while (num > 0) { - size_t numnow = 0; - size_t dataOffset = 0; - String *dataArray; - StringArrayData stringArrayData; - numnow = pvdata->get(offset, num, stringArrayData); - dataArray = pvdata->get(); - dataOffset = stringArrayData.offset; - if (numnow <= 0) { - for (size_t i = 0; i < num; i++) - to[toOffset + i] = "bad pv"; - break; - } - for(size_t i=0; igetScalarArray()->getElementType(); From e948af18513b8bb5ded0c18dd9c56666f439e13d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 26 Apr 2013 18:27:17 -0400 Subject: [PATCH 017/103] PVScalar::assign and PVScalarArray::assign --- pvDataApp/pv/pvData.h | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index 5cd597a..b7e3e0d 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -432,6 +432,8 @@ public: } virtual void putFrom(const void *, ScalarType) = 0; + virtual void assign(const PVScalar&) = 0; + protected: PVScalar(ScalarConstPtr const & scalar); }; @@ -497,6 +499,12 @@ protected: castUnsafeV(1, typeCode, (void*)&result, stype, src); put(result); } + virtual void assign(const PVScalar& scalar) + { + T result; + scalar.getAs((void*)&result, typeCode); + put(result); + } private: friend class PVDataCreate; @@ -652,6 +660,7 @@ public: { getAs(ID, (void*)ptr, count, offset); } + virtual void getAs(ScalarType, void*, size_t, size_t) const = 0; template inline void putFrom(const typename ScalarTypeTraits::type* ptr, @@ -659,11 +668,12 @@ public: { putFrom(ID, (const void*)ptr, count, offset); } + virtual void putFrom(ScalarType, const void*, size_t ,size_t) = 0; + + virtual void assign(const PVScalarArray& pv) = 0; protected: PVScalarArray(ScalarArrayConstPtr const & scalarArray); - virtual void getAs(ScalarType, void*, size_t, size_t) const = 0; - virtual void putFrom(ScalarType, const void*, size_t ,size_t) = 0; private: friend class PVDataCreate; }; @@ -1079,11 +1089,6 @@ public: return o << *(get() + index); } -protected: - PVValueArray(ScalarArrayConstPtr const & scalar) - : PVScalarArray(scalar) {} - friend class PVDataCreate; - virtual void getAs(ScalarType dtype, void* ptr, size_t count, size_t offset) const { castUnsafeV(count, dtype, ptr, typeCode, (const void*)(get()+offset)); @@ -1092,6 +1097,17 @@ protected: { castUnsafeV(count, typeCode, (void*)(get()+offset), dtype, ptr); } + + virtual void assign(const PVScalarArray& pv) + { + setLength(pv.getLength()); + pv.getAs(typeCode, (void*)get(), std::min(getLength(),pv.getLength()), 0); + } + +protected: + PVValueArray(ScalarArrayConstPtr const & scalar) + : PVScalarArray(scalar) {} + friend class PVDataCreate; }; template From a6bfab2d7494f82adafe5bc8a2bfc703f6f9017c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 30 Apr 2013 13:53:55 -0400 Subject: [PATCH 018/103] replace copyScalarArray with PVScalarArray::assign --- pvDataApp/factory/Convert.cpp | 195 +--------------------- pvDataApp/factory/PVDataCreateFactory.cpp | 2 +- pvDataApp/pv/convert.h | 16 -- pvDataApp/pv/pvData.h | 17 +- testApp/pv/testConvert.cpp | 32 ++-- 5 files changed, 34 insertions(+), 228 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index 0d8dc07..ced8c69 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -546,8 +546,7 @@ void Convert::copy(PVFieldPtr const & from, PVFieldPtr const & to) { PVScalarArrayPtr fromArray = static_pointer_cast(from); PVScalarArrayPtr toArray = static_pointer_cast(to); - size_t length = copyScalarArray(fromArray,0,toArray,0,fromArray->getLength()); - if(toArray->getLength()!=length) toArray->setLength(length); + toArray->assign(*fromArray.get()); return; } case structure: @@ -586,98 +585,7 @@ void Convert::copyScalar(PVScalarPtr const & from, PVScalarPtr const & to) String message("Convert.copyScalar destination is immutable"); throw std::invalid_argument(message); } - ScalarType fromType = from->getScalar()->getScalarType(); - ScalarType toType = to->getScalar()->getScalarType(); - switch(fromType) { - case pvBoolean: { - if(toType!=pvBoolean) { - if(toType!=pvString) { - String message("Convert.copyScalar arguments are not compatible"); - throw std::invalid_argument(message); - } - } - PVBooleanPtr data = static_pointer_cast(from); - if(toType==pvString) { - PVStringPtr dataTo = static_pointer_cast(to); - String buf(""); - data->toString(&buf); - dataTo->put(buf); - } else { - bool value = data->get(); - PVBooleanPtr dataTo = static_pointer_cast(to); - dataTo->put(value); - } - return; - } - case pvByte : { - PVBytePtr data = static_pointer_cast(from); - int8 value = data->get(); - fromByte(to,value); - return; - } - case pvShort : { - PVShortPtr data = static_pointer_cast(from); - int16 value = data->get(); - fromShort(to,value); - return; - } - case pvInt :{ - PVIntPtr data = static_pointer_cast(from); - int32 value = data->get(); - fromInt(to,value); - return; - } - case pvLong : { - PVLongPtr data = static_pointer_cast(from); - int64 value = data->get(); - fromLong(to,value); - return; - } - case pvUByte : { - PVUBytePtr data = static_pointer_cast(from); - uint8 value = data->get(); - fromUByte(to,value); - return; - } - case pvUShort : { - PVUShortPtr data = static_pointer_cast(from); - uint16 value = data->get(); - fromUShort(to,value); - return; - } - case pvUInt :{ - PVUIntPtr data = static_pointer_cast(from); - uint32 value = data->get(); - fromUInt(to,value); - return; - } - case pvULong : { - PVULongPtr data = static_pointer_cast(from); - uint64 value = data->get(); - fromULong(to,value); - return; - } - case pvFloat : { - PVFloatPtr data = static_pointer_cast(from); - float value = data->get(); - fromFloat(to,value); - return; - } - case pvDouble : { - PVDoublePtr data = static_pointer_cast(from); - double value = data->get(); - fromDouble(to,value); - return; - } - case pvString: { - PVStringPtr data = static_pointer_cast(from); - String value = data->get(); - fromString(to,value); - return; - } - } - String message("Convert::copyScalar should never get here"); - throw std::logic_error(message); + to->assign(*from.get()); } bool Convert::isCopyScalarArrayCompatible(ScalarArrayConstPtr const &fromArray, @@ -693,99 +601,6 @@ bool Convert::isCopyScalarArrayCompatible(ScalarArrayConstPtr const &fromArray, return false; } -size_t Convert::copyScalarArray(PVScalarArrayPtr const & from, size_t offset, - PVScalarArrayPtr const & to, size_t toOffset, size_t length) -{ - - if(to->isImmutable()) { - if(from==to) return from->getLength(); - String message("Convert.copyArray destination is immutable"); - throw std::invalid_argument(message); - } - ScalarType fromElementType = from->getScalarArray()->getElementType(); - ScalarType toElementType = to->getScalarArray()->getElementType(); - - if(from->isImmutable() && (fromElementType==toElementType)) { - if(offset==0 && toOffset==0 && length==from->getLength()) { - return copyArrayDataReference(from.get(),to.get()); - } - } - - size_t ncopy = 0; - if(ScalarTypeFunc::isNumeric(fromElementType) - && ScalarTypeFunc::isNumeric(toElementType)) { - return copyNumericArray(from.get(),offset,to.get(),toOffset,length); - } else if(toElementType==pvBoolean && fromElementType==pvBoolean) { - PVBooleanArray *pvfrom = static_cast(from.get()); - PVBooleanArray *pvto = static_cast(to.get()); - while(length>0) { - size_t num = 0; - size_t fromOffset = 0; - BooleanArrayData booleanArrayData; - num = pvfrom->get(offset,length,booleanArrayData); - boolean * data = pvfrom->get(); - fromOffset = booleanArrayData.offset; - if(num<=0) return ncopy; - while(num>0) { - size_t n = pvto->put(toOffset,num,data,fromOffset); - if(n<=0) return ncopy; - length -= n; num -= n; ncopy+=n; offset += n; toOffset += n; - } - } - return ncopy; - } else if(toElementType==pvString && fromElementType==pvString) { - PVStringArray *pvfrom = static_cast(from.get()); - PVStringArray *pvto = static_cast(to.get()); - while(length>0) { - size_t num = 0; - String *data; - size_t fromOffset = 0; - StringArrayData stringArrayData; - num = pvfrom->get(offset,length,stringArrayData); - data = pvfrom->get(); - fromOffset = stringArrayData.offset; - if(num<=0) return ncopy; - while(num>0) { - size_t n = pvto->put(toOffset,num,data,fromOffset); - if(n<=0) return ncopy; - length -= n; num -= n; ncopy+=n; offset += n; toOffset += n; - } - } - return ncopy; - } else if(toElementType==pvString) { - PVStringArray *pvto = static_cast(to.get()); - ncopy = from->getLength(); - if(ncopy>length) ncopy = length; - size_t num = ncopy; - StringArray toData(1); - while(num>0) { - toStringArray(from,offset,1,toData,0); - if(pvto->put(toOffset,1,&toData[0],0)<=0) break; - num--; offset++; toOffset++; - } - return ncopy; - } else if(fromElementType==pvString) { - PVStringArray *pvfrom = static_cast(from.get()); - while(length>0) { - size_t num = 0; - size_t fromOffset = 0; - StringArrayData stringArrayData; - num = pvfrom->get(offset,length,stringArrayData); - StringArray const & data = stringArrayData.data; - fromOffset = stringArrayData.offset; - if(num<=0) return ncopy; - while(num>0) { - size_t n = fromStringArray(to,toOffset,num,data,fromOffset); - if(n<=0) return ncopy; - length -= n; num -= n; ncopy+=n; offset += n; toOffset += n; - } - } - return ncopy; - } - String message("Convert::copyScalarArray should not get here"); - throw std::logic_error(message); -} - bool Convert::isCopyStructureCompatible( StructureConstPtr const &fromStruct, StructureConstPtr const &toStruct) { @@ -865,7 +680,7 @@ void Convert::copyStructure(PVStructurePtr const & from, PVStructurePtr const & && (pvArray->getScalarArray()->getElementType()==pvString)) { PVScalarArrayPtr toArray = static_pointer_cast(toDatas[1]); - copyScalarArray(pvArray,0,toArray,0,pvArray->getLength()); + toArray->assign(*pvArray.get()); PVScalarPtr toScalar = static_pointer_cast(toDatas[0]); copyScalar(pvScalar,toScalar); return; @@ -894,9 +709,7 @@ void Convert::copyStructure(PVStructurePtr const & from, PVStructurePtr const & { PVScalarArrayPtr fromArray = static_pointer_cast(fromData); PVScalarArrayPtr toArray = static_pointer_cast(toData); - size_t length = copyScalarArray( - fromArray,0,toArray,0,fromArray->getLength()); - if(toArray->getLength()!=length) toArray->setLength(length); + toArray->assign(*fromArray.get()); break; } case structure: diff --git a/pvDataApp/factory/PVDataCreateFactory.cpp b/pvDataApp/factory/PVDataCreateFactory.cpp index b32d493..7561336 100644 --- a/pvDataApp/factory/PVDataCreateFactory.cpp +++ b/pvDataApp/factory/PVDataCreateFactory.cpp @@ -672,7 +672,7 @@ PVScalarArrayPtr PVDataCreate::createPVScalarArray( { PVScalarArrayPtr pvArray = createPVScalarArray( arrayToClone->getScalarArray()->getElementType()); - getConvert()->copyScalarArray(arrayToClone,0, pvArray,0,arrayToClone->getLength()); + pvArray->assign(*arrayToClone.get()); PVAuxInfoPtr from = arrayToClone->getPVAuxInfo(); PVAuxInfoPtr to = pvArray->getPVAuxInfo(); PVAuxInfo::PVInfoMap & map = from->getInfoMap(); diff --git a/pvDataApp/pv/convert.h b/pvDataApp/pv/convert.h index a54c258..b06c6b8 100644 --- a/pvDataApp/pv/convert.h +++ b/pvDataApp/pv/convert.h @@ -254,22 +254,6 @@ public: bool isCopyScalarArrayCompatible( ScalarArrayConstPtr const & from, ScalarArrayConstPtr const & to); - /** - * Convert from a source PV array to a destination PV array. - * @param from The source array. - * @param offset Starting element in the source. - * @param to The destination array. - * @param toOffset Starting element in the array. - * @param length Number of elements to transfer. - * @return Number of elements converted. - * @throws std::invalid_argument if the arguments are not compatible. - */ - std::size_t copyScalarArray( - PVScalarArrayPtr const & from, - std::size_t offset, - PVScalarArrayPtr const & to, - std::size_t toOffset, - std::size_t length); /** * Are from and to valid arguments for copyStructure. * They are only compatible if they have the same Structure description. diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index b7e3e0d..3ef001c 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -670,7 +670,7 @@ public: } virtual void putFrom(ScalarType, const void*, size_t ,size_t) = 0; - virtual void assign(const PVScalarArray& pv) = 0; + virtual void assign(PVScalarArray& pv) = 0; protected: PVScalarArray(ScalarArrayConstPtr const & scalarArray); @@ -1098,10 +1098,19 @@ public: castUnsafeV(count, typeCode, (void*)(get()+offset), dtype, ptr); } - virtual void assign(const PVScalarArray& pv) + virtual void assign(PVScalarArray& pv) { - setLength(pv.getLength()); - pv.getAs(typeCode, (void*)get(), std::min(getLength(),pv.getLength()), 0); + if(this==&pv) + return; + if(isImmutable()) + throw std::invalid_argument("Destination is immutable"); + if(pv.isImmutable() && typeCode==pv.getScalarArray()->getElementType()) { + PVValueArray& pvr = static_cast(pv); + shareData(pvr.getSharedVector(), pvr.getCapacity(), pvr.getLength()); + } else { + setLength(pv.getLength()); + pv.getAs(typeCode, (void*)get(), std::min(getLength(),pv.getLength()), 0); + } } protected: diff --git a/testApp/pv/testConvert.cpp b/testApp/pv/testConvert.cpp index 48763d0..ab54135 100644 --- a/testApp/pv/testConvert.cpp +++ b/testApp/pv/testConvert.cpp @@ -441,10 +441,10 @@ static void testConvertScalarArray(FILE *fd) { convert->fromByteArray(pvDoublePtr,0,length,barray,0); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvUBytePtr,0, pvFloatPtr,0,length); + pvUBytePtr->assign(*pvFloatPtr.get()); builder.clear(); pvFloatPtr->toString(&builder); if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvUBytePtr,0, pvDoublePtr,0,length); + pvUBytePtr->assign(*pvDoublePtr.get()); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); fprintf(fd,"fromByte PASSED\n"); @@ -484,10 +484,10 @@ static void testConvertScalarArray(FILE *fd) { convert->fromShortArray(pvDoublePtr,0,length,sarray,0); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvUShortPtr,0, pvFloatPtr,0,length); + pvUShortPtr->assign(*pvFloatPtr.get()); builder.clear(); pvFloatPtr->toString(&builder); if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvUShortPtr,0, pvDoublePtr,0,length); + pvUShortPtr->assign(*pvDoublePtr.get()); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); fprintf(fd,"fromShort PASSED\n"); @@ -527,10 +527,10 @@ static void testConvertScalarArray(FILE *fd) { convert->fromIntArray(pvDoublePtr,0,length,iarray,0); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvUIntPtr,0, pvFloatPtr,0,length); + pvUIntPtr->assign(*pvFloatPtr.get()); builder.clear(); pvFloatPtr->toString(&builder); if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvUIntPtr,0, pvDoublePtr,0,length); + pvUIntPtr->assign(*pvDoublePtr.get()); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); fprintf(fd,"fromInt PASSED\n"); @@ -570,10 +570,10 @@ static void testConvertScalarArray(FILE *fd) { convert->fromLongArray(pvDoublePtr,0,length,larray,0); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvULongPtr,0, pvFloatPtr,0,length); + pvULongPtr->assign(*pvFloatPtr.get()); builder.clear(); pvFloatPtr->toString(&builder); if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvULongPtr,0, pvDoublePtr,0,length); + pvULongPtr->assign(*pvDoublePtr.get()); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); fprintf(fd,"fromLong PASSED\n"); @@ -613,10 +613,10 @@ static void testConvertScalarArray(FILE *fd) { convert->fromUByteArray(pvDoublePtr,0,length,ubarray,0); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvUBytePtr,0, pvFloatPtr,0,length); + pvUBytePtr->assign(*pvFloatPtr.get()); builder.clear(); pvFloatPtr->toString(&builder); if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvUBytePtr,0, pvDoublePtr,0,length); + pvUBytePtr->assign(*pvDoublePtr.get()); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); fprintf(fd,"fromUByte PASSED\n"); @@ -656,10 +656,10 @@ static void testConvertScalarArray(FILE *fd) { convert->fromUShortArray(pvDoublePtr,0,length,usarray,0); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvUShortPtr,0, pvFloatPtr,0,length); + pvUShortPtr->assign(*pvFloatPtr.get()); builder.clear(); pvFloatPtr->toString(&builder); if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvUShortPtr,0, pvDoublePtr,0,length); + pvUShortPtr->assign(*pvDoublePtr.get()); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); fprintf(fd,"fromUShort PASSED\n"); @@ -699,10 +699,10 @@ static void testConvertScalarArray(FILE *fd) { convert->fromUIntArray(pvDoublePtr,0,length,uiarray,0); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvUIntPtr,0, pvFloatPtr,0,length); + pvUIntPtr->assign(*pvFloatPtr.get()); builder.clear(); pvFloatPtr->toString(&builder); if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvUIntPtr,0, pvDoublePtr,0,length); + pvUIntPtr->assign(*pvDoublePtr.get()); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); fprintf(fd,"fromUInt PASSED\n"); @@ -742,10 +742,10 @@ static void testConvertScalarArray(FILE *fd) { convert->fromULongArray(pvDoublePtr,0,length,ularray,0); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvULongPtr,0, pvFloatPtr,0,length); + pvULongPtr->assign(*pvFloatPtr.get()); builder.clear(); pvFloatPtr->toString(&builder); if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvULongPtr,0, pvDoublePtr,0,length); + pvULongPtr->assign(*pvDoublePtr.get()); builder.clear(); pvDoublePtr->toString(&builder); if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); fprintf(fd,"fromLong PASSED\n"); From a7fde21300979798207bd212b59155a01eca81fd Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 30 Apr 2013 14:04:24 -0400 Subject: [PATCH 019/103] replace scalar to/from in Convert --- pvDataApp/factory/Convert.cpp | 711 ---------------------------------- pvDataApp/pv/convert.h | 42 +- 2 files changed, 21 insertions(+), 732 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index ced8c69..c1f01f9 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -30,307 +30,6 @@ static void newLineImpl(StringBuilder buffer, int indentLevel) for(int i=0; i -T toScalar(PVScalarPtr const &pv) -{ - ScalarConstPtr scalar = pv->getScalar(); - ScalarType scalarType = scalar->getScalarType(); - switch(scalarType) { - case pvBoolean: - throw std::logic_error(String("boolean can not be converted to scalar")); - case pvByte: { - PVBytePtr value = static_pointer_cast(pv); - return value->get(); - } - case pvShort: { - PVShortPtr value = static_pointer_cast(pv); - return value->get(); - } - case pvInt: { - PVIntPtr value = static_pointer_cast(pv); - return value->get(); - } - case pvLong: { - PVLongPtr value = static_pointer_cast(pv); - return value->get(); - } - case pvUByte: { - PVUBytePtr value = static_pointer_cast(pv); - return value->get(); - } - case pvUShort: { - PVUShortPtr value = static_pointer_cast(pv); - return value->get(); - } - case pvUInt: { - PVUIntPtr value = static_pointer_cast(pv); - return value->get(); - } - case pvULong: { - PVULongPtr value = static_pointer_cast(pv); - return value->get(); - } - case pvFloat: { - PVFloatPtr value = static_pointer_cast(pv); - return static_cast(value->get()); - } - case pvDouble: { - PVDoublePtr value = static_pointer_cast(pv); - return static_cast(value->get()); - } - case pvString: - throw std::logic_error(String("string can not be converted to byte")); - } - throw std::logic_error("Logic error. Should never get here."); -} - -int8 Convert::toByte(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -int16 Convert::toShort(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -int32 Convert::toInt(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -int64 Convert::toLong(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -uint8 Convert::toUByte(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -uint16 Convert::toUShort(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -uint32 Convert::toUInt(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -uint64 Convert::toULong(PVScalarPtr const &pv) -{ - return toScalar(pv); -} - -float Convert::toFloat(PVScalarPtr const &pv) -{ - return toScalar(pv); -} - -double Convert::toDouble(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -template -String scalarToString(T); - -template<> -String scalarToString(int8 value) -{ - char buffer[20]; - int ival = value; - sprintf(buffer,"%d",ival); - return String(buffer); -} - -template<> -String scalarToString(int16 value) -{ - char buffer[20]; - int ival = value; - sprintf(buffer,"%d",ival); - return String(buffer); -} - -template<> -String scalarToString(int32 value) -{ - char buffer[20]; - int ival = value; - sprintf(buffer,"%d",ival); - return String(buffer); -} - -template<> -String scalarToString(int64 value) -{ - char buffer[30]; - sprintf(buffer,"%lld",(long long)value); - return String(buffer); -} - -template<> -String scalarToString(uint8 value) -{ - char buffer[20]; - unsigned int ival = value; - sprintf(buffer,"%ud",ival); - return String(buffer); -} - -template<> -String scalarToString(uint16 value) -{ - char buffer[20]; - unsigned int ival = value; - sprintf(buffer,"%iud",ival); - return String(buffer); -} - -template<> -String scalarToString(uint32 value) -{ - char buffer[20]; - sprintf(buffer,"%ud",(unsigned int)value); - return String(buffer); -} - -template<> -String scalarToString(uint64 value) -{ - char buffer[30]; - sprintf(buffer,"%llu",(unsigned long long)value); - return String(buffer); -} - -template<> -String scalarToString(float value) -{ - char buffer[40]; - sprintf(buffer,"%g",value); - return String(buffer); -} - -template<> -String scalarToString(double value) -{ - char buffer[40]; - sprintf(buffer,"%g",value); - return String(buffer); -} - -template -void fromScalar(PVScalarPtr const &pv,T from) -{ - ScalarConstPtr scalar = pv->getScalar(); - ScalarType scalarType = scalar->getScalarType(); - switch(scalarType) { - case pvBoolean: - throw std::logic_error("byte can not be converted to boolean"); - case pvByte: { - PVBytePtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvShort: { - PVShortPtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvInt: { - PVIntPtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvLong: { - PVLongPtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvUByte: { - PVUBytePtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvUShort: { - PVUShortPtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvUInt: { - PVUIntPtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvULong: { - PVULongPtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvFloat: { - PVFloatPtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvDouble: { - PVDoublePtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvString: { - PVStringPtr pvvalue = static_pointer_cast(pv); - String value = scalarToString(from); - pvvalue->put(value); - return; - } - } - throw std::logic_error("Logic error. Should never get here."); -} - -void Convert::fromByte(PVScalarPtr const &pv,int8 from) -{ - fromScalar(pv,from); -} - -void Convert::fromShort(PVScalarPtr const &pv,int16 from) -{ - fromScalar(pv,from); -} - -void Convert::fromInt(PVScalarPtr const &pv, int32 from) -{ - fromScalar(pv,from); -} - -void Convert::fromLong(PVScalarPtr const &pv, int64 from) -{ - fromScalar(pv,from); -} - -void Convert::fromUByte(PVScalarPtr const &pv,uint8 from) -{ - fromScalar(pv,from); -} - -void Convert::fromUShort(PVScalarPtr const &pv,uint16 from) -{ - fromScalar(pv,from); -} - -void Convert::fromUInt(PVScalarPtr const &pv, uint32 from) -{ - fromScalar(pv,from); -} - -void Convert::fromULong(PVScalarPtr const &pv, uint64 from) -{ - fromScalar(pv,from); -} - -void Convert::fromFloat(PVScalarPtr const &pv, float from) -{ - fromScalar(pv,from); -} - -void Convert::fromDouble(PVScalarPtr const &pv, double from) -{ - fromScalar(pv,from); -} - - static size_t convertFromByteArray(PVScalarArray * pv, size_t offset, size_t len,const int8 from[], size_t fromOffset); static size_t convertToByteArray(PVScalarArray *pv, size_t offset, @@ -372,9 +71,6 @@ static size_t convertFromDoubleArray(PVScalarArray *pv, size_t offset, static size_t convertToDoubleArray(PVScalarArray *pv, size_t offset, size_t len,double to[], size_t toOffset); -static size_t copyArrayDataReference(PVScalarArray *from,PVArray *to); -static size_t copyNumericArray(PVScalarArray *from, - size_t offset, PVScalarArray *to, size_t toOffset, size_t len); static std::vector split(String commaSeparatedList); @@ -751,87 +447,6 @@ void Convert::copyStructureArray( to->put(0,from->getLength(),from->getVector(),0); } -String Convert::toString(PVScalarPtr const & pv) -{ - static String trueString("true"); - static String falseString("false"); - - ScalarConstPtr scalar = pv->getScalar(); - ScalarType scalarType = scalar->getScalarType(); - switch(scalarType) { - case pvBoolean: { - PVBooleanPtr pvalue = static_pointer_cast(pv); - boolean value = pvalue->get(); - return value ? trueString : falseString; - } - case pvByte: { - PVBytePtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%d",(int)value->get()); - return String(buffer); - } - case pvShort: { - PVShortPtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%d",(int)value->get()); - return String(buffer); - } - case pvInt: { - PVIntPtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%d",(int)value->get()); - return String(buffer); - } - case pvLong: { - PVLongPtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%lli",(long long int)value->get()); - return String(buffer); - } - case pvUByte: { - PVUBytePtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%u",(unsigned int)value->get()); - return String(buffer); - } - case pvUShort: { - PVUShortPtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%u",(unsigned int)value->get()); - return String(buffer); - } - case pvUInt: { - PVUIntPtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%u",(unsigned int)value->get()); - return String(buffer); - } - case pvULong: { - PVULongPtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%llu",(unsigned long long int)value->get()); - return String(buffer); - } - case pvFloat: { - PVFloatPtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%g",value->get()); - return String(buffer); - } - case pvDouble: { - PVDoublePtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%g",value->get()); - return String(buffer); - } - case pvString: { - PVStringPtr value = static_pointer_cast(pv); - return value->get(); - } - } - throw std::logic_error("Logic error. Should never get here."); -} - size_t Convert::toByteArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, int8 to[], size_t toOffset) { @@ -1505,332 +1120,6 @@ size_t convertToDoubleArray(PVScalarArray * pv, return convertToScalarArray(pv,offset,len,to,toOffset); } -size_t copyArrayDataReference(PVScalarArray *from,PVArray *to) -{ - ScalarType scalarType = from->getScalarArray()->getElementType(); - switch (scalarType) { - case pvBoolean: { - PVBooleanArray *pvfrom = (PVBooleanArray*) from; - PVBooleanArray *pvto = (PVBooleanArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvByte: { - PVByteArray *pvfrom = (PVByteArray*) from; - PVByteArray *pvto = (PVByteArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvShort: { - PVShortArray *pvfrom = (PVShortArray*) from; - PVShortArray *pvto = (PVShortArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvInt: { - PVIntArray *pvfrom = (PVIntArray*) from; - PVIntArray *pvto = (PVIntArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvLong: { - PVLongArray *pvfrom = (PVLongArray*) from; - PVLongArray *pvto = (PVLongArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvUByte: { - PVUByteArray *pvfrom = (PVUByteArray*) from; - PVUByteArray *pvto = (PVUByteArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvUShort: { - PVUShortArray *pvfrom = (PVUShortArray*) from; - PVUShortArray *pvto = (PVUShortArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvUInt: { - PVUIntArray *pvfrom = (PVUIntArray*) from; - PVUIntArray *pvto = (PVUIntArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvULong: { - PVULongArray *pvfrom = (PVULongArray*) from; - PVULongArray *pvto = (PVULongArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvFloat: { - PVFloatArray *pvfrom = (PVFloatArray*) from; - PVFloatArray *pvto = (PVFloatArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvDouble: { - PVDoubleArray *pvfrom = (PVDoubleArray*) from; - PVDoubleArray *pvto = (PVDoubleArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvString: { - PVStringArray *pvfrom = (PVStringArray*) from; - PVStringArray *pvto = (PVStringArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - } - to->setImmutable(); - return from->getLength(); -} - -size_t copyNumericArray(PVScalarArray *from, size_t offset, PVScalarArray *to, size_t toOffset, size_t len) -{ - ScalarType fromElementType = from->getScalarArray()->getElementType(); - size_t ncopy = 0; - switch (fromElementType) { - case pvBoolean: - throw std::logic_error(String("PVBooleanArray is not a numeric array")); - case pvByte: { - PVByteArray *pvfrom = (PVByteArray*) from; - while (len > 0) { - size_t num = 0; - ByteArrayData arrayData = ByteArrayData(); - num = pvfrom->get(offset, len, arrayData); - int8 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromByteArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvShort: { - PVShortArray *pvfrom = (PVShortArray*) from; - while (len > 0) { - size_t num = 0; - ShortArrayData arrayData = ShortArrayData(); - num = pvfrom->get(offset, len, arrayData); - int16 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromShortArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvInt: { - PVIntArray *pvfrom = (PVIntArray*) from; - while (len > 0) { - size_t num = 0; - IntArrayData arrayData = IntArrayData(); - num = pvfrom->get(offset, len, arrayData); - int32 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromIntArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvLong: { - PVLongArray *pvfrom = (PVLongArray*) from; - while (len > 0) { - size_t num = 0; - LongArrayData arrayData = LongArrayData(); - num = pvfrom->get(offset, len, arrayData); - int64 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromLongArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvUByte: { - PVUByteArray *pvfrom = (PVUByteArray*) from; - while (len > 0) { - size_t num = 0; - UByteArrayData arrayData = UByteArrayData(); - num = pvfrom->get(offset, len, arrayData); - uint8 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromUByteArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvUShort: { - PVUShortArray *pvfrom = (PVUShortArray*) from; - while (len > 0) { - size_t num = 0; - UShortArrayData arrayData = UShortArrayData(); - num = pvfrom->get(offset, len, arrayData); - uint16 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromUShortArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvUInt: { - PVUIntArray *pvfrom = (PVUIntArray*) from; - while (len > 0) { - size_t num = 0; - UIntArrayData arrayData = UIntArrayData(); - num = pvfrom->get(offset, len, arrayData); - uint32 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromUIntArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvULong: { - PVULongArray *pvfrom = (PVULongArray*) from; - while (len > 0) { - size_t num = 0; - ULongArrayData arrayData = ULongArrayData(); - num = pvfrom->get(offset, len, arrayData); - uint64 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromULongArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvFloat: { - PVFloatArray *pvfrom = (PVFloatArray*) from; - while (len > 0) { - size_t num = 0; - FloatArrayData floatArrayData = FloatArrayData(); - num = pvfrom->get(offset, len, floatArrayData); - float * data = get(floatArrayData.data); - size_t dataOffset = floatArrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromFloatArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvDouble: { - PVDoubleArray *pvfrom = (PVDoubleArray*) from; - while (len > 0) { - size_t num = 0; - DoubleArrayData doubleArrayData = DoubleArrayData(); - num = pvfrom->get(offset, len, doubleArrayData); - double * data = get(doubleArrayData.data); - size_t dataOffset = doubleArrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromDoubleArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvString: - throw std::logic_error(String("PVStringArray is not a numeric array")); - } - return ncopy; -} - ConvertPtr Convert::getConvert() { static ConvertPtr convert; diff --git a/pvDataApp/pv/convert.h b/pvDataApp/pv/convert.h index b06c6b8..14532f4 100644 --- a/pvDataApp/pv/convert.h +++ b/pvDataApp/pv/convert.h @@ -297,145 +297,145 @@ public: * @param pv a PV * @return converted value */ - int8 toByte(PVScalarPtr const & pv); + inline int8 toByte(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a short. * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - int16 toShort(PVScalarPtr const & pv); + inline int16 toShort(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a int. * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - int32 toInt(PVScalarPtr const & pv); + inline int32 toInt(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to an long * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - int64 toLong(PVScalarPtr const & pv); + inline int64 toLong(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a ubyte. * @param pv a PV * @return converted value */ - uint8 toUByte(PVScalarPtr const & pv); + inline uint8 toUByte(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a ushort. * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - uint16 toUShort(PVScalarPtr const & pv); + inline uint16 toUShort(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a uint. * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - uint32 toUInt(PVScalarPtr const & pv); + inline uint32 toUInt(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to an ulong * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - uint64 toULong(PVScalarPtr const & pv); + inline uint64 toULong(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a float * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - float toFloat(PVScalarPtr const & pv); + inline float toFloat(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a double * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - double toDouble(PVScalarPtr const & pv); + inline double toDouble(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a String * @param pv a PV * @return converted value */ - String toString(PVScalarPtr const & pv); + inline String toString(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV from a byte * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromByte(PVScalarPtr const & pv,int8 from); + inline void fromByte(PVScalarPtr const & pv,int8 from) { pv->putFrom(from); } /** * Convert a PV from a short * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromShort(PVScalarPtr const & pv,int16 from); + inline void fromShort(PVScalarPtr const & pv,int16 from) { pv->putFrom(from); } /** * Convert a PV from an int * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromInt(PVScalarPtr const & pv, int32 from); + inline void fromInt(PVScalarPtr const & pv, int32 from) { pv->putFrom(from); } /** * Convert a PV from a long * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromLong(PVScalarPtr const & pv, int64 from); + inline void fromLong(PVScalarPtr const & pv, int64 from) { pv->putFrom(from); } /** * Convert a PV from a ubyte * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromUByte(PVScalarPtr const & pv,uint8 from); + inline void fromUByte(PVScalarPtr const & pv,uint8 from) { pv->putFrom(from); } /** * Convert a PV from a ushort * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromUShort(PVScalarPtr const & pv,uint16 from); + inline void fromUShort(PVScalarPtr const & pv,uint16 from) { pv->putFrom(from); } /** * Convert a PV from an uint * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromUInt(PVScalarPtr const & pv, uint32 from); + inline void fromUInt(PVScalarPtr const & pv, uint32 from) { pv->putFrom(from); } /** * Convert a PV from a ulong * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromULong(PVScalarPtr const & pv, uint64 from); + inline void fromULong(PVScalarPtr const & pv, uint64 from) { pv->putFrom(from); } /** * Convert a PV from a float * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromFloat(PVScalarPtr const & pv, float from); + inline void fromFloat(PVScalarPtr const & pv, float from) { pv->putFrom(from); } /** * Convert a PV from a double * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromDouble(PVScalarPtr const & pv, double from); + inline void fromDouble(PVScalarPtr const & pv, double from) { pv->putFrom(from); } /** * Convert a PV array to a byte array. * @param pv a PV From 659ce13e98f9b457390209143bb2abcceda98862 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 30 Apr 2013 14:41:29 -0400 Subject: [PATCH 020/103] replace vector to/from in Convert --- pvDataApp/factory/Convert.cpp | 721 +--------------------------------- pvDataApp/pv/convert.h | 120 ++++-- 2 files changed, 92 insertions(+), 749 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index c1f01f9..7a43cd8 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -24,56 +24,6 @@ using std::size_t; namespace epics { namespace pvData { -static void newLineImpl(StringBuilder buffer, int indentLevel) -{ - *buffer += "\n"; - for(int i=0; i split(String commaSeparatedList); - static std::vector split(String commaSeparatedList) { String::size_type numValues = 1; String::size_type index=0; @@ -447,677 +397,10 @@ void Convert::copyStructureArray( to->put(0,from->getLength(),from->getVector(),0); } -size_t Convert::toByteArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - int8 to[], size_t toOffset) -{ - return convertToByteArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toShortArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - int16 to[], size_t toOffset) -{ - return convertToShortArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toIntArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - int32 to[], size_t toOffset) -{ - return convertToIntArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toLongArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - int64 to[], size_t toOffset) -{ - return convertToLongArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toUByteArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - uint8 to[], size_t toOffset) -{ - return convertToUByteArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toUShortArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - uint16 to[], size_t toOffset) -{ - return convertToUShortArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toUIntArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - uint32 to[], size_t toOffset) -{ - return convertToUIntArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toULongArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - uint64 to[], size_t toOffset) -{ - return convertToULongArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toFloatArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - float to[], size_t toOffset) -{ - return convertToFloatArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toDoubleArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - double to[], size_t toOffset) -{ - return convertToDoubleArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::fromByteArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const int8 from[], size_t fromOffset) -{ - return convertFromByteArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromByteArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const ByteArray & from, size_t fromOffset) -{ - return convertFromByteArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromShortArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const int16 from[], size_t fromOffset) -{ - return convertFromShortArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromShortArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const ShortArray & from, size_t fromOffset) -{ - return convertFromShortArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromIntArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const int32 from[], size_t fromOffset) -{ - return convertFromIntArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromIntArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const IntArray & from, size_t fromOffset) -{ - return convertFromIntArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromLongArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const int64 from[], size_t fromOffset) -{ - return convertFromLongArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromLongArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const LongArray & from, size_t fromOffset) -{ - return convertFromLongArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromUByteArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const uint8 from[], size_t fromOffset) -{ - return convertFromUByteArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromUByteArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const UByteArray & from, size_t fromOffset) -{ - return convertFromUByteArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromUShortArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const uint16 from[], size_t fromOffset) -{ - return convertFromUShortArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromUShortArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const UShortArray &from, size_t fromOffset) -{ - return convertFromUShortArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromUIntArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const uint32 from[], size_t fromOffset) -{ - return convertFromUIntArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromUIntArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const UIntArray & from, size_t fromOffset) -{ - return convertFromUIntArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromULongArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const uint64 from[], size_t fromOffset) -{ - return convertFromULongArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromULongArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const ULongArray &from, size_t fromOffset) -{ - return convertFromULongArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromFloatArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const float from[], size_t fromOffset) -{ - return convertFromFloatArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromFloatArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const FloatArray & from, size_t fromOffset) -{ - return convertFromFloatArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromDoubleArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const double from[], size_t fromOffset) -{ - return convertFromDoubleArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromDoubleArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const DoubleArray & from, size_t fromOffset) -{ - return convertFromDoubleArray(pv.get(), offset, length, get(from), fromOffset); -} - void Convert::newLine(StringBuilder buffer, int indentLevel) { - newLineImpl(buffer,indentLevel); -} - -template -size_t convertFromScalarArray(PVScalarArray *pv, - size_t offset, size_t len,const T from[], size_t fromOffset) -{ - ScalarType elemType = pv->getScalarArray()->getElementType(); - size_t ntransfered = 0; - String xx = typeid(PVT).name(); - String yy = typeid(T).name(); - if(xx.compare(yy)== 0) { - PVT *pvdata = static_cast(pv); - while (len > 0) { - size_t n = pvdata->put(offset, len, from, fromOffset); - if (n == 0) - break; - len -= n; - offset += n; - fromOffset += n; - ntransfered += n; - } - return ntransfered; - } - switch (elemType) { - case pvBoolean: { - String message("convert from numeric array to BooleanArray not legal"); - throw std::invalid_argument(message); - } - case pvByte: { - PVByteArray *pvdata = static_cast(pv); - int8 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvShort: { - PVShortArray *pvdata = static_cast(pv); - int16 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvInt: { - PVIntArray *pvdata = static_cast(pv); - int32 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvLong: { - PVLongArray *pvdata = static_cast(pv); - int64 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvUByte: { - PVUByteArray *pvdata = static_cast(pv); - uint8 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvUShort: { - PVUShortArray *pvdata = static_cast(pv); - uint16 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvUInt: { - PVUIntArray *pvdata = static_cast(pv); - uint32 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvULong: { - PVULongArray *pvdata = static_cast(pv); - uint64 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvFloat: { - PVFloatArray *pvdata = static_cast(pv); - float data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvDouble: { - PVDoubleArray *pvdata = static_cast(pv); - double data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvString: { - String message("convert from byte[] to StringArray not legal"); - throw std::invalid_argument(message); - } - } - String message("Convert::convertFromByteArray should never get here"); - throw std::logic_error(message); -} - -template -size_t convertToScalarArray(PVScalarArray *pv, - size_t offset, size_t len,T to[], size_t toOffset) -{ - ScalarType elemType = pv->getScalarArray()->getElementType(); - size_t ntransfered = 0; - switch (elemType) { - case pvBoolean: { - String message("convert BooleanArray to byte[]] not legal"); - throw std::invalid_argument(message); - } - case pvByte: { - PVByteArray *pvdata = static_cast(pv); - ByteArrayData data; - while (len > 0) { - size_t num = 0; - num = pvdata->get(offset,len,data); - if (num <= 0) break; - ByteArray & dataArray = data.data; - size_t dataOffset = data.offset; - for(size_t i=0;i(pv); - ShortArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) break; - ShortArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = dataArray[i + dataOffset]; - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvInt: { - PVIntArray *pvdata = static_cast(pv); - IntArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) break; - IntArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = dataArray[i + dataOffset]; - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvLong: { - PVLongArray *pvdata = static_cast(pv); - LongArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) - break; - LongArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = dataArray[i + dataOffset]; - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvUByte: { - PVUByteArray *pvdata = static_cast(pv); - UByteArrayData data; - while (len > 0) { - size_t num = 0; - num = pvdata->get(offset,len,data); - if (num <= 0) break; - UByteArray & dataArray = data.data; - size_t dataOffset = data.offset; - for(size_t i=0;i(pv); - UShortArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) break; - UShortArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = dataArray[i + dataOffset]; - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvUInt: { - PVUIntArray *pvdata = static_cast(pv); - UIntArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) break; - UIntArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = dataArray[i + dataOffset]; - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvULong: { - PVULongArray *pvdata = static_cast(pv); - ULongArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) - break; - ULongArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = dataArray[i + dataOffset]; - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvFloat: { - PVFloatArray *pvdata = static_cast(pv); - FloatArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) break; - FloatArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = static_cast(dataArray[i + dataOffset]); - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvDouble: { - PVDoubleArray *pvdata = static_cast(pv); - DoubleArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) - break; - DoubleArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = static_cast(dataArray[i + dataOffset]); - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvString: { - String message("convert StringArray to numeric not legal"); - throw std::invalid_argument(message); - } - } - String message("Convert::convertToScalarArray should never get here"); - throw std::logic_error(message); -} - -size_t convertFromByteArray(PVScalarArray *pv, - size_t offset, size_t len,const int8 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToByteArray(PVScalarArray * pv, - size_t offset, size_t len,int8 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromShortArray(PVScalarArray *pv, - size_t offset, size_t len,const int16 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToShortArray(PVScalarArray * pv, - size_t offset, size_t len,int16 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromIntArray(PVScalarArray *pv, - size_t offset, size_t len,const int32 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToIntArray(PVScalarArray * pv, - size_t offset, size_t len,int32 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromLongArray(PVScalarArray *pv, - size_t offset, size_t len,const int64 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToLongArray(PVScalarArray * pv, - size_t offset, size_t len,int64 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromUByteArray(PVScalarArray *pv, - size_t offset, size_t len,const uint8 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToUByteArray(PVScalarArray * pv, - size_t offset, size_t len,uint8 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromUShortArray(PVScalarArray *pv, - size_t offset, size_t len,const uint16 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToUShortArray(PVScalarArray * pv, - size_t offset, size_t len,uint16 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromUIntArray(PVScalarArray *pv, - size_t offset, size_t len,const uint32 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToUIntArray(PVScalarArray * pv, - size_t offset, size_t len,uint32 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromULongArray(PVScalarArray *pv, - size_t offset, size_t len,const uint64 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToULongArray(PVScalarArray * pv, - size_t offset, size_t len,uint64 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromFloatArray(PVScalarArray *pv, - size_t offset, size_t len,const float from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToFloatArray(PVScalarArray * pv, - size_t offset, size_t len,float to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromDoubleArray(PVScalarArray *pv, - size_t offset, size_t len,const double from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToDoubleArray(PVScalarArray * pv, - size_t offset, size_t len,double to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); + *buffer += "\n"; + *buffer += String(indentLevel*4, ' '); } ConvertPtr Convert::getConvert() diff --git a/pvDataApp/pv/convert.h b/pvDataApp/pv/convert.h index 14532f4..4afa9e5 100644 --- a/pvDataApp/pv/convert.h +++ b/pvDataApp/pv/convert.h @@ -446,11 +446,13 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t toByteArray(PVScalarArrayPtr const & pv, std::size_t offset, std::size_t length, int8* to, - std::size_t toOffset); + std::size_t toOffset) + { pv->getAs(to+toOffset, length, offset); return length; } /** * Convert a PV array to a short array. * @param pv a PV @@ -461,11 +463,13 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t toShortArray(PVScalarArrayPtr const & pv, std::size_t offset, std::size_t length, int16* to, - std::size_t toOffset); + std::size_t toOffset) + { pv->getAs(to+toOffset, length, offset); return length; } /** * Convert a PV array to an int array. * @param pv a PV @@ -476,11 +480,13 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t toIntArray(PVScalarArrayPtr const & pv, std::size_t offset, std::size_t length, int32* to, - std::size_t toOffset); + std::size_t toOffset) + { pv->getAs(to+toOffset, length, offset); return length; } /** * Convert a PV array to a long array. * @param pv a PV @@ -491,11 +497,13 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t toLongArray(PVScalarArrayPtr const & pv, std::size_t offset, std::size_t length, int64* to, - std::size_t toOffset); + std::size_t toOffset) + { pv->getAs(to+toOffset, length, offset); return length; } /** * Convert a PV array to a ubyte array. * @param pv a PV @@ -506,11 +514,13 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t toUByteArray(PVScalarArrayPtr const & pv, std::size_t offset, std::size_t length, uint8* to, - std::size_t toOffset); + std::size_t toOffset) + { pv->getAs(to+toOffset, length, offset); return length; } /** * Convert a PV array to a ushort array. * @param pv a PV @@ -521,11 +531,13 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t toUShortArray(PVScalarArrayPtr const & pv, std::size_t offset, std::size_t length, uint16* to, - std::size_t toOffset); + std::size_t toOffset) + { pv->getAs(to+toOffset, length, offset); return length; } /** * Convert a PV array to an uint array. * @param pv a PV @@ -536,12 +548,14 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t toUIntArray( PVScalarArrayPtr const & pv, std::size_t offset, std::size_t length, uint32* to, - std::size_t toOffset); + std::size_t toOffset) + { pv->getAs(to+toOffset, length, offset); return length; } /** * Convert a PV array to a ulong array. * @param pv a PV @@ -552,12 +566,14 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t toULongArray( PVScalarArrayPtr const & pv, std::size_t offset, std::size_t length, uint64* to, - std::size_t toOffset); + std::size_t toOffset) + { pv->getAs(to+toOffset, length, offset); return length; } /** * Convert a PV array to a float array. * @param pv a PV @@ -568,12 +584,14 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t toFloatArray( PVScalarArrayPtr const & pv, std::size_t offset, std::size_t length, float* to, - std::size_t toOffset); + std::size_t toOffset) + { pv->getAs(to+toOffset, length, offset); return length; } /** * Convert a PV array to a double array. * @param pv a PV @@ -584,12 +602,14 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t toDoubleArray( PVScalarArrayPtr const & pv, std::size_t offset, std::size_t length, double* to, std::size_t - toOffset); + toOffset) + { pv->getAs(to+toOffset, length, offset); return length; } /** * Convert a PV array from a byte array. * @param pv a PV @@ -600,12 +620,16 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t fromByteArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const int8* from, std::size_t fromOffset); + const int8* from, std::size_t fromOffset) + { pv->putFrom(from+fromOffset, length, offset); return length; } + inline std::size_t fromByteArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const ByteArray & from, std::size_t fromOffset); + const ByteArray & from, std::size_t fromOffset) + {return fromByteArray(pv, offset, length, &from[0], fromOffset);} /** * Convert a PV array from a short array. * @param pv a PV @@ -616,12 +640,16 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t fromShortArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const int16* from, std::size_t fromOffset); + const int16* from, std::size_t fromOffset) + { pv->putFrom(from+fromOffset, length, offset); return length; } + inline std::size_t fromShortArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const ShortArray & from, std::size_t fromOffset); + const ShortArray & from, std::size_t fromOffset) + {return fromShortArray(pv, offset, length, &from[0], fromOffset);} /** * Convert a PV array from an int array. * @param pv a PV @@ -632,12 +660,16 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t fromIntArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const int32* from, std::size_t fromOffset); + const int32* from, std::size_t fromOffset) + { pv->putFrom(from+fromOffset, length, offset); return length; } + inline std::size_t fromIntArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const IntArray & from, std::size_t fromOffset); + const IntArray & from, std::size_t fromOffset) + {return fromIntArray(pv, offset, length, &from[0], fromOffset);} /** * Convert a PV array from a long array. * @param pv a PV @@ -648,12 +680,16 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t fromLongArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const int64* from, std::size_t fromOffset); + const int64* from, std::size_t fromOffset) + { pv->putFrom(from+fromOffset, length, offset); return length; } + inline std::size_t fromLongArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const LongArray & from, std::size_t fromOffset); + const LongArray & from, std::size_t fromOffset) + {return fromLongArray(pv, offset, length, &from[0], fromOffset);} /** * Convert a PV array from a ubyte array. * @param pv a PV @@ -664,12 +700,16 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t fromUByteArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const uint8* from, std::size_t fromOffset); + const uint8* from, std::size_t fromOffset) + { pv->putFrom(from+fromOffset, length, offset); return length; } + inline std::size_t fromUByteArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const UByteArray & from, std::size_t fromOffset); + const UByteArray & from, std::size_t fromOffset) + {return fromUByteArray(pv, offset, length, &from[0], fromOffset);} /** * Convert a PV array from a ushort array. * @param pv a PV @@ -680,12 +720,16 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t fromUShortArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const uint16* from, std::size_t fromOffset); + const uint16* from, std::size_t fromOffset) + { pv->putFrom(from+fromOffset, length, offset); return length; } + inline std::size_t fromUShortArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const UShortArray & from, std::size_t fromOffset); + const UShortArray & from, std::size_t fromOffset) + {return fromUShortArray(pv, offset, length, &from[0], fromOffset);} /** * Convert a PV array from an uint array. * @param pv a PV @@ -696,12 +740,16 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t fromUIntArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const uint32* from, std::size_t fromOffset); + const uint32* from, std::size_t fromOffset) + { pv->putFrom(from+fromOffset, length, offset); return length; } + inline std::size_t fromUIntArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const UIntArray & from, std::size_t fromOffset); + const UIntArray & from, std::size_t fromOffset) + {return fromUIntArray(pv, offset, length, &from[0], fromOffset);} /** * Convert a PV array from a ulong array. * @param pv a PV @@ -712,12 +760,16 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t fromULongArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const uint64* from, std::size_t fromOffset); + const uint64* from, std::size_t fromOffset) + { pv->putFrom(from+fromOffset, length, offset); return length; } + inline std::size_t fromULongArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const ULongArray & from, std::size_t fromOffset); + const ULongArray & from, std::size_t fromOffset) + {return fromULongArray(pv, offset, length, &from[0], fromOffset);} /** * Convert a PV array from a float array. * @param pv a PV @@ -728,12 +780,16 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t fromFloatArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const float* from, std::size_t fromOffset); + const float* from, std::size_t fromOffset) + { pv->putFrom(from+fromOffset, length, offset); return length; } + inline std::size_t fromFloatArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const FloatArray & from, std::size_t fromOffset); + const FloatArray & from, std::size_t fromOffset) + {return fromFloatArray(pv, offset, length, &from[0], fromOffset);} /** * Convert a PV array from a double array. * @param pv a PV @@ -744,12 +800,16 @@ public: * @return number of elements converted * @throws std::invalid_argument if the element type is not numeric */ + inline std::size_t fromDoubleArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const double* from, std::size_t fromOffset); + const double* from, std::size_t fromOffset) + { pv->putFrom(from+fromOffset, length, offset); return length; } + inline std::size_t fromDoubleArray( PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const DoubleArray & from, std::size_t fromOffset); + const DoubleArray & from, std::size_t fromOffset) + {return fromDoubleArray(pv, offset, length, &from[0], fromOffset);} /** * Convenience method for implementing toString. * It generates a newline and inserts blanks at the beginning of the newline. From ee5a370c015f7bd1cffee08b959a7d0353a6c5e2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 30 Apr 2013 15:20:17 -0400 Subject: [PATCH 021/103] misc --- pvDataApp/factory/Convert.cpp | 16 ++++++---------- pvDataApp/pv/convert.h | 9 +++------ pvDataApp/pv/pvData.h | 4 ++++ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index 7a43cd8..2633215 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -45,10 +45,7 @@ static std::vector split(String commaSeparatedList) { } Convert::Convert() -: pvDataCreate(getPVDataCreate()), - trueString("true"), - falseString("false"), - illegalScalarType("Illegal ScalarType") +: pvDataCreate(getPVDataCreate()) {} @@ -298,8 +295,7 @@ void Convert::copyStructure(PVStructurePtr const & from, PVStructurePtr const & { if(to->isImmutable()) { if(from==to) return; - String message("Convert.copyStructure destination is immutable"); - throw std::invalid_argument(message); + throw std::invalid_argument("Convert.copyStructure destination is immutable"); } if(from==to) return; PVFieldPtrArray const & fromDatas = from->getPVFields(); @@ -343,6 +339,10 @@ void Convert::copyStructure(PVStructurePtr const & from, PVStructurePtr const & String message("Convert.copyStructure Illegal copyStructure"); throw std::invalid_argument(message); } + if(toData->isImmutable()) { + if(fromData==toData) return; + throw std::invalid_argument("Convert.copyStructure destination is immutable"); + } switch(fromType) { case scalar: { @@ -415,8 +415,4 @@ ConvertPtr Convert::getConvert() return convert; } -ConvertPtr getConvert() { - return Convert::getConvert(); -} - }} diff --git a/pvDataApp/pv/convert.h b/pvDataApp/pv/convert.h index 4afa9e5..1aa5e71 100644 --- a/pvDataApp/pv/convert.h +++ b/pvDataApp/pv/convert.h @@ -89,7 +89,7 @@ public: * @param Second field * @return (false, true) if the fields (are not, are) the same. */ - bool equals(PVFieldPtr const &a,PVFieldPtr const &b) + inline bool equals(PVFieldPtr const &a,PVFieldPtr const &b) { return *a==*b; } @@ -101,7 +101,7 @@ public: * @param Second field * @return (false, true) if the fields (are not, are) the same. */ - bool equals(PVField &a,PVField &b) + inline bool equals(PVField &a,PVField &b) { return a==b; } @@ -820,12 +820,9 @@ public: private: Convert(); PVDataCreatePtr pvDataCreate; - String trueString; - String falseString; - String illegalScalarType; }; -extern ConvertPtr getConvert(); +static inline ConvertPtr getConvert() { return Convert::getConvert(); } }} #endif /* CONVERT_H */ diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index 3ef001c..164406f 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -501,6 +501,10 @@ protected: } virtual void assign(const PVScalar& scalar) { + if(this==&scalar) + return; + if(isImmutable()) + throw std::invalid_argument("Destination is immutable"); T result; scalar.getAs((void*)&result, typeCode); put(result); From 61e8024c65ed05a101bdf09a4010009cd56ed15e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 30 Apr 2013 17:44:25 -0400 Subject: [PATCH 022/103] fix mapping between int* and epicsInt* types --- pvDataApp/misc/parseToPOD.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/pvDataApp/misc/parseToPOD.cpp b/pvDataApp/misc/parseToPOD.cpp index 6fad99f..e947c69 100644 --- a/pvDataApp/misc/parseToPOD.cpp +++ b/pvDataApp/misc/parseToPOD.cpp @@ -420,20 +420,16 @@ void handleParseError(int err) namespace epics { namespace pvData { namespace detail { -void parseToPOD(const std::string& in, int8 *out) { - epicsInt8 temp; - int err = epicsParseInt8(in.c_str(), &temp, 0, NULL); - if(err) handleParseError(err); - else *out = temp; -} - #define INTFN(T, S) \ void parseToPOD(const std::string& in, T *out) { \ - int err = epicsParse ## S(in.c_str(), out, 0, NULL); \ + epics ## S temp; \ + int err = epicsParse ## S (in.c_str(), &temp, 0, NULL); \ if(err) handleParseError(err); \ + else *out = temp; \ } INTFN(char, Int8); +INTFN(int8_t, Int8); INTFN(uint8_t, UInt8); INTFN(int16_t, Int16); INTFN(uint16_t, UInt16); From 00ac5bf64f25ba62a9e68e788c8be4ef9bbc4eec Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 30 Apr 2013 19:10:53 -0400 Subject: [PATCH 023/103] PVStructure::getNumberFields != Structure::getNumberFields Apparently PVStructure::getNumberFields is one indexed??? --- pvDataApp/factory/Compare.cpp | 6 ++++-- pvDataApp/factory/printer.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pvDataApp/factory/Compare.cpp b/pvDataApp/factory/Compare.cpp index 73f928a..689ac21 100644 --- a/pvDataApp/factory/Compare.cpp +++ b/pvDataApp/factory/Compare.cpp @@ -171,13 +171,15 @@ bool compareField(PVScalarArray* left, PVScalarArray* right) bool compareField(PVStructure* left, PVStructure* right) { - if(left->getStructure()!=right->getStructure()) + StructureConstPtr ls = left->getStructure(); + + if(*ls!=*right->getStructure()) return false; const PVFieldPtrArray& lf = left->getPVFields(); const PVFieldPtrArray& rf = right->getPVFields(); - for(size_t i=0, nfld=left->getNumberFields(); igetNumberFields(); igetNumberFields(); iprint(*vals[i]); endStructure(fld); } From ae847aea2b20a0c178b3d0880dd29e378f4a2395 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 1 May 2013 11:27:37 -0400 Subject: [PATCH 024/103] allow putFrom to implicitly resize --- pvDataApp/pv/pvData.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index 164406f..c73c5f7 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -1099,6 +1099,8 @@ public: } virtual void putFrom(ScalarType dtype, const void*ptr, size_t count, size_t offset) { + if(getLength() Date: Wed, 1 May 2013 12:17:58 -0400 Subject: [PATCH 025/103] fix printer Don't overflow the stack for deep structures! --- pvDataApp/factory/printer.cpp | 91 ++++++++++++++++++++++++++--------- pvDataApp/pv/printer.h | 2 - 2 files changed, 68 insertions(+), 25 deletions(-) diff --git a/pvDataApp/factory/printer.cpp b/pvDataApp/factory/printer.cpp index 648812d..baf6c8a 100644 --- a/pvDataApp/factory/printer.cpp +++ b/pvDataApp/factory/printer.cpp @@ -1,4 +1,6 @@ +#include + #include "pv/printer.h" namespace { @@ -46,36 +48,79 @@ void PrinterBase::encodeScalar(const PVScalar& pv) {} void PrinterBase::encodeArray(const PVScalarArray&) {} -void PrinterBase::abortField(const PVField&) {} - void PrinterBase::impl_print(const PVField& pv) { - try { - switch(pv.getField()->getType()) { - case scalar: encodeScalar(static_cast(pv)); return; - case scalarArray: encodeArray(static_cast(pv)); return; - case structure: { - const PVStructure &fld = static_cast(pv); - const PVFieldPtrArray& vals = fld.getPVFields(); + /* Depth first recursive iteration. + * Each PV to be printed is appended to the todo queue. + * The last child of a structure is followed by a NULL. + * As the tree is walked structures and structarrays + * are appended to the inprog queue. + */ + std::deque todo, inprog; - beginStructure(fld); - for(size_t i=0, nfld=fld.getStructure()->getNumberFields(); iprint(*vals[i]); - endStructure(fld); + todo.push_back(&pv); + + while(!todo.empty()) { + const PVField *next = todo.front(); + todo.pop_front(); + + if(!next) { + // finished with a structure or structarray, + // now we fall back to its parent. + assert(!inprog.empty()); + switch(inprog.back()->getField()->getType()) { + case structure: + endStructure(*static_cast(inprog.back())); + break; + + case structureArray: + endStructureArray(*static_cast(inprog.back())); + break; + + default: + assert(false); // oops! + return; } - case structureArray: { - const PVStructureArray &fld = static_cast(pv); - const PVStructureArray::pointer vals = fld.get(); + inprog.pop_back(); - beginStructureArray(fld); - for(size_t i=0, nfld=fld.getLength(); iprint(*vals[i]); - endStructureArray(fld); + } else { + // real field + + switch(next->getField()->getType()) { + case scalar: + encodeScalar(*static_cast(next)); + break; + case scalarArray: + encodeArray(*static_cast(next)); + break; + case structure: { + const PVStructure &fld = *static_cast(next); + const PVFieldPtrArray& vals = fld.getPVFields(); + + inprog.push_back(next); + + beginStructure(fld); + for(size_t i=0, nfld=fld.getStructure()->getNumberFields(); i(next); + const PVStructureArray::pointer vals = fld.get(); + + inprog.push_back(next); + + beginStructureArray(fld); + for(size_t i=0, nfld=fld.getLength(); i Date: Wed, 1 May 2013 12:41:19 -0400 Subject: [PATCH 026/103] testTypeCast use epicsUnitTest --- testApp/misc/Makefile | 18 +++---- testApp/misc/testTypeCast.cpp | 96 ++++++++++++++++++----------------- 2 files changed, 55 insertions(+), 59 deletions(-) diff --git a/testApp/misc/Makefile b/testApp/misc/Makefile index 4e2cf83..2ed381d 100644 --- a/testApp/misc/Makefile +++ b/testApp/misc/Makefile @@ -2,51 +2,45 @@ TOP=../.. include $(TOP)/configure/CONFIG +PROD_LIBS += pvData Com + PROD_HOST += testThread testThread_SRCS += testThread.cpp -testThread_LIBS += pvData Com PROD_HOST += testTimer testTimer_SRCS += testTimer.cpp -testTimer_LIBS += pvData Com PROD_HOST += testBitSet testBitSet_SRCS += testBitSet.cpp -testBitSet_LIBS += pvData Com PROD_HOST += testByteOrder testByteOrder_SRCS += testByteOrder.cpp -testByteOrder_LIBS += Com PROD_HOST += testByteBuffer testByteBuffer_SRCS += testByteBuffer.cpp -testByteBuffer_LIBS += pvData Com PROD_HOST += testBaseException testBaseException_SRCS += testBaseException.cpp -testBaseException_LIBS += pvData Com PROD_HOST += testSerialization testSerialization_SRCS += testSerialization.cpp -testSerialization_LIBS += pvData Com PROD_HOST += testTimeStamp testTimeStamp_SRCS += testTimeStamp.cpp -testTimeStamp_LIBS += pvData Com PROD_HOST += testQueue testQueue_SRCS += testQueue.cpp -testQueue_LIBS += pvData Com PROD_HOST += testMessageQueue testMessageQueue_SRCS += testMessageQueue.cpp -testMessageQueue_LIBS += pvData Com -PROD_HOST += testTypeCast +TESTPROD += testTypeCast testTypeCast_SRCS += testTypeCast.cpp -testTypeCast_LIBS += pvData Com +TESTS += testTypeCast +TESTSCRIPTS_HOST += $(TESTS:%=%.t) + include $(TOP)/configure/RULES #---------------------------------------- # ADD RULES AFTER THIS LINE diff --git a/testApp/misc/testTypeCast.cpp b/testApp/misc/testTypeCast.cpp index d258edc..dc74d60 100644 --- a/testApp/misc/testTypeCast.cpp +++ b/testApp/misc/testTypeCast.cpp @@ -19,12 +19,11 @@ #include #include -#include +#include +#include #include "pv/typeCast.h" -#include - using epics::pvData::String; namespace { @@ -44,8 +43,9 @@ namespace { template struct testcase { - static bool op(std::ostream& msg, TO expect, FROM inp) + static void op(TO expect, FROM inp) { + std::ostringstream msg; TO actual; try { actual = ::epics::pvData::castUnsafe(inp); @@ -54,71 +54,69 @@ namespace { msg<<"Failed to cast " < " <::op(actual, expect)) { msg<<"Failed cast gives unexpected value " < " < " < struct testfail { - static bool op(std::ostream& msg, FROM inp) + static void op(FROM inp) { + std::ostringstream msg; TO actual; try { actual = ::epics::pvData::castUnsafe(inp); msg<<"Failed to generate expected error " < (" < (" <::op(*out, VTO, VFRO) +#define TEST(TTO, VTO, TFRO, VFRO) testcase::op(VTO, VFRO) // Test cast and reverse #define TEST2(TTO, VTO, TFRO, VFRO) TEST(TTO, VTO, TFRO, VFRO); TEST(TFRO, VFRO, TTO, VTO) -#define FAIL(TTO, TFRO, VFRO) fail |= !testfail::op(*out, VFRO) +#define FAIL(TTO, TFRO, VFRO) testfail::op(VFRO) } // end namespace -int main(int argc,char *argv[]) +MAIN(testTypeCast) { - std::ostream *out = &std::cerr; - std::ofstream outf; - if(argc>1){ - outf.open(argv[1]); - if(!outf.good()) { - std::cerr<<"Failed to open "< unsigned\n"; + testDiag("Integer signed <=> unsigned"); TEST2(uint8_t, std::numeric_limits::max(), int8_t, -1); TEST2(uint16_t, std::numeric_limits::max(), int8_t, -1); TEST2(uint32_t, std::numeric_limits::max(), int8_t, -1); TEST2(uint64_t, std::numeric_limits::max(), int8_t, -1); - *out << "Integer unsigned promote (and demote when in range)\n"; + testDiag("Integer unsigned promote (and demote when in range)"); TEST2(uint16_t, 0xff, uint8_t, 0xff); TEST2(uint32_t, 0xffff, uint16_t, 0xffff); @@ -290,7 +288,7 @@ int main(int argc,char *argv[]) TEST2(int32_t, 0x7fff, int16_t, 0x7fff); TEST2(int64_t, 0x7fffffff, int32_t, 0x7fffffff); - *out << "Double to int w/ round towards zero (aka truncation)\n"; + testDiag("Double to int w/ round towards zero (aka truncation)"); TEST(int32_t, 2, double, 2.1); TEST(int32_t, 2, double, 2.5); @@ -299,7 +297,7 @@ int main(int argc,char *argv[]) TEST(int32_t, -2, double, -2.5); TEST(int32_t, -2, double, -2.7); - *out << "Float to int w/ round towards zero (aka truncation)\n"; + testDiag("Float to int w/ round towards zero (aka truncation)"); TEST(int32_t, 2, float, 2.1); TEST(int32_t, 2, float, 2.5); @@ -308,7 +306,7 @@ int main(int argc,char *argv[]) TEST(int32_t, -2, float, -2.5); TEST(int32_t, -2, float, -2.7); - *out << "String Printing/parsing\n"; + testDiag("String Printing/parsing"); TEST2(String, "1", int32_t, 1); TEST2(String, "-1", int32_t, -1); @@ -339,7 +337,7 @@ int main(int argc,char *argv[]) TEST(double, 1.1e100, String, "1.1E+100"); - *out << "String Parsing\n"; + testDiag("String Parsing"); TEST(int32_t, 15, String, "0xf"); TEST(int32_t, 15, String, "0xF"); @@ -363,7 +361,7 @@ int main(int argc,char *argv[]) TEST(int64_t, -7, String, "-07"); TEST(int64_t, -8, String, "-010"); - *out << "String parsing errors\n"; + testDiag("String parsing errors"); FAIL(int32_t, String, "hello!"); FAIL(int32_t, String, "42 is the answer"); @@ -374,32 +372,36 @@ int main(int argc,char *argv[]) FAIL(int8_t, String, "1000"); FAIL(int8_t, String, "-1000"); - +; FAIL(double, String, "1e+10000000"); - *out << "Floating point overflows\n"; + testDiag("Floating point overflows"); TEST(float, FLT_MAX, double, 1e300); TEST(float, -FLT_MAX, double, -1e300); TEST(float, FLT_MIN, double, 1e-300); TEST(float, -FLT_MIN, double, -1e-300); + xfloat = ::epics::pvData::castUnsafe(epicsNAN); - *out << "Test cast double NAN to float NAN yields: "< String\n"; + testDiag("Test vcast int32 -> String"); epics::pvData::castUnsafeV(3, epics::pvData::pvString, (void*)result, epics::pvData::pvInt, (void*)in); - *out << "Yields "< Date: Wed, 1 May 2013 14:20:01 -0400 Subject: [PATCH 027/103] remove remaining state from Convert --- pvDataApp/factory/Convert.cpp | 1 - pvDataApp/pv/convert.h | 1 - 2 files changed, 2 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index 2633215..3724d3b 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -45,7 +45,6 @@ static std::vector split(String commaSeparatedList) { } Convert::Convert() -: pvDataCreate(getPVDataCreate()) {} diff --git a/pvDataApp/pv/convert.h b/pvDataApp/pv/convert.h index 1aa5e71..f67aa47 100644 --- a/pvDataApp/pv/convert.h +++ b/pvDataApp/pv/convert.h @@ -819,7 +819,6 @@ public: void newLine(StringBuilder buf, int indentLevel); private: Convert(); - PVDataCreatePtr pvDataCreate; }; static inline ConvertPtr getConvert() { return Convert::getConvert(); } From fd5ea893406d4e3d065172bbaa86363c6e9dc24c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 28 Dec 2012 11:19:54 -0500 Subject: [PATCH 028/103] typo --- pvDataApp/misc/sharedPtr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvDataApp/misc/sharedPtr.h b/pvDataApp/misc/sharedPtr.h index f896eaf..0a1ed76 100644 --- a/pvDataApp/misc/sharedPtr.h +++ b/pvDataApp/misc/sharedPtr.h @@ -4,7 +4,7 @@ * in file LICENSE that is included with this distribution. */ /** - * @author Michael DavidSaver + * @author Michael Davidsaver */ #ifndef SHAREDPTR_H From 9e8a6b63046d3c015f91d7fd525ccc756c833f83 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 8 May 2013 14:19:45 -0400 Subject: [PATCH 029/103] fix const-ness in PVField compare --- pvDataApp/factory/Compare.cpp | 28 ++++++++++++++-------------- pvDataApp/pv/convert.h | 4 ++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/pvDataApp/factory/Compare.cpp b/pvDataApp/factory/Compare.cpp index 689ac21..8237cc5 100644 --- a/pvDataApp/factory/Compare.cpp +++ b/pvDataApp/factory/Compare.cpp @@ -101,26 +101,26 @@ namespace { // fully typed comparisons template -bool compareScalar(PVScalarValue* left, PVScalarValue* right) +bool compareScalar(const PVScalarValue* left, const PVScalarValue* right) { return left->get()==right->get(); } template -bool compareArray(PVValueArray* left, PVValueArray* right) +bool compareArray(const PVValueArray* left, const PVValueArray* right) { return std::equal(left->get(), left->get()+left->getLength(), right->get()); } // partially typed comparisons -bool compareField(PVScalar* left, PVScalar* right) +bool compareField(const PVScalar* left, const PVScalar* right) { ScalarType lht = left->getScalar()->getScalarType(); if(lht != right->getScalar()->getScalarType()) return false; switch(lht) { -#define OP(ENUM, TYPE) case ENUM: return compareScalar(static_cast*>(left), static_cast*>(right)) +#define OP(ENUM, TYPE) case ENUM: return compareScalar(static_cast*>(left), static_cast*>(right)) OP(pvBoolean, uint8); OP(pvUByte, uint8); OP(pvByte, int8); @@ -134,14 +134,14 @@ bool compareField(PVScalar* left, PVScalar* right) OP(pvDouble, double); #undef OP case pvString: { - PVString *a=static_cast(left), *b=static_cast(right); + const PVString *a=static_cast(left), *b=static_cast(right); return a->get()==b->get(); } } throw std::logic_error("PVScalar with invalid scalar type!"); } -bool compareField(PVScalarArray* left, PVScalarArray* right) +bool compareField(const PVScalarArray* left, const PVScalarArray* right) { ScalarType lht = left->getScalarArray()->getElementType(); if(lht != right->getScalarArray()->getElementType()) @@ -151,7 +151,7 @@ bool compareField(PVScalarArray* left, PVScalarArray* right) return false; switch(lht) { -#define OP(ENUM, TYPE) case ENUM: return compareArray(static_cast*>(left), static_cast*>(right)) +#define OP(ENUM, TYPE) case ENUM: return compareArray(static_cast*>(left), static_cast*>(right)) OP(pvBoolean, uint8); OP(pvUByte, uint8); OP(pvByte, int8); @@ -169,7 +169,7 @@ bool compareField(PVScalarArray* left, PVScalarArray* right) throw std::logic_error("PVScalarArray with invalid element type!"); } -bool compareField(PVStructure* left, PVStructure* right) +bool compareField(const PVStructure* left, const PVStructure* right) { StructureConstPtr ls = left->getStructure(); @@ -186,7 +186,7 @@ bool compareField(PVStructure* left, PVStructure* right) return true; } -bool compareField(PVStructureArray* left, PVStructureArray* right) +bool compareField(const PVStructureArray* left, const PVStructureArray* right) { if(left->getLength()!=right->getLength()) return false; @@ -216,7 +216,7 @@ bool compareField(PVStructureArray* left, PVStructureArray* right) // untyped comparison -bool operator==(PVField& left, PVField& right) +bool operator==(const PVField& left, const PVField& right) { if(&left == &right) return true; @@ -226,10 +226,10 @@ bool operator==(PVField& left, PVField& right) return false; switch(lht) { - case scalar: return compareField(static_cast(&left), static_cast(&right)); - case scalarArray: return compareField(static_cast(&left), static_cast(&right)); - case structure: return compareField(static_cast(&left), static_cast(&right)); - case structureArray: return compareField(static_cast(&left), static_cast(&right)); + case scalar: return compareField(static_cast(&left), static_cast(&right)); + case scalarArray: return compareField(static_cast(&left), static_cast(&right)); + case structure: return compareField(static_cast(&left), static_cast(&right)); + case structureArray: return compareField(static_cast(&left), static_cast(&right)); } throw std::logic_error("PVField with invalid type!"); } diff --git a/pvDataApp/pv/convert.h b/pvDataApp/pv/convert.h index f67aa47..5bb23c0 100644 --- a/pvDataApp/pv/convert.h +++ b/pvDataApp/pv/convert.h @@ -19,9 +19,9 @@ namespace epics { namespace pvData { -bool operator==(PVField&, PVField&); +bool operator==(const PVField&, const PVField&); -static inline bool operator!=(PVField& a, PVField& b) +static inline bool operator!=(const PVField& a, const PVField& b) {return !(a==b);} From 461dbdf0f8bcdab8447b255435d613cc8d99f9da Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 8 May 2013 10:31:36 -0400 Subject: [PATCH 030/103] remove Convert pointer from PVField Allow inline construction of Convert --- pvDataApp/factory/Convert.cpp | 7 ------- pvDataApp/factory/PVField.cpp | 7 +++---- pvDataApp/pv/convert.h | 3 --- pvDataApp/pv/pvData.h | 1 - 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index 3724d3b..c33af5e 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -43,13 +43,6 @@ static std::vector split(String commaSeparatedList) { } return valueList; } - -Convert::Convert() -{} - - - -Convert::~Convert(){} void Convert::getString(StringBuilder buf,PVField const *pvField,int indentLevel) { diff --git a/pvDataApp/factory/PVField.cpp b/pvDataApp/factory/PVField.cpp index 577ccb8..e9cd3b7 100644 --- a/pvDataApp/factory/PVField.cpp +++ b/pvDataApp/factory/PVField.cpp @@ -26,8 +26,7 @@ PVField::PVField(FieldConstPtr field) : notImplemented("not implemented"), parent(NULL),field(field), fieldOffset(0), nextFieldOffset(0), - immutable(false), - convert(getConvert()) + immutable(false) { } @@ -175,7 +174,7 @@ void PVField::setParentAndName(PVStructure * xxx,String const & name) bool PVField::equals(PVField &pv) { - return convert->equals(*this,pv); + return pv==*this; } void PVField::toString(StringBuilder buf) @@ -185,7 +184,7 @@ void PVField::toString(StringBuilder buf) void PVField::toString(StringBuilder buf,int indentLevel) { - convert->getString(buf,this,indentLevel); + Convert().getString(buf,this,indentLevel); if(pvAuxInfo.get()!=NULL) pvAuxInfo->toString(buf,indentLevel); } diff --git a/pvDataApp/pv/convert.h b/pvDataApp/pv/convert.h index 5bb23c0..2ddfc21 100644 --- a/pvDataApp/pv/convert.h +++ b/pvDataApp/pv/convert.h @@ -71,7 +71,6 @@ typedef std::tr1::shared_ptr ConvertPtr; class Convert { public: static ConvertPtr getConvert(); - ~Convert(); /** * Get the full fieldName for the pvField. * @param builder The builder that will have the result. @@ -817,8 +816,6 @@ public: * @param indentLevel Indent level, Each level is four spaces. */ void newLine(StringBuilder buf, int indentLevel); -private: - Convert(); }; static inline ConvertPtr getConvert() { return Convert::getConvert(); } diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index c73c5f7..91738a2 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -373,7 +373,6 @@ private: bool immutable; RequesterPtr requester; PostHandlerPtr postHandler; - std::tr1::shared_ptr convert; friend class PVDataCreate; friend class PVStructure; }; From 3cd2bfdef02813745bfcd071a656d1ddeb1e8f69 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 8 May 2013 18:21:34 -0400 Subject: [PATCH 031/103] shared_vector implementation Shared ownership of a single C array. Tracks offset and length for each instance allowing each owner to "view" a different piece of the array. Parts of shared_vector which can work for T=void are in shared_vector_base. Specializations shared_vector and shared_vector handle un-typed arrays. Allow casting to/from typed vector Offsets and sizes of untyped vectors are tracked in bytes. Therefore casting to types where sizeof(T)>1 is undefined if the offset is not a multiple of sizeof(T). --- pvDataApp/Makefile | 1 + pvDataApp/misc/epicsException.h | 2 +- pvDataApp/misc/sharedVector.h | 734 ++++++++++++++++++++++++++++++++ 3 files changed, 736 insertions(+), 1 deletion(-) create mode 100644 pvDataApp/misc/sharedVector.h diff --git a/pvDataApp/Makefile b/pvDataApp/Makefile index bd628a4..cde0b2b 100644 --- a/pvDataApp/Makefile +++ b/pvDataApp/Makefile @@ -26,6 +26,7 @@ INC += sharedPtr.h INC += localStaticLock.h INC += typeCast.h INC += printer.h +INC += sharedVector.h LIBSRCS += byteBuffer.cpp LIBSRCS += bitSet.cpp diff --git a/pvDataApp/misc/epicsException.h b/pvDataApp/misc/epicsException.h index 24025cd..b7bfad6 100644 --- a/pvDataApp/misc/epicsException.h +++ b/pvDataApp/misc/epicsException.h @@ -103,7 +103,7 @@ namespace detail { * * Takes advantage of the requirement that all exception classes * must be copy constructable. Of course this also requires - * the and extra copy be constructed... + * that an extra copy be constructed... */ template class ExceptionMixed : public E, public ExceptionMixin { diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h new file mode 100644 index 0000000..e5098a8 --- /dev/null +++ b/pvDataApp/misc/sharedVector.h @@ -0,0 +1,734 @@ +#ifndef SHAREDVECTOR_H +#define SHAREDVECTOR_H + +#include +#include +#include +#include + +#include "pv/sharedPtr.h" + +namespace epics { namespace pvData { + +template class shared_vector; + +namespace detail { + template + struct default_array_deleter {void operator()(E a){delete[] a;}}; + + // Implicit casts allowed during copy construction of shared_vector + template + struct vector_implicit_cast { + // There is intentionally no implmentation here to cause + // compile errors for illegal casts. + //static std::tr1::shared_ptr cast(const std::tr1::shared_ptr); + }; + // non-const -> const + template + struct vector_implicit_cast { + static std::tr1::shared_ptr cast(const std::tr1::shared_ptr input) + { + return std::tr1::shared_ptr(input); + } + }; + + /* All the parts of shared_vector which + * don't need special handling for E=void + */ + template + class shared_vector_base + { + // allow specialization for all E to be friends + template friend class shared_vector_base; + protected: + std::tr1::shared_ptr m_data; + //! Offset in the data array of first element + size_t m_offset; + //! Number of visible elements between m_offset and end of data + size_t m_count; + //! Total number of elements between m_offset and the end of data + size_t m_total; + + public: + + //! @brief Empty vector (not very interesting) + shared_vector_base() + :m_data(), m_offset(0), m_count(0), m_total(0) + {} + + protected: + // helper for constructors + // Ensure that offset and size are zero when we are constructed with NULL + void _null_input() + { + if(!m_data.get()) { + m_offset = m_total = m_count = 0; + } + } + public: + + template + shared_vector_base(A v, size_t o, size_t c) + :m_data(v, detail::default_array_deleter()) + ,m_offset(o), m_count(c), m_total(c) + {_null_input();} + + template + shared_vector_base(const std::tr1::shared_ptr& d, size_t o, size_t c) + :m_data(d), m_offset(o), m_count(c), m_total(c) + {_null_input();} + + + template + shared_vector_base(A d, B b, size_t o, size_t c) + :m_data(d,b), m_offset(o), m_count(c), m_total(c) + {_null_input();} + + template + shared_vector_base(const shared_vector_base& o) + : m_data(vector_implicit_cast::cast(o.m_data)) + , m_offset(o.m_offset), m_count(o.m_count), m_total(o.m_total) + {_null_input();} + + //! @brief Copy an existing vector + shared_vector_base& operator=(const shared_vector_base& o) + { + if(&o!=this) { + m_data=o.m_data; + m_offset=o.m_offset; + m_count=o.m_count; + m_total=o.m_total; + } + return *this; + } + + //! @brief Swap the contents of this vector with another + void swap(shared_vector_base& o) { + if(&o!=this) { + m_data.swap(o.m_data); + std::swap(m_count, o.m_count); + std::swap(m_offset, o.m_offset); + std::swap(m_total, o.m_total); + } + } + + //! @brief Clear contents. + //! size() becomes 0 + void clear() { + m_data.reset(); + m_offset = m_total = m_count = 0; + } + + //! @brief Data is not shared? + bool unique() const {return !m_data || m_data.unique();} + + + //! @brief Number of elements visible through this vector + size_t size() const{return m_count;} + bool empty() const{return !m_count;} + + size_t max_size() const{return (size_t)-1;} + + + /** @brief Reduce the view of this shared_vector. + * + * Reduce the portion of the underlying buffer which + * is accessible through this shared_vector. + * + * When the requested new offset and length are not possible + * then the following holds. + * + * When offset is >= size() then after slice() size()==0. + * When length >= size()-offset then after slice() + * size() = old_size-offset. + * + @param offset The request new offset relative to the + * current offset. + @param length The requested new length. + * + @note offset and length are in units of sizeof(E). + * or bytes (1) when E=void. + */ + void slice(size_t offset, size_t length=(size_t)-1) + { + if(offset>m_total) + offset = m_total; + + m_offset += offset; + + m_total -= offset; + + if(offset>m_count) { + m_count = 0; + } else { + if(length > m_count - offset) + length = m_count - offset; + m_count = length; + } + } + + // Access to members. + const std::tr1::shared_ptr& dataPtr() const { return m_data; } + size_t dataOffset() const { return m_offset; } + size_t dataCount() const { return m_count; } + size_t dataTotal() const { return m_total; } + }; +} + +/** @brief A holder for a contigious piece of memory. + * + * Data is shared, but offset and length are not. + * This allows one vector to have access to only a + * subset of a piece of memory. + * + * The ways in which shared_vector is intended to differ from + * std::vector are outlined in @ref vectordiff . + * + * Also see @ref vectormem + */ +template +class shared_vector : public detail::shared_vector_base +{ + typedef detail::shared_vector_base base_t; +public: + typedef E value_type; + typedef E& reference; + typedef E* pointer; + typedef E* iterator; + typedef std::reverse_iterator reverse_iterator; + typedef ptrdiff_t difference_type; + typedef size_t size_type; + + typedef E element_type; + typedef std::tr1::shared_ptr shared_pointer_type; + + // allow specialization for all E to be friends + template friend class shared_vector; + + + //! @brief Empty vector (not very interesting) + shared_vector() :base_t() {} + + //! @brief Allocate (with new[]) a new vector of size c + explicit shared_vector(size_t c) + :base_t(new E[c], 0, c) + {} + + //! @brief Allocate (with new[]) a new vector of size c and fill with value e + shared_vector(size_t c, E e) + :base_t(new E[c], 0, c) + { + std::fill_n(this->m_data.get(), this->m_count, e); + } + + /** @brief Build vector from a raw pointer + * + @param v A raw pointer allocated with new[]. + @param o The offset in v or the first element visible to the vector + @param c The number of elements pointed to by v+o + */ + template + shared_vector(A v, size_t o, size_t c) :base_t(v,o,c) {} + + /** @brief Build vector from an existing smart pointer + * + @param d An existing smart pointer + @param o The offset in v or the first element visible to the vector + @param c The number of elements pointed to by v+o + */ + template + shared_vector(const std::tr1::shared_ptr& d, size_t o, size_t c) + :base_t(d,o,c) {} + + /** @brief Build vector from raw pointer and cleanup function + * + @param d An existing raw pointer + @param b An function/functor used to free d. Invoked as b(d). + @param o The offset in v or the first element visible to the vector + @param c The number of elements pointed to by v+o + */ + template + shared_vector(A d, B b, size_t o, size_t c) + :base_t(d,b,o,c) {} + + //! @brief Copy an existing vector of same or related type + template + shared_vector(const shared_vector& o) :base_t(o) {} + + size_t capacity() const { return this->m_total; } + + /** @brief Set array capacity + * + * A side effect is that array data will be uniquely owned by this instance + * as if make_unique() was called. This holds even if the capacity + * does not increase. + * + * For notes on copying see docs for make_exlcusive(). + */ + void reserve(size_t i) { + if(this->unique() && i<=this->m_total) + return; + pointer temp=new E[i]; + try{ + std::copy(begin(), end(), temp); + this->m_data.reset(temp, detail::default_array_deleter()); + }catch(...){ + delete[] temp; + throw; + } + this->m_offset = 0; + this->m_total = i; + // m_count is unchanged + } + + /** @brief Grow or shrink array + * + * A side effect is that array data will be uniquely owned by this instance + * as if make_unique() was called. This holds even if the size does not change. + * + * For notes on copying see docs for make_exlcusive(). + */ + void resize(size_t i) { + if(i==this->m_count) { + make_unique(); + return; + } + if(this->m_data && this->m_data.unique()) { + // we have data and exclusive ownership of it + if(i<=this->m_total) { + // We have room to grow! + this->m_count = i; + return; + } + } + // must re-allocate :( + size_t new_total = std::max(this->m_total, i); + pointer temp=new E[new_total]; + try{ + // Copy as much as possible from old, + // remaining elements are uninitialized. + std::copy(begin(), + begin()+std::min(i,this->size()), + temp); + this->m_data.reset(temp, detail::default_array_deleter()); + }catch(...){ + delete[] temp; + throw; + } + this->m_offset= 0; + this->m_count = i; + this->m_total = new_total; + } + + /** @brief Grow (and fill) or shrink array. + * + * see @ref resize(size_t) + */ + void resize(size_t i, E v) { + size_t oldsize=this->size(); + resize(i); + if(this->size()>oldsize) { + std::fill(begin()+oldsize, end(), v); + } + } + + /** @brief Ensure (by copying) that this shared_vector is the sole + * owner of the data array. + * + * If a copy is needed, memory is allocated with new[]. If this is + * not desireable then do something like the following. + @code + shared_vector original(...); + + if(!original.unique()){ + shared_vector temp(myallocator(original.size()), + 0, original.size()); + std::copy(original.begin(), original.end(), temp.begin()); + original.swap(temp); + } + assert(original.unique()); + @endcode + */ + void make_unique() { + if(this->unique()) + return; + shared_pointer_type d(new E[this->m_total], detail::default_array_deleter()); + std::copy(this->m_data.get()+this->m_offset, + this->m_data.get()+this->m_offset+this->m_count, + d.get()); + this->m_data.swap(d); + this->m_offset=0; + } + + + // STL iterators + + iterator begin() const{return this->m_data.get()+this->m_offset;} + + iterator end() const{return this->m_data.get()+this->m_offset+this->m_count;} + + reverse_iterator rbegin() const{return reverse_iterator(end());} + + reverse_iterator rend() const{return reverse_iterator(begin());} + + reference front() const{return (*this)[0];} + reference back() const{return (*this)[this->m_count-1];} + + // Modifications + + void push_back(const E& v) + { + resize(this->size()+1); + back() = v; + } + + void pop_back() + { + this->slice(0, this->size()-1); + } + + // data access + + pointer data() const{return this->m_data.get()+this->m_offset;} + + reference operator[](size_t i) const {return this->m_data.get()[this->m_offset+i];} + + reference at(size_t i) const + { + if(i>this->m_count) + throw std::out_of_range("Index out of bounds"); + return (*this)[i]; + } + +}; + +//! Specialization for storing untyped pointers +//! Does not allow access or iteration of contents +template<> +class shared_vector : public detail::shared_vector_base { + typedef detail::shared_vector_base base_t; +public: + typedef void* pointer; + typedef ptrdiff_t difference_type; + typedef size_t size_type; + + typedef std::tr1::shared_ptr shared_pointer_type; + + shared_vector() :base_t() {} + + template + shared_vector(A v, size_t o, size_t c) :base_t(v,o,c) {} + + template + shared_vector(const std::tr1::shared_ptr& d, size_t o, size_t c) + :base_t(d,o,c) {} + + template + shared_vector(A d, B b, size_t o, size_t c) + :base_t(d,b,o,c) {} + + template + shared_vector(const shared_vector& o) :base_t(o) {} + + pointer data() const{ + return (pointer)(((char*)this->m_data.get())+this->m_offset); + } +}; + +//! Specialization for storing constant untyped pointers +//! Does not allow access or iteration of contents +template<> +class shared_vector : public detail::shared_vector_base { + typedef detail::shared_vector_base base_t; +public: + typedef const void* pointer; + typedef ptrdiff_t difference_type; + typedef size_t size_type; + + typedef std::tr1::shared_ptr shared_pointer_type; + + shared_vector() :base_t() {} + + template + shared_vector(A v, size_t o, size_t c) :base_t(v,o,c) {} + + template + shared_vector(const std::tr1::shared_ptr& d, size_t o, size_t c) + :base_t(d,o,c) {} + + template + shared_vector(A d, B b, size_t o, size_t c) + :base_t(d,b,o,c) {} + + template + shared_vector(const shared_vector& o) :base_t(o) {} + + pointer data() const{ + return (pointer)(((char*)this->m_data.get())+this->m_offset); + } +}; + +template +class weak_vector { + std::tr1::weak_ptr m_data; + //! Offset in the data array of first element + size_t m_offset; + //! Number of elements between m_offset and end of data + size_t m_count; + +public: + typedef E element_type; + + weak_vector() + :m_data() + ,m_offset(0) + ,m_count(0) + {} + weak_vector(const weak_vector& o) + :m_data(o.m_data) + ,m_offset(o.m_offset) + ,m_count(o.m_count) + {} + weak_vector(const shared_vector& o) + :m_data(o.dataPtr()) + ,m_offset(o.dataOffset()) + ,m_count(o.dataCount()) + {} + + bool expired() const{return m_data.expired();} + shared_vector lock() const + { + return shared_vector(m_data.lock(), m_offset, m_count); + } + + void reset() + { + m_data.reset(); + m_offset = m_count = 0; + } + + void swap(weak_vector& o) + { + m_data.swap(o); + std::swap(m_offset, o.m_offset); + std::swap(m_count, o.m_count); + } +}; + +namespace detail { + template struct shared_vector_caster {}; + + template + struct shared_vector_caster { + static inline shared_vector op(const shared_vector& src) { + return shared_vector( + std::tr1::static_pointer_cast(src.dataPtr()), + src.dataOffset()*sizeof(FROM), + src.dataCount()*sizeof(FROM)); + } + }; + + template + struct shared_vector_caster { + static inline shared_vector op(const shared_vector& src) { + return shared_vector( + std::tr1::static_pointer_cast(src.dataPtr()), + src.dataOffset()/sizeof(TO), + src.dataCount()/sizeof(TO)); + } + }; +} + +/** @brief Allow casting of shared_vector between types + * + * Currently only to/from void is implemented. + * + @warning Casting from void is undefined unless the offset and length + * are integer multiples of the size of the destination type. + */ +template +static inline +shared_vector +static_shared_vector_cast(const shared_vector& src) +{ + return detail::shared_vector_caster::op(src); +} + +//! Allows casting from const TYPE -> TYPE. +template +static inline +shared_vector +const_shared_vector_cast(const shared_vector& src) +{ + return shared_vector( + std::tr1::const_pointer_cast(src.dataPtr()), + src.dataOffset(), + src.dataCount()); +} + + +}} // namespace epics::pvData + +// Global operators for shared_vector + +template +bool operator==(const epics::pvData::shared_vector& a, + const epics::pvData::shared_vector& b) +{ + if(a.size() != b.size()) + return false; + if(a.dataOffset()==b.dataOffset() && a.dataPtr().get()==b.dataPtr().get()) + return true; + return std::equal(a.begin(), a.end(), b.begin()); +} + +template +bool operator!=(const epics::pvData::shared_vector& a, + const epics::pvData::shared_vector& b) +{ + return !(a==b); +} + +template +std::ostream& operator<<(std::ostream& strm, const epics::pvData::shared_vector& arr) +{ + strm<<'{'<10) { + strm<<"..."; + break; + } + strm<' is 'const shared_vector'. However, + * it is also possible to have 'const shared_vector' analogous to + * 'E* const' and 'shared_vector' which is analogous to + * 'const E*'. + * + * Copying a shared_vector, by construction or assignment, does + * not copy its contents. Modifications to one such "copy" effect + * all associated shared_vector instances. + * + * std::vector::reserve(N) has no effect if N<=std::vector::capacity(). + * However, like resize(), shared_vector::reserve() has the side + * effect of always calling make_unique(). + * + * @section notimpl Parts of std::vector interface not implemented + * + * Mutating methods insert(), erase(), shrink_to_fit(), + * emplace(), and emplace_back() are not implemented. + * + * shared_vector does not model an allocator which is bound to the object. + * Therefore the get_allocator() method and the allocator_type typedef are + * not provided. + * + * shared_vector does not provide the const_* typedefs. + * + * The assign() method and the related constructor are not implemented + * at this time. + * + * The comparison operators '>', '>=', '<=', and '<' are not implemented + * at this time. + * + * @section newstuff Parts not found in std::vector + * + * shared_vector has additional constructors from raw pointers + * and shared_ptr s. + * + * The copy constructor and assignment operator allow implicit + * casting from type 'shared_vector' to 'shared_vector'. + * + * To faciliate safe modification the methods unique() and + * make_unique() are provided. + * + * The slice() method selects a sub-set of the shared_vector. + * + * The low level accessors dataPtr(), dataOffset(), dataCount(), + * and dataTotal(). + * + */ + +/** @page vectormem Memory Management with shared_vector + * + * The @link epics::pvData::shared_vector shared_vector class @endlink + * is a std::vector like class which implements sharing data by reference counting. + * + * Internally memory is tracked with the shared_ptr reference counting smart pointer. + * This allows a custom destructor to be specified. This allows a vector to borrow + * memory allocated by 3rd party libraries which require special cleanup. + * + * In place element modification is allowed. It is left to user code to ensure + * that such modification is safe, either from application specific knowledge, or by + * calling + * @link paramTable::string_data::make_unique make_unique @endlink + * explicitly, or implicitly by calling + * @link paramTable::shared_vector::resize resize @endlink + * prior to making modifications. + * + @code + extern "C" { + // array embedded in C structure + struct composite { + int other, stuff; + char buf[42]; + } + + // Unknown relation between array and handle + typedef void* handle_type; + handle_type mylib_alloc(void); + char *mylib_mem(handle_type); + void mylib_free(handle_type); + } + + // Note that mylibcleaner must be copy constructable + struct mylibcleaner { + handle_type handle; + mylibcleaner(handle_type h) :handle(h) {} + void operator()(char*){ mylib_free(handle);} + }; + + struct compcleaner { + void operator()(char* c){ free(c-offsetof(composite,buf)); } + }; + + void main() { + + unsigned char* buf=calloc(42,1); + + shared_vector a(buf, &free); + + a.clear(); // calls free(ptr) + + + composite *c=malloc(sizeof(*c)); + assert(c!=NULL); + + shared_vector d(c->buf, compcleaner()); + + d.clear(); // calls free(ptr-offsetof(composite,buf)) + + + void *handle=mylib_alloc(); + char *hmem=mylib_mem(handle); + assert(hmem!=NULL); + + shared_vector b(hmem, mylibcleaner(handle)); + + b.clear(); // calls mylib_free(handleptr) + } + @endcode + */ From b137b32fc6b89f695293dc15be50fd7566994bd7 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 8 May 2013 18:21:52 -0400 Subject: [PATCH 032/103] test shared_vector use epicsUnitTest test handling of void and const void instances --- testApp/misc/Makefile | 3 + testApp/misc/testSharedVector.cpp | 336 ++++++++++++++++++++++++++++++ 2 files changed, 339 insertions(+) create mode 100644 testApp/misc/testSharedVector.cpp diff --git a/testApp/misc/Makefile b/testApp/misc/Makefile index 2ed381d..a9fceba 100644 --- a/testApp/misc/Makefile +++ b/testApp/misc/Makefile @@ -38,6 +38,9 @@ TESTPROD += testTypeCast testTypeCast_SRCS += testTypeCast.cpp TESTS += testTypeCast +TESTPROD += testSharedVector +testSharedVector_SRCS += testSharedVector.cpp +TESTS += testSharedVector TESTSCRIPTS_HOST += $(TESTS:%=%.t) diff --git a/testApp/misc/testSharedVector.cpp b/testApp/misc/testSharedVector.cpp new file mode 100644 index 0000000..c76e350 --- /dev/null +++ b/testApp/misc/testSharedVector.cpp @@ -0,0 +1,336 @@ +/** + * 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 */ + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "pv/sharedVector.h" + +static void testEmpty() +{ + testDiag("Test empty vector"); + epics::pvData::shared_vector empty, empty2; + + testOk1(empty.size()==0); + testOk1(empty.empty()); + testOk1(empty.begin()==empty.end()); + testOk1(empty.unique()); + + testOk1(empty.data()==NULL); + + testOk1(empty==empty); + testOk1(!(empty!=empty)); + testOk1(empty==empty2); + testOk1(!(empty!=empty2)); +} + +static void testInternalAlloc() +{ + testDiag("Test vector alloc w/ new[]"); + + epics::pvData::shared_vector internal(5); + + testOk1(internal.size()==5); + testOk1(!internal.empty()); + testOk1(internal.unique()); + testOk1(internal.data()!=NULL); + + testOk1(internal.begin()+5==internal.end()); + testOk1(internal.begin()==internal.end()-5); + testOk1(internal.begin()+2==internal.end()-3); + testOk1(internal.end()-internal.begin()==5); + + internal[2] = 42; + testOk1(internal[2]==42); + + epics::pvData::shared_vector internal2(15, 500); + + testOk1(internal2.size()==15); + testOk1(internal2[1]==500); + + internal.swap(internal2); + + testOk1(internal2.size()==5); + testOk1(internal.size()==15); + + internal.clear(); + + testOk1(internal.size()==0); + testOk1(internal.empty()); + testOk1(internal.unique()); + testOk1(internal.data()==NULL); +} + +namespace { + //Note: STL shared_ptr requires that deletors be copy constructable + template + struct callCounter { + std::tr1::shared_ptr count; + callCounter():count(new int){*count=0;} + callCounter(const callCounter& o):count(o.count) {}; + callCounter& operator=(const callCounter& o){count=o.count;} + void operator()(E){*count=1;} + }; +} + +static void testExternalAlloc() +{ + testDiag("Test vector external alloc"); + + // Simulate a failed malloc() or similar + int *oops=0; + epics::pvData::shared_vector nullPtr(oops, 42, 100); + + testOk1(nullPtr.size()==0); + testOk1(nullPtr.empty()); + testOk1(nullPtr.begin()==nullPtr.end()); + testOk1(nullPtr.unique()); + + testOk1(nullPtr.data()==NULL); + + int *raw=new int[5]; + epics::pvData::shared_vector newData(raw, 1, 4); + + testOk1(newData.size()==4); + testOk1(!newData.empty()); + + // check that offset is used + raw[1]=14; + testOk1(newData[0]==14); + + // Check use of custom deleter + int localVar[4] = {1,2,3,4}; + callCounter tracker; + testOk1(*tracker.count==0); + + epics::pvData::shared_vector locvar(localVar, + tracker, + 0, 4); + + testOk1(locvar[1]==2); + testOk1(*tracker.count==0); + + newData.swap(locvar); + + testOk1(*tracker.count==0); + + newData.clear(); + + testOk1(*tracker.count==1); +} + +static void testShare() +{ + testDiag("Test vector Sharing"); + + epics::pvData::shared_vector one, two(15); + epics::pvData::shared_vector three(two); + + testOk1(one.unique()); + testOk1(!two.unique()); + testOk1(!three.unique()); + + testOk1(two.data() == three.data()); + + one = two; + + testOk1(!one.unique()); + + testOk1(two.data() == one.data()); + + one = one; // no-op + + testOk1(two.data() == one.data()); + + one[1] = 43; + testOk1(two[1]==43); + testOk1(three[1]==43); + + one.make_unique(); + + one[1] = 143; + testOk1(two[1]==43); + testOk1(three[1]==43); + + two.resize(two.size()); + + two[1] = 243; + testOk1(one[1]==143); + testOk1(three[1]==43); + + testOk1(one.unique()); + testOk1(two.unique()); + testOk1(three.unique()); + + one.resize(2); + + testOk1(one.size()==2); + testOk1(two.size()==15); + testOk1(three.size()==15); + + two.resize(20, 5000); + + testOk1(one.size()==2); + testOk1(two.size()==20); + testOk1(three.size()==15); + + testOk1(two[19]==5000); +} + +static void testConst() +{ + testDiag("Test constant vector"); + + epics::pvData::shared_vector writable(15, 100); + + // can re-target container, but data is R/O + epics::pvData::shared_vector rodata(writable); + + // Data is R/W, but container can't be re-targeted + const epics::pvData::shared_vector roref(writable); + + // Can't change anything. + const epics::pvData::shared_vector fixed(writable); + + testOk1(rodata[1]==100); + + writable[1]=200; + + testOk1(rodata[1]==200); +} + +static void testSlice() +{ + testDiag("Test vector slicing"); + + epics::pvData::shared_vector original(10, 100); + + epics::pvData::shared_vector half1(original), half2(original), half2a(original); + + half1.slice(0, 5); + half2.slice(5, 5); + half2a.slice(5); + + testOk1(half1.dataOffset()==0); + testOk1(half2.dataOffset()==5); + testOk1(half2a.dataOffset()==5); + + testOk1(half2.size() == half2a.size()); + + testOk1(original.data() == half1.data()); + testOk1(half2.data() == half2a.data()); + + half1.slice(100000); + half2.slice(1); + half2a.slice(1,1); + + testOk1(half1.size()==0); + testOk1(half2.size()==4); + testOk1(half2a.size()==1); + + testOk1(half1.dataOffset()==10); + testOk1(half2.dataOffset()==6); + testOk1(half2a.dataOffset()==6); + + half2.clear(); + testOk1(half2.dataOffset()==0); + testOk1(half2.dataCount()==0); + testOk1(half2.dataTotal()==0); + testOk1(half2.data()==NULL); +} + +static void testCapacity() +{ + testDiag("Test vector capacity"); + + epics::pvData::shared_vector vect(10, 100); + + int *peek = vect.dataPtr().get(); + + vect.slice(0, 5); + + testOk1(vect.size()==5); + testOk1(vect.dataTotal()==10); + testOk1(vect.dataPtr().get() == peek); + + vect.resize(6); + + testOk1(vect.dataPtr().get() == peek); + testOk1(vect.size()==6); + testOk1(vect.dataTotal()==10); + + vect.resize(10); + + testOk1(vect.dataPtr().get() == peek); + testOk1(vect.size()==10); + testOk1(vect.dataTotal()==10); + + vect.resize(11); + + testOk1(vect.dataPtr().get() != peek); + testOk1(vect.size()==11); + testOk1(vect.dataTotal()>=11); + + vect[1] = 124; + + vect.reserve(15); + + testOk1(vect.size()==11); + testOk1(vect.dataTotal()>=15); + + testOk1(vect[1]==124); +} + +static void testVoid() +{ + testDiag("Test vecter cast to/from void"); + + epics::pvData::shared_vector typed(4); + epics::pvData::shared_vector untyped; + epics::pvData::shared_vector constuntyped; + + untyped = epics::pvData::const_shared_vector_cast(constuntyped); + + epics::pvData::shared_vector untyped2(epics::pvData::static_shared_vector_cast(typed)); + + testOk1(typed.dataPtr().get()==untyped2.dataPtr().get()); + testOk1(typed.size()*sizeof(int)==untyped2.size()); + + untyped2.slice(sizeof(int), 2*sizeof(int)); + + typed = epics::pvData::static_shared_vector_cast(untyped2); + + testOk1(typed.dataOffset()==1); + testOk1(typed.size()==2); +} + +MAIN(testSharedVector) +{ + testPlan(99); + testDiag("Tests for shared_vector"); + + testDiag("sizeof(shared_vector)=%lu", + (unsigned long)sizeof(epics::pvData::shared_vector)); + + testEmpty(); + testInternalAlloc(); + testExternalAlloc(); + testCapacity(); + testShare(); + testConst(); + testSlice(); + testVoid(); + return testDone(); +} From 79cd374f16dc298eacde10f9adf83e5494fc440c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 7 May 2013 13:22:50 -0400 Subject: [PATCH 033/103] add ScalarTypeFunc::allocArray --- pvDataApp/factory/TypeFunc.cpp | 22 ++++++++++++++++++++++ pvDataApp/pv/pvIntrospect.h | 17 +++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/pvDataApp/factory/TypeFunc.cpp b/pvDataApp/factory/TypeFunc.cpp index 68075b3..2685d3c 100644 --- a/pvDataApp/factory/TypeFunc.cpp +++ b/pvDataApp/factory/TypeFunc.cpp @@ -78,6 +78,28 @@ namespace ScalarTypeFunc { *buf += name(scalarType); } + shared_vector allocArray(ScalarType id, size_t len) + { + switch(id) { +#define OP(ENUM, TYPE) case ENUM: return static_shared_vector_cast(shared_vector(len)) + OP(pvBoolean, uint8); + OP(pvUByte, uint8); + OP(pvByte, int8); + OP(pvUShort, uint16); + OP(pvShort, int16); + OP(pvUInt, uint32); + OP(pvInt, int32); + OP(pvULong, uint64); + OP(pvLong, int64); + OP(pvFloat, float); + OP(pvDouble, double); + OP(pvString, String); +#undef OP + default: + throw std::bad_alloc(); + } + } + } // namespace ScalarTypeFunc }} diff --git a/pvDataApp/pv/pvIntrospect.h b/pvDataApp/pv/pvIntrospect.h index 9f3179d..bedd97f 100644 --- a/pvDataApp/pv/pvIntrospect.h +++ b/pvDataApp/pv/pvIntrospect.h @@ -16,6 +16,7 @@ #include #include #include +#include namespace epics { namespace pvData { @@ -579,5 +580,21 @@ OP(pvDouble, double); OP(pvString, String); #undef OP + +namespace ScalarTypeFunc { + //! Allocate an untyped array based on ScalarType + shared_vector allocArray(ScalarType id, size_t len); + + //! Allocate an untyped array based on ScalarType + template + inline + shared_vector::type> + allocArray(size_t len) + { + shared_vector raw(allocArray(ID, len)); + return static_shared_vector_cast::type>(raw); + } +} + }} #endif /* PVINTROSPECT_H */ From 5f4ca240b4467dc9327e59fd60aa6c2a883a708f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 7 May 2013 16:51:48 -0400 Subject: [PATCH 034/103] add ScalarTypeFunc::elementSize --- pvDataApp/factory/TypeFunc.cpp | 26 ++++++++++++++++++++++++-- pvDataApp/pv/pvIntrospect.h | 3 +++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/pvDataApp/factory/TypeFunc.cpp b/pvDataApp/factory/TypeFunc.cpp index 2685d3c..0d38b6c 100644 --- a/pvDataApp/factory/TypeFunc.cpp +++ b/pvDataApp/factory/TypeFunc.cpp @@ -78,11 +78,33 @@ namespace ScalarTypeFunc { *buf += name(scalarType); } + size_t elementSize(ScalarType id) + { + switch(id) { +#define OP(ENUM, TYPE) case ENUM: return sizeof(TYPE) + OP(pvBoolean, boolean); + OP(pvUByte, uint8); + OP(pvByte, int8); + OP(pvUShort, uint16); + OP(pvShort, int16); + OP(pvUInt, uint32); + OP(pvInt, int32); + OP(pvULong, uint64); + OP(pvLong, int64); + OP(pvFloat, float); + OP(pvDouble, double); + OP(pvString, String); +#undef OP + default: + THROW_EXCEPTION2(std::invalid_argument, "error unknown ScalarType"); + } + } + shared_vector allocArray(ScalarType id, size_t len) { switch(id) { -#define OP(ENUM, TYPE) case ENUM: return static_shared_vector_cast(shared_vector(len)) - OP(pvBoolean, uint8); +#define OP(ENUM, TYPE) case ENUM: return static_shared_vector_cast(shared_vector(len)) + OP(pvBoolean, boolean); OP(pvUByte, uint8); OP(pvByte, int8); OP(pvUShort, uint16); diff --git a/pvDataApp/pv/pvIntrospect.h b/pvDataApp/pv/pvIntrospect.h index bedd97f..51d1015 100644 --- a/pvDataApp/pv/pvIntrospect.h +++ b/pvDataApp/pv/pvIntrospect.h @@ -192,6 +192,9 @@ namespace ScalarTypeFunc { * @param scalarType The type. */ void toString(StringBuilder builder,ScalarType scalarType); + + //! gives sizeof(T) where T depends on the scalar type id. + size_t elementSize(ScalarType id); }; /** From e843779555a17d36f5609a71c664cbc4cfad8cc8 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 2 May 2013 18:09:53 -0400 Subject: [PATCH 035/103] New array API for PVValueArray using shared_vector * In PVScalarArray Add methods assign, getAs/putFrom, and copyOut/copyIn to allow get/put with implicit convert. assign() copys on PVScalarArray to another converting as necessary. If the types do not match then an allocate and convert is done. getAs/putFrom work with shared_vector and can avoid a allocate and convert operation if the types match. copyOut/copyIn use plain C arrays will do either a copy if the types match, and a convert otherwise. No allocation is performed. * In PVValueArray All array operations re-implemented in terms of two virtual methods virtual const shared_vector& viewUnsafe() const; virtual void swap(shared_vector&); Some convienence methods are also included: shared_vector view() const shared_vector take() shared_vector reuse() Deprecate get(...), put(...), and shareData(...) Remove getVector() and getSharedVector() Adjust DefaultPVArray accordingly --- pvDataApp/factory/PVDataCreateFactory.cpp | 332 ++++++++-------------- pvDataApp/pv/pvData.h | 286 ++++++++++++++++--- 2 files changed, 364 insertions(+), 254 deletions(-) diff --git a/pvDataApp/factory/PVDataCreateFactory.cpp b/pvDataApp/factory/PVDataCreateFactory.cpp index 7561336..0a2fe00 100644 --- a/pvDataApp/factory/PVDataCreateFactory.cpp +++ b/pvDataApp/factory/PVDataCreateFactory.cpp @@ -196,51 +196,31 @@ public: typedef const std::vector const_vector; typedef std::tr1::shared_ptr shared_vector; + typedef ::epics::pvData::shared_vector svector; + typedef ::epics::pvData::shared_vector const_svector; + DefaultPVArray(ScalarArrayConstPtr const & scalarArray); virtual ~DefaultPVArray(); + virtual void setCapacity(size_t capacity); virtual void setLength(size_t length); - virtual size_t get(size_t offset, size_t length, PVArrayData &data) ; - virtual size_t put(size_t offset,size_t length, const_pointer from, - size_t fromOffset); - virtual void shareData( - std::tr1::shared_ptr > const & value, - std::size_t capacity, - std::size_t length); - virtual pointer get() ; - virtual pointer get() const ; - virtual vector const & getVector() { return *value.get(); } - virtual shared_vector const & getSharedVector(){return value;}; + + virtual const svector& viewUnsafe() const; + virtual void swap(svector &other); + // from Serializable virtual void serialize(ByteBuffer *pbuffer,SerializableControl *pflusher) const; virtual void deserialize(ByteBuffer *pbuffer,DeserializableControl *pflusher); virtual void serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, size_t offset, size_t count) const; private: - shared_vector value; + svector value; }; -template -T *DefaultPVArray::get() -{ - std::vector *vec = value.get(); - T *praw = &((*vec)[0]); - return praw; -} - -template -T *DefaultPVArray::get() const -{ - std::vector *vec = value.get(); - T *praw = &((*vec)[0]); - return praw; -} - - template DefaultPVArray::DefaultPVArray(ScalarArrayConstPtr const & scalarArray) : PVValueArray(scalarArray), - value(std::tr1::shared_ptr >(new std::vector())) + value() { } @@ -251,101 +231,41 @@ DefaultPVArray::~DefaultPVArray() template void DefaultPVArray::setCapacity(size_t capacity) { - if(PVArray::getCapacity()==capacity) return; - if(!PVArray::isCapacityMutable()) { - std::string message("not capacityMutable"); - PVField::message(message, errorMessage); - return; + if(capacity>value.capacity()) { + value.reserve(capacity); + PVArray::setCapacityLength(value.capacity(), value.size()); } - size_t length = PVArray::getLength(); - if(length>capacity) length = capacity; - size_t oldCapacity = PVArray::getCapacity(); - if(oldCapacity>capacity) { - std::vector array; - array.reserve(capacity); - array.resize(length); - T * from = get(); - for (size_t i=0; iswap(array); - } else { - value->reserve(capacity); - } - PVArray::setCapacityLength(capacity,length); } template void DefaultPVArray::setLength(size_t length) { - if(PVArray::getLength()==length) return; - size_t capacity = PVArray::getCapacity(); - if(length>capacity) { - if(!PVArray::isCapacityMutable()) { - std::string message("not capacityMutable"); - PVField::message(message, errorMessage); - return; - } - setCapacity(length); - } - value->resize(length); - PVArray::setCapacityLength(capacity,length); + if(length == value.size()) + return; + else if(length < value.size()) + value.slice(0, length); + else + value.resize(length); + PVArray::setCapacityLength(value.capacity(), value.size()); +} + + +template +const typename DefaultPVArray::svector& DefaultPVArray::viewUnsafe() const +{ + return value; } template -size_t DefaultPVArray::get(size_t offset, size_t len, PVArrayData &data) +void DefaultPVArray::swap(svector &other) { - size_t n = len; - size_t length = this->getLength(); - if(offset+len > length) { - n = length-offset; - //if(n<0) n = 0; - } - data.data = *value.get(); - data.offset = offset; - return n; + if(this->isImmutable()) + THROW_EXCEPTION2(std::logic_error,"Immutable"); + + value.swap(other); + PVArray::setCapacityLength(value.capacity(), value.size()); } -template -size_t DefaultPVArray::put(size_t offset,size_t len, - const_pointer from,size_t fromOffset) -{ - if(PVField::isImmutable()) { - PVField::message("field is immutable",errorMessage); - return 0; - } - T * pvalue = get(); - if(from==pvalue) return len; - if(len<1) return 0; - size_t length = this->getLength(); - size_t capacity = this->getCapacity(); - if(offset+len > length) { - size_t newlength = offset + len; - if(newlength>capacity) { - setCapacity(newlength); - newlength = this->getCapacity(); - len = newlength - offset; - if(len<=0) return 0; - } - length = newlength; - setLength(length); - } - pvalue = get(); - for(size_t i=0;isetLength(length); - this->postPut(); - return len; -} - -template -void DefaultPVArray::shareData( - std::tr1::shared_ptr > const & sharedValue, - std::size_t capacity, - std::size_t length) -{ - value = sharedValue; - PVArray::setCapacityLength(capacity,length); -} template void DefaultPVArray::serialize(ByteBuffer *pbuffer, @@ -357,93 +277,91 @@ template void DefaultPVArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { size_t size = SerializeHelper::readSize(pbuffer, pcontrol); - // alignment if (size>0) { pcontrol->ensureData(sizeof(T)-1); pbuffer->align(sizeof(T)); } - //if(size>=0) { - // prepare array, if necessary - if(size>this->getCapacity()) this->setCapacity(size); - // set new length - this->setLength(size); - // try to avoid deserializing from the buffer - // this is only possible if we do not need to do endian-swapping - if (!pbuffer->reverse()) - if (pcontrol->directDeserialize(pbuffer, (char*)(get()), size, sizeof(T))) - { - // inform about the change? - PVField::postPut(); - return; - } + value.resize(size); // TODO: avoid copy of stuff we will then overwrite - // retrieve value from the buffer - size_t i = 0; - T * pvalue = get(); - while(true) { - /* - size_t maxIndex = min(size-i, (int)(pbuffer->getRemaining()/sizeof(T)))+i; - for(; iget(); - */ - size_t maxCount = min(size-i, (pbuffer->getRemaining()/sizeof(T))); - pbuffer->getArray(pvalue+i, maxCount); - i += maxCount; - - if(iensureData(sizeof(T)); // this is not OK since can exceen max local buffer (size-i)*sizeof(T)); - else - break; - } + PVArray::setCapacityLength(value.capacity(), value.size()); + T* cur = value.data(); + + // try to avoid deserializing from the buffer + // this is only possible if we do not need to do endian-swapping + if (!pbuffer->reverse()) + if (pcontrol->directDeserialize(pbuffer, (char*)cur, size, sizeof(T))) + { // inform about the change? PVField::postPut(); - //} - // TODO null arrays (size == -1) not supported + return; + } + + // retrieve value from the buffer + size_t remaining = size; + while(remaining) { + const size_t have_bytes = pbuffer->getRemaining(); + + // correctly rounds down in an element is partially received + const size_t available = have_bytes/sizeof(T); + + if(available == 0) { + size_t want = sizeof(T); + if(remaining==1 && sizeof(T)>1) { + // Need to wait for the last few bytes + // of the final element. + // available==0 implies have_bytesensureData(want); + continue; + } + + const size_t n2read = std::min(remaining, available); + + pbuffer->getArray(cur, n2read); + cur += n2read; + remaining -= n2read; + } + // inform about the change? + PVField::postPut(); } template void DefaultPVArray::serialize(ByteBuffer *pbuffer, - SerializableControl *pflusher, size_t offset, size_t count) const { - // cache - size_t length = this->getLength(); + SerializableControl *pflusher, size_t offset, size_t count) const +{ + //TODO: avoid incrementing the ref counter... + svector temp(value); + temp.slice(offset, count); + count = temp.size(); - // check bounds - /*if(offset<0) - offset = 0; - else*/ if(offset>length) offset = length; - //if(count<0) count = length; - - size_t maxCount = length-offset; - if(count>maxCount) count = maxCount; - - // write - SerializeHelper::writeSize(count, pbuffer, pflusher); - //if (count == 0) return; pcontrol->ensureData(sizeof(T)-1); pbuffer->align(sizeof(T)); + SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); + T* cur = temp.data(); // try to avoid copying into the buffer // this is only possible if we do not need to do endian-swapping if (!pbuffer->reverse()) - if (pflusher->directSerialize(pbuffer, (const char*)(get()+offset), count, sizeof(T))) + if (pflusher->directSerialize(pbuffer, (const char*)cur, count, sizeof(T))) return; - size_t end = offset+count; - size_t i = offset; - T * pvalue = const_cast(get()); - while(true) { - - /* - size_t maxIndex = min(end-i, (int)(pbuffer->getRemaining()/sizeof(T)))+i; - for(; iput(value[i]); - */ - - size_t maxCount = min(end-i, (int)(pbuffer->getRemaining()/sizeof(T))); - pbuffer->putArray(pvalue+i, maxCount); - i += maxCount; - - if(igetRemaining(); + const size_t space_for = empty/sizeof(T); + + if(space_for==0) { pflusher->flushSerializeBuffer(); - else - break; + // Can we be certain that more space is now free??? + // If not then we spinnnnnnnnn + continue; + } + + const size_t n2send = std::min(count, space_for); + + pbuffer->putArray(cur, n2send); + cur += n2send; + count -= n2send; } + + pflusher->flushSerializeBuffer(); } // specializations for String @@ -452,42 +370,36 @@ template<> void DefaultPVArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { size_t size = SerializeHelper::readSize(pbuffer, pcontrol); - //if(size>=0) { - // prepare array, if necessary - if(size>getCapacity()) setCapacity(size); - // set new length - setLength(size); - // retrieve value from the buffer - String * pvalue = get(); - for(size_t i = 0; i value.size() || !value.unique()) + value.resize(size); + else if(size < value.size()) + value.slice(0, size); + + setCapacityLength(size, size); + + + String * pvalue = value.data(); + for(size_t i = 0; i void DefaultPVArray::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, size_t offset, size_t count) const { - size_t length = getLength(); - // check bounds - /*if(offset<0) - offset = 0; - else*/ if(offset>length) offset = length; - //if(count<0) count = length; + svector temp(value); + temp.slice(offset, count); - size_t maxCount = length-offset; - if(count>maxCount) count = maxCount; + SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); - // write - SerializeHelper::writeSize(count, pbuffer, pflusher); - size_t end = offset+count; - String * pvalue = get(); - for(size_t i = offset; i #include #include @@ -19,6 +28,7 @@ #include #include #include +#include namespace epics { namespace pvData { @@ -657,22 +667,75 @@ public: */ const ScalarArrayConstPtr getScalarArray() const ; + /** + * Fetch the current value and convert to the requeted type. + * + * A copy is made if the requested type does not match + * the element type. If the types do match then + * no copy is made. + */ template - inline void getAs(typename ScalarTypeTraits::type* ptr, - size_t count, size_t offset = 0) const + inline void + getAs(shared_vector::type>& out) const { - getAs(ID, (void*)ptr, count, offset); + shared_vector temp(static_shared_vector_cast(out)); + getAs(ID, temp); + out = static_shared_vector_cast::type>(temp); } - virtual void getAs(ScalarType, void*, size_t, size_t) const = 0; + virtual void + getAs(ScalarType, shared_vector& out) const = 0; + /** + * Assign the given value after conversion. + * + * A copy and element-wise conversion is are always performed. + */ template - inline void putFrom(const typename ScalarTypeTraits::type* ptr, - size_t count, size_t offset = 0) + inline size_t copyOut(typename ScalarTypeTraits::type* inp, size_t len) const { - putFrom(ID, (const void*)ptr, count, offset); + return copyOut(ID, (void*)inp, len); } - virtual void putFrom(ScalarType, const void*, size_t ,size_t) = 0; + virtual size_t copyOut(ScalarType, void*, size_t) const = 0; + + /** + * Assign the given value after conversion. + * + * A copy and element-wise conversion is performed unless + * the element type of the PVScalarArray matches the + * type of the provided data. + * If the types do match then a new refernce to the provided + * data is kept. + */ + template + inline void putFrom(const shared_vector::type>& inp) + { + shared_vector temp(static_shared_vector_cast(inp)); + putFrom(ID, temp); + } + virtual void putFrom(ScalarType, const shared_vector&) = 0; + + /** + * Assign the given value after conversion. + * + * A copy and element-wise conversion is are always performed. + */ + template + inline void copyIn(const typename ScalarTypeTraits::type* inp, size_t len) + { + copyIn(ID, (const void*)inp, len); + } + virtual void copyIn(ScalarType, const void*, size_t) = 0; + + /** + * Assign the given PVScalarArray's value. + * + * A copy and element-wise conversion is performed unless + * the element type of the PVScalarArray matches the + * type of the provided data. + * If the types do match then a new refernce to the provided + * data is kept. + */ virtual void assign(PVScalarArray& pv) = 0; protected: @@ -1016,6 +1079,19 @@ private: friend class PVDataCreate; }; +namespace detail { + // adaptor to allow epics::pvData::shared_vector to hold a reference + // to a shared_ptr > + template + struct shared_ptr_vector_deletor { + typedef std::tr1::shared_ptr > shared_vector; + shared_vector vec; + shared_ptr_vector_deletor(const shared_vector& v) + :vec(v) {} + void operator()(T*){vec.reset();} + }; +} + template class PVValueArray : public PVScalarArray { public: @@ -1023,12 +1099,19 @@ public: typedef T value_type; typedef T* pointer; typedef const T* const_pointer; + + //TODO: full namespace can be removed along with local typedef 'shared_vector' + typedef ::epics::pvData::shared_vector svector; + typedef ::epics::pvData::shared_vector const_svector; + + // begin deprecated typedef PVArrayData ArrayDataType; typedef std::vector vector; typedef const std::vector const_vector; typedef std::tr1::shared_ptr shared_vector; typedef PVValueArray & reference; typedef const PVValueArray & const_reference; + // end deprecated static const ScalarType typeCode; @@ -1036,40 +1119,122 @@ public: * Destructor */ virtual ~PVValueArray() {} + + // Primative array manipulations + + //! unchecked writable reference + //! Before you call this directly, consider using one + //! other the following methods. + virtual const svector& viewUnsafe() const = 0; + + //! Exchange our contents for the provided. + //! Fails for Immutable arrays + virtual void swap(svector& other) = 0; + + //! Discard current contents and replaced with the provided. + //! Fails for Immutable arrays + virtual void replace(const svector& next) + { + svector temp(next); + this->swap(temp); + } + + // Derived operations + + //! Fetch a read-only view of the current array data + inline const_svector view() const + { + const_svector newref(this->viewUnsafe()); + return newref; + } + + //! Remove and return the current array data + inline svector take() + { + svector result; + this->swap(result); + return result; + } + + //! take() with an implied make_unique() + inline svector reuse() + { + svector result; + this->swap(result); + result.make_unique(); + return result; + } + /** * Get array elements * @param offset The offset of the first element, * @param length The number of elements to get. * @param data The place where the data is placed. */ - virtual std::size_t get( - std::size_t offset, std::size_t length, ArrayDataType &data) = 0; + std::size_t get( + std::size_t offset, std::size_t length, ArrayDataType &data) USAGE_DEPRECATED + { + const_svector ref = this->view(); + ref.slice(offset, length); + data.data.resize(ref.size()); + data.offset = 0; + std::copy(ref.begin(), ref.end(), data.data.begin()); + return ref.size(); + } + /** - * Put data into the array. + * Copy data into the array growing the length as needed. * @param offset The offset of the first element, * @param length The number of elements to get. * @param from The new values to put into the array. * @param fromOffset The offset in from. * @return The number of elements put into the array. */ - virtual std::size_t put(std::size_t offset, - std::size_t length, const_pointer from, std::size_t fromOffset) = 0; - virtual std::size_t put(std::size_t offset, - std::size_t length, const_vector &from, std::size_t fromOffset); + std::size_t put(std::size_t offset, + std::size_t length, const_pointer from, std::size_t fromOffset) USAGE_DEPRECATED + { + from += fromOffset; + + svector temp; + this->swap(temp); + if(temp.size() < length+offset) + temp.resize(length+offset); + else + temp.make_unique(); + + std::copy(from, from + length, temp.begin() + offset); + this->swap(temp); + return length; + } + + std::size_t put(std::size_t offset, + std::size_t length, const_vector &from, std::size_t fromOffset) USAGE_DEPRECATED + { return this->put(offset,length, &from[0], fromOffset); } + /** * Share data from another source. * @param value The data to share. * @param capacity The capacity of the array. * @param length The length of the array. */ - virtual void shareData( + void shareData( shared_vector const & value, std::size_t capacity, - std::size_t length) = 0; - virtual pointer get() = 0; - virtual pointer get() const = 0; - virtual vector const & getVector() = 0; - virtual shared_vector const & getSharedVector() = 0; + std::size_t length) USAGE_DEPRECATED + { + vector& vref = *value.get(); + typename svector::shared_pointer_type p(&vref[0], + detail::shared_ptr_vector_deletor(value)); + svector temp(p, 0, std::min(length, vref.size())); + this->swap(temp); + } + + pointer get() const { + return this->viewUnsafe().data(); + } + + vector const & getVector() USAGE_ERROR("No longer implemented"); + shared_vector const & getSharedVector() USAGE_ERROR("No longer implemented"); std::ostream& dumpValue(std::ostream& o) const { @@ -1092,30 +1257,67 @@ public: return o << *(get() + index); } - virtual void getAs(ScalarType dtype, void* ptr, size_t count, size_t offset) const + virtual void + getAs(ScalarType id, ::epics::pvData::shared_vector& out) const { - castUnsafeV(count, dtype, ptr, typeCode, (const void*)(get()+offset)); + const svector& data(viewUnsafe()); + ::epics::pvData::shared_vector temp(static_shared_vector_cast(data)); + if(id==typeCode) { + out = temp; // no convert = no copy + } else { + //TODO: reuse out if possible?? + ::epics::pvData::shared_vector vcopy(ScalarTypeFunc::allocArray(id, data.size())); + + castUnsafeV(data.size(), id, vcopy.data(), typeCode, temp.data()); + + out.swap(vcopy); + } } - virtual void putFrom(ScalarType dtype, const void*ptr, size_t count, size_t offset) + + virtual size_t copyOut(ScalarType id, void* ptr, size_t olen) const { - if(getLength()& inp) + { + if(id==typeCode) { + svector next(static_shared_vector_cast(inp)); + this->swap(next); // no convert == no copy + } else { + size_t len = inp.size() / ScalarTypeFunc::elementSize(id); + svector result; + this->swap(result); + result.resize(len); + + castUnsafeV(len, typeCode, result.data(), id, inp.data()); + + this->swap(result); + } + } + + virtual void copyIn(ScalarType id, const void* ptr, size_t len) + { + svector data; + this->swap(data); + data.resize(len); + castUnsafeV(len, typeCode, (void*)data.data(), id, ptr); + this->swap(data); } virtual void assign(PVScalarArray& pv) { if(this==&pv) return; - if(isImmutable()) - throw std::invalid_argument("Destination is immutable"); - if(pv.isImmutable() && typeCode==pv.getScalarArray()->getElementType()) { - PVValueArray& pvr = static_cast(pv); - shareData(pvr.getSharedVector(), pvr.getCapacity(), pvr.getLength()); - } else { - setLength(pv.getLength()); - pv.getAs(typeCode, (void*)get(), std::min(getLength(),pv.getLength()), 0); - } + ::epics::pvData::shared_vector temp; + pv.getAs(typeCode, temp); + svector next(static_shared_vector_cast(temp)); + this->swap(next); } protected: @@ -1124,13 +1326,6 @@ protected: friend class PVDataCreate; }; -template -std::size_t PVValueArray::put( - std::size_t offset, - std::size_t length, - const_vector &from, - std::size_t fromOffset) -{ return put(offset,length, &from[0], fromOffset); } /** * Definitions for the various scalarArray types. @@ -1281,6 +1476,9 @@ private: */ extern PVDataCreatePtr getPVDataCreate(); - + +#undef USAGE_DEPRECATED +#undef USAGE_ERROR + }} #endif /* PVDATA_H */ From 992ac730684d580bb14d2a04dbe92e9af1b323b8 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 8 May 2013 15:16:58 -0400 Subject: [PATCH 036/103] use new API make copying explicit and replace some use of PVValueArray::put and get --- pvDataApp/factory/Convert.cpp | 5 +++-- pvDataApp/factory/StandardPVField.cpp | 16 ++++++---------- pvDataApp/factory/printer.cpp | 4 ++-- pvDataApp/property/pvEnumerated.cpp | 20 ++++++-------------- pvDataApp/property/pvEnumerated.h | 4 ++-- testApp/property/testProperty.cpp | 4 ++-- 6 files changed, 21 insertions(+), 32 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index c33af5e..35763ac 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -114,11 +114,12 @@ size_t Convert::fromStringArray(PVScalarArrayPtr const &pv, StringArray const & from, size_t fromOffset) { + assert(offset==0); size_t alen = pv->getLength(); if(fromOffset>alen) return 0; alen -= fromOffset; if(length>alen) length=alen; - pv->putFrom(&from[fromOffset], length, offset); + pv->copyIn(&from[fromOffset], length); return length; } @@ -130,7 +131,7 @@ size_t Convert::toStringArray(PVScalarArrayPtr const & pv, if(offset>alen) return 0; alen -= offset; if(length>alen) length=alen; - pv->getAs(&to[toOffset], length, offset); + pv->copyOut(&to[toOffset], length); return length; } diff --git a/pvDataApp/factory/StandardPVField.cpp b/pvDataApp/factory/StandardPVField.cpp index c497c8e..7e3f743 100644 --- a/pvDataApp/factory/StandardPVField.cpp +++ b/pvDataApp/factory/StandardPVField.cpp @@ -59,11 +59,9 @@ PVStructurePtr StandardPVField::enumerated(StringArray const &choices) PVStructurePtr pvStructure = pvDataCreate->createPVStructure(field); PVScalarArrayPtr pvScalarArray = pvStructure->getScalarArrayField( "choices",pvString); - if(pvScalarArray.get()==NULL) { - throw std::logic_error(String("StandardPVField::enumerated")); - } - PVStringArray * pvChoices = static_cast(pvScalarArray.get()); - pvChoices->put(0,choices.size(),get(choices),0); + PVStringArray::svector cdata(choices.size()); + std::copy(choices.begin(), choices.end(), cdata.begin()); + static_cast(*pvScalarArray).swap(cdata); return pvStructure; } @@ -74,11 +72,9 @@ PVStructurePtr StandardPVField::enumerated( PVStructurePtr pvStructure = pvDataCreate->createPVStructure(field); PVScalarArrayPtr pvScalarArray = pvStructure->getScalarArrayField( "value.choices",pvString); - if(pvScalarArray.get()==NULL) { - throw std::logic_error(String("StandardPVField::enumerated")); - } - PVStringArray * pvChoices = static_cast(pvScalarArray.get()); - pvChoices->put(0,choices.size(),get(choices),0); + PVStringArray::svector cdata(choices.size()); + std::copy(choices.begin(), choices.end(), cdata.begin()); + static_cast(*pvScalarArray).swap(cdata); return pvStructure; } diff --git a/pvDataApp/factory/printer.cpp b/pvDataApp/factory/printer.cpp index baf6c8a..20dde9d 100644 --- a/pvDataApp/factory/printer.cpp +++ b/pvDataApp/factory/printer.cpp @@ -166,8 +166,8 @@ void PrinterPlain::encodeScalar(const PVScalar& pv) void PrinterPlain::encodeArray(const PVScalarArray& pv) { indentN(S(), ilvl); - StringArray temp(pv.getLength()); // TODO: no copy - pv.getAs(&temp[0], temp.size()); + shared_vector temp; + pv.getAs(temp); S() << pv.getScalarArray()->getID() << " " << pv.getFieldName() << " ["; diff --git a/pvDataApp/property/pvEnumerated.cpp b/pvDataApp/property/pvEnumerated.cpp index ee00601..c108434 100644 --- a/pvDataApp/property/pvEnumerated.cpp +++ b/pvDataApp/property/pvEnumerated.cpp @@ -78,9 +78,8 @@ String PVEnumerated::getChoice() throw std::logic_error(notAttached); } int index = pvIndex->get(); - StringArrayData data; - pvChoices->get(0,pvChoices->getLength(),data); - return data.data[index]; + const PVStringArray::svector& data(pvChoices->viewUnsafe()); + return data[index]; } bool PVEnumerated::choicesMutable() @@ -91,15 +90,6 @@ bool PVEnumerated::choicesMutable() return pvChoices->isImmutable(); } -StringArrayPtr const & PVEnumerated:: getChoices() -{ - if(pvIndex.get()==NULL ) { - throw std::logic_error(notAttached); - } - StringArrayData data; - return pvChoices->getSharedVector(); -} - int32 PVEnumerated::getNumberChoices() { if(pvIndex.get()==NULL ) { @@ -108,13 +98,15 @@ int32 PVEnumerated::getNumberChoices() return pvChoices->getLength(); } -bool PVEnumerated:: setChoices(StringArray & choices) +bool PVEnumerated:: setChoices(const StringArray & choices) { if(pvIndex.get()==NULL ) { throw std::logic_error(notAttached); } if(pvChoices->isImmutable()) return false; - pvChoices->put(0,choices.size(),get(choices),0); + PVStringArray::svector data(choices.size()); + std::copy(choices.begin(), choices.end(), data.begin()); + pvChoices->swap(data); return true; } diff --git a/pvDataApp/property/pvEnumerated.h b/pvDataApp/property/pvEnumerated.h index 4e2fbe0..7887908 100644 --- a/pvDataApp/property/pvEnumerated.h +++ b/pvDataApp/property/pvEnumerated.h @@ -30,9 +30,9 @@ public: int32 getIndex(); String getChoice(); bool choicesMutable(); - StringArrayPtr const & getChoices(); + inline PVStringArray::const_svector getChoices(){return pvChoices->view();} int32 getNumberChoices(); - bool setChoices(StringArray & choices); + bool setChoices(const StringArray & choices); private: static String notFound; static String notAttached; diff --git a/testApp/property/testProperty.cpp b/testApp/property/testProperty.cpp index 923276c..4d1dc59 100644 --- a/testApp/property/testProperty.cpp +++ b/testApp/property/testProperty.cpp @@ -229,11 +229,11 @@ static void testEnumerated(FILE * fd,FILE */*auxfd*/) assert(result); int32 index = pvEnumerated.getIndex(); String choice = pvEnumerated.getChoice(); - StringArrayPtr const & choices = pvEnumerated.getChoices(); + PVStringArray::const_svector choices = pvEnumerated.getChoices(); int32 numChoices = pvEnumerated.getNumberChoices(); if(debug) { fprintf(fd,"index %d choice %s choices",index,choice.c_str()); - for(int i=0; i Date: Tue, 7 May 2013 18:36:53 -0400 Subject: [PATCH 037/103] Convert: remove to/from*Array --- pvDataApp/pv/convert.h | 375 +------------------------------------ testApp/pv/testConvert.cpp | 360 ----------------------------------- 2 files changed, 1 insertion(+), 734 deletions(-) diff --git a/pvDataApp/pv/convert.h b/pvDataApp/pv/convert.h index 2ddfc21..8399ec3 100644 --- a/pvDataApp/pv/convert.h +++ b/pvDataApp/pv/convert.h @@ -435,380 +435,7 @@ public: * @throws std::invalid_argument if the Type is not a numeric scalar */ inline void fromDouble(PVScalarPtr const & pv, double from) { pv->putFrom(from); } - /** - * Convert a PV array to a byte array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t toByteArray(PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - int8* to, - std::size_t toOffset) - { pv->getAs(to+toOffset, length, offset); return length; } - /** - * Convert a PV array to a short array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t toShortArray(PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - int16* to, - std::size_t toOffset) - { pv->getAs(to+toOffset, length, offset); return length; } - /** - * Convert a PV array to an int array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t toIntArray(PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - int32* to, - std::size_t toOffset) - { pv->getAs(to+toOffset, length, offset); return length; } - /** - * Convert a PV array to a long array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t toLongArray(PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - int64* to, - std::size_t toOffset) - { pv->getAs(to+toOffset, length, offset); return length; } - /** - * Convert a PV array to a ubyte array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t toUByteArray(PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - uint8* to, - std::size_t toOffset) - { pv->getAs(to+toOffset, length, offset); return length; } - /** - * Convert a PV array to a ushort array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t toUShortArray(PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - uint16* to, - std::size_t toOffset) - { pv->getAs(to+toOffset, length, offset); return length; } - /** - * Convert a PV array to an uint array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t toUIntArray( - PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - uint32* to, - std::size_t toOffset) - { pv->getAs(to+toOffset, length, offset); return length; } - /** - * Convert a PV array to a ulong array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t toULongArray( - PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - uint64* to, - std::size_t toOffset) - { pv->getAs(to+toOffset, length, offset); return length; } - /** - * Convert a PV array to a float array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t toFloatArray( - PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - float* to, - std::size_t toOffset) - { pv->getAs(to+toOffset, length, offset); return length; } - /** - * Convert a PV array to a double array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t toDoubleArray( - PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - double* to, std::size_t - toOffset) - { pv->getAs(to+toOffset, length, offset); return length; } - /** - * Convert a PV array from a byte array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t fromByteArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const int8* from, std::size_t fromOffset) - { pv->putFrom(from+fromOffset, length, offset); return length; } - inline - std::size_t fromByteArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const ByteArray & from, std::size_t fromOffset) - {return fromByteArray(pv, offset, length, &from[0], fromOffset);} - /** - * Convert a PV array from a short array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t fromShortArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const int16* from, std::size_t fromOffset) - { pv->putFrom(from+fromOffset, length, offset); return length; } - inline - std::size_t fromShortArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const ShortArray & from, std::size_t fromOffset) - {return fromShortArray(pv, offset, length, &from[0], fromOffset);} - /** - * Convert a PV array from an int array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t fromIntArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const int32* from, std::size_t fromOffset) - { pv->putFrom(from+fromOffset, length, offset); return length; } - inline - std::size_t fromIntArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const IntArray & from, std::size_t fromOffset) - {return fromIntArray(pv, offset, length, &from[0], fromOffset);} - /** - * Convert a PV array from a long array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t fromLongArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const int64* from, std::size_t fromOffset) - { pv->putFrom(from+fromOffset, length, offset); return length; } - inline - std::size_t fromLongArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const LongArray & from, std::size_t fromOffset) - {return fromLongArray(pv, offset, length, &from[0], fromOffset);} - /** - * Convert a PV array from a ubyte array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t fromUByteArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const uint8* from, std::size_t fromOffset) - { pv->putFrom(from+fromOffset, length, offset); return length; } - inline - std::size_t fromUByteArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const UByteArray & from, std::size_t fromOffset) - {return fromUByteArray(pv, offset, length, &from[0], fromOffset);} - /** - * Convert a PV array from a ushort array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t fromUShortArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const uint16* from, std::size_t fromOffset) - { pv->putFrom(from+fromOffset, length, offset); return length; } - inline - std::size_t fromUShortArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const UShortArray & from, std::size_t fromOffset) - {return fromUShortArray(pv, offset, length, &from[0], fromOffset);} - /** - * Convert a PV array from an uint array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t fromUIntArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const uint32* from, std::size_t fromOffset) - { pv->putFrom(from+fromOffset, length, offset); return length; } - inline - std::size_t fromUIntArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const UIntArray & from, std::size_t fromOffset) - {return fromUIntArray(pv, offset, length, &from[0], fromOffset);} - /** - * Convert a PV array from a ulong array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t fromULongArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const uint64* from, std::size_t fromOffset) - { pv->putFrom(from+fromOffset, length, offset); return length; } - inline - std::size_t fromULongArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const ULongArray & from, std::size_t fromOffset) - {return fromULongArray(pv, offset, length, &from[0], fromOffset);} - /** - * Convert a PV array from a float array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t fromFloatArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const float* from, std::size_t fromOffset) - { pv->putFrom(from+fromOffset, length, offset); return length; } - inline - std::size_t fromFloatArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const FloatArray & from, std::size_t fromOffset) - {return fromFloatArray(pv, offset, length, &from[0], fromOffset);} - /** - * Convert a PV array from a double array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - inline - std::size_t fromDoubleArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const double* from, std::size_t fromOffset) - { pv->putFrom(from+fromOffset, length, offset); return length; } - inline - std::size_t fromDoubleArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const DoubleArray & from, std::size_t fromOffset) - {return fromDoubleArray(pv, offset, length, &from[0], fromOffset);} + /** * Convenience method for implementing toString. * It generates a newline and inserts blanks at the beginning of the newline. diff --git a/testApp/pv/testConvert.cpp b/testApp/pv/testConvert.cpp index ab54135..c6264b1 100644 --- a/testApp/pv/testConvert.cpp +++ b/testApp/pv/testConvert.cpp @@ -392,365 +392,6 @@ static void testConvertScalar(FILE *fd) { fprintf(fd,"fromULong PASSED\n"); } -static void testConvertScalarArray(FILE *fd) { - PVScalarArrayPtr pvBytePtr = pvDataCreate->createPVScalarArray(pvByte); - PVScalarArrayPtr pvUBytePtr = pvDataCreate->createPVScalarArray(pvUByte); - PVScalarArrayPtr pvShortPtr = pvDataCreate->createPVScalarArray(pvShort); - PVScalarArrayPtr pvUShortPtr = pvDataCreate->createPVScalarArray(pvUShort); - PVScalarArrayPtr pvIntPtr = pvDataCreate->createPVScalarArray(pvInt); - PVScalarArrayPtr pvUIntPtr = pvDataCreate->createPVScalarArray(pvUInt); - PVScalarArrayPtr pvLongPtr = pvDataCreate->createPVScalarArray(pvLong); - PVScalarArrayPtr pvULongPtr = pvDataCreate->createPVScalarArray(pvULong); - PVScalarArrayPtr pvFloatPtr = pvDataCreate->createPVScalarArray(pvFloat); - PVScalarArrayPtr pvDoublePtr = pvDataCreate->createPVScalarArray(pvDouble); - - fprintf(fd,"testConvertScalarArray\n"); - if(debug) fprintf(fd,"\nfromByte\n"); - size_t length = 4; - int8 barray[length]; - int8 bval = 127; - barray[0] = bval; - for(size_t i=1; ifromByteArray(pvBytePtr,0,length,barray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromByteArray(pvUBytePtr,0,length,barray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromByteArray(pvShortPtr,0,length,barray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromByteArray(pvUShortPtr,0,length,barray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromByteArray(pvIntPtr,0,length,barray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromByteArray(pvUIntPtr,0,length,barray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromByteArray(pvLongPtr,0,length,barray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromByteArray(pvULongPtr,0,length,barray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromByteArray(pvFloatPtr,0,length,barray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromByteArray(pvDoublePtr,0,length,barray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - pvUBytePtr->assign(*pvFloatPtr.get()); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - pvUBytePtr->assign(*pvDoublePtr.get()); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromByte PASSED\n"); - - if(debug) fprintf(fd,"\nfromShort\n"); - int16 sarray[length]; - int16 sval = 0x7fff; - sarray[0] = sval; - for(size_t i=1; ifromShortArray(pvBytePtr,0,length,sarray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromShortArray(pvUBytePtr,0,length,sarray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromShortArray(pvShortPtr,0,length,sarray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromShortArray(pvUShortPtr,0,length,sarray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromShortArray(pvIntPtr,0,length,sarray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromShortArray(pvUIntPtr,0,length,sarray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromShortArray(pvLongPtr,0,length,sarray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromShortArray(pvULongPtr,0,length,sarray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromShortArray(pvFloatPtr,0,length,sarray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromShortArray(pvDoublePtr,0,length,sarray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - pvUShortPtr->assign(*pvFloatPtr.get()); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - pvUShortPtr->assign(*pvDoublePtr.get()); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromShort PASSED\n"); - - if(debug) fprintf(fd,"\nfromInt\n"); - int32 iarray[length]; - int32 ival = 0x7fffffff; - iarray[0] = ival; - for(size_t i=1; ifromIntArray(pvBytePtr,0,length,iarray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromIntArray(pvUBytePtr,0,length,iarray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromIntArray(pvShortPtr,0,length,iarray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromIntArray(pvUShortPtr,0,length,iarray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromIntArray(pvIntPtr,0,length,iarray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromIntArray(pvUIntPtr,0,length,iarray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromIntArray(pvLongPtr,0,length,iarray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromIntArray(pvULongPtr,0,length,iarray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromIntArray(pvFloatPtr,0,length,iarray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromIntArray(pvDoublePtr,0,length,iarray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - pvUIntPtr->assign(*pvFloatPtr.get()); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - pvUIntPtr->assign(*pvDoublePtr.get()); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromInt PASSED\n"); - - if(debug) fprintf(fd,"\nfromLong\n"); - int64 larray[length]; - int64 lval = 0x7fffffffffffffffLL; - larray[0] = lval; - for(size_t i=1; ifromLongArray(pvBytePtr,0,length,larray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromLongArray(pvUBytePtr,0,length,larray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromLongArray(pvShortPtr,0,length,larray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromLongArray(pvUShortPtr,0,length,larray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromLongArray(pvIntPtr,0,length,larray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromLongArray(pvUIntPtr,0,length,larray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromLongArray(pvLongPtr,0,length,larray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromLongArray(pvULongPtr,0,length,larray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromLongArray(pvFloatPtr,0,length,larray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromLongArray(pvDoublePtr,0,length,larray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - pvULongPtr->assign(*pvFloatPtr.get()); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - pvULongPtr->assign(*pvDoublePtr.get()); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromLong PASSED\n"); - - if(debug) fprintf(fd,"\nfromUByte\n"); - uint8 ubarray[length]; - uint8 ubval = 127; - ubarray[0] = ubval; - for(size_t i=1; ifromUByteArray(pvBytePtr,0,length,ubarray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromUByteArray(pvUBytePtr,0,length,ubarray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromUByteArray(pvShortPtr,0,length,ubarray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromUByteArray(pvUShortPtr,0,length,ubarray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromUByteArray(pvIntPtr,0,length,ubarray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromUByteArray(pvUIntPtr,0,length,ubarray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromUByteArray(pvLongPtr,0,length,ubarray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromUByteArray(pvULongPtr,0,length,ubarray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromUByteArray(pvFloatPtr,0,length,ubarray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromUByteArray(pvDoublePtr,0,length,ubarray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - pvUBytePtr->assign(*pvFloatPtr.get()); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - pvUBytePtr->assign(*pvDoublePtr.get()); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromUByte PASSED\n"); - - if(debug) fprintf(fd,"\nfromUShort\n"); - uint16 usarray[length]; - uint16 usval = 0x7fff; - usarray[0] = usval; - for(size_t i=1; ifromUShortArray(pvBytePtr,0,length,usarray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromUShortArray(pvUBytePtr,0,length,usarray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromUShortArray(pvShortPtr,0,length,usarray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromUShortArray(pvUShortPtr,0,length,usarray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromUShortArray(pvIntPtr,0,length,usarray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromUShortArray(pvUIntPtr,0,length,usarray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromUShortArray(pvLongPtr,0,length,usarray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromUShortArray(pvULongPtr,0,length,usarray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromUShortArray(pvFloatPtr,0,length,usarray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromUShortArray(pvDoublePtr,0,length,usarray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - pvUShortPtr->assign(*pvFloatPtr.get()); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - pvUShortPtr->assign(*pvDoublePtr.get()); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromUShort PASSED\n"); - - if(debug) fprintf(fd,"\nfromUInt\n"); - uint32 uiarray[length]; - uint32 uival = 0x7fffffff; - uiarray[0] = uival; - for(size_t i=1; ifromUIntArray(pvBytePtr,0,length,uiarray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromUIntArray(pvUBytePtr,0,length,uiarray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromUIntArray(pvShortPtr,0,length,uiarray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromUIntArray(pvUShortPtr,0,length,uiarray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromUIntArray(pvIntPtr,0,length,uiarray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromUIntArray(pvUIntPtr,0,length,uiarray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromUIntArray(pvLongPtr,0,length,uiarray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromUIntArray(pvULongPtr,0,length,uiarray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromUIntArray(pvFloatPtr,0,length,uiarray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromUIntArray(pvDoublePtr,0,length,uiarray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - pvUIntPtr->assign(*pvFloatPtr.get()); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - pvUIntPtr->assign(*pvDoublePtr.get()); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromUInt PASSED\n"); - - if(debug) fprintf(fd,"\nfromULong\n"); - uint64 ularray[length]; - uint64 ulval = 0x7fffffffffffffffLL; - ularray[0] = ulval; - for(size_t i=1; ifromULongArray(pvBytePtr,0,length,ularray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromULongArray(pvUBytePtr,0,length,ularray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromULongArray(pvShortPtr,0,length,ularray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromULongArray(pvUShortPtr,0,length,ularray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromULongArray(pvIntPtr,0,length,ularray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromULongArray(pvUIntPtr,0,length,ularray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromULongArray(pvLongPtr,0,length,ularray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromULongArray(pvULongPtr,0,length,ularray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromULongArray(pvFloatPtr,0,length,ularray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromULongArray(pvDoublePtr,0,length,ularray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - pvULongPtr->assign(*pvFloatPtr.get()); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - pvULongPtr->assign(*pvDoublePtr.get()); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromLong PASSED\n"); -} - int main(int argc,char *argv[]) { char *fileName = 0; @@ -765,7 +406,6 @@ int main(int argc,char *argv[]) standardPVField = getStandardPVField(); convert = getConvert(); testConvertScalar(fd); - testConvertScalarArray(fd); fprintf(fd,"THIS NEEDS MANY MORE TESTS AND ASSERTS\n"); return(0); } From 3c08834377297576260f6306a9cc9b8f9ba01444 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 8 May 2013 14:18:29 -0400 Subject: [PATCH 038/103] update testSerialization --- testApp/misc/Makefile | 3 +- testApp/misc/testSerialization.cpp | 564 +++++++++-------------------- 2 files changed, 165 insertions(+), 402 deletions(-) diff --git a/testApp/misc/Makefile b/testApp/misc/Makefile index a9fceba..f627433 100644 --- a/testApp/misc/Makefile +++ b/testApp/misc/Makefile @@ -22,8 +22,9 @@ testByteBuffer_SRCS += testByteBuffer.cpp PROD_HOST += testBaseException testBaseException_SRCS += testBaseException.cpp -PROD_HOST += testSerialization +TESTPROD += testSerialization testSerialization_SRCS += testSerialization.cpp +TESTS += testSerialization PROD_HOST += testTimeStamp testTimeStamp_SRCS += testTimeStamp.cpp diff --git a/testApp/misc/testSerialization.cpp b/testApp/misc/testSerialization.cpp index a1fd98f..50e4266 100644 --- a/testApp/misc/testSerialization.cpp +++ b/testApp/misc/testSerialization.cpp @@ -12,7 +12,9 @@ #include #include -#include +#include +#include +#include // for NELEMENTS #include #include @@ -45,6 +47,8 @@ using namespace epics::pvData; +namespace { + static SerializableControl* flusher; static DeserializableControl* control; static ByteBuffer* buffer; @@ -122,14 +126,13 @@ void serializationTest(PVFieldPtr const & field) { deserializedField->deserialize(buffer, control); // must equal - bool isEqual = getConvert()->equals(*field,*deserializedField); - assert(isEqual); + testOk1(*field==*deserializedField); } -void testEquals(std::ostream& ofile) { - ofile<<"Testing equals...\n"; +void testEquals() { + testDiag("Testing equals..."); PVDataCreatePtr factory = getPVDataCreate(); - assert(factory.get()!=NULL); + testOk1(factory.get()!=NULL); // be sure all is covered for (int i = pvBoolean; i < pvString; i++) @@ -138,32 +141,63 @@ void testEquals(std::ostream& ofile) { PVScalarPtr scalar1 = factory->createPVScalar(scalarType); PVScalarPtr scalar2 = factory->createPVScalar(scalarType); - assert((*scalar1)==(*scalar2)); + testOk1((*scalar1)==(*scalar2)); PVScalarArrayPtr array1 = factory->createPVScalarArray(scalarType); PVScalarArrayPtr array2 = factory->createPVScalarArray(scalarType); - assert((*array1)==(*array2)); + testOk1((*array1)==(*array2)); } // and a structure PVStructurePtr structure1 = factory->createPVStructure(getStandardField()->timeStamp()); PVStructurePtr structure2 = factory->createPVStructure(getStandardField()->timeStamp()); - assert((*structure1)==(*structure2)); + testOk1((*structure1)==(*structure2)); // and a structure array PVStructureArrayPtr structureArray1 = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure1->getStructure())); PVStructureArrayPtr structureArray2 = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure2->getStructure())); - assert((*structureArray1)==(*structureArray2)); - - ofile<<"!!! PASSED\n\n"; + testOk1((*structureArray1)==(*structureArray2)); } -void testScalar(std::ostream& ofile) { - ofile<<"Testing scalars...\n"; - PVDataCreatePtr factory = getPVDataCreate(); - assert(factory.get()!=NULL); +template +void testScalarType() +{ + typedef typename PVT::value_type value_type; - ofile<<"\tPVBoolean\n"; + testDiag("type %s", ScalarTypeFunc::name(PVT::typeCode)); + + typename PVT::shared_pointer pv = std::tr1::static_pointer_cast(getPVDataCreate()->createPVScalar(PVT::typeCode)); + + pv->put(0); + serializationTest(pv); + pv->put(42); + serializationTest(pv); + pv->put(std::numeric_limits::max()-1); + serializationTest(pv); + pv->put(std::numeric_limits::max()); + serializationTest(pv); + + if(std::numeric_limits::min()!=0) { + pv->put(-42); + serializationTest(pv); + pv->put(std::numeric_limits::min()+1); + serializationTest(pv); + pv->put(std::numeric_limits::min()); + serializationTest(pv); + } + + if(std::numeric_limits::has_infinity) { + pv->put(std::numeric_limits::infinity()); + serializationTest(pv); + } +} + +void testScalar() { + testDiag("Testing scalars..."); + PVDataCreatePtr factory = getPVDataCreate(); + testOk1(factory.get()!=NULL); + + testDiag("type %s", ScalarTypeFunc::name(pvBoolean)); PVBooleanPtr pvBoolean = std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvBoolean)); pvBoolean->put(false); @@ -171,196 +205,19 @@ void testScalar(std::ostream& ofile) { pvBoolean->put(true); serializationTest(pvBoolean); - ofile<<"\tPVByte\n"; - PVBytePtr pvByte = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvByte)); - pvByte->put(0); - serializationTest(pvByte); - pvByte->put(12); - serializationTest(pvByte); - pvByte->put(BYTE_MAX_VALUE); - serializationTest(pvByte); - pvByte->put(BYTE_MIN_VALUE); - serializationTest(pvByte); - - ofile<<"\tPVShort\n"; - PVShortPtr pvShort = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvShort)); - pvShort->put(0); - serializationTest(pvShort); - pvShort->put(123); - serializationTest(pvShort); - pvShort->put(BYTE_MAX_VALUE); - serializationTest(pvShort); - pvShort->put(BYTE_MIN_VALUE); - serializationTest(pvShort); - pvShort->put(SHORT_MAX_VALUE); - serializationTest(pvShort); - pvShort->put(SHORT_MIN_VALUE); - serializationTest(pvShort); - - ofile<<"\tPVInt\n"; - PVIntPtr pvInt = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvInt)); - pvInt->put(0); - serializationTest(pvInt); - pvInt->put(123456); - serializationTest(pvInt); - pvInt->put(BYTE_MAX_VALUE); - serializationTest(pvInt); - pvInt->put(BYTE_MIN_VALUE); - serializationTest(pvInt); - pvInt->put(SHORT_MAX_VALUE); - serializationTest(pvInt); - pvInt->put(SHORT_MIN_VALUE); - serializationTest(pvInt); - pvInt->put(INT_MAX_VALUE); - serializationTest(pvInt); - pvInt->put(INT_MIN_VALUE); - serializationTest(pvInt); - - ofile<<"\tPVLong\n"; - PVLongPtr pvLong = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvLong)); - pvLong->put(0); - serializationTest(pvLong); - pvLong->put(12345678901LL); - serializationTest(pvLong); - pvLong->put(BYTE_MAX_VALUE); - serializationTest(pvLong); - pvLong->put(BYTE_MIN_VALUE); - serializationTest(pvLong); - pvLong->put(SHORT_MAX_VALUE); - serializationTest(pvLong); - pvLong->put(SHORT_MIN_VALUE); - serializationTest(pvLong); - pvLong->put(INT_MAX_VALUE); - serializationTest(pvLong); - pvLong->put(INT_MIN_VALUE); - serializationTest(pvLong); - pvLong->put(LONG_MAX_VALUE); - serializationTest(pvLong); - pvLong->put(LONG_MIN_VALUE); - serializationTest(pvLong); + testScalarType(); + testScalarType(); + testScalarType(); + testScalarType(); + testScalarType(); + testScalarType(); + testScalarType(); + testScalarType(); + testScalarType(); + testScalarType(); - ofile<<"\tPVUByte\n"; - PVUBytePtr pvUByte = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvUByte)); - pvUByte->put(0); - serializationTest(pvUByte); - pvUByte->put(12); - serializationTest(pvUByte); - pvUByte->put(UBYTE_MAX_VALUE); - serializationTest(pvUByte); - pvUByte->put(BYTE_MAX_VALUE); - serializationTest(pvUByte); - pvUByte->put(BYTE_MIN_VALUE); - serializationTest(pvUByte); - - ofile<<"\tPVUShort\n"; - PVUShortPtr pvUShort = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvUShort)); - pvUShort->put(0); - serializationTest(pvUShort); - pvUShort->put(1234); - serializationTest(pvUShort); - pvUShort->put(BYTE_MAX_VALUE); - serializationTest(pvUShort); - pvUShort->put(BYTE_MIN_VALUE); - serializationTest(pvUShort); - pvUShort->put(UBYTE_MAX_VALUE); - serializationTest(pvUShort); - pvUShort->put(SHORT_MAX_VALUE); - serializationTest(pvUShort); - pvUShort->put(SHORT_MIN_VALUE); - serializationTest(pvUShort); - pvUShort->put(USHORT_MAX_VALUE); - serializationTest(pvUShort); - - ofile<<"\tPVInt\n"; - PVIntPtr pvUInt = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvUInt)); - pvUInt->put(0); - serializationTest(pvUInt); - pvUInt->put(123456); - serializationTest(pvUInt); - pvUInt->put(BYTE_MAX_VALUE); - serializationTest(pvUInt); - pvUInt->put(BYTE_MIN_VALUE); - serializationTest(pvUInt); - pvUInt->put(UBYTE_MAX_VALUE); - serializationTest(pvUInt); - pvUInt->put(SHORT_MAX_VALUE); - serializationTest(pvUInt); - pvUInt->put(SHORT_MIN_VALUE); - serializationTest(pvUInt); - pvUInt->put(USHORT_MAX_VALUE); - serializationTest(pvUInt); - pvUInt->put(INT_MAX_VALUE); - serializationTest(pvUInt); - pvUInt->put(INT_MIN_VALUE); - serializationTest(pvUInt); - pvUInt->put(UINT_MAX_VALUE); - serializationTest(pvUInt); - - ofile<<"\tPVLong\n"; - PVLongPtr pvULong = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvULong)); - pvULong->put(0); - serializationTest(pvULong); - pvULong->put(12345678901LL); - serializationTest(pvULong); - pvULong->put(BYTE_MAX_VALUE); - serializationTest(pvULong); - pvULong->put(BYTE_MIN_VALUE); - serializationTest(pvULong); - pvULong->put(UBYTE_MAX_VALUE); - serializationTest(pvULong); - pvULong->put(SHORT_MAX_VALUE); - serializationTest(pvULong); - pvULong->put(SHORT_MIN_VALUE); - serializationTest(pvULong); - pvULong->put(USHORT_MAX_VALUE); - serializationTest(pvULong); - pvULong->put(INT_MAX_VALUE); - serializationTest(pvULong); - pvULong->put(INT_MIN_VALUE); - serializationTest(pvULong); - pvULong->put(UINT_MAX_VALUE); - serializationTest(pvULong); - pvULong->put(LONG_MAX_VALUE); - serializationTest(pvULong); - pvULong->put(LONG_MIN_VALUE); - serializationTest(pvULong); - pvULong->put(ULONG_MAX_VALUE); - serializationTest(pvULong); - - ofile<<"\tPVFloat\n"; - PVFloatPtr pvFloat = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvFloat)); - pvFloat->put(0); - serializationTest(pvFloat); - pvFloat->put(12.345); - serializationTest(pvFloat); - pvFloat->put(FLOAT_MAX_VALUE); - serializationTest(pvFloat); - pvFloat->put(FLOAT_MIN_VALUE); - serializationTest(pvFloat); - - ofile<<"\tPVDouble\n"; - PVDoublePtr pvDouble = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvDouble)); - pvDouble->put(0); - serializationTest(pvDouble); - pvDouble->put(12.345); - serializationTest(pvDouble); - pvDouble->put(DOUBLE_MAX_VALUE); - serializationTest(pvDouble); - pvDouble->put(DOUBLE_MIN_VALUE); - serializationTest(pvDouble); - - ofile<<"\tPVString\n"; + testDiag("type %s", ScalarTypeFunc::name(pvString)); PVStringPtr pvString = std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvString)); pvString->put(""); @@ -377,167 +234,88 @@ void testScalar(std::ostream& ofile) { // huge string test pvString->put(String(10000, 'a')); serializationTest(pvString); - - // TODO unsigned test - - ofile<<"!!! PASSED\n\n"; } -void testArray(std::ostream& ofile) { - ofile<<"Testing arrays...\n"; +template +void testArrayType(const typename PVT::value_type* rdata, size_t len) +{ + typedef typename PVT::value_type value_type; - PVDataCreatePtr factory = getPVDataCreate(); - assert(factory.get()!=NULL); + typename PVT::svector empty(0), data(len); - ofile<<"\tPVBooleanArray\n"; - //bool boolEmpty[] = { false }; - //bool bv[] = { false, true, false, true, true }; - PVBooleanArrayPtr pvBoolean = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvBoolean)); - //pvBoolean->put(0, 0, boolEmpty, 0); - serializationTest(pvBoolean); - //pvBoolean->put(0, 5, bv, 0); - serializationTest(pvBoolean); + std::copy(rdata, rdata+len, data.begin()); - ofile<<"\tPVByteArray\n"; - int8 byteEmpty[] = { 0 }; - int8 byv[] = { 0, 1, 2, -1, BYTE_MAX_VALUE, BYTE_MAX_VALUE-1, - BYTE_MIN_VALUE+1, BYTE_MIN_VALUE }; - PVByteArrayPtr pvByte = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvByte)); - pvByte->put(0, 0, byteEmpty, 0); - serializationTest(pvByte); - pvByte->put(0, 8, byv, 0); - serializationTest(pvByte); + testDiag("type %s", ScalarTypeFunc::name(PVT::typeCode)); - ofile<<"\tPVShortArray\n"; - int16 shortEmpty[] = { 0 }; - int16 sv[] = { 0, 1, 2, -1, SHORT_MAX_VALUE, SHORT_MAX_VALUE-1, - SHORT_MIN_VALUE+1, SHORT_MIN_VALUE }; - PVShortArrayPtr pvShort = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvShort)); - pvShort->put(0, 0, shortEmpty, 0); - serializationTest(pvShort); - pvShort->put(0, 8, sv, 0); - serializationTest(pvShort); + typename PVT::shared_pointer pv = std::tr1::static_pointer_cast(getPVDataCreate()->createPVScalarArray(PVT::typeCode)); - ofile<<"\tPVIntArray\n"; - int32 intEmpty[] = { 0 }; - int32 iv[] = { 0, 1, 2, -1, INT_MAX_VALUE, INT_MAX_VALUE-1, - INT_MIN_VALUE+1, INT_MIN_VALUE }; - PVIntArrayPtr pvInt = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvInt)); - pvInt->put(0, 0, intEmpty, 0); - serializationTest(pvInt); - pvInt->put(0, 8, iv, 0); - serializationTest(pvInt); - - ofile<<"\tPVLongArray\n"; - int64 longEmpty[] = { 0 }; - int64 lv[] = { 0, 1, 2, -1, LONG_MAX_VALUE, LONG_MAX_VALUE-1, - LONG_MIN_VALUE+1, LONG_MIN_VALUE }; - PVLongArrayPtr pvLong = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvLong)); - pvLong->put(0, 0, longEmpty, 0); - serializationTest(pvLong); - pvLong->put(0, 8, lv, 0); - serializationTest(pvLong); - - ofile<<"\tPVUByteArray\n"; - uint8 ubyteEmpty[] = { 0 }; - uint8 ubyv[] = { 0, 1, 2, -1, BYTE_MAX_VALUE, BYTE_MAX_VALUE-1, - BYTE_MIN_VALUE+1, BYTE_MIN_VALUE, UBYTE_MAX_VALUE }; - PVUByteArrayPtr pvUByte = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvUByte)); - pvUByte->put(0, 0, ubyteEmpty, 0); - serializationTest(pvUByte); - pvUByte->put(0, 9, ubyv, 0); - serializationTest(pvUByte); - - ofile<<"\tPVUShortArray\n"; - uint16 ushortEmpty[] = { 0 }; - uint16 usv[] = { 0, 1, 2, -1, SHORT_MAX_VALUE, SHORT_MAX_VALUE-1, - SHORT_MIN_VALUE+1, SHORT_MIN_VALUE, USHORT_MAX_VALUE }; - PVUShortArrayPtr pvUShort = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvUShort)); - pvUShort->put(0, 0, ushortEmpty, 0); - serializationTest(pvUShort); - pvUShort->put(0, 8, usv, 0); - serializationTest(pvUShort); - - ofile<<"\tPVUIntArray\n"; - uint32 uintEmpty[] = { 0 }; - uint32 uiv[] = { 0, 1, 2, -1, INT_MAX_VALUE, INT_MAX_VALUE-1, - INT_MIN_VALUE+1, INT_MIN_VALUE, UINT_MAX_VALUE }; - PVUIntArrayPtr pvUInt = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvUInt)); - pvUInt->put(0, 0, uintEmpty, 0); - serializationTest(pvUInt); - pvUInt->put(0, 9, uiv, 0); - serializationTest(pvUInt); - - ofile<<"\tPVULongArray\n"; - uint64 ulongEmpty[] = { 0 }; - uint64 ulv[] = { 0, 1, 2, -1, LONG_MAX_VALUE, LONG_MAX_VALUE-1, - LONG_MIN_VALUE+1, LONG_MIN_VALUE, ULONG_MAX_VALUE }; - PVULongArrayPtr pvULong = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvULong)); - pvULong->put(0, 0, ulongEmpty, 0); - serializationTest(pvULong); - pvULong->put(0, 9, ulv, 0); - serializationTest(pvULong); - - ofile<<"\tPVFloatArray\n"; - float floatEmpty[] = { (float)0.0 }; - float fv[] = { (float)0.0, (float)1.1, (float)2.3, (float)-1.4, - FLOAT_MAX_VALUE, FLOAT_MAX_VALUE-(float)123456.789, FLOAT_MIN_VALUE - +(float)1.1, FLOAT_MIN_VALUE }; - PVFloatArrayPtr pvFloat = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvFloat)); - pvFloat->put(0, 0, floatEmpty, 0); - serializationTest(pvFloat); - pvFloat->put(0, 8, fv, 0); - serializationTest(pvFloat); - - ofile<<"\tPVDoubleArray\n"; - double doubleEmpty[] = { (double)0.0 }; - double dv[] = { (double)0.0, (double)1.1, (double)2.3, (double)-1.4, - DOUBLE_MAX_VALUE, DOUBLE_MAX_VALUE-(double)123456.789, - DOUBLE_MIN_VALUE+(double)1.1, DOUBLE_MIN_VALUE }; - PVDoubleArrayPtr pvDouble = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvDouble)); - pvDouble->put(0, 0, doubleEmpty, 0); - serializationTest(pvDouble); - pvDouble->put(0, 8, dv, 0); - serializationTest(pvDouble); - - ofile<<"\tPVStringArray\n"; - String stringEmpty[] = { "" }; - String - strv[] = - { - "", - "a", - "a b", - " ", - "test", - "smile", - "this is a little longer string... maybe a little but longer... this makes test better", - String(10000, 'b') }; - PVStringArrayPtr pvString = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvString)); - pvString->put(0, 0, stringEmpty, 0); - serializationTest(pvString); - pvString->put(0, 8, strv, 0); - serializationTest(pvString); - - ofile<<"!!! PASSED\n\n"; + pv->replace(empty); + serializationTest(pv); + pv->replace(data); + serializationTest(pv); } -void testNonInitialized(std::ostream& ofile) { - ofile<<"Testing non-initialized...\n"; +static const boolean bdata[] = {0, 1, 0, 1, 1}; + +static const int8 i8data[] = { 0, 1, 2, -1, BYTE_MAX_VALUE, BYTE_MAX_VALUE-1, + BYTE_MIN_VALUE+1, BYTE_MIN_VALUE }; +static const uint8 u8data[] = { 0, 1, 2, -1, UBYTE_MAX_VALUE, UBYTE_MAX_VALUE-1 }; + +static const int16 i16data[] = { 0, 1, 2, -1, SHORT_MAX_VALUE, SHORT_MAX_VALUE-1, + SHORT_MIN_VALUE+1, SHORT_MIN_VALUE }; +static const uint16 u16data[] = { 0, 1, 2, -1, USHORT_MAX_VALUE, USHORT_MAX_VALUE-1 }; + +static const int32 i32data[] = { 0, 1, 2, -1, INT_MAX_VALUE, INT_MAX_VALUE-1, + INT_MIN_VALUE+1, INT_MIN_VALUE }; +static const uint32 u32data[] = { 0, 1, 2, -1, UINT_MAX_VALUE, UINT_MAX_VALUE-1 }; + +static const int64 i64data[] = { 0, 1, 2, -1, LONG_MAX_VALUE, LONG_MAX_VALUE-1, + LONG_MIN_VALUE+1, LONG_MIN_VALUE }; +static const uint64 u64data[] = { 0, 1, 2, -1, ULONG_MAX_VALUE, ULONG_MAX_VALUE-1 }; + +static const double ddata[] = { (double)0.0, (double)1.1, (double)2.3, (double)-1.4, + DOUBLE_MAX_VALUE, DOUBLE_MAX_VALUE-(double)123456.789, + DOUBLE_MIN_VALUE+(double)1.1, DOUBLE_MIN_VALUE }; + +static const float fdata[] = { (float)0.0, (float)1.1, (float)2.3, (float)-1.4, + FLOAT_MAX_VALUE, FLOAT_MAX_VALUE-(float)123456.789, + FLOAT_MIN_VALUE+(float)1.1, FLOAT_MIN_VALUE }; + +static const String sdata[] = { + "", + "a", + "a b", + " ", + "test", + "smile", + "this is a little longer string... maybe a little but longer... this makes test better", + String(10000, 'b') +}; + +void testArray() { + testDiag("Testing arrays..."); + + testArrayType(bdata, NELEMENTS(bdata)); + + testArrayType(i8data, NELEMENTS(i8data)); + testArrayType(u8data, NELEMENTS(u8data)); + testArrayType(i16data, NELEMENTS(i16data)); + testArrayType(u16data, NELEMENTS(u16data)); + testArrayType(i32data, NELEMENTS(i32data)); + testArrayType(u32data, NELEMENTS(u32data)); + testArrayType(i64data, NELEMENTS(i64data)); + testArrayType(u64data, NELEMENTS(u64data)); + + testArrayType(ddata, NELEMENTS(ddata)); + testArrayType(fdata, NELEMENTS(fdata)); + + testArrayType(sdata, NELEMENTS(sdata)); +} + +void testNonInitialized() { + testDiag("Testing non-initialized..."); PVDataCreatePtr factory = getPVDataCreate(); - assert(factory.get()!=NULL); + testOk1(factory.get()!=NULL); // be sure all is covered for (int i = pvBoolean; i < pvString; i++) @@ -558,17 +336,15 @@ void testNonInitialized(std::ostream& ofile) { // and a structure array PVStructureArrayPtr structureArray = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure->getStructure())); serializationTest(structureArray); - - ofile<<"!!! PASSED\n\n"; } -void testStructure(std::ostream& ofile) { - ofile<<"Testing structure...\n"; +void testStructure() { + testDiag("Testing structure..."); PVDataCreatePtr factory = getPVDataCreate(); - assert(factory.get()!=NULL); + testOk1(factory.get()!=NULL); - ofile<<"\tSimple structure serialization\n"; + testDiag("\tSimple structure serialization"); PVStructurePtr pvStructure = factory->createPVStructure(getStandardField()->timeStamp()); pvStructure->getLongField("secondsPastEpoch")->put(123); pvStructure->getIntField("nanoSeconds")->put(456); @@ -576,21 +352,19 @@ void testStructure(std::ostream& ofile) { serializationTest(pvStructure); - ofile<<"\tComplex structure serialization\n"; + testDiag("\tComplex structure serialization"); pvStructure = factory->createPVStructure( getStandardField()->structureArray( getStandardField()->timeStamp(), "alarm,control,display,timeStamp") ); // TODO fill with data serializationTest(pvStructure); - - ofile<<"!!! PASSED\n\n"; } -void testStructureId(std::ostream& ofile) { - ofile<<"Testing structureID...\n"; +void testStructureId() { + testDiag("Testing structureID..."); FieldCreatePtr fieldCreate = getFieldCreate(); @@ -607,15 +381,13 @@ void testStructureId(std::ostream& ofile) { StructureConstPtr structure2 = fieldCreate->createStructure("id2", fieldNames, fields); - assert(structureWithNoId!=structure1); - assert(structure1!=structure2); + testOk1(structureWithNoId!=structure1); + testOk1(structure1!=structure2); //serializationTest(structure1); PVStructurePtr pvStructure = getPVDataCreate()->createPVStructure(structure1); serializationTest(pvStructure); - - ofile<<"!!! PASSED\n\n"; } void serializatioTest(FieldConstPtr const & field) @@ -631,17 +403,15 @@ void serializatioTest(FieldConstPtr const & field) FieldConstPtr deserializedField = getFieldCreate()->deserialize(buffer, control); // must equal - bool isEqual = *field == *deserializedField; - assert(isEqual); - //assertEquals("field " + field.toString() + " serialization broken", field, deserializedField); + testOk1(*field == *deserializedField); } -void testIntrospectionSerialization(std::ostream& ofile) +void testIntrospectionSerialization() { - ofile<<"Testing introspection serialization...\n"; + testDiag("Testing introspection serialization..."); FieldCreatePtr factory = getFieldCreate(); - assert(factory.get()!=NULL); + testOk1(factory.get()!=NULL); // be sure all is covered for (int i = pvBoolean; i < pvString; i++) @@ -662,42 +432,34 @@ void testIntrospectionSerialization(std::ostream& ofile) // and a structure array StructureArrayConstPtr structureArray = factory->createStructureArray(structure); serializatioTest(structureArray); - - ofile<<"!!! PASSED\n\n"; } -void testStringCopy(std::ostream& ofile) { +void testStringCopy() { String s1 = "abc"; String s2 = s1; if (s1.c_str() != s2.c_str()) - ofile << "\n!!! implementation of epics::pvData::String assignment operator does not share content !!!\n\n"; + testDiag("implementation of epics::pvData::String assignment operator does not share content"); } -int main(int argc, char *argv[]) { - std::ofstream outfile; - std::ostream *out=NULL; - if(argc>1) { - outfile.open(argv[1]); - if(outfile.is_open()){ - out=&outfile; - }else{ - fprintf(stderr, "Failed to open test output file\n"); - } - } - if(!out) out=&std::cout; +} // end namespace + +MAIN(testSerialization) { + + testPlan(171); + flusher = new SerializableControlImpl(); control = new DeserializableControlImpl(); buffer = new ByteBuffer(1<<16); - testStringCopy(*out); + testStringCopy(); - testIntrospectionSerialization(*out); - testEquals(*out); - testNonInitialized(*out); + testIntrospectionSerialization(); + testEquals(); + testNonInitialized(); - testScalar(*out); - testArray(*out); - testStructure(*out); + testScalar(); + testArray(); + testStructure(); delete buffer; @@ -705,6 +467,6 @@ int main(int argc, char *argv[]) { delete flusher; epicsExitCallAtExits(); - return 0; + return testDone(); } From 80777b293f5cc3eefd46c7c8fabe950bd813cb87 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 8 May 2013 15:17:13 -0400 Subject: [PATCH 039/103] rewrite testPVScalarArray --- testApp/pv/Makefile | 5 +- testApp/pv/testPVScalarArray.cpp | 463 +++++++++---------------------- 2 files changed, 132 insertions(+), 336 deletions(-) diff --git a/testApp/pv/Makefile b/testApp/pv/Makefile index 558e4c0..b93d140 100644 --- a/testApp/pv/Makefile +++ b/testApp/pv/Makefile @@ -34,9 +34,10 @@ PROD_HOST += testConvert testConvert_SRCS += testConvert.cpp testConvert_LIBS += pvData Com -PROD_HOST += testPVScalarArray +TESTPROD += testPVScalarArray testPVScalarArray_SRCS += testPVScalarArray.cpp testPVScalarArray_LIBS += pvData Com +TESTS += testPVScalarArray PROD_HOST += testPVStructureArray testPVStructureArray_SRCS += testPVStructureArray.cpp @@ -46,6 +47,8 @@ PROD_HOST += testOperators testOperators_SRCS += testOperators.cpp testOperators_LIBS += pvData Com +TESTSCRIPTS_HOST += $(TESTS:%=%.t) + include $(TOP)/configure/RULES #---------------------------------------- # ADD RULES AFTER THIS LINE diff --git a/testApp/pv/testPVScalarArray.cpp b/testApp/pv/testPVScalarArray.cpp index e709831..f4c24cb 100644 --- a/testApp/pv/testPVScalarArray.cpp +++ b/testApp/pv/testPVScalarArray.cpp @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include @@ -25,352 +27,143 @@ using namespace epics::pvData; using std::tr1::static_pointer_cast; -static bool debug = false; +namespace { -static FieldCreatePtr fieldCreate = getFieldCreate(); -static PVDataCreatePtr pvDataCreate = getPVDataCreate(); -static StandardFieldPtr standardField = getStandardField(); -static StandardPVFieldPtr standardPVField = getStandardPVField(); -static ConvertPtr convert = getConvert(); -static String builder; -static String alarmTimeStamp("alarm,timeStamp"); -static String alarmTimeStampValueAlarm("alarm,timeStamp,valueAlarm"); -static String allProperties("alarm,timeStamp,display,control,valueAlarm"); -static FILE * fd = NULL; -static size_t length = 4; - -static void byteArray() +static void testFactory() { - if(debug) fprintf(fd,"\nbyteArray\n"); - PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvByte);; - PVByteArrayPtr pvByteArray = static_pointer_cast(pvScalarArray); - ByteArray value; - value.reserve(length); - int8 xxx = 0x7f; - for(size_t i = 0; iput(0,length,value,0); - builder.clear(); - pvByteArray->toString(&builder); - if(debug) fprintf(fd,"put\n%s\n",builder.c_str()); - convert->fromByteArray(pvScalarArray,0,length,value,0); - builder.clear(); - pvByteArray->toString(&builder); - if(debug) fprintf(fd,"convert\n%s\n",builder.c_str()); - ByteArrayData data; - pvByteArray->get(0,length,data); - ByteArray_iterator iter = data.data.begin(); - if(debug) fprintf(fd,"iter ["); - for(iter=data.data.begin();iter!=data.data.end();++iter) { - if(debug) fprintf(fd,"%d ",*iter); + testDiag("Check array creation"); + + for(ScalarType e=pvBoolean; e<=pvString; e=(ScalarType)(1+(int)e)) + { + testDiag("Check type %s", ScalarTypeFunc::name(e)); + PVScalarArrayPtr arr = getPVDataCreate()->createPVScalarArray(e); + testOk1(arr.get()!=NULL); + if(!arr.get()) + continue; + testOk1(arr->getScalarArray()->getElementType()==e); + testOk1(arr->getLength()==0); + arr->setLength(10); + testOk1(arr->getLength()==10); + testOk1(arr->getCapacity()>=10); + arr->setLength(0); + testOk1(arr->getLength()==0); } - if(debug) fprintf(fd,"]\n"); - if(debug) fprintf(fd,"raw ["); - int8 * pdata = get(data.data); - for(size_t i=0; i +struct basicTestData { + static inline void fill(typename PVT::svector& data) { + data.resize(100); + for(typename PVT::value_type i=0; + (size_t)i +struct basicTestData { + static inline void fill(PVStringArray::svector& data) { + PVIntArray::svector idata; + basicTestData::fill(idata); + data.resize(idata.size()); + castUnsafeV(data.size(), pvString, data.data(), pvInt, idata.data()); + } +}; + +template +static void testBasic() { - if(debug) fprintf(fd,"\nubyteArray\n"); - PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvUByte);; - PVUByteArrayPtr pvUByteArray = static_pointer_cast(pvScalarArray); - UByteArray value; - value.reserve(length); - uint8 xxx = 0x7f; - for(size_t i = 0; iput(0,length,value,0); - builder.clear(); - pvUByteArray->toString(&builder); - if(debug) fprintf(fd,"put\n%s\n",builder.c_str()); - convert->fromUByteArray(pvScalarArray,0,length,value,0); - builder.clear(); - pvUByteArray->toString(&builder); - if(debug) fprintf(fd,"convert\n%s\n",builder.c_str()); - UByteArrayData data; - pvUByteArray->get(0,length,data); - UByteArray_iterator iter = data.data.begin(); - if(debug) fprintf(fd,"iter ["); - for(iter=data.data.begin();iter!=data.data.end();++iter) { - if(debug) fprintf(fd,"%u ",*iter); - } - if(debug) fprintf(fd,"]\n"); - if(debug) fprintf(fd,"raw ["); - uint8 * pdata = get(data.data); - for(size_t i=0; i(getPVDataCreate()->createPVScalarArray(PVT::typeCode)); + typename PVT::shared_pointer arr2 = static_pointer_cast(getPVDataCreate()->createPVScalarArray(PVT::typeCode)); + + testOk1(*arr1==*arr2); + testOk1(*arr1==*arr1); + testOk1(*arr1->getScalarArray()==*arr2->getScalarArray()); + + typename PVT::svector data; + data.reserve(200); + basicTestData::fill(data); + + testOk1(data.unique()); + arr1->replace(data); + testOk1(!data.unique()); + + testOk1(arr1->getLength()==data.size()); + + testOk1(*arr1!=*arr2); + + data.clear(); + + testOk1(arr1->viewUnsafe().unique()); + + arr2->assign(*arr1); + + testOk1(*arr1==*arr2); + testOk1(!arr1->viewUnsafe().unique()); + + arr2->swap(data); + + testOk1(arr2->getLength()==0); + testOk1(data.size()==arr1->getLength()); + + PVIntArray::svector idata; + arr1->PVScalarArray::getAs(idata); + + testOk1(idata[1]==10); + + idata.make_unique(); + idata[1] = 42; + + arr1->PVScalarArray::putFrom(idata); + + testOk1(castUnsafe(arr1->viewUnsafe()[1])==42); } -static void longArray() +static void testShare() { - if(debug) fprintf(fd,"\nlongArray\n"); - PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvLong);; - PVLongArrayPtr pvLongArray = static_pointer_cast(pvScalarArray); - LongArray value; - value.reserve(length); - int64 xxx = 0x7fffffffffffffffLL; - for(size_t i = 0; iput(0,length,value,0); - builder.clear(); - pvLongArray->toString(&builder); - if(debug) fprintf(fd,"put\n%s\n",builder.c_str()); - convert->fromLongArray(pvScalarArray,0,length,value,0); - builder.clear(); - pvLongArray->toString(&builder); - if(debug) fprintf(fd,"convert\n%s\n",builder.c_str()); - LongArrayData data; - pvLongArray->get(0,length,data); - LongArray_iterator iter = data.data.begin(); - if(debug) fprintf(fd,"iter ["); - for(iter=data.data.begin();iter!=data.data.end();++iter) { - if(debug) fprintf(fd,"%lli ",(long long)*iter); - } - if(debug) fprintf(fd,"]\n"); - if(debug) fprintf(fd,"raw ["); - int64 * pdata = get(data.data); - for(size_t i=0; i(getPVDataCreate()->createPVScalarArray(pvInt)); + PVStringArrayPtr sarr = static_pointer_cast(getPVDataCreate()->createPVScalarArray(pvString)); + + PVIntArray::svector idata(4, 1); + + sarr->PVScalarArray::putFrom(idata); // copy and convert + + testOk1(idata.unique()); + + iarr->PVScalarArray::putFrom(idata); // take a reference + + testOk1(!idata.unique()); + + idata.clear(); + + sarr->PVScalarArray::getAs(idata); // copy and convert + + testOk1(idata.unique()); + + iarr->PVScalarArray::getAs(idata); // take a reference + + testOk1(!idata.unique()); } -static void ulongArray() -{ - if(debug) fprintf(fd,"\nulongArray\n"); - PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvULong);; - PVULongArrayPtr pvULongArray = static_pointer_cast(pvScalarArray); - ULongArray value; - value.reserve(length); - uint64 xxx = 0x7fffffffffffffffLL; - for(size_t i = 0; iput(0,length,value,0); - builder.clear(); - pvULongArray->toString(&builder); - if(debug) fprintf(fd,"put\n%s\n",builder.c_str()); - convert->fromULongArray(pvScalarArray,0,length,value,0); - builder.clear(); - pvULongArray->toString(&builder); - if(debug) fprintf(fd,"convert\n%s\n",builder.c_str()); - ULongArrayData data; - pvULongArray->get(0,length,data); - ULongArray_iterator iter = data.data.begin(); - if(debug) fprintf(fd,"iter ["); - for(iter=data.data.begin();iter!=data.data.end();++iter) { - if(debug) fprintf(fd,"%llu ",(long long unsigned)*iter); - } - if(debug) fprintf(fd,"]\n"); - if(debug) fprintf(fd,"raw ["); - uint64 * pdata = get(data.data); - for(size_t i=0; icreatePVScalarArray(pvFloat);; - PVFloatArrayPtr pvFloatArray = static_pointer_cast(pvScalarArray); - FloatArray value; - value.reserve(length); - for(size_t i = 0; iput(0,length,value,0); - builder.clear(); - pvFloatArray->toString(&builder); - if(debug) fprintf(fd,"put\n%s\n",builder.c_str()); - convert->fromFloatArray(pvScalarArray,0,length,value,0); - builder.clear(); - pvFloatArray->toString(&builder); - if(debug) fprintf(fd,"convert\n%s\n",builder.c_str()); - FloatArrayData data; - pvFloatArray->get(0,length,data); - FloatArray_iterator iter = data.data.begin(); - if(debug) fprintf(fd,"iter ["); - for(iter=data.data.begin();iter!=data.data.end();++iter) { - if(debug) fprintf(fd,"%f ",*iter); - } - if(debug) fprintf(fd,"]\n"); - if(debug) fprintf(fd,"raw ["); - float * pdata = get(data.data); - for(size_t i=0; i(); + testBasic(); + testBasic(); + testBasic(); + testBasic(); + testShare(); + return testDone(); } - -static void doubleArray() -{ - if(debug) fprintf(fd,"\ndoubleArray\n"); - PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvDouble);; - PVDoubleArrayPtr pvDoubleArray = static_pointer_cast(pvScalarArray); - DoubleArray value; - value.reserve(length); - for(size_t i = 0; iput(0,length,value,0); - builder.clear(); - pvDoubleArray->toString(&builder); - if(debug) fprintf(fd,"put\n%s\n",builder.c_str()); - convert->fromDoubleArray(pvScalarArray,0,length,value,0); - builder.clear(); - pvDoubleArray->toString(&builder); - if(debug) fprintf(fd,"convert\n%s\n",builder.c_str()); - DoubleArrayData data; - pvDoubleArray->get(0,length,data); - DoubleArray_iterator iter = data.data.begin(); - if(debug) fprintf(fd,"iter ["); - for(iter=data.data.begin();iter!=data.data.end();++iter) { - if(debug) fprintf(fd,"%lf ",*iter); - } - if(debug) fprintf(fd,"]\n"); - if(debug) fprintf(fd,"raw ["); - double * pdata = get(data.data); - for(size_t i=0; icreatePVScalarArray(pvString);; - PVStringArrayPtr pvStringArray = static_pointer_cast(pvScalarArray); - StringArray value; - value.reserve(length); - for(size_t i = 0; iput(0,length,value,0); - builder.clear(); - pvStringArray->toString(&builder); - if(debug) fprintf(fd,"put\n%s\n",builder.c_str()); - convert->fromStringArray(pvScalarArray,0,length,value,0); - builder.clear(); - pvStringArray->toString(&builder); - if(debug) fprintf(fd,"convert\n%s\n",builder.c_str()); - StringArrayData data; - pvStringArray->get(0,length,data); - StringArray_iterator iter = data.data.begin(); - if(debug) fprintf(fd,"iter ["); - for(iter=data.data.begin();iter!=data.data.end();++iter) { - String val = *iter; - if(debug) fprintf(fd,"%s ",val.c_str()); - } - if(debug) fprintf(fd,"]\n"); - if(debug) fprintf(fd,"raw ["); - String* pdata = get(data.data); - for(size_t i=0; icreatePVScalarArray(pvDouble);; - PVDoubleArrayPtr pvDoubleArray = static_pointer_cast(pvScalarArray); - DoubleArray value; - value.reserve(length); - for(size_t i = 0; iput(0,length,value,0); - PVDoubleArrayPtr pvShareArray = static_pointer_cast( - pvDataCreate->createPVScalarArray(pvDouble)); - pvShareArray->shareData( - pvDoubleArray->getSharedVector(), - pvDoubleArray->getCapacity(), - pvDoubleArray->getLength()); - printf("pvDoubleArray->get() %p pvShareArray->get() %p\n",pvDoubleArray->get(),pvShareArray->get()); - printf("pvDoubleArray->getVector() %p pvShareArray->getVector() %p\n", - &(pvDoubleArray->getVector()),&(pvShareArray->getVector())); - printf("pvDoubleArray->getSharedVector() %p pvShareArray->getSharedVector() %p\n", - &(pvDoubleArray->getSharedVector()),&(pvShareArray->getSharedVector())); - assert(pvDoubleArray->get()==pvShareArray->get()); - builder.clear(); - pvShareArray->toString(&builder); - if(debug) fprintf(fd,"pvShare\n%s\n",builder.c_str()); - fprintf(fd,"shareArray PASSED\n"); -} - -int main(int argc,char *argv[]) -{ - char *fileName = 0; - if(argc>1) fileName = argv[1]; - fd = stdout; - if(fileName!=0 && fileName[0]!=0) { - fd = fopen(fileName,"w+"); - } - byteArray(); - ubyteArray(); - longArray(); - ulongArray(); - floatArray(); - doubleArray(); - stringArray(); - shareArray(); - return(0); -} - From 572c02bf6e48dcae7a76a874eead958da7af7d5b Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 8 May 2013 14:35:36 -0400 Subject: [PATCH 040/103] update testOperators --- testApp/pv/testOperators.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/testApp/pv/testOperators.cpp b/testApp/pv/testOperators.cpp index 6512d20..2a49424 100644 --- a/testApp/pv/testOperators.cpp +++ b/testApp/pv/testOperators.cpp @@ -66,9 +66,10 @@ int main(int, char**) pvStructure = standardPVField->scalarArray(pvDouble,"alarm,timeStamp"); std::cout << *pvStructure << std::endl; - double values[] = { 1.1, 2.2, 3.3 }; + PVDoubleArray::svector values(3); + values[0] = 1.1; values[1] = 2.2; values[2] = 3.3; PVDoubleArrayPtr darray = std::tr1::dynamic_pointer_cast(pvStructure->getScalarArrayField("value", pvDouble)); - darray->put(0, 3, values, 0); + darray->replace(values); std::cout << *darray << std::endl; std::cout << format::array_at(1) << *darray << std::endl; From 1bf2ff430a8aa313d7e9f4ee372576b328b07a67 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 14 May 2013 11:24:44 -0400 Subject: [PATCH 041/103] array resize respect immutability --- pvDataApp/factory/PVDataCreateFactory.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pvDataApp/factory/PVDataCreateFactory.cpp b/pvDataApp/factory/PVDataCreateFactory.cpp index 0a2fe00..e169596 100644 --- a/pvDataApp/factory/PVDataCreateFactory.cpp +++ b/pvDataApp/factory/PVDataCreateFactory.cpp @@ -231,7 +231,7 @@ DefaultPVArray::~DefaultPVArray() template void DefaultPVArray::setCapacity(size_t capacity) { - if(capacity>value.capacity()) { + if(this->isCapacityMutable() && capacity>value.capacity()) { value.reserve(capacity); PVArray::setCapacityLength(value.capacity(), value.size()); } @@ -240,6 +240,8 @@ void DefaultPVArray::setCapacity(size_t capacity) template void DefaultPVArray::setLength(size_t length) { + if(this->isImmutable()) + THROW_EXCEPTION2(std::logic_error,"Immutable"); if(length == value.size()) return; else if(length < value.size()) From 629c8346d2279169f30a188f64f3b1e8d0da6a47 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 23 May 2013 17:50:12 -0400 Subject: [PATCH 042/103] postPut in new array API Call when appropriate (putFrom(), copyIn(), and replace()). Not called by swap(), take(), reuse(), or shareData(). Users of the second set of methods are expected to call one of the methods in the first set, or call postPut() directly. Document when postPut is (not) called. --- pvDataApp/factory/StandardPVField.cpp | 4 ++-- pvDataApp/property/pvEnumerated.cpp | 2 +- pvDataApp/pv/pvData.h | 18 +++++++++++++++++- testApp/pv/testPVScalarArray.cpp | 1 + 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/pvDataApp/factory/StandardPVField.cpp b/pvDataApp/factory/StandardPVField.cpp index 7e3f743..f74f60a 100644 --- a/pvDataApp/factory/StandardPVField.cpp +++ b/pvDataApp/factory/StandardPVField.cpp @@ -61,7 +61,7 @@ PVStructurePtr StandardPVField::enumerated(StringArray const &choices) "choices",pvString); PVStringArray::svector cdata(choices.size()); std::copy(choices.begin(), choices.end(), cdata.begin()); - static_cast(*pvScalarArray).swap(cdata); + static_cast(*pvScalarArray).replace(cdata); return pvStructure; } @@ -74,7 +74,7 @@ PVStructurePtr StandardPVField::enumerated( "value.choices",pvString); PVStringArray::svector cdata(choices.size()); std::copy(choices.begin(), choices.end(), cdata.begin()); - static_cast(*pvScalarArray).swap(cdata); + static_cast(*pvScalarArray).replace(cdata); return pvStructure; } diff --git a/pvDataApp/property/pvEnumerated.cpp b/pvDataApp/property/pvEnumerated.cpp index c108434..9ad557f 100644 --- a/pvDataApp/property/pvEnumerated.cpp +++ b/pvDataApp/property/pvEnumerated.cpp @@ -106,7 +106,7 @@ bool PVEnumerated:: setChoices(const StringArray & choices) if(pvChoices->isImmutable()) return false; PVStringArray::svector data(choices.size()); std::copy(choices.begin(), choices.end(), data.begin()); - pvChoices->swap(data); + pvChoices->replace(data); return true; } diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index e644f28..78bffe9 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -706,6 +706,8 @@ public: * type of the provided data. * If the types do match then a new refernce to the provided * data is kept. + * + * Calls postPut() */ template inline void putFrom(const shared_vector::type>& inp) @@ -719,6 +721,8 @@ public: * Assign the given value after conversion. * * A copy and element-wise conversion is are always performed. + * + * Calls postPut() */ template inline void copyIn(const typename ScalarTypeTraits::type* inp, size_t len) @@ -1128,15 +1132,19 @@ public: virtual const svector& viewUnsafe() const = 0; //! Exchange our contents for the provided. - //! Fails for Immutable arrays + //! Fails for Immutable arrays. + //! Callers must ensure that postPut() is called + //! after the last swap() operation. virtual void swap(svector& other) = 0; //! Discard current contents and replaced with the provided. //! Fails for Immutable arrays + //! calls postPut() virtual void replace(const svector& next) { svector temp(next); this->swap(temp); + this->postPut(); } // Derived operations @@ -1149,6 +1157,7 @@ public: } //! Remove and return the current array data + //! Does @b not call postPut() inline svector take() { svector result; @@ -1157,6 +1166,7 @@ public: } //! take() with an implied make_unique() + //! Does @b not call postPut() inline svector reuse() { svector result; @@ -1189,6 +1199,7 @@ public: * @param from The new values to put into the array. * @param fromOffset The offset in from. * @return The number of elements put into the array. + * calls postPut() */ std::size_t put(std::size_t offset, std::size_t length, const_pointer from, std::size_t fromOffset) USAGE_DEPRECATED @@ -1204,6 +1215,7 @@ public: std::copy(from, from + length, temp.begin() + offset); this->swap(temp); + this->postPut(); return length; } @@ -1216,6 +1228,7 @@ public: * @param value The data to share. * @param capacity The capacity of the array. * @param length The length of the array. + * Does @b not call postPut() */ void shareData( shared_vector const & value, @@ -1299,6 +1312,7 @@ public: this->swap(result); } + this->postPut(); } virtual void copyIn(ScalarType id, const void* ptr, size_t len) @@ -1308,6 +1322,7 @@ public: data.resize(len); castUnsafeV(len, typeCode, (void*)data.data(), id, ptr); this->swap(data); + this->postPut(); } virtual void assign(PVScalarArray& pv) @@ -1318,6 +1333,7 @@ public: pv.getAs(typeCode, temp); svector next(static_shared_vector_cast(temp)); this->swap(next); + this->postPut(); } protected: diff --git a/testApp/pv/testPVScalarArray.cpp b/testApp/pv/testPVScalarArray.cpp index f4c24cb..3d6b23c 100644 --- a/testApp/pv/testPVScalarArray.cpp +++ b/testApp/pv/testPVScalarArray.cpp @@ -108,6 +108,7 @@ static void testBasic() testOk1(!arr1->viewUnsafe().unique()); arr2->swap(data); + arr2->postPut(); testOk1(arr2->getLength()==0); testOk1(data.size()==arr1->getLength()); From 54ee8bf7a0850a3716cf633a893ebc5f3c9e9232 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 23 May 2013 17:50:58 -0400 Subject: [PATCH 043/103] PVStructureArray: setLength before postPut Ensure that the correct (new) length is seen. --- pvDataApp/factory/PVStructureArray.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvDataApp/factory/PVStructureArray.cpp b/pvDataApp/factory/PVStructureArray.cpp index d08b6a4..8ef5efe 100644 --- a/pvDataApp/factory/PVStructureArray.cpp +++ b/pvDataApp/factory/PVStructureArray.cpp @@ -175,8 +175,8 @@ size_t PVStructureArray::put(size_t offset,size_t len, } (*to)[i+offset] = frompv; } - postPut(); setLength(length); + postPut(); return len; } From 9e865bc37d8e0c726cc4e698b10f9d568876ca79 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 23 May 2013 18:19:26 -0400 Subject: [PATCH 044/103] Avoid unnecessary copying in copyIn Only re-use the existing reference if it is large enough to hold all the new data. If it isn't then throw it away to avoid copying its current contents during the resize(). --- pvDataApp/pv/pvData.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index 78bffe9..536a8ae 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -1319,6 +1319,10 @@ public: { svector data; this->swap(data); + // Will have to re-alloc anyway? If so avoid copying + // data which will only be over-written + if(data.capacity()swap(data); From 9039a10c9ad4e855a2d016ff8e349e129acbbc6e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 24 May 2013 18:25:09 -0400 Subject: [PATCH 045/103] update testIntrospect with epicsUnitTest --- testApp/pv/Makefile | 1 + testApp/pv/testIntrospect.cpp | 220 +++++++++++++++++++--------------- 2 files changed, 123 insertions(+), 98 deletions(-) diff --git a/testApp/pv/Makefile b/testApp/pv/Makefile index b93d140..a6ab274 100644 --- a/testApp/pv/Makefile +++ b/testApp/pv/Makefile @@ -5,6 +5,7 @@ include $(TOP)/configure/CONFIG PROD_HOST += testIntrospect testIntrospect_SRCS += testIntrospect.cpp testIntrospect_LIBS += pvData Com +TESTS += testIntrospect PROD_HOST += testPVAppend testPVAppend_SRCS += testPVAppend.cpp diff --git a/testApp/pv/testIntrospect.cpp b/testApp/pv/testIntrospect.cpp index 3577f2b..e405502 100644 --- a/testApp/pv/testIntrospect.cpp +++ b/testApp/pv/testIntrospect.cpp @@ -12,8 +12,8 @@ #include #include -#include -#include +#include +#include #include #include @@ -23,130 +23,154 @@ using namespace epics::pvData; -static bool debug = false; - static FieldCreatePtr fieldCreate; static PVDataCreatePtr pvDataCreate; static StandardFieldPtr standardField; -static String builder(""); -static void testScalarCommon(FILE * fd,ScalarType stype, +static void testScalarCommon(ScalarType stype, bool isInteger,bool isNumeric,bool isPrimitive) { + String builder; ScalarConstPtr pscalar = fieldCreate->createScalar(stype); Type type = pscalar->getType(); - assert(type==scalar); + testOk1(type==scalar); builder.clear(); TypeFunc::toString(&builder,type); - assert(builder.compare("scalar")==0); + testOk1(builder.compare("scalar")==0); ScalarType scalarType = pscalar->getScalarType(); - assert(scalarType==stype); - assert(ScalarTypeFunc::isInteger(scalarType)==isInteger); - assert(ScalarTypeFunc::isNumeric(scalarType)==isNumeric); - assert(ScalarTypeFunc::isPrimitive(scalarType)==isPrimitive); - builder.clear(); - pscalar->toString(&builder); - if(debug) fprintf(fd,"%s\n",builder.c_str()); + testOk1(scalarType==stype); + testOk1(ScalarTypeFunc::isInteger(scalarType)==isInteger); + testOk1(ScalarTypeFunc::isNumeric(scalarType)==isNumeric); + testOk1(ScalarTypeFunc::isPrimitive(scalarType)==isPrimitive); } -static void testScalar(FILE * fd) { - if(debug) fprintf(fd,"\ntestScalar\n"); - testScalarCommon(fd,pvBoolean,false,false,true); - testScalarCommon(fd,pvByte,true,true,true); - testScalarCommon(fd,pvShort,true,true,true); - testScalarCommon(fd,pvInt,true,true,true); - testScalarCommon(fd,pvLong,true,true,true); - testScalarCommon(fd,pvFloat,false,true,true); - testScalarCommon(fd,pvDouble,false,true,true); - testScalarCommon(fd,pvString,false,false,false); - fprintf(fd,"testScalar PASSED\n"); +static void testScalar() { + testDiag("testScalar"); + testScalarCommon(pvBoolean,false,false,true); + testScalarCommon(pvByte,true,true,true); + testScalarCommon(pvShort,true,true,true); + testScalarCommon(pvInt,true,true,true); + testScalarCommon(pvLong,true,true,true); + testScalarCommon(pvFloat,false,true,true); + testScalarCommon(pvDouble,false,true,true); + testScalarCommon(pvString,false,false,false); } -static void testScalarArrayCommon(FILE * fd,ScalarType stype, +static void testScalarArrayCommon(ScalarType stype, bool isInteger,bool isNumeric,bool isPrimitive) { + String builder; ScalarArrayConstPtr pscalar = fieldCreate->createScalarArray(stype); Type type = pscalar->getType(); - assert(type==scalarArray); + testOk1(type==scalarArray); builder.clear(); TypeFunc::toString(&builder,type); - assert(builder.compare("scalarArray")==0); + testOk1(builder.compare("scalarArray")==0); ScalarType scalarType = pscalar->getElementType(); - assert(scalarType==stype); - assert(ScalarTypeFunc::isInteger(scalarType)==isInteger); - assert(ScalarTypeFunc::isNumeric(scalarType)==isNumeric); - assert(ScalarTypeFunc::isPrimitive(scalarType)==isPrimitive); - builder.clear(); - pscalar->toString(&builder); - if(debug) fprintf(fd,"%s\n",builder.c_str()); + testOk1(scalarType==stype); + testOk1(ScalarTypeFunc::isInteger(scalarType)==isInteger); + testOk1(ScalarTypeFunc::isNumeric(scalarType)==isNumeric); + testOk1(ScalarTypeFunc::isPrimitive(scalarType)==isPrimitive); } -static void testScalarArray(FILE * fd) { - if(debug) fprintf(fd,"\ntestScalarArray\n"); - testScalarArrayCommon(fd,pvBoolean,false,false,true); - testScalarArrayCommon(fd,pvByte,true,true,true); - testScalarArrayCommon(fd,pvShort,true,true,true); - testScalarArrayCommon(fd,pvInt,true,true,true); - testScalarArrayCommon(fd,pvLong,true,true,true); - testScalarArrayCommon(fd,pvFloat,false,true,true); - testScalarArrayCommon(fd,pvDouble,false,true,true); - testScalarArrayCommon(fd,pvString,false,false,false); - fprintf(fd,"testScalarArray PASSED\n"); +static void testScalarArray() { + testDiag("testScalarArray"); + testScalarArrayCommon(pvBoolean,false,false,true); + testScalarArrayCommon(pvByte,true,true,true); + testScalarArrayCommon(pvShort,true,true,true); + testScalarArrayCommon(pvInt,true,true,true); + testScalarArrayCommon(pvLong,true,true,true); + testScalarArrayCommon(pvFloat,false,true,true); + testScalarArrayCommon(pvDouble,false,true,true); + testScalarArrayCommon(pvString,false,false,false); } -static void testSimpleStructure(FILE * fd) { - if(debug) fprintf(fd,"\ntestSimpleStructure\n"); - String properties("alarm,timeStamp,display,control,valueAlarm"); - StructureConstPtr ptop = standardField->scalar(pvDouble,properties); - builder.clear(); - ptop->toString(&builder); - if(debug) fprintf(fd,"%s\n",builder.c_str()); - fprintf(fd,"testSimpleStructure PASSED\n"); -} - -static StructureConstPtr createPowerSupply() { - size_t nfields = 3; - String properties("alarm"); - StringArray names; - names.reserve(nfields); - FieldConstPtrArray powerSupply; - powerSupply.reserve(nfields); - names.push_back("voltage"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - names.push_back("power"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - names.push_back("current"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - return fieldCreate->createStructure(names,powerSupply); -} - -static void testStructureArray(FILE * fd) { - if(debug) fprintf(fd,"\ntestStructureArray\n"); - String properties("alarm,timeStamp"); - StructureConstPtr powerSupply = createPowerSupply(); - StructureConstPtr top = standardField->structureArray( - powerSupply,properties); - builder.clear(); - top->toString(&builder); - if(debug) fprintf(fd,"%s\n",builder.c_str()); - fprintf(fd,"testStructureArray PASSED\n"); -} - -int main(int argc,char *argv[]) +static void testStructure() { - char *fileName = 0; - if(argc>1) fileName = argv[1]; - FILE * fd = stdout; - if(fileName!=0 && fileName[0]!=0) { - fd = fopen(fileName,"w+"); - } + testDiag("testStructure"); + StringArray names1(2); + names1[0] = "innerA"; + names1[1] = "innerB"; + FieldConstPtrArray fields1(2); + fields1[0] = fieldCreate->createScalar(pvDouble); + fields1[1] = fieldCreate->createScalarArray(pvString); + + StructureConstPtr struct1 = fieldCreate->createStructure(names1, fields1); + + testOk1(struct1->getNumberFields()==2); + testOk1(struct1->getField("innerA")==fields1[0]); + testOk1(struct1->getField("innerB")==fields1[1]); + testOk1(struct1->getFieldIndex("innerA")==0); + testOk1(struct1->getFieldIndex("innerB")==1); + testOk1(struct1->getField(0)==fields1[0]); + testOk1(struct1->getField(1)==fields1[1]); + testOk1(struct1->getFieldName(0)==names1[0]); + testOk1(struct1->getFieldName(1)==names1[1]); + + testOk1(struct1->getID() == Structure::DEFAULT_ID); + + testOk1(fields1 == struct1->getFields()); // vector equality + + StructureArrayConstPtr struct1arr = fieldCreate->createStructureArray(struct1); + + testOk1(struct1arr->getStructure()==struct1); + testOk1(struct1arr->getID()=="structure[]"); +} + +#define testExcept(EXCEPT, CMD) try{ CMD; testFail( "No exception from: " #CMD); } \ +catch(EXCEPT& e) {testPass("Got expected exception from: " #CMD);} \ +catch(std::exception& e) {testFail("Got wrong exception %s(%s) from: " #CMD, typeid(e).name(),e.what());} \ +catch(...) {testFail("Got unknown execption from: " #CMD);} + +static void testError() +{ + testDiag("testError"); + ScalarType invalidtype = (ScalarType)9999; + + testExcept(std::invalid_argument, ScalarTypeFunc::getScalarType("invalidtype")); + + testExcept(std::invalid_argument, ScalarTypeFunc::elementSize(invalidtype)); + + testExcept(std::invalid_argument, ScalarTypeFunc::name(invalidtype)); + + testOk1(!ScalarTypeFunc::isInteger(invalidtype)); + testOk1(!ScalarTypeFunc::isUInteger(invalidtype)); + testOk1(!ScalarTypeFunc::isNumeric(invalidtype)); + testOk1(!ScalarTypeFunc::isPrimitive(invalidtype)); + + testExcept(std::invalid_argument, fieldCreate->createScalar(invalidtype)); + testExcept(std::invalid_argument, fieldCreate->createScalarArray(invalidtype)); + + StringArray names; + FieldConstPtrArray fields(1); + + // fails because names.size()!=fields.size() + testExcept(std::invalid_argument, fieldCreate->createStructure(names,fields)); + + names.resize(1);; + + // fails because names[0].size()==0 + testExcept(std::invalid_argument, fieldCreate->createStructure(names,fields)); + + names[0] = "hello"; + + // fails because fields[0].get()==NULL + testExcept(std::invalid_argument, fieldCreate->createStructure(names,fields)); + + fields[0] = std::tr1::static_pointer_cast(fieldCreate->createScalar(pvDouble)); + + testOk1(fieldCreate->createStructure(names,fields).get()!=NULL); +} + +MAIN(testIntrospect) +{ + testPlan(122); fieldCreate = getFieldCreate(); pvDataCreate = getPVDataCreate(); standardField = getStandardField(); - testScalar(fd); - testScalarArray(fd); - testSimpleStructure(fd); - testStructureArray(fd); - return(0); + testScalar(); + testScalarArray(); + testStructure(); + testError(); + return testDone(); } - From 57804494ef75a47fcc0a18ab07c3df948afbcd72 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 24 May 2013 18:26:47 -0400 Subject: [PATCH 046/103] Misc fixes and error checking fix argument type for getScalarType mark getFieldName as const Argument checking for Field construction --- pvDataApp/factory/FieldCreateFactory.cpp | 18 ++++++++++++++---- pvDataApp/factory/TypeFunc.cpp | 2 +- pvDataApp/pv/pvIntrospect.h | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/pvDataApp/factory/FieldCreateFactory.cpp b/pvDataApp/factory/FieldCreateFactory.cpp index 7024cd7..e8444ba 100644 --- a/pvDataApp/factory/FieldCreateFactory.cpp +++ b/pvDataApp/factory/FieldCreateFactory.cpp @@ -66,7 +66,11 @@ struct StructureArrayHashFunction { Scalar::Scalar(ScalarType scalarType) - : Field(scalar),scalarType(scalarType){} + : Field(scalar),scalarType(scalarType) +{ + if(scalarTypepvString) + throw std::invalid_argument("Can't construct Scalar from invalid ScalarType"); +} Scalar::~Scalar(){} @@ -166,7 +170,11 @@ static StructureConstPtr deserializeStructureField(const FieldCreate* fieldCreat } ScalarArray::ScalarArray(ScalarType elementType) -: Field(scalarArray),elementType(elementType){} +: Field(scalarArray),elementType(elementType) +{ + if(elementTypepvString) + throw std::invalid_argument("Can't construct ScalarArray from invalid ScalarType"); +} ScalarArray::~ScalarArray() {} @@ -275,10 +283,12 @@ Structure::Structure ( } size_t number = fields.size(); for(size_t i=0; i Date: Wed, 29 May 2013 09:30:02 -0400 Subject: [PATCH 047/103] more testIntrospect --- testApp/pv/testIntrospect.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/testApp/pv/testIntrospect.cpp b/testApp/pv/testIntrospect.cpp index e405502..79bfe52 100644 --- a/testApp/pv/testIntrospect.cpp +++ b/testApp/pv/testIntrospect.cpp @@ -111,6 +111,18 @@ static void testStructure() testOk1(fields1 == struct1->getFields()); // vector equality + StringArray names2(2); + names2[0] = "outerA"; + names2[1] = "outerB"; + FieldConstPtrArray fields2(2); + fields2[0] = fieldCreate->createScalar(pvInt); + fields2[1] = std::tr1::static_pointer_cast(struct1); + + StructureConstPtr struct2 = fieldCreate->createStructure(names2, fields2); + + testOk1(struct2->getNumberFields()==2); // not recursive + testOk1(struct2->getField(1)==fields2[1]); + StructureArrayConstPtr struct1arr = fieldCreate->createStructureArray(struct1); testOk1(struct1arr->getStructure()==struct1); @@ -164,7 +176,7 @@ static void testError() MAIN(testIntrospect) { - testPlan(122); + testPlan(124); fieldCreate = getFieldCreate(); pvDataCreate = getPVDataCreate(); standardField = getStandardField(); From 3b6268a4fc6bbdff69fc1d2b58f53a0f28e38d01 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 30 May 2013 19:16:22 -0400 Subject: [PATCH 048/103] add const_iterator to shared_vector --- pvDataApp/misc/sharedVector.h | 15 ++++++++++++--- testApp/misc/testSharedVector.cpp | 21 ++++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index e5098a8..9d9cc5e 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -32,6 +32,10 @@ namespace detail { } }; + // avoid adding 'const' twice + template struct decorate_const { typedef const T type; }; + template struct decorate_const { typedef const T type; }; + /* All the parts of shared_vector which * don't need special handling for E=void */ @@ -193,9 +197,12 @@ class shared_vector : public detail::shared_vector_base public: typedef E value_type; typedef E& reference; + typedef typename detail::decorate_const::type& const_reference; typedef E* pointer; typedef E* iterator; typedef std::reverse_iterator reverse_iterator; + typedef typename detail::decorate_const::type* const_iterator; + typedef std::reverse_iterator const_reverse_iterator; typedef ptrdiff_t difference_type; typedef size_t size_type; @@ -296,7 +303,7 @@ public: if(this->m_data && this->m_data.unique()) { // we have data and exclusive ownership of it if(i<=this->m_total) { - // We have room to grow! + // We have room to grow (or shrink)! this->m_count = i; return; } @@ -364,12 +371,16 @@ public: // STL iterators iterator begin() const{return this->m_data.get()+this->m_offset;} + const_iterator cbegin() const{return begin();} iterator end() const{return this->m_data.get()+this->m_offset+this->m_count;} + const_iterator cend() const{return end();} reverse_iterator rbegin() const{return reverse_iterator(end());} + const_reverse_iterator crbegin() const{return rbegin();} reverse_iterator rend() const{return reverse_iterator(begin());} + const_reverse_iterator crend() const{return rend();} reference front() const{return (*this)[0];} reference back() const{return (*this)[this->m_count-1];} @@ -636,8 +647,6 @@ std::ostream& operator<<(std::ostream& strm, const epics::pvData::shared_vector< * Therefore the get_allocator() method and the allocator_type typedef are * not provided. * - * shared_vector does not provide the const_* typedefs. - * * The assign() method and the related constructor are not implemented * at this time. * diff --git a/testApp/misc/testSharedVector.cpp b/testApp/misc/testSharedVector.cpp index c76e350..71fd943 100644 --- a/testApp/misc/testSharedVector.cpp +++ b/testApp/misc/testSharedVector.cpp @@ -206,9 +206,28 @@ static void testConst() testOk1(rodata[1]==100); + // intentionally modify shared data! + // safe since this thread owns all references. writable[1]=200; testOk1(rodata[1]==200); + + epics::pvData::shared_vector::const_iterator a; + epics::pvData::shared_vector::iterator b; + epics::pvData::shared_vector::const_iterator c; + + a = writable.begin(); + b = rodata.begin(); + c = rodata.end(); + + testOk1(std::equal(b, c, a)); + + a = writable.cbegin(); + c = rodata.cend(); + + epics::pvData::shared_vector::const_reference x = rodata[1]; + + testOk1(x==200); } static void testSlice() @@ -318,7 +337,7 @@ static void testVoid() MAIN(testSharedVector) { - testPlan(99); + testPlan(101); testDiag("Tests for shared_vector"); testDiag("sizeof(shared_vector)=%lu", From 82a33460cf8b3e4883b6e20875d137c6c4f06c1e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 31 May 2013 09:34:38 -0400 Subject: [PATCH 049/103] pvData update doc comments --- pvDataApp/pv/pvData.h | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index 536a8ae..93b8c65 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -1126,15 +1126,20 @@ public: // Primative array manipulations - //! unchecked writable reference - //! Before you call this directly, consider using one - //! other the following methods. + //! unchecked reference to writable data + //! Please consider the view() method instead of viewUnsafe(). virtual const svector& viewUnsafe() const = 0; - //! Exchange our contents for the provided. - //! Fails for Immutable arrays. - //! Callers must ensure that postPut() is called - //! after the last swap() operation. + /** Exchange our contents for the provided. + * + @throws std::logic_error for Immutable arrays. + * + * Callers must ensure that postPut() is called + * after the last swap() operation. + * + * Before you call this directly, consider using + * the take(), reuse(), or replace() methods. + */ virtual void swap(svector& other) = 0; //! Discard current contents and replaced with the provided. @@ -1157,7 +1162,7 @@ public: } //! Remove and return the current array data - //! Does @b not call postPut() + //! Does @b not (and should not) call postPut() inline svector take() { svector result; @@ -1166,7 +1171,7 @@ public: } //! take() with an implied make_unique() - //! Does @b not call postPut() + //! Does @b not (and should not) call postPut() inline svector reuse() { svector result; @@ -1246,8 +1251,8 @@ public: return this->viewUnsafe().data(); } - vector const & getVector() USAGE_ERROR("No longer implemented"); - shared_vector const & getSharedVector() USAGE_ERROR("No longer implemented"); + vector const & getVector() USAGE_ERROR("No longer implemented. Replace with view()"); + shared_vector const & getSharedVector() USAGE_ERROR("No longer implemented. Replace with view()"); std::ostream& dumpValue(std::ostream& o) const { From 4294710d9ef2c234bd821f41e7d5498cac56005a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 3 Jun 2013 13:43:01 -0400 Subject: [PATCH 050/103] make viewUnsafe protected No longer part of the public API of PVValueArray --- pvDataApp/property/pvEnumerated.cpp | 2 +- pvDataApp/pv/pvData.h | 3 ++- testApp/pv/testPVScalarArray.cpp | 20 ++++++++++++++------ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/pvDataApp/property/pvEnumerated.cpp b/pvDataApp/property/pvEnumerated.cpp index 9ad557f..ce76355 100644 --- a/pvDataApp/property/pvEnumerated.cpp +++ b/pvDataApp/property/pvEnumerated.cpp @@ -78,7 +78,7 @@ String PVEnumerated::getChoice() throw std::logic_error(notAttached); } int index = pvIndex->get(); - const PVStringArray::svector& data(pvChoices->viewUnsafe()); + const PVStringArray::const_svector& data(pvChoices->view()); return data[index]; } diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index 93b8c65..05d77d3 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -1125,10 +1125,11 @@ public: virtual ~PVValueArray() {} // Primative array manipulations - +protected: //! unchecked reference to writable data //! Please consider the view() method instead of viewUnsafe(). virtual const svector& viewUnsafe() const = 0; +public: /** Exchange our contents for the provided. * diff --git a/testApp/pv/testPVScalarArray.cpp b/testApp/pv/testPVScalarArray.cpp index 3d6b23c..67cbd6e 100644 --- a/testApp/pv/testPVScalarArray.cpp +++ b/testApp/pv/testPVScalarArray.cpp @@ -50,13 +50,21 @@ static void testFactory() } } +template +bool hasUniqueVector(const typename PVT::shared_pointer& pv) +{ + typename PVT::svector data; + pv->swap(data); + bool ret = data.unique(); + pv->swap(data); + return ret; +} + template struct basicTestData { static inline void fill(typename PVT::svector& data) { data.resize(100); - for(typename PVT::value_type i=0; - (size_t)iviewUnsafe().unique()); + testOk1(hasUniqueVector(arr1)); arr2->assign(*arr1); testOk1(*arr1==*arr2); - testOk1(!arr1->viewUnsafe().unique()); + testOk1(!hasUniqueVector(arr1)); arr2->swap(data); arr2->postPut(); @@ -123,7 +131,7 @@ static void testBasic() arr1->PVScalarArray::putFrom(idata); - testOk1(castUnsafe(arr1->viewUnsafe()[1])==42); + testOk1(castUnsafe(arr1->view()[1])==42); } static void testShare() From bc3187a3f6779c622ea0199639c5870484d7fca2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 3 Jun 2013 15:04:38 -0400 Subject: [PATCH 051/103] optimize shared_vector for storing non-POD types pass values by reference where appropriate. When reallocating arrays of shared_ptr "move" with swap() instead of operator= to avoid ref counter inc and dec for each element. --- pvDataApp/misc/sharedVector.h | 42 +++++++++++++++++++++++++------ testApp/misc/testSharedVector.cpp | 37 ++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 9d9cc5e..611b3c9 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -36,6 +36,31 @@ namespace detail { template struct decorate_const { typedef const T type; }; template struct decorate_const { typedef const T type; }; + // How values should be passed as arguments to shared_vector methods + // really should use boost::call_traits + template struct call_with { typedef T type; }; + template struct call_with > + { typedef const std::tr1::shared_ptr& type; }; + template<> struct call_with { typedef const std::string& type; }; + + // For lack of C++11's std::move do our own special handling of shared_ptr + template + struct moveme { + template + static void op(const arg& a, const arg& b, const arg& c) + {std::copy(a,b,c);} + }; + template + struct moveme > { + template + static void op(arg a, arg b, arg c) + { + // "move" with swap to avoid ref counter operations + for(;a!=b;a++,c++) + c->swap(*a); + } + }; + /* All the parts of shared_vector which * don't need special handling for E=void */ @@ -194,6 +219,7 @@ template class shared_vector : public detail::shared_vector_base { typedef detail::shared_vector_base base_t; + typedef typename detail::call_with::type param_type; public: typedef E value_type; typedef E& reference; @@ -222,7 +248,7 @@ public: {} //! @brief Allocate (with new[]) a new vector of size c and fill with value e - shared_vector(size_t c, E e) + shared_vector(size_t c, param_type e) :base_t(new E[c], 0, c) { std::fill_n(this->m_data.get(), this->m_count, e); @@ -277,8 +303,8 @@ public: return; pointer temp=new E[i]; try{ - std::copy(begin(), end(), temp); - this->m_data.reset(temp, detail::default_array_deleter()); + detail::moveme::op(begin(), end(), temp); + this->m_data.reset(temp, detail::default_array_deleter()); }catch(...){ delete[] temp; throw; @@ -314,10 +340,10 @@ public: try{ // Copy as much as possible from old, // remaining elements are uninitialized. - std::copy(begin(), + detail::moveme::op(begin(), begin()+std::min(i,this->size()), temp); - this->m_data.reset(temp, detail::default_array_deleter()); + this->m_data.reset(temp, detail::default_array_deleter()); }catch(...){ delete[] temp; throw; @@ -331,7 +357,7 @@ public: * * see @ref resize(size_t) */ - void resize(size_t i, E v) { + void resize(size_t i, param_type v) { size_t oldsize=this->size(); resize(i); if(this->size()>oldsize) { @@ -360,7 +386,7 @@ public: if(this->unique()) return; shared_pointer_type d(new E[this->m_total], detail::default_array_deleter()); - std::copy(this->m_data.get()+this->m_offset, + detail::moveme::op(this->m_data.get()+this->m_offset, this->m_data.get()+this->m_offset+this->m_count, d.get()); this->m_data.swap(d); @@ -387,7 +413,7 @@ public: // Modifications - void push_back(const E& v) + void push_back(param_type v) { resize(this->size()+1); back() = v; diff --git a/testApp/misc/testSharedVector.cpp b/testApp/misc/testSharedVector.cpp index 71fd943..b36d5b6 100644 --- a/testApp/misc/testSharedVector.cpp +++ b/testApp/misc/testSharedVector.cpp @@ -160,12 +160,14 @@ static void testShare() one.make_unique(); + testOk1(one[1]==43); one[1] = 143; testOk1(two[1]==43); testOk1(three[1]==43); two.resize(two.size()); + testOk1(two[1]==43); two[1] = 243; testOk1(one[1]==143); testOk1(three[1]==43); @@ -177,11 +179,13 @@ static void testShare() one.resize(2); testOk1(one.size()==2); + testOk1(one[1]==143); testOk1(two.size()==15); testOk1(three.size()==15); two.resize(20, 5000); + testOk1(two[1]==243); testOk1(one.size()==2); testOk1(two.size()==20); testOk1(three.size()==15); @@ -335,9 +339,39 @@ static void testVoid() testOk1(typed.size()==2); } +struct dummyStruct {}; + +static void testNonPOD() +{ + testDiag("Test vector of non-POD types"); + + epics::pvData::shared_vector strings(6); + epics::pvData::shared_vector > structs(5); + + testOk1(strings[0].empty()); + testOk1(structs[0].get()==NULL); + + structs[1].reset(new dummyStruct); + dummyStruct *temp = structs[1].get(); + + epics::pvData::shared_vector > structs2(structs); + + testOk1(!structs.unique()); + testOk1(structs[1].unique()); + + testOk1(structs2[1].get()==temp); + + structs2.make_unique(); + + testOk1(structs.unique()); + testOk1(!structs[1].unique()); + + testOk1(structs2[1].get()==temp); +} + MAIN(testSharedVector) { - testPlan(101); + testPlan(113); testDiag("Tests for shared_vector"); testDiag("sizeof(shared_vector)=%lu", @@ -351,5 +385,6 @@ MAIN(testSharedVector) testConst(); testSlice(); testVoid(); + testNonPOD(); return testDone(); } From ac53153bea30911ca4dd364bb89d61a87ef984fe Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 5 Jun 2013 16:14:52 -0400 Subject: [PATCH 052/103] shared_vector: test reference and const_reference Ensure that these typedefs are present and work for 'T' and 'const T'. --- testApp/misc/testSharedVector.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/testApp/misc/testSharedVector.cpp b/testApp/misc/testSharedVector.cpp index b36d5b6..6610b41 100644 --- a/testApp/misc/testSharedVector.cpp +++ b/testApp/misc/testSharedVector.cpp @@ -199,9 +199,19 @@ static void testConst() epics::pvData::shared_vector writable(15, 100); + epics::pvData::shared_vector::reference wr = writable[0]; + epics::pvData::shared_vector::const_reference ror = writable[0]; + + testOk1(wr==ror); + // can re-target container, but data is R/O epics::pvData::shared_vector rodata(writable); + epics::pvData::shared_vector::reference wcr = rodata[0]; + epics::pvData::shared_vector::const_reference rocr = rodata[0]; + + testOk1(wcr==rocr); + // Data is R/W, but container can't be re-targeted const epics::pvData::shared_vector roref(writable); @@ -371,7 +381,7 @@ static void testNonPOD() MAIN(testSharedVector) { - testPlan(113); + testPlan(115); testDiag("Tests for shared_vector"); testDiag("sizeof(shared_vector)=%lu", From 0b89f08d0908099cfce15fc393b4e724ef38851b Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 10 Jun 2013 12:07:27 -0400 Subject: [PATCH 053/103] explicit copy and assignment for shared_vector Add explicit copy constructor and assignment operator for shared_vector. --- pvDataApp/misc/sharedVector.h | 23 ++++++++++++++++++++++- testApp/misc/testSharedVector.cpp | 5 ++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 611b3c9..3aee3db 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -113,6 +113,11 @@ namespace detail { :m_data(d,b), m_offset(o), m_count(c), m_total(c) {_null_input();} + shared_vector_base(const shared_vector_base& O) + :m_data(O.m_data), m_offset(O.m_offset) + ,m_count(O.m_count), m_total(O.m_total) + {} + template shared_vector_base(const shared_vector_base& o) : m_data(vector_implicit_cast::cast(o.m_data)) @@ -131,6 +136,19 @@ namespace detail { return *this; } + //! @brief Copy an existing vector of a related type + template + shared_vector_base& operator=(const shared_vector_base& o) + { + if(&o!=this) { + m_data=vector_implicit_cast::cast(o.m_data); + m_offset=o.m_offset; + m_count=o.m_count; + m_total=o.m_total; + } + return *this; + } + //! @brief Swap the contents of this vector with another void swap(shared_vector_base& o) { if(&o!=this) { @@ -284,7 +302,10 @@ public: shared_vector(A d, B b, size_t o, size_t c) :base_t(d,b,o,c) {} - //! @brief Copy an existing vector of same or related type + //! @brief Copy an existing vector of same type + shared_vector(const shared_vector& o) :base_t(o) {} + + //! @brief Copy an existing vector of a related type template shared_vector(const shared_vector& o) :base_t(o) {} diff --git a/testApp/misc/testSharedVector.cpp b/testApp/misc/testSharedVector.cpp index 6610b41..638c562 100644 --- a/testApp/misc/testSharedVector.cpp +++ b/testApp/misc/testSharedVector.cpp @@ -212,6 +212,9 @@ static void testConst() testOk1(wcr==rocr); + rodata = writable; + testOk1(rodata.data()==writable.data()); + // Data is R/W, but container can't be re-targeted const epics::pvData::shared_vector roref(writable); @@ -381,7 +384,7 @@ static void testNonPOD() MAIN(testSharedVector) { - testPlan(115); + testPlan(116); testDiag("Tests for shared_vector"); testDiag("sizeof(shared_vector)=%lu", From b63c3da5651a19520447634c3a3626f4e2a5295c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 10 Jun 2013 12:08:59 -0400 Subject: [PATCH 054/103] add const_pointer to shared_vector --- pvDataApp/misc/sharedVector.h | 1 + 1 file changed, 1 insertion(+) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 3aee3db..895e325 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -243,6 +243,7 @@ public: typedef E& reference; typedef typename detail::decorate_const::type& const_reference; typedef E* pointer; + typedef typename detail::decorate_const::type* const_pointer; typedef E* iterator; typedef std::reverse_iterator reverse_iterator; typedef typename detail::decorate_const::type* const_iterator; From be4738f59c342879bd819966afa9248ac23cd69c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 10 Jun 2013 14:48:59 -0400 Subject: [PATCH 055/103] remove weak_vector It seems that shared_ptr::use_count() does not include weak_ptr instances. Therefore shared_ptr::use_count()==1 (aka unique()) does *not* ensure exclusive ownership! This breaks the assumption used by shared_vector::make_unique() to avoid allocating a new array in some cases. --- pvDataApp/misc/sharedVector.h | 54 ++++--------------------------- testApp/misc/testSharedVector.cpp | 28 +++++++++++++++- 2 files changed, 34 insertions(+), 48 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 895e325..9bb50a2 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -232,6 +232,13 @@ namespace detail { * std::vector are outlined in @ref vectordiff . * * Also see @ref vectormem + * + * @warning Due to the implementation of std::tr1::shared_ptr, use of + * shared_vector should not be combined with use of weak_ptr. + * shared_ptr::unique() and shared_ptr::use_count() do @b not + * include weak_ptr instances. This breaks the assumption made + * by make_unique() that unique()==true implies exclusive + * ownership. */ template class shared_vector : public detail::shared_vector_base @@ -527,53 +534,6 @@ public: } }; -template -class weak_vector { - std::tr1::weak_ptr m_data; - //! Offset in the data array of first element - size_t m_offset; - //! Number of elements between m_offset and end of data - size_t m_count; - -public: - typedef E element_type; - - weak_vector() - :m_data() - ,m_offset(0) - ,m_count(0) - {} - weak_vector(const weak_vector& o) - :m_data(o.m_data) - ,m_offset(o.m_offset) - ,m_count(o.m_count) - {} - weak_vector(const shared_vector& o) - :m_data(o.dataPtr()) - ,m_offset(o.dataOffset()) - ,m_count(o.dataCount()) - {} - - bool expired() const{return m_data.expired();} - shared_vector lock() const - { - return shared_vector(m_data.lock(), m_offset, m_count); - } - - void reset() - { - m_data.reset(); - m_offset = m_count = 0; - } - - void swap(weak_vector& o) - { - m_data.swap(o); - std::swap(m_offset, o.m_offset); - std::swap(m_count, o.m_count); - } -}; - namespace detail { template struct shared_vector_caster {}; diff --git a/testApp/misc/testSharedVector.cpp b/testApp/misc/testSharedVector.cpp index 638c562..685b8f9 100644 --- a/testApp/misc/testSharedVector.cpp +++ b/testApp/misc/testSharedVector.cpp @@ -382,9 +382,34 @@ static void testNonPOD() testOk1(structs2[1].get()==temp); } +static void testWeak() +{ + testDiag("Test weak_ptr counting"); + + epics::pvData::shared_vector data(6); + + testOk1(data.unique()); + + std::tr1::shared_ptr pdata(data.dataPtr()); + + testOk1(!data.unique()); + + pdata.reset(); + + testOk1(data.unique()); + + std::tr1::weak_ptr wdata(data.dataPtr()); + + testOk1(data.unique()); // True, but I wish it wasn't!!! + + pdata = wdata.lock(); + + testOk1(!data.unique()); +} + MAIN(testSharedVector) { - testPlan(116); + testPlan(121); testDiag("Tests for shared_vector"); testDiag("sizeof(shared_vector)=%lu", @@ -399,5 +424,6 @@ MAIN(testSharedVector) testSlice(); testVoid(); testNonPOD(); + testWeak(); return testDone(); } From a4cfab12426a273bc1a5665823bef2e95ad3cea4 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 11 Jun 2013 14:31:33 -0400 Subject: [PATCH 056/103] Fix "optimize shared_vector for storing non-POD types" Can't move references when the source array is still referenced by other shared_vectors --- pvDataApp/misc/sharedVector.h | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 9bb50a2..0a3cdc8 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -43,24 +43,6 @@ namespace detail { { typedef const std::tr1::shared_ptr& type; }; template<> struct call_with { typedef const std::string& type; }; - // For lack of C++11's std::move do our own special handling of shared_ptr - template - struct moveme { - template - static void op(const arg& a, const arg& b, const arg& c) - {std::copy(a,b,c);} - }; - template - struct moveme > { - template - static void op(arg a, arg b, arg c) - { - // "move" with swap to avoid ref counter operations - for(;a!=b;a++,c++) - c->swap(*a); - } - }; - /* All the parts of shared_vector which * don't need special handling for E=void */ @@ -332,8 +314,8 @@ public: return; pointer temp=new E[i]; try{ - detail::moveme::op(begin(), end(), temp); - this->m_data.reset(temp, detail::default_array_deleter()); + std::copy(begin(), end(), temp); + this->m_data.reset(temp, detail::default_array_deleter()); }catch(...){ delete[] temp; throw; @@ -369,7 +351,7 @@ public: try{ // Copy as much as possible from old, // remaining elements are uninitialized. - detail::moveme::op(begin(), + std::copy(begin(), begin()+std::min(i,this->size()), temp); this->m_data.reset(temp, detail::default_array_deleter()); @@ -415,7 +397,7 @@ public: if(this->unique()) return; shared_pointer_type d(new E[this->m_total], detail::default_array_deleter()); - detail::moveme::op(this->m_data.get()+this->m_offset, + std::copy(this->m_data.get()+this->m_offset, this->m_data.get()+this->m_offset+this->m_count, d.get()); this->m_data.swap(d); From 11e2ee19ea837922b665be6b0bea45874a511009 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 11 Jun 2013 14:11:53 -0400 Subject: [PATCH 057/103] Fix Printer for structure arrays Not handling NULL elements correctly. --- pvDataApp/factory/printer.cpp | 23 +++++++++++++++++++---- pvDataApp/pv/printer.h | 2 ++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/pvDataApp/factory/printer.cpp b/pvDataApp/factory/printer.cpp index 20dde9d..1776a1d 100644 --- a/pvDataApp/factory/printer.cpp +++ b/pvDataApp/factory/printer.cpp @@ -48,8 +48,12 @@ void PrinterBase::encodeScalar(const PVScalar& pv) {} void PrinterBase::encodeArray(const PVScalarArray&) {} +void PrinterBase::encodeNull() {} + void PrinterBase::impl_print(const PVField& pv) { + static const PVField* marker = (const PVField*)▮ + /* Depth first recursive iteration. * Each PV to be printed is appended to the todo queue. * The last child of a structure is followed by a NULL. @@ -64,7 +68,7 @@ void PrinterBase::impl_print(const PVField& pv) const PVField *next = todo.front(); todo.pop_front(); - if(!next) { + if(next==marker) { // finished with a structure or structarray, // now we fall back to its parent. assert(!inprog.empty()); @@ -86,6 +90,12 @@ void PrinterBase::impl_print(const PVField& pv) } else { // real field + if(!next) { + // NULL entry in a structure array + encodeNull(); + continue; + } + switch(next->getField()->getType()) { case scalar: encodeScalar(*static_cast(next)); @@ -103,7 +113,7 @@ void PrinterBase::impl_print(const PVField& pv) for(size_t i=0, nfld=fld.getStructure()->getNumberFields(); igetID() << " " - << pv.getFieldName() << " "; + << pv.getFieldName() << "[] "; ilvl++; } @@ -179,5 +189,10 @@ void PrinterPlain::encodeArray(const PVScalarArray& pv) S() << "]" << std::endl; } +void PrinterPlain::encodeNull() +{ + indentN(S(), ilvl); + S() << "NULL" << std::endl; +} }} diff --git a/pvDataApp/pv/printer.h b/pvDataApp/pv/printer.h index 115b052..b9b60df 100644 --- a/pvDataApp/pv/printer.h +++ b/pvDataApp/pv/printer.h @@ -27,6 +27,7 @@ protected: virtual void encodeScalar(const PVScalar&); virtual void encodeArray(const PVScalarArray&); + virtual void encodeNull(); inline std::ostream& S() { return *strm; } @@ -47,6 +48,7 @@ protected: virtual void encodeScalar(const PVScalar&); virtual void encodeArray(const PVScalarArray&); + virtual void encodeNull(); public: PrinterPlain(); From 70c9a7c18f4d419b57dbf6b75fea322ea7fd9fdd Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 11 Jun 2013 10:04:14 -0400 Subject: [PATCH 058/103] simplify shared_vector ctors Casting will be done through the copy constructor. --- pvDataApp/misc/sharedVector.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 0a3cdc8..fb6cd99 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -84,8 +84,7 @@ namespace detail { ,m_offset(o), m_count(c), m_total(c) {_null_input();} - template - shared_vector_base(const std::tr1::shared_ptr& d, size_t o, size_t c) + shared_vector_base(const std::tr1::shared_ptr& d, size_t o, size_t c) :m_data(d), m_offset(o), m_count(c), m_total(c) {_null_input();} From 4e749cc8beadbd32faec9206559f3aa2bcef10d9 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 11 Jun 2013 17:40:59 -0400 Subject: [PATCH 059/103] Improve shared_vector::push_back push_back now allocates additional space in powers of 2 up to 1k elements, then in blocks of 1k elements. --- pvDataApp/misc/sharedVector.h | 29 ++++++++++++++++++++++++++++- testApp/misc/testSharedVector.cpp | 28 +++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index fb6cd99..8e64f39 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -6,6 +6,8 @@ #include #include +#include + #include "pv/sharedPtr.h" namespace epics { namespace pvData { @@ -423,9 +425,34 @@ public: // Modifications +private: + void _push_resize() { + if(this->m_count==this->m_total || !this->unique()) { + size_t next; + if(this->m_total<1024) { + // round m_total+1 up to the next power of 2 + next = this->m_total; + next |= next >> 1; + next |= next >> 2; + next |= next >> 4; + next |= next >> 8; + next++; + } else { + // pad m_total up to the next multiple of 1024 + next = this->m_total+1024; + next &= ~0x3ff; + } + assert(next > this->m_total); + reserve(next); + } + resize(this->size()+1); + } + +public: + void push_back(param_type v) { - resize(this->size()+1); + _push_resize(); back() = v; } diff --git a/testApp/misc/testSharedVector.cpp b/testApp/misc/testSharedVector.cpp index 685b8f9..8895124 100644 --- a/testApp/misc/testSharedVector.cpp +++ b/testApp/misc/testSharedVector.cpp @@ -329,6 +329,31 @@ static void testCapacity() testOk1(vect[1]==124); } +static void testPush() +{ + epics::pvData::shared_vector vect; + + testDiag("Test push_back optimizations"); + + size_t nallocs = 0; + size_t cap = vect.capacity(); + + for(size_t s=0; s<16*1024; s++) { + vect.push_back(s); + + if(cap!=vect.capacity()) { + nallocs++; + cap = vect.capacity(); + } + } + + testDiag("push_back %ld times caused %ld re-allocations", + (unsigned long)vect.size(), + (unsigned long)nallocs); + + testOk1(nallocs==26); +} + static void testVoid() { testDiag("Test vecter cast to/from void"); @@ -409,7 +434,7 @@ static void testWeak() MAIN(testSharedVector) { - testPlan(121); + testPlan(122); testDiag("Tests for shared_vector"); testDiag("sizeof(shared_vector)=%lu", @@ -422,6 +447,7 @@ MAIN(testSharedVector) testShare(); testConst(); testSlice(); + testPush(); testVoid(); testNonPOD(); testWeak(); From 7f9745c8d105df76e834cfdd7098d662cb63c0c4 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 10 Jun 2013 18:47:55 -0400 Subject: [PATCH 060/103] Implement PVStructureArray with shared_vector Combine as much as possible with scalar array handling. PVStructureArray becomes PVValueArray > Bulk of shared implementation moved the PVVectorStorage which has a parametrized base to avoid using multiple inheritance. --- pvDataApp/factory/Convert.cpp | 13 +- pvDataApp/factory/PVArray.cpp | 61 +-- pvDataApp/factory/PVDataCreateFactory.cpp | 8 +- pvDataApp/factory/PVStructureArray.cpp | 249 ++++------ pvDataApp/pv/pvData.h | 523 +++++++++++----------- 5 files changed, 374 insertions(+), 480 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index 35763ac..dc29861 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -382,12 +382,15 @@ bool Convert::isCopyStructureArrayCompatible( void Convert::copyStructureArray( PVStructureArrayPtr const & from, PVStructureArrayPtr const & to) { - if(to->isImmutable()) { - if(from==to) return; - String message("Convert.copyStructureArray destination is immutable"); - throw std::invalid_argument(message); + if(from==to) { + return; + } else if(to->isImmutable()) { + throw std::invalid_argument("Convert.copyStructureArray destination is immutable"); } - to->put(0,from->getLength(),from->getVector(),0); + PVStructureArray::svector data; + from->swap(data); + to->replace(data); + from->swap(data); } void Convert::newLine(StringBuilder buffer, int indentLevel) diff --git a/pvDataApp/factory/PVArray.cpp b/pvDataApp/factory/PVArray.cpp index 89dd863..19e3b88 100644 --- a/pvDataApp/factory/PVArray.cpp +++ b/pvDataApp/factory/PVArray.cpp @@ -19,83 +19,32 @@ using std::size_t; namespace epics { namespace pvData { -class PVArrayPvt { -public: - PVArrayPvt() : length(0),capacity(0),capacityMutable(true) - {} - size_t length; - size_t capacity; - bool capacityMutable; -}; - PVArray::PVArray(FieldConstPtr const & field) -: PVField(field),pImpl(new PVArrayPvt()) +: PVField(field),capacityMutable(true) { } -PVArray::~PVArray() -{ - delete pImpl; -} - void PVArray::setImmutable() { - pImpl->capacityMutable = false; + capacityMutable = false; PVField::setImmutable(); } - size_t PVArray::getLength() const {return pImpl->length;} - - size_t PVArray::getCapacity() const {return pImpl->capacity;} - - static String fieldImmutable("field is immutable"); - - void PVArray::setLength(size_t length) { - if(length==pImpl->length) return; - if(PVField::isImmutable()) { - PVField::message(fieldImmutable,errorMessage); - return; - } - if(length>pImpl->capacity) this->setCapacity(length); - if(length>pImpl->capacity) length = pImpl->capacity; - pImpl->length = length; - } - - void PVArray::setCapacityLength(size_t capacity,size_t length) { - pImpl->capacity = capacity; - pImpl->length = length; - } - - bool PVArray::isCapacityMutable() const { if(PVField::isImmutable()) { return false; } - return pImpl->capacityMutable; + return capacityMutable; } void PVArray::setCapacityMutable(bool isMutable) { if(isMutable && PVField::isImmutable()) { - PVField::message(fieldImmutable,errorMessage); - return; + throw std::runtime_error("field is immutable"); } - pImpl->capacityMutable = isMutable; + capacityMutable = isMutable; } - static String capacityImmutable("capacity is immutable"); - - void PVArray::setCapacity(size_t capacity) { - if(PVField::isImmutable()) { - PVField::message(fieldImmutable,errorMessage); - return; - } - if(pImpl->capacityMutable==false) { - PVField::message(capacityImmutable,errorMessage); - return; - } - pImpl->capacity = capacity; - } std::ostream& operator<<(format::array_at_internal const& manip, const PVArray& array) { diff --git a/pvDataApp/factory/PVDataCreateFactory.cpp b/pvDataApp/factory/PVDataCreateFactory.cpp index e169596..7c20509 100644 --- a/pvDataApp/factory/PVDataCreateFactory.cpp +++ b/pvDataApp/factory/PVDataCreateFactory.cpp @@ -231,9 +231,8 @@ DefaultPVArray::~DefaultPVArray() template void DefaultPVArray::setCapacity(size_t capacity) { - if(this->isCapacityMutable() && capacity>value.capacity()) { + if(this->isCapacityMutable()) { value.reserve(capacity); - PVArray::setCapacityLength(value.capacity(), value.size()); } } @@ -248,7 +247,6 @@ void DefaultPVArray::setLength(size_t length) value.slice(0, length); else value.resize(length); - PVArray::setCapacityLength(value.capacity(), value.size()); } @@ -265,7 +263,6 @@ void DefaultPVArray::swap(svector &other) THROW_EXCEPTION2(std::logic_error,"Immutable"); value.swap(other); - PVArray::setCapacityLength(value.capacity(), value.size()); } @@ -282,7 +279,6 @@ void DefaultPVArray::deserialize(ByteBuffer *pbuffer, value.resize(size); // TODO: avoid copy of stuff we will then overwrite - PVArray::setCapacityLength(value.capacity(), value.size()); T* cur = value.data(); // try to avoid deserializing from the buffer @@ -379,8 +375,6 @@ void DefaultPVArray::deserialize(ByteBuffer *pbuffer, else if(size < value.size()) value.slice(0, size); - setCapacityLength(size, size); - String * pvalue = value.data(); for(size_t i = 0; i(new PVStructurePtrArray())) -{ -} - size_t PVStructureArray::append(size_t number) { - size_t currentLength = getLength(); - size_t newLength = currentLength + number; - setCapacity(newLength); - setLength(newLength); + svector data; + swap(data); + data.resize(data.size()+number); + StructureConstPtr structure = structureArray->getStructure(); - PVStructurePtrArray *to = value.get(); - for(size_t i=currentLength; icreatePVStructure(structure); - } + + for(svector::reverse_iterator it = data.rbegin(); number; ++it, --number) + *it = getPVDataCreate()->createPVStructure(structure); + + size_t newLength = data.size(); + + swap(data); + return newLength; } bool PVStructureArray::remove(size_t offset,size_t number) { - size_t length = getLength(); - if(offset+number>length) return false; - PVStructurePtrArray vec = *value.get(); + if(number==0) + return true; + else if(offset+number>getLength()) + return false; + + svector vec(reuse()); + + size_t length = vec.size(); + for(size_t i = offset; i+number < length; i++) { - vec[i] = vec[i + number]; + vec[i].swap(vec[i + number]); } - size_t newLength = length - number; - setCapacityLength(newLength,newLength); + + vec.resize(length - number); + swap(vec); + return true; } void PVStructureArray::compress() { - size_t length = getCapacity(); + svector vec(reuse()); // TODO: check for first NULL before realloc + + size_t length = vec.size(); size_t newLength = 0; - PVStructurePtrArray vec = *value.get(); + for(size_t i=0; iisCapacityMutable()) { + svector value; + swap(value); + value.reserve(capacity); + swap(value); } - size_t length = getLength(); - if(length>capacity) length = capacity; - size_t oldCapacity = getCapacity(); - if(oldCapacity>capacity) { - PVStructurePtrArray array; - array.reserve(capacity); - array.resize(length); - PVStructurePtr * from = get(); - for (size_t i=0; iswap(array); +} + +void PVStructureArray::setLength(size_t length) +{ + if(this->isImmutable()) + THROW_EXCEPTION2(std::logic_error,"Immutable"); + svector value; + swap(value); + if(length == value.size()) { + // nothing + } else if(length < value.size()) { + value.slice(0, length); } else { - value->reserve(capacity); + value.resize(length); } - setCapacityLength(capacity,length); + swap(value); } -void PVStructureArray::setLength(size_t length) { - if(PVArray::getLength()==length) return; - size_t capacity = PVArray::getCapacity(); - if(length>capacity) { - if(!PVArray::isCapacityMutable()) { - std::string message("not capacityMutable"); - PVField::message(message, errorMessage); - return; - } - setCapacity(length); - } - value->resize(length); - PVArray::setCapacityLength(capacity,length); -} - -StructureArrayConstPtr PVStructureArray::getStructureArray() const +void PVStructureArray::swap(svector &other) { - return structureArray; -} + if(this->isImmutable()) + THROW_EXCEPTION2(std::logic_error,"Immutable"); -size_t PVStructureArray::get( - size_t offset, size_t len, StructureArrayData &data) -{ - size_t n = len; - size_t length = getLength(); - if(offset+len > length) { - n = length - offset; - //if(n<0) n = 0; - } - data.data = *value.get(); - data.offset = offset; - return n; -} - -size_t PVStructureArray::put(size_t offset,size_t len, - const_vector const & from, size_t fromOffset) -{ - if(isImmutable()) { - message(String("field is immutable"), errorMessage); - return 0; - } - if(&from==value.get()) return 0; - if(len<1) return 0; - size_t length = getLength(); - size_t capacity = getCapacity(); - if(offset+len > length) { - size_t newlength = offset + len; - if(newlength>capacity) { - setCapacity(newlength); - capacity = getCapacity(); - newlength = capacity; - len = newlength - offset; - if(len<=0) return 0; - } - length = newlength; - setLength(length); - } - PVStructurePtrArray *to = value.get(); - StructureConstPtr structure = structureArray->getStructure(); - for(size_t i=0; igetStructure()!=structure) { - throw std::invalid_argument(String( - "Element is not a compatible structure")); - } - } - (*to)[i+offset] = frompv; - } - setLength(length); - postPut(); - return len; -} - -void PVStructureArray::shareData( - std::tr1::shared_ptr > const & sharedValue, - std::size_t capacity, - std::size_t length) -{ - value = sharedValue; - setCapacityLength(capacity,length); + value.swap(other); } void PVStructureArray::serialize(ByteBuffer *pbuffer, @@ -196,56 +133,48 @@ void PVStructureArray::serialize(ByteBuffer *pbuffer, void PVStructureArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { + svector data; + swap(data); + size_t size = SerializeHelper::readSize(pbuffer, pcontrol); - //if(size>=0) { - // prepare array, if necessary - if(size>getCapacity()) setCapacity(size); - setLength(size); - PVStructurePtrArray *pvArray = value.get(); - for(size_t i = 0; iensureData(1); - size_t temp = pbuffer->getByte(); - if(temp==0) { - (*pvArray)[i].reset(); - } - else { - if((*pvArray)[i].get()==NULL) { - StructureConstPtr structure = structureArray->getStructure(); - (*pvArray)[i] = getPVDataCreate()->createPVStructure(structure); - } - (*pvArray)[i]->deserialize(pbuffer, pcontrol); - } + data.resize(size); + + StructureConstPtr structure = structureArray->getStructure(); + + for(size_t i = 0; iensureData(1); + size_t temp = pbuffer->getByte(); + if(temp==0) { + data[i].reset(); } - postPut(); - //} + else { + if(data[i].get()==NULL) { + data[i] = getPVDataCreate()->createPVStructure(structure); + } + data[i]->deserialize(pbuffer, pcontrol); + } + } + replace(data); // calls postPut() } void PVStructureArray::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, size_t offset, size_t count) const { - // cache - size_t length = getLength(); - // check bounds - /*if(offset<0) - offset = 0; - else*/ if(offset>length) offset = length; - //if(count<0) count = length; + const_svector temp(view()); + temp.slice(offset, count); - size_t maxCount = length-offset; - if(count>maxCount) count = maxCount; + SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); - PVStructurePtrArray pvArray = *value.get(); - // write - SerializeHelper::writeSize(count, pbuffer, pflusher); for(size_t i = 0; igetRemaining()<1) pflusher->flushSerializeBuffer(); - PVStructurePtr pvStructure = pvArray[i+offset]; - if(pvStructure.get()==NULL) { + if(pbuffer->getRemaining()<1) + pflusher->flushSerializeBuffer(); + + if(temp[i].get()==NULL) { pbuffer->putByte(0); } else { pbuffer->putByte(1); - pvStructure->serialize(pbuffer, pflusher); + temp[i]->serialize(pbuffer, pflusher); } } } @@ -267,9 +196,9 @@ std::ostream& PVStructureArray::dumpValue(std::ostream& o) const std::ostream& PVStructureArray::dumpValue(std::ostream& o, std::size_t index) const { - PVStructurePtrArray pvArray = *value.get(); - PVStructurePtr pvStructure = pvArray[index]; - return o << *(pvStructure.get()); + const_svector temp(view()); + if(index class PVValueArray; + /** * typedef for a pointer to a PVAuxInfo. @@ -149,6 +151,8 @@ typedef std::vector::const_iterator PVStructurePtrArray_const__i /** * typedef for a pointer to a PVStructureArray. */ + +typedef PVValueArray PVStructureArray; typedef std::tr1::shared_ptr PVStructureArrayPtr; typedef std::vector PVStructureArrayPtrArray; typedef std::tr1::shared_ptr PVStructureArrayPtrArrayPtr; @@ -574,7 +578,7 @@ public: /** * Destructor */ - virtual ~PVArray(); + virtual ~PVArray(){}; /** * Set the field to be immutable, i. e. it can no longer be modified. * This is permanent, i.e. once done the field can onot be made mutable. @@ -584,17 +588,17 @@ public: * Get the array length. * @return The length. */ - std::size_t getLength() const; + virtual std::size_t getLength() const = 0; /** * Set the array length. * @param The length. */ - virtual void setLength(std::size_t length); + virtual void setLength(std::size_t length) = 0; /** * Get the array capacity. * @return The capacity. */ - std::size_t getCapacity() const; + virtual std::size_t getCapacity() const = 0; /** * Can the capacity be changed. * @return (false,true) if (can not, can) be changed. @@ -615,9 +619,8 @@ public: protected: PVArray(FieldConstPtr const & field); - void setCapacityLength(std::size_t capacity,std::size_t length); private: - class PVArrayPvt * pImpl; + bool capacityMutable; friend class PVDataCreate; }; @@ -748,113 +751,6 @@ private: friend class PVDataCreate; }; -/** - * This is provided by code that calls get. - */ -typedef PVArrayData StructureArrayData; - -/** - * Data class for a structureArray - */ -class PVStructureArray : public PVArray -{ -public: - POINTER_DEFINITIONS(PVStructureArray); - typedef PVStructurePtr value_type; - typedef PVStructurePtr* pointer; - typedef const PVStructurePtr* const_pointer; - typedef PVArrayData ArrayDataType; - typedef std::vector vector; - typedef const std::vector const_vector; - typedef std::tr1::shared_ptr shared_vector; - typedef PVStructureArray &reference; - typedef const PVStructureArray& const_reference; - /** - * Destructor - */ - virtual ~PVStructureArray() {} - /** - * Set the array capacity. - * @param capacity The length. - */ - virtual void setCapacity(size_t capacity); - /** - * Set the array length. - * @param length The length. - */ - virtual void setLength(std::size_t length); - /** - * Get the introspection interface - * @return The interface. - */ - virtual StructureArrayConstPtr getStructureArray() const ; - /** - * Append new elements to the end of the array. - * @param number The number of elements to add. - * @return the new length of the array. - */ - virtual std::size_t append(std::size_t number); - /** - * Remove elements from the array. - * @param offset The offset of the first element to remove. - * @param number The number of elements to remove. - * @return (false,true) if the elements were removed. - */ - virtual bool remove(std::size_t offset,std::size_t number); - /** - * Compress. This removes all null elements from the array. - */ - virtual void compress(); - /** - * Get array elements - * @param offset The offset of the first element, - * @param length The number of elements to get. - * @param data The place where the data is placed. - */ - virtual std::size_t get(std::size_t offset, std::size_t length, - StructureArrayData &data); - /** - * Put data into the array. - * @param offset The offset of the first element, - * @param length The number of elements to get. - * @param from The new values to put into the array. - * @param fromOffset The offset in from. - * @return The number of elements put into the array. - */ - virtual std::size_t put(std::size_t offset,std::size_t length, - const_vector const & from, std::size_t fromOffset); - /** - * Share data from another source. - * @param value The data to share. - * @param capacity The capacity of the array. - * @param length The length of the array. - */ - virtual void shareData( - shared_vector const & value, - std::size_t capacity, - std::size_t length); - virtual void serialize(ByteBuffer *pbuffer, - SerializableControl *pflusher) const; - virtual void deserialize(ByteBuffer *buffer, - DeserializableControl *pflusher); - virtual void serialize(ByteBuffer *pbuffer, - SerializableControl *pflusher, std::size_t offset, std::size_t count) const ; - virtual pointer get() { return &((*value.get())[0]); } - virtual pointer get() const { return &((*value.get())[0]); } - virtual vector const & getVector() {return *value;} - virtual shared_vector const & getSharedVector() {return value;} - - virtual std::ostream& dumpValue(std::ostream& o) const; - virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const; - -protected: - PVStructureArray(StructureArrayConstPtr const & structureArray); -private: - StructureArrayConstPtr structureArray; - shared_vector value; - friend class PVDataCreate; -}; - class PVStructure : public PVField, public BitSetSerializable { @@ -1094,10 +990,176 @@ namespace detail { :vec(v) {} void operator()(T*){vec.reset();} }; -} + + template + class PVVectorStorage : public Base + { + public: + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + + //TODO: full namespace can be removed along with local typedef 'shared_vector' + typedef ::epics::pvData::shared_vector svector; + typedef ::epics::pvData::shared_vector const_svector; + + // begin deprecated + typedef PVArrayData ArrayDataType; + typedef std::vector vector; + typedef const std::vector const_vector; + typedef std::tr1::shared_ptr shared_vector; + // end deprecated + + protected: + PVVectorStorage() : Base() {} + + template + PVVectorStorage(A a) : Base(a) {} + public: + virtual ~PVVectorStorage(){}; + + // Primative array manipulations + protected: + //! unchecked reference to writable data + //! Please consider the view() method instead of viewUnsafe(). + virtual const svector& viewUnsafe() const = 0; + public: + + /** Exchange our contents for the provided. + * + @throws std::logic_error for Immutable arrays. + * + * Callers must ensure that postPut() is called + * after the last swap() operation. + * + * Before you call this directly, consider using + * the take(), reuse(), or replace() methods. + */ + virtual void swap(svector& other) = 0; + + //! Discard current contents and replaced with the provided. + //! Fails for Immutable arrays + //! calls postPut() + virtual void replace(const svector& next) + { + svector temp(next); + this->swap(temp); + this->postPut(); + } + + // methods from PVArray + + virtual size_t getLength() const {return viewUnsafe().size();} + virtual size_t getCapacity() const {return viewUnsafe().capacity();} + + // Derived operations + + //! Fetch a read-only view of the current array data + inline const_svector view() const + { + const_svector newref(this->viewUnsafe()); + return newref; + } + + //! Remove and return the current array data + //! Does @b not (and should not) call postPut() + inline svector take() + { + svector result; + this->swap(result); + return result; + } + + //! take() with an implied make_unique() + //! Does @b not (and should not) call postPut() + inline svector reuse() + { + svector result; + this->swap(result); + result.make_unique(); + return result; + } + + /** + * Get array elements + * @param offset The offset of the first element, + * @param length The number of elements to get. + * @param data The place where the data is placed. + */ + std::size_t get( + std::size_t offset, std::size_t length, ArrayDataType &data) USAGE_DEPRECATED + { + const_svector ref = this->view(); + ref.slice(offset, length); + data.data.resize(ref.size()); + data.offset = 0; + std::copy(ref.begin(), ref.end(), data.data.begin()); + return ref.size(); + } + + /** + * Copy data into the array growing the length as needed. + * @param offset The offset of the first element, + * @param length The number of elements to get. + * @param from The new values to put into the array. + * @param fromOffset The offset in from. + * @return The number of elements put into the array. + * calls postPut() + */ + std::size_t put(std::size_t offset, + std::size_t length, const_pointer from, std::size_t fromOffset) USAGE_DEPRECATED + { + from += fromOffset; + + svector temp; + this->swap(temp); + if(temp.size() < length+offset) + temp.resize(length+offset); + else + temp.make_unique(); + + std::copy(from, from + length, temp.begin() + offset); + this->swap(temp); + this->postPut(); + return length; + } + + std::size_t put(std::size_t offset, + std::size_t length, const_vector &from, std::size_t fromOffset) USAGE_DEPRECATED + { return this->put(offset,length, &from[0], fromOffset); } + + /** + * Share data from another source. + * @param value The data to share. + * @param capacity The capacity of the array. + * @param length The length of the array. + * Does @b not call postPut() + */ + void shareData( + shared_vector const & value, + std::size_t capacity, + std::size_t length) USAGE_DEPRECATED + { + vector& vref = *value.get(); + typename svector::shared_pointer_type p(&vref[0], + detail::shared_ptr_vector_deletor(value)); + svector temp(p, 0, std::min(length, vref.size())); + this->swap(temp); + } + + pointer get() const { + return this->viewUnsafe().data(); + } + + vector const & getVector() USAGE_ERROR("No longer implemented. Replace with view()"); + shared_vector const & getSharedVector() USAGE_ERROR("No longer implemented. Replace with view()"); + + }; +} // namespace detail template -class PVValueArray : public PVScalarArray { +class PVValueArray : public detail::PVVectorStorage { + typedef detail::PVVectorStorage base_t; public: POINTER_DEFINITIONS(PVValueArray); typedef T value_type; @@ -1124,141 +1186,10 @@ public: */ virtual ~PVValueArray() {} - // Primative array manipulations -protected: - //! unchecked reference to writable data - //! Please consider the view() method instead of viewUnsafe(). - virtual const svector& viewUnsafe() const = 0; -public: - - /** Exchange our contents for the provided. - * - @throws std::logic_error for Immutable arrays. - * - * Callers must ensure that postPut() is called - * after the last swap() operation. - * - * Before you call this directly, consider using - * the take(), reuse(), or replace() methods. - */ - virtual void swap(svector& other) = 0; - - //! Discard current contents and replaced with the provided. - //! Fails for Immutable arrays - //! calls postPut() - virtual void replace(const svector& next) - { - svector temp(next); - this->swap(temp); - this->postPut(); - } - - // Derived operations - - //! Fetch a read-only view of the current array data - inline const_svector view() const - { - const_svector newref(this->viewUnsafe()); - return newref; - } - - //! Remove and return the current array data - //! Does @b not (and should not) call postPut() - inline svector take() - { - svector result; - this->swap(result); - return result; - } - - //! take() with an implied make_unique() - //! Does @b not (and should not) call postPut() - inline svector reuse() - { - svector result; - this->swap(result); - result.make_unique(); - return result; - } - - /** - * Get array elements - * @param offset The offset of the first element, - * @param length The number of elements to get. - * @param data The place where the data is placed. - */ - std::size_t get( - std::size_t offset, std::size_t length, ArrayDataType &data) USAGE_DEPRECATED - { - const_svector ref = this->view(); - ref.slice(offset, length); - data.data.resize(ref.size()); - data.offset = 0; - std::copy(ref.begin(), ref.end(), data.data.begin()); - return ref.size(); - } - - /** - * Copy data into the array growing the length as needed. - * @param offset The offset of the first element, - * @param length The number of elements to get. - * @param from The new values to put into the array. - * @param fromOffset The offset in from. - * @return The number of elements put into the array. - * calls postPut() - */ - std::size_t put(std::size_t offset, - std::size_t length, const_pointer from, std::size_t fromOffset) USAGE_DEPRECATED - { - from += fromOffset; - - svector temp; - this->swap(temp); - if(temp.size() < length+offset) - temp.resize(length+offset); - else - temp.make_unique(); - - std::copy(from, from + length, temp.begin() + offset); - this->swap(temp); - this->postPut(); - return length; - } - - std::size_t put(std::size_t offset, - std::size_t length, const_vector &from, std::size_t fromOffset) USAGE_DEPRECATED - { return this->put(offset,length, &from[0], fromOffset); } - - /** - * Share data from another source. - * @param value The data to share. - * @param capacity The capacity of the array. - * @param length The length of the array. - * Does @b not call postPut() - */ - void shareData( - shared_vector const & value, - std::size_t capacity, - std::size_t length) USAGE_DEPRECATED - { - vector& vref = *value.get(); - typename svector::shared_pointer_type p(&vref[0], - detail::shared_ptr_vector_deletor(value)); - svector temp(p, 0, std::min(length, vref.size())); - this->swap(temp); - } - - pointer get() const { - return this->viewUnsafe().data(); - } - - vector const & getVector() USAGE_ERROR("No longer implemented. Replace with view()"); - shared_vector const & getSharedVector() USAGE_ERROR("No longer implemented. Replace with view()"); - std::ostream& dumpValue(std::ostream& o) const { o << '['; - std::size_t len = getLength(); + std::size_t len = this->getLength(); bool first = true; for (std::size_t i = 0; i < len; i++) { @@ -1273,13 +1204,13 @@ public: std::ostream& dumpValue(std::ostream& o, size_t index) const { - return o << *(get() + index); + return o << *(this->get() + index); } virtual void getAs(ScalarType id, ::epics::pvData::shared_vector& out) const { - const svector& data(viewUnsafe()); + const svector& data(this->viewUnsafe()); ::epics::pvData::shared_vector temp(static_shared_vector_cast(data)); if(id==typeCode) { out = temp; // no convert = no copy @@ -1295,7 +1226,7 @@ public: virtual size_t copyOut(ScalarType id, void* ptr, size_t olen) const { - const svector& data(viewUnsafe()); + const svector& data(this->viewUnsafe()); size_t len = std::min(olen, data.size()); castUnsafeV(len, id, ptr, typeCode, (const void*)data.data()); @@ -1348,10 +1279,98 @@ public: protected: PVValueArray(ScalarArrayConstPtr const & scalar) - : PVScalarArray(scalar) {} + : base_t(scalar) {} friend class PVDataCreate; }; +/** + * This is provided by code that calls get. + */ +typedef PVArrayData StructureArrayData; + +/** + * Data class for a structureArray + */ +template<> +class PVValueArray : public detail::PVVectorStorage +{ + typedef detail::PVVectorStorage base_t; +public: + POINTER_DEFINITIONS(PVStructureArray); + typedef PVStructurePtr value_type; + typedef PVStructurePtr* pointer; + typedef const PVStructurePtr* const_pointer; + typedef PVArrayData ArrayDataType; + typedef std::vector vector; + typedef const std::vector const_vector; + typedef std::tr1::shared_ptr shared_vector; + typedef PVStructureArray &reference; + typedef const PVStructureArray& const_reference; + + //TODO: full namespace can be removed along with local typedef 'shared_vector' + typedef ::epics::pvData::shared_vector svector; + typedef ::epics::pvData::shared_vector const_svector; + /** + * Destructor + */ + virtual ~PVValueArray() {} + /** + * Set the array capacity. + * @param capacity The length. + */ + virtual void setCapacity(size_t capacity); + /** + * Set the array length. + * @param length The length. + */ + virtual void setLength(std::size_t length); + + /** + * Get the introspection interface + * @return The interface. + */ + StructureArrayConstPtr getStructureArray() const {return structureArray;} + /** + * Append new elements to the end of the array. + * @param number The number of elements to add. + * @return the new length of the array. + */ + virtual std::size_t append(std::size_t number); + /** + * Remove elements from the array. + * @param offset The offset of the first element to remove. + * @param number The number of elements to remove. + * @return (false,true) if the elements were removed. + */ + virtual bool remove(std::size_t offset,std::size_t number); + /** + * Compress. This removes all null elements from the array. + */ + virtual void compress(); + + virtual const svector& viewUnsafe() const { return value; } + virtual void swap(svector &other); + + virtual void serialize(ByteBuffer *pbuffer, + SerializableControl *pflusher) const; + virtual void deserialize(ByteBuffer *buffer, + DeserializableControl *pflusher); + virtual void serialize(ByteBuffer *pbuffer, + SerializableControl *pflusher, std::size_t offset, std::size_t count) const ; + + virtual std::ostream& dumpValue(std::ostream& o) const; + virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const; + +protected: + PVValueArray(StructureArrayConstPtr const & structureArray) + :base_t(structureArray) + ,structureArray(structureArray) + {} +private: + StructureArrayConstPtr structureArray; + svector value; + friend class PVDataCreate; +}; /** * Definitions for the various scalarArray types. From 8cb0b1a7d6e18a2867bd6ead28cc975f91f273f3 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 11 Jun 2013 10:59:32 -0400 Subject: [PATCH 061/103] use new PVStructureArray api --- pvDataApp/factory/Compare.cpp | 23 ++++++++++------------- testApp/pv/testOperators.cpp | 9 ++++----- testApp/pv/testStandardPVField.cpp | 9 ++++----- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/pvDataApp/factory/Compare.cpp b/pvDataApp/factory/Compare.cpp index 8237cc5..d47d533 100644 --- a/pvDataApp/factory/Compare.cpp +++ b/pvDataApp/factory/Compare.cpp @@ -188,26 +188,23 @@ bool compareField(const PVStructure* left, const PVStructure* right) bool compareField(const PVStructureArray* left, const PVStructureArray* right) { - if(left->getLength()!=right->getLength()) + if(*left->getStructureArray()->getStructure() + != *right->getStructureArray()->getStructure()) return false; - StructureConstPtr ls = left->getStructureArray()->getStructure(); + PVStructureArray::const_svector ld=left->view(), rd=right->view(); - if(*ls!=*right->getStructureArray()->getStructure()) + if(ld.size()!=rd.size()) return false; - const PVStructureArray::pointer ld=left->get(), rd=right->get(); + PVStructureArray::const_svector::const_iterator lit, lend, rit; - for(size_t i=0, ilen=left->getLength(); igetPVFields(); - const PVFieldPtrArray& rf = rd[i]->getPVFields(); - - for(size_t k=0, klen=ls->getNumberFields(); kscalar(pvDouble, "alarm,timeStamp"); pvStructure = standardPVField->structureArray(structure,"alarm,timeStamp"); size_t num = 2; - PVStructurePtrArray pvStructures; - pvStructures.reserve(num); + PVStructureArray::svector pvStructures(num); for(size_t i=0; icreatePVStructure(structure)); + pvStructures[i]= + pvDataCreate->createPVStructure(structure); } PVStructureArrayPtr pvStructureArray = pvStructure->getStructureArrayField("value"); - pvStructureArray->put(0, num, pvStructures, 0); + pvStructureArray->replace(pvStructures); std::cout << *pvStructure << std::endl; return 0; diff --git a/testApp/pv/testStandardPVField.cpp b/testApp/pv/testStandardPVField.cpp index 7c19ccd..238ba82 100644 --- a/testApp/pv/testStandardPVField.cpp +++ b/testApp/pv/testStandardPVField.cpp @@ -70,14 +70,13 @@ int main(int, char **) StructureConstPtr structure = standardField->scalar(pvDouble, "alarm,timeStamp"); pvStructure = standardPVField->structureArray(structure,"alarm,timeStamp"); size_t num = 2; - PVStructurePtrArray pvStructures; - pvStructures.reserve(num); + PVStructureArray::svector pvStructures(num); for(size_t i=0; icreatePVStructure(structure)); + pvStructures[i]= + pvDataCreate->createPVStructure(structure); } PVStructureArrayPtr pvStructureArray = pvStructure->getStructureArrayField("value"); - pvStructureArray->put(0, num, pvStructures, 0); + pvStructureArray->replace(pvStructures); builder.clear(); pvStructure->toString(&builder); print("structureArrayTest"); From b0c8249562708d0811a7ff316fec319164046d6a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 11 Jun 2013 10:40:14 -0400 Subject: [PATCH 062/103] re-write testPVStructureArray --- testApp/pv/Makefile | 1 + testApp/pv/testPVStructureArray.cpp | 201 ++++++++++++++++------------ 2 files changed, 118 insertions(+), 84 deletions(-) diff --git a/testApp/pv/Makefile b/testApp/pv/Makefile index a6ab274..3d687aa 100644 --- a/testApp/pv/Makefile +++ b/testApp/pv/Makefile @@ -43,6 +43,7 @@ TESTS += testPVScalarArray PROD_HOST += testPVStructureArray testPVStructureArray_SRCS += testPVStructureArray.cpp testPVStructureArray_LIBS += pvData Com +TESTS += testPVStructureArray PROD_HOST += testOperators testOperators_SRCS += testOperators.cpp diff --git a/testApp/pv/testPVStructureArray.cpp b/testApp/pv/testPVStructureArray.cpp index 8614271..c9b36e6 100644 --- a/testApp/pv/testPVStructureArray.cpp +++ b/testApp/pv/testPVStructureArray.cpp @@ -22,101 +22,134 @@ #include #include -using namespace epics::pvData; +#include +#include -static bool debug = false; +using namespace epics::pvData; static FieldCreatePtr fieldCreate; static PVDataCreatePtr pvDataCreate; static StandardFieldPtr standardField; static StandardPVFieldPtr standardPVField; static ConvertPtr convert; -static String buffer; -static void testPVStructureArray(FILE * fd) { - if(debug) fprintf(fd,"/ntestPVStructureArray\n"); - StructureArrayConstPtr alarm( - fieldCreate->createStructureArray(standardField->alarm())); - PVStructureArrayPtr pvAlarmStructure( - pvDataCreate->createPVStructureArray(alarm)); - PVStructurePtrArray palarms; - size_t na=2; - palarms.reserve(na); - for(size_t i=0; icreatePVStructure(standardField->alarm())); - } - pvAlarmStructure->put(0,2,palarms,0); - buffer.clear(); - pvAlarmStructure->toString(&buffer); - if(debug) fprintf(fd,"pvAlarmStructure\n%s\n",buffer.c_str()); - PVStructureArrayPtr copy(pvDataCreate->createPVStructureArray(alarm)); - convert->copyStructureArray(pvAlarmStructure,copy); - buffer.clear(); - copy->toString(&buffer); - if(debug) fprintf(fd,"copy\n%s\n",buffer.c_str()); - fprintf(fd,"testPVStructureArray PASSED\n"); -} - -static StructureConstPtr getPowerSupplyStructure() { - String properties("alarm"); - FieldConstPtrArray fields; - StringArray fieldNames; - fields.reserve(3); - fieldNames.reserve(3); - fieldNames.push_back("voltage"); - fieldNames.push_back("power"); - fieldNames.push_back("current"); - fields.push_back(standardField->scalar(pvDouble,properties)); - fields.push_back(standardField->scalar(pvDouble,properties)); - fields.push_back(standardField->scalar(pvDouble,properties)); - StructureConstPtr structure = fieldCreate->createStructure( - "powerSupply_t",fieldNames,fields); - return structure; -} - -static void testPowerSupplyArray(FILE * fd) { - if(debug) fprintf(fd,"/ntestPowerSupplyArray\n"); - PVStructurePtr powerSupplyArrayStruct = standardPVField->structureArray( - getPowerSupplyStructure(),String("alarm,timeStamp")); - PVStructureArrayPtr powerSupplyArray = - powerSupplyArrayStruct->getStructureArrayField(String("value")); - assert(powerSupplyArray.get()!=NULL); - int offset = powerSupplyArray->append(5); - if(debug) fprintf(fd,"offset %d\n",offset); - buffer.clear(); - powerSupplyArrayStruct->toString(&buffer); - if(debug) fprintf(fd,"after append 5\n%s\n",buffer.c_str()); - powerSupplyArray->remove(0,2); - buffer.clear(); - powerSupplyArrayStruct->toString(&buffer); - if(debug) fprintf(fd,"after remove(0,2)\n%s\n",buffer.c_str()); - powerSupplyArray->remove(2,1); - buffer.clear(); - powerSupplyArrayStruct->toString(&buffer); - if(debug) fprintf(fd,"after remove 2,1%s\n",buffer.c_str()); - powerSupplyArray->compress(); - buffer.clear(); - powerSupplyArrayStruct->toString(&buffer); - if(debug) fprintf(fd,"after compress%s\n",buffer.c_str()); - fprintf(fd,"testPowerSupplyArray PASSED\n"); -} - -int main(int argc,char *argv[]) +static void testBasic() { - char *fileName = 0; - if(argc>1) fileName = argv[1]; - FILE * fd = stdout; - if(fileName!=0 && fileName[0]!=0) { - fd = fopen(fileName,"w+"); - } + testDiag("Basic structure array ops"); + + StructureArrayConstPtr alarmtype( + fieldCreate->createStructureArray(standardField->alarm())); + + PVStructureArrayPtr alarmarr(pvDataCreate->createPVStructureArray(alarmtype)); + + testOk1(alarmarr->getLength()==0); + + alarmarr->setLength(5); + + testOk1(alarmarr->getLength()==5); + + PVStructureArray::const_svector aview = alarmarr->view(); + + testOk1(aview.size()==5); + testOk1(aview[4].get()==NULL); + + alarmarr->append(2); + + testOk1(alarmarr->getLength()==7); + + aview = alarmarr->view(); + + testOk1(aview[4].get()==NULL); + testOk1(aview[5].get()!=NULL); + testOk1(aview[6].get()!=NULL); +} + +static void testCompress() +{ + testDiag("Test structure array compress"); + + StructureArrayConstPtr alarmtype( + fieldCreate->createStructureArray(standardField->alarm())); + + PVStructureArrayPtr alarmarr(pvDataCreate->createPVStructureArray(alarmtype)); + + alarmarr->setLength(5); + + testOk1(alarmarr->getLength()==5); + + alarmarr->compress(); + + testOk1(alarmarr->getLength()==0); + + alarmarr->setLength(4); + + testOk1(alarmarr->getLength()==4); + + PVStructureArray::svector contents(10); + + contents[2] = pvDataCreate->createPVStructure(standardField->alarm()); + contents[4] = pvDataCreate->createPVStructure(standardField->alarm()); + contents[5] = pvDataCreate->createPVStructure(standardField->alarm()); + contents[8] = pvDataCreate->createPVStructure(standardField->alarm()); + + alarmarr->replace(contents); + + testOk1(!contents.unique()); + testOk1(alarmarr->getLength()==10); + + alarmarr->compress(); + + testOk1(contents.unique()); // a realloc happened + testOk1(alarmarr->getLength()==4); + + PVStructureArray::svector compressed(alarmarr->reuse()); + + testOk1(contents[2]==compressed[0]); + testOk1(contents[4]==compressed[1]); + testOk1(contents[5]==compressed[2]); + testOk1(contents[8]==compressed[3]); +} + +static void testRemove() +{ + testDiag("Test structure array remove"); + + PVStructureArray::svector contents(10); + + for(size_t i=0; icreatePVStructure(standardField->alarm()); + + StructureArrayConstPtr alarmtype( + fieldCreate->createStructureArray(standardField->alarm())); + PVStructureArrayPtr alarmarr(pvDataCreate->createPVStructureArray(alarmtype)); + + alarmarr->replace(contents); + + alarmarr->remove(0, 10); // all + + testOk1(alarmarr->getLength()==0); + + alarmarr->replace(contents); + + alarmarr->remove(1, 1); + + PVStructureArray::const_svector check(alarmarr->view()); + + testOk1(contents[0]==check[0]); + testOk1(contents[2]==check[1]); + testOk1(contents[3]==check[2]); +} + +MAIN(testPVStructureArray) +{ + testPlan(0); + testDiag("Testing structure array handling"); fieldCreate = getFieldCreate(); pvDataCreate = getPVDataCreate(); standardField = getStandardField(); standardPVField = getStandardPVField(); - convert = getConvert(); - testPVStructureArray(fd); - testPowerSupplyArray(fd); - return(0); + testBasic(); + testCompress(); + testRemove(); + return testDone(); } - From cf8c6718ddd51ba4715de726b3bacef5d0619f3b Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 11 Jun 2013 10:51:37 -0400 Subject: [PATCH 063/103] test PVStructureArray in testSerialization --- testApp/misc/testSerialization.cpp | 43 ++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/testApp/misc/testSerialization.cpp b/testApp/misc/testSerialization.cpp index 50e4266..d51451a 100644 --- a/testApp/misc/testSerialization.cpp +++ b/testApp/misc/testSerialization.cpp @@ -126,7 +126,17 @@ void serializationTest(PVFieldPtr const & field) { deserializedField->deserialize(buffer, control); // must equal - testOk1(*field==*deserializedField); + if(*field==*deserializedField) + testPass("Serialization round trip OK"); + else { + testFail("Serialization round trip did not match!"); + std::string buf; + field->toString(&buf); + testDiag("Expected: %s", buf.c_str()); + buf.clear(); + deserializedField->toString(&buf); + testDiag("Found: %s", buf.c_str()); + } } void testEquals() { @@ -361,6 +371,34 @@ void testStructure() { serializationTest(pvStructure); } +void testStructureArray() { + testDiag("Testing structure array..."); + + PVDataCreatePtr factory = getPVDataCreate(); + testOk1(factory.get()!=NULL); + + StructureArrayConstPtr tstype( + getFieldCreate()->createStructureArray(getStandardField()->alarm())); + PVStructureArrayPtr pvArr = getPVDataCreate()->createPVStructureArray(tstype); + + testDiag("empty array"); + serializationTest(pvArr); + + pvArr->setLength(10); + + testDiag("All NULLs"); + serializationTest(pvArr); + + PVStructureArray::svector data(5); + + data[1] = getPVDataCreate()->createPVStructure(getStandardField()->alarm()); + data[4] = getPVDataCreate()->createPVStructure(getStandardField()->alarm()); + + pvArr->replace(data); + + testDiag("Some NULLs"); + serializationTest(pvArr); +} void testStructureId() { @@ -445,7 +483,7 @@ void testStringCopy() { MAIN(testSerialization) { - testPlan(171); + testPlan(175); flusher = new SerializableControlImpl(); control = new DeserializableControlImpl(); @@ -460,6 +498,7 @@ MAIN(testSerialization) { testScalar(); testArray(); testStructure(); + testStructureArray(); delete buffer; From 23d5aab1e8ad813cc9882a6f04237e2c5f46eb7b Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 8 May 2013 16:04:06 -0400 Subject: [PATCH 064/103] add Doxyfile --- documentation/Doxyfile | 1621 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1621 insertions(+) create mode 100644 documentation/Doxyfile diff --git a/documentation/Doxyfile b/documentation/Doxyfile new file mode 100644 index 0000000..55df4dd --- /dev/null +++ b/documentation/Doxyfile @@ -0,0 +1,1621 @@ +# Doxyfile 1.7.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = pvDataCPP + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = xyz + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = .. + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../pvDataApp + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = YES + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvances is that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = ./pvDataCPP.tag + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans.ttf + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES From 3de28e3cef76fbf2d0b234181ed5743617a1e707 Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Thu, 13 Jun 2013 14:52:27 -0400 Subject: [PATCH 065/103] added pvArray.html; made queue.h and bitSetUtil.* compatible with pvDataCPP. --- documentation/pvArray.html | 998 ++++++++++++++++++++++++++++++++ pvDataApp/misc/queue.h | 8 +- pvDataApp/pvMisc/bitSetUtil.cpp | 40 +- pvDataApp/pvMisc/bitSetUtil.h | 2 +- 4 files changed, 1022 insertions(+), 26 deletions(-) create mode 100644 documentation/pvArray.html diff --git a/documentation/pvArray.html b/documentation/pvArray.html new file mode 100644 index 0000000..af43eb6 --- /dev/null +++ b/documentation/pvArray.html @@ -0,0 +1,998 @@ + + + + + + EPICS pvArray + + + + + + + + +
+

EPICS Array

+ + +

EPICS v4 Working Group, Working Draft, 13-Jun-2013

+ +
+
Latest version:
+
pvArray.html +
+
This version:
+
none
+
Previous version:
+
None
+
Editors:
+
Marty Kraimer, BNL
+ Michael Davidsaver, BNL
+
+ + +
+
+ + +
+

Table of Contents

+
+
+ + +

Introduction

+

This is the documentation for the scalarArray data type as defined by pvDataCPP-md. +When complete it will be merged into pvDataCPP.html. +Only sharedVector is currently documented. +It is documented in the next section, but when merged into pvDataCPP.html, +will appear in a later section. +For now ignore the documentation in pvDataApp/pv.

+

When NOTE EXISTING appears it means that there is a question about +the existing shared_vector implementation.

+ +

shared_vector

+

Status

+

I think that all public components of sharedVector.h +are now documented, but not all have a description or example. +Thus the documentation needs more work. +

+

Introduction

+

A shared_vector is a container as defined by the C++ standard library. +It is like std::vector but provides two additional features +1) shared raw array and 2) a window into the raw array.

+

To support these two features a shared_vector keeps the following +private data: +

+
m_data
+
This is a std::tr1::shared_ptr for the actual data array. +
+
m_offset
+
This is the offset of the first element seen by the window.
+
m_count
+
This is the size, i. e. total number of elements, seen by the window.
+
m_total
+
This is the number of elements between offset and the end of the array referenced + by m_data.
+
+Note that only m_data is shared. Thus each shared_vector has it's own window.

+

The following subsections are organized as follows: +

+
shared_vector example
+
The example code is based on a shared_vector<int32> + This subsection show the C++ definitions that are assumed by + the example code. + The source that contains the example code will be part + of this project but not yet.
+
std::vector compatible subsections
+
The types and methods that have the same names as std::vector.
+
share_vector specific
+
The methods that are not part of std::vector.
+

+

The subsections that are compatible with std::vector are organized +and start with a brief summary modeled after Section 31.3(STL Containers) in:
+"The C++ Programming Language, C++11, Fourth Edition", Bjarne Stroustrup,2013
+The subsection names are the same names that Stroustrup uses. +Each subsection starts with a brief summary that is similar to +the summary Stroustrup has at the beginnining of each subsection.

+

The comparison is always with std::vector. +In addition it shows what is defined by by std::vector but not by +shared_vector.

+

Someone who already understand the C++ STL can understand shared_vector +by just looking at the brief summarys. +For others the brief summary is followed by tutorial information. +

+

shared_vector example

+

The examples all assume that the following has been defined:

+
+typedef shared_vector<int32> Int32Array;
+...
+static void dumpArray(String const &message,Int32Array const& int32Array);
+
+

The following: +

+Int32Array int32Array(5);
+dumpArray("example",int32Array);
+
+creates a shared vector that holds an array of five elements where each element is a +32 bit signed integer. +The call to dumpArray displays the message and the array elements on standard out: +
+example 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+

+

exampleSharedVector is a main program that has the code for the +examples shown below.

+

Member Types

+

Brief Summary +

+value_type              Type of element
+size_type               Unsigned type of subscripts, element counts, etc.
+difference_type         Signed type of difference between iterators
+iterator                Behaves like value_type*
+const_iterator          Behaves like const value_type*
+reverse_iterator        Behaves like value_type*
+const_reverse_iterator  Behaves like const value_type*
+reference               value_types&
+const_reference         const_value_type&
+pointer                 Behaves like value_type *
+const_pointer           Behaves like const value_type*
+//not part of std::vector
+element_type            same as value_type
+shared_pointer_type     std::tr1::shared_ptr<value_type>
+// defined by std::vector but not by shared_vector
+allocator_type
+
+

+

+The typedefs are compatible with the STL container member types. +These define types for various types of variables that belong to a container +or are used to access a container.

+

value_type, reference, and const_reference

+

These three typedefs define the same types as the equivalent types for +an element of the shared_vector. +

+Int32Array::value_type value;
+//is the same as
+int32 value;
+
+Int32Array::reference rvalue = value;
+//is the same as
+int32 & rvalue = value;
+
+Int32Array::const_reference rvalue = value;
+//is the same as
+const int32 & rvalue = value;
+
+

+

pointer and const_pointer

+

The following is an example of code that uses the +pointer typedef:

+
+Int32Array int32Array(5);
+Int32Array::pointer pint32Array = int32Array.data();
+size_t len = int32Array.size();
+for(size_t i=0; i<len; ++i) pint32Array[i] = i;
+
+

A const_pointer is like a pointer except that only read access to the array elements +is allowed.

+

Dangorous: data should not be used unless it is necessary to +call C code. The above code should be:

+
+Int32Array int32Array(5);
+size_t len = int32Array.size();
+for(size_t i=0; i<len; ++i) int32Array[i] = i;
+
+ +

difference_type

+

This is used to get the number of elements between two elements. +For example:

+
+Int32Array::difference_type pdiff = int32Array[3] - int32Array[1];
+// pdiff will have the value 2
+
+

element_type and shared_pointer_type

+

These are member types defined by std::tr1::shared_ptr. +These are not used by any of the client methods.

+ +

Constructors, Destructor, and Assignments

+

Brief Summary +

+C c();         Default constructor; c is empty.
+C c(n);        c is initialized with n elementis with the value value_type{};
+               offset is 0; size is n;
+C c(n,e);      Initialize c with n copies of e.
+               offset is 0; size is n;
+
+C c(c);        Copy an existing shared_vector of the same type.
+               offset and taken same as v.
+               shared_ptr is copied; not the raw array
+C operator=(c) Assignment constructor.
+               shared_ptr is copied; not the raw array
+C c(c,o,n);    Copy an existing std::tr1::shared_ptr<value_type>
+               offset is o; size is c;
+C c(r,o,n);    Use an existing raw pointer.
+               default deleter use "delete[]" to delete.
+               offset is o; size is c;
+C c(r,d,o,n);  Use an existing raw pointer and deleter d;
+               offset is o; size is c;
+
+not implemented
+~C()           The C++ default destructor is used.
+C++11 specific
+&& constructor move constructor
+{} constructor uniform initializer constructor
+
+where +
+
C
+
The class name, e. g. shared_vector<int32>
+
c
+
shared_vector instance
+
n
+
size, i. e. the number of elements
+
o
+
offset
+
e
+
element instance
+
r
+
raw pointer, e. g. int32 *
+
d
+
a deleter, i. e. object that destroys the raw array.
+
+

+

Construct by creating new raw array

+
+shared_vector();
+shared_vector(size_t n);
+shared_vector(size_t n, value_type e);
+
+

The first three constructors all create a new shared_vector +by also creating a new raw array, +The difference is the size of the array, i.e. how many elements it contains, +and how the elements are initalized. +

+
+
shared_vector()
+
The array is empty, i.e. it has no elements.
+
shared_vector(size_t n)
+
The array has n elements. Each element is initialized +by the default constructor for the element type. +For numeric elements, like int32, this means 0.
+
shared_vector(size_t n, value_type e)
+
The array has n elements. +Each element has the initial value e. +
+
+

The following: +

+    cout << "***exampleConstructors***" << endl;
+    Int32Array emptyArray();
+    Int32Array zeroArray(16);
+    int32 value = 1;
+    Int32Array oneArray(8, value);
+    dumpArray("emptyArray",emptyArray);
+    dumpArray("zeroArray",zeroArray);
+    dumpArray("oneArray",oneArray);
+
+produces +
+***exampleConstructors***
+emptyArray 1
+zeroArray {16}[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...]
+oneArray {8}[1, 1, 1, 1, 1, 1, 1, 1]
+
+

NOTE EXISTING: Why did emptyArray disply the above. +Should it be "emptyArray {0} []"? +

+

Construct by sharing raw array from a shared_vector

+
+shared_vector(const shared_vector& o);
+shared_vector_base& operator=(const shared_vector_base& o);
+
+

These create a vector by coping the contents of an existing shared_vector +of the same type into the newly created vector. +Note that the complete raw array is not copied but just the std::tr1:: shared_ptr +that holds the array.

+

The following: +

+    cout << "***exampleCopyConstructors***" << endl;
+    size_t max = 16;
+    Int32Array int32Array(max);
+    for(size_t i=0; i<max; ++i) int32Array[i] = i+1;
+    Int32Array xxx(int32Array);    //copy constructor
+    Int32Array yyy = int32Array;   //copy assignment
+    cout << "dataPtr int32Array " << int32Array.dataPtr();
+    cout << " xxx " << xxx.dataPtr();
+    cout << " yyy " << yyy.dataPtr() << endl;
+    dumpArray("int32Array",emptyArray);
+    dumpArray("xxx",emptyArray);
+    dumpArray("yyy",emptyArray);
+
+produces +
+***exampleConstructors***
+dataPtr int32Array 0x136ea90 xxx 0x136ea90 yyy 0x136ea90
+int32Array {16}[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...]
+xxx {16}[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...]
+yyy {16}[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...]
+
+

Construct by wrapping an existing raw array

+
+shared_vector(A v, size_t o, size_t c)
+shared_vector(A d, B b, size_t o, size_t c)
+
+

NOTE EXISTING: Are these constructors necessary? +If code wants to wrap an existing raw array then +a std::tr1::shared_ptr can first be created +and the constructor in the next section can be called.

+

These "wrap" an existing raw pointer. +They allows access to a sub-array starting at offset o> +and has size c +The second provides a destructor and the first has a default deleter.

+

The default deleter does the following: +When the shared_vector is deleted, i. e. when no code references it, +the statement "delete[] a;" is executed.

+

An example of wrapping a raw array without using these constructors is:

+
+class Int32ArrayDeleter
+{
+//Note that this an example that does nothing.
+//But it could have private data
+public:
+     Int32ArrayDeleter() {}
+     virtual ~Int32ArrayDeleter() {}
+     void operator()(int32* a){
+         // MUST HANDLE DELETION
+         // default is "delete[] a;"
+     }
+};
+...
+int32 *pother; // something managed by other code
+size_t capacity; // size of array managed by other code
+
+Int32Array int32Array(pother,int32array_deleter,0,capacity);
+
+

This is used to wrap arrays that are managed by other +code. This should only be used if You understand the other code +and know what your deleter has to do. +An example, exampleShareRawArray, gives a more complete example. +

+ +

Create a shared_vector from an existing shared_ptr

+
+shared_vector(const std::tr1::shared_ptr<E1>& d, size_t o, size_t c)
+
+

This creates a vector from an existing smart pointer. +Thus the vector will share reference counting with the existing smart +pointer. This is useful for creating "windows" into the array +that the smart pointer references.

+ + + +

Create a shared_vector from an existing shared_vector

+
+ template<typename E1>
+    shared_vector(const shared_vector<E1>& o) :base_t(o) {}
+
+

NOTE EXISTING: I do not understand how this works or what it does.

+

This create a vector by coping the contents of an existing shared_vector +of the same or a different but related type +into the newly created vector. +This constructor creates a new raw array and copies the elements from +the existing array to the new array.

+ +

Size and Capacity

+

Brief Summary +

+size()      Return the number of elements in the window
+empty()     Is the window empty? this means shared_ptr is empty
+max_size()  The maximum possible number of elements.
+capacity()  The number of possible elements without re-allocating raw array.
+reserve(n)  Reserve at least n elements in raw array; May cause reallocation.
+resize(n)   Change size to n; May cause reallocation
+clear()     shared_ptr is reset, Window will be empty.
+
+not implemented
+resize(n,v)
+shrink_to_fit()
+

+

Details +

+size_t size() const;
+bool empty() const;
+size_t max_size() const;
+size_t capacity() const;
+void reserve(size_t n);
+void resize(size_t n);
+void clear();
+
+

+
+
size
+
The current number of elements in the window.
+
empty
+
(true,false) if size is (0,>0)
+
max_size
+
Maximum possible number of elements. +NOTE EXISTING; Should this be sizof(W)/(size_t -1) ? +
+
capacity
+
The maximum size the window can be without reallocating raw array
+
reserve
+
Set the maximum number of element that the window can see. + If the caller is the only user of the window and the number + of elements specified does not cause the number of elements to change + then this method just returns. + In all other cases a new raw array is allocated.

+
resize
+
Change the window size: may cause a reallocation of the raw array.
+
clear
+
If the shared_vector is not already empty the shared_ptr will + be reset. The new size will be 0.
+
+

The following: +

+static void exampleSizeEtc()
+{
+    cout << "***exampleSizeEtc***" << endl;
+    size_t max = 16;
+    Int32Array int32Array(max);
+    size_t capacity = int32Array.capacity();
+    size_t size = int32Array.size();
+    bool empty = int32Array.empty();
+    size_t max_size = int32Array.max_size();
+    cout<< "capacity" << capacity;
+    cout<< " size " << size;
+    cout<< " empty " << (empty ? true : false) ;
+    cout<< " max_size " << max_size << endl;
+}
+
+
+produces: +
+***exampleSizeEtc***
+capacity16 size 16 empty 0 max_size 18446744073709551615
+
+

+

Iterators

+

Brief Summary +

+begin()      First element
+end()        One past last element
+cbegin()     Constant first element
+cend()       Constant last element
+rbegin()     First element of reverse sequence
+rend()       One past last element of reverse sequence
+crbegin()    Constant first element of reverse sequence
+crend()      Constant last element of reverse sequence
+

+

+shared_vector supports both iterators and reverse iterators as defined by the STL. +For both constant iterators are also defined. +A constant iterator does not allow an array elemnent to be modified.

+

The following is an example of a constant iterator.

+
+int32 sum = 0;
+for(Int32Array::const_iterator iter=int32Array.begin(); iter<int32Array.end(); ++iter )
+{
+     sum += *iter;
+}
+
+

The following is an example of a non constant iterator.

+
+int32 value = 0;
+for(Int32Array::iterator iter=int32Array.begin(); iter<int32Array.end(); ++iter )
+{
+     *iter += ++value;
+}
+
+

Element Access

+

Brief Summary +

+operator[i]    random element access 
+data()         return the raw array
+
+implemented by std::vector but not implemented
+front()
+back()
+at()
+

+

Note that: +

+Int32Array::pointer pint32= int32Array.data();
+
+is NOT gauranteed to be the same as +
+int32 * pint32 = int32Array.data();
+
+

+

NOTE EXISTING: data() should be defined to return a const_pointer. +It is currently defined to return a plain pointer.

+

Stack Operations

+

Brief Summary +

+push_back(x)     Add an element after the last element
+pop_back(x)      Remove the last element.
+

+

List operations

+

shared_vector does not support the standard list operations like: +

+implemented by std::vector but not by shared_vector
+
+insert(p,x)   Add x before p
+...
+
+

+

Other Operations

+

Brief Summary +

+operator==       Do all elements of both containers compare equal.
+operator!=       Does any element not compare equal.
+operator<<       ostream operator
+swap(c2)         Swap the contents of two shared_vectors of the same type.
+swap(c1,c2)      Swap the contents of two shared_vectors of the same type.
+
+not implemented
+operator<
+operator<=
+operator>
+operator>=
+

+

operators equals, not equals, and ostream

+
+template<typename A, typename B>
+bool operator==(const epics::pvData::shared_vector<A>& a,
+                const epics::pvData::shared_vector<B>& b);
+
+template<typename A, typename B>
+bool operator!=(const epics::pvData::shared_vector<A>& a,
+                const epics::pvData::shared_vector<B>& b);
+
+template<typename E>
+std::ostream& operator<<(
+    std::ostream& strm, const epics::pvData::shared_vector<E>& arr);
+
+
+

swap

+

Swap the contents of two shared_vectors. The following code: +

+    cout << "***exampleSwap***" << endl;
+    Int32Array first(8);
+    Int32Array second(16);
+    cout << " before swap  size ";
+    cout<< "first " << first.size() << " second " << second.size() << endl;
+    first.swap(second);
+    cout << " after swap   size ";
+    cout<< "first " << first.size() << " second " << second.size() << endl;
+    swap(first,second);
+    cout << " swap again   size ";
+    cout<< "first " << first.size() << " second " << second.size() << endl;
+
+produces: +
+***exampleSwap***
+ before swap  size first 8 second 16
+ after swap   size first 16 second 8
+ swap again   size first 8 second 16
+

+ +

shared_vector specific operations

+

Brief Summary +

+void make_unique()         Make caller the only user of std::tr1::shared_ptr
+bool unique()              Is the caller the only user of std::tr1::shared_ptr
+void slice(offset,length)  Change window offset andsize
+
+// following should only be used for debugging
+const std::tr1::shared_ptr<E>&
+       dataPtr()           Return const  shared_ptr
+size_t dataOffset()        Return offset.
+size_t dataCount()         Return count which is also the size
+size_t dataTotal()         Return total number of elements between
+                           offset and end of the raw array
+
+// following converts from type FROM to type TO
+shared_vector static_shared_vector_cast(const shared_vector<FROM>& src);
+
+// following casts from const Type to Type
+shared_vector
+const_shared_vector_cast(const shared_vector<const TYPE>& src)
+

+

NOTE EXISTING: The C++ standard library considers a slice to be every nth element +of some part of an array, i. e., slice has arguments (offset,length,stride). +shared_vector only has offset and length. +Perhaps it should have another name like rewindow. +

make_unique and unique

+
+void make_unique();
+bool unique() const;
+
+
+
make_unique
+
Makes sure that caller is the only user of this standard_vector. + If the caller is not already the only user a new raw array is allocated.
+
unique
+
+ Returns (true,false) if there is only one user of the shared_vector. +
+
+

slice

+
+void slice(size_t offset, size_t length=(size_t)-1);
+
+

This modifies the "window" into the raw array starting at offset and of +the specified length. The offset and length are forced to be +within the raw array. +Note that this method never reallocates the underlying raw array. +

+

The following code: +

+static void exampleSlice()
+{
+    cout << "***exampleSlice***" << endl;
+    size_t max = 16;
+    Int32Array int32Array(max);
+    int32 value = 0;
+    for(Int32Array::iterator iter = int32Array.begin(); iter!=int32Array.end(); ++iter)
+    {
+        *iter = ++value;
+    }
+    dumpArray("int32Array",int32Array);
+    size_t offset = 0;
+    size_t length = 8;
+    Int32Array window1(int32Array);
+    window1.slice(offset,length);
+    dumpArray("window1",window1);
+    offset = 8;
+    length = 8;
+    Int32Array window2(int32Array);
+    window2.slice(offset,length);
+    dumpArray("window2",window2);
+    offset = 2;
+    length = 4;
+    Int32Array window3(window2);
+    window3.slice(offset,length);
+    dumpArray("window3",window3);
+}
+
+produces the following output: +
+***exampleSlice***
+int32Array 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+window1 1 2 3 4 5 6 7 8
+window2 9 10 11 12 13 14 15 16
+window3 11 12 13 14
+
+

dataPtr, dataOffset, dataCount, and dataTotal

+
+
dataPtr
+
Returns the shared_ptr that holds the raw array. +
+
dataOffset
+
Offset in the data array of first element
+
dataCount
+
Number of visible elements. + Same as size. +
+
dataTotal
+
Total number of elements between m_offset and the end of data. + Same as capacity. +
+
+

The following: +

+static void exampleDataEtc()
+{
+    cout << "***exampleDataEtc***" << endl;
+    size_t max = 16;
+    Int32Array int32Array(max);
+    long use_count = int32Array.dataPtr().use_count();
+    long offset = int32Array.dataOffset();
+    long count = int32Array.dataCount();
+    long total = int32Array.dataTotal();
+    cout << "use_count " << use_count;
+    cout << " offset " << offset;
+    cout << " count " << count;
+    cout << " total " <<  total << endl;
+}
+
+produces: +
+***exampleDataEtc***
+use_count 1 offset 0 count 16 total 16
+
+

+ +

static_shared_vector_cast

+

Not yet documented

+ +

const_shared_vector_cast

+

Not yet documented

+ +

specialization for untyped pointers

+

Not yet documented

+ +

pvDataApp/pv

+

INGORE REST OF DOCUMENT!!!!

+

pvData.h

+ +

PVArray

+ +

PVArray is the base interface for all the other PV Array interfaces. It +extends PVField and provides the additional methods:

+
class PVArray : public PVField, public SerializableArray {
+public:
+    POINTER_DEFINITIONS(PVArray);
+    virtual ~PVArray();
+    virtual void setImmutable();
+    std::size_t getLength() const;
+    virtual void setLength(std::size_t length);
+    std::size_t getCapacity() const;
+    bool isCapacityMutable() const;
+    void setCapacityMutable(bool isMutable);
+    virtual void setCapacity(std::size_t capacity) = 0;
+ ...
+};
+
+
setImmutable
+
Set the data immutable. Note that this is permanent since there is no + methods to make it mutable.
+
getLength
+
Get the current length. This is less than or equal to the capacity.
+
setLength
+
Set the length. If the PVField is not mutable then an exception is + thrown. If this is greater than the capacity setCapacity is called.
+
getCapacity
+
Get the capacity, i.e. this is the size of the underlying data + array.
+
setCapacity
+
Set the capacity. The semantics are implementation dependent but + typical semantics are as follows: If the capacity is not mutable an + exception is thrown. A new data array is created and data is copied from + the old array to the new array.
+
isCapacityMutable
+
Is the capacity mutable
+
setCapacityMutable
+
Specify if the capacity can be changed.
+
setCapacity
+
Set the capaciity.
+
+ + +

PVScalarArray

+ +

PVScalarArray is the base class for scalar array data. PVValueArray is a +templete for the various scalar array data classes. There is a class for each +possible scalar type, i. e. PVBooleanArray, ..., PVStringArray.

+
class PVScalarArray : public PVArray {
+public:
+    POINTER_DEFINITIONS(PVScalarArray);
+    virtual ~PVScalarArray();
+    typedef PVScalarArray &reference;
+    typedef const PVScalarArray& const_reference;
+    const ScalarArrayConstPtr getScalarArray() const ;
+    virtual std::ostream& dumpValue(std::ostream& o, size_t index) const = 0;
+ ...
+}
+ +

where

+
+
getScalarArray
+
Get the introspection interface.
+
dumpValue
+
Method for streams I/O.
+
+ +

PVValueArray

+ +

This is a template class plus instances for PVBooleanArray, ..., +PVStringArray.

+
template<typename T>
+class PVValueArray : public PVScalarArray {
+public:
+    POINTER_DEFINITIONS(PVValueArray);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    typedef PVArrayData<T> ArrayDataType;
+    typedef std::vector<T> vector;
+    typedef const std::vector<T> const_vector;
+    typedef std::tr1::shared_ptr<vector> shared_vector;
+    typedef PVValueArray & reference;
+    typedef const PVValueArray & const_reference;
+
+    virtual ~PVValueArray() {}
+    virtual std::size_t get(
+         std::size_t offset, std::size_t length, ArrayDataType &data) = 0;
+    virtual std::size_t put(std::size_t offset,
+        std::size_t length, const_pointer from, std::size_t fromOffset) = 0;
+    virtual std::size_t put(std::size_t offset,
+        std::size_t length, const_vector &from, std::size_t fromOffset);
+    virtual void shareData(
+         shared_vector const & value,
+         std::size_t capacity,
+         std::size_t length) = 0;
+    virtual pointer get() = 0;
+    virtual pointer get() const = 0;
+    virtual vector const & getVector() = 0;
+    virtual shared_vector const & getSharedVector() = 0;
+    std::ostream& dumpValue(std::ostream& o) const;
+    std::ostream& dumpValue(std::ostream& o, size_t index) const;
+protected:
+    PVValueArray(ScalarArrayConstPtr const & scalar)
+    : PVScalarArray(scalar) {}
+    friend class PVDataCreate;
+};
+
+template<typename T>
+std::size_t PVValueArray<T>::put(
+    std::size_t offset,
+    std::size_t length,
+    const_vector &from,
+    std::size_t fromOffset)
+{ return put(offset,length, &from[0], fromOffset); }
+
+/**
+ * Definitions for the various scalarArray types.
+ */
+typedef PVArrayData<uint8> BooleanArrayData;
+typedef PVValueArray<uint8> PVBooleanArray;
+typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
+
+typedef PVArrayData<int8> ByteArrayData;
+typedef PVValueArray<int8> PVByteArray;
+typedef std::tr1::shared_ptr<PVByteArray> PVByteArrayPtr;
+
+typedef PVArrayData<int16> ShortArrayData;
+typedef PVValueArray<int16> PVShortArray;
+typedef std::tr1::shared_ptr<PVShortArray> PVShortArrayPtr;
+
+typedef PVArrayData<int32> IntArrayData;
+typedef PVValueArray<int32> PVIntArray;
+typedef std::tr1::shared_ptr<PVIntArray> PVIntArrayPtr;
+
+typedef PVArrayData<int64> LongArrayData;
+typedef PVValueArray<int64> PVLongArray;
+typedef std::tr1::shared_ptr<PVLongArray> PVLongArrayPtr;
+
+typedef PVArrayData<uint8> UByteArrayData;
+typedef PVValueArray<uint8> PVUByteArray;
+typedef std::tr1::shared_ptr<PVUByteArray> PVUByteArrayPtr;
+
+typedef PVArrayData<uint16> UShortArrayData;
+typedef PVValueArray<uint16> PVUShortArray;
+typedef std::tr1::shared_ptr<PVUShortArray> PVUShortArrayPtr;
+
+typedef PVArrayData<uint32> UIntArrayData;
+typedef PVValueArray<uint32> PVUIntArray;
+typedef std::tr1::shared_ptr<PVUIntArray> PVUIntArrayPtr;
+
+typedef PVArrayData<uint64> ULongArrayData;
+typedef PVValueArray<uint64> PVULongArray;
+typedef std::tr1::shared_ptr<PVULongArray> PVULongArrayPtr;
+
+typedef PVArrayData<float> FloatArrayData;
+typedef PVValueArray<float> PVFloatArray;
+typedef std::tr1::shared_ptr<PVFloatArray> PVFloatArrayPtr;
+
+typedef PVArrayData<double> DoubleArrayData;
+typedef PVValueArray<double> PVDoubleArray;
+typedef std::tr1::shared_ptr<PVDoubleArray> PVDoubleArrayPtr;
+
+typedef PVArrayData<String> StringArrayData;
+typedef PVValueArray<String> PVStringArray;
+typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
+ +

where

+
+
get( std::size_t offset, std::size_t length, ArrayDataType &data) +
+
This method "exposes" it's internal array by setting data.data and + data.offset. The caller is responsible for copying the array elements. + This violates the principle that objects should not expose their internal + data but is done for efficency. For example it makes it possible to copy + between arrays with identical element types without requiring an + intermediate array.
+
put(std::size_t offset, std::size_t length, const_pointer from, + std::size_t fromOffset)
+
Put data into the array. from is a raw array.
+
put(std::size_t offset, std::size_t length, const_vector &from, + std::size_t fromOffset)
+
Put data into the array from a vector holding the raw array.
+
shareData( shared_vector const & value, std::size_t capacity, + std::size_t length)
+
Make the instance share the raw data from value.
+ One use is + for immutable arrays. In this case the caller must set the PVArray to be + immutable. In the PVArray is not immutable then it is the applications + responsibility to coordinate access to the array. Again this violates the + principle that objects should not expose their internal data but is + important for immutable arrays. For example pvData and the javaIOC define + many enumerated structures where an enumerated structure has two fields: + index and choices. Choices is a PVStringArray that holds the enumerated + choices. Index is a PVInt that is the index of the currently selected + choice. For many enumerated structures choices is immutable. Allowing the + choices internal String[] to be shared between all the instances of an + enumerated structure saves on storage.
+ Another use for shared data is an application which processes an + array via multiple modules. Each accesses the internal data array of a + PVArray. In this case it is the applications responsibility + to coordinate access to the array.
+
get()
+
Get the raw array.
+
getVector()
+
Get the vector holding the raw array.
+
getSharedVector()
+
Get the shared vector holding the data.
+
dumpValue
+
Method for streams I/O.
+
+ +

Both get and put return the number of elements actually transfered. The +arguments are:

+
+
offset
+
The offset in the PV array.
+
len
+
The maximum number of elements to transfer. The number actually + transfered will be less than or equal to this value.
+
data
+
Get sets data.data to it's internal array and data.offset to the offset + into the array. The caller is responsible for the actual data + transfer.
+
from
+
The array from which the data is taken. This array is supplied by the + caller
+
fromOffset
+
The offset in from
+
+ +

The caller must be prepared to make multiple calls to retrieve or put an +entire array. A caller should accept or put partial arrays. For example the +following reads an entire array:

+
void getArray(PVDoubleArrayPtr & pv,DoubleArray const & to)
+{
+    size_t len = pv->getLength();
+    if(to.size()<len) to.resize(len);
+    DoubleArrayData data;
+    size_t offset = 0;
+    while(offset<len) {
+        size_t num = pv->get(offset,(len-offset),data);
+        DoubleArray &from = data.data;
+        size_t fromOffset = data.offset;
+        for(size_t i=0; i<num; i++) to[i+offset] = from[i + fromOffset];
+        offset += num;
+    }
+} 
+ + + +
+ + diff --git a/pvDataApp/misc/queue.h b/pvDataApp/misc/queue.h index d496594..dea98f2 100644 --- a/pvDataApp/misc/queue.h +++ b/pvDataApp/misc/queue.h @@ -29,9 +29,9 @@ public: int getNumberFree(); int getNumberUsed(); queueElementPtr & getFree(); - void setUsed(queueElementPtr &element); + void setUsed(queueElementPtr const &element); queueElementPtr & getUsed(); - void releaseUsed(queueElementPtr &element); + void releaseUsed(queueElementPtr const &element); private: queueElementPtr nullElement; queueElementPtrArray elements; @@ -92,7 +92,7 @@ std::tr1::shared_ptr & Queue::getFree() } template -void Queue::setUsed(std::tr1::shared_ptr &element) +void Queue::setUsed(std::tr1::shared_ptr const &element) { if(element!=elements[nextSetUsed++]) { throw std::logic_error("not correct queueElement"); @@ -112,7 +112,7 @@ std::tr1::shared_ptr & Queue::getUsed() } template -void Queue::releaseUsed(std::tr1::shared_ptr &element) +void Queue::releaseUsed(std::tr1::shared_ptr const &element) { if(element!=elements[nextReleaseUsed++]) { throw std::logic_error( diff --git a/pvDataApp/pvMisc/bitSetUtil.cpp b/pvDataApp/pvMisc/bitSetUtil.cpp index cf6569d..b27075c 100644 --- a/pvDataApp/pvMisc/bitSetUtil.cpp +++ b/pvDataApp/pvMisc/bitSetUtil.cpp @@ -13,25 +13,31 @@ namespace epics { namespace pvData { +using std::tr1::static_pointer_cast; +using std::size_t; + static bool checkBitSetPVField( - PVField *pvField,BitSet *bitSet,int32 initialOffset) + PVFieldPtr const &pvField,BitSetPtr const &bitSet,int32 initialOffset) { - bool atLeastOneBitSet = false; - bool allBitsSet = true; int32 offset = initialOffset; int32 nbits = pvField->getNumberFields(); if(nbits==1) return bitSet->get(offset); int32 nextSetBit = bitSet->nextSetBit(offset); if(nextSetBit>=(offset+nbits)) return false; + if(nextSetBit<0) return false; if(bitSet->get(offset)) { if(nbits>1) { for(int32 i=offset+1; iclear(i); } return true; } - PVStructure *pvStructure = static_cast(pvField); + + bool atLeastOneBitSet = false; + bool allBitsSet = true; + PVStructurePtr pvStructure = static_pointer_cast(pvField); + offset = pvStructure->getFieldOffset() + 1; while(offsetgetSubField(offset).get(); + PVFieldPtr pvSubField = pvStructure->getSubField(offset); int32 nbitsNow = pvSubField->getNumberFields(); if(nbitsNow==1) { if(bitSet->get(offset)) { @@ -41,24 +47,16 @@ static bool checkBitSetPVField( } offset++; } else { - offset++; - PVStructure *pvSubStructure = static_cast(pvField); - PVFieldPtrArray pvSubStructureFields = - pvSubStructure->getPVFields(); - int num = pvSubStructure->getStructure()->getNumberFields(); - for(int32 i=0; iget(offset)) { - allBitsSet = false; - } - } else { + bool result = checkBitSetPVField(pvSubField,bitSet,offset); + if(result) { + atLeastOneBitSet = true; + if(!bitSet->get(offset)) { allBitsSet = false; } - offset += pvSubSubField->getNumberFields(); + } else { + allBitsSet = false; } + offset += pvSubField->getNumberFields(); } } if(allBitsSet) { @@ -72,7 +70,7 @@ static bool checkBitSetPVField( return atLeastOneBitSet; } -bool BitSetUtil::compress(BitSet *bitSet,PVStructure *pvStructure) +bool BitSetUtil::compress(BitSetPtr const &bitSet,PVStructurePtr const &pvStructure) { return checkBitSetPVField(pvStructure,bitSet,0); } diff --git a/pvDataApp/pvMisc/bitSetUtil.h b/pvDataApp/pvMisc/bitSetUtil.h index 44fac32..add517a 100644 --- a/pvDataApp/pvMisc/bitSetUtil.h +++ b/pvDataApp/pvMisc/bitSetUtil.h @@ -17,7 +17,7 @@ namespace epics { namespace pvData { class BitSetUtil : private NoDefaultMethods { public: - static bool compress(BitSet *bitSet,PVStructure *pvStructure); + static bool compress(BitSetPtr const &bitSet,PVStructurePtr const &pvStructure); }; }} From ec6b67ffad27b1db7318e4b451cab0e9fc1f8f24 Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Tue, 18 Jun 2013 10:01:52 -0400 Subject: [PATCH 066/103] Proposed pvData.h interface --- documentation/pvArray.html | 658 ++++++++++++++++++++++--------------- 1 file changed, 395 insertions(+), 263 deletions(-) diff --git a/documentation/pvArray.html b/documentation/pvArray.html index af43eb6..4b21ed5 100644 --- a/documentation/pvArray.html +++ b/documentation/pvArray.html @@ -37,7 +37,7 @@

EPICS Array

-

EPICS v4 Working Group, Working Draft, 13-Jun-2013

+

EPICS v4 Working Group, Working Draft, 18-Jun-2013

Latest version:
@@ -67,14 +67,398 @@ license.

Introduction

-

This is the documentation for the scalarArray data type as defined by pvDataCPP-md. -When complete it will be merged into pvDataCPP.html. -Only sharedVector is currently documented. -It is documented in the next section, but when merged into pvDataCPP.html, -will appear in a later section. -For now ignore the documentation in pvDataApp/pv.

-

When NOTE EXISTING appears it means that there is a question about -the existing shared_vector implementation.

+

This is the documentation for pvData.h as defined by pvDataCPP-md. +When complete it will be merged into pvDataCPP.html.

+

+pvData provides an interface for network accessible structured data. +The interfaces for C++ and Java are similar. +Thus someone who understands the interface in one of the languages +and knows both languages will quickly understand the interface of the other language. +With only a few exceptions the naming and other conventions do +not follow the C++ standard library conventions. +The definition of pvData is similar to the definition for Java. +The differences are mainly related to language differences. +Some differences are: +

+
shared pointers
+
Java has a garbage collector. In C++ the implementation manages + memory. The primary tool is std::tr1::shared_ptr.
+
PVArray
+
The Java garbage collector allows raw data arrays, e. g. int[], + to be shared. For C++ a shared_vector holds the raw data. +
+
ostream replaces toString
+
In Java every object has method toString. + For C++ operator<< replaces toString
+
shared_vector
+
This is similar to std::vector but uses a shared_ptr to wrap the raw + data and also supports a window into the raw data. It does follow + naming and other conventions for C++ standard library containers.
+
+

There is one big difference from the existing Java implelentation: +The method PVValueArray::get. +As an example the Java definition for PVDoubleArray is currently: +

+    int get(int offset, int length, DoubleArrayData data);
+
+This document assumes this be replaced by: +
+    double[] get();
+
+

The existing version allowed the data source to provide the array in chunks. +The new version assumes that the data source always provides contiguous storage +for the entire raw array. If this is accepted it simplifies a lot of code. +

+

Three topics not discussed in this document are: +

+
pvDataCreate
+
There should be a new method something like: +
+PVScalarArrayPtr createPVScalarArray(const PVScalarArray &, size_t offset, size_t length);
+      
+ This will share the raw data array but allow a new window. +
+
convert
+
This will be changed to do conversions itself instead of calling + methods like getAs. It will again support methods toXXXArray and fromXXXArray, + with a raw array replaced by a shared_vector. + Templates should be able to minimize the code required.
+
PVStructureArray
+
Can this also use shared_vector to hold elements?
+
+

+

pvDataApp/pv

+

pvData.h

+

This provides the interface for network accessible data. +Although templates are used to minimize the amount of code, +the interface is not meant to be extended. +Only the types defined by pvIntrospect are implemented.

+ +

PVField

+
+class PVField
+: virtual public Serializable,
+  public std::tr1::enable_shared_from_this
+{
+public:
+    POINTER_DEFINITIONS(PVField);
+    virtual ~PVField();
+    virtual void message(String message,MessageType messageType);
+    const String& getFieldName() const;
+    String getFullName() const;
+    virtual void setRequester(RequesterPtr const &prequester);
+    std::size_t getFieldOffset() const;
+    std::size_t getNextFieldOffset() const;
+    std::size_t getNumberFields() const;
+    PVAuxInfoPtr & getPVAuxInfo();
+    bool isImmutable() const;
+    void setImmutable();
+    const FieldConstPtr & getField() const;
+    PVStructure * getParent() const;
+    void replacePVField(const PVFieldPtr&  newPVField);
+    void renameField(String const & newName);
+    void postPut();
+    void setPostHandler(PostHandlerPtr const &postHandler);
+    virtual  std::ostream& operator<<(std::ostream& o) const;
+    std::ostream& operator<<(std::ostream& o, size_t index) const;
+...
+};
+
+std::ostream& operator<<(std::ostream& o, const PVFieldPtr & f);
+std::ostream& operator<<(std::ostream& o, const PVFieldPtr & f, size_t index);
+
+

The public methods for PVField are:

+
+
~PVField
+
Destructor. Since shared pointers are used it should never be called by + user code.
+
message
+
Code attached to this field can call this method to report + problems.
+
getFieldName
+
Get the field name. If the field is a top level structure the field + name will be an empty string.
+
setRequester
+
Sets a requester to be called when message or getRequesterName are + called. This is only legal for the top level PVField.
+
getFieldOffset
+
Get offset of the PVField field within top level structure. Every field + within the PVStructure has a unique offset. The top level structure has + an offset of 0. The first field within the structure has offset equal to + 1. The other offsets are determined by recursively traversing each + structure of the tree.
+
getNextFieldOffset
+
Get the next offset. If the field is a scalar or array field then this + is just offset + 1. If the field is a structure it is the offset of the + next field after this structure. Thus (nextOffset - offset) is always + equal to the total number of fields within the field.
+
getNumberFields
+
Get the total number of fields in this field. This is nextFieldOffset - + fieldOffset.
+
getPVAuxInfo
+
Get the PVAuxInfo for this field. PVAuxInfo is described below.
+
isImmutable
+
Is the field immutable?
+
setImmutable
+
Make the field immutable. Once a field is immutable it can never be + changed since there is no method to again make it mutable. This is an + important design decision since it allows immutable array fields to share + the internal primitive data array.
+
getField
+
Get the reflection interface for the data.
+
getParent
+
Get the interface for the parent or null if this is the top level + PVStructure.
+
replacePVField
+
Replace the data implementation for the field.
+
renameField
+
Rename the field name.
+
postPut
+
If a postHandler is registered it is called otherwise no action is + taken.
+
setPostHandler
+
Set the postHandler for the record. Only a single handler can be + registered.
+
operator<<
+
Stream output +
+

PVScalar

+
+class PVScalar : public PVField {
+public:
+    POINTER_DEFINITIONS(PVScalar);
+    virtual ~PVScalar();
+
+    typedef PVScalar &reference;
+    typedef const PVScalar& const_reference;
+
+    const ScalarConstPtr getScalar() const;
+...
+};
+
+

where

+
+
getScalar
+
Get the introspection interface for the PVScalar.
+
+ +

PVScalarValue

+
+template
+class PVScalarValue : public PVScalar {
+public:
+    POINTER_DEFINITIONS(PVScalarValue);
+    typedef T value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+
+    virtual ~PVScalarValue() {}
+    virtual T get() const = 0;
+    virtual void put(T value) = 0;
+
+    std::ostream& operator<<(std::ostream& o) const
+    std::ostream& operator<<(std::ostream& o, size_t index) const;
+...
+};
+typedef PVScalarValue<uint8> PVBoolean;
+typedef PVScalarValue<int8> PVByte;
+typedef PVScalarValue<int16> PVShort;
+typedef PVScalarValue<int32> PVInt;
+typedef PVScalarValue<int64> PVLong;
+typedef PVScalarValue<uint8> PVUByte;
+typedef PVScalarValue<uint16> PVUShort;
+typedef PVScalarValue<uint32> PVUInt;
+typedef PVScalarValue<uint64> PVULong;
+typedef PVScalarValue<float> PVFloat;
+typedef PVScalarValue<double> PVDouble;
+typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
+typedef std::tr1::shared_ptr<PVByte> PVBytePtr;
+typedef std::tr1::shared_ptr<PVShort> PVShortPtr;
+typedef std::tr1::shared_ptr<PVInt> PVIntPtr;
+typedef std::tr1::shared_ptr<PVLong> PVLongPtr;
+typedef std::tr1::shared_ptr<PVUByte> PVUBytePtr;
+typedef std::tr1::shared_ptr<PVUShort> PVUShortPtr;
+typedef std::tr1::shared_ptr<PVUInt> PVUIntPtr;
+typedef std::tr1::shared_ptr<PVULong> PVULongPtr;
+typedef std::tr1::shared_ptr<PVFloat> PVFloatPtr;
+typedef std::tr1::shared_ptr<PVDouble> PVDoublePtr;
+
+// PVString is special case, since it implements SerializableArray
+class PVString : public PVScalarValue<String>, SerializableArray {
+public:
+    virtual ~PVString() {}
+ ...
+};
+
+ +

where

+
+
get
+
Get the value stored in the object.
+
put
+
Change the value stored in the object.
+
operator<<
+
Methods for stream I/O.
+
+ + +

PVArray

+ +

PVArray is the base interface for all the other PV Array interfaces. It +extends PVField and provides the additional methods:

+
class PVArray : public PVField, public SerializableArray {
+public:
+    POINTER_DEFINITIONS(PVArray);
+    virtual ~PVArray();
+    virtual std::size_t getLength() const = 0;
+    virtual void setLength(std::size_t length) = 0;
+    bool isCapacityMutable() const;
+    void setCapacityMutable(bool isMutable);
+    virtual std::size_t getCapacity() const = 0;
+    virtual void setCapacity(std::size_t capacity) = 0;
+ ...
+};
+
+
getLength
+
Get the current length. This is less than or equal to the capacity.
+
setLength
+
Set the length. If the PVField is not mutable then an exception is + thrown. If this is greater than the capacity setCapacity is called.
+
isCapacityMutable
+
Is the capacity mutable
+
setCapacityMutable
+
Specify if the capacity can be changed.
+
getCapacity
+
Get the capacity, i.e. this is the size of the underlying data + array.
+
setCapacity
+
Set the capacity. The semantics are implementation dependent but + typical semantics are as follows: If the capacity is not mutable an + exception is thrown. A new data array is created and data is copied from + the old array to the new array.
+
+ + +

PVScalarArray

+ +

PVScalarArray is the base class for scalar array data. PVValueArray is a +templete for the various scalar array data classes. There is a class for each +possible scalar type, i. e. PVBooleanArray, ..., PVStringArray.

+
class PVScalarArray : public PVArray {
+public:
+    POINTER_DEFINITIONS(PVScalarArray);
+    typedef PVScalarArray &reference;
+    typedef const PVScalarArray& const_reference;
+
+    virtual ~PVScalarArray();
+    const ScalarArrayConstPtr getScalarArray() const;
+ ...
+};
+
+// PVString is special case, since it implements SerializableArray
+class PVString : public PVScalarValue<String>, SerializableArray {
+public:
+    virtual ~PVString() {}
+ ...
+};
+
+ +

where

+
+
getScalarArray
+
Get the introspection interface.
+
+ +

PVValueArray

+ +

This is a template class plus instances for PVBooleanArray, ..., +PVStringArray.

+
template<typename T>
+class PVValueArray :
+public PVScalarArray
+...
+{
+public:
+    POINTER_DEFINITIONS(PVValueArray);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    typedef PVValueArray & reference;
+    typedef const PVValueArray & const_reference;
+
+    typedef shared_vector<T> svector;
+    typedef shared_vector<const T> const_svector;
+
+    virtual ~PVValueArray() {}
+    const_svector & get();
+    size_t put(size_t offset,size_t length, const_svector &from, size_t fromOffset);
+
+    void shareData(const_svector &from);
+
+    virtual std::ostream& operator<<(std::ostream& o) const;
+    std::ostream& operator<<(std::ostream& o, size_t index) const;
+...
+};
+
+typedef PVValueArray<uint8> PVBooleanArray;
+typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
+
+typedef PVValueArray<int8> PVByteArray;
+typedef std::tr1::shared_ptr<PVByteArray> PVByteArrayPtr;
+
+typedef PVValueArray<int16> PVShortArray;
+typedef std::tr1::shared_ptr<PVShortArray> PVShortArrayPtr;
+
+typedef PVValueArray<int32> PVIntArray;
+typedef std::tr1::shared_ptr<PVIntArray> PVIntArrayPtr;
+
+typedef PVValueArray<int64> PVLongArray;
+typedef std::tr1::shared_ptr<PVLongArray> PVLongArrayPtr;
+
+typedef PVValueArray<uint8> PVUByteArray;
+typedef std::tr1::shared_ptr<PVUByteArray> PVUByteArrayPtr;
+
+typedef PVValueArray<uint16> PVUShortArray;
+typedef std::tr1::shared_ptr<PVUShortArray> PVUShortArrayPtr;
+
+typedef PVValueArray<uint32> PVUIntArray;
+typedef std::tr1::shared_ptr<PVUIntArray> PVUIntArrayPtr;
+
+typedef PVValueArray<uint64> PVULongArray;
+typedef std::tr1::shared_ptr<PVULongArray> PVULongArrayPtr;
+
+typedef PVValueArray<float> PVFloatArray;
+typedef std::tr1::shared_ptr<PVFloatArray> PVFloatArrayPtr;
+
+typedef PVValueArray<double> PVDoubleArray;
+typedef std::tr1::shared_ptr<PVDoubleArray> PVDoubleArrayPtr;
+
+typedef PVValueArray<String> PVStringArray;
+typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
+
+ +

where

+
+
get
+
Get the shared_vector that holds the data. + Code that calls this is able to modify the array elements + but should be very careful if it does. + For example it must call postPut after modifying the array elements. + It must also respect isImmutable(). +
+
put
+
This is the recommended method for modifying the array elements. + It may change the capacity if len asks for more elements + than the cureent capacity allows. + It does not change the current length. +
+
shareData
+
Share data with an existing shared_vector. + Note that if capacity is every changed then data will no + longer be shared.
+
operator<<
+
Methods for stream I/O.
+

shared_vector

Status

@@ -82,6 +466,8 @@ the existing shared_vector implementation.

are now documented, but not all have a description or example. Thus the documentation needs more work.

+

When NOTE EXISTING appears it means that there is a question about +the existing shared_vector implementation.

Introduction

A shared_vector is a container as defined by the C++ standard library. It is like std::vector but provides two additional features @@ -738,260 +1124,6 @@ use_count 1 offset 0 count 16 total 16

specialization for untyped pointers

Not yet documented

-

pvDataApp/pv

-

INGORE REST OF DOCUMENT!!!!

-

pvData.h

- -

PVArray

- -

PVArray is the base interface for all the other PV Array interfaces. It -extends PVField and provides the additional methods:

-
class PVArray : public PVField, public SerializableArray {
-public:
-    POINTER_DEFINITIONS(PVArray);
-    virtual ~PVArray();
-    virtual void setImmutable();
-    std::size_t getLength() const;
-    virtual void setLength(std::size_t length);
-    std::size_t getCapacity() const;
-    bool isCapacityMutable() const;
-    void setCapacityMutable(bool isMutable);
-    virtual void setCapacity(std::size_t capacity) = 0;
- ...
-};
-
-
setImmutable
-
Set the data immutable. Note that this is permanent since there is no - methods to make it mutable.
-
getLength
-
Get the current length. This is less than or equal to the capacity.
-
setLength
-
Set the length. If the PVField is not mutable then an exception is - thrown. If this is greater than the capacity setCapacity is called.
-
getCapacity
-
Get the capacity, i.e. this is the size of the underlying data - array.
-
setCapacity
-
Set the capacity. The semantics are implementation dependent but - typical semantics are as follows: If the capacity is not mutable an - exception is thrown. A new data array is created and data is copied from - the old array to the new array.
-
isCapacityMutable
-
Is the capacity mutable
-
setCapacityMutable
-
Specify if the capacity can be changed.
-
setCapacity
-
Set the capaciity.
-
- - -

PVScalarArray

- -

PVScalarArray is the base class for scalar array data. PVValueArray is a -templete for the various scalar array data classes. There is a class for each -possible scalar type, i. e. PVBooleanArray, ..., PVStringArray.

-
class PVScalarArray : public PVArray {
-public:
-    POINTER_DEFINITIONS(PVScalarArray);
-    virtual ~PVScalarArray();
-    typedef PVScalarArray &reference;
-    typedef const PVScalarArray& const_reference;
-    const ScalarArrayConstPtr getScalarArray() const ;
-    virtual std::ostream& dumpValue(std::ostream& o, size_t index) const = 0;
- ...
-}
- -

where

-
-
getScalarArray
-
Get the introspection interface.
-
dumpValue
-
Method for streams I/O.
-
- -

PVValueArray

- -

This is a template class plus instances for PVBooleanArray, ..., -PVStringArray.

-
template<typename T>
-class PVValueArray : public PVScalarArray {
-public:
-    POINTER_DEFINITIONS(PVValueArray);
-    typedef T  value_type;
-    typedef T* pointer;
-    typedef const T* const_pointer;
-    typedef PVArrayData<T> ArrayDataType;
-    typedef std::vector<T> vector;
-    typedef const std::vector<T> const_vector;
-    typedef std::tr1::shared_ptr<vector> shared_vector;
-    typedef PVValueArray & reference;
-    typedef const PVValueArray & const_reference;
-
-    virtual ~PVValueArray() {}
-    virtual std::size_t get(
-         std::size_t offset, std::size_t length, ArrayDataType &data) = 0;
-    virtual std::size_t put(std::size_t offset,
-        std::size_t length, const_pointer from, std::size_t fromOffset) = 0;
-    virtual std::size_t put(std::size_t offset,
-        std::size_t length, const_vector &from, std::size_t fromOffset);
-    virtual void shareData(
-         shared_vector const & value,
-         std::size_t capacity,
-         std::size_t length) = 0;
-    virtual pointer get() = 0;
-    virtual pointer get() const = 0;
-    virtual vector const & getVector() = 0;
-    virtual shared_vector const & getSharedVector() = 0;
-    std::ostream& dumpValue(std::ostream& o) const;
-    std::ostream& dumpValue(std::ostream& o, size_t index) const;
-protected:
-    PVValueArray(ScalarArrayConstPtr const & scalar)
-    : PVScalarArray(scalar) {}
-    friend class PVDataCreate;
-};
-
-template<typename T>
-std::size_t PVValueArray<T>::put(
-    std::size_t offset,
-    std::size_t length,
-    const_vector &from,
-    std::size_t fromOffset)
-{ return put(offset,length, &from[0], fromOffset); }
-
-/**
- * Definitions for the various scalarArray types.
- */
-typedef PVArrayData<uint8> BooleanArrayData;
-typedef PVValueArray<uint8> PVBooleanArray;
-typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
-
-typedef PVArrayData<int8> ByteArrayData;
-typedef PVValueArray<int8> PVByteArray;
-typedef std::tr1::shared_ptr<PVByteArray> PVByteArrayPtr;
-
-typedef PVArrayData<int16> ShortArrayData;
-typedef PVValueArray<int16> PVShortArray;
-typedef std::tr1::shared_ptr<PVShortArray> PVShortArrayPtr;
-
-typedef PVArrayData<int32> IntArrayData;
-typedef PVValueArray<int32> PVIntArray;
-typedef std::tr1::shared_ptr<PVIntArray> PVIntArrayPtr;
-
-typedef PVArrayData<int64> LongArrayData;
-typedef PVValueArray<int64> PVLongArray;
-typedef std::tr1::shared_ptr<PVLongArray> PVLongArrayPtr;
-
-typedef PVArrayData<uint8> UByteArrayData;
-typedef PVValueArray<uint8> PVUByteArray;
-typedef std::tr1::shared_ptr<PVUByteArray> PVUByteArrayPtr;
-
-typedef PVArrayData<uint16> UShortArrayData;
-typedef PVValueArray<uint16> PVUShortArray;
-typedef std::tr1::shared_ptr<PVUShortArray> PVUShortArrayPtr;
-
-typedef PVArrayData<uint32> UIntArrayData;
-typedef PVValueArray<uint32> PVUIntArray;
-typedef std::tr1::shared_ptr<PVUIntArray> PVUIntArrayPtr;
-
-typedef PVArrayData<uint64> ULongArrayData;
-typedef PVValueArray<uint64> PVULongArray;
-typedef std::tr1::shared_ptr<PVULongArray> PVULongArrayPtr;
-
-typedef PVArrayData<float> FloatArrayData;
-typedef PVValueArray<float> PVFloatArray;
-typedef std::tr1::shared_ptr<PVFloatArray> PVFloatArrayPtr;
-
-typedef PVArrayData<double> DoubleArrayData;
-typedef PVValueArray<double> PVDoubleArray;
-typedef std::tr1::shared_ptr<PVDoubleArray> PVDoubleArrayPtr;
-
-typedef PVArrayData<String> StringArrayData;
-typedef PVValueArray<String> PVStringArray;
-typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
- -

where

-
-
get( std::size_t offset, std::size_t length, ArrayDataType &data) -
-
This method "exposes" it's internal array by setting data.data and - data.offset. The caller is responsible for copying the array elements. - This violates the principle that objects should not expose their internal - data but is done for efficency. For example it makes it possible to copy - between arrays with identical element types without requiring an - intermediate array.
-
put(std::size_t offset, std::size_t length, const_pointer from, - std::size_t fromOffset)
-
Put data into the array. from is a raw array.
-
put(std::size_t offset, std::size_t length, const_vector &from, - std::size_t fromOffset)
-
Put data into the array from a vector holding the raw array.
-
shareData( shared_vector const & value, std::size_t capacity, - std::size_t length)
-
Make the instance share the raw data from value.
- One use is - for immutable arrays. In this case the caller must set the PVArray to be - immutable. In the PVArray is not immutable then it is the applications - responsibility to coordinate access to the array. Again this violates the - principle that objects should not expose their internal data but is - important for immutable arrays. For example pvData and the javaIOC define - many enumerated structures where an enumerated structure has two fields: - index and choices. Choices is a PVStringArray that holds the enumerated - choices. Index is a PVInt that is the index of the currently selected - choice. For many enumerated structures choices is immutable. Allowing the - choices internal String[] to be shared between all the instances of an - enumerated structure saves on storage.
- Another use for shared data is an application which processes an - array via multiple modules. Each accesses the internal data array of a - PVArray. In this case it is the applications responsibility - to coordinate access to the array.
-
get()
-
Get the raw array.
-
getVector()
-
Get the vector holding the raw array.
-
getSharedVector()
-
Get the shared vector holding the data.
-
dumpValue
-
Method for streams I/O.
-
- -

Both get and put return the number of elements actually transfered. The -arguments are:

-
-
offset
-
The offset in the PV array.
-
len
-
The maximum number of elements to transfer. The number actually - transfered will be less than or equal to this value.
-
data
-
Get sets data.data to it's internal array and data.offset to the offset - into the array. The caller is responsible for the actual data - transfer.
-
from
-
The array from which the data is taken. This array is supplied by the - caller
-
fromOffset
-
The offset in from
-
- -

The caller must be prepared to make multiple calls to retrieve or put an -entire array. A caller should accept or put partial arrays. For example the -following reads an entire array:

-
void getArray(PVDoubleArrayPtr & pv,DoubleArray const & to)
-{
-    size_t len = pv->getLength();
-    if(to.size()<len) to.resize(len);
-    DoubleArrayData data;
-    size_t offset = 0;
-    while(offset<len) {
-        size_t num = pv->get(offset,(len-offset),data);
-        DoubleArray &from = data.data;
-        size_t fromOffset = data.offset;
-        for(size_t i=0; i<num; i++) to[i+offset] = from[i + fromOffset];
-        offset += num;
-    }
-} 
- - From 5f52f140944eed84c19adbc78dea847642410854 Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Tue, 25 Jun 2013 12:18:38 -0400 Subject: [PATCH 067/103] comparison between implementations --- documentation/pvArray.html | 793 ++++++++++++++++++++++++++++++++++++- 1 file changed, 771 insertions(+), 22 deletions(-) diff --git a/documentation/pvArray.html b/documentation/pvArray.html index 4b21ed5..8621bb7 100644 --- a/documentation/pvArray.html +++ b/documentation/pvArray.html @@ -37,7 +37,7 @@

EPICS Array

-

EPICS v4 Working Group, Working Draft, 18-Jun-2013

+

EPICS v4 Working Group, Working Draft, 23-Jun-2013

Latest version:
@@ -68,7 +68,18 @@ license.

Introduction

This is the documentation for pvData.h as defined by pvDataCPP-md. -When complete it will be merged into pvDataCPP.html.

+When complete it will be merged into pvDataCPP.html. +This document proposes an implementation of the PVXXX interfaces that are +different than the existing pvDataCPP-md interfaces. +See the next section for a comparison of the four interface descriptions. +The main reason for proposing a different definition is the primary +purpose for pvData:
+pvData (Process Variable Data) defines and implements an efficent +way to store, access, and communicate memory resident data structures.
+This statement appears as the first sentence of pvDataJava.html. +A few sentances later the document makes clear that communication +includes network communication. +Thus it is important to keep the Java and C++ descriptions similar.

pvData provides an interface for network accessible structured data. The interfaces for C++ and Java are similar. @@ -82,7 +93,7 @@ Some differences are:

shared pointers
Java has a garbage collector. In C++ the implementation manages - memory. The primary tool is std::tr1::shared_ptr.
+ memory. An important tool is std::tr1::shared_ptr.
PVArray
The Java garbage collector allows raw data arrays, e. g. int[], to be shared. For C++ a shared_vector holds the raw data. @@ -92,8 +103,11 @@ Some differences are: For C++ operator<< replaces toString
shared_vector
This is similar to std::vector but uses a shared_ptr to wrap the raw - data and also supports a window into the raw data. It does follow - naming and other conventions for C++ standard library containers.
+ data and also supports a window into the raw data. It does follow the + naming and other conventions for C++ standard library containers. + Code that wants to use features of the C++ standard library + like iterators and algorithms can get the shared_vector. +

There is one big difference from the existing Java implelentation: The method PVValueArray::get. @@ -120,13 +134,736 @@ PVScalarArrayPtr createPVScalarArray(const PVScalarArray &, size_t offset, s

convert
This will be changed to do conversions itself instead of calling - methods like getAs. It will again support methods toXXXArray and fromXXXArray, - with a raw array replaced by a shared_vector. - Templates should be able to minimize the code required.
+ methods like getAs. It will again support methods toXXXArray and fromXXXArray. + Templates should be used to minimize the code required.
PVStructureArray
Can this also use shared_vector to hold elements?

+

PVXXX: pvDataJava, pvDataCPP, pvDataCPP-md, and proposed interface

+

The following compares the definitions of the following: PVField, +PVScalar and extensions, PVArray and extensions. +Note, however, that PVStructureArray is not discussed. +

+

PVField

+

This is the base for all the PVXXX iterfaces. +It provides basic methods for allowing network transfer and for +traversing structured data. +The pvDataJava and pvDataCPP definitions are similar. +pvDataCPP-md added method getFullName. +The proposed interface is like the existing pvDataCPP except that +the toString and dumpValue methods are replaced by the stream operator<<. +

+

Java

+
interface PVField extends Requester, Serializable {
+    String getFieldName();
+    void setRequester(Requester requester);
+    int getFieldOffset();
+    int getNextFieldOffset();
+    int getNumberFields();
+    PVAuxInfo getPVAuxInfo();
+    boolean isImmutable();
+    void setImmutable();
+    Field getField();
+    PVStructure getParent();
+    void renameField(String newName);
+    void postPut(); // calls PVRecordField.postPut if this is a field of a record
+    void setPostHandler(PostHandler postHandler);
+    void toString(StringBuilder buf);
+    void toString(StringBuilder buf,int indentLevel);
+    String toString();
+}
+

pvDataCPP

+
class PVField
+: virtual public Serializable,
+  public std::tr1::enable_shared_from_this<PVField>
+{
+public:
+   POINTER_DEFINITIONS(PVField);
+   virtual ~PVField();
+   virtual void message(String message,MessageType messageType);
+   String getFieldName() const ;
+   virtual void setRequester(RequesterPtr const &prequester);
+   std::size_t getFieldOffset() const;
+   std::size_t getNextFieldOffset() const;
+   std::size_t getNumberFields() const;
+   PVAuxInfoPtr & getPVAuxInfo()
+   bool isImmutable() const;
+   virtual void setImmutable();
+   const FieldConstPtr & getField() const ;
+   PVStructure * getParent() const
+   void replacePVField(const PVFieldPtr&  newPVField);
+   void renameField(String const &newName);
+   void postPut() ;
+   void setPostHandler(PostHandlerPtr const &postHandler);
+   virtual bool equals(PVField &pv);
+   virtual void toString(StringBuilder buf) ;
+   virtual void toString(StringBuilder buf,int indentLevel);
+   std::ostream& dumpValue(std::ostream& o) const;
+ ...
+}
+
+std::ostream& operator<<(std::ostream& o, const PVFieldPtr & f);
+
+

pvDataCPP-md

+
class PVField
+: virtual public Serializable,
+  public std::tr1::enable_shared_from_this<PVField>
+{
+public:
+   POINTER_DEFINITIONS(PVField);
+   virtual ~PVField();
+   virtual void message(String message,MessageType messageType);
+   String getFieldName() const ;
+   virtual void setRequester(RequesterPtr const &prequester);
+   std::size_t getFieldOffset() const;
+   std::size_t getNextFieldOffset() const;
+   std::size_t getNumberFields() const;
+   PVAuxInfoPtr & getPVAuxInfo()
+   bool isImmutable() const;
+   virtual void setImmutable();
+   const FieldConstPtr & getField() const ;
+   PVStructure * getParent() const
+   void replacePVField(const PVFieldPtr&  newPVField);
+   void renameField(String const &newName);
+   void postPut() ;
+   void setPostHandler(PostHandlerPtr const &postHandler);
+   virtual bool equals(PVField &pv);
+   virtual void toString(StringBuilder buf) ;
+   virtual void toString(StringBuilder buf,int indentLevel);
+   std::ostream& dumpValue(std::ostream& o) const;
+   // not in pvDataCPP
+   String getFullName() const;
+ ...
+}
+
+std::ostream& operator<<(std::ostream& o, const PVFieldPtr & f);
+
+

proposed

+
+class PVField
+: virtual public Serializable,
+  public std::tr1::enable_shared_from_this
+{
+public:
+    POINTER_DEFINITIONS(PVField);
+    virtual ~PVField();
+    virtual void message(String message,MessageType messageType);
+    const String& getFieldName() const;
+    String getFullName() const;
+    virtual void setRequester(RequesterPtr const &prequester);
+    std::size_t getFieldOffset() const;
+    std::size_t getNextFieldOffset() const;
+    std::size_t getNumberFields() const;
+    PVAuxInfoPtr & getPVAuxInfo();
+    bool isImmutable() const;
+    void setImmutable();
+    const FieldConstPtr & getField() const;
+    PVStructure * getParent() const;
+    void replacePVField(const PVFieldPtr&  newPVField);
+    void renameField(String const & newName);
+    void postPut();
+    void setPostHandler(PostHandlerPtr const &postHandler);
+    virtual bool equals(PVField &pv);
+    virtual std::ostream& operator<<(std::ostream& o) const = 0;
+    virtual std::ostream& operator<<(std::ostream& o, size_t index) const = 0;
+...
+};
+
+std::ostream& operator<<(std::ostream& o, const PVFieldPtr & f);
+std::ostream& operator<<(std::ostream& o, const PVFieldPtr & f, size_t index);
+
+

PVScalar

+

The Java and pvDataCPP versions differ in that Java has an interface definition +for each scalar type, i. e. PVBoolean, ..., PVString, +and the CPP versions provide a template PVValue for the implementation.

+

+pvDataCPP-md differs from pvDataCPP in that it implements three additional +methods: +

+
getAs
+
This is used to implement the Convert::toXXX methods. + This belongs in the Convert implementation not in PVScalar.
+
putFrom
+
This is used to implement the Convert::fromXXX scalar methods. + This belongs in the Convert implementation not in PVScalar.
+
assign
+
This does the same thing as the Convert::fromXXX methods except + that it does not go through Convert. + This belongs in the Convert implementation not in PVScalar.
+
+

+

The proposed version is like the pvDataCPP version except for dumpValue +and the stream interators.

+

pvDataJava

+
+interface PVScalar extends PVField {
+    Scalar getScalar();
+}
+
+interface PVBoolean extends PVScalar {
+    boolean get();
+    void put(boolean value);
+}
+
+interface PVByte extends PVScalar {
+    byte get();
+    void put(byte value);
+}
+...
+interface PVDouble extends PVScalar {
+    double get();
+    void put(double value);
+}
+interface PVString extends PVScalar, SerializableArray {
+    String get();
+    void put(String value);
+}
+
+

pvDataCPP

+
class PVScalar : public PVField {
+public:
+    POINTER_DEFINITIONS(PVScalar);
+    virtual ~PVScalar();
+    typedef PVScalar &reference;
+    typedef const PVScalar& const_reference;
+    const ScalarConstPtr getScalar() const ;
+ ...
+}
+
+template<typename T>
+class PVScalarValue : public PVScalar {
+public:
+    POINTER_DEFINITIONS(PVScalarValue);
+    typedef T value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    virtual ~PVScalarValue() {}
+    virtual T get() const = 0;
+    virtual void put(T value) = 0;
+    std::ostream& dumpValue(std::ostream& o) const
+    void operator>>=(T& value) const;
+    void operator<<=(T value);
+ ...
+}
+
+typedef PVScalarValue PVBoolean;
+typedef PVScalarValue PVByte;
+...typedef PVScalarValue PVDouble;
+typedef std::tr1::shared_ptr PVBooleanPtr;
+typedef std::tr1::shared_ptr PVBytePtr;
+...
+typedef std::tr1::shared_ptr PVDoublePtr;
+
+
+// PVString is special case, since it implements SerializableArray
+class PVString : public PVScalarValue<String>, SerializableArray {
+public:
+    virtual ~PVString() {}
+ ...
+};
+ +

pvDataCPP-md

+
class PVScalar : public PVField {
+public:
+    POINTER_DEFINITIONS(PVScalar);
+    virtual ~PVScalar();
+    typedef PVScalar &reference;
+    typedef const PVScalar& const_reference;
+    const ScalarConstPtr getScalar() const ;
+
+    // not in pvDataCPP
+    template<ScalarType ID>
+    inline typename ScalarTypeTraits<ID>::type getAs() const;
+
+    virtual void getAs(void *, ScalarType) const = 0;
+    template<ScalarType ID>
+    inline void putFrom(typename ScalarTypeTraits<ID>::type val)
+
+    virtual void putFrom(const void *, ScalarType) = 0;
+    virtual void assign(const PVScalar&) = 0;
+
+ ...
+}
+
+template<typename T>
+class PVScalarValue : public PVScalar {
+public:
+    POINTER_DEFINITIONS(PVScalarValue);
+    typedef T value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    virtual ~PVScalarValue() {}
+    virtual T get() const = 0;
+    virtual void put(T value) = 0;
+    std::ostream& dumpValue(std::ostream& o) const
+    void operator>>=(T& value) const;
+    void operator<<=(T value);
+
+    // not in pvDataCPP
+    static const ScalarType typeCode;
+ ...
+}
+
+typedef PVScalarValue PVBoolean;
+typedef PVScalarValue PVByte;
+...typedef PVScalarValue PVDouble;
+typedef std::tr1::shared_ptr PVBooleanPtr;
+typedef std::tr1::shared_ptr PVBytePtr;
+...
+typedef std::tr1::shared_ptr PVDoublePtr;
+
+
+// PVString is special case, since it implements SerializableArray
+class PVString : public PVScalarValue<String>, SerializableArray {
+public:
+    virtual ~PVString() {}
+ ...
+};
+

proposed

+
+class PVScalar : public PVField {
+public:
+    POINTER_DEFINITIONS(PVScalar);
+    virtual ~PVScalar();
+
+    typedef PVScalar &reference;
+    typedef const PVScalar& const_reference;
+
+    const ScalarConstPtr getScalar() const;
+...
+};
+
+template<typename T>
+class PVScalarValue : public PVScalar {
+public:
+    POINTER_DEFINITIONS(PVScalarValue);
+    typedef T value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+
+    virtual ~PVScalarValue() {}
+    virtual T get() const = 0;
+    virtual void put(T value) = 0;
+
+    void operator>>=(T& value) const;
+    void operator<<=(T value);
+    virtual std::ostream& operator<<(std::ostream& o) const
+    virtual std::ostream& operator>>(std::ostream& o, size_t index) const;
+...
+};
+typedef PVScalarValue<uint8> PVBoolean;
+typedef PVScalarValue<int8> PVByte;
+typedef PVScalarValue<double> PVDouble;
+...
+typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
+typedef std::tr1::shared_ptr<PVByte> PVBytePtr;
+...
+typedef std::tr1::shared_ptr<PVDouble> PVDoublePtr;
+
+// PVString is special case, since it implements SerializableArray
+class PVString : public PVScalarValue<String>, SerializableArray {
+public:
+    virtual ~PVString() {}
+ ...
+};
+
+

PVArray

+

The Java and pvDataCPP versions differ in that Java has an interface definition +for each scalarArray type, i. e. PVBooleanArray, ..., PVStringArray, +and the CPP versions provide a template PVValueArray for the implementation.

+

+pvDataCPP-md differs from pvDataCPP in that it implements additional +methods: +

+
getAs
+
This is used to implement the Convert::toXXXArray methods. + This belongs in the Convert implementation not in PVArray.
+
putFrom
+
This is used to implement the Convert::fromXXXArray scalar methods. + This belongs in the Convert implementation not in PVArray.
+
assign
+
This does the same thing as the Convert::fromXXXArray methods except + that it does not go through Convert. + This belongs in the Convert implementation not in PVArray.
+
copyOut
+
This is used to copy data to a raw array.
+
copyIn
+
This is used to copy data in from a raw array. +
+

+

The proposed version is differs from pvJava, pvDataCPP, and pvCPP-md. +It is like the Java version if the Java get method is simplified as discussed above. +For example PVDoubleArray::get becomes: +

+    double[] get();
+
+The corresponding C++ version becomes: +
+    const svector & get();
+
+

+

The remaining difference is that dumpValue is replaced by the stream operator<<.

+

The main difference from the pvDataJava version is that PVValueArray "wraps" shared_vector. +Thus shared_vector takes the place of the raw arrays in Java. +This allows the C++ interface to be more similar to Java.

+

The main difference from the pvDataCPP-md version is that it does not implement +the extra methods and allows +the client access to the shared_vector. +The client is then able to perform C++ specific things to the data. +BUT it also means that if the client modifies the shared_vector the client is also responsibel +for ensuring that the immutable and capacity related features of PVField and PVArray are +respected and the postPut is properly handled. +The new method for PVValueArray: + + void put(const svector &from); + +helps ensure that shared_vector from the client is kept in sync with the shared_vector wrapped +by PVValueArray. But the used is still responsible for making sure that +PVField::isImmutable is honored. +

+

pvDataJava

+
interface PVArray extends PVField, SerializableArray {
+    int getLength();
+    void setLength(int length);
+    int getCapacity();
+    void setCapacity(int length);
+    boolean isCapacityMutable();
+    void setCapacityMutable(boolean isMutable);
+}
+
+interface PVScalarArray extends PVArray {
+    ScalarArray getScalarArray();
+}
+

For each scalar type an associated array data interface is defined. Each has +a get and put method. For example:

+
public class DoubleArrayData {
+    public double[] data;
+    public int offset;
+}
+
+interface PVDoubleArray extends PVArray {
+    int get(int offset, int len, DoubleArrayData data);
+    int put(int offset,int len, double[] from, int fromOffset);
+    void shareData(double[] from);
+}
+

pvDataCPP

+
class PVArray : public PVField, public SerializableArray {
+public:
+    POINTER_DEFINITIONS(PVArray);
+    virtual ~PVArray();
+    virtual void setImmutable();
+    std::size_t getLength() const;
+    virtual void setLength(std::size_t length);
+    std::size_t getCapacity() const;
+    bool isCapacityMutable() const;
+    void setCapacityMutable(bool isMutable);
+    virtual void setCapacity(std::size_t capacity) = 0;
+    virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const = 0;
+
+ ...
+};
+
+std::ostream& operator<<(format::array_at_internal const& manip, const PVArray& array);
+
+
+template<typename T>
+class PVArrayData {
+private:
+    std::vector<T> init;
+public:
+    POINTER_DEFINITIONS(PVArrayData);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    std::vector<T> & data;
+    std::size_t offset;
+    PVArrayData()
+    : data(init)
+    {}
+};
+
+class PVScalarArray : public PVArray {
+public:
+    POINTER_DEFINITIONS(PVScalarArray);
+    virtual ~PVScalarArray();
+    typedef PVScalarArray &reference;
+    typedef const PVScalarArray& const_reference;
+    const ScalarArrayConstPtr getScalarArray() const ;
+    virtual std::ostream& dumpValue(std::ostream& o, size_t index) const = 0;
+ ...
+}
+
+template<typename T>
+class PVValueArray : public detail::PVVectorStorage<T,PVScalarArray> {
+    typedef detail::PVVectorStorage<T,PVScalarArray> base_t;
+public:
+    POINTER_DEFINITIONS(PVValueArray);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+
+    typedef PVArrayData<T> ArrayDataType;
+    typedef std::vector<T> vector;
+    typedef const std::vector<T> const_vector;
+    typedef std::tr1::shared_ptr<vector> shared_vector;
+    typedef PVValueArray & reference;
+    typedef const PVValueArray & const_reference;
+
+    virtual ~PVValueArray() {}
+    virtual std::size_t get(
+         std::size_t offset, std::size_t length, ArrayDataType &data) = 0;
+    virtual std::size_t put(std::size_t offset,
+        std::size_t length, const_pointer from, std::size_t fromOffset) = 0;
+    virtual std::size_t put(std::size_t offset,
+        std::size_t length, const_vector &from, std::size_t fromOffset);
+    virtual void shareData(
+         shared_vector const & value,
+         std::size_t capacity,
+         std::size_t length) = 0;
+    virtual pointer get() = 0;
+    virtual pointer get() const = 0;
+    virtual vector const & getVector() = 0;
+    virtual shared_vector const & getSharedVector() = 0;
+    std::ostream& dumpValue(std::ostream& o) const;
+    std::ostream& dumpValue(std::ostream& o, size_t index) const;
+
+...
+};
+template<typename T>
+std::size_t PVValueArray<T>::put(
+    std::size_t offset,
+    std::size_t length,
+    const_vector &from,
+    std::size_t fromOffset)
+{ return put(offset,length, &from[0], fromOffset); }
+
+/**
+ * Definitions for the various scalarArray types.
+ */
+typedef PVArrayData<uint8> BooleanArrayData;
+typedef PVValueArray<uint8> PVBooleanArray;
+typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
+...
+typedef PVArrayData<String> StringArrayData;
+typedef PVValueArray<String> PVStringArray;
+typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;i
+
+ +

pvDataCPP-md

+
class PVArray : public PVField, public SerializableArray {
+public:
+    POINTER_DEFINITIONS(PVArray);
+    virtual ~PVArray();
+    virtual void setImmutable();
+    std::size_t getLength() const;
+    virtual void setLength(std::size_t length);
+    std::size_t getCapacity() const;
+    bool isCapacityMutable() const;
+    void setCapacityMutable(bool isMutable);
+    virtual void setCapacity(std::size_t capacity) = 0;
+    virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const = 0;
+ ...
+};
+
+std::ostream& operator<<(format::array_at_internal const& manip, const PVArray& array);
+
+template<typename T>
+class PVArrayData {
+private:
+    std::vector<T> init;
+public:
+    POINTER_DEFINITIONS(PVArrayData);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    std::vector<T> & data;
+    std::size_t offset;
+    PVArrayData()
+    : data(init)
+    {}
+};
+
+class PVScalarArray : public PVArray {
+public:
+    POINTER_DEFINITIONS(PVScalarArray);
+    virtual ~PVScalarArray();
+    typedef PVScalarArray &reference;
+    typedef const PVScalarArray& const_reference;
+    const ScalarArrayConstPtr getScalarArray() const ;
+
+    // in pvDataCPP but not in pvDataCPP=md
+    //virtual std::ostream& dumpValue(std::ostream& o, size_t index) const = 0;
+
+    // not in pvDataCPP
+    template<ScalarType ID>
+    virtual void
+    getAs(shared_vector<typename ScalarTypeTraits<ID>::type>& out) const;
+
+    virtual void
+    getAs(ScalarType, shared_vector<void>& out) const = 0;
+
+    template<ScalarType ID>
+    inline size_t copyOut(typename ScalarTypeTraits<ID>::type* inp, size_t len) const;
+
+    virtual size_t copyOut(ScalarType id, void* ptr, size_t olen) const = 0;
+
+    template<ScalarType ID>
+    inline void putFrom(const shared_vector<typename ScalarTypeTraits<ID>::type>& inp);
+
+    virtual void putFrom(ScalarType, const shared_vector<void>&) = 0;
+
+    template<ScalarType ID>
+    inline void copyIn(const typename ScalarTypeTraits<ID>::type* inp, size_t len);
+
+    virtual void copyIn(ScalarType, const void*, size_t) = 0;
+
+    virtual void assign(PVScalarArray& pv) = 0;
+    
+ ...
+}
+
+template<typename T>
+class PVValueArray : public detail::PVVectorStorage {
+    typedef detail::PVVectorStorage base_t;
+public:
+    POINTER_DEFINITIONS(PVValueArray);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    typedef PVArrayData<T> ArrayDataType;
+    typedef std::vector<T> vector;
+    typedef const std::vector<T> const_vector;
+    typedef std::tr1::shared_ptr<vector> shared_vector;
+    typedef PVValueArray & reference;
+    typedef const PVValueArray & const_reference;
+
+    virtual ~PVValueArray() {}
+    virtual std::size_t get(
+         std::size_t offset, std::size_t length, ArrayDataType &data) = 0;
+    virtual std::size_t put(std::size_t offset,
+        std::size_t length, const_pointer from, std::size_t fromOffset) = 0;
+    virtual std::size_t put(std::size_t offset,
+        std::size_t length, const_vector &from, std::size_t fromOffset);
+    virtual void shareData(
+         shared_vector const & value,
+         std::size_t capacity,
+         std::size_t length) = 0;
+    virtual pointer get() = 0;
+    virtual pointer get() const = 0;
+    virtual vector const & getVector() = 0;
+    virtual shared_vector const & getSharedVector() = 0;
+    std::ostream& dumpValue(std::ostream& o) const;
+    std::ostream& dumpValue(std::ostream& o, size_t index) const;
+
+    /// not in pvDataCPP
+    static const ScalarType typeCode;
+    typedef ::epics::pvData::shared_vector<T> svector;
+    typedef ::epics::pvData::shared_vector<const T> const_svector;
+
+     virtual void
+    getAs(ScalarType id, ::epics::pvData::shared_vector<void>& out) const;
+    virtual size_t copyOut(ScalarType id, void* ptr, size_t olen) const;
+    virtual void
+    putFrom(ScalarType id, const ::epics::pvData::shared_vector<void>& inp);
+    virtual void copyIn(ScalarType id, const void* ptr, size_t len);
+    virtual void assign(PVScalarArray& pv);
+
+
+protected:
+    PVValueArray(ScalarArrayConstPtr const & scalar)
+    : PVScalarArray(scalar) {}
+    friend class PVDataCreate;
+};
+template<typename T>
+std::size_t PVValueArray<T>::put(
+    std::size_t offset,
+    std::size_t length,
+    const_vector &from,
+    std::size_t fromOffset)
+{ return put(offset,length, &from[0], fromOffset); }
+
+/**
+ * Definitions for the various scalarArray types.
+ */
+typedef PVArrayData<uint8> BooleanArrayData;
+typedef PVValueArray<uint8> PVBooleanArray;
+typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
+...
+typedef PVArrayData<String> StringArrayData;
+typedef PVValueArray<String> PVStringArray;
+typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;i
+
+

proposed

+
class PVArray : public PVField, public SerializableArray {
+public:
+    POINTER_DEFINITIONS(PVArray);
+    virtual ~PVArray();
+    virtual std::size_t getLength() const = 0;
+    virtual void setLength(std::size_t length) = 0;
+    bool isCapacityMutable() const;
+    void setCapacityMutable(bool isMutable);
+    virtual std::size_t getCapacity() const = 0;
+    virtual void setCapacity(std::size_t capacity) = 0;
+ ...
+};
+
+
+class PVScalarArray : public PVArray {
+public:
+    POINTER_DEFINITIONS(PVScalarArray);
+    typedef PVScalarArray &reference;
+    typedef const PVScalarArray& const_reference;
+
+    virtual ~PVScalarArray();
+    const ScalarArrayConstPtr getScalarArray() const;
+ ...
+};
+
+// PVString is special case, since it implements SerializableArray
+class PVString : public PVScalarValue<String>, SerializableArray {
+public:
+    virtual ~PVString() {}
+ ...
+};
+
+template<typename T>
+class PVValueArray :
+public PVScalarArray
+...
+{
+public:
+    POINTER_DEFINITIONS(PVValueArray);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    typedef PVValueArray & reference;
+    typedef const PVValueArray & const_reference;
+
+    typedef shared_vector<T> svector;
+    typedef shared_vector<const T> const_svector;
+
+    virtual ~PVValueArray() {}
+    const svector & get() const;
+    size_t put(size_t offset,size_t length, const_pointer from, size_t fromOffset);
+    void put(const svector & from);
+
+    void shareData(const svector &from);
+    virtual std::ostream& operator<<(std::ostream& o) const;
+    virtual std::ostream& operator<<(std::ostream& o, size_t index) const;
+
+...
+};
+
+typedef PVValueArray<uint8> PVBooleanArray;
+typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
+...
+typedef PVValueArray<String> PVStringArray;
+typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
+
+ + +

pvDataApp/pv

pvData.h

This provides the interface for network accessible data. @@ -159,8 +896,9 @@ public: void renameField(String const & newName); void postPut(); void setPostHandler(PostHandlerPtr const &postHandler); - virtual std::ostream& operator<<(std::ostream& o) const; - std::ostream& operator<<(std::ostream& o, size_t index) const; + virtual bool equals(PVField &pv); + virtual std::ostream& operator<<(std::ostream& o) const = 0; + virtual std::ostream& operator<<(std::ostream& o, size_t index) const = 0; ... }; @@ -255,9 +993,11 @@ public: virtual ~PVScalarValue() {} virtual T get() const = 0; virtual void put(T value) = 0; + void operator>>=(T& value) const; + void operator<<=(T value); - std::ostream& operator<<(std::ostream& o) const - std::ostream& operator<<(std::ostream& o, size_t index) const; + virtual std::ostream& operator<<(std::ostream& o) const + virtual std::ostream& operator<<(std::ostream& o, size_t index) const; ... }; typedef PVScalarValue<uint8> PVBoolean; @@ -298,6 +1038,7 @@ public:

put
Change the value stored in the object.
operator<<
+
operator>>
Methods for stream I/O.
@@ -390,13 +1131,14 @@ public: typedef shared_vector<const T> const_svector; virtual ~PVValueArray() {} - const_svector & get(); - size_t put(size_t offset,size_t length, const_svector &from, size_t fromOffset); + const svector & get() const; + size_t put(size_t offset,size_t length, const_pointer from, size_t fromOffset); + void put(const svector & from); - void shareData(const_svector &from); + void shareData(const svector &from); - virtual std::ostream& operator<<(std::ostream& o) const; - std::ostream& operator<<(std::ostream& o, size_t index) const; + virtual std::ostream& operator<<(std::ostream& o) const + virtual std::ostream& operator<<(std::ostream& o, size_t index) const; ... }; @@ -446,17 +1188,25 @@ typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr; For example it must call postPut after modifying the array elements. It must also respect isImmutable(). +
size_t put(size_t offset,size_t length, const_pointer from, size_t fromOffset);
put
This is the recommended method for modifying the array elements. It may change the capacity if len asks for more elements than the cureent capacity allows. It does not change the current length.
+
void put(const svector & from);
+
This puts data into the PVValueArray from the shared_vector. + If the shared_vector holds the same raw array as the PVValueArray then + the shared_vector held by the PVValueArray is put in sync with from. + If not the shared_vector will share the data. + potsPut will always be called.
shareData
Share data with an existing shared_vector. - Note that if capacity is every changed then data will no + Note that if capacity is ever changed then data will no longer be shared.
operator<<
+
operator>>
Methods for stream I/O.
@@ -587,8 +1337,7 @@ for(size_t i=0; i<len; ++i) pint32Array[i] = i;

A const_pointer is like a pointer except that only read access to the array elements is allowed.

-

Dangorous: data should not be used unless it is necessary to -call C code. The above code should be:

+

NOTE: data The above code is better implemented as:

 Int32Array int32Array(5);
 size_t len = int32Array.size();
@@ -826,7 +1575,7 @@ void clear();
      
(true,false) if size is (0,>0)
max_size
Maximum possible number of elements. -NOTE EXISTING; Should this be sizof(W)/(size_t -1) ? +NOTE EXISTING; Should be ((size_t)-1)/sizeof(T)
capacity
The maximum size the window can be without reallocating raw array
@@ -913,7 +1662,7 @@ at()
 Int32Array::pointer pint32= int32Array.data();
 
-is NOT gauranteed to be the same as +is guaranteed to be the same as
 int32 * pint32 = int32Array.data();
 
From b58b97a9162baf87bb46efd931ec8705c7d9e0a6 Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Fri, 28 Jun 2013 14:17:23 -0400 Subject: [PATCH 068/103] minor changes --- documentation/pvArray.html | 147 ++++++++++++++----------------------- 1 file changed, 55 insertions(+), 92 deletions(-) diff --git a/documentation/pvArray.html b/documentation/pvArray.html index 8621bb7..b5c53c3 100644 --- a/documentation/pvArray.html +++ b/documentation/pvArray.html @@ -37,7 +37,7 @@

EPICS Array

-

EPICS v4 Working Group, Working Draft, 23-Jun-2013

+

EPICS v4 Working Group, Working Draft, 28-Jun-2013

Latest version:
@@ -66,6 +66,22 @@ license.

+

Changes

+

Since the last version of this document the following changes have +been made to the proposed interface definitionsi for PVValueArray:

+
+
put(const svector &from)
+
This has been removed. shareData can be used instead.
+
get
+
The get methods has been replaced by two methods. + One allows write access to array elements and the other does not. +
+
+

The stream operator++ methods were changed so that they only appear +in PVField. All the complexity should be hidden in the implementation +and, perhaps like Java, in the convert facility.

+

A few minor changes were made because of mistakes in documenting +existing API descriptions.

Introduction

This is the documentation for pvData.h as defined by pvDataCPP-md. When complete it will be merged into pvDataCPP.html. @@ -73,21 +89,19 @@ This document proposes an implementation of the PVXXX interfaces that are different than the existing pvDataCPP-md interfaces. See the next section for a comparison of the four interface descriptions. The main reason for proposing a different definition is the primary -purpose for pvData:
-pvData (Process Variable Data) defines and implements an efficent -way to store, access, and communicate memory resident data structures.
+purpose for pvData: +

pvData (Process Variable Data) defines and implements an efficent +way to store, access, and communicate memory resident data structures.
This statement appears as the first sentence of pvDataJava.html. A few sentances later the document makes clear that communication includes network communication. -Thus it is important to keep the Java and C++ descriptions similar.

-

-pvData provides an interface for network accessible structured data. -The interfaces for C++ and Java are similar. -Thus someone who understands the interface in one of the languages +Thus pvData provides an interface for network accessible structured data. +If the interfaces for C++ and Java are similar then +someone who understands the interface in one of the languages and knows both languages will quickly understand the interface of the other language. With only a few exceptions the naming and other conventions do not follow the C++ standard library conventions. -The definition of pvData is similar to the definition for Java. +The pvData.h API is similar to the definition for Java. The differences are mainly related to language differences. Some differences are:

@@ -99,8 +113,8 @@ Some differences are: to be shared. For C++ a shared_vector holds the raw data.
ostream replaces toString
-
In Java every object has method toString. - For C++ operator<< replaces toString
+
In Java every object has method toString(). + For C++ stream operator<< replaces toString
shared_vector
This is similar to std::vector but uses a shared_ptr to wrap the raw data and also supports a window into the raw data. It does follow the @@ -109,13 +123,13 @@ Some differences are: like iterators and algorithms can get the shared_vector.
-

There is one big difference from the existing Java implelentation: +

There is one big difference from the existing Java API: The method PVValueArray::get. As an example the Java definition for PVDoubleArray is currently:

     int get(int offset, int length, DoubleArrayData data);
 
-This document assumes this be replaced by: +This document assumes this will be replaced by:
     double[] get();
 
@@ -137,13 +151,13 @@ PVScalarArrayPtr createPVScalarArray(const PVScalarArray &, size_t offset, s methods like getAs. It will again support methods toXXXArray and fromXXXArray. Templates should be used to minimize the code required.
PVStructureArray
-
Can this also use shared_vector to hold elements?
+
This should also be able to use shared_vector to hold elements.

PVXXX: pvDataJava, pvDataCPP, pvDataCPP-md, and proposed interface

The following compares the definitions of the following: PVField, PVScalar and extensions, PVArray and extensions. -Note, however, that PVStructureArray is not discussed. +PVStructureArray is not discussed.

PVField

This is the base for all the PVXXX iterfaces. @@ -152,7 +166,7 @@ traversing structured data. The pvDataJava and pvDataCPP definitions are similar. pvDataCPP-md added method getFullName. The proposed interface is like the existing pvDataCPP except that -the toString and dumpValue methods are replaced by the stream operator<<. +the dumpValue method is replaced by the stream operator<<.

Java

interface PVField extends Requester, Serializable {
@@ -199,7 +213,7 @@ public:
    virtual bool equals(PVField &pv);
    virtual void toString(StringBuilder buf) ;
    virtual void toString(StringBuilder buf,int indentLevel);
-   std::ostream& dumpValue(std::ostream& o) const;
+   virtual std::ostream& dumpValue(std::ostream& o) const =0;
  ...
 }
 
@@ -250,7 +264,6 @@ public:
     virtual ~PVField();
     virtual void message(String message,MessageType messageType);
     const String& getFieldName() const;
-    String getFullName() const;
     virtual void setRequester(RequesterPtr const &prequester);
     std::size_t getFieldOffset() const;
     std::size_t getNextFieldOffset() const;
@@ -265,13 +278,12 @@ public:
     void postPut();
     void setPostHandler(PostHandlerPtr const &postHandler);
     virtual bool equals(PVField &pv);
-    virtual std::ostream& operator<<(std::ostream& o) const = 0;
-    virtual std::ostream& operator<<(std::ostream& o, size_t index) const = 0;
+    void toString(StringBuilder buf) ;
+    void toString(StringBuilder buf,int indentLevel);
+    std::ostream& operator<<(std::ostream& o) const;
 ...
 };
 
-std::ostream& operator<<(std::ostream& o, const PVFieldPtr & f);
-std::ostream& operator<<(std::ostream& o, const PVFieldPtr & f, size_t index);
 

PVScalar

The Java and pvDataCPP versions differ in that Java has an interface definition @@ -448,8 +460,6 @@ public: void operator>>=(T& value) const; void operator<<=(T value); - virtual std::ostream& operator<<(std::ostream& o) const - virtual std::ostream& operator>>(std::ostream& o, size_t index) const; ... }; typedef PVScalarValue<uint8> PVBoolean; @@ -501,6 +511,7 @@ For example PVDoubleArray::get becomes: The corresponding C++ version becomes:

     const svector & get();
+    const const_svector & get() const;
 

The remaining difference is that dumpValue is replaced by the stream operator<<.

@@ -511,17 +522,13 @@ This allows the C++ interface to be more similar to Java.

the extra methods and allows the client access to the shared_vector. The client is then able to perform C++ specific things to the data. -BUT it also means that if the client modifies the shared_vector the client is also responsibel -for ensuring that the immutable and capacity related features of PVField and PVArray are +BUT it also means that if the client modifies the shared_vector +the client is also responsible for ensuring that the +immutable and capacity related features of PVField and PVArray are respected and the postPut is properly handled. -The new method for PVValueArray: -
- void put(const svector &from); - -helps ensure that shared_vector from the client is kept in sync with the shared_vector wrapped -by PVValueArray. But the used is still responsible for making sure that -PVField::isImmutable is honored.

+

Note that two get methods exist. +One allows write access to the raw data and the other doesn't/

pvDataJava

interface PVArray extends PVField, SerializableArray {
     int getLength();
@@ -564,8 +571,6 @@ public:
  ...
 };
 
-std::ostream& operator<<(format::array_at_internal const& manip, const PVArray& array);
-
 
 template<typename T>
 class PVArrayData {
@@ -590,13 +595,11 @@ public:
     typedef PVScalarArray &reference;
     typedef const PVScalarArray& const_reference;
     const ScalarArrayConstPtr getScalarArray() const ;
-    virtual std::ostream& dumpValue(std::ostream& o, size_t index) const = 0;
  ...
 }
 
 template<typename T>
-class PVValueArray : public detail::PVVectorStorage<T,PVScalarArray> {
-    typedef detail::PVVectorStorage<T,PVScalarArray> base_t;
+class PVValueArray : public PVScalarArray {
 public:
     POINTER_DEFINITIONS(PVValueArray);
     typedef T  value_type;
@@ -630,13 +633,6 @@ public:
 
 ...
 };
-template<typename T>
-std::size_t PVValueArray<T>::put(
-    std::size_t offset,
-    std::size_t length,
-    const_vector &from,
-    std::size_t fromOffset)
-{ return put(offset,length, &from[0], fromOffset); }
 
 /**
  * Definitions for the various scalarArray types.
@@ -820,17 +816,8 @@ public:
  ...
 };
 
-// PVString is special case, since it implements SerializableArray
-class PVString : public PVScalarValue<String>, SerializableArray {
-public:
-    virtual ~PVString() {}
- ...
-};
-
 template<typename T>
-class PVValueArray :
-public PVScalarArray
-...
+class PVValueArray : public PVScalarArray
 {
 public:
     POINTER_DEFINITIONS(PVValueArray);
@@ -844,13 +831,11 @@ public:
     typedef shared_vector<const T> const_svector;
 
     virtual ~PVValueArray() {}
-    const svector & get() const;
+    const svector & get() ;
+    const const_svector &get() const;
     size_t put(size_t offset,size_t length, const_pointer from, size_t fromOffset);
-    void put(const svector & from);
 
     void shareData(const svector &from);
-    virtual std::ostream& operator<<(std::ostream& o) const;
-    virtual std::ostream& operator<<(std::ostream& o, size_t index) const;
 
 ...
 };
@@ -882,7 +867,6 @@ public:
     virtual ~PVField();
     virtual void message(String message,MessageType messageType);
     const String& getFieldName() const;
-    String getFullName() const;
     virtual void setRequester(RequesterPtr const &prequester);
     std::size_t getFieldOffset() const;
     std::size_t getNextFieldOffset() const;
@@ -897,8 +881,9 @@ public:
     void postPut();
     void setPostHandler(PostHandlerPtr const &postHandler);
     virtual bool equals(PVField &pv);
-    virtual  std::ostream& operator<<(std::ostream& o) const = 0;
-    virtual std::ostream& operator<<(std::ostream& o, size_t index) const = 0;
+    void toString(StringBuilder buf) ;
+    void toString(StringBuilder buf,int indentLevel);
+    std::ostream& operator<<(std::ostream& o) const;
 ...
 };
 
@@ -995,9 +980,6 @@ public:
     virtual void put(T value) = 0;
     void operator>>=(T& value) const;
     void operator<<=(T value);
-
-    virtual std::ostream& operator<<(std::ostream& o) const
-    virtual std::ostream& operator<<(std::ostream& o, size_t index) const;
 ...
 };
 typedef PVScalarValue<uint8> PVBoolean;
@@ -1095,13 +1077,6 @@ public:
     const ScalarArrayConstPtr getScalarArray() const;
  ...
 };
-
-// PVString is special case, since it implements SerializableArray
-class PVString : public PVScalarValue<String>, SerializableArray {
-public:
-    virtual ~PVString() {}
- ...
-};
 

where

@@ -1115,10 +1090,7 @@ public:

This is a template class plus instances for PVBooleanArray, ..., PVStringArray.

template<typename T>
-class PVValueArray :
-public PVScalarArray
-...
-{
+class PVValueArray : public PVScalarArray {
 public:
     POINTER_DEFINITIONS(PVValueArray);
     typedef T  value_type;
@@ -1131,14 +1103,11 @@ public:
     typedef shared_vector<const T> const_svector;
 
     virtual ~PVValueArray() {}
-    const svector & get() const;
+    const svector & get() ;
+    const const_svector &get() const;
     size_t put(size_t offset,size_t length, const_pointer from, size_t fromOffset);
-    void put(const svector & from);
 
     void shareData(const svector &from);
-
-    virtual std::ostream& operator<<(std::ostream& o) const
-    virtual std::ostream& operator<<(std::ostream& o, size_t index) const;
 ...
 };
 
@@ -1195,19 +1164,13 @@ typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
        than the cureent capacity allows.
        It does not change the current length.
       
-   
void put(const svector & from);
-
This puts data into the PVValueArray from the shared_vector. - If the shared_vector holds the same raw array as the PVValueArray then - the shared_vector held by the PVValueArray is put in sync with from. - If not the shared_vector will share the data. - potsPut will always be called.
shareData
Share data with an existing shared_vector. Note that if capacity is ever changed then data will no - longer be shared.
-
operator<<
-
operator>>
-
Methods for stream I/O.
+ longer be shared. + This method can also be called to force the PVValueArray to have a new + raw array. This is usefull for implementing Copy On Write. +

shared_vector

From 5699c43b74859c86839076a94f843723470399d0 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 Jul 2013 17:42:46 -0400 Subject: [PATCH 069/103] correct max_size Take into account sizeof(E). --- pvDataApp/misc/sharedVector.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 8e64f39..bbe949f 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -157,8 +157,6 @@ namespace detail { size_t size() const{return m_count;} bool empty() const{return !m_count;} - size_t max_size() const{return (size_t)-1;} - /** @brief Reduce the view of this shared_vector. * @@ -300,6 +298,8 @@ public: template shared_vector(const shared_vector& o) :base_t(o) {} + size_t max_size() const{return ((size_t)-1)/sizeof(E);} + size_t capacity() const { return this->m_total; } /** @brief Set array capacity @@ -504,6 +504,8 @@ public: template shared_vector(const shared_vector& o) :base_t(o) {} + size_t max_size() const{return (size_t)-1;} + pointer data() const{ return (pointer)(((char*)this->m_data.get())+this->m_offset); } @@ -537,6 +539,8 @@ public: template shared_vector(const shared_vector& o) :base_t(o) {} + size_t max_size() const{return (size_t)-1;} + pointer data() const{ return (pointer)(((char*)this->m_data.get())+this->m_offset); } From 986f036d201789bafc47222e0172fad763988ae1 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 3 Jul 2013 11:34:32 -0400 Subject: [PATCH 070/103] replace accepts const_svector Allows PVValueArray *a, *b; a->replace(b->view()); --- pvDataApp/pv/pvData.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index 49913f3..752ddd8 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -1040,9 +1040,9 @@ namespace detail { //! Discard current contents and replaced with the provided. //! Fails for Immutable arrays //! calls postPut() - virtual void replace(const svector& next) + virtual void replace(const const_svector& next) { - svector temp(next); + svector temp(const_shared_vector_cast(next)); this->swap(temp); this->postPut(); } From 00da6c88ae88e763817e0635cdfec597aff48f28 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 3 Jul 2013 11:41:53 -0400 Subject: [PATCH 071/103] minor --- pvDataApp/pv/pvData.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index 752ddd8..e8aeef5 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -1241,8 +1241,7 @@ public: this->swap(next); // no convert == no copy } else { size_t len = inp.size() / ScalarTypeFunc::elementSize(id); - svector result; - this->swap(result); + svector result(this->take()); result.resize(len); castUnsafeV(len, typeCode, result.data(), id, inp.data()); @@ -1254,8 +1253,7 @@ public: virtual void copyIn(ScalarType id, const void* ptr, size_t len) { - svector data; - this->swap(data); + svector data(this->take()); // Will have to re-alloc anyway? If so avoid copying // data which will only be over-written if(data.capacity() Date: Wed, 3 Jul 2013 12:11:05 -0400 Subject: [PATCH 072/103] added --- documentation/pvDataDiscussion.html | 792 ++++++++++++++++++++++++++++ 1 file changed, 792 insertions(+) create mode 100644 documentation/pvDataDiscussion.html diff --git a/documentation/pvDataDiscussion.html b/documentation/pvDataDiscussion.html new file mode 100644 index 0000000..08a1e45 --- /dev/null +++ b/documentation/pvDataDiscussion.html @@ -0,0 +1,792 @@ + + + + + + EPICS pvDataDiscussion + + + + + + + + +
+

EPICS pvDataDiscussion

+ + +

EPICS v4 Working Group, Working Draft, 03-Jul-2013

+ +
+
Latest version:
+
pvDataDiscussion.html +
+
This version:
+
none
+
Previous version:
+
None
+
Editors:
+
Marty Kraimer, BNL
+
+ + +
+
+ + +
+

Table of Contents

+
+
+ + +

Introduction

+

As pvDataCPP progressed PVField and derived classes accumulated +more and more member functions. +These member functions have nothing to do with the primary primary +purpose for pvData: +

pvData (Process Variable Data) defines and implements an efficent +way to store, access, and communicate memory resident data structures.
+This statement appears as the first sentence of pvDataJava.html. +A few sentances later the document makes it clear that communication +includes efficent network communication. +Thus pvData provides an interface for network accessible structured data. +The problem of adding member functions that have nothing to do with the primary purpose +started with the Java API. +It already had extra methods that solved problems that should have had a different solution. +This document removes the extra methods so that when new problems arise in the future +the solution will not involve adding new member functions to the introspection and data API. +

+

The introspection and data API for pvData should only encapuslate methods that support the primary purpose +stated above. +The interfaces for C++ and Java should be similar so that +someone who understands the interface in one of the languages +and knows both languages will quickly understand the interface of the other language.

+

There is another problem with the existing API. There are methods that allow the "structure" +to change after an pvData object is created. An example is PVField::renameField(String newName). +Such methods should not exist.

+

There are methods regarding immutability: setImmutable, isImmutablei, setCapacityMutable, and isCapacityMutable. +Should they exists? For now lets assume no. +

+

One last issue is the interface for array data. This document proposes a simplified +version of what currently exists. It requires that the implementation always provides storage for +the complete raw array. The existing APIs allow the implementation to provide the data in +"chunks". Giving up this requirement simplifies the array interfaces. +The existing C++ implementation of PVValueArray has serious problems. +The shared_vector that is implemented in pvDataCP-md provides the solution to fixing +the problems. This document describes an API that is very similar to the new Java API +except that raw arrays are replaced by shared_vector.

+

This document will first describe changes to the existing Java interfaces +and then the corresponding C++ API.

+

Java API

+

The following shows which methods will be removed from the existing interfaces +and what will be added. +The methods to be removed are in red +and methods to add are in blue +Also the removed methods are at the end with a comment above. +The new methods also have a comment. +

+

Introspection Interfaces

+ +
interface Field extends Serializable {
+    String getId();
+    Type getType();
+    // following will be removed
+    void toString(StringBuilder buf);
+    void toString(StringBuilder buf,int indentLevel);
+    String toString();
+}
+
+
+// new interface
+interface FieldToString {
+    String toString(Field field);
+}
+
+interface Scalar extends Field {
+    ScalarType getScalarType();
+}
+
+interface ScalarArray extends Field {
+    ScalarType getElementType();
+}
+
+interface Structure extends Field {
+    Field getField(String fieldName);
+    int getFieldIndex(String fieldName);
+    Field[] getFields();
+    Field getField(int fieldIndex);
+    String[] getFieldNames();
+    String getFieldName(int fieldIndex)
+}
+
+interface StructureArray extends Field {
+    Structure getStructure();
+}
+
+interface FieldCreate {
+    Scalar createScalar(ScalarType scalarType);
+    ScalarArray createScalarArray(ScalarType elementType);
+    StructureArray createStructureArray(Structure elementStructure);
+    Structure createStructure(String[] fieldNames, Field[] field);
+    Structure createStructure(String id,String[] fieldNames, Field[] field);
+    Structure createStructure(Structure structToClone);
+    Field deserialize(ByteBuffer buffer, DeserializableControl control);
+    // following will be removed
+    Structure appendField(Structure structure,String fieldName, Field field);
+    Structure appendFields(Structure structure,String[] fieldNames, Field[] fields);
+}
+
+

Data Interfaces

+
+interface PVField extends Requester, Serializable {
+    String getFieldName();
+    void setRequester(Requester requester);
+    int getFieldOffset();
+    int getNextFieldOffset();
+    int getNumberFields();
+    Field getField();
+    PVStructure getParent();
+    void postPut();
+    void setPostHandler(PostHandler postHandler);
+    // following will be removed
+    PVAuxInfo getPVAuxInfo();
+    boolean isImmutable();
+    void setImmutable();
+    void renameField(String newName);
+    void toString(StringBuilder buf);
+    void toString(StringBuilder buf,int indentLevel);
+    String toString();
+}
+
+
+// The following is a new interface
+interface PVFieldToString {
+    String toString(PVField pvField);
+    void setMaxInitialArrayElements(int num);
+    void setMaxFinalArrayElements(int num);
+    int getMaxInitialArrayElements();
+    int getMaxFinalArrayElements();
+}
+    
+interface PVScalar extends PVField{
+    Scalar getScalar();
+}
+
+interface PVDouble extends PVScalar{
+    double get();
+    void put(double value);
+}
+// also PVBoolean, PVByte, PVShort, PVInt, PVLong, PVFloat, and PVString
+
+interface PVArray extends PVField, SerializableArray {
+    int getLength();
+    void setLength(int length);
+    int getCapacity();
+    void setCapacity(int length);
+    // following will be removed
+    boolean isCapacityMutable();
+    void setCapacityMutable(boolean isMutable);
+}
+
+interface PVScalarArray extends PVArray {
+    ScalarArray getScalarArray();
+}
+
+
+//following will be removed
+public class DoubleArrayData {
+    public double[] data;
+    public int offset;
+}
+
+interface PVDoubleArray extends PVArray {
+    // following are new
+    double[] get();
+    void swap(double[] value);
+    //following will be removed
+    int get(int offset, int len, DoubleArrayData data);
+    int put(int offset,int len, double[] from, int fromOffset);
+    void shareData(double[] from);
+}
+
+// also PVBooleanArray, ..., PVStringArray
+
+
+interface PVStructure extends PVField , BitSetSerializable{
+    Structure getStructure();
+    PVField[] getPVFields();
+    PVField getSubField(String fieldName);
+    PVField getSubField(int fieldOffset);
+    // The following are convenience methods
+    PVBoolean getBooleanField(String fieldName);
+    PVByte getByteField(String fieldName);
+    PVShort getShortField(String fieldName);
+    PVInt getIntField(String fieldName);
+    PVLong getLongField(String fieldName);
+    PVFloat getFloatField(String fieldName);
+    PVDouble getDoubleField(String fieldName);
+    PVString getStringField(String fieldName);
+    PVScalarArray getScalarArrayField(String fieldName);
+    PVStructureArray getStructureArrayField(String fieldName);
+    PVStructure getStructureField(String fieldName);
+    PVArray getArrayField(String fieldName,ScalarType elementType);
+    // following will be removed
+    void appendPVField(String fieldName,PVField pvField);
+    void appendPVFields(String[] fieldNames,PVField[] pvFields);
+    void removePVField(String fieldName);
+    void replacePVField(PVField oldPVField,PVField newPVField);
+    String getExtendsStructureName();
+    boolean putExtendsStructureName(String extendsStructureName);
+    public boolean checkValid();
+}
+ 
+
+//following will be removed
+public class StructureArrayData {
+    public PVStructure[] data;
+    public int offset;
+}
+
+
+interface PVStructureArray extends PVArray{
+    StructureArray getStructureArray();
+    // following are new
+    PVStructure[] get();
+    void swap(PVStructure[] value);
+    // following will be removed
+    int get(int offset, int length, StructureArrayData data);
+    int put(int offset,int length, PVStructure[] from, int fromOffset);
+    void shareData(PVStructure[] from);
+}
+
+
+public interface PVDataCreate {
+    PVField createPVField(Field field);
+    PVField createPVField(PVField fieldToClone);
+    PVScalar createPVScalar(Scalar scalar);
+    PVScalar createPVScalar(ScalarType fieldType);
+    PVScalar createPVScalar(PVScalar scalarToClone);
+    PVScalarArray createPVScalarArray(ScalarArray array);
+    PVScalarArray createPVScalarArray(ScalarType elementType);
+    PVScalarArray createPVScalarArray(PVScalarArray arrayToClone;
+    PVStructureArray createPVStructureArray(StructureArray structureArray);
+    PVStructure createPVStructure(Structure structure);
+    PVStructure createPVStructure(String[] fieldNames,Field[] fields);
+    PVStructure createPVStructure(PVStructure structToClone);
+    // following will be removed
+    PVField[] flattenPVStructure(PVStructure pvStructure);
+}
+
+

PVFieldToString

+

In addition to toString this has methods to limit the number of array element to display. +The existing Java implementation of toString displayed all elements. +For large arrays this is not desirable. +The new methods provide a way for the client to limit the number of elements. +The default might be set to something like display up to 10 elements with 5 fron the beginning and 5 from the end.

+

For C++ this can be a replacement for dumpValue.

+

PVBooleanArray, ..., PVStructureArray

+

The old get and put are replaced by two new and simpler methods: +

+
get
+
Returns the raw array. If the client code modifies the elements in the array then + the client must call postPut. The client also has to realize that if the raw array held by the PVXXXArray changes + then the client is no longer sharing data +
swap
+
This exchanges the old raw data with the new raw data.
+
+

+

+The method setCapacity will always create a new raw array and copy old data from the old to the new array. +This is not true now since the implementation does not create a new array if the old capacity is equal to the requested capacity. +

+

C++ API

+

The C++ class definitions are similar to the Java definitions with two main exceptions: +

+
toString
+
In c++ this is replaced by std::ostream.
+
raw array data
+
Java supports array data like double[] + The C++ replacement is shared_vector<double>, which is implemented + in pvDataCPP-md.
+

Introspection Interfaces

+ +
+class Field :
+    virtual public Serializable,
+    public std::tr1::enable_shared_from_this<Field>
+{
+public:
+    POINTER_DEFINITIONS(Field);
+    virtual ~Field();
+    Type getType() const{return m_type;}
+    virtual String getID() const = 0;
+    
+    // following will be removed
+    virtual void toString(StringBuilder buf) const{toString(buf,0);}
+    virtual void toString(StringBuilder buf,int indentLevel) const;
+    
+ ...
+};
+
+// new function
+std::ostream &toString(Field::const_reference field, std::ostream& o);
+
+
+class Scalar : public Field{
+public:
+    POINTER_DEFINITIONS(Scalar);
+    virtual ~Scalar();
+    typedef Scalar& reference;
+    typedef const Scalar& const_reference;
+
+    ScalarType getScalarType() const {return scalarType;}
+    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+    virtual void deserialize(ByteBuffer *buffer, DeserializableContol *control);
+    
+    // following will be removed
+    virtual void toString(StringBuilder buf) const{toString(buf,0);}
+    virtual void toString(StringBuilder buf,int indentLevel) const;
+    virtual String getID() const;
+    
+ ...
+};
+class ScalarArray : public Field{
+public:
+    POINTER_DEFINITIONS(ScalarArray);
+    typedef ScalarArray& reference;
+    typedef const ScalarArray& const_reference;
+
+    ScalarArray(ScalarType scalarType);
+    ScalarType  getElementType() const {return elementType;}
+    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
+    
+    // following will be removed
+    virtual void toString(StringBuilder buf) const{toString(buf,0);}
+    virtual void toString(StringBuilder buf,int indentLevel) const;
+    virtual String getID() const;
+    
+ ...
+};
+
+class Structure : public Field {
+public:
+    POINTER_DEFINITIONS(Structure);
+    typedef Structure& reference;
+    typedef const Structure& const_reference;
+
+   std::size_t getNumberFields() const {return numberFields;}
+   FieldConstPtr getField(String const & fieldName) const;
+   FieldConstPtr getField(std::size_t index) const;
+   std::size_t getFieldIndex(String const &fieldName) const;
+   FieldConstPtrArray const & getFields() const {return fields;}
+   StringArray const & getFieldNames() const;
+   String getFieldName(std::size_t fieldIndex);
+   virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+   virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
+    
+    // following will be removed
+   void renameField(std::size_t fieldIndex,String const &newName);
+   virtual void toString(StringBuilder buf,int indentLevel) const;
+   virtual String getID() const;
+   
+ ...
+};
+
+class StructureArray : public Field{
+public:
+    POINTER_DEFINITIONS(StructureArray);
+    typedef StructureArray& reference;
+    typedef const StructureArray& const_reference;
+
+    StructureConstPtr  getStructure() const {return pstructure;}
+    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
+    
+    // following will be removed
+    virtual void toString(StringBuilder buf,int indentLevel=0) const;
+    virtual String getID() const;
+    
+ ...
+};
+
+class FieldCreate  {
+public:
+    static FieldCreatePtr getFieldCreate();
+    ScalarConstPtr  createScalar(ScalarType scalarType) const
+    ScalarArrayConstPtr createScalarArray(ScalarType elementType) const;
+    StructureArrayConstPtr createStructureArray(StructureConstPtr const & structure) const;
+    StructureConstPtr createStructure (
+        StringArray const & fieldNames,
+        FieldConstPtrArray const & fields) const;
+    StructureConstPtr createStructure (
+        String const &id,
+        StringArray const & fieldNames,
+        FieldConstPtrArray const & fields) const;
+    FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const;
+    
+    // following will be removed
+    StructureConstPtr appendField(
+        StructureConstPtr const & structure,
+        String const &fieldName, FieldConstPtr const & field) const;
+    StructureConstPtr appendFields(
+        StructureConstPtr const & structure,
+        StringArray const & fieldNames,
+        FieldConstPtrArray const & fields) const;
+    
+ ...
+};
+
+extern FieldCreatePtr getFieldCreate();
+ 
+

Data Interfaces

+
+class PVField
+: virtual public Serializable,
+  public std::tr1::enable_shared_from_this<PVField>
+{
+public:
+   POINTER_DEFINITIONS(PVField);
+   virtual ~PVField();
+   inline const String &getFieldName() const ;
+   virtual void setRequester(RequesterPtr const &prequester);
+   std::size_t getFieldOffset() const;
+   std::size_t getNextFieldOffset() const;
+   std::size_t getNumberFields() const;
+   const FieldConstPtr & getField() const ;
+   PVStructure * getParent() const
+   void postPut() ;
+   void setPostHandler(PostHandlerPtr const &postHandler);
+    // following will be removed
+    
+   virtual void message(String message,MessageType messageType);
+   void replacePVField(const PVFieldPtr&  newPVField);
+   String getFullName() const;
+   virtual bool equals(PVField &pv);
+   PVAuxInfoPtr & getPVAuxInfo()
+   bool isImmutable() const;
+   virtual void setImmutable();
+   void replacePVField(const PVFieldPtr&  newPVField);
+   void renameField(String const &newName);
+   virtual void toString(StringBuilder buf) ;
+   virtual void toString(StringBuilder buf,int indentLevel);
+   std::ostream& dumpValue(std::ostream& o) const;
+   
+ ...
+};
+
+
+// The following is a new class
+class PVFieldToString {
+    String toString(const PVFieldPtr &pvField);
+    void setMaxInitialArrayElements(size_t num);
+    void setMaxFinalArrayElements(size_t num);
+    size_t getMaxInitialArrayElements();
+    size_t getMaxFinalArrayElements();
+...
+}
+
+class PVScalar : public PVField {
+public:
+    POINTER_DEFINITIONS(PVScalar);
+    virtual ~PVScalar();
+    typedef PVScalar &reference;
+    typedef const PVScalar& const_reference;
+
+    const ScalarConstPtr getScalar() const ;
+ ...
+}
+
+
+template<typename T>
+class PVScalarValue : public PVScalar {
+public:
+    POINTER_DEFINITIONS(PVScalarValue);
+    typedef T value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+
+    virtual ~PVScalarValue() {}
+    virtual T get() const = 0;
+    virtual void put(T value) = 0;
+    
+    // following will be removed
+    std::ostream& dumpValue(std::ostream& o)
+    void operator>>=(T& value) const;
+    void operator<<=(T value);
+    
+ ...
+}
+
+// PVString is special case, since it implements SerializableArray
+class PVString : public PVScalarValue<String>, SerializableArray {
+public:
+    virtual ~PVString() {}
+ ...
+}
+class PVArray : public PVField, public SerializableArray {
+public:
+    POINTER_DEFINITIONS(PVArray);
+    virtual ~PVArray();
+    std::size_t getLength() const;
+    virtual void setLength(std::size_t length);
+    std::size_t getCapacity() const;
+    virtual void setCapacity(std::size_t capacity) = 0;
+    
+    // following will be removed
+    virtual void setImmutable();
+    bool isCapacityMutable() const;
+    void setCapacityMutable(bool isMutable);
+    virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const = 0;
+    
+ ...
+};
+
+class PVScalarArray : public PVArray {
+public:
+    POINTER_DEFINITIONS(PVScalarArray);
+    virtual ~PVScalarArray();
+    typedef PVScalarArray &reference;
+    typedef const PVScalarArray& const_reference;
+
+    const ScalarArrayConstPtr getScalarArray() const ;
+    
+    // following will be removed
+    virtual std::ostream& dumpValue(std::ostream& o, size_t index) const = 0;
+    
+ ...
+}
+
+
+// following will be removed
+template<typename T>
+class PVArrayData {
+private:
+    std::vector<T> init;
+public:
+    POINTER_DEFINITIONS(PVArrayData);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    std::vector<T> & data;
+    std::size_t offset;
+    PVArrayData()
+    : data(init)
+    {}
+};
+
+
+template<typename T>
+class PVValueArray : public PVScalarArray {
+public:
+    POINTER_DEFINITIONS(PVValueArray);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    // following are new typeDefs
+    typedef shared_vector<T> svector;
+    typedef shared_vector<const T> const_svector; 
+
+    virtual ~PVValueArray() {}
+    // following are added
+    svector get();
+    void swap(svector& value);
+    
+    // following are removed
+    typedef PVValueArray & reference;
+    typedef const PVValueArray & const_reference;
+    typedef PVArrayData<T> ArrayDataType;
+    typedef std::vector<T> vector;
+    typedef const std::vector<T> const_vector;
+    typedef std::tr1::shared_ptr<vector> shared_vector;
+
+    virtual std::size_t get(
+         std::size_t offset, std::size_t length, ArrayDataType &data) = 0;
+    virtual std::size_t put(std::size_t offset,
+        std::size_t length, const_pointer from, std::size_t fromOffset) = 0;
+    virtual std::size_t put(std::size_t offset,
+        std::size_t length, const_vector &from, std::size_t fromOffset);
+    virtual void shareData(
+         shared_vector const & value,
+         std::size_t capacity,
+         std::size_t length) = 0;
+    virtual pointer get() = 0;
+    virtual pointer get() const = 0;
+    virtual vector const & getVector() = 0;
+    virtual shared_vector const & getSharedVector() = 0;
+    std::ostream& dumpValue(std::ostream& o) const;
+    std::ostream& dumpValue(std::ostream& o, size_t index) const;
+    
+...
+};
+
+typedef PVValueArray<uint8> PVBooleanArray;
+typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
+...
+typedef PVValueArray<String> PVStringArray;
+typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
+
+class PVStructure : public PVField,public BitSetSerializable {
+public:
+    POINTER_DEFINITIONS(PVStructure);
+    virtual ~PVStructure();
+    typedef PVStructure & reference;
+    typedef const PVStructure & const_reference;
+
+    StructureConstPtr getStructure() const;
+    const PVFieldPtrArray & getPVFields() const;
+    PVFieldPtr getSubField(String const &fieldName) const;
+    PVFieldPtr getSubField(std::size_t fieldOffset) const;
+    PVBooleanPtr getBooleanField(String const &fieldName) ;
+    PVBytePtr getByteField(String const &fieldName) ;
+    PVShortPtr getShortField(String const &fieldName) ;
+    PVIntPtr getIntField(String const &fieldName) ;
+    PVLongPtr getLongField(String const &fieldName) ;
+    PVUBytePtr getUByteField(String const &fieldName) ;
+    PVUShortPtr getUShortField(String const &fieldName) ;
+    PVUIntPtr getUIntField(String const &fieldName) ;
+    PVULongPtr getULongField(String const &fieldName) ;
+    PVFloatPtr getFloatField(String const &fieldName) ;
+    PVDoublePtr getDoubleField(String const &fieldName) ;
+    PVStringPtr getStringField(String const &fieldName) ;
+    PVStructurePtr getStructureField(String const &fieldName) ;
+    PVScalarArrayPtr getScalarArrayField(
+        String const &fieldName,ScalarType elementType) ;
+    PVStructureArrayPtr getStructureArrayField(String const &fieldName) ;
+    virtual void serialize(
+        ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
+    virtual void deserialize(
+        ByteBuffer *pbuffer,DeserializableControl *pflusher);
+    virtual void serialize(ByteBuffer *pbuffer,
+        SerializableControl *pflusher,BitSet *pbitSet) const;
+    virtual void deserialize(ByteBuffer *pbuffer,
+        DeserializableControl*pflusher,BitSet *pbitSet);
+    PVStructure(StructureConstPtr const & structure);
+    PVStructure(StructureConstPtr const & structure,PVFieldPtrArray const & pvFields);
+    
+    // following are removed
+    void appendPVField(
+        String const &fieldName,
+        PVFieldPtr const & pvField);
+    void appendPVFields(
+        StringArray const & fieldNames,
+        PVFieldPtrArray const & pvFields);
+    void removePVField(String const &fieldName);
+    virtual void setImmutable();
+    String getExtendsStructureName() const;
+    bool putExtendsStructureName(
+        String const &extendsStructureName);
+    
+};
+
+
+// following will be removed
+typedef PVArrayData<PVStructurePtr> StructureArrayData;
+
+
+class PVStructureArray : public PVArray
+{
+public:
+    POINTER_DEFINITIONS(PVStructureArray);
+    typedef PVStructurePtr  value_type;
+    typedef PVStructurePtr* pointer;
+    typedef const PVStructurePtr* const_pointer;
+    
+    // following are new typeDefs
+    typedef shared_vector<PVStructurePtr> svector;
+    typedef shared_vector<const PVStructurePtr> const_svector;
+    
+
+    virtual ~PVStructureArray() {}
+    virtual void setCapacity(size_t capacity);
+    virtual void setLength(std::size_t length);
+    virtual StructureArrayConstPtr getStructureArray() const ;
+    virtual void serialize(ByteBuffer *pbuffer,
+        SerializableControl *pflusher) const;
+    virtual void deserialize(ByteBuffer *buffer,
+    virtual void serialize(ByteBuffer *pbuffer,
+        SerializableControl *pflusher, std::size_t offset, std::size_t count) const ;
+    // following are new
+    svector get();
+    void swap(svector & value);
+    
+    // following are removed
+    typedef PVArrayData<PVStructurePtr> ArrayDataType;
+    typedef std::vector<PVStructurePtr> vector;
+    typedef const std::vector<PVStructurePtr> const_vector;
+    typedef std::tr1::shared_ptr<vector> shared_vector;
+    typedef PVStructureArray &reference;
+    typedef const PVStructureArray& const_reference;
+    
+    virtual std::size_t append(std::size_t number);
+    virtual bool remove(std::size_t offset,std::size_t number);
+    virtual void compress();
+    virtual std::size_t get(std::size_t offset, std::size_t length,
+        StructureArrayData &data);
+    virtual std::size_t put(std::size_t offset,std::size_t length,
+        const_vector const & from, std::size_t fromOffset);
+    virtual void shareData(
+         shared_vector const & value,
+         std::size_t capacity,
+         std::size_t length);
+    virtual pointer get() { return &((*value.get())[0]); }
+    virtual pointer get() const { return &((*value.get())[0]); }
+    virtual vector const & getVector() {return *value;}
+    virtual shared_vector const & getSharedVector() {return value;}
+    
+ ...
+};
+
+class PVDataCreate {
+public:
+    static PVDataCreatePtr getPVDataCreate();
+    PVFieldPtr createPVField(FieldConstPtr const & field);
+    PVFieldPtr createPVField(PVFieldPtr const & fieldToClone);
+    PVScalarPtr createPVScalar(ScalarConstPtr const & scalar);
+    PVScalarPtr createPVScalar(ScalarType scalarType);
+    PVScalarPtr createPVScalar(PVScalarPtr const & scalarToClone);
+    PVScalarArrayPtr createPVScalarArray(ScalarArrayConstPtr const & scalarArray);
+    PVScalarArrayPtr createPVScalarArray(ScalarType elementType);
+    PVScalarArrayPtr createPVScalarArray(PVScalarArrayPtr const  & scalarArrayToClone);
+    PVStructureArrayPtr createPVStructureArray(StructureArrayConstPtr const & structureArray);
+    PVStructurePtr createPVStructure(StructureConstPtr const & structure);
+    PVStructurePtr createPVStructure(
+        StringArray const & fieldNames,PVFieldPtrArray const & pvFields);
+   PVStructurePtr createPVStructure(PVStructurePtr const & structToClone);
+ ...
+};
+
+extern PVDataCreatePtr getPVDataCreate();
+
+ + +
+ + From 73450bdbc7ebcf329456681b355e9c234aff5879 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 3 Jul 2013 14:23:17 -0400 Subject: [PATCH 073/103] combine shared_vector for void and const void --- pvDataApp/misc/sharedVector.h | 59 ++++++++++------------------------- 1 file changed, 17 insertions(+), 42 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index bbe949f..953660d 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -12,7 +12,7 @@ namespace epics { namespace pvData { -template class shared_vector; +template class shared_vector; namespace detail { template @@ -221,7 +221,7 @@ namespace detail { * by make_unique() that unique()==true implies exclusive * ownership. */ -template +template class shared_vector : public detail::shared_vector_base { typedef detail::shared_vector_base base_t; @@ -243,7 +243,7 @@ public: typedef std::tr1::shared_ptr shared_pointer_type; // allow specialization for all E to be friends - template friend class shared_vector; + template friend class shared_vector; //! @brief Empty vector (not very interesting) @@ -476,17 +476,25 @@ public: }; +namespace detail { + template struct is_void {}; + template<> struct is_void { typedef void type; }; + template<> struct is_void { typedef void type; }; +} + //! Specialization for storing untyped pointers //! Does not allow access or iteration of contents -template<> -class shared_vector : public detail::shared_vector_base { - typedef detail::shared_vector_base base_t; +template +class shared_vector::type > + : public detail::shared_vector_base +{ + typedef detail::shared_vector_base base_t; public: - typedef void* pointer; + typedef E* pointer; typedef ptrdiff_t difference_type; typedef size_t size_type; - typedef std::tr1::shared_ptr shared_pointer_type; + typedef std::tr1::shared_ptr shared_pointer_type; shared_vector() :base_t() {} @@ -504,40 +512,7 @@ public: template shared_vector(const shared_vector& o) :base_t(o) {} - size_t max_size() const{return (size_t)-1;} - - pointer data() const{ - return (pointer)(((char*)this->m_data.get())+this->m_offset); - } -}; - -//! Specialization for storing constant untyped pointers -//! Does not allow access or iteration of contents -template<> -class shared_vector : public detail::shared_vector_base { - typedef detail::shared_vector_base base_t; -public: - typedef const void* pointer; - typedef ptrdiff_t difference_type; - typedef size_t size_type; - - typedef std::tr1::shared_ptr shared_pointer_type; - - shared_vector() :base_t() {} - - template - shared_vector(A v, size_t o, size_t c) :base_t(v,o,c) {} - - template - shared_vector(const std::tr1::shared_ptr& d, size_t o, size_t c) - :base_t(d,o,c) {} - - template - shared_vector(A d, B b, size_t o, size_t c) - :base_t(d,b,o,c) {} - - template - shared_vector(const shared_vector& o) :base_t(o) {} + shared_vector(const shared_vector& o) :base_t(o) {} size_t max_size() const{return (size_t)-1;} From 6900d4bbecfdf09c92f1908e1a698f76249b4bac Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 3 Jul 2013 17:25:29 -0400 Subject: [PATCH 074/103] make boolean type unambiguous "char", "signed char", and "unsigned char" are distinct types. Define "boolean" to be whichever is not "int8" or "uint8". --- pvDataApp/factory/PVDataCreateFactory.cpp | 4 ++-- pvDataApp/pv/pvData.h | 6 +++--- pvDataApp/pv/pvType.h | 12 +++++++++++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/pvDataApp/factory/PVDataCreateFactory.cpp b/pvDataApp/factory/PVDataCreateFactory.cpp index 7c20509..a9efae1 100644 --- a/pvDataApp/factory/PVDataCreateFactory.cpp +++ b/pvDataApp/factory/PVDataCreateFactory.cpp @@ -28,7 +28,7 @@ using std::min; namespace epics { namespace pvData { -//template<> const ScalarType PVBoolean::typeCode = pvBoolean; +template<> const ScalarType PVBoolean::typeCode = pvBoolean; template<> const ScalarType PVByte::typeCode = pvByte; template<> const ScalarType PVShort::typeCode = pvShort; template<> const ScalarType PVInt::typeCode = pvInt; @@ -41,7 +41,7 @@ template<> const ScalarType PVFloat::typeCode = pvFloat; template<> const ScalarType PVDouble::typeCode = pvDouble; template<> const ScalarType PVScalarValue::typeCode = pvString; -//template<> const ScalarType PVBooleanArray::typeCode = pvBoolean; +template<> const ScalarType PVBooleanArray::typeCode = pvBoolean; template<> const ScalarType PVByteArray::typeCode = pvByte; template<> const ScalarType PVShortArray::typeCode = pvShort; template<> const ScalarType PVIntArray::typeCode = pvInt; diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index e8aeef5..fd7cea4 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -530,7 +530,7 @@ private: /** * typedefs for the various possible scalar types. */ -typedef PVScalarValue PVBoolean; +typedef PVScalarValue PVBoolean; typedef PVScalarValue PVByte; typedef PVScalarValue PVShort; typedef PVScalarValue PVInt; @@ -1373,8 +1373,8 @@ private: /** * Definitions for the various scalarArray types. */ -typedef PVArrayData BooleanArrayData; -typedef PVValueArray PVBooleanArray; +typedef PVArrayData BooleanArrayData; +typedef PVValueArray PVBooleanArray; typedef std::tr1::shared_ptr PVBooleanArrayPtr; typedef PVArrayData ByteArrayData; diff --git a/pvDataApp/pv/pvType.h b/pvDataApp/pv/pvType.h index b9ffce7..0dc2b81 100644 --- a/pvDataApp/pv/pvType.h +++ b/pvDataApp/pv/pvType.h @@ -33,6 +33,14 @@ typedef unsigned int uintptr_t; namespace epics { namespace pvData { +namespace detail { + // Pick either type If or type Else to not be Cond + template + struct pick_type { typedef If type; }; + template + struct pick_type { typedef Else type; }; +} + /** * This is a set of typdefs used by pvData. */ @@ -40,7 +48,9 @@ namespace epics { namespace pvData { /** * boolean, i.e. can only have the values {@code false} or {@code true} */ -typedef uint8_t boolean; +typedef detail::pick_type::type + >::type boolean; /** * A 8 bit signed integer */ From 2cb07a8490223fb9b9339d6e9994fc1aab766624 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 8 Jul 2013 09:53:08 -0400 Subject: [PATCH 075/103] move parts of ScalarTypeFunc to sharedVector.h Move the parts of ScalarTypeFunc which deal with untyped shared_vector s to sharedVector.h to allow sharedVector.h to include pvIntrospect.h w/o creating an include loop... --- pvDataApp/factory/TypeFunc.cpp | 1 + pvDataApp/misc/sharedVector.h | 17 +++++++++++++++++ pvDataApp/pv/pvIntrospect.h | 17 ----------------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/pvDataApp/factory/TypeFunc.cpp b/pvDataApp/factory/TypeFunc.cpp index 2fa0872..3d1a51a 100644 --- a/pvDataApp/factory/TypeFunc.cpp +++ b/pvDataApp/factory/TypeFunc.cpp @@ -14,6 +14,7 @@ #include #include +#include #include "dbDefs.h" // for NELEMENTS diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 953660d..5f921a9 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -9,6 +9,7 @@ #include #include "pv/sharedPtr.h" +#include "pv/pvIntrospect.h" namespace epics { namespace pvData { @@ -573,6 +574,22 @@ const_shared_vector_cast(const shared_vector& src) } + +namespace ScalarTypeFunc { + //! Allocate an untyped array based on ScalarType + shared_vector allocArray(ScalarType id, size_t len); + + //! Allocate an untyped array based on ScalarType + template + inline + shared_vector::type> + allocArray(size_t len) + { + shared_vector raw(allocArray(ID, len)); + return static_shared_vector_cast::type>(raw); + } +} + }} // namespace epics::pvData // Global operators for shared_vector diff --git a/pvDataApp/pv/pvIntrospect.h b/pvDataApp/pv/pvIntrospect.h index f1df915..b897325 100644 --- a/pvDataApp/pv/pvIntrospect.h +++ b/pvDataApp/pv/pvIntrospect.h @@ -16,7 +16,6 @@ #include #include #include -#include namespace epics { namespace pvData { @@ -583,21 +582,5 @@ OP(pvDouble, double); OP(pvString, String); #undef OP - -namespace ScalarTypeFunc { - //! Allocate an untyped array based on ScalarType - shared_vector allocArray(ScalarType id, size_t len); - - //! Allocate an untyped array based on ScalarType - template - inline - shared_vector::type> - allocArray(size_t len) - { - shared_vector raw(allocArray(ID, len)); - return static_shared_vector_cast::type>(raw); - } -} - }} #endif /* PVINTROSPECT_H */ From d319e2ed7b4b3b590bafce5bf909f8828d0abe13 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 8 Jul 2013 09:54:13 -0400 Subject: [PATCH 076/103] add ScalarTypeID template Define a compile time mapping from type to ScalarType enum value. --- pvDataApp/pv/pvIntrospect.h | 43 ++++++++++++++++++++++++----------- testApp/pv/testIntrospect.cpp | 26 ++++++++++++++++++++- 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/pvDataApp/pv/pvIntrospect.h b/pvDataApp/pv/pvIntrospect.h index b897325..5a087cc 100644 --- a/pvDataApp/pv/pvIntrospect.h +++ b/pvDataApp/pv/pvIntrospect.h @@ -558,6 +558,19 @@ private: */ extern FieldCreatePtr getFieldCreate(); +/** Define a compile time mapping from + * type to enum value. + @code + ScalarType code = (ScalarType)ScalarTypeID::value; + assert(code==pvByte); + @endcode + * + * For unspecified types this evaluates to an invalid ScalarType + * value (eg -1). + */ +template +struct ScalarTypeID { enum {value=-1}; }; + /** * Static mapping from ScalarType enum to value type. @code @@ -567,19 +580,23 @@ extern FieldCreatePtr getFieldCreate(); template struct ScalarTypeTraits {}; -#define OP(ENUM, TYPE) template<> struct ScalarTypeTraits {typedef TYPE type;} -OP(pvBoolean, boolean); -OP(pvByte, int8); -OP(pvShort, int16); -OP(pvInt, int32); -OP(pvLong, int64); -OP(pvUByte, uint8); -OP(pvUShort, uint16); -OP(pvUInt, uint32); -OP(pvULong, uint64); -OP(pvFloat, float); -OP(pvDouble, double); -OP(pvString, String); +#define OP(ENUM, TYPE) \ +template<> struct ScalarTypeTraits {typedef TYPE type;}; \ +template<> struct ScalarTypeID { enum {value=ENUM}; }; \ +template<> struct ScalarTypeID { enum {value=ENUM}; }; + +OP(pvBoolean, boolean) +OP(pvByte, int8) +OP(pvShort, int16) +OP(pvInt, int32) +OP(pvLong, int64) +OP(pvUByte, uint8) +OP(pvUShort, uint16) +OP(pvUInt, uint32) +OP(pvULong, uint64) +OP(pvFloat, float) +OP(pvDouble, double) +OP(pvString, String) #undef OP }} diff --git a/testApp/pv/testIntrospect.cpp b/testApp/pv/testIntrospect.cpp index 79bfe52..f9531f1 100644 --- a/testApp/pv/testIntrospect.cpp +++ b/testApp/pv/testIntrospect.cpp @@ -174,9 +174,32 @@ static void testError() testOk1(fieldCreate->createStructure(names,fields).get()!=NULL); } +static void testMapping() +{ +#define OP(TYPE, ENUM) \ + testOk1(typeid(ScalarTypeTraits::type)==typeid(TYPE)); \ + testOk1(ENUM==(ScalarType)ScalarTypeID::value); \ + testOk1(ENUM==(ScalarType)ScalarTypeID::value); + OP(boolean, pvBoolean) + OP(int8, pvByte) + OP(int16, pvShort) + OP(int32, pvInt) + OP(int64, pvLong) + OP(uint8, pvUByte) + OP(uint16, pvUShort) + OP(uint32, pvUInt) + OP(uint64, pvULong) + OP(float, pvFloat) + OP(double, pvDouble) + OP(String, pvString) +#undef OP + + testOk1((ScalarType)ScalarTypeID::value==(ScalarType)-1); +} + MAIN(testIntrospect) { - testPlan(124); + testPlan(161); fieldCreate = getFieldCreate(); pvDataCreate = getPVDataCreate(); standardField = getStandardField(); @@ -184,5 +207,6 @@ MAIN(testIntrospect) testScalarArray(); testStructure(); testError(); + testMapping(); return testDone(); } From 22d4a53d6588bd808363eb227032d5766e914597 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 8 Jul 2013 10:51:20 -0400 Subject: [PATCH 077/103] create templateMeta.h Home for common C++ template tricks --- pvDataApp/Makefile | 1 + pvDataApp/misc/sharedVector.h | 19 ++---- pvDataApp/misc/templateMeta.h | 120 ++++++++++++++++++++++++++++++++++ pvDataApp/misc/typeCast.h | 22 +------ 4 files changed, 129 insertions(+), 33 deletions(-) create mode 100644 pvDataApp/misc/templateMeta.h diff --git a/pvDataApp/Makefile b/pvDataApp/Makefile index cde0b2b..3e78645 100644 --- a/pvDataApp/Makefile +++ b/pvDataApp/Makefile @@ -27,6 +27,7 @@ INC += localStaticLock.h INC += typeCast.h INC += printer.h INC += sharedVector.h +INC += templateMeta.h LIBSRCS += byteBuffer.cpp LIBSRCS += bitSet.cpp diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 5f921a9..073d6a2 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -10,6 +10,7 @@ #include "pv/sharedPtr.h" #include "pv/pvIntrospect.h" +#include "pv/templateMeta.h" namespace epics { namespace pvData { @@ -35,10 +36,6 @@ namespace detail { } }; - // avoid adding 'const' twice - template struct decorate_const { typedef const T type; }; - template struct decorate_const { typedef const T type; }; - // How values should be passed as arguments to shared_vector methods // really should use boost::call_traits template struct call_with { typedef T type; }; @@ -230,12 +227,12 @@ class shared_vector : public detail::shared_vector_base public: typedef E value_type; typedef E& reference; - typedef typename detail::decorate_const::type& const_reference; + typedef typename meta::decorate_const::type& const_reference; typedef E* pointer; - typedef typename detail::decorate_const::type* const_pointer; + typedef typename meta::decorate_const::type* const_pointer; typedef E* iterator; typedef std::reverse_iterator reverse_iterator; - typedef typename detail::decorate_const::type* const_iterator; + typedef typename meta::decorate_const::type* const_iterator; typedef std::reverse_iterator const_reverse_iterator; typedef ptrdiff_t difference_type; typedef size_t size_type; @@ -477,16 +474,10 @@ public: }; -namespace detail { - template struct is_void {}; - template<> struct is_void { typedef void type; }; - template<> struct is_void { typedef void type; }; -} - //! Specialization for storing untyped pointers //! Does not allow access or iteration of contents template -class shared_vector::type > +class shared_vector::type > : public detail::shared_vector_base { typedef detail::shared_vector_base base_t; diff --git a/pvDataApp/misc/templateMeta.h b/pvDataApp/misc/templateMeta.h new file mode 100644 index 0000000..cd82f48 --- /dev/null +++ b/pvDataApp/misc/templateMeta.h @@ -0,0 +1,120 @@ +/** + * 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. + */ +/** C++ Template meta programming helpers + */ +#ifndef TEMPLATEMETA_H +#define TEMPLATEMETA_H + +// gently nudge the compiler to inline our wrappers +// Warning: Only use this when the template body is *small*. +// You have been warned! +#if defined(__GNUC__) && __GNUC__>=3 +# define FORCE_INLINE __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +# define FORCE_INLINE __forceinline +#else +# define FORCE_INLINE inline +#endif + +namespace epics { namespace pvData { +namespace meta { + +/** If needed, add the 'const' qualifier to the provided type. + * + * Avoids adding the const qualifier twice (aka 'const const int') + @code + assert(typeid(decorate_const::type)==typeid(const int)); + assert(typeid(decorate_const::type)==typeid(const int)); + @endcode + */ +template struct decorate_const { typedef const T type; }; +template struct decorate_const { typedef const T type; }; + +/** Remove the 'const' qualifier if present + @code + assert(typeid(strip_const::type)==typeid(int)); + assert(typeid(strip_const::type)==typeid(int)); + @endcode + */ +template struct strip_const { typedef T type; }; +template struct strip_const { typedef T type; }; + +/** test to allow specialization only when A!=B + * + @code + template + struct myTemp {...}; + + // specialization when A==B + template + struct myTemp {...}; + + // specialization for A is 'int', + // enabler needed to remove ambiguity when B is 'int'. + template + struct myTemp::type> + {...}; + @endcode + */ +template +struct not_same_type {typedef R type;}; +template +struct not_same_type {}; + +//! Select if both A and B have the same root type (excluding const qualifier) +template struct same_root {}; +template struct same_root { typedef R type; }; +template struct same_root { typedef R type; }; +template struct same_root { typedef R type; }; + +namespace detail { + struct _const_yes {}; + struct _const_no {}; + template struct _has_const { typedef _const_no type; }; + template struct _has_const { typedef _const_yes type; }; + + template struct _same_type {}; + template struct _same_type { typedef R type; }; +} // namespace detail + +//! Check if both A and B are either const or non-const. +template +struct same_const : + public detail::_same_type::type, + typename detail::_has_const::type, + R> +{}; + +/** test if provided type is 'void' or 'const void' + * + * Avoid having to explicitly specialize for both + @code + template + struct myTemp {...}; + + // specialization when A is 'void' or 'const void' + template + struct myTemp::type> {...}; + @endcode + */ +template struct is_void {}; +template struct is_void { typedef R type; }; +template struct is_void { typedef R type; }; + +//! Inverse of is_void +template struct is_not_void { typedef R type; }; +template<> struct is_not_void {}; +template<> struct is_not_void {}; + +//! Enabler to ensure that both conditions A and B are true +template +struct _and {}; +template +struct _and { typedef R type; }; + +}}} + +#endif // TEMPLATEMETA_H diff --git a/pvDataApp/misc/typeCast.h b/pvDataApp/misc/typeCast.h index e27c585..8bf33be 100644 --- a/pvDataApp/misc/typeCast.h +++ b/pvDataApp/misc/typeCast.h @@ -14,15 +14,7 @@ #include #include - -// gently nudge the compiler to inline our wrappers -#if defined(__GNUC__) && __GNUC__>=3 -# define FORCE_INLINE __attribute__((always_inline)) inline -#elif defined(_MSC_VER) -# define FORCE_INLINE __forceinline -#else -# define FORCE_INLINE inline -#endif +#include namespace epics { namespace pvData { @@ -51,12 +43,6 @@ namespace detail { template<> struct cast_arg { typedef const String& arg; }; - // test to allow specialization only when A!=B - template - struct not_same_type {typedef R type;}; - template - struct not_same_type {}; - // trick std::ostream into treating char's as numbers // by promoting char to int template @@ -87,7 +73,7 @@ namespace detail { // print POD to string // when String!=FROM template - struct cast_helper::type> { + struct cast_helper::type> { static String op(FROM from) { typedef typename print_cast::type ptype; std::ostringstream strm; @@ -101,7 +87,7 @@ namespace detail { // parse POD from string // TO!=String template - struct cast_helper::type> { + struct cast_helper::type> { static FORCE_INLINE TO op(const String& from) { TO ret; parseToPOD(from, &ret); @@ -175,6 +161,4 @@ void castUnsafeV(size_t count, ScalarType to, void *dest, ScalarType from, const }} // end namespace -#undef FORCE_INLINE - #endif // PVTYPECAST_H From 3c7a738ffcfbc08ebff10f3626bff64f774c62e8 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 8 Jul 2013 09:59:48 -0400 Subject: [PATCH 078/103] shared_vector tracks original type --- pvDataApp/misc/sharedVector.h | 46 +++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 073d6a2..718c1ce 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -476,11 +476,13 @@ public: //! Specialization for storing untyped pointers //! Does not allow access or iteration of contents +//! other than as void* or const void* template class shared_vector::type > : public detail::shared_vector_base { typedef detail::shared_vector_base base_t; + ScalarType m_vtype; public: typedef E* pointer; typedef ptrdiff_t difference_type; @@ -488,29 +490,53 @@ public: typedef std::tr1::shared_ptr shared_pointer_type; - shared_vector() :base_t() {} + shared_vector() :base_t(), m_vtype((ScalarType)-1) {} - template - shared_vector(A v, size_t o, size_t c) :base_t(v,o,c) {} + shared_vector(pointer v, size_t o, size_t c) + :base_t(v,o,c), m_vtype((ScalarType)-1) {} + + template + shared_vector(pointer d, B b, size_t o, size_t c) + :base_t(d,b,o,c), m_vtype((ScalarType)-1) {} template shared_vector(const std::tr1::shared_ptr& d, size_t o, size_t c) - :base_t(d,o,c) {} - - template - shared_vector(A d, B b, size_t o, size_t c) - :base_t(d,b,o,c) {} + :base_t(d,o,c), m_vtype((ScalarType)-1) {} template - shared_vector(const shared_vector& o) :base_t(o) {} + shared_vector(const shared_vector& o) + :base_t(o), m_vtype(o.m_vtype) {} - shared_vector(const shared_vector& o) :base_t(o) {} + shared_vector(const shared_vector& o) + :base_t(o), m_vtype(o.m_vtype) {} + + shared_vector& operator=(const shared_vector& o) + { + if(&o!=this) { + this->base_t::operator=(o); + m_vtype = o.m_vtype; + } + return *this; + } + + template + shared_vector& operator=(const shared_vector& o) + { + if(&o!=this) { + this->base_t::operator=(o); + m_vtype = o.m_vtype; + } + return *this; + } size_t max_size() const{return (size_t)-1;} pointer data() const{ return (pointer)(((char*)this->m_data.get())+this->m_offset); } + + shared_vector& set_original_type(ScalarType t) { m_vtype=t; return *this; } + ScalarType original_type() const {return m_vtype;} }; namespace detail { From 74f68c47d338bb1c7d1559a66781848f6c7971da Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 9 Jul 2013 10:32:41 -0400 Subject: [PATCH 079/103] shared_vector_convert Allow converting of shared_vector between types Conversion utilizes castUnsafe(). Converting to/from void is supported. Convert to void is an alias for static_shared_vector_cast(). Convert from void utilizes shared_vector::original_type() and throws std::runtime_error if this is not valid. Casting now handles 'const void' is most places where 'void' can be used. --- pvDataApp/misc/sharedVector.h | 107 ++++++++++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 10 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 718c1ce..d1442f4 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -10,6 +10,7 @@ #include "pv/sharedPtr.h" #include "pv/pvIntrospect.h" +#include "pv/typeCast.h" #include "pv/templateMeta.h" namespace epics { namespace pvData { @@ -540,27 +541,96 @@ public: }; namespace detail { - template struct shared_vector_caster {}; + template + struct shared_vector_caster {}; - template - struct shared_vector_caster { - static inline shared_vector op(const shared_vector& src) { - return shared_vector( - std::tr1::static_pointer_cast(src.dataPtr()), + // Cast from non-void to 'void' or 'const void' + template + struct shared_vector_caster, meta::is_not_void >::type + > + { + static inline shared_vector op(const shared_vector& src) { + return shared_vector( + std::tr1::static_pointer_cast(src.dataPtr()), src.dataOffset()*sizeof(FROM), - src.dataCount()*sizeof(FROM)); + src.dataCount()*sizeof(FROM)) + .set_original_type((ScalarType)ScalarTypeID::value); } }; - template - struct shared_vector_caster { - static inline shared_vector op(const shared_vector& src) { + // Cast from 'void' or 'const void' to non-void + template + struct shared_vector_caster, meta::is_void >::type + > + { + static inline shared_vector op(const shared_vector& src) { return shared_vector( std::tr1::static_pointer_cast(src.dataPtr()), src.dataOffset()/sizeof(TO), src.dataCount()/sizeof(TO)); } }; + + + // Default to type conversion using castUnsafe (C++ type casting) on each element + template + struct shared_vector_converter { + static inline shared_vector op(const shared_vector& src) + { + shared_vector ret(src.size()); + std::transform(src.begin(), src.end(), ret.begin(), castUnsafe); + return ret; + } + }; + + // copy reference when types are the same (excluding const qualifiers) + template + struct shared_vector_converter::type > { + static FORCE_INLINE shared_vector op(const shared_vector& src) { + return src; + } + }; + + // "convert" to 'void' or 'const void from non-void + // is an alias for shared_vector_cast() + template + struct shared_vector_converter, meta::is_not_void >::type + > + { + static FORCE_INLINE shared_vector op(const shared_vector& src) { + return shared_vector_caster::op(src); + } + }; + + // convert from void uses original type or throws an exception. + template + struct shared_vector_converter, meta::is_void >::type + > + { + static shared_vector op(const shared_vector& src) { + typedef typename meta::strip_const::type to_t; + ScalarType stype = src.original_type(), + dtype = (ScalarType)ScalarTypeID::value; + if(stype==dtype) { + // no convert needed + return shared_vector_caster::op(src); + } else { + // alloc and convert + shared_vector ret(src.size()/ScalarTypeFunc::elementSize(stype)); + castUnsafeV(ret.size(), + (ScalarType)ScalarTypeID::value, + static_cast(ret.data()), + stype, + static_cast(src.data())); + return ret; + } + } + }; + } /** @brief Allow casting of shared_vector between types @@ -578,6 +648,23 @@ static_shared_vector_cast(const shared_vector& src) return detail::shared_vector_caster::op(src); } +/** @brief Allow converting of shared_vector between types + * + * Conversion utilizes castUnsafe(). + * + * Converting to/from void is supported. Convert to void + * is an alias for static_shared_vector_cast(). + * Convert from void utilizes shared_vector::original_type() + * and throws std::runtime_error if this is not valid. + */ +template +static inline +shared_vector +shared_vector_convert(const shared_vector& src) +{ + return detail::shared_vector_converter::op(src); +} + //! Allows casting from const TYPE -> TYPE. template static inline From 46feb86a995399333424cdfb2dc5b4a3b8839eef Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 8 Jul 2013 11:28:05 -0400 Subject: [PATCH 080/103] test shared_vector_convert --- testApp/misc/testSharedVector.cpp | 47 ++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/testApp/misc/testSharedVector.cpp b/testApp/misc/testSharedVector.cpp index 8895124..edcd1d7 100644 --- a/testApp/misc/testSharedVector.cpp +++ b/testApp/misc/testSharedVector.cpp @@ -407,6 +407,50 @@ static void testNonPOD() testOk1(structs2[1].get()==temp); } +static void testVectorConvert() +{ + testDiag("Test shared_vector_convert"); + + epics::pvData::shared_vector ints(6, 42), moreints; + epics::pvData::shared_vector floats; + epics::pvData::shared_vector strings; + epics::pvData::shared_vector voids; + + testOk1(ints.unique()); + + // no-op convert. Just returns another reference + moreints = epics::pvData::shared_vector_convert(ints); + + testOk1(!ints.unique()); + moreints.clear(); + + // conversion when both types are known. + // returns a new vector + floats = epics::pvData::shared_vector_convert(ints); + + testOk1(ints.unique()); + testOk1(floats.size()==ints.size()); + testOk1(floats.at(0)==42.0); + + // convert to void is static_shared_vector_cast() + // returns a reference + voids = epics::pvData::shared_vector_convert(ints); + + testOk1(!ints.unique()); + testOk1(voids.size()==ints.size()*sizeof(int)); + + // convert from void uses shared_vector::original_type() + // to find that the actual type is 'int'. + // returns a new vector + strings = epics::pvData::shared_vector_convert(voids); + + voids.clear(); + + testOk1(ints.unique()); + testOk1(strings.size()==ints.size()); + testOk1(strings.at(0)=="42"); +} + static void testWeak() { testDiag("Test weak_ptr counting"); @@ -434,7 +478,7 @@ static void testWeak() MAIN(testSharedVector) { - testPlan(122); + testPlan(132); testDiag("Tests for shared_vector"); testDiag("sizeof(shared_vector)=%lu", @@ -450,6 +494,7 @@ MAIN(testSharedVector) testPush(); testVoid(); testNonPOD(); + testVectorConvert(); testWeak(); return testDone(); } From 79eeb0fa2ace1872edb859ddda9e318181199262 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 8 Jul 2013 14:47:11 -0400 Subject: [PATCH 081/103] update PVScalar and PVScalarValue hide the void* members for now. Define PVScalarValue::getAs and putFrom to give a more efficient implementation. --- pvDataApp/pv/pvData.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index fd7cea4..fcb2758 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -103,6 +103,8 @@ class PVScalarArray; class PVStructure; + +template class PVScalarValue; template class PVValueArray; @@ -397,6 +399,10 @@ std::ostream& operator<<(std::ostream& o, const PVField& f); * PVScalar is the base class for each scalar field. */ class PVScalar : public PVField { + // friend our child class(s) so that it + // can call protected methods of other + // PVScalar instances. + template friend class PVScalarValue; public: POINTER_DEFINITIONS(PVScalar); /** @@ -427,7 +433,9 @@ public: this->getAs((void*)&result, ID); return result; } +protected: virtual void getAs(void *, ScalarType) const = 0; +public: /** * Convert and assign the provided value. @@ -443,7 +451,9 @@ public: inline void putFrom(typename ScalarTypeTraits::type val) { this->putFrom((const void*)&val, ID); } +protected: virtual void putFrom(const void *, ScalarType) = 0; +public: virtual void assign(const PVScalar&) = 0; @@ -498,6 +508,19 @@ public: put(value); } + template + inline typename ScalarTypeTraits::type getAs() const { + typedef typename ScalarTypeTraits::type to_t; + to_t result(castUnsafe(get())); + return result; + } + + template + inline void putFrom(typename ScalarTypeTraits::type val) { + typedef typename ScalarTypeTraits::type from_t; + put(castUnsafe(val)); + } + protected: PVScalarValue(ScalarConstPtr const & scalar) : PVScalar(scalar) {} From c0e9dcff217d7ac53fc67353ddcb791b74095cb0 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 9 Jul 2013 11:19:21 -0400 Subject: [PATCH 082/103] revise static_shared_vector_cast Move the work into a special ctor to allow full inline of casting wrapper Prevent static_shared_vector_cast from casting const <-> non-const --- pvDataApp/misc/sharedVector.h | 71 ++++++++++++++++------------------- 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index d1442f4..d932b19 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -200,6 +200,9 @@ namespace detail { size_t dataCount() const { return m_count; } size_t dataTotal() const { return m_total; } }; + + + struct _shared_vector_cast_tag {}; } /** @brief A holder for a contigious piece of memory. @@ -297,6 +300,16 @@ public: template shared_vector(const shared_vector& o) :base_t(o) {} + //! @internal + //! Internal for static_shared_vector_cast + template + shared_vector(const shared_vector &src, + typename meta::is_void::type) + :base_t(std::tr1::static_pointer_cast(src.dataPtr()), + src.dataOffset()/sizeof(E), + src.dataCount()/sizeof(E)) + {} + size_t max_size() const{return ((size_t)-1)/sizeof(E);} size_t capacity() const { return this->m_total; } @@ -511,6 +524,17 @@ public: shared_vector(const shared_vector& o) :base_t(o), m_vtype(o.m_vtype) {} + //! @internal + //! Internal for static_shared_vector_cast + template + shared_vector(const shared_vector &src, + typename meta::is_not_void::type) + :base_t(std::tr1::static_pointer_cast(src.dataPtr()), + src.dataOffset()*sizeof(FROM), + src.dataCount()*sizeof(FROM)) + ,m_vtype((ScalarType)ScalarTypeID::value) + {} + shared_vector& operator=(const shared_vector& o) { if(&o!=this) { @@ -541,38 +565,6 @@ public: }; namespace detail { - template - struct shared_vector_caster {}; - - // Cast from non-void to 'void' or 'const void' - template - struct shared_vector_caster, meta::is_not_void >::type - > - { - static inline shared_vector op(const shared_vector& src) { - return shared_vector( - std::tr1::static_pointer_cast(src.dataPtr()), - src.dataOffset()*sizeof(FROM), - src.dataCount()*sizeof(FROM)) - .set_original_type((ScalarType)ScalarTypeID::value); - } - }; - - // Cast from 'void' or 'const void' to non-void - template - struct shared_vector_caster, meta::is_void >::type - > - { - static inline shared_vector op(const shared_vector& src) { - return shared_vector( - std::tr1::static_pointer_cast(src.dataPtr()), - src.dataOffset()/sizeof(TO), - src.dataCount()/sizeof(TO)); - } - }; - // Default to type conversion using castUnsafe (C++ type casting) on each element template @@ -601,7 +593,7 @@ namespace detail { > { static FORCE_INLINE shared_vector op(const shared_vector& src) { - return shared_vector_caster::op(src); + return shared_vector(src, detail::_shared_vector_cast_tag()); } }; @@ -617,7 +609,7 @@ namespace detail { dtype = (ScalarType)ScalarTypeID::value; if(stype==dtype) { // no convert needed - return shared_vector_caster::op(src); + return shared_vector(src, detail::_shared_vector_cast_tag()); } else { // alloc and convert shared_vector ret(src.size()/ScalarTypeFunc::elementSize(stype)); @@ -641,11 +633,12 @@ namespace detail { * are integer multiples of the size of the destination type. */ template -static inline +static FORCE_INLINE shared_vector -static_shared_vector_cast(const shared_vector& src) +static_shared_vector_cast(const shared_vector& src, + typename meta::same_const::type = 0) { - return detail::shared_vector_caster::op(src); + return shared_vector(src, detail::_shared_vector_cast_tag()); } /** @brief Allow converting of shared_vector between types @@ -658,7 +651,7 @@ static_shared_vector_cast(const shared_vector& src) * and throws std::runtime_error if this is not valid. */ template -static inline +static FORCE_INLINE shared_vector shared_vector_convert(const shared_vector& src) { @@ -667,7 +660,7 @@ shared_vector_convert(const shared_vector& src) //! Allows casting from const TYPE -> TYPE. template -static inline +static FORCE_INLINE shared_vector const_shared_vector_cast(const shared_vector& src) { From 0c4ef8f079efb45f7a5239a2a5dde60b16405c38 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 8 Jul 2013 16:35:58 -0400 Subject: [PATCH 083/103] PV* use shared_vector_convert --- pvDataApp/factory/printer.cpp | 2 +- pvDataApp/pv/pvData.h | 87 +++++++++++++---------------------- 2 files changed, 32 insertions(+), 57 deletions(-) diff --git a/pvDataApp/factory/printer.cpp b/pvDataApp/factory/printer.cpp index 1776a1d..23f4d72 100644 --- a/pvDataApp/factory/printer.cpp +++ b/pvDataApp/factory/printer.cpp @@ -176,7 +176,7 @@ void PrinterPlain::encodeScalar(const PVScalar& pv) void PrinterPlain::encodeArray(const PVScalarArray& pv) { indentN(S(), ilvl); - shared_vector temp; + shared_vector temp; pv.getAs(temp); S() << pv.getScalarArray()->getID() << " " diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index fcb2758..0a9e3cd 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -693,23 +693,27 @@ public: */ const ScalarArrayConstPtr getScalarArray() const ; +protected: + virtual void _getAsVoid(shared_vector&) const = 0; + virtual void _putFromVoid(const shared_vector&) = 0; +public: + /** - * Fetch the current value and convert to the requeted type. + * Fetch the current value and convert to the requested type. * * A copy is made if the requested type does not match * the element type. If the types do match then * no copy is made. */ template - inline void - getAs(shared_vector::type>& out) const + void + getAs(shared_vector::type>& out) const { - shared_vector temp(static_shared_vector_cast(out)); - getAs(ID, temp); - out = static_shared_vector_cast::type>(temp); + typedef typename ScalarTypeTraits::type dest_type; + shared_vector temp; + _getAsVoid(temp); + out = shared_vector_convert(temp); } - virtual void - getAs(ScalarType, shared_vector& out) const = 0; /** * Assign the given value after conversion. @@ -736,12 +740,11 @@ public: * Calls postPut() */ template - inline void putFrom(const shared_vector::type>& inp) + inline void putFrom(const shared_vector::type>& inp) { - shared_vector temp(static_shared_vector_cast(inp)); - putFrom(ID, temp); + shared_vector temp(static_shared_vector_cast(inp)); + _putFromVoid(temp); } - virtual void putFrom(ScalarType, const shared_vector&) = 0; /** * Assign the given value after conversion. @@ -766,7 +769,11 @@ public: * If the types do match then a new refernce to the provided * data is kept. */ - virtual void assign(PVScalarArray& pv) = 0; + void assign(PVScalarArray& pv) { + shared_vector temp; + pv._getAsVoid(temp); + _putFromVoid(temp); + } protected: PVScalarArray(ScalarArrayConstPtr const & scalarArray); @@ -1230,23 +1237,20 @@ public: return o << *(this->get() + index); } - virtual void - getAs(ScalarType id, ::epics::pvData::shared_vector& out) const +protected: + virtual void _getAsVoid(epics::pvData::shared_vector& out) const { - const svector& data(this->viewUnsafe()); - ::epics::pvData::shared_vector temp(static_shared_vector_cast(data)); - if(id==typeCode) { - out = temp; // no convert = no copy - } else { - //TODO: reuse out if possible?? - ::epics::pvData::shared_vector vcopy(ScalarTypeFunc::allocArray(id, data.size())); - - castUnsafeV(data.size(), id, vcopy.data(), typeCode, temp.data()); - - out.swap(vcopy); - } + out = static_shared_vector_cast(this->view()); } + virtual void _putFromVoid(const epics::pvData::shared_vector& in) + { + // TODO: try to re-use storage + replace(shared_vector_convert(in)); + } + +public: + virtual size_t copyOut(ScalarType id, void* ptr, size_t olen) const { const svector& data(this->viewUnsafe()); @@ -1256,24 +1260,6 @@ public: return len; } - virtual void - putFrom(ScalarType id, const ::epics::pvData::shared_vector& inp) - { - if(id==typeCode) { - svector next(static_shared_vector_cast(inp)); - this->swap(next); // no convert == no copy - } else { - size_t len = inp.size() / ScalarTypeFunc::elementSize(id); - svector result(this->take()); - result.resize(len); - - castUnsafeV(len, typeCode, result.data(), id, inp.data()); - - this->swap(result); - } - this->postPut(); - } - virtual void copyIn(ScalarType id, const void* ptr, size_t len) { svector data(this->take()); @@ -1287,17 +1273,6 @@ public: this->postPut(); } - virtual void assign(PVScalarArray& pv) - { - if(this==&pv) - return; - ::epics::pvData::shared_vector temp; - pv.getAs(typeCode, temp); - svector next(static_shared_vector_cast(temp)); - this->swap(next); - this->postPut(); - } - protected: PVValueArray(ScalarArrayConstPtr const & scalar) : base_t(scalar) {} From cdcbfe73781bee08c7f78892a2d5643737d89bd6 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 8 Jul 2013 18:58:12 -0400 Subject: [PATCH 084/103] update testPVScalarArray --- testApp/pv/testPVScalarArray.cpp | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/testApp/pv/testPVScalarArray.cpp b/testApp/pv/testPVScalarArray.cpp index 67cbd6e..54f3fb8 100644 --- a/testApp/pv/testPVScalarArray.cpp +++ b/testApp/pv/testPVScalarArray.cpp @@ -102,6 +102,13 @@ static void testBasic() arr1->replace(data); testOk1(!data.unique()); + { + typename PVT::const_svector avoid; + arr1->PVScalarArray::getAs<(ScalarType)ScalarTypeID::value>(avoid); + testOk1(avoid.data()==data.data()); + testOk1(avoid.data()==arr1->view().data()); + } + testOk1(arr1->getLength()==data.size()); testOk1(*arr1!=*arr2); @@ -121,15 +128,18 @@ static void testBasic() testOk1(arr2->getLength()==0); testOk1(data.size()==arr1->getLength()); - PVIntArray::svector idata; + PVIntArray::const_svector idata; arr1->PVScalarArray::getAs(idata); - testOk1(idata[1]==10); + testOk1(idata.at(1)==10); - idata.make_unique(); - idata[1] = 42; + PVIntArray::svector wdata(const_shared_vector_cast(idata)); + idata.clear(); + wdata.make_unique(); - arr1->PVScalarArray::putFrom(idata); + wdata.at(1) = 42; + + arr1->PVScalarArray::putFrom(wdata); testOk1(castUnsafe(arr1->view()[1])==42); } @@ -152,21 +162,22 @@ static void testShare() testOk1(!idata.unique()); idata.clear(); + PVIntArray::const_svector cdata; - sarr->PVScalarArray::getAs(idata); // copy and convert + sarr->PVScalarArray::getAs(cdata); // copy and convert - testOk1(idata.unique()); + testOk1(cdata.unique()); - iarr->PVScalarArray::getAs(idata); // take a reference + iarr->PVScalarArray::getAs(cdata); // take a reference - testOk1(!idata.unique()); + testOk1(!cdata.unique()); } } // end namespace MAIN(testPVScalarArray) { - testPlan(146); + testPlan(156); testFactory(); testBasic(); testBasic(); From cff59487ae60fe5c8e509a4ee0fc373ba18604a8 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 9 Jul 2013 18:21:13 -0400 Subject: [PATCH 085/103] shared_vector freeze and thaw --- pvDataApp/misc/sharedVector.h | 36 ++++++++++++++++++++++++++++++++ testApp/pv/testPVScalarArray.cpp | 4 +--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index d932b19..bc90ae8 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -670,6 +670,42 @@ const_shared_vector_cast(const shared_vector& src) src.dataCount()); } +/** @brief transform a shared_vector to shared_vector + * + * Transform a reference to mutable data into a reference to read-only data. + * Throws an exception unless the reference to mutable data is unique. + * On success the reference to mutable data is cleared. + */ +template +static FORCE_INLINE +shared_vector::type> +freeze(SRC& src) +{ + if(!src.unique()) + throw std::runtime_error("Can't freeze non-unique vector"); + typedef typename meta::decorate_const::type const_value; + shared_vector ret(src); + src.clear(); + return ret; +} + +/** @brief transform a shared_vector to shared_vector + * + * Transform a reference to read-only data into a unique reference to mutable data. + * + * The reference to read-only data is cleared. + */ +template +static FORCE_INLINE +shared_vector::type> +thaw(SRC& src) +{ + typedef typename meta::strip_const::type value; + shared_vector ret(const_shared_vector_cast(src)); + src.clear(); + ret.make_unique(); + return ret; +} namespace ScalarTypeFunc { diff --git a/testApp/pv/testPVScalarArray.cpp b/testApp/pv/testPVScalarArray.cpp index 54f3fb8..e5de290 100644 --- a/testApp/pv/testPVScalarArray.cpp +++ b/testApp/pv/testPVScalarArray.cpp @@ -133,9 +133,7 @@ static void testBasic() testOk1(idata.at(1)==10); - PVIntArray::svector wdata(const_shared_vector_cast(idata)); - idata.clear(); - wdata.make_unique(); + PVIntArray::svector wdata(thaw(idata)); wdata.at(1) = 42; From 2e3cbed5205e2d51400b94143b83ea9b2d50f5eb Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 16 Jul 2013 10:47:11 -0400 Subject: [PATCH 086/103] restart testConvert start with fromStringArray --- testApp/pv/testConvert.cpp | 420 ++++--------------------------------- 1 file changed, 37 insertions(+), 383 deletions(-) diff --git a/testApp/pv/testConvert.cpp b/testApp/pv/testConvert.cpp index c6264b1..33258d4 100644 --- a/testApp/pv/testConvert.cpp +++ b/testApp/pv/testConvert.cpp @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include @@ -23,390 +25,42 @@ #include using namespace epics::pvData; -using std::tr1::static_pointer_cast; -static bool debug = false; - -static FieldCreatePtr fieldCreate; -static PVDataCreatePtr pvDataCreate; -static StandardFieldPtr standardField; -static StandardPVFieldPtr standardPVField; -static ConvertPtr convert; -static String builder(""); - -static void testConvertScalar(FILE *fd) { - PVScalarPtr pvBytePtr = pvDataCreate->createPVScalar(pvByte); - PVScalarPtr pvUBytePtr = pvDataCreate->createPVScalar(pvUByte); - PVScalarPtr pvShortPtr = pvDataCreate->createPVScalar(pvShort); - PVScalarPtr pvUShortPtr = pvDataCreate->createPVScalar(pvUShort); - PVScalarPtr pvIntPtr = pvDataCreate->createPVScalar(pvInt); - PVScalarPtr pvUIntPtr = pvDataCreate->createPVScalar(pvUInt); - PVScalarPtr pvLongPtr = pvDataCreate->createPVScalar(pvLong); - PVScalarPtr pvULongPtr = pvDataCreate->createPVScalar(pvULong); - PVScalarPtr pvFloatPtr = pvDataCreate->createPVScalar(pvFloat); - PVScalarPtr pvDoublePtr = pvDataCreate->createPVScalar(pvDouble); - - fprintf(fd,"testConvertScalar\n"); - if(debug) fprintf(fd,"\nfromByte\n"); - int8 bval = 127; - for(int i=0; i<3; i++) { - convert->fromByte(pvBytePtr, bval); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromByte(pvUBytePtr, bval); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromByte(pvShortPtr, bval); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromByte(pvUShortPtr, bval); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromByte(pvIntPtr, bval); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromByte(pvUIntPtr, bval); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromByte(pvLongPtr, bval); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromByte(pvULongPtr, bval); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromByte(pvFloatPtr, bval); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromByte(pvDoublePtr, bval); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvUBytePtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvUBytePtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - bval++; - } - fprintf(fd,"fromByte PASSED\n"); - - if(debug) fprintf(fd,"\nfromShort\n"); - int16 sval = 0x7fff; - for(int i=0; i<3; i++) { - convert->fromShort(pvBytePtr, sval); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromShort(pvUBytePtr, sval); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromShort(pvShortPtr, sval); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromShort(pvUShortPtr, sval); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromShort(pvIntPtr, sval); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromShort(pvUIntPtr, sval); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromShort(pvLongPtr, sval); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromShort(pvULongPtr, sval); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromShort(pvFloatPtr, sval); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromShort(pvDoublePtr, sval); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvUShortPtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvUShortPtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - sval++; - } - fprintf(fd,"fromShort PASSED\n"); - - if(debug) fprintf(fd,"\nfromInt\n"); - int32 ival = 0x7fffffff; - for(int i=0; i<3; i++) { - convert->fromInt(pvBytePtr, ival); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromInt(pvUBytePtr, ival); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromInt(pvShortPtr, ival); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromInt(pvUShortPtr, ival); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromInt(pvIntPtr, ival); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromInt(pvUIntPtr, ival); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromInt(pvLongPtr, ival); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromInt(pvULongPtr, ival); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromInt(pvFloatPtr, ival); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromInt(pvDoublePtr, ival); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvUIntPtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvUIntPtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - ival++; - } - fprintf(fd,"fromInt PASSED\n"); - - if(debug) fprintf(fd,"\nfromLong\n"); - int64 lval = 0x7fffffffffffffffLL; - for(int i=0; i<3; i++) { - convert->fromLong(pvBytePtr, lval); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromLong(pvUBytePtr, lval); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromLong(pvShortPtr, lval); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromLong(pvUShortPtr, lval); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromLong(pvIntPtr, lval); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromLong(pvUIntPtr, lval); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromLong(pvLongPtr, lval); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromLong(pvULongPtr, lval); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromLong(pvFloatPtr, lval); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromLong(pvDoublePtr, lval); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvULongPtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvULongPtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - lval++; - } - fprintf(fd,"fromLong PASSED\n"); - - if(debug) fprintf(fd,"\nfromUByte\n"); - uint8 ubval = 127; - for(int i=0; i<3; i++) { - convert->fromUByte(pvBytePtr, ubval); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromUByte(pvUBytePtr, ubval); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromUByte(pvShortPtr, ubval); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromUByte(pvUShortPtr, ubval); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromUByte(pvIntPtr, ubval); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromUByte(pvUIntPtr, ubval); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromUByte(pvLongPtr, ubval); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromUByte(pvULongPtr, ubval); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromUByte(pvFloatPtr, ubval); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromUByte(pvDoublePtr, ubval); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvUBytePtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvUBytePtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - ubval++; - } - fprintf(fd,"fromUByte PASSED\n"); - - if(debug) fprintf(fd,"\nfromUShort\n"); - uint16 usval = 0x7fff; - for(int i=0; i<3; i++) { - convert->fromUShort(pvBytePtr, usval); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromUShort(pvUBytePtr, usval); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromUShort(pvShortPtr, usval); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromUShort(pvUShortPtr, usval); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromUShort(pvIntPtr, usval); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromUShort(pvUIntPtr, usval); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromUShort(pvLongPtr, usval); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromUShort(pvULongPtr, usval); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromUShort(pvFloatPtr, usval); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromUShort(pvDoublePtr, usval); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvUShortPtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvUShortPtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - usval++; - } - fprintf(fd,"fromUShort PASSED\n"); - - if(debug) fprintf(fd,"\nfromUInt\n"); - uint32 uival = 0x7fffffff; - for(int i=0; i<3; i++) { - convert->fromUInt(pvBytePtr, uival); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromUInt(pvUBytePtr, uival); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromUInt(pvShortPtr, uival); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromUInt(pvUShortPtr, uival); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromUInt(pvIntPtr, uival); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromUInt(pvUIntPtr, uival); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromUInt(pvLongPtr, uival); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromUInt(pvULongPtr, uival); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromUInt(pvFloatPtr, uival); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromUInt(pvDoublePtr, uival); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvUIntPtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvUIntPtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - uival++; - } - fprintf(fd,"fromUInt PASSED\n"); - - if(debug) fprintf(fd,"\nfromULong\n"); - uint64 ulval = 0x7fffffffffffffffLL; - for(int i=0; i<3; i++) { - convert->fromULong(pvBytePtr, ulval); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromULong(pvUBytePtr, ulval); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromULong(pvShortPtr, ulval); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromULong(pvUShortPtr, ulval); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromULong(pvIntPtr, ulval); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromULong(pvUIntPtr, ulval); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromULong(pvLongPtr, ulval); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromULong(pvULongPtr, ulval); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromULong(pvFloatPtr, ulval); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromULong(pvDoublePtr, ulval); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvULongPtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvULongPtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - ulval++; - } - fprintf(fd,"fromULong PASSED\n"); -} - -int main(int argc,char *argv[]) +static void testFromString() { - char *fileName = 0; - if(argc>1) fileName = argv[1]; - FILE * fd = stdout; - if(fileName!=0 && fileName[0]!=0) { - fd = fopen(fileName,"w+"); - } - fieldCreate = getFieldCreate(); - pvDataCreate = getPVDataCreate(); - standardField = getStandardField(); - standardPVField = getStandardPVField(); - convert = getConvert(); - testConvertScalar(fd); - fprintf(fd,"THIS NEEDS MANY MORE TESTS AND ASSERTS\n"); - return(0); + StringArray inp(2); + + inp[0] = "0"; + inp[1] = "1"; + + PVScalarArrayPtr A(getPVDataCreate()->createPVScalarArray(pvInt)); + PVScalarArrayPtr B(getPVDataCreate()->createPVScalarArray(pvString)); + + testOk1(2==getConvert()->fromStringArray(A, 0, inp.size(), inp, 0)); + testOk1(2==getConvert()->fromStringArray(B, 0, inp.size(), inp, 0)); + + PVIntArrayPtr Ax(std::tr1::static_pointer_cast(A)); + PVStringArrayPtr Bx(std::tr1::static_pointer_cast(B)); + + PVIntArray::const_svector Adata(Ax->view()); + PVStringArray::const_svector Bdata(Bx->view()); + + testOk1(inp.size()==Adata.size()); + if(inp.size()==Adata.size()) + testOk1(Adata[0]==0 && Adata[1]==1); + else + testFail("Can't compare"); + + testOk1(inp.size()==Bdata.size()); + if(inp.size()==Bdata.size()) + testOk1(Bdata[0]=="0" && Bdata[1]=="1"); + else + testFail("Can't compare"); } +MAIN(testConvert) +{ + testPlan(0); + testFromString(); + return testDone(); +} From 6e3a344caaea2bfebdaca81e6c068f5b13b62d69 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 16 Jul 2013 10:48:01 -0400 Subject: [PATCH 087/103] fix Convert::fromStringArray destination should grow to fit --- pvDataApp/factory/Convert.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index dc29861..463989b 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -114,13 +114,20 @@ size_t Convert::fromStringArray(PVScalarArrayPtr const &pv, StringArray const & from, size_t fromOffset) { - assert(offset==0); size_t alen = pv->getLength(); - if(fromOffset>alen) return 0; - alen -= fromOffset; - if(length>alen) length=alen; - pv->copyIn(&from[fromOffset], length); - return length; + + if(offset==0 && length>=alen) { + // replace all existing elements + assert(from.size()>=fromOffset+length); + if(length>alen) + pv->setLength(length); + pv->copyIn(&from[fromOffset], length); + return length; + + } else { + // partial update. + throw std::runtime_error("fromStringArray: partial update not implemented"); + } } size_t Convert::toStringArray(PVScalarArrayPtr const & pv, From 70ae281f45e8f071ffc5520f87e483ea3807b069 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 16 Jul 2013 18:59:04 -0400 Subject: [PATCH 088/103] test freeze/thaw --- testApp/misc/testSharedVector.cpp | 67 ++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/testApp/misc/testSharedVector.cpp b/testApp/misc/testSharedVector.cpp index edcd1d7..bc64f44 100644 --- a/testApp/misc/testSharedVector.cpp +++ b/testApp/misc/testSharedVector.cpp @@ -476,9 +476,73 @@ static void testWeak() testOk1(!data.unique()); } +static void testICE() +{ + testDiag("Test freeze and thaw"); + + epics::pvData::shared_vector A(6, 42), C; + epics::pvData::shared_vector B, D; + + int *check = A.data(); + + // check freeze w/ unique reference + + // clears A and moves reference to B + // no copy + B = epics::pvData::freeze(A); + + testOk1(A.unique()); + testOk1(B.unique()); + testOk1(A.size()==0); + testOk1(B.size()==6); + testOk1(A.data()!=check); + testOk1(B.data()==check); + + D = B; // create second const reference + + // clears D, but reference to B refrence + // to B remains, so a copy is made + C = epics::pvData::thaw(D); + + testOk1(B.unique()); + testOk1(C.unique()); + testOk1(B.size()==6); + testOk1(C.size()==6); + testOk1(B.data()==check); + testOk1(C.data()!=NULL); + testOk1(C.at(0)==42); + + C.clear(); + + // clears B and moves reference to A + // no copy + A = epics::pvData::thaw(B); + + testOk1(A.unique()); + testOk1(B.unique()); + testOk1(A.size()==6); + testOk1(B.size()==0); + testOk1(A.data()==check); + testOk1(B.data()!=check); + + C = A; // create second non-const reference + + testOk1(!A.unique()); + + try { + // would clear A, but remaining reference C + // fails operation. A not cleared + // and exception thrown + B = epics::pvData::freeze(A); + testFail("Froze non-unique vector!"); + } catch(std::runtime_error& e) { + testPass("freeze of non-unique throws runtime_error as expected"); + } +} + MAIN(testSharedVector) { - testPlan(132); + testPlan(153); testDiag("Tests for shared_vector"); testDiag("sizeof(shared_vector)=%lu", @@ -496,5 +560,6 @@ MAIN(testSharedVector) testNonPOD(); testVectorConvert(); testWeak(); + testICE(); return testDone(); } From 5565e4e30c637cca4297ee6d12ecbb8eb389d0ce Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 19 Jul 2013 14:18:04 -0400 Subject: [PATCH 089/103] Convert don't use copyIn or copyOut --- pvDataApp/factory/Convert.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index 463989b..7e60f10 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -119,9 +119,13 @@ size_t Convert::fromStringArray(PVScalarArrayPtr const &pv, if(offset==0 && length>=alen) { // replace all existing elements assert(from.size()>=fromOffset+length); - if(length>alen) - pv->setLength(length); - pv->copyIn(&from[fromOffset], length); + + PVStringArray::svector data(length); + std::copy(from.begin()+fromOffset, + from.begin()+fromOffset+length, + data.begin()); + + pv->putFrom(data); return length; } else { @@ -134,12 +138,13 @@ size_t Convert::toStringArray(PVScalarArrayPtr const & pv, size_t offset, size_t length, StringArray &to, size_t toOffset) { - size_t alen = pv->getLength(); - if(offset>alen) return 0; - alen -= offset; - if(length>alen) length=alen; - pv->copyOut(&to[toOffset], length); - return length; + PVStringArray::const_svector data; + pv->getAs(data); + data.slice(offset, length); + if(toOffset+data.size() > to.size()) + to.resize(toOffset+data.size()); + std::copy(data.begin()+toOffset, data.end(), to.begin()); + return data.size(); } bool Convert::isCopyCompatible(FieldConstPtr const &from, FieldConstPtr const &to) From 105c3185f7e67f10d1834ba3cb3aa96b423f515f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 19 Jul 2013 14:20:55 -0400 Subject: [PATCH 090/103] remove take(), copyIn(), and copyOut(). --- pvDataApp/pv/pvData.h | 73 ++++++------------------------------------- 1 file changed, 9 insertions(+), 64 deletions(-) diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index 0a9e3cd..ef4232b 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -715,19 +715,6 @@ public: out = shared_vector_convert(temp); } - /** - * Assign the given value after conversion. - * - * A copy and element-wise conversion is are always performed. - */ - template - inline size_t copyOut(typename ScalarTypeTraits::type* inp, size_t len) const - { - return copyOut(ID, (void*)inp, len); - } - virtual size_t copyOut(ScalarType, void*, size_t) const = 0; - - /** * Assign the given value after conversion. * @@ -746,20 +733,6 @@ public: _putFromVoid(temp); } - /** - * Assign the given value after conversion. - * - * A copy and element-wise conversion is are always performed. - * - * Calls postPut() - */ - template - inline void copyIn(const typename ScalarTypeTraits::type* inp, size_t len) - { - copyIn(ID, (const void*)inp, len); - } - virtual void copyIn(ScalarType, const void*, size_t) = 0; - /** * Assign the given PVScalarArray's value. * @@ -1063,7 +1036,7 @@ namespace detail { * after the last swap() operation. * * Before you call this directly, consider using - * the take(), reuse(), or replace() methods. + * the reuse(), or replace() methods. */ virtual void swap(svector& other) = 0; @@ -1091,17 +1064,14 @@ namespace detail { return newref; } - //! Remove and return the current array data - //! Does @b not (and should not) call postPut() - inline svector take() - { - svector result; - this->swap(result); - return result; - } - - //! take() with an implied make_unique() - //! Does @b not (and should not) call postPut() + /** Remove and return the current array data + * or an unique copy if shared. + * + * Does @b not (and should not) call postPut() + * + * The returned shared_vector will + * have unique()==true. + */ inline svector reuse() { svector result; @@ -1249,31 +1219,6 @@ protected: replace(shared_vector_convert(in)); } -public: - - virtual size_t copyOut(ScalarType id, void* ptr, size_t olen) const - { - const svector& data(this->viewUnsafe()); - size_t len = std::min(olen, data.size()); - - castUnsafeV(len, id, ptr, typeCode, (const void*)data.data()); - return len; - } - - virtual void copyIn(ScalarType id, const void* ptr, size_t len) - { - svector data(this->take()); - // Will have to re-alloc anyway? If so avoid copying - // data which will only be over-written - if(data.capacity()swap(data); - this->postPut(); - } - -protected: PVValueArray(ScalarArrayConstPtr const & scalar) : base_t(scalar) {} friend class PVDataCreate; From 45bb461c323a27d269aeeea0f659c4cf702efbb8 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 25 Jul 2013 15:26:29 -0400 Subject: [PATCH 091/103] shared_vector require freeze/thaw Remove the implicit cast from non-const to const. Require the use of freeze/thaw when changing between const and non-const. Change argument of const_shared_vector_cast to a non-const shared_vector reference to allow it to be cleared by freeze/thaw. --- pvDataApp/misc/sharedVector.h | 201 ++++++++++++++++++++-------------- 1 file changed, 120 insertions(+), 81 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index bc90ae8..ed3fd11 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -15,28 +15,17 @@ namespace epics { namespace pvData { -template class shared_vector; +template class shared_vector; + +template +static FORCE_INLINE +shared_vector +const_shared_vector_cast(shared_vector& src); namespace detail { template struct default_array_deleter {void operator()(E a){delete[] a;}}; - // Implicit casts allowed during copy construction of shared_vector - template - struct vector_implicit_cast { - // There is intentionally no implmentation here to cause - // compile errors for illegal casts. - //static std::tr1::shared_ptr cast(const std::tr1::shared_ptr); - }; - // non-const -> const - template - struct vector_implicit_cast { - static std::tr1::shared_ptr cast(const std::tr1::shared_ptr input) - { - return std::tr1::shared_ptr(input); - } - }; - // How values should be passed as arguments to shared_vector methods // really should use boost::call_traits template struct call_with { typedef T type; }; @@ -44,6 +33,10 @@ namespace detail { { typedef const std::tr1::shared_ptr& type; }; template<> struct call_with { typedef const std::string& type; }; + struct _shared_vector_freeze_tag {}; + struct _shared_vector_thaw_tag {}; + struct _shared_vector_cast_tag {}; + /* All the parts of shared_vector which * don't need special handling for E=void */ @@ -100,11 +93,33 @@ namespace detail { ,m_count(O.m_count), m_total(O.m_total) {} - template - shared_vector_base(const shared_vector_base& o) - : m_data(vector_implicit_cast::cast(o.m_data)) - , m_offset(o.m_offset), m_count(o.m_count), m_total(o.m_total) - {_null_input();} + protected: + typedef typename meta::strip_const::type _E_non_const; + public: + shared_vector_base(shared_vector_base<_E_non_const>& O, + _shared_vector_freeze_tag) + :m_data() + ,m_offset(O.m_offset) + ,m_count(O.m_count) + ,m_total(O.m_total) + { + if(!O.unique()) + throw std::runtime_error("Can't freeze non-unique vector"); + m_data = O.m_data; + O.clear(); + } + + shared_vector_base(shared_vector& O, + _shared_vector_thaw_tag) + :m_data() + ,m_offset(O.m_offset) + ,m_count(O.m_count) + ,m_total(O.m_total) + { + O.make_unique(); + m_data = std::tr1::const_pointer_cast(O.m_data); + O.clear(); + } //! @brief Copy an existing vector shared_vector_base& operator=(const shared_vector_base& o) @@ -118,19 +133,6 @@ namespace detail { return *this; } - //! @brief Copy an existing vector of a related type - template - shared_vector_base& operator=(const shared_vector_base& o) - { - if(&o!=this) { - m_data=vector_implicit_cast::cast(o.m_data); - m_offset=o.m_offset; - m_count=o.m_count; - m_total=o.m_total; - } - return *this; - } - //! @brief Swap the contents of this vector with another void swap(shared_vector_base& o) { if(&o!=this) { @@ -200,9 +202,6 @@ namespace detail { size_t dataCount() const { return m_count; } size_t dataTotal() const { return m_total; } }; - - - struct _shared_vector_cast_tag {}; } /** @brief A holder for a contigious piece of memory. @@ -223,11 +222,12 @@ namespace detail { * by make_unique() that unique()==true implies exclusive * ownership. */ -template +template class shared_vector : public detail::shared_vector_base { typedef detail::shared_vector_base base_t; typedef typename detail::call_with::type param_type; + typedef typename meta::strip_const::type _E_non_const; public: typedef E value_type; typedef E& reference; @@ -253,14 +253,14 @@ public: //! @brief Allocate (with new[]) a new vector of size c explicit shared_vector(size_t c) - :base_t(new E[c], 0, c) + :base_t(new _E_non_const[c], 0, c) {} //! @brief Allocate (with new[]) a new vector of size c and fill with value e shared_vector(size_t c, param_type e) - :base_t(new E[c], 0, c) + :base_t(new _E_non_const[c], 0, c) { - std::fill_n(this->m_data.get(), this->m_count, e); + std::fill_n((_E_non_const*)this->m_data.get(), this->m_count, e); } /** @brief Build vector from a raw pointer @@ -296,10 +296,6 @@ public: //! @brief Copy an existing vector of same type shared_vector(const shared_vector& o) :base_t(o) {} - //! @brief Copy an existing vector of a related type - template - shared_vector(const shared_vector& o) :base_t(o) {} - //! @internal //! Internal for static_shared_vector_cast template @@ -310,6 +306,17 @@ public: src.dataCount()/sizeof(E)) {} + + shared_vector(shared_vector& O, + detail::_shared_vector_freeze_tag t) + :base_t(O,t) + {} + + shared_vector(shared_vector& O, + detail::_shared_vector_thaw_tag t) + :base_t(O,t) + {} + size_t max_size() const{return ((size_t)-1)/sizeof(E);} size_t capacity() const { return this->m_total; } @@ -325,7 +332,7 @@ public: void reserve(size_t i) { if(this->unique() && i<=this->m_total) return; - pointer temp=new E[i]; + _E_non_const* temp=new _E_non_const[i]; try{ std::copy(begin(), end(), temp); this->m_data.reset(temp, detail::default_array_deleter()); @@ -360,7 +367,7 @@ public: } // must re-allocate :( size_t new_total = std::max(this->m_total, i); - pointer temp=new E[new_total]; + _E_non_const* temp=new _E_non_const[new_total]; try{ // Copy as much as possible from old, // remaining elements are uninitialized. @@ -409,11 +416,17 @@ public: void make_unique() { if(this->unique()) return; - shared_pointer_type d(new E[this->m_total], detail::default_array_deleter()); - std::copy(this->m_data.get()+this->m_offset, - this->m_data.get()+this->m_offset+this->m_count, - d.get()); - this->m_data.swap(d); + typedef typename meta::strip_const::type nE; + nE *d = new nE[this->m_total]; + try { + std::copy(this->m_data.get()+this->m_offset, + this->m_data.get()+this->m_offset+this->m_count, + d); + }catch(...){ + delete[] d; + throw; + } + this->m_data.reset(d, detail::default_array_deleter()); this->m_offset=0; } @@ -517,10 +530,6 @@ public: shared_vector(const std::tr1::shared_ptr& d, size_t o, size_t c) :base_t(d,o,c), m_vtype((ScalarType)-1) {} - template - shared_vector(const shared_vector& o) - :base_t(o), m_vtype(o.m_vtype) {} - shared_vector(const shared_vector& o) :base_t(o), m_vtype(o.m_vtype) {} @@ -535,6 +544,16 @@ public: ,m_vtype((ScalarType)ScalarTypeID::value) {} + shared_vector(shared_vector& O, + detail::_shared_vector_freeze_tag t) + :base_t(O,t) + {} + + shared_vector(shared_vector& O, + detail::_shared_vector_thaw_tag t) + :base_t(O,t) + {} + shared_vector& operator=(const shared_vector& o) { if(&o!=this) { @@ -614,15 +633,14 @@ namespace detail { // alloc and convert shared_vector ret(src.size()/ScalarTypeFunc::elementSize(stype)); castUnsafeV(ret.size(), - (ScalarType)ScalarTypeID::value, + dtype, static_cast(ret.data()), stype, static_cast(src.data())); - return ret; + return const_shared_vector_cast(ret); } } }; - } /** @brief Allow casting of shared_vector between types @@ -658,18 +676,6 @@ shared_vector_convert(const shared_vector& src) return detail::shared_vector_converter::op(src); } -//! Allows casting from const TYPE -> TYPE. -template -static FORCE_INLINE -shared_vector -const_shared_vector_cast(const shared_vector& src) -{ - return shared_vector( - std::tr1::const_pointer_cast(src.dataPtr()), - src.dataOffset(), - src.dataCount()); -} - /** @brief transform a shared_vector to shared_vector * * Transform a reference to mutable data into a reference to read-only data. @@ -681,12 +687,8 @@ static FORCE_INLINE shared_vector::type> freeze(SRC& src) { - if(!src.unique()) - throw std::runtime_error("Can't freeze non-unique vector"); typedef typename meta::decorate_const::type const_value; - shared_vector ret(src); - src.clear(); - return ret; + return shared_vector(src, detail::_shared_vector_freeze_tag()); } /** @brief transform a shared_vector to shared_vector @@ -701,10 +703,47 @@ shared_vector::type> thaw(SRC& src) { typedef typename meta::strip_const::type value; - shared_vector ret(const_shared_vector_cast(src)); - src.clear(); - ret.make_unique(); - return ret; + return shared_vector(src, detail::_shared_vector_thaw_tag()); +} + +namespace detail { + template + struct const_caster {}; + + template + struct const_caster { + static FORCE_INLINE shared_vector op(shared_vector& src) + { + return thaw(src); + } + }; + + template + struct const_caster { + static FORCE_INLINE shared_vector op(shared_vector& src) + { + return freeze(src); + } + }; + + template + struct const_caster { + static FORCE_INLINE shared_vector op(shared_vector& src) + { + shared_vector ret(src); + src.clear(); + return ret; + } + }; +} + +//! Allows casting from const TYPE -> TYPE. +template +static FORCE_INLINE +shared_vector +const_shared_vector_cast(shared_vector& src) +{ + return detail::const_caster::op(src); } From 569bd3b681389a124c27018c0ea7f78dbddf1717 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 25 Jul 2013 17:02:08 -0400 Subject: [PATCH 092/103] update testSharedVector --- testApp/misc/testSharedVector.cpp | 47 ++++++++++--------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/testApp/misc/testSharedVector.cpp b/testApp/misc/testSharedVector.cpp index bc64f44..a1bcd1f 100644 --- a/testApp/misc/testSharedVector.cpp +++ b/testApp/misc/testSharedVector.cpp @@ -204,47 +204,34 @@ static void testConst() testOk1(wr==ror); + int *compare = writable.data(); + + testOk1(writable.unique()); + // can re-target container, but data is R/O - epics::pvData::shared_vector rodata(writable); + epics::pvData::shared_vector rodata(freeze(writable)); epics::pvData::shared_vector::reference wcr = rodata[0]; epics::pvData::shared_vector::const_reference rocr = rodata[0]; testOk1(wcr==rocr); - rodata = writable; - testOk1(rodata.data()==writable.data()); + testOk1(rodata.data()==compare); + writable = thaw(rodata); - // Data is R/W, but container can't be re-targeted - const epics::pvData::shared_vector roref(writable); + testOk1(writable.data()==compare); - // Can't change anything. - const epics::pvData::shared_vector fixed(writable); + rodata = freeze(writable); - testOk1(rodata[1]==100); + testOk1(rodata.data()==compare); - // intentionally modify shared data! - // safe since this thread owns all references. - writable[1]=200; + epics::pvData::shared_vector rodata2(rodata); - testOk1(rodata[1]==200); + testOk1(rodata.data()==rodata2.data()); - epics::pvData::shared_vector::const_iterator a; - epics::pvData::shared_vector::iterator b; - epics::pvData::shared_vector::const_iterator c; + rodata2.make_unique(); - a = writable.begin(); - b = rodata.begin(); - c = rodata.end(); - - testOk1(std::equal(b, c, a)); - - a = writable.cbegin(); - c = rodata.cend(); - - epics::pvData::shared_vector::const_reference x = rodata[1]; - - testOk1(x==200); + testOk1(rodata.data()!=rodata2.data()); } static void testSlice() @@ -359,10 +346,6 @@ static void testVoid() testDiag("Test vecter cast to/from void"); epics::pvData::shared_vector typed(4); - epics::pvData::shared_vector untyped; - epics::pvData::shared_vector constuntyped; - - untyped = epics::pvData::const_shared_vector_cast(constuntyped); epics::pvData::shared_vector untyped2(epics::pvData::static_shared_vector_cast(typed)); @@ -542,7 +525,7 @@ static void testICE() MAIN(testSharedVector) { - testPlan(153); + testPlan(154); testDiag("Tests for shared_vector"); testDiag("sizeof(shared_vector)=%lu", From 9ac030169ac96617c8cfcef43a73bd5fc74b375c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 25 Jul 2013 17:22:16 -0400 Subject: [PATCH 093/103] update pvD array handling Interface only uses shared_vector storage also uses only const. --- pvDataApp/misc/byteBuffer.h | 4 +-- pvDataApp/pv/pvData.h | 61 +++++++++++++++---------------------- 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/pvDataApp/misc/byteBuffer.h b/pvDataApp/misc/byteBuffer.h index 5964668..903daf2 100644 --- a/pvDataApp/misc/byteBuffer.h +++ b/pvDataApp/misc/byteBuffer.h @@ -379,7 +379,7 @@ public: * @param count The number of elements. */ template - inline void putArray(T* values, std::size_t count); + inline void putArray(const T* values, std::size_t count); /** * Get an array of type {@code T} from the byte buffer. * The position is adjusted. @@ -842,7 +842,7 @@ private: } template - inline void ByteBuffer::putArray(T* values, std::size_t count) + inline void ByteBuffer::putArray(const T* values, std::size_t count) { // this avoids int8 specialization, compiler will take care if optimization, -O2 or more if (sizeof(T) == 1) diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index ef4232b..257fd34 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -1022,11 +1022,9 @@ namespace detail { virtual ~PVVectorStorage(){}; // Primative array manipulations - protected: - //! unchecked reference to writable data - //! Please consider the view() method instead of viewUnsafe(). - virtual const svector& viewUnsafe() const = 0; - public: + + //! Fetch a read-only view of the current array data + virtual const_svector view() const = 0; /** Exchange our contents for the provided. * @@ -1038,32 +1036,15 @@ namespace detail { * Before you call this directly, consider using * the reuse(), or replace() methods. */ - virtual void swap(svector& other) = 0; + virtual void swap(const_svector& other) = 0; //! Discard current contents and replaced with the provided. //! Fails for Immutable arrays //! calls postPut() - virtual void replace(const const_svector& next) - { - svector temp(const_shared_vector_cast(next)); - this->swap(temp); - this->postPut(); - } - - // methods from PVArray - - virtual size_t getLength() const {return viewUnsafe().size();} - virtual size_t getCapacity() const {return viewUnsafe().capacity();} + virtual void replace(const const_svector& next) = 0; // Derived operations - //! Fetch a read-only view of the current array data - inline const_svector view() const - { - const_svector newref(this->viewUnsafe()); - return newref; - } - /** Remove and return the current array data * or an unique copy if shared. * @@ -1074,10 +1055,9 @@ namespace detail { */ inline svector reuse() { - svector result; + const_svector result; this->swap(result); - result.make_unique(); - return result; + return thaw(result); } /** @@ -1111,16 +1091,14 @@ namespace detail { { from += fromOffset; - svector temp; - this->swap(temp); + svector temp(this->reuse()); if(temp.size() < length+offset) temp.resize(length+offset); else temp.make_unique(); std::copy(from, from + length, temp.begin() + offset); - this->swap(temp); - this->postPut(); + this->replace(freeze(temp)); return length; } @@ -1143,12 +1121,13 @@ namespace detail { vector& vref = *value.get(); typename svector::shared_pointer_type p(&vref[0], detail::shared_ptr_vector_deletor(value)); - svector temp(p, 0, std::min(length, vref.size())); + const_svector temp(p, 0, std::min(length, vref.size())); this->swap(temp); } - pointer get() const { - return this->viewUnsafe().data(); + pointer get() const USAGE_DEPRECATED { + // evil unsafe cast! + return (pointer)this->view().data(); } vector const & getVector() USAGE_ERROR("No longer implemented. Replace with view()"); @@ -1255,6 +1234,10 @@ public: * Destructor */ virtual ~PVValueArray() {} + + virtual size_t getLength() const {return value.size();} + virtual size_t getCapacity() const {return value.capacity();} + /** * Set the array capacity. * @param capacity The length. @@ -1289,8 +1272,12 @@ public: */ virtual void compress(); - virtual const svector& viewUnsafe() const { return value; } - virtual void swap(svector &other); + virtual const_svector view() const { return value; } + virtual void swap(const_svector &other); + virtual void replace(const const_svector &other) { + value = other; + PVField::postPut(); + } virtual void serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) const; @@ -1309,7 +1296,7 @@ protected: {} private: StructureArrayConstPtr structureArray; - svector value; + const_svector value; friend class PVDataCreate; }; From 8fd9bf10e5333d38ed662d9b0f7a0cb70c662374 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 25 Jul 2013 17:30:18 -0400 Subject: [PATCH 094/103] update pvD array implementation --- pvDataApp/factory/Convert.cpp | 8 ++-- pvDataApp/factory/PVDataCreateFactory.cpp | 46 +++++++++++++---------- pvDataApp/factory/PVStructureArray.cpp | 33 +++++++++------- pvDataApp/factory/StandardPVField.cpp | 4 +- pvDataApp/property/pvEnumerated.cpp | 2 +- 5 files changed, 53 insertions(+), 40 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index 7e60f10..fbacdb6 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -125,7 +125,8 @@ size_t Convert::fromStringArray(PVScalarArrayPtr const &pv, from.begin()+fromOffset+length, data.begin()); - pv->putFrom(data); + PVStringArray::const_svector temp(freeze(data)); + pv->putFrom(temp); return length; } else { @@ -399,10 +400,7 @@ void Convert::copyStructureArray( } else if(to->isImmutable()) { throw std::invalid_argument("Convert.copyStructureArray destination is immutable"); } - PVStructureArray::svector data; - from->swap(data); - to->replace(data); - from->swap(data); + to->replace(from->view()); } void Convert::newLine(StringBuilder buffer, int indentLevel) diff --git a/pvDataApp/factory/PVDataCreateFactory.cpp b/pvDataApp/factory/PVDataCreateFactory.cpp index a9efae1..adf813f 100644 --- a/pvDataApp/factory/PVDataCreateFactory.cpp +++ b/pvDataApp/factory/PVDataCreateFactory.cpp @@ -202,11 +202,15 @@ public: DefaultPVArray(ScalarArrayConstPtr const & scalarArray); virtual ~DefaultPVArray(); + virtual size_t getLength() const {return value.size();} + virtual size_t getCapacity() const {return value.capacity();} + virtual void setCapacity(size_t capacity); virtual void setLength(size_t length); - virtual const svector& viewUnsafe() const; - virtual void swap(svector &other); + virtual const_svector view() const {return value;} + virtual void swap(const_svector &other); + virtual void replace(const const_svector& next); // from Serializable virtual void serialize(ByteBuffer *pbuffer,SerializableControl *pflusher) const; @@ -214,7 +218,7 @@ public: virtual void serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, size_t offset, size_t count) const; private: - svector value; + const_svector value; }; template @@ -227,7 +231,6 @@ DefaultPVArray::DefaultPVArray(ScalarArrayConstPtr const & scalarArray) template DefaultPVArray::~DefaultPVArray() { } - template void DefaultPVArray::setCapacity(size_t capacity) { @@ -249,15 +252,15 @@ void DefaultPVArray::setLength(size_t length) value.resize(length); } - template -const typename DefaultPVArray::svector& DefaultPVArray::viewUnsafe() const +void DefaultPVArray::replace(const const_svector& next) { - return value; + value = next; + this->postPut(); } template -void DefaultPVArray::swap(svector &other) +void DefaultPVArray::swap(const_svector &other) { if(this->isImmutable()) THROW_EXCEPTION2(std::logic_error,"Immutable"); @@ -277,9 +280,10 @@ void DefaultPVArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { size_t size = SerializeHelper::readSize(pbuffer, pcontrol); - value.resize(size); // TODO: avoid copy of stuff we will then overwrite + svector nextvalue(thaw(value)); + nextvalue.resize(size); // TODO: avoid copy of stuff we will then overwrite - T* cur = value.data(); + T* cur = nextvalue.data(); // try to avoid deserializing from the buffer // this is only possible if we do not need to do endian-swapping @@ -318,6 +322,7 @@ void DefaultPVArray::deserialize(ByteBuffer *pbuffer, cur += n2read; remaining -= n2read; } + value = freeze(nextvalue); // inform about the change? PVField::postPut(); } @@ -327,13 +332,13 @@ void DefaultPVArray::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, size_t offset, size_t count) const { //TODO: avoid incrementing the ref counter... - svector temp(value); + const_svector temp(value); temp.slice(offset, count); count = temp.size(); SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); - T* cur = temp.data(); + const T* cur = temp.data(); // try to avoid copying into the buffer // this is only possible if we do not need to do endian-swapping @@ -369,18 +374,21 @@ void DefaultPVArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { size_t size = SerializeHelper::readSize(pbuffer, pcontrol); + svector nextvalue(thaw(value)); + // Decide if we must re-allocate - if(size > value.size() || !value.unique()) - value.resize(size); - else if(size < value.size()) - value.slice(0, size); + if(size > nextvalue.size() || !nextvalue.unique()) + nextvalue.resize(size); + else if(size < nextvalue.size()) + nextvalue.slice(0, size); - String * pvalue = value.data(); + String * pvalue = nextvalue.data(); for(size_t i = 0; i void DefaultPVArray::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, size_t offset, size_t count) const { - svector temp(value); + const_svector temp(value); temp.slice(offset, count); SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); - String * pvalue = temp.data(); + const String * pvalue = temp.data(); for(size_t i = 0; igetStructure(); @@ -34,7 +33,8 @@ size_t PVStructureArray::append(size_t number) size_t newLength = data.size(); - swap(data); + const_svector cdata(freeze(data)); + swap(cdata); return newLength; } @@ -55,7 +55,8 @@ bool PVStructureArray::remove(size_t offset,size_t number) } vec.resize(length - number); - swap(vec); + const_svector cdata(freeze(vec)); + swap(cdata); return true; } @@ -89,15 +90,20 @@ void PVStructureArray::compress() { } vec.resize(newLength); - swap(vec); + const_svector cdata(freeze(vec)); + swap(cdata); } void PVStructureArray::setCapacity(size_t capacity) { if(this->isCapacityMutable()) { - svector value; + const_svector value; swap(value); - value.reserve(capacity); + if(value.capacity()isImmutable()) THROW_EXCEPTION2(std::logic_error,"Immutable"); - svector value; + const_svector value; swap(value); if(length == value.size()) { // nothing } else if(length < value.size()) { value.slice(0, length); } else { - value.resize(length); + svector mvalue(thaw(value)); + mvalue.resize(length); + value = freeze(mvalue); } swap(value); } -void PVStructureArray::swap(svector &other) +void PVStructureArray::swap(const_svector &other) { if(this->isImmutable()) THROW_EXCEPTION2(std::logic_error,"Immutable"); @@ -133,8 +141,7 @@ void PVStructureArray::serialize(ByteBuffer *pbuffer, void PVStructureArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { - svector data; - swap(data); + svector data(reuse()); size_t size = SerializeHelper::readSize(pbuffer, pcontrol); data.resize(size); @@ -154,7 +161,7 @@ void PVStructureArray::deserialize(ByteBuffer *pbuffer, data[i]->deserialize(pbuffer, pcontrol); } } - replace(data); // calls postPut() + replace(freeze(data)); // calls postPut() } void PVStructureArray::serialize(ByteBuffer *pbuffer, diff --git a/pvDataApp/factory/StandardPVField.cpp b/pvDataApp/factory/StandardPVField.cpp index f74f60a..80058f9 100644 --- a/pvDataApp/factory/StandardPVField.cpp +++ b/pvDataApp/factory/StandardPVField.cpp @@ -61,7 +61,7 @@ PVStructurePtr StandardPVField::enumerated(StringArray const &choices) "choices",pvString); PVStringArray::svector cdata(choices.size()); std::copy(choices.begin(), choices.end(), cdata.begin()); - static_cast(*pvScalarArray).replace(cdata); + static_cast(*pvScalarArray).replace(freeze(cdata)); return pvStructure; } @@ -74,7 +74,7 @@ PVStructurePtr StandardPVField::enumerated( "value.choices",pvString); PVStringArray::svector cdata(choices.size()); std::copy(choices.begin(), choices.end(), cdata.begin()); - static_cast(*pvScalarArray).replace(cdata); + static_cast(*pvScalarArray).replace(freeze(cdata)); return pvStructure; } diff --git a/pvDataApp/property/pvEnumerated.cpp b/pvDataApp/property/pvEnumerated.cpp index ce76355..77f24d9 100644 --- a/pvDataApp/property/pvEnumerated.cpp +++ b/pvDataApp/property/pvEnumerated.cpp @@ -106,7 +106,7 @@ bool PVEnumerated:: setChoices(const StringArray & choices) if(pvChoices->isImmutable()) return false; PVStringArray::svector data(choices.size()); std::copy(choices.begin(), choices.end(), data.begin()); - pvChoices->replace(data); + pvChoices->replace(freeze(data)); return true; } From b5b6ae100db58c00f99651913a970239977590e7 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 25 Jul 2013 17:30:33 -0400 Subject: [PATCH 095/103] update pvD array in tests --- testApp/misc/testSerialization.cpp | 6 +++--- testApp/pv/testOperators.cpp | 4 ++-- testApp/pv/testPVScalarArray.cpp | 26 +++++++++++++++----------- testApp/pv/testPVStructureArray.cpp | 28 ++++++++++++++++------------ testApp/pv/testStandardPVField.cpp | 2 +- 5 files changed, 37 insertions(+), 29 deletions(-) diff --git a/testApp/misc/testSerialization.cpp b/testApp/misc/testSerialization.cpp index d51451a..3549b5a 100644 --- a/testApp/misc/testSerialization.cpp +++ b/testApp/misc/testSerialization.cpp @@ -259,9 +259,9 @@ void testArrayType(const typename PVT::value_type* rdata, size_t len) typename PVT::shared_pointer pv = std::tr1::static_pointer_cast(getPVDataCreate()->createPVScalarArray(PVT::typeCode)); - pv->replace(empty); + pv->replace(freeze(empty)); serializationTest(pv); - pv->replace(data); + pv->replace(freeze(data)); serializationTest(pv); } @@ -394,7 +394,7 @@ void testStructureArray() { data[1] = getPVDataCreate()->createPVStructure(getStandardField()->alarm()); data[4] = getPVDataCreate()->createPVStructure(getStandardField()->alarm()); - pvArr->replace(data); + pvArr->replace(freeze(data)); testDiag("Some NULLs"); serializationTest(pvArr); diff --git a/testApp/pv/testOperators.cpp b/testApp/pv/testOperators.cpp index cff09b6..eaf30bc 100644 --- a/testApp/pv/testOperators.cpp +++ b/testApp/pv/testOperators.cpp @@ -69,7 +69,7 @@ int main(int, char**) PVDoubleArray::svector values(3); values[0] = 1.1; values[1] = 2.2; values[2] = 3.3; PVDoubleArrayPtr darray = std::tr1::dynamic_pointer_cast(pvStructure->getScalarArrayField("value", pvDouble)); - darray->replace(values); + darray->replace(freeze(values)); std::cout << *darray << std::endl; std::cout << format::array_at(1) << *darray << std::endl; @@ -83,7 +83,7 @@ int main(int, char**) pvDataCreate->createPVStructure(structure); } PVStructureArrayPtr pvStructureArray = pvStructure->getStructureArrayField("value"); - pvStructureArray->replace(pvStructures); + pvStructureArray->replace(freeze(pvStructures)); std::cout << *pvStructure << std::endl; return 0; diff --git a/testApp/pv/testPVScalarArray.cpp b/testApp/pv/testPVScalarArray.cpp index e5de290..363a7cf 100644 --- a/testApp/pv/testPVScalarArray.cpp +++ b/testApp/pv/testPVScalarArray.cpp @@ -53,7 +53,7 @@ static void testFactory() template bool hasUniqueVector(const typename PVT::shared_pointer& pv) { - typename PVT::svector data; + typename PVT::const_svector data; pv->swap(data); bool ret = data.unique(); pv->swap(data); @@ -98,22 +98,24 @@ static void testBasic() data.reserve(200); basicTestData::fill(data); - testOk1(data.unique()); - arr1->replace(data); - testOk1(!data.unique()); + typename PVT::const_svector cdata(freeze(data)); + + testOk1(cdata.unique()); + arr1->replace(cdata); + testOk1(!cdata.unique()); { typename PVT::const_svector avoid; arr1->PVScalarArray::getAs<(ScalarType)ScalarTypeID::value>(avoid); - testOk1(avoid.data()==data.data()); + testOk1(avoid.data()==cdata.data()); testOk1(avoid.data()==arr1->view().data()); } - testOk1(arr1->getLength()==data.size()); + testOk1(arr1->getLength()==cdata.size()); testOk1(*arr1!=*arr2); - data.clear(); + cdata.clear(); testOk1(hasUniqueVector(arr1)); @@ -122,11 +124,11 @@ static void testBasic() testOk1(*arr1==*arr2); testOk1(!hasUniqueVector(arr1)); - arr2->swap(data); + arr2->swap(cdata); arr2->postPut(); testOk1(arr2->getLength()==0); - testOk1(data.size()==arr1->getLength()); + testOk1(cdata.size()==arr1->getLength()); PVIntArray::const_svector idata; arr1->PVScalarArray::getAs(idata); @@ -137,7 +139,9 @@ static void testBasic() wdata.at(1) = 42; - arr1->PVScalarArray::putFrom(wdata); + idata = freeze(wdata); + + arr1->PVScalarArray::putFrom(idata); testOk1(castUnsafe(arr1->view()[1])==42); } @@ -149,7 +153,7 @@ static void testShare() PVIntArrayPtr iarr = static_pointer_cast(getPVDataCreate()->createPVScalarArray(pvInt)); PVStringArrayPtr sarr = static_pointer_cast(getPVDataCreate()->createPVScalarArray(pvString)); - PVIntArray::svector idata(4, 1); + PVIntArray::const_svector idata(4, 1); sarr->PVScalarArray::putFrom(idata); // copy and convert diff --git a/testApp/pv/testPVStructureArray.cpp b/testApp/pv/testPVStructureArray.cpp index c9b36e6..f5701fb 100644 --- a/testApp/pv/testPVStructureArray.cpp +++ b/testApp/pv/testPVStructureArray.cpp @@ -92,22 +92,24 @@ static void testCompress() contents[5] = pvDataCreate->createPVStructure(standardField->alarm()); contents[8] = pvDataCreate->createPVStructure(standardField->alarm()); - alarmarr->replace(contents); + PVStructureArray::const_svector scont(freeze(contents)); - testOk1(!contents.unique()); + alarmarr->replace(scont); + + testOk1(!scont.unique()); testOk1(alarmarr->getLength()==10); alarmarr->compress(); - testOk1(contents.unique()); // a realloc happened + testOk1(scont.unique()); // a realloc happened testOk1(alarmarr->getLength()==4); PVStructureArray::svector compressed(alarmarr->reuse()); - testOk1(contents[2]==compressed[0]); - testOk1(contents[4]==compressed[1]); - testOk1(contents[5]==compressed[2]); - testOk1(contents[8]==compressed[3]); + testOk1(scont[2]==compressed[0]); + testOk1(scont[4]==compressed[1]); + testOk1(scont[5]==compressed[2]); + testOk1(scont[8]==compressed[3]); } static void testRemove() @@ -123,21 +125,23 @@ static void testRemove() fieldCreate->createStructureArray(standardField->alarm())); PVStructureArrayPtr alarmarr(pvDataCreate->createPVStructureArray(alarmtype)); - alarmarr->replace(contents); + PVStructureArray::const_svector scont(freeze(contents)); + + alarmarr->replace(scont); alarmarr->remove(0, 10); // all testOk1(alarmarr->getLength()==0); - alarmarr->replace(contents); + alarmarr->replace(scont); alarmarr->remove(1, 1); PVStructureArray::const_svector check(alarmarr->view()); - testOk1(contents[0]==check[0]); - testOk1(contents[2]==check[1]); - testOk1(contents[3]==check[2]); + testOk1(scont[0]==check[0]); + testOk1(scont[2]==check[1]); + testOk1(scont[3]==check[2]); } MAIN(testPVStructureArray) diff --git a/testApp/pv/testStandardPVField.cpp b/testApp/pv/testStandardPVField.cpp index 238ba82..11a276b 100644 --- a/testApp/pv/testStandardPVField.cpp +++ b/testApp/pv/testStandardPVField.cpp @@ -76,7 +76,7 @@ int main(int, char **) pvDataCreate->createPVStructure(structure); } PVStructureArrayPtr pvStructureArray = pvStructure->getStructureArrayField("value"); - pvStructureArray->replace(pvStructures); + pvStructureArray->replace(freeze(pvStructures)); builder.clear(); pvStructure->toString(&builder); print("structureArrayTest"); From 0eecd3b1fea2a9ecd0af23bb17cae7ee152ee08a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 29 Jul 2013 11:02:27 -0400 Subject: [PATCH 096/103] document freeze/thaw --- pvDataApp/misc/sharedVector.h | 80 +++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index ed3fd11..5686296 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -213,7 +213,7 @@ namespace detail { * The ways in which shared_vector is intended to differ from * std::vector are outlined in @ref vectordiff . * - * Also see @ref vectormem + * Also see @ref vectormem and @ref vectorconst * * @warning Due to the implementation of std::tr1::shared_ptr, use of * shared_vector should not be combined with use of weak_ptr. @@ -327,7 +327,7 @@ public: * as if make_unique() was called. This holds even if the capacity * does not increase. * - * For notes on copying see docs for make_exlcusive(). + * For notes on copying see docs for make_unique(). */ void reserve(size_t i) { if(this->unique() && i<=this->m_total) @@ -348,9 +348,9 @@ public: /** @brief Grow or shrink array * * A side effect is that array data will be uniquely owned by this instance - * as if make_unique() was called. This holds even if the size does not change. + * as if make_unique() were called. This holds even if the size does not change. * - * For notes on copying see docs for make_exlcusive(). + * For notes on copying see docs for make_unique(). */ void resize(size_t i) { if(i==this->m_count) { @@ -925,3 +925,75 @@ std::ostream& operator<<(std::ostream& strm, const epics::pvData::shared_vector< } @endcode */ + +/** @page vectorconst Value const-ness and shared_vector + +The type 'shared_vector' can be thought of as 'T*'. +Like the T pointer there are three related constant types: + +@code + shared_vector v_mutable; // 1 + const shared_vector v_const_ref; // 2 + shared_vector v_const_data; // 3 + const shared_vector v_const_ref_data; // 4 +@endcode + +The distinction between these types is what "part" of the type is constant, +the "reference" (pointer) or the "value" (location being pointed to). + +Type #2 is constant reference to a mutable value. +Type #3 is a mutable reference to a constant value. +Type #4 is a constant reference to a constant value. + +Casting between const and non-const references of the same value type +is governed by the normal C++ casting rules. + +Casting between const and non-const values does @b not follow the normal +C++ casting rules. + +For casting between shared_vector and shared_vector +explicit casting operations are required. These operations are +@b freeze() (non-const to const) and @b thaw() (const to non-const). + +A shared_vector is "frozen" as its value can not be modified. + +These functions are defined like: + +@code +namespace epics{namespace pvData{ + template + shared_vector freeze(shared_vector&); + + template + shared_vector thaw(shared_vector&); +}} +@endcode + +So each consumes a shared_vector with a certain value +const-ness, and returns one with the other. + +The following guarantees are provided by both functions: + +# The returned reference points to a value which is equal to the value referenced + by the argument. +# The returned reference points to a value which is only referenced by + shared_vectors with the same value const-ness as the returned reference. + +Please note that the argument of both freeze and thaw is a non-const +reference which will always be cleared. + +@section vfreeze Freezing + +The act of freezing a shared_vector requires that the shared_vector +passed in must be unique() or an exception is thrown. This is +done to reduce the possibility of accidental copying. + +This possibility can be avoided by calling the make_unique() on a +shared_vector before passing it to freeze(). + +@section vthaw Thawing + +The act of thawing a shared_vector may make a copy of the value +referenced by its argument if this reference is not unique(). + +*/ From e96b447e375e06764e9602c537c2c69c91e20b27 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 29 Jul 2013 11:42:33 -0400 Subject: [PATCH 097/103] add print_cast() Cast value to "printable" type. A no-op except for char types, which are cast to int so that they are printed as numbers std::ostream operators. --- pvDataApp/misc/typeCast.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pvDataApp/misc/typeCast.h b/pvDataApp/misc/typeCast.h index 8bf33be..0717d0c 100644 --- a/pvDataApp/misc/typeCast.h +++ b/pvDataApp/misc/typeCast.h @@ -159,6 +159,14 @@ static FORCE_INLINE TO castUnsafe(const FROM& from) void castUnsafeV(size_t count, ScalarType to, void *dest, ScalarType from, const void *src); +//! Cast value to printable type +//! A no-op except for char types, which are cast to int +//! so that they are printed as numbers std::ostream operators. +template +static FORCE_INLINE +typename detail::print_cast::type +print_cast(const T& v) { return v; } + }} // end namespace #endif // PVTYPECAST_H From 0860f8e6f96929ed4ae247cdffa9cc979b2365e6 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 25 Jul 2013 17:54:46 -0400 Subject: [PATCH 098/103] don't use deprecated PVValueArray::get() --- pvDataApp/factory/Compare.cpp | 3 ++- pvDataApp/factory/PVScalarArray.cpp | 12 ------------ pvDataApp/factory/printer.cpp | 9 ++++++--- pvDataApp/pv/pvData.h | 21 ++++++++++----------- 4 files changed, 18 insertions(+), 27 deletions(-) diff --git a/pvDataApp/factory/Compare.cpp b/pvDataApp/factory/Compare.cpp index d47d533..f6780dc 100644 --- a/pvDataApp/factory/Compare.cpp +++ b/pvDataApp/factory/Compare.cpp @@ -109,7 +109,8 @@ bool compareScalar(const PVScalarValue* left, const PVScalarValue* right) template bool compareArray(const PVValueArray* left, const PVValueArray* right) { - return std::equal(left->get(), left->get()+left->getLength(), right->get()); + typename PVValueArray::const_svector lhs(left->view()), rhs(right->view()); + return std::equal(lhs.begin(), lhs.end(), rhs.begin()); } // partially typed comparisons diff --git a/pvDataApp/factory/PVScalarArray.cpp b/pvDataApp/factory/PVScalarArray.cpp index 86f1821..19d0339 100644 --- a/pvDataApp/factory/PVScalarArray.cpp +++ b/pvDataApp/factory/PVScalarArray.cpp @@ -28,16 +28,4 @@ namespace epics { namespace pvData { return static_pointer_cast(PVField::getField()); } - template<> - std::ostream& PVValueArray::dumpValue(std::ostream& o, size_t index) const - { - return o << static_cast(*(get() + index)); - } - - template<> - std::ostream& PVValueArray::dumpValue(std::ostream& o, size_t index) const - { - return o << static_cast(*(get() + index)); - } - }} diff --git a/pvDataApp/factory/printer.cpp b/pvDataApp/factory/printer.cpp index 23f4d72..ad455fe 100644 --- a/pvDataApp/factory/printer.cpp +++ b/pvDataApp/factory/printer.cpp @@ -118,13 +118,16 @@ void PrinterBase::impl_print(const PVField& pv) } case structureArray: { const PVStructureArray &fld = *static_cast(next); - const PVStructureArray::pointer vals = fld.get(); + PVStructureArray::const_svector vals(fld.view()); inprog.push_back(next); beginStructureArray(fld); - for(size_t i=0, nfld=fld.getLength(); iget()); + } todo.push_back(marker); break; diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index 257fd34..30165ff 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -1167,23 +1167,22 @@ public: std::ostream& dumpValue(std::ostream& o) const { + const_svector v(this->view()); + typename const_svector::const_iterator it(v.begin()), + end(v.end()); o << '['; - std::size_t len = this->getLength(); - bool first = true; - for (std::size_t i = 0; i < len; i++) - { - if (first) - first = false; - else - o << ','; - dumpValue(o, i); - } + if(it!=end) { + o << print_cast(*it++); + for(; it!=end; ++it) + o << ',' << print_cast(*it); + + } return o << ']'; } std::ostream& dumpValue(std::ostream& o, size_t index) const { - return o << *(this->get() + index); + return o << print_cast(this->view().at(index)); } protected: From c643509c7e58178b639837fe6d4699c2b836cb69 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 29 Jul 2013 15:08:59 -0400 Subject: [PATCH 099/103] PVField converters use type Use type as template parameter instead of ScalarType enum value. --- pvDataApp/pv/pvData.h | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index 30165ff..c7e9b3f 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -427,10 +427,10 @@ public: uint32 val = pv->getAs(); @endcode */ - template - inline typename ScalarTypeTraits::type getAs() const { - typename ScalarTypeTraits::type result; - this->getAs((void*)&result, ID); + template + inline T getAs() const { + T result; + this->getAs((void*)&result, (ScalarType)ScalarTypeID::value); return result; } protected: @@ -447,9 +447,9 @@ public: pv->putFrom((int32)42); @endcode */ - template - inline void putFrom(typename ScalarTypeTraits::type val) { - this->putFrom((const void*)&val, ID); + template + inline void putFrom(T val) { + this->putFrom((const void*)&val, (ScalarType)ScalarTypeID::value); } protected: virtual void putFrom(const void *, ScalarType) = 0; @@ -508,17 +508,15 @@ public: put(value); } - template - inline typename ScalarTypeTraits::type getAs() const { - typedef typename ScalarTypeTraits::type to_t; - to_t result(castUnsafe(get())); + template + inline T1 getAs() const { + T1 result(castUnsafe(get())); return result; } - template - inline void putFrom(typename ScalarTypeTraits::type val) { - typedef typename ScalarTypeTraits::type from_t; - put(castUnsafe(val)); + template + inline void putFrom(T1 val) { + put(castUnsafe(val)); } protected: @@ -705,14 +703,13 @@ public: * the element type. If the types do match then * no copy is made. */ - template + template void - getAs(shared_vector::type>& out) const + getAs(shared_vector& out) const { - typedef typename ScalarTypeTraits::type dest_type; shared_vector temp; _getAsVoid(temp); - out = shared_vector_convert(temp); + out = shared_vector_convert(temp); } /** @@ -726,8 +723,8 @@ public: * * Calls postPut() */ - template - inline void putFrom(const shared_vector::type>& inp) + template + inline void putFrom(const shared_vector& inp) { shared_vector temp(static_shared_vector_cast(inp)); _putFromVoid(temp); From f21811eb6abd76d78733ba401f5beaf46d51f7d8 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 29 Jul 2013 15:09:47 -0400 Subject: [PATCH 100/103] Change enum to type in converters --- pvDataApp/factory/Convert.cpp | 4 ++-- pvDataApp/factory/printer.cpp | 4 ++-- pvDataApp/pv/convert.h | 44 +++++++++++++++++------------------ 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index fbacdb6..627c062 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -126,7 +126,7 @@ size_t Convert::fromStringArray(PVScalarArrayPtr const &pv, data.begin()); PVStringArray::const_svector temp(freeze(data)); - pv->putFrom(temp); + pv->putFrom(temp); return length; } else { @@ -140,7 +140,7 @@ size_t Convert::toStringArray(PVScalarArrayPtr const & pv, StringArray &to, size_t toOffset) { PVStringArray::const_svector data; - pv->getAs(data); + pv->getAs(data); data.slice(offset, length); if(toOffset+data.size() > to.size()) to.resize(toOffset+data.size()); diff --git a/pvDataApp/factory/printer.cpp b/pvDataApp/factory/printer.cpp index ad455fe..f6e3a96 100644 --- a/pvDataApp/factory/printer.cpp +++ b/pvDataApp/factory/printer.cpp @@ -173,14 +173,14 @@ void PrinterPlain::encodeScalar(const PVScalar& pv) indentN(S(), ilvl); S() << pv.getScalar()->getID() << " " << pv.getFieldName() << " " - << pv.getAs() << std::endl; + << pv.getAs() << std::endl; } void PrinterPlain::encodeArray(const PVScalarArray& pv) { indentN(S(), ilvl); shared_vector temp; - pv.getAs(temp); + pv.getAs(temp); S() << pv.getScalarArray()->getID() << " " << pv.getFieldName() << " ["; diff --git a/pvDataApp/pv/convert.h b/pvDataApp/pv/convert.h index 8399ec3..6faead0 100644 --- a/pvDataApp/pv/convert.h +++ b/pvDataApp/pv/convert.h @@ -157,7 +157,7 @@ public: */ void fromString(PVScalarPtr const & pv, String const & from) { - pv->putFrom(from); + pv->putFrom(from); } /** @@ -296,145 +296,145 @@ public: * @param pv a PV * @return converted value */ - inline int8 toByte(PVScalarPtr const & pv) { return pv->getAs();} + inline int8 toByte(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a short. * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline int16 toShort(PVScalarPtr const & pv) { return pv->getAs();} + inline int16 toShort(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a int. * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline int32 toInt(PVScalarPtr const & pv) { return pv->getAs();} + inline int32 toInt(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to an long * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline int64 toLong(PVScalarPtr const & pv) { return pv->getAs();} + inline int64 toLong(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a ubyte. * @param pv a PV * @return converted value */ - inline uint8 toUByte(PVScalarPtr const & pv) { return pv->getAs();} + inline uint8 toUByte(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a ushort. * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline uint16 toUShort(PVScalarPtr const & pv) { return pv->getAs();} + inline uint16 toUShort(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a uint. * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline uint32 toUInt(PVScalarPtr const & pv) { return pv->getAs();} + inline uint32 toUInt(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to an ulong * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline uint64 toULong(PVScalarPtr const & pv) { return pv->getAs();} + inline uint64 toULong(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a float * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline float toFloat(PVScalarPtr const & pv) { return pv->getAs();} + inline float toFloat(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a double * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline double toDouble(PVScalarPtr const & pv) { return pv->getAs();} + inline double toDouble(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a String * @param pv a PV * @return converted value */ - inline String toString(PVScalarPtr const & pv) { return pv->getAs();} + inline String toString(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV from a byte * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline void fromByte(PVScalarPtr const & pv,int8 from) { pv->putFrom(from); } + inline void fromByte(PVScalarPtr const & pv,int8 from) { pv->putFrom(from); } /** * Convert a PV from a short * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline void fromShort(PVScalarPtr const & pv,int16 from) { pv->putFrom(from); } + inline void fromShort(PVScalarPtr const & pv,int16 from) { pv->putFrom(from); } /** * Convert a PV from an int * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline void fromInt(PVScalarPtr const & pv, int32 from) { pv->putFrom(from); } + inline void fromInt(PVScalarPtr const & pv, int32 from) { pv->putFrom(from); } /** * Convert a PV from a long * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline void fromLong(PVScalarPtr const & pv, int64 from) { pv->putFrom(from); } + inline void fromLong(PVScalarPtr const & pv, int64 from) { pv->putFrom(from); } /** * Convert a PV from a ubyte * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline void fromUByte(PVScalarPtr const & pv,uint8 from) { pv->putFrom(from); } + inline void fromUByte(PVScalarPtr const & pv,uint8 from) { pv->putFrom(from); } /** * Convert a PV from a ushort * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline void fromUShort(PVScalarPtr const & pv,uint16 from) { pv->putFrom(from); } + inline void fromUShort(PVScalarPtr const & pv,uint16 from) { pv->putFrom(from); } /** * Convert a PV from an uint * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline void fromUInt(PVScalarPtr const & pv, uint32 from) { pv->putFrom(from); } + inline void fromUInt(PVScalarPtr const & pv, uint32 from) { pv->putFrom(from); } /** * Convert a PV from a ulong * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline void fromULong(PVScalarPtr const & pv, uint64 from) { pv->putFrom(from); } + inline void fromULong(PVScalarPtr const & pv, uint64 from) { pv->putFrom(from); } /** * Convert a PV from a float * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline void fromFloat(PVScalarPtr const & pv, float from) { pv->putFrom(from); } + inline void fromFloat(PVScalarPtr const & pv, float from) { pv->putFrom(from); } /** * Convert a PV from a double * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - inline void fromDouble(PVScalarPtr const & pv, double from) { pv->putFrom(from); } + inline void fromDouble(PVScalarPtr const & pv, double from) { pv->putFrom(from); } /** * Convenience method for implementing toString. From 759d268af04c801f541da15db4804af48da5d488 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 29 Jul 2013 15:10:04 -0400 Subject: [PATCH 101/103] update testPVScalarArray --- testApp/pv/testPVScalarArray.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/testApp/pv/testPVScalarArray.cpp b/testApp/pv/testPVScalarArray.cpp index 363a7cf..c32e807 100644 --- a/testApp/pv/testPVScalarArray.cpp +++ b/testApp/pv/testPVScalarArray.cpp @@ -106,7 +106,7 @@ static void testBasic() { typename PVT::const_svector avoid; - arr1->PVScalarArray::getAs<(ScalarType)ScalarTypeID::value>(avoid); + arr1->PVScalarArray::getAs(avoid); testOk1(avoid.data()==cdata.data()); testOk1(avoid.data()==arr1->view().data()); } @@ -131,7 +131,7 @@ static void testBasic() testOk1(cdata.size()==arr1->getLength()); PVIntArray::const_svector idata; - arr1->PVScalarArray::getAs(idata); + arr1->PVScalarArray::getAs(idata); testOk1(idata.at(1)==10); @@ -141,7 +141,7 @@ static void testBasic() idata = freeze(wdata); - arr1->PVScalarArray::putFrom(idata); + arr1->PVScalarArray::putFrom(idata); testOk1(castUnsafe(arr1->view()[1])==42); } @@ -155,22 +155,22 @@ static void testShare() PVIntArray::const_svector idata(4, 1); - sarr->PVScalarArray::putFrom(idata); // copy and convert + sarr->PVScalarArray::putFrom(idata); // copy and convert testOk1(idata.unique()); - iarr->PVScalarArray::putFrom(idata); // take a reference + iarr->PVScalarArray::putFrom(idata); // take a reference testOk1(!idata.unique()); idata.clear(); PVIntArray::const_svector cdata; - sarr->PVScalarArray::getAs(cdata); // copy and convert + sarr->PVScalarArray::getAs(cdata); // copy and convert testOk1(cdata.unique()); - iarr->PVScalarArray::getAs(cdata); // take a reference + iarr->PVScalarArray::getAs(cdata); // take a reference testOk1(!cdata.unique()); } From 31be738c10c10180d2ca7b560f09c993590f8f32 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 6 Aug 2013 10:43:47 -0400 Subject: [PATCH 102/103] minor --- pvDataApp/misc/sharedVector.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 5686296..755e256 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -416,8 +416,7 @@ public: void make_unique() { if(this->unique()) return; - typedef typename meta::strip_const::type nE; - nE *d = new nE[this->m_total]; + _E_non_const *d = new _E_non_const[this->m_total]; try { std::copy(this->m_data.get()+this->m_offset, this->m_data.get()+this->m_offset+this->m_count, From de70d90603c6b0c70022b086b8be2d6020bcb2b0 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 6 Aug 2013 11:32:34 -0400 Subject: [PATCH 103/103] shared_vector: simplify slice() Correctly tracks capacity when user over-slices. --- pvDataApp/misc/sharedVector.h | 28 ++++++++++++++++++---------- testApp/misc/testSharedVector.cpp | 20 +++++++++++++++----- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 755e256..cd8ee39 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -47,13 +47,18 @@ namespace detail { template friend class shared_vector_base; protected: std::tr1::shared_ptr m_data; - //! Offset in the data array of first element + //! Offset in the data array of first visible element size_t m_offset; //! Number of visible elements between m_offset and end of data size_t m_count; //! Total number of elements between m_offset and the end of data size_t m_total; + /* invariants + * m_count <= m_total (enforced) + * m_offset + m_total <= (size_t)-1 (checked w/ assert()) + */ + public: //! @brief Empty vector (not very interesting) @@ -68,6 +73,9 @@ namespace detail { { if(!m_data.get()) { m_offset = m_total = m_count = 0; + } else { + // ensure we won't have integer overflows later + assert( m_offset <= ((size_t)-1) - m_total); } } public: @@ -96,6 +104,8 @@ namespace detail { protected: typedef typename meta::strip_const::type _E_non_const; public: + //! Constructor used to implement freeze(). + //! Should not be called directly. shared_vector_base(shared_vector_base<_E_non_const>& O, _shared_vector_freeze_tag) :m_data() @@ -109,6 +119,8 @@ namespace detail { O.clear(); } + //! Constructor used to implement thaw(). + //! Should not be called directly. shared_vector_base(shared_vector& O, _shared_vector_thaw_tag) :m_data() @@ -180,20 +192,16 @@ namespace detail { */ void slice(size_t offset, size_t length=(size_t)-1) { - if(offset>m_total) - offset = m_total; + if(offset>m_count) + offset = m_count; // will slice down to zero length + + const size_t max_count = m_count - offset; m_offset += offset; m_total -= offset; - if(offset>m_count) { - m_count = 0; - } else { - if(length > m_count - offset) - length = m_count - offset; - m_count = length; - } + m_count = std::min(length, max_count); } // Access to members. diff --git a/testApp/misc/testSharedVector.cpp b/testApp/misc/testSharedVector.cpp index a1bcd1f..0c1487d 100644 --- a/testApp/misc/testSharedVector.cpp +++ b/testApp/misc/testSharedVector.cpp @@ -250,7 +250,13 @@ static void testSlice() testOk1(half2.dataOffset()==5); testOk1(half2a.dataOffset()==5); - testOk1(half2.size() == half2a.size()); + testOk1(half1.size()==5); + testOk1(half2.size()==5); + testOk1(half2a.size()==5); + + testOk1(half1.dataTotal()==10); + testOk1(half2.dataTotal()==5); + testOk1(half2a.dataTotal()==5); testOk1(original.data() == half1.data()); testOk1(half2.data() == half2a.data()); @@ -259,13 +265,17 @@ static void testSlice() half2.slice(1); half2a.slice(1,1); + testOk1(half1.dataOffset()==5); + testOk1(half2.dataOffset()==6); + testOk1(half2a.dataOffset()==6); + testOk1(half1.size()==0); testOk1(half2.size()==4); testOk1(half2a.size()==1); - testOk1(half1.dataOffset()==10); - testOk1(half2.dataOffset()==6); - testOk1(half2a.dataOffset()==6); + testOk1(half1.dataTotal()==5); + testOk1(half2.dataTotal()==4); + testOk1(half2a.dataTotal()==4); half2.clear(); testOk1(half2.dataOffset()==0); @@ -525,7 +535,7 @@ static void testICE() MAIN(testSharedVector) { - testPlan(154); + testPlan(162); testDiag("Tests for shared_vector"); testDiag("sizeof(shared_vector)=%lu",