75 Commits

Author SHA1 Message Date
Andrew Johnson
d0022ed5f6 Update version numbers after tagging 2025-12-15 10:39:07 -06:00
Andrew Johnson
e67486c319 Final commit for 6.0.2 2025-12-15 10:18:01 -06:00
Andrew Johnson
4f1da262d2 Replease UNRELEASED for EPICS 7.0.10 2025-12-15 10:11:49 -06:00
Andrew Johnson
65c31491d9 Updates to Release Notes
Document the NTNDArray::getValueSize() fix.
Fix markdown errors, back-quoting identifiers with "_" chars.
Reformat the text to use semantic line breaks: https://sembr.org/
2025-11-05 12:10:27 -06:00
Andrew Johnson
5450f564dc Merge pull request #20 from JJL772/pr-fix-possible-nullptr-deref
Fix possible NULL deref in NTNDArray::getValueSize()
2025-04-04 09:53:04 -05:00
JJL772
453c267c9b Fix possible NULL deref in NTNDArray::getValueSize() 2024-06-21 16:47:54 -07:00
7a2d264f2c removed empty lines at end of file 2020-04-15 08:01:07 -07:00
03f9c1ab07 removed spaces at end of line 2020-04-15 08:01:07 -07:00
Andrew Johnson
6d41566b40 Incr version and set development flag after release 2019-10-31 16:34:40 -05:00
Andrew Johnson
1250a3c236 Reset development flag for 6.0.1 release 2019-10-31 16:30:33 -05:00
Andrew Johnson
28e5defc9b Document read-the-docs in Release Notes for 6.0.1 2019-10-31 16:29:32 -05:00
Ralph Lange
fbe1a1135f doc: fix link to reference manual 2019-09-06 10:42:53 +02:00
Ralph Lange
b75f942d5a doc: update/improve ntCPP.rst
- update Sourceforge links
- rename V4 -> 7
- shorten section names
2019-09-06 10:42:53 +02:00
Ralph Lange
e83ce61bf6 rtd-ci: add read-the-docs integration 2019-09-06 10:42:53 +02:00
Ralph Lange
86d8b5deec doc: change doxygen HTML_OUTPUT to html/doxygen 2019-09-05 14:52:59 +02:00
Ralph Lange
abbcf486b8 doc: make doxygen search src (not include) 2019-09-05 13:05:18 +02:00
Ralph Lange
e286d32716 doc: convert ntCPP.html to ntCPP.rst 2019-09-05 11:51:17 +02:00
Andrew Johnson
ba33c7443c Update version number to 6.0.1 DEVELOPMENT 2019-08-13 11:09:49 -05:00
Andrew Johnson
c6168a7477 New CONFIG_NTYPES_VERSION file, use for SHRLIB_VERSION 2019-07-29 11:14:27 -05:00
Bruno Martins
dd2aa1863d Bump SHRLIB version 2019-07-26 17:04:30 -04:00
Bruno Martins
66737740ef Add isCompatible reimplementation note to RELEASE_NOTES 2019-07-26 17:02:28 -04:00
Bruno Martins
54bddc9942 NTNDArrayAttribute: fix forward declaration of Result 2019-06-14 11:43:42 -04:00
Bruno Martins
02151964a9 NTField: fix forward declaration of Result 2019-06-14 08:41:27 -04:00
Bruno Martins
d366cc9682 Validator: explicitly include <algorithm> 2019-06-14 08:41:10 -04:00
Bruno Martins
1cac2ccd7e Add -DNOMINMAX to Windows builds 2019-06-13 16:45:54 -04:00
Bruno Martins
9702b68d72 Remove cache implementation, to be discussed and done later 2019-06-13 11:08:25 -07:00
Bruno Martins
6a163d7fd4 Make Travis happy 2019-06-13 11:08:25 -07:00
Bruno Martins
1832c417e6 Make Travis happy 2019-06-13 11:08:25 -07:00
Bruno Martins
148cfef572 Make Travis happy 2019-06-13 11:08:25 -07:00
Bruno Martins
31050952b6 Validator: add simple Result caching 2019-06-13 11:08:25 -07:00
Bruno Martins
e0d422ffd9 Validator: fix path handling and tests Makefile 2019-06-13 11:08:25 -07:00
Bruno Martins
452f2379a1 Validator: use it in all remaining normative types 2019-06-13 11:08:25 -07:00
Bruno Martins
e2d95128a3 Validator: add some documentation 2019-06-13 11:08:25 -07:00
Bruno Martins
3a178ea5c4 Use Validator API for ntattribute and ntndarrayattribute 2019-06-13 11:08:25 -07:00
Bruno Martins
24489f6535 NTField: remove is<Structure> check from its is* methods 2019-06-13 11:08:25 -07:00
Bruno Martins
28ca7ac1ab Validator: '{maybe,}has<fn>' becomes {maybe,}has<fn, T=Field> to allow for optional specific type checking 2019-06-13 11:08:25 -07:00
Bruno Martins
5a0b42fec7 Remove leftover 'once' declaration from ntndarray.h 2019-06-13 11:08:25 -07:00
Bruno Martins
35bf9dcb13 Revert changes in NTNDArray's builder: should be part of a separate PR 2019-06-13 11:08:25 -07:00
Bruno Martins
f22b5d5b7b Completely rework Validator API 2019-06-13 11:08:25 -07:00
Bruno Martins
9923459c4b Formatting 2019-06-13 11:08:25 -07:00
Bruno Martins
50a7208174 Fix NTNDArray Validator 2019-06-13 11:08:25 -07:00
Bruno Martins
7e7949b1fa Rework Validator API, allow extra Union fields, add tests 2019-06-13 11:08:25 -07:00
Bruno Martins
76c00b78c9 Make Validator private 2019-06-13 11:08:25 -07:00
Bruno Martins
1676192dd1 Fix ifdef guard for shared symbols 2019-06-13 11:08:25 -07:00
Bruno Martins
b76c91a885 Begin work on general NT validator 2019-06-13 11:08:25 -07:00
Michael Davidsaver
2d186d40d5 remove use of Display.setFormat 2019-05-05 19:42:57 -07:00
Andrew Johnson
e803240fbf Update SHRLIB_VERSION 2019-03-20 13:57:00 -05:00
Michael Davidsaver
54c07f705f update docs 2019-03-12 19:45:30 -07:00
Michael Davidsaver
fa23ddd370 NTTable::getColumnNames() wrong field 2019-03-12 17:42:36 -07:00
Andrew Johnson
41d56fdf89 Update version numbers and formatting in documentation 2018-12-17 16:05:45 -06:00
Andrew Johnson
a65fc3ef30 Update and unify README.md 2018-12-17 16:04:09 -06:00
Michael Davidsaver
b69bc44974 5.2.1 2018-11-26 11:52:01 -08:00
Michael Davidsaver
a90f0173a7 drop redundant generated html 2018-11-26 11:50:39 -08:00
Michael Davidsaver
83342beb7e travis-ci dropped 3.14 2018-10-29 19:42:12 -07:00
Michael Davidsaver
f6e6cf037f update travis-ci 2018-10-29 17:57:18 -07:00
Andrew Johnson
80920ae0b0 Clean up warnings
Removed unused member variables 'bool dim'.
2018-01-04 17:16:34 -06:00
Michael Davidsaver
1f7667b22d drop prototype PVNTField::createAlarmLimit
not implemented.
2017-12-19 17:15:37 -06:00
Ralph Lange
e15e84fb14 jenkins-ci: fix/update CloudBees jobs 2017-12-19 09:58:49 +01:00
Andrew Johnson
ba2e1c8a1d Update documentation for 5.2.0 release 2017-12-14 17:30:55 -06:00
Andrew Johnson
fb6873e9a3 Applied documentation changes since 5.0.0 to the master branch 2017-12-14 17:21:40 -06:00
Michael Davidsaver
2f4c0eea9d missing include 2017-12-12 09:43:25 -06:00
Andrew Johnson
a2b635c2fe Include <top>/../RELEASE.<host>.local 2017-12-06 20:35:26 -06:00
Andrew Johnson
abd029aa71 Use 'make test-results' in travis-build script 2017-11-30 12:00:28 -06:00
Andrew Johnson
57c6d07a93 Unify .gitignore file 2017-11-30 11:59:45 -06:00
Michael Davidsaver
91c5136883 Test for missing "attribute" array in NTNDArray 2017-11-21 10:59:23 -06:00
Ralph Lange
5e151c3b7a jenkins: remove microbench option and pvCommon dependency from CB build 2017-11-15 17:25:51 +01:00
Ralph Lange
fc4b51cb49 travis-ci: consolidate travis configuration 2017-09-28 15:10:04 +02:00
Ralph Lange
fc703958b3 travis-ci: minor configuration fix 2017-09-27 15:34:02 +02:00
Ralph Lange
1b156c92cd travis-ci: update/streamline configuration for EPICS 7 2017-09-27 12:00:06 +02:00
Marty Kraimer
2c75f1d1e9 Merge pull request #13 from mrkraimer/master
create travis files
2017-09-13 05:31:22 -04:00
mrkraimer
e03096c35e create travis files 2017-09-13 05:14:10 -04:00
Bruno Martins
4b0970ffcb Set tags to false inside reset. Fixes #11 2017-07-26 17:19:45 +02:00
Dave Hickin
048d6ef737 NTUnionBuilder: Add missing value() function
Add missing function NTUnionBuilder::value() to allow the union type of
the NTUnion's value field to be specified.
2016-09-09 18:07:59 +01:00
Ralph Lange
4768444b8a Add QtCreator wildcard to .gitignore 2016-07-28 11:56:26 +02:00
Dave Hickin
0ce3613acc SHRLIB: Set version to 5.2 2016-07-22 17:06:37 +01:00
66 changed files with 4792 additions and 2787 deletions

10
.ci/travis-build.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/sh
set -e -x
make -j2 $EXTRA
if [ "$TEST" != "NO" ]
then
make -j2 tapfiles
make -j2 -s test-results
fi

107
.ci/travis-prepare.sh Executable file
View File

