From bc048cea78a836f8326fe079d8bd18bca6eda253 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 19 Dec 2019 13:01:36 -0800 Subject: [PATCH] TypeDef helpers --- src/nt.cpp | 20 ++++++------ src/pvxs/data.h | 77 +++++++++++++++++++++++++++++++++++++++++++++-- test/testtype.cpp | 2 +- 3 files changed, 87 insertions(+), 12 deletions(-) diff --git a/src/nt.cpp b/src/nt.cpp index 5aa5de0..27591d7 100644 --- a/src/nt.cpp +++ b/src/nt.cpp @@ -11,18 +11,20 @@ namespace nt { TypeDef NTScalar::build() const { + using namespace pvxs::members; + return TypeDef(TypeCode::Struct, value.isarray() ? "epics:nt/NTScalarArray:1.0" : "epics:nt/NTScalar:1.0", { Member(value, "value"), - Member(TypeCode::Struct, "alarm", "alarm_t", { - Member(TypeCode::Int32, "severity"), - Member(TypeCode::Int32, "status"), - Member(TypeCode::String, "message"), + Struct("alarm", "alarm_t", { + Int32("severity"), + Int32("status"), + String("message"), }), - Member(TypeCode::Struct, "timeStamp", "time_t", { - Member(TypeCode::Int64, "secondsPastEpoch"), - Member(TypeCode::Int32, "nanoseconds"), - Member(TypeCode::Int32, "userTag"), + Struct("timeStamp", "time_t", { + Int64("secondsPastEpoch"), + Int32("nanoseconds"), + Int32("userTag"), }), }); @@ -73,7 +75,7 @@ TypeDef NTScalar::build() const TypeDef NTNDArray::build() const { - TypeDef def(TypeCode::Struct, "epics:nt/NTNDArray:1.0"); + TypeDef def(TypeCode::Struct, "epics:nt/NTNDArray:1.0", {}); return def; diff --git a/src/pvxs/data.h b/src/pvxs/data.h index 5d6c747..6d8a6dc 100644 --- a/src/pvxs/data.h +++ b/src/pvxs/data.h @@ -167,22 +167,89 @@ inline std::ostream& operator<<(std::ostream& strm, TypeCode c) { return strm; } +//! Definition of a member of a Struct/Union for use with TypeDef struct Member { TypeCode code; std::string name; std::string id; std::vector children; + inline Member(TypeCode code, const std::string& name, const std::string& id = std::string()) :Member(code, name, id, {}) {} PVXS_API Member(TypeCode code, const std::string& name, const std::string& id, std::initializer_list children); + inline Member(TypeCode code, const std::string& name, std::initializer_list children) :Member(code, name , std::string(), children) {} }; +/** Helper functions for building TypeDef. + * + * Each of the TypeCode::code_t enums has an associated helper function of the same name + * which is a shorthand notation for a Member(). + * + * eg. @code members::UInt32("blah") @endcode is equivalent to @code Member(TypeCode::UInt32, "blah") @endcode + */ +namespace members { +#define CASE(TYPE) \ +inline Member TYPE(const std::string& name) { return Member(TypeCode::TYPE, name); } +CASE(Bool) +CASE(UInt8) +CASE(UInt16) +CASE(UInt32) +CASE(UInt64) +CASE(Int8) +CASE(Int16) +CASE(Int32) +CASE(Int64) +CASE(Float32) +CASE(Float64) +CASE(String) +CASE(Any) +CASE(BoolA) +CASE(UInt8A) +CASE(UInt16A) +CASE(UInt32A) +CASE(UInt64A) +CASE(Int8A) +CASE(Int16A) +CASE(Int32A) +CASE(Int64A) +CASE(Float32A) +CASE(Float64A) +CASE(StringA) +CASE(AnyA) +#undef CASE + +#define CASE(TYPE) \ +inline Member TYPE(const std::string& name, std::initializer_list children) { return Member(TypeCode::TYPE, name, children); } \ +inline Member TYPE(const std::string& name, const std::string& id, std::initializer_list children) { return Member(TypeCode::TYPE, name, id, children); } + +CASE(Struct) +CASE(Union) +CASE(StructA) +CASE(UnionA) +#undef CASE +} // namespace members + +/** Define a new type, either from scratch, or based on an existing Value + * + * @code + * namespace M = pvxs::members; + * auto def1 = TypeDef(TypeCode::Int32); // a single scalar field + * auto def2 = TypeDef(TypeCode::Struct, { + * M::Int32("value"), + * M::Struct("alarm", "alarm_t", { + * M::Int32("severity"), + * }), + * + * auto val = def2.create(); // instanciate a Value + * }); + * @endcode + */ class PVXS_API TypeDef { public: @@ -190,25 +257,31 @@ public: private: std::shared_ptr top; public: + //! new, empty, definition TypeDef() = default; // moveable, copyable TypeDef(const TypeDef&) = default; TypeDef(TypeDef&&) = default; TypeDef& operator=(const TypeDef&) = default; TypeDef& operator=(TypeDef&&) = default; + //! pre-populate definition based on provided Value explicit TypeDef(const Value&); ~TypeDef(); + //! new definition with id and children. code must be TypeCode::Struct or TypeCode::Union TypeDef(TypeCode code, const std::string& id, std::initializer_list children); - TypeDef(TypeCode code, const std::string& id=std::string()) - :TypeDef(code, id, {}) + //! new definition for a single scalar field. code must __not__ be TypeCode::Struct or TypeCode::Union + TypeDef(TypeCode code) + :TypeDef(code, std::string(), {}) {} + //! new definition without id. code must be TypeCode::Struct or TypeCode::Union TypeDef(TypeCode code, std::initializer_list children) :TypeDef(code, std::string(), children) {} //TypeDef& operator+=(const Member& ) + //! Instanciate this definition Value create() const; friend diff --git a/test/testtype.cpp b/test/testtype.cpp index ab03581..3165abb 100644 --- a/test/testtype.cpp +++ b/test/testtype.cpp @@ -71,7 +71,7 @@ void testTypeDef() testEq(std::string(SB()<\n"); - testEq(std::string(SB()<