From 76c00b78c97730e869e89518b5ea2d06cd12f4da Mon Sep 17 00:00:00 2001 From: Bruno Martins Date: Thu, 16 May 2019 13:18:07 -0400 Subject: [PATCH] Make Validator private --- src/Makefile | 3 +- src/ntndarray.cpp | 3 +- src/ntvalidator.cpp | 231 ---------------- src/validator.cpp | 247 ++++++++++++++++++ src/{pv/ntvalidator.h => validator.h} | 0 test/Makefile | 6 +- ...{ntvalidatorTest.cpp => validatorTest.cpp} | 2 +- 7 files changed, 254 insertions(+), 238 deletions(-) delete mode 100644 src/ntvalidator.cpp create mode 100644 src/validator.cpp rename src/{pv/ntvalidator.h => validator.h} (100%) rename test/{ntvalidatorTest.cpp => validatorTest.cpp} (96%) diff --git a/src/Makefile b/src/Makefile index 39fc5a2..3334d51 100644 --- a/src/Makefile +++ b/src/Makefile @@ -21,7 +21,6 @@ INC += pv/ntcontinuum.h INC += pv/nthistogram.h INC += pv/nturi.h INC += pv/ntndarrayAttribute.h -INC += pv/ntvalidator.h LIBSRCS += ntutils.cpp LIBSRCS += ntid.cpp @@ -42,7 +41,7 @@ LIBSRCS += ntcontinuum.cpp LIBSRCS += nthistogram.cpp LIBSRCS += nturi.cpp LIBSRCS += ntndarrayAttribute.cpp -LIBSRCS += ntvalidator.cpp +LIBSRCS += validator.cpp LIBRARY = nt diff --git a/src/ntndarray.cpp b/src/ntndarray.cpp index 22844f8..f8bfc7b 100644 --- a/src/ntndarray.cpp +++ b/src/ntndarray.cpp @@ -11,11 +11,12 @@ #include #include +#include "validator.h" + #define epicsExportSharedSymbols #include #include #include -#include using namespace std; using namespace epics::pvData; diff --git a/src/ntvalidator.cpp b/src/ntvalidator.cpp deleted file mode 100644 index 3693cba..0000000 --- a/src/ntvalidator.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* ntvalidator.cpp */ -/* - * Copyright information and license terms for this software can be - * found in the file LICENSE that is included with the distribution - */ - -#include -#include -#include - -#define epicsExportSharedSymbols -#include -#include - -namespace epics { namespace nt { - -using epics::pvData::Type; -using epics::pvData::Field; -using epics::pvData::Union; -using epics::pvData::UnionArray; -using epics::pvData::Structure; -using epics::pvData::StructureConstPtr; -using epics::pvData::StructureArray; -using epics::pvData::StringArray; -using epics::pvData::FieldConstPtr; -using epics::pvData::FieldConstPtrArray; -using epics::pvData::BitSet; - -using std::string; - -struct Helper -{ - Validator::Definition const & definition; - std::deque path; - Validator::Result result; - - Helper(Validator::Definition const & definition) : definition(definition) {} - - bool isOptional(Field const & field) const - { - return definition.optional.find(&field) != definition.optional.end(); - } - - string getCurrentPath(void) const - { - std::ostringstream os; - - // TODO: is there a better string join? - std::deque::const_iterator it; - for (it = path.cbegin(); it != path.cend(); ++it) { - if (it != path.cbegin()) - os << "."; - os << *it; - } - - return os.str(); - } - - void appendError(Validator::ErrorType type) - { - result.errors.push_back(Validator::Error(getCurrentPath(), type)); - } - - void appendError(Validator::ErrorType type, string const & field_name) - { - path.push_back(field_name); - appendError(type); - path.pop_back(); - } - - bool validate(Union const & ref, Union const & un) - { - // TODO: Validator Errors for unions could be more granular - if (&un == &ref) - return true; - - if (ref.isVariant() != un.isVariant()) { - appendError(Validator::ErrorType::INCORRECT_TYPE); - return false; - } - - if (ref.isVariant()) - return true; - - size_t numfields = ref.getNumberFields(); - - if (un.getNumberFields() != numfields) { - appendError(Validator::ErrorType::INCORRECT_TYPE); - return false; - } - - StringArray const & rnames = ref.getFieldNames(); - StringArray const & unames = un.getFieldNames(); - - if (!std::equal(rnames.cbegin(), rnames.cend(), unames.cend())) { - appendError(Validator::ErrorType::INCORRECT_TYPE); - return false; - } - - FieldConstPtrArray const & rfields = ref.getFields(); - FieldConstPtrArray const & ufields = un.getFields(); - - bool fields_ok = true; - for (size_t i = 0; i < numfields; ++i) { - path.push_back(rnames[i]); - fields_ok = fields_ok && validate(*rfields[i], *ufields[i]); - path.pop_back(); - } - - return fields_ok; - } - - bool validate(Structure const & ref, Structure const & struc) - { - if (&struc == &ref) - return true; - - StringArray const & rnames = ref.getFieldNames(); - StringArray const & snames = struc.getFieldNames(); - - // TODO: This is naive O(N^2), replace with better algorithm - // TODO: This assumes getField doesn't fail (there's no Field::getFieldT) - bool fields_ok = true; - StringArray::const_iterator ri; - for (ri = rnames.cbegin(); ri != rnames.cend(); ++ri) { - - FieldConstPtr rfield(ref.getField(*ri)); - - if (std::find(snames.cbegin(), snames.cend(), *ri) == snames.end()) { - if (isOptional(*rfield)) - continue; - - appendError(Validator::ErrorType::MISSING_FIELD, *ri); - fields_ok = false; - } else { - path.push_back(*ri); - - if (!validate(*rfield, *struc.getField(*ri))) { - appendError(Validator::ErrorType::INCORRECT_TYPE, *ri); - fields_ok = false; - } - - path.pop_back(); - } - } - - return fields_ok; - } - - bool validate(Field const & reference, Field const & field) - { - Type referenceType = reference.getType(); - if (referenceType != field.getType()) - return false; - - switch(referenceType) { - case Type::scalar: - case Type::scalarArray: - return true; - - case Type::structure: - return validate( - static_cast(reference), - static_cast(field) - ); - - case Type::structureArray: - return validate( - *static_cast(reference).getStructure(), - *static_cast(field).getStructure() - ); - - case Type::union_: - return validate( - static_cast(reference), - static_cast(field) - ); - - case Type::unionArray: - return validate( - *static_cast(reference).getUnion(), - *static_cast(field).getUnion() - ); - - default: - throw std::logic_error("Unknown Field type"); - return false; - } - } - - bool validate(Field const & field) - { - return validate(*definition.structure, field); - } -}; - -Validator::Result Validator::validate(Validator::Definition const & definition, - Field const & field) -{ - Helper helper(definition); - helper.validate(field); - return helper.result; -} - -bool Validator::isCompatible(Validator::Definition const & definition, - Field const & field) -{ - return Helper(definition).validate(field); -} - -bool Validator::isCompatible(Validator::Definition const & definition, - StructureConstPtr const & structure) -{ - FieldConstPtr field(std::static_pointer_cast(structure)); - return Validator::isCompatible(definition, *field); -} - -std::ostream& operator<<(std::ostream& o, const Validator::Error& error) -{ - switch (error.type) { - case Validator::ErrorType::MISSING_FIELD: - return o << "Missing field '" << error.path << "'"; - case Validator::ErrorType::INCORRECT_TYPE: - return o << "Field '" << error.path << "' has incorrect type"; - default: - return o << "Unknown error " << error.type << " in field '" - << error.path << "'"; - } -} - -}} diff --git a/src/validator.cpp b/src/validator.cpp new file mode 100644 index 0000000..84efa80 --- /dev/null +++ b/src/validator.cpp @@ -0,0 +1,247 @@ +/* ntvalidator.cpp */ +/* + * Copyright information and license terms for this software can be + * found in the file LICENSE that is included with the distribution + */ + +#include +#include +#include + +#include "validator.h" + +#define epicsExportSharedSymbols +#include + +namespace epics { namespace nt { + +using epics::pvData::Type; +using epics::pvData::Field; +using epics::pvData::Union; +using epics::pvData::UnionArray; +using epics::pvData::Structure; +using epics::pvData::StructureConstPtr; +using epics::pvData::StructureArray; +using epics::pvData::StringArray; +using epics::pvData::FieldConstPtr; +using epics::pvData::FieldConstPtrArray; +using epics::pvData::BitSet; + +using std::string; + +namespace { + +struct Helper { + Validator::Definition const & definition; + std::deque path; + Validator::Result result; + + Helper(Validator::Definition const & definition); + bool isOptional(Field const & field) const; + string getCurrentPath(void) const; + void appendError(Validator::ErrorType type); + void appendError(Validator::ErrorType type, string const & field_name); + bool validate(Union const & ref, Union const & un); + bool validate(Structure const & ref, Structure const & struc); + bool validate(Field const & reference, Field const & field); + bool validate(Field const & field); +}; + +Helper::Helper(Validator::Definition const & definition) : definition(definition) {} + +bool Helper::isOptional(Field const & field) const +{ + return definition.optional.find(&field) != definition.optional.end(); +} + +string Helper::getCurrentPath(void) const +{ + std::ostringstream os; + + // TODO: is there a better string join? + std::deque::const_iterator it; + for (it = path.cbegin(); it != path.cend(); ++it) { + if (it != path.cbegin()) + os << "."; + os << *it; + } + + return os.str(); + } + +void Helper::appendError(Validator::ErrorType type) +{ + result.errors.push_back(Validator::Error(getCurrentPath(), type)); +} + +void Helper::appendError(Validator::ErrorType type, string const & field_name) +{ + path.push_back(field_name); + appendError(type); + path.pop_back(); +} + +bool Helper::validate(Union const & ref, Union const & un) +{ + // TODO: Validator Errors for unions could be more granular + if (&un == &ref) + return true; + + if (ref.isVariant() != un.isVariant()) { + appendError(Validator::ErrorType::INCORRECT_TYPE); + return false; + } + + if (ref.isVariant()) + return true; + + size_t numfields = ref.getNumberFields(); + + if (un.getNumberFields() != numfields) { + appendError(Validator::ErrorType::INCORRECT_TYPE); + return false; + } + + StringArray const & rnames = ref.getFieldNames(); + StringArray const & unames = un.getFieldNames(); + + if (!std::equal(rnames.cbegin(), rnames.cend(), unames.cend())) { + appendError(Validator::ErrorType::INCORRECT_TYPE); + return false; + } + + FieldConstPtrArray const & rfields = ref.getFields(); + FieldConstPtrArray const & ufields = un.getFields(); + + bool fields_ok = true; + for (size_t i = 0; i < numfields; ++i) { + path.push_back(rnames[i]); + fields_ok = fields_ok && validate(*rfields[i], *ufields[i]); + path.pop_back(); + } + + return fields_ok; +} + +bool Helper::validate(Structure const &ref, Structure const &struc) +{ + if (&struc == &ref) + return true; + + StringArray const &rnames = ref.getFieldNames(); + StringArray const &snames = struc.getFieldNames(); + + // TODO: This is naive O(N^2), replace with better algorithm + // TODO: This assumes getField doesn't fail (there's no Field::getFieldT) + bool fields_ok = true; + StringArray::const_iterator ri; + for (ri = rnames.cbegin(); ri != rnames.cend(); ++ri) + { + + FieldConstPtr rfield(ref.getField(*ri)); + + if (std::find(snames.cbegin(), snames.cend(), *ri) == snames.end()) + { + if (isOptional(*rfield)) + continue; + + appendError(Validator::ErrorType::MISSING_FIELD, *ri); + fields_ok = false; + } + else + { + path.push_back(*ri); + + if (!validate(*rfield, *struc.getField(*ri))) + { + appendError(Validator::ErrorType::INCORRECT_TYPE, *ri); + fields_ok = false; + } + + path.pop_back(); + } + } + + return fields_ok; +} + +bool Helper::validate(Field const &reference, Field const &field) +{ + Type referenceType = reference.getType(); + if (referenceType != field.getType()) + return false; + + switch (referenceType) + { + case Type::scalar: + case Type::scalarArray: + return true; + + case Type::structure: + return validate( + static_cast(reference), + static_cast(field)); + + case Type::structureArray: + return validate( + *static_cast(reference).getStructure(), + *static_cast(field).getStructure()); + + case Type::union_: + return validate( + static_cast(reference), + static_cast(field)); + + case Type::unionArray: + return validate( + *static_cast(reference).getUnion(), + *static_cast(field).getUnion()); + + default: + throw std::logic_error("Unknown Field type"); + return false; + } +} + +bool Helper::validate(Field const &field) +{ + return validate(*definition.structure, field); +} +} + + +Validator::Result Validator::validate(Validator::Definition const & definition, + Field const & field) +{ + Helper helper(definition); + helper.validate(field); + return helper.result; +} + +bool Validator::isCompatible(Validator::Definition const & definition, + Field const & field) +{ + return Helper(definition).validate(field); +} + +bool Validator::isCompatible(Validator::Definition const & definition, + StructureConstPtr const & structure) +{ + FieldConstPtr field(std::static_pointer_cast(structure)); + return Validator::isCompatible(definition, *field); +} + +std::ostream& operator<<(std::ostream& o, const Validator::Error& error) +{ + switch (error.type) { + case Validator::ErrorType::MISSING_FIELD: + return o << "Missing field '" << error.path << "'"; + case Validator::ErrorType::INCORRECT_TYPE: + return o << "Field '" << error.path << "' has incorrect type"; + default: + return o << "Unknown error " << error.type << " in field '" + << error.path << "'"; + } +} + +}} diff --git a/src/pv/ntvalidator.h b/src/validator.h similarity index 100% rename from src/pv/ntvalidator.h rename to src/validator.h diff --git a/test/Makefile b/test/Makefile index e225719..b6535de 100644 --- a/test/Makefile +++ b/test/Makefile @@ -72,9 +72,9 @@ TESTPROD_HOST += ntutilsTest ntutilsTest_SRCS = ntutilsTest.cpp TESTS += ntutilsTest -TESTPROD_HOST += ntvalidatorTest -ntutilsTest_SRCS = ntvalidatorTest.cpp -TESTS += ntvalidatorTest +TESTPROD_HOST += validatorTest +ntutilsTest_SRCS = validatorTest.cpp +TESTS += validatorTest TESTSCRIPTS_HOST += $(TESTS:%=%.t) diff --git a/test/ntvalidatorTest.cpp b/test/validatorTest.cpp similarity index 96% rename from test/ntvalidatorTest.cpp rename to test/validatorTest.cpp index 3f1afc4..ce53a64 100644 --- a/test/ntvalidatorTest.cpp +++ b/test/validatorTest.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include "../src/validator.h" #include using namespace epics::nt;