@@ -0,0 +1,107 @@
#!/bin/sh
set -e -x
CURDIR="$PWD"
cat << EOF > $CURDIR/configure/RELEASE.local
EPICS_BASE=$HOME/.source/epics-base
EOF
install -d "$HOME/.source"
cd "$HOME/.source"
add_gh_flat() {
MODULE=$1
REPOOWNER=$2
REPONAME=$3
BRANCH=$4
MODULE_UC=$(echo $MODULE | tr 'a-z' 'A-Z')
( git clone --quiet --depth 5 --branch $BRANCH https://github.com/$REPOOWNER/$REPONAME.git $MODULE && \
cd $MODULE && git log -n1 )
cat < $CURDIR/configure/RELEASE.local > $MODULE/configure/RELEASE.local
cat << EOF >> $CURDIR/configure/RELEASE.local
${MODULE_UC}=$HOME/.source/$MODULE
EOF
}
# not recursive
git clone --quiet --depth 5 --branch "$BRBASE" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base
(cd epics-base && git log -n1 )
add_gh_flat pvData ${REPOPVD:-epics-base} pvDataCPP ${BRPVD:-master}
if [ -e $CURDIR/configure/RELEASE.local ]
then
cat $CURDIR/configure/RELEASE.local
fi
EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch`
# requires wine and g++-mingw-w64-i686
if [ "$WINE" = "32" ]
then
echo "Cross mingw32"
sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
CMPLR_PREFIX=i686-w64-mingw32-
EOF
cat << EOF >> epics-base/configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw
EOF
fi
if [ "$STATIC" = "YES" ]
then
echo "Build static libraries/executables"
cat << EOF >> epics-base/configure/CONFIG_SITE
SHARED_LIBRARIES=NO
STATIC_BUILD=YES
EOF
fi
case "$CMPLR" in
clang)
echo "Host compiler is clang"
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH
GNU = NO
CMPLR_CLASS = clang
CC = clang
CCC = clang++
EOF
# hack
sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' epics-base/configure/CONFIG.gnuCommon
clang --version
;;
*)
echo "Host compiler is default"
gcc --version
;;
esac
cat <<EOF >> epics-base/configure/CONFIG_SITE
USR_CPPFLAGS += $USR_CPPFLAGS
USR_CFLAGS += $USR_CFLAGS
USR_CXXFLAGS += $USR_CXXFLAGS
EOF
# set RTEMS to eg. "4.9" or "4.10"
# requires qemu, bison, flex, texinfo, install-info
if [ -n "$RTEMS" ]
then
echo "Cross RTEMS${RTEMS} for pc386"
curl -L "https://github.com/mdavidsaver/rsb/releases/download/20171203-${RTEMS}/i386-rtems${RTEMS}-trusty-20171203-${RTEMS}.tar.bz2" \
| tar -C / -xmj
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' epics-base/configure/os/CONFIG_SITE.Common.RTEMS
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.RTEMS
RTEMS_VERSION=$RTEMS
RTEMS_BASE=$HOME/.rtems
EOF
cat << EOF >> epics-base/configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS += RTEMS-pc386-qemu
EOF
fi
make -j2 -C epics-base $EXTRA
make -j2 -C pvData $EXTRA

24
.gitignore vendored
View File

@@ -1,10 +1,14 @@
bin/
include/
lib/
db/
dbd/
configure/*.local
html/
**/O.*
**/**/O.*
QtC-*
/cfg/
/bin/
/lib/
/db/
/dbd/
/html/
/include/
/templates/
/configure/*.local
O.*/
/QtC-*
*.orig
*.log
.*.swp

17
.readthedocs.yml Normal file
View File

@@ -0,0 +1,17 @@
# .readthedocs.yml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Build documentation in the documentation/ directory with Sphinx
sphinx:
configuration: documentation/conf.py
# Build documentation with MkDocs
#mkdocs:
# configuration: mkdocs.yml
# Optionally build your docs in additional formats such as PDF and ePub
formats: all

31
.travis.yml Normal file
View File

@@ -0,0 +1,31 @@
sudo: false
dist: trusty
language: c++
compiler:
- gcc
addons:
apt:
packages:
- libreadline6-dev
- libncurses5-dev
- perl
- clang
- g++-mingw-w64-i686
- qemu-system-x86
install:
- ./.ci/travis-prepare.sh
script:
- ./.ci/travis-build.sh
env:
- BRBASE=7.0
- BRBASE=7.0 CMPLR=clang
- BRBASE=7.0 EXTRA="CMD_CXXFLAGS=-std=c++98"
- BRBASE=7.0 EXTRA="CMD_CXXFLAGS=-std=c++11"
- BRBASE=7.0 CMPLR=clang EXTRA="CMD_CXXFLAGS=-std=c++11"
- BRBASE=7.0 WINE=32 TEST=NO STATIC=YES
- BRBASE=7.0 WINE=32 TEST=NO STATIC=NO
- BRBASE=7.0 RTEMS=4.10 TEST=NO
- BRBASE=7.0 RTEMS=4.9 TEST=NO
- BRBASE=3.16
- BRBASE=3.15
- BRBASE=3.14

View File

@@ -38,7 +38,7 @@ PROJECT_NAME = normativeTypesCPP
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER =
PROJECT_NUMBER = 6.0.3-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -743,7 +743,7 @@ WARN_LOGFILE =
# spaces.
# Note: If this tag is empty the current directory is searched.
INPUT = include
INPUT = src
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -1008,7 +1008,7 @@ GENERATE_HTML = YES
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = documentation/html
HTML_OUTPUT = html/doxygen
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).

View File

@@ -1,78 +1,17 @@
normativeTypesCPP
=================
# normativeTypesCPP
normativeTypesCPP is a C++ module containing helper classes which implement
and provide support for the EPICS V4 Normative Types.
The EPICS **Normative Types** are a set of standard high-level data types, designed to aid interoperability between EPICS PVA applications.
The latter are a set of standard high-level data types to aid interoperability
of EPICS V4 applications and are specified in the
[NormativeTypes Specification](http://epics-pvdata.sourceforge.net/alpha/normativeTypes/normativeTypes.html).
This normativeTypesCPP module is a part of the EPICS software toolkit that provides C++ helper classes which implement the EPICS Normative Types.
## Links
Status
------
- General information about EPICS can be found at the
[EPICS Controls website](https://epics-controls.org).
- API documentation for this module can be found in its
documentation directory, in particular the file
normativeTypesCPP.html
The current release (5.0) implements fully the
[16 Mar 2015 version](http://epics-pvdata.sourceforge.net/alpha/normativeTypes/normativeTypes_20150316.html)
of the Normative Types Specification.
The module status is alpha and the API and behaviour may change in future
versions.
The previous release (4.0) supported only 6 types.
There is no documentation yet for the new types added in 5.0.
Further Info
------------
Consult the documents in the documentation directory, in particular
* normativeTypesCPP.html
* RELEASE_NOTES.md
Also see the [EPICS Version 4 website](http://epics-pvdata.sourceforge.net)
Prerequisites
-------------
normativeTypesCPP requires recent versions of the following software:
1. EPICS Base (v3.14.12.3 or later)
2. EPICS4 pvCommonCPP (4.1.0 or later)
2. pvDataCPP (5.0.0 or later)
(pvCommonCPP may not be needed depending on host/compiler.)
Building
--------
Building uses the make utility and the EPICS base build system.
The build system needs the location of the prerequisites, e.g. by placing the
lines of the form
PVDATA = /home/install/epicsV4/pvDataCPP
PVCOMMON = /home/install/epicsV4/pvCommonCPP
EPICS_BASE = /home/install/epics/base
pointing to the locations in a file called RELEASE.local
in the configure directory or the parent directory of normativeTypesCPP.
With this in place, to build type make
make
To perform a clean build type
make clean uninstall
To run the unit tests type
make runtests
For more information on the EPICS build system consult the
[Application Development guide](http://www.aps.anl.gov/epics/base/R3-14/12-docs/AppDevGuide.pdf).
## Building
This module is included as a submodule of a full EPICS 7 release and will be compiled during builds of that software.

View File

@@ -0,0 +1,12 @@
# Version number for the Normative Types API and shared library
EPICS_NTYPES_MAJOR_VERSION = 6
EPICS_NTYPES_MINOR_VERSION = 0
EPICS_NTYPES_MAINTENANCE_VERSION = 3
# Development flag, set to zero for release versions
EPICS_NTYPES_DEVELOPMENT_FLAG = 1
# Immediately after a release the MAINTENANCE_VERSION
# will be incremented and the DEVELOPMENT_FLAG set to 1

View File

@@ -32,3 +32,5 @@ endif
-include $(TOP)/../CONFIG_SITE.local
-include $(TOP)/configure/CONFIG_SITE.local
# MSVC - skip defining min()/max() macros
USR_CPPFLAGS_WIN32 += -DNOMINMAX

View File

@@ -10,6 +10,8 @@ include $(TOP)/configure/CONFIG
# but continue the build even if conflicts are found.
CHECK_RELEASE = YES
CFG += CONFIG_NTYPES_VERSION
TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))

View File

@@ -1,32 +1,40 @@
#RELEASE Location of external products
# RELEASE - Location of external support modules
#
# IF YOU MAKE ANY CHANGES to this file you MUST at least run
# "gnumake" in this directory afterwards; you usually need
# to run "gnumake rebuild" in the application's top level
# directory each time this file is changed.
# IF YOU CHANGE ANY PATHS in this file or make API changes to
# any modules it refers to, you should do a "make rebuild" in
# this application's top level directory.
#
# NOTE: The build does not check dependencies against files
# that are outside this application, thus you should run
# "gnumake distclean install" in the top directory each time
# EPICS_BASE, SNCSEQ, or any other external module defined
# in the RELEASE file is rebuilt.
# The EPICS build process does not check dependencies against
# any files from outside the application, so it is safest to
# rebuild it completely if any modules it depends on change.
#
# Host/target specific settings can be specified in files named
# Host- or target-specific settings can be given in files named
# RELEASE.$(EPICS_HOST_ARCH).Common
# RELEASE.Common.$(T_A)
# RELEASE.$(EPICS_HOST_ARCH).$(T_A)
#
# This file is parsed by both GNUmake and an EPICS Perl script,
# so it may ONLY contain definititions of paths to other support
# modules, variable definitions that are used in module paths,
# and include statements that pull in other RELEASE files.
# Variables may be used before their values have been set.
# Build variables that are NOT used in paths should be set in
# the CONFIG_SITE file.
TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
# Variables and paths to dependent modules:
#MODULES = /path/to/modules
#MYMODULE = $(MODULES)/my-module
#If using the sequencer, point SNCSEQ at its top directory:
#SNCSEQ=$(EPICS_BASE)/../modules/soft/seq
# If building the EPICS modules individually, set these:
#EPICS_PVDATA = $(MODULES)/pvData-7.0.0
#EPICS_LIBCOM = $(MODULES)/libcom-3.17.0
#EPICS_BASE = $(MODULES)/core-7.0.1
# EPICS_BASE usually appears last so other apps can override stuff:
#EPICS_BASE=/opt/epics/base
#Capfast users may need the following definitions
#CAPFAST_TEMPLATES=
#SCH2EDIF_PATH=
# Set RULES here if you want to use build rules from elsewhere:
#RULES = $(MODULES)/build-rules
# These allow developers to override the RELEASE variable settings
# without having to modify the configure/RELEASE file itself.
-include $(TOP)/../RELEASE.local
-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
-include $(TOP)/configure/RELEASE.local

View File

@@ -1,113 +0,0 @@
<h1>Release 5.1.0</h1>
<p>The main changes since release 5.0 are:</p>
<ul>
<li>Linux shared library version added</li>
<li>Headers and source locations have changed</li>
<li>Missing is_a implementations added</li>
<li>NTAttribute::addTags() is now non-virtual</li>
<li>New license file replaces LICENSE and COPYRIGHT</li>
</ul>
<h2>Shared library version added</h2>
<p>Linux shared library version numbers have been added by setting SHRLIB_VERSION
(to 5.1 in this case). So shared object will be libnt.so.5.1 instead of
libpvData.so.</p>
<h2>Headers and source locations have changed</h2>
<p>Source has moved out of nt directory directly into src.</p>
<p>Headers have been moved into a pv directory. This facilitates using some IDEs
such as Qt Creator.</p>
<p>src/nt/ntscalar.cpp -> src/ntscalar.cpp
src/nt/ntscalar.h -> src/pv/ntscalar.h</p>
<h2>Missing is_a implementations added</h2>
<p>is_a(PVStructurePtr const &amp;) implementation has been added for each type.</p>
<h1>Release 5.0</h1>
<p>This release adds support through wrapper classes and builders for the
remaining Normative Types:</p>
<ul>
<li>NTEnum</li>
<li>NTMatrix</li>
<li>NTURI</li>
<li>NTAttribute</li>
<li>NTContinuum</li>
<li>NTHistogram</li>
<li>NTAggregate</li>
<li>NTUnion</li>
<li>NTScalarMultiChannel</li>
</ul>
<p>Release 5.0 therefore implements fully the
<a href="http://epics-pvdata.sourceforge.net/alpha/normativeTypes/normativeTypes_20150316.html">16 Mar 2015 version</a>
of the normativeTypes specification.</p>
<p>Each wrapper class has an extended API:</p>
<ul>
<li>is_a now has a convenience overload taking a PVStructure.</li>
<li>isCompatible, reporting introspection type compatibility, now has an overload
taking a Structure. The PVStructure version is retained as a convenience
method and for backwards compatibility.</li>
<li>An isValid function now reports validity of a compatible PVStructure's data
with respect to the specification.</li>
</ul>
<p>Other changes are:</p>
<ul>
<li>Support for NTAttributes extended as required by NTNDArray
(NTNDArrayAttributes).</li>
<li>A new class for parsing NT IDs (NTID).</li>
<li>Resolution of the confusion between column names and labels in NTTable and
improved API. Function for adding columns is now addColumn rather than add.
New getColumnNames function provided.</li>
<li>isConnected is treated as an optional rather than a required field in
NTMultiChannelArray. isConnected() and addIsConnected() functions added to
wrapper and builder respectively.</li>
<li>Unit tests for all new classes.</li>
</ul>
<h1>Release 4.0</h1>
<p>This is the first release of normativeTypesCPP that is part of an official
EPICS V4 release.
It is a major rewrite of the previous versions of normativeTypesCPP.</p>
<p>This release provides support through wrapper classes and builders for the
following Normative Types:</p>
<ul>
<li>NTScalar</li>
<li>NTScalarArray</li>
<li>NTNameValue</li>
<li>NTTable</li>
<li>NTMultiChannel</li>
<li>NTNDArray</li>
</ul>
<p>Each type has a wrapper class of the same name which has functions for checking
compatibility of existing PVStructures (isCompatible) and the reported types of
Structures (is_a), wraps existing PVStructures (wrap, wrapUnsafe) and provides
a convenient interface to all required and optional fields.</p>
<p>Each type has a builder which can create a Structure, a PVStructure or a
wrapper around a new PVStructure. In each case optional or extra fields can be
added and options such as choice of scalar type can be made.</p>
<p>Additional features are:</p>
<ul>
<li>Utility classes NTField and NTPVField for standard structure fields and
NTUtils for type IDs.</li>
<li>Unit tests for the implemented classes.</li>
</ul>

View File

@@ -1,82 +1,135 @@
Release 5.1.0
=============
# normativeTypes Module
This document summarizes the changes to the module between releases.
## Release 6.0.2 (EPICS 7.0.10, December 2025)
- Fix potential NULL pointer dereference in `NTNDArray::getValueSize()`
## Release 6.0.1 (EPICS 7.0.3.1, October 2019)
- Doxygen updates and read-the-docs integration.
## Release 6.0.0 (EPICS 7.0.3, July 2019)
- Reimplement `isCompatible()` methods to use a new internal validation API in
order to make the implementation uniform, less repetitive and less strict.
The new implementation is less strict in the sense that it considers types that
can be converted into one another compatible with each other.
For example, any `Scalar` is considered compatible with any other `Scalar`,
regardless of the underlying type.
Normative Types users are advised to use `getAs()` and `putFrom()` when
getting/putting data from/into `PVScalar`s and `PVScalarArray`s.
Also, `isCompatible()` methods now disregard field order and extra fields that
are not part of the specification.
This change is not expected to break any current server or client, but it will
break existing clients that rely on the previous `isCompatible()` strictness
once servers start to take advantage of `isCompatible()` now being less strict.
## Release 5.2.2
- Fix `NTTable::getColumnNames()`.
## Release 5.2.1 (EPICS 7.0.2, Dec 2018)
- No functional changes.
- Removal of declaration for unimplemented `PVNTField::createAlarmLimit()` and
elimination of unused variables.
## Release 5.2.0 (EPICS 7.0.1, Dec 2017)
This release contains bug fixes and minor source updates needed to
build against the latest version of pvData.
## Release 5.1.2 (EPICS V4.6, Aug 2016)
The main changes since release 5.1.1 are:
- NTUnionBuilder: Add missing `value()` function
- Updated document: Now document all Normative Types
## Release 5.1.1
The main changes since release 5.0 are:
* Linux shared library version added
* Headers and source locations have changed
* Missing is_a implementations added
* NTAttribute::addTags() is now non-virtual
* New license file replaces LICENSE and COPYRIGHT
- Linux shared library version added
- Headers and source locations have changed
- Missing `is_a()` implementations added
- `NTAttribute::addTags()` is now non-virtual
- New license file replaces LICENSE and COPYRIGHT
Shared library version added
----------------------------
### Shared library version added
Linux shared library version numbers have been added by setting SHRLIB_VERSION
(to 5.1 in this case). So shared object will be libnt.so.5.1 instead of
libpvData.so.
Linux shared library version numbers have been added by setting `SHRLIB_VERSION`
(to 5.1 in this case).
The shared object will be `libnt.so.5.1` instead of `libnt.so`.
Headers and source locations have changed
-----------------------------------------
### Headers and source locations have changed
Source has moved out of nt directory directly into src.
Headers have been moved into a pv directory. This facilitates using some IDEs
such as Qt Creator.
Headers have been moved into a pv directory.
This facilitates using some IDEs such as Qt Creator.
src/nt/ntscalar.cpp -> src/ntscalar.cpp
src/nt/ntscalar.h -> src/pv/ntscalar.h
- `src/nt/ntscalar.cpp -> src/ntscalar.cpp`
- `src/nt/ntscalar.h -> src/pv/ntscalar.h`
Missing is_a implementations added
----------------------------------
### Missing `is_a()` implementations added
is_a(PVStructurePtr const &) implementation has been added for each type.
`is_a(PVStructurePtr const &)` implementation has been added for each type.
Release 5.0
===========
## Release 5.0 (EPICS V4.5, Oct 2015)
This release adds support through wrapper classes and builders for the
remaining Normative Types:
* NTEnum
* NTMatrix
* NTURI
* NTAttribute
* NTContinuum
* NTHistogram
* NTAggregate
* NTUnion
* NTScalarMultiChannel
- NTEnum
- NTMatrix
- NTURI
- NTAttribute
- NTContinuum
- NTHistogram
- NTAggregate
- NTUnion
- NTScalarMultiChannel
Release 5.0 therefore implements fully the
[16 Mar 2015 version](http://epics-pvdata.sourceforge.net/alpha/normativeTypes/normativeTypes_20150316.html)
of the normativeTypes specification.
Release 5.0 therefore fully implements the 16 Mar 2015 version of the
normativeTypes specification.
Each wrapper class has an extended API:
* is_a now has a convenience overload taking a PVStructure.
* isCompatible, reporting introspection type compatibility, now has an overload
taking a Structure. The PVStructure version is retained as a convenience
method and for backwards compatibility.
* An isValid function now reports validity of a compatible PVStructure's data
with respect to the specification.
- `is_a()` now has a convenience overload taking a PVStructure.
- `isCompatible()`, reporting introspection type compatibility, now has an
overload taking a Structure.
The PVStructure version is retained as a convenience method and for backwards
compatibility.
- An `isValid()` function now reports validity of a compatible PVStructure's
data with respect to the specification.
Other changes are:
* Support for NTAttributes extended as required by NTNDArray
- Support for NTAttributes extended as required by NTNDArray
(NTNDArrayAttributes).
* A new class for parsing NT IDs (NTID).
* Resolution of the confusion between column names and labels in NTTable and
improved API. Function for adding columns is now addColumn rather than add.
New getColumnNames function provided.
* isConnected is treated as an optional rather than a required field in
NTMultiChannelArray. isConnected() and addIsConnected() functions added to
wrapper and builder respectively.
* Unit tests for all new classes.
- A new class for parsing NT IDs (NTID).
- Resolution of the confusion between column names and labels in NTTable and
improved API.
Function for adding columns is now `addColumn()` rather than `add()`.
A new `getColumnNames()` function provided.
- `isConnected()` is treated as an optional rather than a required field in
NTMultiChannelArray.
`isConnected()` and `addIsConnected()` functions added to wrapper and builder
respectively.
Release 4.0
===========
- Unit tests for all new classes.
## Release 4.0 (EPICS V4.4, Dec 2014)
This is the first release of normativeTypesCPP that is part of an official
EPICS V4 release.
@@ -85,26 +138,27 @@ It is a major rewrite of the previous versions of normativeTypesCPP.
This release provides support through wrapper classes and builders for the
following Normative Types:
* NTScalar
* NTScalarArray
* NTNameValue
* NTTable
* NTMultiChannel
* NTNDArray
- NTScalar
- NTScalarArray
- NTNameValue
- NTTable
- NTMultiChannel
- NTNDArray
Each type has a wrapper class of the same name which has functions for checking
compatibility of existing PVStructures (isCompatible) and the reported types of
Structures (is_a), wraps existing PVStructures (wrap, wrapUnsafe) and provides
a convenient interface to all required and optional fields.
compatibility of existing PVStructures (`isCompatible()`) and the reported types
of Structures (`is_a()`),
wraps existing PVStructures (`wrap()`, `wrapUnsafe()`) and provides a convenient
interface to all required and optional fields.
Each type has a builder which can create a Structure, a PVStructure or a
wrapper around a new PVStructure. In each case optional or extra fields can be
added and options such as choice of scalar type can be made.
wrapper around a new PVStructure.
In each case optional or extra fields can be added and options such as choice of
scalar type can be made.
Additional features are:
* Utility classes NTField and NTPVField for standard structure fields and
- Utility classes NTField and NTPVField for standard structure fields and
NTUtils for type IDs.
* Unit tests for the implemented classes.
- Unit tests for the implemented classes.

View File

@@ -0,0 +1,7 @@
.wy-side-nav-search {
background-color: #18334B;
}
.wy-side-nav-search input[type="text"] {
border-color: #18334b;
}

77
documentation/conf.py Normal file
View File

@@ -0,0 +1,77 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# http://www.sphinx-doc.org/en/master/config
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- Project information -----------------------------------------------------
project = 'normativeTypes (C++)'
copyright = '2019, EPICS Controls.'
author = 'EPICS'
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.intersphinx',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# Intersphinx links to subprojects
intersphinx_mapping = {
}
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_css_files = [
'css/custom.css',
]
master_doc = 'index'
html_theme_options = {
'logo_only': True,
}
html_logo = "images/EPICS_white_logo_v02.png"
html_extra_path = ['../html']
# -- Run Doxygen ------------------------------------------------------------
import subprocess
subprocess.call('cd ..; mkdir -p html/doxygen; doxygen', shell=True)

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

17
documentation/index.rst Normal file
View File

@@ -0,0 +1,17 @@
NormativeTypes (C++) Library
============================
.. toctree::
:hidden:
EPICS Website <https://epics-controls.org>
EPICS Documentation Home <https://docs.epics-controls.org>
.. toctree::
:maxdepth: 1
:caption: normativeTypesCPP
Reference Manual <ntCPP>
API Documentation <https://docs.epics-controls.org/projects/normativetypes-cpp/en/latest/doxygen>
Source Code Repository on GitHub <https://github.com/epics-base/normativeTypesCPP>

File diff suppressed because it is too large Load Diff

3270
documentation/ntCPP.rst Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -21,28 +21,20 @@ installE4 () {
local module=$1
local branch=$2
# If microbench version does not exist, try without
if [ "${MB}" = "WITH_MICROBENCH" ]; then
if ! wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=WITH_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz; then
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
fi
else
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
fi
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE}/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
tar -xzf ${module}.CB-dist.tar.gz
}
###########################################
# Defaults for EPICS Base and MB
# Defaults for EPICS Base
DEFAULT_BASE=3.15.4
BASE=${BASE:-${DEFAULT_BASE}}
MB=${MB:-"NO_MICROBENCH"}
###########################################
# Dependent module branches
PVDATA_BRANCH="release-6.0"
PVDATA_BRANCH="master"
###########################################
# Fetch and unpack dependencies
@@ -80,6 +72,6 @@ make distclean all
make runtests
###########################################
# Create distribution
# Create cache
tar --exclude=test* -czf normativeTypes.CB-dist.tar.gz lib include

View File

@@ -21,14 +21,7 @@ installE4 () {
local module=$1
local branch=$2
# If microbench version does not exist, try without
if [ "${MB}" = "WITH_MICROBENCH" ]; then
if wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=WITH_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz; then
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
fi
else
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
fi
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE}/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
tar -xzf ${module}.CB-dist.tar.gz
}
@@ -38,7 +31,6 @@ installE4 () {
BASE=3.15.4
PUBLISH=${PUBLISH:-NO}
BRANCH=${BRANCH:-master}
MB=NO_MICROBENCH
###########################################
# Fetch and unpack dependencies
@@ -65,9 +57,10 @@ doxygen
###########################################
# Publish
if [ "${PUBLISH}" != "NO" ]; then
if [ "${PUBLISH}" != "DONT" ]; then
# Upload explicit dummy to ensure target directory exists
echo "Created by CloudBees Jenkins upload job. Should be deleted as part of the job." > DUMMY
rsync -q -e ssh DUMMY epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/normativeTypesCPP/${PUBLISH}/
rsync -aqP --delete -e ssh documentation epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/normativeTypesCPP/${PUBLISH}/
fi

View File

@@ -47,7 +47,7 @@ LIBRARY = nt
nt_LIBS += pvData Com
# shared library ABI version.
SHRLIB_VERSION ?= 5.1
SHRLIB_VERSION ?= $(EPICS_NTYPES_MAJOR_VERSION).$(EPICS_NTYPES_MINOR_VERSION).$(EPICS_NTYPES_MAINTENANCE_VERSION)
include $(TOP)/configure/RULES

View File

@@ -4,6 +4,8 @@
* found in the file LICENSE that is included with the distribution
*/
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntaggregate.h>
#include <pv/ntutils.h>
@@ -194,83 +196,26 @@ bool NTAggregate::is_a(PVStructurePtr const & pvStructure)
bool NTAggregate::isCompatible(StructureConstPtr const &structure)
{
if (structure.get() == 0) return false;
ScalarConstPtr valueField = structure->getField<Scalar>("value");
if (valueField.get() == 0 || valueField->getScalarType() != pvDouble)
if (!structure)
return false;
ScalarConstPtr nField = structure->getField<Scalar>("N");
if (nField.get() == 0 || nField->getScalarType() != pvLong)
return false;
Result result(structure);
FieldConstPtr field = structure->getField("dispersion");
if (field.get())
{
ScalarConstPtr dispersionField = structure->getField<Scalar>("dispersion");
if (!dispersionField.get() || dispersionField->getScalarType() != pvDouble)
return false;
}
field = structure->getField("first");
if (field.get())
{
ScalarConstPtr firstField = structure->getField<Scalar>("first");
if (!firstField.get() || firstField->getScalarType() != pvDouble)
return false;
}
field = structure->getField("firstTimeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
field = structure->getField("last");
if (field.get())
{
ScalarConstPtr lastField = structure->getField<Scalar>("last");
if (!lastField.get() || lastField->getScalarType() != pvDouble)
return false;
}
field = structure->getField("lastTimeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
field = structure->getField("max");
if (field.get())
{
ScalarConstPtr maxField = structure->getField<Scalar>("max");
if (!maxField.get() || maxField->getScalarType() != pvDouble)
return false;
}
field = structure->getField("min");
if (field.get())
{
ScalarConstPtr minField = structure->getField<Scalar>("min");
if (!minField.get() || minField->getScalarType() != pvDouble)
return false;
}
field = structure->getField("descriptor");
if (field.get())
{
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
return false;
}
NTFieldPtr ntField = NTField::get();
field = structure->getField("alarm");
if (field.get() && !ntField->isAlarm(field))
return false;
field = structure->getField("timeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
return true;
return result
.is<Structure>()
.has<Scalar>("value")
.has<Scalar>("N")
.maybeHas<Scalar>("dispersion")
.maybeHas<Scalar>("first")
.maybeHas<&NTField::isTimeStamp, Structure>("firstTimeStamp")
.maybeHas<Scalar>("last")
.maybeHas<&NTField::isTimeStamp, Structure>("lastTimeStamp")
.maybeHas<Scalar>("max")
.maybeHas<Scalar>("min")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.valid();
}
bool NTAggregate::isCompatible(PVStructurePtr const & pvStructure)

View File

@@ -4,6 +4,8 @@
* found in the file LICENSE that is included with the distribution
*/
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntattribute.h>
#include <pv/ntutils.h>
@@ -130,46 +132,22 @@ bool NTAttribute::is_a(PVStructurePtr const & pvStructure)
bool NTAttribute::isCompatible(StructureConstPtr const & structure)
{
if (structure.get() == 0) return false;
ScalarConstPtr nameField = structure->getField<Scalar>("name");
if (nameField.get() == 0 || nameField->getScalarType() != pvString)
if (!structure)
return false;
UnionConstPtr valueField = structure->getField<Union>("value");
if (valueField.get() == 0 || !valueField->isVariant())
return false;
Result result(structure);
FieldConstPtr field = structure->getField("tags");
if (field.get())
{
ScalarArrayConstPtr tagsField = structure->getField<ScalarArray>("tags");
if (tagsField.get() == 0 || tagsField->getElementType() != pvString)
return false;
}
field = structure->getField("descriptor");
if (field.get())
{
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
return false;
}
NTFieldPtr ntField = NTField::get();
field = structure->getField("alarm");
if (field.get() && !ntField->isAlarm(field))
return false;
field = structure->getField("timeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
return true;
return result
.is<Structure>()
.has<Scalar>("name")
.has<Union>("value")
.maybeHas<ScalarArray>("tags")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.valid();
}
bool NTAttribute::isCompatible(PVStructurePtr const & pvStructure)
{
if(!pvStructure) return false;

View File

@@ -4,6 +4,8 @@
* found in the file LICENSE that is included with the distribution
*/
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntcontinuum.h>
#include <pv/ntutils.h>
@@ -122,42 +124,22 @@ bool NTContinuum::is_a(PVStructurePtr const & pvStructure)
bool NTContinuum::isCompatible(StructureConstPtr const & structure)
{
if (structure.get() == 0) return false;
ScalarArrayConstPtr baseField = structure->getField<ScalarArray>("base");
if (baseField.get() == 0 || baseField->getElementType() != pvDouble)
if (!structure)
return false;
ScalarArrayConstPtr valueField = structure->getField<ScalarArray>("value");
if (valueField.get() == 0 || valueField->getElementType() != pvDouble)
return false;
Result result(structure);
ScalarArrayConstPtr unitsField = structure->getField<ScalarArray>("units");
if (unitsField.get() == 0 || unitsField->getElementType() != pvString)
return false;
FieldConstPtr field = structure->getField("descriptor");
if (field.get())
{
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
return false;
}
NTFieldPtr ntField = NTField::get();
field = structure->getField("alarm");
if (field.get() && !ntField->isAlarm(field))
return false;
field = structure->getField("timeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
return true;
return result
.is<Structure>()
.has<ScalarArray>("base")
.has<ScalarArray>("value")
.has<ScalarArray>("units")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.valid();
}
bool NTContinuum::isCompatible(PVStructurePtr const & pvStructure)
{
if(!pvStructure) return false;

View File

@@ -4,6 +4,8 @@
* found in the file LICENSE that is included with the distribution
*/
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntenum.h>
#include <pv/ntutils.h>
@@ -121,34 +123,20 @@ bool NTEnum::is_a(PVStructurePtr const & pvStructure)
bool NTEnum::isCompatible(StructureConstPtr const &structure)
{
if (structure.get() == 0) return false;
NTFieldPtr ntField = NTField::get();
FieldConstPtr valueField = structure->getField("value");
if (!valueField.get() || !ntField->isEnumerated(valueField))
if (!structure)
return false;
FieldConstPtr field = structure->getField("descriptor");
if (field.get())
{
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
return false;
}
Result result(structure);
field = structure->getField("alarm");
if (field.get() && !ntField->isAlarm(field))
return false;
field = structure->getField("timeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
return true;
return result
.is<Structure>()
.has<&NTField::isEnumerated, Structure>("value")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.valid();
}
bool NTEnum::isCompatible(PVStructurePtr const & pvStructure)
{
if(!pvStructure) return false;

View File

@@ -5,6 +5,7 @@
*/
#include <pv/lock.h>
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntfield.h>
@@ -31,198 +32,97 @@ NTField::NTField()
{
}
Result& NTField::isEnumerated(Result& result)
{
return result
.has<Scalar>("index")
.has<ScalarArray>("choices");
}
bool NTField::isEnumerated(FieldConstPtr const & field)
{
if(field->getType()!=structure) return false;
StructureConstPtr structurePtr = static_pointer_cast<const Structure>(field);
FieldConstPtrArray fields = structurePtr->getFields();
StringArray names = structurePtr->getFieldNames();
size_t n = structurePtr->getNumberFields();
if(n!=2) return false;
FieldConstPtr f = fields[0];
if(names[0].compare("index")!=0) return false;
if(f->getType()!=scalar) return false;
ScalarConstPtr s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvInt) return false;
f = fields[1];
if(names[1].compare("choices")!=0) return false;
if(f->getType()!=scalarArray) return false;
ScalarConstPtr sa = static_pointer_cast<const Scalar>(f);
if(sa->getScalarType()!=pvString) return false;
return true;
Result result(field);
return isEnumerated(result.is<Structure>()).valid();
}
Result& NTField::isTimeStamp(Result& result)
{
return result
.has<Scalar>("secondsPastEpoch")
.has<Scalar>("nanoseconds")
.has<Scalar>("userTag");
}
bool NTField::isTimeStamp(FieldConstPtr const & field)
{
if(field->getType()!=structure) return false;
StructureConstPtr structurePtr = static_pointer_cast<const Structure>(field);
FieldConstPtrArray fields = structurePtr->getFields();
StringArray names = structurePtr->getFieldNames();
size_t n = structurePtr->getNumberFields();
if(n!=3) return false;
FieldConstPtr f = fields[0];
if(names[0].compare("secondsPastEpoch")!=0) return false;
if(f->getType()!=scalar) return false;
ScalarConstPtr s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvLong) return false;
f = fields[1];
if(names[1].compare("nanoseconds")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvInt) return false;
f = fields[2];
if(names[2].compare("userTag")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvInt) return false;
return true;
Result result(field);
return isTimeStamp(result.is<Structure>()).valid();
}
Result& NTField::isAlarm(Result& result)
{
return result
.has<Scalar>("severity")
.has<Scalar>("status")
.has<Scalar>("message");
}
bool NTField::isAlarm(FieldConstPtr const & field)
{
if(field->getType()!=structure) return false;
StructureConstPtr structurePtr = static_pointer_cast<const Structure>(field);
FieldConstPtrArray fields = structurePtr->getFields();
StringArray names = structurePtr->getFieldNames();
size_t n = structurePtr->getNumberFields();
if(n!=3) return false;
FieldConstPtr f = fields[0];
if(names[0].compare("severity")!=0) return false;
if(f->getType()!=scalar) return false;
ScalarConstPtr s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvInt) return false;
f = fields[1];
if(names[1].compare("status")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvInt) return false;
f = fields[2];
if(names[2].compare("message")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvString) return false;
return true;
Result result(field);
return isAlarm(result.is<Structure>()).valid();
}
Result& NTField::isDisplay(Result& result)
{
return result
.has<Scalar>("limitLow")
.has<Scalar>("limitHigh")
.has<Scalar>("description")
.has<Scalar>("format")
.has<Scalar>("units");
}
bool NTField::isDisplay(FieldConstPtr const & field)
{
if(field->getType()!=structure) return false;
StructureConstPtr structurePtr = static_pointer_cast<const Structure>(field);
FieldConstPtrArray fields = structurePtr->getFields();
StringArray names = structurePtr->getFieldNames();
size_t n = structurePtr->getNumberFields();
if(n!=5) return false;
FieldConstPtr f = fields[0];
if(names[0].compare("limitLow")!=0) return false;
if(f->getType()!=scalar) return false;
ScalarConstPtr s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvDouble) return false;
f = fields[1];
if(names[1].compare("limitHigh")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvDouble) return false;
f = fields[2];
if(names[2].compare("description")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvString) return false;
f = fields[3];
if(names[3].compare("format")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvString) return false;
f = fields[4];
if(names[4].compare("units")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvString) return false;
return true;
Result result(field);
return isDisplay(result.is<Structure>()).valid();
}
Result& NTField::isAlarmLimit(Result& result)
{
return result
.has<Scalar>("active")
.has<Scalar>("lowAlarmLimit")
.has<Scalar>("lowWarningLimit")
.has<Scalar>("highWarningLimit")
.has<Scalar>("highAlarmLimit")
.has<Scalar>("lowAlarmSeverity")
.has<Scalar>("lowWarningSeverity")
.has<Scalar>("highWarningSeverity")
.has<Scalar>("highAlarmSeverity")
.has<Scalar>("hysteresis");
}
bool NTField::isAlarmLimit(FieldConstPtr const & field)
{
if(field->getType()!=structure) return false;
StructureConstPtr structurePtr = static_pointer_cast<const Structure>(field);
FieldConstPtrArray fields = structurePtr->getFields();
StringArray names = structurePtr->getFieldNames();
size_t n = structurePtr->getNumberFields();
if(n!=10) return false;
FieldConstPtr f = fields[0];
if(names[0].compare("active")!=0) return false;
if(f->getType()!=scalar) return false;
ScalarConstPtr s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvBoolean) return false;
f = fields[1];
if(names[1].compare("lowAlarmLimit")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvDouble) return false;
f = fields[2];
if(names[2].compare("lowWarningLimit")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvDouble) return false;
f = fields[3];
if(names[3].compare("highWarningLimit")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvDouble) return false;
f = fields[4];
if(names[4].compare("highAlarmLimit")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvDouble) return false;
f = fields[5];
if(names[5].compare("lowAlarmSeverity")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvInt) return false;
f = fields[6];
if(names[6].compare("lowWarningSeverity")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvInt) return false;
f = fields[7];
if(names[7].compare("highWarningSeverity")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvInt) return false;
f = fields[8];
if(names[8].compare("highAlarmSeverity")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvInt) return false;
f = fields[9];
if(names[9].compare("hysteresis")!=0) return false;
if(f->getType()!=scalar) return false;
return true;
Result result(field);
return isAlarmLimit(result.is<Structure>()).valid();
}
Result& NTField::isControl(Result& result)
{
return result
.has<Scalar>("limitLow")
.has<Scalar>("limitHigh")
.has<Scalar>("minStep");
}
bool NTField::isControl(FieldConstPtr const & field)
{
if(field->getType()!=structure) return false;
StructureConstPtr structurePtr = static_pointer_cast<const Structure>(field);
FieldConstPtrArray fields = structurePtr->getFields();
StringArray names = structurePtr->getFieldNames();
size_t n = structurePtr->getNumberFields();
if(n!=3) return false;
FieldConstPtr f = fields[0];
if(names[0].compare("limitLow")!=0) return false;
if(f->getType()!=scalar) return false;
ScalarConstPtr s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvDouble) return false;
f = fields[1];
if(names[1].compare("limitHigh")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvDouble) return false;
f = fields[2];
if(names[2].compare("minStep")!=0) return false;
if(f->getType()!=scalar) return false;
s = static_pointer_cast<const Scalar>(f);
if(s->getScalarType()!=pvDouble) return false;
return true;
Result result(field);
return isControl(result.is<Structure>()).valid();
}
StructureConstPtr NTField::createEnumerated()
@@ -339,4 +239,3 @@ PVStructureArrayPtr PVNTField::createAlarmArray()
}
}}

View File

@@ -4,6 +4,8 @@
* found in the file LICENSE that is included with the distribution
*/
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/nthistogram.h>
#include <pv/ntutils.h>
@@ -135,37 +137,19 @@ bool NTHistogram::is_a(PVStructurePtr const & pvStructure)
bool NTHistogram::isCompatible(StructureConstPtr const &structure)
{
if(!structure.get()) return false;
ScalarArrayConstPtr rangesField = structure->getField<ScalarArray>("ranges");
if(!rangesField.get() || rangesField->getElementType() != pvDouble) return false;
ScalarArrayConstPtr valueField = structure->getField<ScalarArray>("value");
if(!valueField.get()) return false;
ScalarType scalarType = valueField->getElementType();
if (scalarType != pvShort &&
scalarType != pvInt &&
scalarType != pvLong)
if (!structure)
return false;
FieldConstPtr field = structure->getField("descriptor");
if(field)
{
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
return false;
}
Result result(structure);
field = structure->getField("alarm");
if (field.get() && !ntField->isAlarm(field))
return false;
field = structure->getField("timeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
return true;
return result
.is<Structure>()
.has<ScalarArray>("ranges")
.has<ScalarArray>("value")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.valid();
}
bool NTHistogram::isCompatible(PVStructurePtr const & pvStructure)

View File

@@ -7,11 +7,11 @@
#include <pv/ntid.h>
#include <pv/typeCast.h>
namespace epics {
namespace epics {
namespace nt {
const static std::string BAD_NAME = "?";
const static std::string BAD_NAME = "?";
NTID::NTID(const std::string & id)
: fullName(id),
@@ -81,7 +81,7 @@ namespace nt {
else
{
name = fullName;
}
}
}
return name;
}
@@ -105,7 +105,7 @@ namespace nt {
{
endMajorIndex = fullName.find('.', versionSepIndex+1);
majorVersionStr = (endMajorIndex != std::string::npos)
? fullName.substr(versionSepIndex+1, endMajorIndex-(versionSepIndex+1)) :
? fullName.substr(versionSepIndex+1, endMajorIndex-(versionSepIndex+1)) :
fullName.substr(versionSepIndex+1);
}
else
@@ -150,7 +150,7 @@ namespace nt {
{
endMinorIndex = fullName.find('.', endMajorIndex+1);
minorVersionStr = (endMinorIndex != std::string::npos)
? fullName.substr(endMajorIndex+1, endMinorIndex-(endMajorIndex+1)) :
? fullName.substr(endMajorIndex+1, endMinorIndex-(endMajorIndex+1)) :
fullName.substr(endMajorIndex+1);
}
else
@@ -186,5 +186,3 @@ namespace nt {
}}

View File

@@ -4,6 +4,8 @@
* found in the file LICENSE that is included with the distribution
*/
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntmatrix.h>
#include <pv/ntutils.h>
@@ -139,43 +141,20 @@ bool NTMatrix::is_a(PVStructurePtr const & pvStructure)
bool NTMatrix::isCompatible(StructureConstPtr const & structure)
{
if (structure.get() == 0) return false;
ScalarArrayConstPtr valueField = structure->getField<ScalarArray>("value");
if (valueField.get() == 0 || valueField->getElementType() != pvDouble)
if (!structure)
return false;
FieldConstPtr field = structure->getField("dim");
if (field.get())
{
ScalarArrayConstPtr dimField = structure->getField<ScalarArray>("dim");
if (dimField.get() == 0 || dimField->getElementType() != pvInt)
return false;
}
Result result(structure);
field = structure->getField("descriptor");
if (field.get())
{
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
return false;
}
NTFieldPtr ntField = NTField::get();
field = structure->getField("alarm");
if (field.get() && !ntField->isAlarm(field))
return false;
field = structure->getField("timeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
field = structure->getField("display");
if (field.get() && !ntField->isDisplay(field))
return false;
return true;
return result
.is<Structure>()
.has<ScalarArray>("value")
.maybeHas<ScalarArray>("dim")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.maybeHas<&NTField::isDisplay, Structure>("display")
.valid();
}
bool NTMatrix::isCompatible(PVStructurePtr const & pvStructure)

View File

@@ -6,6 +6,8 @@
#include <algorithm>
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntmultiChannel.h>
#include <pv/ntutils.h>
@@ -13,7 +15,7 @@
using namespace std;
using namespace epics::pvData;
namespace epics { namespace nt {
namespace epics { namespace nt {
static FieldCreatePtr fieldCreate = getFieldCreate();
@@ -232,86 +234,27 @@ bool NTMultiChannel::is_a(PVStructurePtr const & pvStructure)
bool NTMultiChannel::isCompatible(StructureConstPtr const & structure)
{
if (!structure.get()) return false;
UnionArrayConstPtr valueField = structure->getField<UnionArray>("value");
if (!valueField.get()) return false;
ScalarArrayConstPtr channelNameField = structure->getField<ScalarArray>(
"channelName");
if (!channelNameField.get()) return false;
if (channelNameField->getElementType() != pvString) return false;
FieldConstPtr field = structure->getField("severity");
if (field.get())
{
ScalarArrayConstPtr severityField = structure->getField<ScalarArray>("severity");
if (!severityField.get() || severityField->getElementType() != pvInt)
return false;
}
field = structure->getField("status");
if (field.get())
{
ScalarArrayConstPtr statusField = structure->getField<ScalarArray>("status");
if (!statusField.get() || statusField->getElementType() != pvInt)
return false;
}
field = structure->getField("message");
if (field.get())
{
ScalarArrayConstPtr messageField = structure->getField<ScalarArray>("message");
if (!messageField.get() || messageField->getElementType() != pvString)
return false;
}
field = structure->getField("secondsPastEpoch");
if (field.get())
{
ScalarArrayConstPtr secondsPastEpochField = structure->getField<ScalarArray>("secondsPastEpoch");
if (!secondsPastEpochField.get() || secondsPastEpochField->getElementType() != pvLong)
return false;
}
field = structure->getField("nanoseconds");
if (field.get())
{
ScalarArrayConstPtr nanosecondsField = structure->getField<ScalarArray>("nanoseconds");
if (!nanosecondsField.get() || nanosecondsField->getElementType() != pvInt)
return false;
}
field = structure->getField("userTag");
if (field.get())
{
ScalarArrayConstPtr userTagField = structure->getField<ScalarArray>("userTag");
if (!userTagField.get() || userTagField->getElementType() != pvInt)
return false;
}
field = structure->getField("descriptor");
if (field.get())
{
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
return false;
}
NTFieldPtr ntField = NTField::get();
field = structure->getField("alarm");
if (field.get() && !ntField->isAlarm(field))
if (!structure)
return false;
field = structure->getField("timeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
Result result(structure);
return true;
return result
.is<Structure>()
.has<UnionArray>("value")
.has<ScalarArray>("channelName")
.maybeHas<ScalarArray>("severity")
.maybeHas<ScalarArray>("status")
.maybeHas<ScalarArray>("message")
.maybeHas<ScalarArray>("secondsPastEpoch")
.maybeHas<ScalarArray>("nanoseconds")
.maybeHas<ScalarArray>("userTag")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.valid();
}
bool NTMultiChannel::isCompatible(PVStructurePtr const &pvStructure)
{
if(!pvStructure.get()) return false;
@@ -326,7 +269,7 @@ bool NTMultiChannel::isValid()
if (getChannelName()->getLength() != valueLength) return false;
PVScalarArrayPtr arrayFields[] = {
getSeverity(), getStatus(), getMessage(),
getSeverity(), getStatus(), getMessage(),
getSecondsPastEpoch(), getNanoseconds(), getUserTag()
};
size_t N = sizeof(arrayFields)/sizeof(arrayFields[0]);
@@ -338,7 +281,7 @@ bool NTMultiChannel::isValid()
if (arrayField.get() && arrayField->getLength() != valueLength)
return false;
}
return true;
return true;
}

View File

@@ -4,6 +4,8 @@
* found in the file LICENSE that is included with the distribution
*/
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntnameValue.h>
#include <pv/ntutils.h>
@@ -134,35 +136,19 @@ bool NTNameValue::is_a(PVStructurePtr const & pvStructure)
bool NTNameValue::isCompatible(StructureConstPtr const & structure)
{
if (structure.get() == 0) return false;
ScalarArrayConstPtr nameField = structure->getField<ScalarArray>("name");
if (nameField.get() == 0 || nameField->getElementType() != pvString)
if (!structure)
return false;
ScalarArrayConstPtr valueField = structure->getField<ScalarArray>("value");
if (valueField.get() == 0)
return false;
Result result(structure);
FieldConstPtr field = structure->getField("descriptor");
if (field.get())
{
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (!descriptorField || descriptorField->getScalarType() != pvString)
return false;
}
NTFieldPtr ntField = NTField::get();
field = structure->getField("alarm");
if (field && !ntField->isAlarm(field))
return false;
field = structure->getField("timeStamp");
if (field && !ntField->isTimeStamp(field))
return false;
return true;
return result
.is<Structure>()
.has<ScalarArray>("name")
.has<ScalarArray>("value")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.valid();
}
bool NTNameValue::isCompatible(PVStructurePtr const & pvStructure)

View File

@@ -6,6 +6,11 @@
#include <algorithm>
#include <pv/lock.h>
#include <pv/sharedPtr.h>
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntndarray.h>
#include <pv/ntndarrayAttribute.h>
@@ -16,9 +21,6 @@ using namespace epics::pvData;
namespace epics { namespace nt {
static NTFieldPtr ntField = NTField::get();
namespace detail {
static FieldCreatePtr fieldCreate = getFieldCreate();
@@ -69,7 +71,7 @@ StructureConstPtr NTNDArrayBuilder::createStructure()
ScalarType st = static_cast<ScalarType>(i);
fb->addArray(std::string(ScalarTypeFunc::name(st)) + "Value", st);
}
valueType = fb->createUnion();
valueType = fb->createUnion();
}
if (!codecStruc)
@@ -125,7 +127,7 @@ StructureConstPtr NTNDArrayBuilder::createStructure()
returnedStruc = fb->createStructure();
if (!isExtended)
ntndarrayStruc[index] = returnedStruc;
ntndarrayStruc[index] = returnedStruc;
}
else
{
@@ -190,95 +192,11 @@ NTNDArrayBuilder::shared_pointer NTNDArrayBuilder::add(string const & name, Fiel
return shared_from_this();
}
}
const std::string NTNDArray::URI("epics:nt/NTNDArray:1.0");
const std::string ntAttrStr("epics:nt/NTAttribute:1.0");
static FieldCreatePtr fieldCreate = getFieldCreate();
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
class NTValueType
{
public:
static bool isCompatible(UnionConstPtr const &u)
{
if(!u.get()) return false;
if (u->getID() != Union::defaultId()) return false;
if (u->isVariant()) return false;
for (int i = pvBoolean; i != pvString; ++i)
{
ScalarType scalarType = static_cast<ScalarType>(i);
std::string name(ScalarTypeFunc::name(scalarType));
name += "Value";
ScalarArrayConstPtr scalarField = u->getField<ScalarArray>(name);
if (scalarField.get() == 0 ||
scalarField->getElementType() != scalarType)
return false;
}
return true;
}
};
class NTCodec
{
public:
static bool isCompatible(StructureConstPtr const &structure)
{
if(!structure.get()) return false;
if (structure->getID() != "codec_t") return false;
ScalarConstPtr scalarField = structure->getField<Scalar>("name");
if (scalarField.get() == 0 || scalarField->getScalarType() != pvString)
return false;
UnionConstPtr paramField = structure->getField<Union>("parameters");
if (paramField.get() == 0 || !paramField->isVariant())
return false;
return true;
}
};
class NTDimension
{
public:
static bool isCompatible(StructureConstPtr const &structure)
{
if(!structure.get()) return false;
if (structure->getID() != "dimension_t") return false;
ScalarConstPtr scalarField = structure->getField<Scalar>("size");
if (scalarField.get() == 0 || scalarField->getScalarType() != pvInt)
return false;
scalarField = structure->getField<Scalar>("offset");
if (scalarField.get() == 0 || scalarField->getScalarType() != pvInt)
return false;
scalarField = structure->getField<Scalar>("fullSize");
if (scalarField.get() == 0 || scalarField->getScalarType() != pvInt)
return false;
scalarField = structure->getField<Scalar>("binning");
if (scalarField.get() == 0 || scalarField->getScalarType() != pvInt)
return false;
scalarField = structure->getField<Scalar>("reverse");
if (scalarField.get() == 0 || scalarField->getScalarType() != pvBoolean)
return false;
return true;
}
};
NTNDArray::shared_pointer NTNDArray::wrap(PVStructurePtr const & pvStructure)
{
if(!isCompatible(pvStructure)) return shared_pointer();
@@ -300,84 +218,62 @@ bool NTNDArray::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
bool NTNDArray::isCompatible(StructureConstPtr const &structure)
{
if(!structure.get()) return false;
UnionConstPtr valueField = structure->getField<Union>("value");
if(!NTValueType::isCompatible(valueField)) return false;
StructureConstPtr codecField = structure->getField<Structure>("codec");
if(!NTCodec::isCompatible(codecField)) return false;
ScalarConstPtr compressedSizeField = structure->getField<Scalar>("compressedSize");
if (compressedSizeField.get() == 0)
return false;
if (compressedSizeField->getScalarType() != pvLong)
return false;
ScalarConstPtr uncompressedSizeField = structure->getField<Scalar>("uncompressedSize");
if (uncompressedSizeField.get() == 0)
return false;
if (uncompressedSizeField->getScalarType() != pvLong)
return false;
StructureArrayConstPtr dimensionField = structure->getField<StructureArray>("dimension");
if (dimensionField.get() == 0)
return false;
StructureConstPtr dimElementStruc = dimensionField->getStructure();
if(!NTDimension::isCompatible(dimElementStruc))
return false;
NTFieldPtr ntField = NTField::get();
StructureConstPtr dataTimeStampField = structure->getField<Structure>(
"dataTimeStamp");
if (dataTimeStampField.get() == 0 || !ntField->isTimeStamp(dataTimeStampField))
return false;
ScalarConstPtr uniqueIdField = structure->getField<Scalar>("uniqueId");
if (uniqueIdField.get() == 0)
return false;
if (uniqueIdField->getScalarType() != pvInt)
return false;
StructureArrayConstPtr attributeField = structure->getField<StructureArray>( "attribute");
StructureConstPtr attributeElementStruc = attributeField->getStructure();
if (!NTNDArrayAttribute::isCompatible(attributeElementStruc))
return false;
FieldConstPtr field = structure->getField("descriptor");
if (field.get())
namespace {
Result& isValue(Result& result)
{
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
return false;
result.is<Union>(Union::defaultId());
for (int i = pvBoolean; i < pvString; ++i) {
ScalarType type = static_cast<ScalarType>(i);
string name(ScalarTypeFunc::name(type));
result.has<ScalarArray>(name + "Value");
}
return result;
}
field = structure->getField("alarm");
if (field.get() && !ntField->isAlarm(field))
Result& isCodec(Result& result)
{
return result
.is<Structure>("codec_t")
.has<Scalar>("name")
.has<Union>("parameters");
}
Result& isDimension(Result& result)
{
return result
.is<StructureArray>("dimension_t[]")
.has<Scalar>("size")
.has<Scalar>("offset")
.has<Scalar>("fullSize")
.has<Scalar>("binning")
.has<Scalar>("reverse");
}
}
bool NTNDArray::isCompatible(StructureConstPtr const &structure)
{
if (!structure)
return false;
field = structure->getField("timeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
Result result(structure);
field = structure->getField("display");
if (field.get() && !ntField->isDisplay(field))
return false;
return true;
return result
.is<Structure>()
.has<&isValue>("value")
.has<&isCodec>("codec")
.has<Scalar>("compressedSize")
.has<Scalar>("uncompressedSize")
.has<&isDimension>("dimension")
.has<Scalar>("uniqueId")
.has<&NTField::isTimeStamp, Structure>("dataTimeStamp")
.has<&NTNDArrayAttribute::isAttribute, StructureArray>("attribute")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.maybeHas<&NTField::isDisplay, Structure>("display")
.valid();
}
@@ -388,7 +284,6 @@ bool NTNDArray::isCompatible(PVStructurePtr const & pvStructure)
return isCompatible(pvStructure->getStructure());
}
bool NTNDArray::isValid()
{
int64 valueSize = getValueSize();
@@ -432,10 +327,8 @@ int64 NTNDArray::getValueSize()
{
int64 size = 0;
PVScalarArrayPtr storedValue = getValue()->get<PVScalarArray>();
if (!storedValue.get())
{
if (storedValue.get())
size = storedValue->getLength()*getValueTypeSize();
}
return size;
}

View File

@@ -4,6 +4,8 @@
* found in the file LICENSE that is included with the distribution
*/
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntndarrayAttribute.h>
#include <pv/ntattribute.h>
@@ -93,6 +95,7 @@ NTNDArrayAttributeBuilder::NTNDArrayAttributeBuilder()
void NTNDArrayAttributeBuilder::reset()
{
tags = false;
descriptor = false;
alarm = false;
timeStamp = false;
@@ -131,24 +134,25 @@ bool NTNDArrayAttribute::is_a(PVStructurePtr const & pvStructure)
return is_a(pvStructure->getStructure());
}
Result& NTNDArrayAttribute::isAttribute(Result& result) {
return result
.has<Scalar>("name")
.has<Union>("value")
.maybeHas<ScalarArray>("tags")
.has<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.has<Scalar>("sourceType")
.has<Scalar>("source");
}
bool NTNDArrayAttribute::isCompatible(StructureConstPtr const & structure)
{
if (!NTAttribute::isCompatible(structure)) return false;
// descriptor required field for attibute in an ndarray
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (descriptorField.get() == 0 || descriptorField->getScalarType() != pvString)
if (!structure)
return false;
ScalarConstPtr sourcedTypeField = structure->getField<Scalar>("sourceType");
if (sourcedTypeField.get() == 0 || sourcedTypeField->getScalarType() != pvInt)
return false;
ScalarConstPtr sourcedField = structure->getField<Scalar>("source");
if (sourcedField.get() == 0 || sourcedField->getScalarType() != pvString)
return false;
return true;
Result result(structure);
return isAttribute(result.is<Structure>()).valid();
}
bool NTNDArrayAttribute::isCompatible(PVStructurePtr const & pvStructure)

View File

@@ -4,6 +4,8 @@
* found in the file LICENSE that is included with the distribution
*/
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntscalar.h>
#include <pv/ntutils.h>
@@ -152,42 +154,22 @@ bool NTScalar::is_a(PVStructurePtr const & pvStructure)
bool NTScalar::isCompatible(StructureConstPtr const &structure)
{
if (structure.get() == 0) return false;
ScalarConstPtr valueField = structure->getField<Scalar>("value");
if (valueField.get() == 0)
if (!structure)
return false;
FieldConstPtr field = structure->getField("descriptor");
if (field.get())
{
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
return false;
}
Result result(structure);
NTFieldPtr ntField = NTField::get();
field = structure->getField("alarm");
if (field.get() && !ntField->isAlarm(field))
return false;
field = structure->getField("timeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
field = structure->getField("display");
if (field.get() && !ntField->isDisplay(field))
return false;
field = structure->getField("control");
if (field.get() && !ntField->isControl(field))
return false;
return true;
return result
.is<Structure>()
.has<Scalar>("value")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.maybeHas<&NTField::isDisplay, Structure>("display")
.maybeHas<&NTField::isControl, Structure>("control")
.valid();
}
bool NTScalar::isCompatible(PVStructurePtr const & pvStructure)
{
if(!pvStructure) return false;

View File

@@ -4,6 +4,8 @@
* found in the file LICENSE that is included with the distribution
*/
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntscalarArray.h>
#include <pv/ntutils.h>
@@ -161,39 +163,20 @@ bool NTScalarArray::is_a(PVStructurePtr const & pvStructure)
bool NTScalarArray::isCompatible(StructureConstPtr const & structure)
{
if (structure.get() == 0) return false;
ScalarArrayConstPtr valueField = structure->getField<ScalarArray>("value");
if (valueField.get() == 0)
if (!structure)
return false;
FieldConstPtr field = structure->getField("descriptor");
if (field.get())
{
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
return false;
}
Result result(structure);
NTFieldPtr ntField = NTField::get();
field = structure->getField("alarm");
if (field.get() && !ntField->isAlarm(field))
return false;
field = structure->getField("timeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
field = structure->getField("display");
if (field.get() && !ntField->isDisplay(field))
return false;
field = structure->getField("control");
if (field.get() && !ntField->isControl(field))
return false;
return true;
return result
.is<Structure>()
.has<ScalarArray>("value")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.maybeHas<&NTField::isDisplay, Structure>("display")
.maybeHas<&NTField::isControl, Structure>("control")
.valid();
}
bool NTScalarArray::isCompatible(PVStructurePtr const & pvStructure)

View File

@@ -4,6 +4,7 @@
* found in the file LICENSE that is included with the distribution
*/
#include <algorithm>
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntscalarMultiChannel.h>
@@ -12,7 +13,7 @@
using namespace std;
using namespace epics::pvData;
namespace epics { namespace nt {
namespace epics { namespace nt {
static FieldCreatePtr fieldCreate = getFieldCreate();
@@ -228,86 +229,27 @@ bool NTScalarMultiChannel::is_a(PVStructurePtr const & pvStructure)
bool NTScalarMultiChannel::isCompatible(StructureConstPtr const & structure)
{
if (!structure.get()) return false;
ScalarArrayConstPtr valueField = structure->getField<ScalarArray>("value");
if (!valueField.get()) return false;
ScalarArrayConstPtr channelNameField = structure->getField<ScalarArray>(
"channelName");
if (!channelNameField.get()) return false;
if (channelNameField->getElementType() != pvString) return false;
FieldConstPtr field = structure->getField("severity");
if (field.get())
{
ScalarArrayConstPtr severityField = structure->getField<ScalarArray>("severity");
if (!severityField.get() || severityField->getElementType() != pvInt)
return false;
}
field = structure->getField("status");
if (field.get())
{
ScalarArrayConstPtr statusField = structure->getField<ScalarArray>("status");
if (!statusField.get() || statusField->getElementType() != pvInt)
return false;
}
field = structure->getField("message");
if (field.get())
{
ScalarArrayConstPtr messageField = structure->getField<ScalarArray>("message");
if (!messageField.get() || messageField->getElementType() != pvString)
return false;
}
field = structure->getField("secondsPastEpoch");
if (field.get())
{
ScalarArrayConstPtr secondsPastEpochField = structure->getField<ScalarArray>("secondsPastEpoch");
if (!secondsPastEpochField.get() || secondsPastEpochField->getElementType() != pvLong)
return false;
}
field = structure->getField("nanoseconds");
if (field.get())
{
ScalarArrayConstPtr nanosecondsField = structure->getField<ScalarArray>("nanoseconds");
if (!nanosecondsField.get() || nanosecondsField->getElementType() != pvInt)
return false;
}
field = structure->getField("userTag");
if (field.get())
{
ScalarArrayConstPtr userTagField = structure->getField<ScalarArray>("userTag");
if (!userTagField.get() || userTagField->getElementType() != pvInt)
return false;
}
field = structure->getField("descriptor");
if (field.get())
{
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
return false;
}
NTFieldPtr ntField = NTField::get();
field = structure->getField("alarm");
if (field.get() && !ntField->isAlarm(field))
if (!structure)
return false;
field = structure->getField("timeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
Result result(structure);
return true;
return result
.is<Structure>()
.has<ScalarArray>("value")
.has<ScalarArray>("channelName")
.maybeHas<ScalarArray>("severity")
.maybeHas<ScalarArray>("status")
.maybeHas<ScalarArray>("message")
.maybeHas<ScalarArray>("secondsPastEpoch")
.maybeHas<ScalarArray>("nanoseconds")
.maybeHas<ScalarArray>("userTag")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.valid();
}
bool NTScalarMultiChannel::isCompatible(PVStructurePtr const &pvStructure)
{
if(!pvStructure.get()) return false;
@@ -321,7 +263,7 @@ bool NTScalarMultiChannel::isValid()
if (getChannelName()->getLength() != valueLength) return false;
PVScalarArrayPtr arrayFields[] = {
getSeverity(), getStatus(), getMessage(),
getSeverity(), getStatus(), getMessage(),
getSecondsPastEpoch(), getNanoseconds(), getUserTag()
};
size_t N = sizeof(arrayFields)/sizeof(arrayFields[0]);
@@ -333,7 +275,7 @@ bool NTScalarMultiChannel::isValid()
if (arrayField.get() && arrayField->getLength() != valueLength)
return false;
}
return true;
return true;
}
NTScalarMultiChannelBuilderPtr NTScalarMultiChannel::createBuilder()

View File

@@ -5,6 +5,7 @@
*/
#include <algorithm>
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/nttable.h>
@@ -149,42 +150,32 @@ bool NTTable::is_a(PVStructurePtr const & pvStructure)
bool NTTable::isCompatible(StructureConstPtr const & structure)
{
if (!structure.get()) return false;
StructureConstPtr valueField = structure->getField<Structure>("value");
if (!valueField.get())
if (!structure)
return false;
FieldConstPtrArray const & fields = valueField->getFields();
for (FieldConstPtrArray::const_iterator it = fields.begin();
it != fields.end(); ++it)
{
if ((*it)->getType() != scalarArray) return false;
Result result(structure);
result
.is<Structure>()
.has<Structure>("value")
.has<ScalarArray>("labels")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp");
StructureConstPtr value(structure->getField<Structure>("value"));
if (value) {
Result r(value);
StringArray const & names(value->getFieldNames());
StringArray::const_iterator it;
for (it = names.begin(); it != names.end(); ++it)
r.has<ScalarArray>(*it);
result |= r;
}
ScalarArrayConstPtr labelsField = structure->getField<ScalarArray>("labels");
if (!labelsField.get() || labelsField->getElementType() != pvString)
return false;
FieldConstPtr field = structure->getField("descriptor");
if (field.get())
{
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
return false;
}
NTFieldPtr ntField = NTField::get();
field = structure->getField("alarm");
if (field.get() && !ntField->isAlarm(field))
return false;
field = structure->getField("timeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
return true;
return result.valid();
}
bool NTTable::isCompatible(PVStructurePtr const & pvStructure)
@@ -197,7 +188,7 @@ bool NTTable::isCompatible(PVStructurePtr const & pvStructure)
bool NTTable::isValid()
{
PVFieldPtrArray const & columns = pvValue->getPVFields();
if (getLabels()->getLength() != columns.size()) return false;
bool first = true;
int length = 0;
@@ -270,7 +261,7 @@ PVStringArrayPtr NTTable::getLabels() const
StringArray const & NTTable::getColumnNames() const
{
return pvNTTable->getStructure()->getFieldNames();
return pvValue->getStructure()->getFieldNames();
}
PVFieldPtr NTTable::getColumn(std::string const & columnName) const

View File

@@ -4,6 +4,8 @@
* found in the file LICENSE that is included with the distribution
*/
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntunion.h>
#include <pv/ntutils.h>
@@ -18,6 +20,12 @@ static NTFieldPtr ntField = NTField::get();
namespace detail {
NTUnionBuilder::shared_pointer NTUnionBuilder::value(UnionConstPtr unionType)
{
valueType = unionType;
return shared_from_this();
}
StructureConstPtr NTUnionBuilder::createStructure()
{
FieldBuilderPtr builder =
@@ -122,31 +130,18 @@ bool NTUnion::is_a(PVStructurePtr const & pvStructure)
bool NTUnion::isCompatible(StructureConstPtr const &structure)
{
if (structure.get() == 0) return false;
UnionConstPtr valueField = structure->getField<Union>("value");
if (valueField.get() == 0)
if (!structure)
return false;
FieldConstPtr field = structure->getField("descriptor");
if (field.get())
{
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
return false;
}
Result result(structure);
NTFieldPtr ntField = NTField::get();
field = structure->getField("alarm");
if (field.get() && !ntField->isAlarm(field))
return false;
field = structure->getField("timeStamp");
if (field.get() && !ntField->isTimeStamp(field))
return false;
return true;
return result
.is<Structure>()
.has<Union>("value")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.valid();
}
bool NTUnion::isCompatible(PVStructurePtr const & pvStructure)

View File

@@ -5,6 +5,7 @@
*/
#include <algorithm>
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/nturi.h>
@@ -149,45 +150,31 @@ bool NTURI::is_a(PVStructurePtr const & pvStructure)
bool NTURI::isCompatible(StructureConstPtr const & structure)
{
if (!structure.get()) return false;
ScalarConstPtr schemeField = structure->getField<Scalar>("scheme");
if (schemeField.get() == 0 || schemeField->getScalarType() != pvString)
if (!structure)
return false;
ScalarConstPtr pathField = structure->getField<Scalar>("path");
if (pathField.get() == 0 || pathField->getScalarType() != pvString)
return false;
Result result(structure);
FieldConstPtr field = structure->getField("authority");
if (field.get())
{
ScalarConstPtr authorityField = structure->getField<Scalar>("authority");
if (!authorityField.get() || authorityField->getScalarType() != pvString)
return false;
result
.is<Structure>()
.has<Scalar>("scheme")
.has<Scalar>("path")
.maybeHas<Scalar>("authority")
.maybeHas<Structure>("query");
StructureConstPtr query(structure->getField<Structure>("query"));
if (query) {
Result r(query);
StringArray const & names(query->getFieldNames());
StringArray::const_iterator it;
for (it = names.begin(); it != names.end(); ++it)
r.has<ScalarArray>(*it);
result |= r;
}
field = structure->getField("query");
if (field.get())
{
StructureConstPtr queryField = structure->getField<Structure>("query");
if (!queryField.get())
return false;
FieldConstPtrArray const & fields = queryField->getFields();
for (FieldConstPtrArray::const_iterator it = fields.begin();
it != fields.end(); ++it)
{
if ((*it)->getType() != scalar) return false;
ScalarType scalarType = std::tr1::dynamic_pointer_cast<const Scalar>(
(*it))->getScalarType();
if (scalarType != pvString &&
scalarType != pvInt &&
scalarType != pvDouble) return false;
}
}
return true;
return result.valid();
}

View File

@@ -31,7 +31,7 @@
/** @page Overview Documentation
*
* <a href = "ntCPP.html">ntCPP.html</a>
* <a href = "../ntCPP.html">Normative Types (C++) Reference</a>
*
*/

View File

@@ -93,7 +93,6 @@ namespace detail {
void reset();
bool dim;
bool descriptor;
bool alarm;
bool timeStamp;

View File

@@ -30,6 +30,8 @@
namespace epics { namespace nt {
struct Result;
class NTField;
typedef std::tr1::shared_ptr<NTField> NTFieldPtr;
@@ -149,6 +151,30 @@ private:
NTField();
epics::pvData::FieldCreatePtr fieldCreate;
epics::pvData::StandardFieldPtr standardField;
// These won't be public just yet
static Result& isEnumerated(Result&);
static Result& isTimeStamp(Result&);
static Result& isAlarm(Result&);
static Result& isDisplay(Result&);
static Result& isAlarmLimit(Result&);
static Result& isControl(Result&);
friend class NTAggregate;
friend class NTAttribute;
friend class NTContinuum;
friend class NTEnum;
friend class NTHistogram;
friend class NTMatrix;
friend class NTMultiChannel;
friend class NTNameValue;
friend class NTNDArray;
friend class NTNDArrayAttribute;
friend class NTScalar;
friend class NTScalarArray;
friend class NTScalarMultiChannel;
friend class NTTable;
friend class NTUnion;
};
/**
@@ -197,12 +223,6 @@ public:
*/
epics::pvData::PVStructurePtr createDisplay();
/**
* Creates an alarmLimit PVStructure.
* @return an alarmLimit PVStructure.
*/
epics::pvData::PVStructurePtr createAlarmLimit();
/**
* Creates a control PVStructure.
* @return a control PVStructure.

View File

@@ -103,7 +103,6 @@ namespace detail {
bool valueTypeSet;
epics::pvData::ScalarType valueType;
bool dim;
bool descriptor;
bool alarm;
bool timeStamp;

View File

@@ -10,16 +10,16 @@
#include <string>
#ifdef epicsExportSharedSymbols
# define ntscalarArrayEpicsExportSharedSymbols
# define ntndarrayEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <pv/pvDisplay.h>
#include <pv/pvControl.h>
#ifdef ntscalarArrayEpicsExportSharedSymbols
#ifdef ntndarrayEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef ntscalarArrayEpicsExportSharedSymbols
# undef ntndarrayEpicsExportSharedSymbols
#endif
#include <pv/ntfield.h>
@@ -139,7 +139,7 @@ public:
* and if so returns an NTScalarArray which wraps it.
* This method will return null if the structure is is not compatible
* or is null.
*
*
* @param pvStructure the PVStructure to be wrapped
* @return NTScalarArray instance wrapping pvStructure on success, null otherwise
*/
@@ -150,7 +150,7 @@ public:
* <p>
* No checks are made as to whether the specified PVStructure
* is compatible with NTNDArray or is non-null.
*
*
* @param pvStructure the PVStructure to be wrapped
* @return NTNDArray instance wrapping pvStructure
*/
@@ -163,7 +163,7 @@ public:
* version of NTNDArray through its type ID, including checking version numbers.
* The return value does not depend on whether the structure is actually
* compatible in terms of its introspection type.
*
*
* @param structure the pvStructure to test
* @return (false,true) if the specified Structure (is not, is) a compatible NTNDArray
*/
@@ -176,7 +176,7 @@ public:
* version of NTNDArray through its type ID, including checking version numbers.
* The return value does not depend on whether the structure is actually
* compatible in terms of its introspection type.
*
*
* @param pvStructure the PVStructure to test
* @return (false,true) if the specified PVStructure (is not, is) a compatible NTNDArray
*/
@@ -187,7 +187,7 @@ public:
* <p>
* Checks if the specified Structure is compatible with this version
* of NTNDArray through the introspection interface.
*
*
* @param structure the Structure to test
* @return (false,true) if the specified Structure (is not, is) a compatible NTNDArray
*/

View File

@@ -22,6 +22,7 @@
namespace epics { namespace nt {
struct Result;
class NTNDArrayAttribute;
typedef std::tr1::shared_ptr<NTNDArrayAttribute> NTNDArrayAttributePtr;
@@ -302,10 +303,13 @@ public:
private:
NTNDArrayAttribute(epics::pvData::PVStructurePtr const & pvStructure);
static Result& isAttribute(Result& result);
epics::pvData::PVStructurePtr pvNTNDArrayAttribute;
epics::pvData::PVUnionPtr pvValue;
friend class detail::NTNDArrayAttributeBuilder;
friend class NTNDArray;
};
}}

View File

@@ -40,6 +40,14 @@ namespace detail {
public:
POINTER_DEFINITIONS(NTUnionBuilder);
/**
* Specifies the union for the value field.
* If this is not called then a variant union is the default.
* @param unionType the introspection object for the union value field
* @return this instance of NTUnionBuilder
*/
shared_pointer value(epics::pvData::UnionConstPtr unionType);
/**
* Adds descriptor field to the NTUnion.
* @return this instance of <b>NTUnionBuilder</b>.

277
src/validator.h Normal file
View File

@@ -0,0 +1,277 @@
/* validator.h */
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#ifndef VALIDATOR_H
#define VALIDATOR_H
#include <string>
#include <set>
#include <algorithm>
#include <pv/pvIntrospect.h>
namespace epics { namespace nt {
/**
* @brief Validation methods for NT types.
*
* @author bsm
*/
struct Result {
struct Error {
std::string path;
enum Type {
MissingField,
IncorrectType,
IncorrectId,
} type;
Error(std::string const & path, Type type)
: path(path), type(type) {}
bool operator==(const Error& other) const {
return type == other.type && path == other.path;
}
std::ostream& dump(std::ostream& os) const {
os << "Error(path=" << (path.empty() ? "<root>" : path) << ": ";
switch(type) {
case MissingField: os << "missing"; break;
case IncorrectType: os << "incorrect type"; break;
case IncorrectId: os << "incorrect ID"; break;
}
os << ")";
return os;
}
};
epics::pvData::FieldConstPtr field;
std::string path;
std::vector<Error> errors;
enum result_t {
Pass,
Fail,
} result;
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);
errors.insert(errors.end(), other.errors.begin(), other.errors.end());
return *this;
}
/**
* Returns whether this Result is valid.
*
* @return true if all tests passed, false otherwise.
*/
inline bool valid(void) const {
return result == Pass;
}
/**
* Test that this Result's field is of a particular type 'T'.
*
* Appends an Error::Type::IncorrectType if the field is not of type 'T'.
*
* @return itself
*/
template<typename T>
Result& is(void) {
if (!dynamic_cast<T const *>(field.get())) {
result = Fail;
errors.push_back(Error(path, Error::IncorrectType));
}
return *this;
}
/**
* Test that this Result's field is of a particular type 'T' and has
* an ID equal to 'id'.
*
* Appends an Error::Type::IncorrectType if the field is not of type 'T'.
* Appends an Error::Type::IncorrectId if the field does not have an ID
* equal to 'id'.
*
* @return itself
*/
template<typename T>
Result& is(const std::string& id) {
T const *s = dynamic_cast<T const *>(field.get());
if (!s) {
result = Fail;
errors.push_back(Error(path, Error::IncorrectType));
} else if (s->getID() != id) {
result = Fail;
errors.push_back(Error(path, Error::IncorrectId));
}
return *this;
}
/**
* Test that this Result's field has a subfield with name 'name' and
* apply the function 'fn' to the subfield.
*
* Appends an Error::Type::IncorrectType if the field is not one of
* Structure, StructureArray, Union, UnionArray.
* Appends an Error::Type::MissingField if the subfield is not
* present.
*
* @return itself
*/
template<Result& (*fn)(Result&)>
Result& has(const std::string& name) {
return has<epics::pvData::Field>(name, false, fn);
}
/**
* Test that this Result's field has an optional subfield with name
* 'name' and, if it has, apply the function 'fn' to the subfield.
*
* Appends an Error::Type::IncorrectType if the field is not one of
* Structure, StructureArray, Union, UnionArray.
*
* @return itself
*/
template<Result& (*fn)(Result&)>
Result& maybeHas(const std::string& name) {
return has<epics::pvData::Field>(name, true, fn);
}
/**
* Test that this Result's field has a subfield with name 'name',
* apply the function 'fn' to the subfield and
* test that the subfield is of type 'T'.
*
* Appends an Error::Type::IncorrectType if the field is not one of
* Structure, StructureArray, Union, UnionArray.
* Appends an Error::Type::IncorrectType if the subfield is not of
* type 'T'.
* Appends an Error::Type::MissingField if the subfield is not
* present.
*
* @return itself
*/
template<Result& (*fn)(Result&), typename T>
Result& has(const std::string& name) {
return has<T>(name, false, fn);
}
/**
* Test that this Result's field has an optional subfield with name
* 'name' and, if it has, apply the function 'fn' to the subfield and
* test that the subfield is of type 'T'.
*
* Appends an Error::Type::IncorrectType if the field is not one of
* Structure, StructureArray, Union, UnionArray.
* Appends an Error::Type::IncorrectType if the subfield exists and
* is not of type 'T'.
*
* @return itself
*/
template<Result& (*fn)(Result&), typename T>
Result& maybeHas(const std::string& name) {
return has<T>(name, true, fn);
}
/**
* Test that this Result's field has a subfield with name 'name' and
* test that the subfield is of type 'T'.
*
* Appends an Error::Type::IncorrectType if the field is not one of
* Structure, StructureArray, Union, UnionArray.
* Appends an Error::Type::IncorrectType if the subfield is not of
* type 'T'.
* Appends an Error::Type::MissingField if the subfield is not
* present.
*
* @return itself
*/
template<typename T>
Result& has(const std::string& name) {
return has<T>(name, false, NULL);
}
/**
* Test that this Result's field has an optional subfield with name
* 'name' and, if it has, test that the subfield is of type 'T'.
*
* Appends an Error::Type::IncorrectType if the field is not one of
* Structure, StructureArray, Union, UnionArray.
* Appends an Error::Type::IncorrectType if the subfield exists and
* is not of type 'T'.
*
* @return itself
*/
template<typename T>
Result& maybeHas(const std::string& name) {
return has<T>(name, true, NULL);
}
std::ostream& dump(std::ostream& os) const {
os << "Result(valid=" << (result == Pass) << ", errors=[ ";
std::vector<Error>::const_iterator it;
for (it = errors.begin(); it != errors.end(); ++it) {
(*it).dump(os);
os << " ";
}
os << "])";
return os;
}
private:
template<typename T>
Result& has(const std::string& name, bool optional, Result& (*check)(Result&) = NULL) {
epics::pvData::FieldConstPtr subField;
switch(field->getType()) {
case epics::pvData::structure:
subField = static_cast<epics::pvData::Structure const *>(field.get())->getField(name);
break;
case epics::pvData::structureArray:
subField = static_cast<epics::pvData::StructureArray const *>(field.get())->getStructure()->getField(name);
break;
case epics::pvData::union_:
subField = static_cast<epics::pvData::Union const *>(field.get())->getField(name);
break;
case epics::pvData::unionArray:
subField = static_cast<epics::pvData::UnionArray const *>(field.get())->getUnion()->getField(name);
break;
default:
// Expected a structure-like Field
result = Fail;
errors.push_back(Error(path, Error::IncorrectType));
return *this;
}
std::string subFieldPath(path.empty() ? name : path + "." + name);
if (!subField) {
if (!optional) {
result = Fail;
errors.push_back(Error(subFieldPath, Error::MissingField));
}
} else if (!dynamic_cast<T const *>(subField.get())) {
result = Fail;
errors.push_back(Error(subFieldPath, Error::IncorrectType));
} else if (check) {
Result r(subField, subFieldPath);
*this |= check(r);
}
return *this;
}
};
}}
#endif

View File

@@ -72,6 +72,10 @@ TESTPROD_HOST += ntutilsTest
ntutilsTest_SRCS = ntutilsTest.cpp
TESTS += ntutilsTest
TESTPROD_HOST += validatorTest
validatorTest_SRCS = validatorTest.cpp
TESTS += validatorTest
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
include $(TOP)/configure/RULES

View File

@@ -78,7 +78,7 @@ void test_ntaggregate()
// example how to set a value
//
ntAggregate->getValue()->put(1.0);
//
// example how to get a value
//
@@ -173,5 +173,3 @@ MAIN(testNTAggregate) {
test_wrap();
return testDone();
}

View File

@@ -173,5 +173,3 @@ MAIN(testNTAttribute) {
test_wrap();
return testDone();
}

View File

@@ -274,5 +274,3 @@ MAIN(testNTContinuum) {
test_extra();
return testDone();
}

View File

@@ -84,7 +84,7 @@ void test_ntenum()
choices[1] = "On";
pvValue->getSubField<PVStringArray>("choices")->replace(freeze(choices));
pvValue->getSubField<PVInt>("index")->put(1);
//
// example how to get a value
//
@@ -185,5 +185,3 @@ MAIN(testNTEnum) {
test_wrap();
return testDone();
}

View File

@@ -259,5 +259,3 @@ MAIN(testNTHistogram) {
test_extra();
return testDone();
}

View File

@@ -151,7 +151,6 @@ void test_ntmatrix()
display.setLow(-15);
display.setHigh(15);
display.setDescription("This is a test scalar array");
display.setFormat("%d");
display.setUnits("A");
pvDisplay.set(display);
}
@@ -208,5 +207,3 @@ MAIN(testNTMatrix) {
test_wrap();
return testDone();
}

View File

@@ -193,4 +193,3 @@ MAIN(testCreateRequest)
test_wrap();
return testDone();
}

View File

@@ -254,5 +254,3 @@ MAIN(testNTNameValue) {
test_extra();
return testDone();
}

View File

@@ -175,5 +175,3 @@ MAIN(testNTNDArrayAttribute) {
test_wrap();
return testDone();
}

View File

@@ -21,8 +21,8 @@ void test_builder(bool extraFields)
testOk(builder.get() != 0, "Got builder");
builder->addDescriptor()->
addTimeStamp()->
addAlarm()->
addTimeStamp()->
addAlarm()->
addDisplay();
if (extraFields)
@@ -68,9 +68,9 @@ void test_all()
PVStructurePtr pvStructure = builder->
addDescriptor()->
addTimeStamp()->
addAlarm()->
addDisplay()->
addTimeStamp()->
addAlarm()->
addDisplay()->
add("extra1",fieldCreate->createScalar(pvString)) ->
add("extra2",fieldCreate->createScalarArray(pvString)) ->
createPVStructure();
@@ -120,5 +120,3 @@ MAIN(testNTNDArray) {
test_wrap();
return testDone();
}

View File

@@ -167,7 +167,6 @@ void test_ntscalarArray()
display.setLow(-15);
display.setHigh(15);
display.setDescription("This is a test scalar array");
display.setFormat("%d");
display.setUnits("A");
pvDisplay.set(display);
}
@@ -243,5 +242,3 @@ MAIN(testNTScalarArray) {
test_wrap();
return testDone();
}

View File

@@ -180,4 +180,3 @@ MAIN(testCreateRequest)
test_wrap();
return testDone();
}

View File

@@ -159,7 +159,6 @@ void test_ntscalar()
display.setLow(-15);
display.setHigh(15);
display.setDescription("This is a test scalar");
display.setFormat("%d");
display.setUnits("A");
pvDisplay.set(display);
}
@@ -234,5 +233,3 @@ MAIN(testNTScalar) {
test_wrap();
return testDone();
}

View File

@@ -245,5 +245,3 @@ MAIN(testNTTable) {
test_wrap();
return testDone();
}

View File

@@ -47,7 +47,6 @@ void test_builder()
testOk(valueField.get() != 0, "value is enum");
std::cout << *structure << std::endl;
}
void test_ntunion()
@@ -158,12 +157,42 @@ void test_wrap()
testOk(ptr.get() != 0, "wrapUnsafe OK");
}
MAIN(testNTUnion) {
testPlan(29);
test_builder();
test_ntunion();
test_wrap();
return testDone();
void test_variant_union()
{
StructureConstPtr structure = NTUnion::createBuilder()->
addDescriptor()->
addAlarm()->
addTimeStamp()->
createStructure();
testOk1(structure->getField<Union>("value")->isVariant());
}
void test_regular_union()
{
UnionConstPtr u = getFieldCreate()->createFieldBuilder()->
add("x", pvDouble)->
add("i", pvInt)->
createUnion();
StructureConstPtr structure = NTUnion::createBuilder()->
value(u)->
addDescriptor()->
addAlarm()->
addTimeStamp()->
createStructure();
testOk1(!structure->getField<Union>("value")->isVariant());
testOk1(structure->getField<Union>("value") == u);
}
MAIN(testNTUnion) {
testPlan(32);
test_builder();
test_ntunion();
test_wrap();
test_variant_union();
test_regular_union();
return testDone();
}

View File

@@ -33,5 +33,3 @@ MAIN(testNTUtils) {
test_is_a();
return testDone();
}

311
test/validatorTest.cpp Normal file
View File

@@ -0,0 +1,311 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#include <epicsUnitTest.h>
#include <testMain.h>
#include "../src/validator.h"
#include <pv/ntndarray.h>
#include <pv/pvIntrospect.h>
using namespace epics::nt;
using namespace epics::pvData;
static epics::pvData::FieldCreatePtr FC;
void test_is()
{
testDiag("test_is");
// Result::is<Scalar> must be valid for Scalars of any type
for(int i = pvBoolean; i <= pvString; ++i) {
ScalarType t = static_cast<ScalarType>(i);
testOk(Result(FC->createScalar(t)).is<Scalar>().valid(),
"Result(Scalar<%s>).is<Scalar>().valid()", ScalarTypeFunc::name(t));
}
// Result::is<ScalarArray> must be valid for ScalarArray of any type
for(int i = pvBoolean; i <= pvString; ++i) {
ScalarType t = static_cast<ScalarType>(i);
testOk(Result(FC->createScalarArray(t)).is<ScalarArray>().valid(),
"Result(ScalarArray<%s>).is<ScalarArray>().valid()", ScalarTypeFunc::name(t));
}
{
// Result::is<Scalar> must be invalid for non-Scalar
Result result(FC->createScalarArray(pvInt));
result.is<Scalar>();
testOk(!result.valid(), "!Result(ScalarArray<pvInt>).is<Scalar>.valid()");
testOk1(result.errors.at(0) == Result::Error("", Result::Error::IncorrectType));
}
{
// Result::is<ScalarArray> must be invalid for non-ScalarArray
Result result(FC->createScalar(pvInt));
result.is<ScalarArray>();
testOk(!result.valid(), "!Result(ScalarArray<pvInt>).is<Scalar>.valid()");
testOk1(result.errors.at(0) == Result::Error("", Result::Error::IncorrectType));
}
}
void test_is_id()
{
testDiag("test_is_id");
FieldBuilderPtr FB(FieldBuilder::begin());
{
// Both type and ID match for Structure
Result result(FB->setId("TEST_ID")->createStructure());
result.is<Structure>("TEST_ID");
testOk(result.valid(), "Result(Structure['TEST_ID']).is<Structure>('TEST_ID').valid()");
}
{
// Both type and ID match for Union
UnionConstPtr un(FB->
setId("TEST_ID")->
add("A", pvInt)->
add("B", pvString)->
createUnion()
);
Result result(un);
result.is<Union>("TEST_ID");
testOk(result.valid(), "Result(Union{A:int,B:string}['TEST_ID']).is<Union>('TEST_ID').valid()");
}
{
// Both type and ID match for Variant Union
Result result(FB-> createUnion());
result.is<Union>(Union::ANY_ID);
testOk(result.valid(), "Result(Union).is<Union>('%s').valid()", Union::ANY_ID.c_str());
}
{
// ID matches, type doesn't
Result result(FB->setId("TEST_ID")->createStructure());
result.is<Union>("TEST_ID");
testOk(!result.valid(), "!Result(Union['TEST_ID']).is<Structure>('TEST_ID').valid()");
testOk1(result.errors.at(0) == Result::Error("", Result::Error::IncorrectType));
}
{
// Type matches, ID doesn't
Result result(FB->setId("WRONG_ID")->createStructure());
result.is<Structure>("TEST_ID");
testOk(!result.valid(), "!Result(Structure['WRONG_ID']).is<Structure>('TEST_ID').valid()");
testOk1(result.errors.at(0) == Result::Error("", Result::Error::IncorrectId));
}
{
// Neither type nor ID match (ID is not even checked in this case since it doesn't exist)
Result result(FC->createScalar(pvDouble));
result.is<Structure>("SOME_ID");
testOk(!result.valid(), "!Result(Scalar).is<Structure>('SOME_ID').valid()");
testOk1(result.errors.at(0) == Result::Error("", Result::Error::IncorrectType));
}
}
void test_has()
{
testDiag("test_has");
FieldBuilderPtr FB(FieldBuilder::begin());
StructureConstPtr struc(FB->
add("A", pvInt)->
add("B", pvString)->
createStructure()
);
std::string strucRepr("Structure{A:int,B:String}");
{
// Test that struc has both A and B, both being Scalars
Result result(struc);
result
.has<Scalar>("A")
.has<Scalar>("B");
testOk(result.valid(),
"Result(%s).has<Scalar>('A').has<Scalar>('B').valid()",
strucRepr.c_str());
}
{
// Test that struc does not have a field B of type ScalarArray
Result result(struc);
result
.has<Scalar>("A")
.has<ScalarArray>("B");
testOk(!result.valid(),
"!Result(%s).has<Scalar>('A').has<ScalarArray>('B').valid()",
strucRepr.c_str());
testOk1(result.errors.at(0) == Result::Error("B", Result::Error::IncorrectType));
}
{
// Test that struc does not have a field C
Result result(struc);
result
.has<Scalar>("A")
.has<Scalar>("C");
testOk(!result.valid(),
"!Result(%s).has<Scalar>('A').has<Scalar>('C').valid()",
strucRepr.c_str());
testOk1(result.errors.at(0) == Result::Error("C", Result::Error::MissingField));
}
{
// Test that 'has' fails for non-structure-like Fields
Result result(FC->createScalar(pvByte));
result.has<Scalar>("X");
testOk(!result.valid(), "!Result(Scalar<pvByte>).has<Scalar>('X').valid()");
testOk1(result.errors.at(0) == Result::Error("", Result::Error::IncorrectType));
}
}
void test_maybe_has()
{
testDiag("test_maybe_has");
FieldBuilderPtr FB(FieldBuilder::begin());
StructureConstPtr struc(FB->
add("A", pvInt)->
add("B", pvString)->
createStructure()
);
std::string strucRepr("Structure{A:int,B:String}");
{
// Test that struc maybe has A and B, both being Scalars
Result result(struc);
result
.maybeHas<Scalar>("A")
.maybeHas<Scalar>("B");
testOk(result.valid(),
"Result(%s).maybeHas<Scalar>('A').maybeHas<Scalar>('B').valid()",
strucRepr.c_str());
}
{
// Test that if struc has a field B, it must be of type ScalarArray
Result result(struc);
result
.maybeHas<Scalar>("A")
.maybeHas<ScalarArray>("B");
testOk(!result.valid(),
"!Result(%s).maybeHas<Scalar>('A').maybeHas<ScalarArray>('B').valid()",
strucRepr.c_str());
testOk1(result.errors.at(0) == Result::Error("B", Result::Error::IncorrectType));
}
{
// Test that struc maybe has A (which it does) and B (which it doesn't)
Result result(struc);
result
.maybeHas<Scalar>("A")
.maybeHas<Scalar>("C");
testOk(result.valid(),
"Result(%s).maybeHas<Scalar>('A').maybeHas<Scalar>('C').valid()",
strucRepr.c_str());
}
{
// Test that 'maybeHas' fails for non-structure-like Fields
Result result(FC->createScalar(pvByte));
result.maybeHas<Scalar>("X");
testOk(!result.valid(), "!Result(Scalar<pvByte>).maybeHas<Scalar>('X').valid()");
testOk1(result.errors.at(0) == Result::Error("", Result::Error::IncorrectType));
}
}
Result& isStructABC(Result& result)
{
return result
.is<Structure>("ABC")
.has<Scalar>("A")
.has<ScalarArray>("B")
.maybeHas<Scalar>("C");
}
void test_has_fn()
{
testDiag("test_has_fn");
FieldBuilderPtr FB(FieldBuilder::begin());
{
StructureConstPtr inner(FB->
setId("ABC")->
add("A", pvInt)->
addArray("B", pvDouble)->
add("C", pvString)->
createStructure()
);
Result result(FB->add("inner", inner)->createStructure());
result.has<&isStructABC>("inner");
testOk(result.valid(), "Result({inner:<valid structABC>}).has<&isStructAbc>('inner').valid()");
}
{
StructureConstPtr inner(FB->
setId("ABC")->
add("A", pvInt)->
addArray("B", pvDouble)->
createStructure()
);
Result result(FB->add("inner", inner)->createStructure());
result.has<&isStructABC>("inner");
testOk(result.valid(), "Result({inner:<valid structABC w/o C>}).has<&isStructAbc>('inner').valid()");
}
{
StructureConstPtr inner(FB->
setId("XYZ")->
add("A", pvInt)->
addArray("B", pvDouble)->
createStructure()
);
Result result(FB->add("inner", inner)->createStructure());
result.has<&isStructABC>("inner");
testOk(!result.valid(), "!Result({inner:<structABC wrong id>}).has<&isStructAbc>('inner').valid()");
testOk1(result.errors.at(0) == Result::Error("inner", Result::Error::IncorrectId));
}
{
StructureConstPtr inner(FB->
setId("XYZ")->
add("A", pvInt)->
add("B", pvDouble)->
createStructure()
);
Result result(FB->add("inner", inner)->createStructure());
result.has<&isStructABC>("inner");
testOk(!result.valid(), "!Result({inner:<structABC wrong id and fields>}).has<&isStructAbc>('inner').valid()");
testOk1(result.errors.size() == 2);
}
}
MAIN(testValidator) {
testPlan(56);
FC = epics::pvData::getFieldCreate();
test_is();
test_is_id();
test_has();
test_maybe_has();
test_has_fn();
return testDone();
}