Prefetch enum variants
CI / build-and-test (push) Successful in 6s

This commit is contained in:
2026-04-29 15:36:44 +02:00
parent ccfda8d045
commit f4fac4d0c6
2 changed files with 34 additions and 14 deletions
+5
View File
@@ -7,6 +7,7 @@
#include <menuAlarmStat.h>
#include <optional>
#include <string>
#include <vector>
/**
* @brief Holds information about the CA channel: Value type and element count.
@@ -305,6 +306,10 @@ template <typename T> class mEpicsCa {
*/
std::optional<T> _cached;
// Vector holding the possible enum variants, if the record is an enum
// record like e.g. bo. For all other record types, this is empty.
std::vector<std::string> _enumVariants;
// Status and severity of the last read (or subscription callback)
menuAlarmStat _status;
menuAlarmSevr _severity;
+29 -14
View File
@@ -171,7 +171,8 @@ template <typename T>
mEpicsCa<T>::mEpicsCa(std::string_view chanName, bool subscribe, double timeout)
: _timeout(timeout), _pChanID(nullptr), _chanName(chanName),
_subscribe(subscribe), _eventId(nullptr), _cached(std::nullopt),
_status(menuAlarmStatUDF), _severity(menuAlarmSevrNO_ALARM) {
_enumVariants(std::vector<std::string>()), _status(menuAlarmStatUDF),
_severity(menuAlarmSevrNO_ALARM) {
// Compile time check of T
dbfFromType<T>();
@@ -580,23 +581,36 @@ template <bool S>
int mEpicsCa<T>::putRaw(const char *buf, u_long len) {
if constexpr (dbfFromType<T>() == DBF_ENUM) {
// Check if the given string corresponds to one of the enum variants
// and fetch the corresponding index, if it does. Otherwise, create
// a nice error message.
struct dbr_ctrl_enum data;
ca_get(DBR_CTRL_ENUM, this->_pChanID, &data);
ca_pend_io(_timeout);
// Prefetch all enum variants if the vector is currently empty. We
// cannot do this at connection time, because this results in a segfault
// (likely because we are trying to use ca_get while being inside a
// callback).
if (_enumVariants.empty()) {
struct dbr_ctrl_enum data;
ca_get(DBR_CTRL_ENUM, _pChanID, &data);
ca_pend_io(_timeout);
for (int i = 0; i < data.no_str; ++i) {
_enumVariants.push_back(data.strs[i]);
}
}
// Check if the given string matches one of the enum variants
for (size_t i = 0; i < _enumVariants.size(); i++) {
if (_enumVariants[i] == buf) {
uint16_t idx = i;
return putRaw<S>(&idx);
}
}
// If we didn't exit from the loop, the given buffer is not one of the
// enum variants. Hence, we now create an error message (looping again).
std::string variants;
for (int i = 0; i < data.no_str; ++i) {
for (size_t i = 0; i < _enumVariants.size(); i++) {
if (i > 0)
variants += ", ";
variants += data.strs[i];
if (strcmp(data.strs[i], buf) == 0)
return putRaw<S>(&i);
variants += _enumVariants[i];
}
// Given string did not match any of the variants -> return an
@@ -692,6 +706,7 @@ void mEpicsCa<T>::connStateCallback(struct connection_handler_args args) {
} else {
// Any other event -> assume the channel is disconnected and reset the
// internal fields
self->_enumVariants.clear();
self->_channelInfo.reset();
self->_cached.reset();
cm_msg(MDEBUG, __FILE__, "PV %s disconnected", self->_chanName.c_str());