From 13d02530cf07b81d12370dd3faa933ef4c31243b Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 31 Aug 2023 10:35:54 +0200 Subject: [PATCH] Add NTTable helper --- documentation/nt.rst | 8 ++++++ src/nt.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++ src/pvxs/nt.h | 40 +++++++++++++++++++++++++++++ test/testnt.cpp | 18 ++++++++++++- 4 files changed, 126 insertions(+), 1 deletion(-) diff --git a/documentation/nt.rst b/documentation/nt.rst index d8fd13b..af4a2ee 100644 --- a/documentation/nt.rst +++ b/documentation/nt.rst @@ -95,6 +95,14 @@ Container for image data used by areaDetector. .. doxygenstruct:: pvxs::nt::NTNDArray :members: +NTTable +------- + +Container for tabular data. + +.. doxygenstruct:: pvxs::nt::NTTable + :members: + NTURI ----- diff --git a/src/nt.cpp b/src/nt.cpp index 02442d7..8cc84ad 100644 --- a/src/nt.cpp +++ b/src/nt.cpp @@ -5,6 +5,7 @@ */ #include +#include "utilpvt.h" namespace pvxs { namespace nt { @@ -132,6 +133,66 @@ TypeDef NTEnum::build() const return def; } +struct NTTable::Pvt { + struct Col { + TypeCode code; + std::string name, label; + }; + std::vector cols; +}; + +NTTable::NTTable() + :pvt(std::make_shared()) +{} + +NTTable::~NTTable() {} + +NTTable& NTTable::add_column(TypeCode code, + const char *name, + const char *label) +{ + if(!code.valid() || code.isarray()) + throw std::logic_error(SB()<<"NTTable column "<cols.emplace_back(std::move(col)); + return *this; +} + +TypeDef NTTable::build() const +{ + std::vector columns; + columns.reserve(pvt->cols.size()); + + for(const auto& col : pvt->cols) { + columns.emplace_back(col.code, col.name); + } + + TypeDef def(TypeCode::Struct, "", { + members::StringA("labels"), + members::Struct("value", columns), + members::String("descriptor"), // ??? + Alarm{}.build().as("alarm"), + TimeStamp{}.build().as("timeStamp"), + }); + + return def; +} + +Value NTTable::create() const +{ + Value ret(build().create()); + shared_array labels; + labels.resize(pvt->cols.size()); + + size_t i=0; + for(const auto& col : pvt->cols) { + labels[i++] = col.label; + } + ret["labels"] = labels.freeze(); + + return ret; +} + TypeDef NTNDArray::build() const { using namespace pvxs::members; diff --git a/src/pvxs/nt.h b/src/pvxs/nt.h index 3736fc7..a436a64 100644 --- a/src/pvxs/nt.h +++ b/src/pvxs/nt.h @@ -6,6 +6,8 @@ #ifndef PVXS_NT_H #define PVXS_NT_H +#include + #include #include @@ -105,6 +107,44 @@ struct NTEnum { } }; +/** Columnar data. + * + * Unlike other NT* builders. This create() method returns a Value + * with the labels field set, and marked. While suitable for an + * initial value, repeated create() could result in re-sending + * the same labels array with every update. User could should + * create() once, and then Value::cloneEmpty() or unmark() for + * subsequent updates. + * + * @since UNRELEASED + */ +struct PVXS_API NTTable final { + + NTTable(); + ~NTTable(); + + /** Append a column + * + * @param code Value type of column + * @param name Field name of column + * @param label Display label of column. (defaults to field name) + * Only used in create(). + * @returns this + */ + NTTable& add_column(TypeCode code, + const char *name, + const char *label=nullptr); + + //! A TypeDef which can be appended + TypeDef build() const; + //! Instantiate. Also populates labels list. + Value create() const; + + struct Pvt; +private: + std::shared_ptr pvt; +}; + /** The areaDetector inspired N-dimension array/image container. * * @code diff --git a/test/testnt.cpp b/test/testnt.cpp index 13ff91e..131ee16 100644 --- a/test/testnt.cpp +++ b/test/testnt.cpp @@ -82,13 +82,29 @@ void testNTEnum() testTrue(top.idStartsWith("epics:nt/NTEnum:"))<<"\n"< labels({"Col A", "Col B"}); + testArrEq(top["labels"].as>(), labels); + testTrue(top["value.A"].type()==TypeCode::Int32A); + testTrue(top["value.B"].type()==TypeCode::StringA); +} + } // namespace MAIN(testnt) { - testPlan(18); + testPlan(21); testNTScalar(); testNTNDArray(); testNTURI(); testNTEnum(); + testNTTable(); return testDone(); }