Validator: add simple Result caching

This commit is contained in:
Bruno Martins
2019-05-29 14:22:47 -04:00
committed by mdavidsaver
parent e0d422ffd9
commit 31050952b6
18 changed files with 218 additions and 88 deletions

View File

@ -193,15 +193,20 @@ bool NTAggregate::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTAggregate::isCompatible(StructureConstPtr const &structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
return result
if (result.wraps(structure))
return result.valid();
return result.reset(structure)
.is<Structure>()
.has<Scalar>("value")
.has<Scalar>("N")

View File

@ -130,14 +130,20 @@ bool NTAttribute::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTAttribute::isCompatible(StructureConstPtr const & structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
return result
if (result.wraps(structure))
return result.valid();
return result.reset(structure)
.is<Structure>()
.has<Scalar>("name")
.has<Union>("value")

View File

@ -122,14 +122,20 @@ bool NTContinuum::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTContinuum::isCompatible(StructureConstPtr const & structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
return result
if (result.wraps(structure))
return result.valid();
return result.reset(structure)
.is<Structure>()
.has<ScalarArray>("base")
.has<ScalarArray>("value")

View File

@ -121,14 +121,20 @@ bool NTEnum::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTEnum::isCompatible(StructureConstPtr const &structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
return result
if (result.wraps(structure))
return result.valid();
return result.reset(structure)
.is<Structure>()
.has<&NTField::isEnumerated, Structure>("value")
.maybeHas<Scalar>("descriptor")

View File

@ -39,12 +39,6 @@ Result& NTField::isEnumerated(Result& result)
.has<ScalarArray>("choices");
}
bool NTField::isEnumerated(FieldConstPtr const & field)
{
Result result(field);
return isEnumerated(result.is<Structure>()).valid();
}
Result& NTField::isTimeStamp(Result& result)
{
return result
@ -53,12 +47,6 @@ Result& NTField::isTimeStamp(Result& result)
.has<Scalar>("userTag");
}
bool NTField::isTimeStamp(FieldConstPtr const & field)
{
Result result(field);
return isTimeStamp(result.is<Structure>()).valid();
}
Result& NTField::isAlarm(Result& result)
{
return result
@ -67,12 +55,6 @@ Result& NTField::isAlarm(Result& result)
.has<Scalar>("message");
}
bool NTField::isAlarm(FieldConstPtr const & field)
{
Result result(field);
return isAlarm(result.is<Structure>()).valid();
}
Result& NTField::isDisplay(Result& result)
{
return result
@ -81,13 +63,6 @@ Result& NTField::isDisplay(Result& result)
.has<Scalar>("description")
.has<Scalar>("format")
.has<Scalar>("units");
}
bool NTField::isDisplay(FieldConstPtr const & field)
{
Result result(field);
return isDisplay(result.is<Structure>()).valid();
}
Result& NTField::isAlarmLimit(Result& result)
@ -105,12 +80,6 @@ Result& NTField::isAlarmLimit(Result& result)
.has<Scalar>("hysteresis");
}
bool NTField::isAlarmLimit(FieldConstPtr const & field)
{
Result result(field);
return isAlarmLimit(result.is<Structure>()).valid();
}
Result& NTField::isControl(Result& result)
{
return result
@ -119,11 +88,24 @@ Result& NTField::isControl(Result& result)
.has<Scalar>("minStep");
}
bool NTField::isControl(FieldConstPtr const & field)
{
Result result(field);
return isControl(result.is<Structure>()).valid();
}
#define IS_NTFIELD_FUNC(name) \
static epicsThreadOnceId cached##name##OnceId = EPICS_THREAD_ONCE_INIT; \
static epicsThreadPrivateId cached##name##Id; \
bool NTField::is##name(FieldConstPtr const & field) { \
Result& result = Result::fromCache(&cached##name##OnceId, \
&cached##name##Id); \
if (result.wraps(field)) return result.valid(); \
return is##name(result.reset(field).is<Structure>()).valid(); \
}
IS_NTFIELD_FUNC(Enumerated)
IS_NTFIELD_FUNC(TimeStamp)
IS_NTFIELD_FUNC(Alarm)
IS_NTFIELD_FUNC(Display)
IS_NTFIELD_FUNC(AlarmLimit)
IS_NTFIELD_FUNC(Control)
#undef IS_NTFIELD_FUNC
StructureConstPtr NTField::createEnumerated()
{

View File

@ -135,14 +135,20 @@ bool NTHistogram::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTHistogram::isCompatible(StructureConstPtr const &structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
return result
if (result.wraps(structure))
return result.valid();
return result.reset(structure)
.is<Structure>()
.has<ScalarArray>("ranges")
.has<ScalarArray>("value")

View File

@ -139,14 +139,20 @@ bool NTMatrix::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTMatrix::isCompatible(StructureConstPtr const & structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
return result
if (result.wraps(structure))
return result.valid();
return result.reset(structure)
.is<Structure>()
.has<ScalarArray>("value")
.maybeHas<ScalarArray>("dim")

View File

@ -232,14 +232,20 @@ bool NTMultiChannel::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTMultiChannel::isCompatible(StructureConstPtr const & structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
return result
if (result.wraps(structure))
return result.valid();
return result.reset(structure)
.is<Structure>()
.has<UnionArray>("value")
.has<ScalarArray>("channelName")

View File

@ -134,14 +134,20 @@ bool NTNameValue::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTNameValue::isCompatible(StructureConstPtr const & structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
if (result.wraps(structure))
return result.valid();
return result
return result.reset(structure)
.is<Structure>()
.has<ScalarArray>("name")
.has<ScalarArray>("value")

View File

@ -252,14 +252,20 @@ namespace {
}
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTNDArray::isCompatible(StructureConstPtr const &structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
return result
if (result.wraps(structure))
return result.valid();
return result.reset(structure)
.is<Structure>()
.has<&isValue>("value")
.has<&isCodec>("codec")
@ -276,7 +282,6 @@ bool NTNDArray::isCompatible(StructureConstPtr const &structure)
.valid();
}
bool NTNDArray::isCompatible(PVStructurePtr const & pvStructure)
{
if(!pvStructure.get()) return false;

View File

@ -146,13 +146,20 @@ Result& NTNDArrayAttribute::isAttribute(Result& result) {
.has<Scalar>("source");
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTNDArrayAttribute::isCompatible(StructureConstPtr const & structure)
{
if (!structure)
return false;
Result result(structure);
return isAttribute(result.is<Structure>()).valid();
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
if (result.wraps(structure))
return result.valid();
return isAttribute(result.reset(structure).is<Structure>()).valid();
}
bool NTNDArrayAttribute::isCompatible(PVStructurePtr const & pvStructure)

View File

@ -152,14 +152,20 @@ bool NTScalar::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTScalar::isCompatible(StructureConstPtr const &structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
return result
if (result.wraps(structure))
return result.valid();
return result.reset(structure)
.is<Structure>()
.has<Scalar>("value")
.maybeHas<Scalar>("descriptor")

View File

@ -161,14 +161,20 @@ bool NTScalarArray::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTScalarArray::isCompatible(StructureConstPtr const & structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
return result
if (result.wraps(structure))
return result.valid();
return result.reset(structure)
.is<Structure>()
.has<ScalarArray>("value")
.maybeHas<Scalar>("descriptor")

View File

@ -227,14 +227,20 @@ bool NTScalarMultiChannel::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTScalarMultiChannel::isCompatible(StructureConstPtr const & structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
return result
if (result.wraps(structure))
return result.valid();
return result.reset(structure)
.is<Structure>()
.has<ScalarArray>("value")
.has<ScalarArray>("channelName")

View File

@ -148,14 +148,20 @@ bool NTTable::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTTable::isCompatible(StructureConstPtr const & structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
result
if (result.wraps(structure))
return result.valid();
result.reset(structure)
.is<Structure>()
.has<Structure>("value")
.has<ScalarArray>("labels")

View File

@ -128,14 +128,20 @@ bool NTUnion::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTUnion::isCompatible(StructureConstPtr const &structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
return result
if (result.wraps(structure))
return result.valid();
return result.reset(structure)
.is<Structure>()
.has<Union>("value")
.maybeHas<Scalar>("descriptor")

View File

@ -148,14 +148,20 @@ bool NTURI::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT;
static epicsThreadPrivateId cachedResultId;
bool NTURI::isCompatible(StructureConstPtr const & structure)
{
if (!structure)
return false;
Result result(structure);
Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId);
result
if (result.wraps(structure))
return result.valid();
result.reset(structure)
.is<Structure>()
.has<Scalar>("scheme")
.has<Scalar>("path")

View File

@ -9,6 +9,8 @@
#include <string>
#include <set>
#include <epicsThread.h>
#include <pv/pvIntrospect.h>
namespace epics { namespace nt {
@ -48,8 +50,8 @@ struct Result {
}
};
const epics::pvData::FieldConstPtr f;
const std::string path;
epics::pvData::FieldConstPtr field;
std::string path;
std::vector<Error> errors;
enum result_t {
@ -57,8 +59,10 @@ struct Result {
Fail,
} result;
explicit Result(const epics::pvData::FieldConstPtr& f, const std::string& path = std::string())
: f(f), path(path), errors(), result(Pass) {}
Result(const epics::pvData::FieldConstPtr& field, const std::string& path = std::string())
: field(field), path(path), errors(), result(Pass) {}
Result() {}
Result& operator|=(const Result& other) {
result = std::max(result, other.result);
@ -66,12 +70,56 @@ struct Result {
return *this;
}
/**
* Clears the contents of this Result.
*
* @return a reference to itself.
*/
Result& reset(const epics::pvData::FieldConstPtr& newField) {
field = newField;
path.clear();
errors.clear();
result = Pass;
return *this;
}
/**
* Retrieves a Result from a thread-local cache. Allocates a new Result
* if it wasn't allocated yet.
*
* @return a reference to the stored Result.
*
*/
static Result& fromCache(epicsThreadOnceId *onceId, epicsThreadPrivateId *cachedId) {
epicsThreadOnce(onceId, &once, static_cast<void*>(cachedId));
Result *result = static_cast<Result*>(epicsThreadPrivateGet(*cachedId));
if (!result) {
result = new Result;
epicsThreadPrivateSet(*cachedId, result);
}
return *result;
}
/**
* Returns whether this Result already wraps a particular Field.
* Note: this is done via pointer equality, which pvData guarantees
* will work if the pointed-to Fields are the same.
*
* @return true if it does wrap the passed-in field, false otherwise.
*/
inline bool wraps(epics::pvData::FieldConstPtr const & other) const {
return field && field == other;
}
/**
* Returns whether this Result is valid.
*
* @return true if all tests passed, false otherwise.
*/
bool valid(void) const {
inline bool valid(void) const {
return result == Pass;
}
@ -84,7 +132,7 @@ struct Result {
*/
template<typename T>
Result& is(void) {
if (!dynamic_cast<T const *>(f.get())) {
if (!dynamic_cast<T const *>(field.get())) {
result = Fail;
errors.push_back(Error(path, Error::IncorrectType));
}
@ -103,7 +151,7 @@ struct Result {
*/
template<typename T>
Result& is(const std::string& id) {
T const *s = dynamic_cast<T const *>(f.get());
T const *s = dynamic_cast<T const *>(field.get());
if (!s) {
result = Fail;
errors.push_back(Error(path, Error::IncorrectType));
@ -199,20 +247,20 @@ struct Result {
private:
template<typename T>
Result& has(const std::string& name, bool optional, Result& (*check)(Result&) = NULL) {
epics::pvData::FieldConstPtr field;
epics::pvData::FieldConstPtr subField;
switch(f->getType()) {
switch(field->getType()) {
case epics::pvData::Type::structure:
field = static_cast<epics::pvData::Structure const *>(f.get())->getField(name);
subField = static_cast<epics::pvData::Structure const *>(field.get())->getField(name);
break;
case epics::pvData::Type::structureArray:
field = static_cast<epics::pvData::StructureArray const *>(f.get())->getStructure()->getField(name);
subField = static_cast<epics::pvData::StructureArray const *>(field.get())->getStructure()->getField(name);
break;
case epics::pvData::Type::union_:
field = static_cast<epics::pvData::Union const *>(f.get())->getField(name);
subField = static_cast<epics::pvData::Union const *>(field.get())->getField(name);
break;
case epics::pvData::Type::unionArray:
field = static_cast<epics::pvData::UnionArray const *>(f.get())->getUnion()->getField(name);
subField = static_cast<epics::pvData::UnionArray const *>(field.get())->getUnion()->getField(name);
break;
default:
// Expected a structure-like Field
@ -221,23 +269,28 @@ private:
return *this;
}
std::string fieldPath(path.empty() ? name : path + "." + name);
std::string subFieldPath(path.empty() ? name : path + "." + name);
if (!field) {
if (!subField) {
if (!optional) {
result = Fail;
errors.push_back(Error(fieldPath, Error::Type::MissingField));
errors.push_back(Error(subFieldPath, Error::Type::MissingField));
}
} else if (!dynamic_cast<T const *>(field.get())) {
} else if (!dynamic_cast<T const *>(subField.get())) {
result = Fail;
errors.push_back(Error(fieldPath, Error::Type::IncorrectType));
errors.push_back(Error(subFieldPath, Error::Type::IncorrectType));
} else if (check) {
Result r(field, fieldPath);
Result r(subField, subFieldPath);
*this |= check(r);
}
return *this;
}
static void once(void *arg) {
epicsThreadPrivateId *id = static_cast<epicsThreadPrivateId *>(arg);
*id = epicsThreadPrivateCreate();
}
};
}}