Files
pvxs/ioc/fieldname.cpp
Michael Davidsaver afafa09547 ioc: revise qsrv 2 prototype
ioc: check for mis-matched onStartSubscription()/onDisableSubscription()

ioc: fix subscription lifetime

ioc: catch exceptions in dbEvent callbacks

ioc: avoid unnecessary virtual

ioc: minor

ioc: fix qsrv -S

ioc: qsrvGroupSourceInit() catch+log

ioc: runOnServer avoid std::function

ioc: cleanup and simplifications.

Avoid some redundant std::map lookups.
Make Group partially const to prevent implicit ctor.

ioc: avoid typedefs only used once

ioc: overhaul Group::show().  shows triggers

ioc: MappingType

ioc: pvxsgl -> pvxgl

ioc: separate group config singleton from server singleton

ioc: remove unnecessary forward declarations

ioc: restructure pvxsInitHook

ioc: qsrv runtime disable by default

ioc: compat w/ older Base

ioc: link pvxsIoc w/ DB libs

ioc: Channel proper detection of invalid PV

ioc: no need to keep vector<dbCommon*> around

ioc: fix initial group update for mappings w/o dbChannel

ioc: redo testing

split out group tests, only run with Base >= 7.0

ioc: minor

ioc: loc_bad_alloc

ioc: avoid symbol/DTYP clash with pva2pva

ioc: test record alias in group json

ioc: test put failure when SPC_NOMOD and DISP=1

ioc: test channel filters

ioc: unnecessary capture

ioc: avoid sharing Value between multiple subscriptions

It is possible to create two subscriptions through the same channel.

ioc: group subscription include queueSize

ioc: eliminate unused atomicMonitor

ioc: consolidate GroupSource::get()

avoid some indirection

ioc: pvRequest override of atomicPutGet

ioc: fix group non-atomic put

ioc: test asTrap hooks

ioc: test putOrder also sets field order

ioc: simplify GroupConfigProcessor::loadConfigFiles()

Also ensure that groupMapMutex is held

ioc: testqgroup cover JSON def.

ioc: dbLoadGroup() use macros

ioc: pvxsl() take integer argument

ioc: display.form and info(Q:form

ioc: "NO_ALARM" -> ""

ioc: use dbServer

at least for informational callbacks.

ioc: consolidate createRequestAndSubscriptionHandlers()

ioc: eliminate ChannelAndLock

properties dbChannel doesn't need a separate DBManyLock

ioc: test that putOrder also controls field order

ioc: MappingType -> MappingInfo

Handle info(Q:time:tag
Add +type:"const"

ioc: cleanup includes

ioc: test dbNotifyCancel()

ioc: inline checkForTrailingCommentsAtEnd()
2023-05-09 22:24:05 -07:00

110 lines
3.5 KiB
C++

/*
* Copyright - See the COPYRIGHT that is included with this distribution.
* pvxs is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*
* Author George S. McIntyre <george@level-n.com>, 2023
*
*/
#include <string>
#include <sstream>
#include <stdexcept>
#include <cstdlib>
#include "fieldname.h"
#include "utilpvt.h"
namespace pvxs {
namespace ioc {
/**
* Construct a Group field name from a field name string. The string is a sequence of components separated by
* periods each of which may be optionally followed by an array specifier. e.g. a.b[1].c.
*
* This constructor breaks the string on periods and stores each component in the fieldNameComponents member,
* while extracting the array reference where specified.
* @param fieldName
*/
FieldName::FieldName(const std::string& fieldName) {
if (!fieldName.empty()) {
// Split field name on periods
std::istringstream splitter(fieldName);
std::string fieldNamePart;
while (std::getline(splitter, fieldNamePart, '.')) {
if (fieldNamePart.empty()) {
throw std::runtime_error("Empty field component in: " + fieldName);
}
// If this is an array reference then extract the index
auto endArraySpecifier = fieldNamePart.size();
if (fieldNamePart[endArraySpecifier - 1] == ']') {
const size_t startArraySpecifier = fieldNamePart.find_last_of('[');
if (startArraySpecifier == std::string::npos) {
throw std::runtime_error("Invalid field array sub-script in : " + fieldName);
}
auto arrayIndex = fieldNamePart.substr(startArraySpecifier + 1);
long index = 0;
char* endScan;
index = strtol(arrayIndex.c_str(), &endScan, 10);
if (*endScan != ']') {
throw std::runtime_error("Invalid field array sub-script in : " + fieldName);
}
fieldNameComponents.emplace_back(fieldNamePart.substr(0, startArraySpecifier), index);
} else {
// Otherwise this is a regular field part
fieldNameComponents.emplace_back(fieldNamePart);
}
}
// If empty then throw an error
if (fieldNameComponents.empty()) {
throw std::runtime_error("Empty field name");
}
}
}
/**
* Convert this group field name to a string.
*
* @param padLength the amount of padding to add, defaults to none
*/
std::string FieldName::to_string(size_t padLength) const {
std::ostringstream strm;
strm<<(*this);
auto sofar(strm.tellp());
if(sofar >=0 && size_t(sofar) < padLength) {
for(auto i : range(padLength - size_t(sofar))) {
(void)i;
strm.put(PADDING_CHARACTER);
}
}
return strm.str();
}
std::ostream& operator<<(std::ostream& strm, const FieldName& name)
{
if (name.fieldNameComponents.empty()) {
strm<<"/";
} else {
bool first = true;
for (const auto& fieldNameComponent: name.fieldNameComponents) {
if (!first) {
strm.put('.');
} else {
first = false;
}
strm<<fieldNameComponent.name;
if (fieldNameComponent.isArray()) {
strm<<'['<<fieldNameComponent.index<<']';
}
}
}
return strm;
}
} // pvxs
} // ioc