diff --git a/.hgignore b/.hgignore index edb9c72..721dbf6 100644 --- a/.hgignore +++ b/.hgignore @@ -1,11 +1,12 @@ -^QtC- -^bin/ -^lib/ -^doc/ -^include/ -^db/ -^dbd/ -^documentation/html +QtC- +bin/ +lib/ +doc/ +include/ +db/ +dbd/ +documentation/html +documentation/*.tag envPaths configure/.*\.local /O\..* diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md new file mode 100644 index 0000000..0e0311c --- /dev/null +++ b/documentation/RELEASE_NOTES.md @@ -0,0 +1,47 @@ +Release release/3.1 IN DEVELOPMENT +=========== + +The main changes since release 3.0.2 are: + +* array semantics now enforce Copy On Write. +* union is new type. +* copy is new. +* monitorPlugin is new. + +New Semantics for Arrays +-------- + +PVScalarArray, PVStructureArray, and PVUnionArray all enforce COW (Copy On Write) Semantics. +In order to limit memory usage the storage for raw data is managed via a new shared_vector facility. +This allows multiple instances of array data to use the shared raw data. +COW is implemented via shared_vectors of const data, i. e. data that can not be modified. + +union is a new basic type. +------------ + +There are two new basic types: union_t and unionArray. + +A union is like a structure that has a single subfield. +There are two flavors: + +* varient union The field can have any type. +* union The field can any of specified set of types. + +The field type can be dynamically changed. + +copy +---- + +This consists of createRequest and pvCopy. +createRequest was moved from pvAccess to here. +pvCopy is moved from pvDatabaseCPP and now depends +only on pvData, i. e. it no longer has any knowledge of PVRecord. + +monitorPlugin +------------- + +This is for is for use by code that implements pvAccess monitors. + +Release 3.0.2 +========== +This was the starting point for RELEASE_NOTES diff --git a/documentation/TODO.md b/documentation/TODO.md new file mode 100644 index 0000000..268a561 --- /dev/null +++ b/documentation/TODO.md @@ -0,0 +1,54 @@ +TODO +=========== + +toString, dumpValue, printer, and streams +------------ + +The way to print introspection and data instances is not consistent. +This needs work. +Some items that need work are: + +* Introspection has no support for streams. Only for toString. +* data has problems. toString is implemented by calling Convert::getString. +It look like this was intended to use printer but that did nor properly indent fields of structures. + +The current implementation is: + + void Convert::getString(StringBuilder buf,PVField const *pvField,int /*indentLevel*/) + { + // TODO indextLevel ignored + std::ostringstream strm; + strm << pvField->dumpValue(strm) << std::endl; + // PrinterPlain p; + // p.setStream(strm); + // p.print(*pvField); + strm.str().swap(*buf); + } + +Thus it just uses dumpValue. +What should it do? +If printer is used it must do proper indentation. + +doxygen +------- + +There is a lot of public code that does not have doxygen tags. + + +monitorPlugin +------------- + +A debate is on-going about what semantics should be. + +PVFieldConstPtr etc +------------------- + +In pvDataCPP.html look at the monoitorPlugin example. +It has a discussion of a possible need for shared pointers that can not be used to modify data. +This in addition to PVFieldPtr should PVFieldConstPtr exist. +But this means that all methods defined in pvDataCPP must be checked. +This is a BIG job. + +Release 3.0.2 +========== +This was the starting point for RELEASE_NOTES diff --git a/documentation/copyandmonitor.html b/documentation/copyandmonitor.html new file mode 100644 index 0000000..e4901a0 --- /dev/null +++ b/documentation/copyandmonitor.html @@ -0,0 +1,679 @@ + + + + + + EPICS pvDataCPP: copy and monitor + + + + + + + + + +
+

Table of Contents

+
+
+ +

support for copy and monitor

+

copy and monitor are not used in this project. +They are intended for use by pvAccess and by pvAccess servers. +They are provided with this project because the code depends only on +pvData itself. +

+

This document describes C++ specific code. + +pvRequest.html +provides a language independent overview of copy and monitor. +

+

+NOTE:pvRequest.html must be updated since it is based on an earlier version of pvCopy that +had knowlege of PVRecord. The C++ version was implemented in pvDatabaseCPP +and the Java version on pvIOCJava. +At present only the C++ version of the new API for pvCopy is implemented. +

+

Copy provides: +

+
createRequest
+
+ The Channel create methods in pvAccess all have an argument + PVStructure pvRequest.
+ Given an ascii string createRequest creates a PVStructure that provides + a pvData representation of the information from the ascii string. + It is this structure that can be passed to the channel create methods.
+ The information in a pvRequest selects an arbitrarary subset of the + fields in a top level structure that resides in the server. + In addition options can be specified. Both global and field specific + options can be specified. +
+
pvCopy
+
This is a faculity used by channel providers. + It provides client specific code that manages a copy of an arbitrary + subset of the fields in a top level structure that resides in the + provider. It also allows provider access to options specified + by the client. +
+
+Monitor provides: +
+
monitor
+
This is support code for channel providers that implement channel + monitor. It, together with the queue facility, provides support for + monitor queues. +
+
monitorPlugin
+
This is support for implementing monitor plugins. + A monitor plugin can be developed that has no knowledge + of pvAccess but only pvData. +
+
+

+ +

support for copy

+

copy provides the ability to create a structure that has +a copy of an arbitrary subset of the fields in an existing top level +structure. In addition it allows global options and field specific options. +It has two main components: createRequest and pvCopy. +Given a string createRequest creates a pvRequest, which is a PVStructure +that has the format expected by pvCopy. +

+ +

createRequest

+

This is mainly used by pvAccess clients. Given a request string it creates +a pvRequest structure that can be passed to the pvAccess create methods. +In turn pvAccess passes the pvRequest to a local channel provider which +then passes it to pvCopy. +

+

The definition of the public members is:

+
+class CreateRequest {
+...
+     static CreateRequestPtr create();
+     virtual PVStructurePtr createRequest(String const &request);
+     String getMessage();
+};
+
+

An example of how it is used is:

+
+CreateRequestPtr createRequest = CreateRequest::create();
+PVStructurePtr pvRequest = createRequest->createRequest(request);
+if(pvRequest==NULL) {
+    String error = createRequest->getMessage();
+    // take some action
+} else {
+    //success do something
+}
+
+

pvCopy

+

The definition of the public members is:

+
+class epicsShareClass PVCopyTraverseMasterCallback
+{
+...
+    virtual void nextMasterPVField(PVFieldPtr const &pvField);
+};
+
+class class epicsShareClass PVCopy
+{
+...
+    static PVCopyPtr create(
+        PVStructurePtr const &pvMaster,
+        PVStructurePtr const &pvRequest,
+        String const & structureName);
+    PVStructurePtr getPVMaster();
+    void traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback);
+    StructureConstPtr getStructure();
+    PVStructurePtr createPVStructure();
+    size_t getCopyOffset(PVFieldPtr const  &masterPVField);
+    size_t getCopyOffset(
+        PVStructurePtr const  &masterPVStructure,
+        PVFieldPtr const  &masterPVField);
+     PVFieldPtr getMasterPVField(std::size_t structureOffset);
+     void initCopy(
+        PVStructurePtr const  &copyPVStructure,
+        BitSetPtr const  &bitSet);
+     void updateCopySetBitSet(
+        PVStructurePtr const  &copyPVStructure,
+        BitSetPtr const  &bitSet);
+    void updateCopyFromBitSet(
+        PVStructurePtr const  &copyPVStructure,
+        BitSetPtr const  &bitSet);
+    void updateMaster(
+        PVStructurePtr const  &copyPVStructure,
+        BitSetPtr const  &bitSet);
+    PVStructurePtr getOptions(std::size_t fieldOffset);
+...
+};
+
+where +
+
PVCopyTraverseMasterCallback::nextMasterPVField
+
+ PVCopyTraverseMasterCallback is a callback which must + be implemented by the code that uses pvCopy, normally + the channel provider. It has the single method nextMasterPVField +
+ nextMasterPVField is called for each field in the master + as a result of a call to traverseMaster. +
+
create
+
+ This is the method for creating a PVCopy instance.
+
+
pvMaster
+
the top level sructure managed by the server.
+
pvRequest
+
selects the set of subfields desired + and options for each field.
+
structureName
+
the name for the top level of any PVStructure created. +
+
+
+
getPVMaster
+
+ Gets the top level structure from pvMaster. +
+
traverseMaster
+
+ Traverse all fields of the top level structure of pvMaster. + For each field the callback is called. +
+
getStructure
+
+ Get the introspection interface for a PVStructure for e copy. +
+
createPVStructure
+
Create a copy instance. + Monitors keep a queue of monitor elements. + Since each element needs a PVStructure, multiple top level structures + will be created. +
+
getCopyOffset
+
Given a field in pvMaster. + return the offset in copy for the same field. + A value of String::npos means that the copy does not have this field. + Two overloaded methods are provided. The first is called if + the field of master is not a structure. The second is for + subfields of a structure. +
+
getMasterPVField
+
+ Given a offset in the copy get the corresponding field in pvMaster. +
+
initCopy
+
+ Initialize the fields in copyPVStructure + by giving each field the value from the corresponding field in pvMaster. + bitSet will be set to show that all fields are changed. + This means that bit set will have the value {0}. +
+
updateCopySetBitSet
+
+ Set all fields in copyPVStructure to the value of the corresponding field + in pvMaster. Each field that is changed has it's corresponding + bit set in bitSet. +
+
updateCopyFromBitSet
+
+ For each set bit in bitSet set the field in copyPVStructure to the value + of the corrseponding field in pvMaster. +
+
updateMaster
+
+ For each set bit in bitSet set the field in pvMaster to the value + of the corrseponding field in copyPVStructure. + +
+
getOptions
+
+ Get the options for the field at the specified offset. + A NULL is returned if no options were specified for the field. + If options were specified,PVStructurePtr is + a structure with a set of PVString subfields that specify name,value + pairs. name is the subField name and value is the subField value. +
+
+ + + + +

support for monitor

+

This consists of two components: +

+
monitor
+
Used by code that implements pvAccess montors.
+
monitorPlugin
+
Code that provides special semantics for monitors.
+
+

+

monitor

+
+class MonitorElement {
+    MonitorElement(PVStructurePtr const & pvStructurePtr);
+    PVStructurePtr pvStructurePtr;
+    BitSetPtr changedBitSet;
+    BitSetPtr overrunBitSet;
+};
+
+class Monitor {
+    virtual Status start() = 0;
+    virtual Status stop() = 0;
+    virtual MonitorElementPtr poll() = 0;
+    virtual void release(MonitorElementPtr const & monitorElement) = 0;
+};
+
+class MonitorRequester : public virtual Requester {
+    virtual void monitorConnect(Status const & status,
+        MonitorPtr const & monitor, StructureConstPtr const & structure) = 0;
+    virtual void monitorEvent(MonitorPtr const & monitor) = 0;
+    virtual void unlisten(MonitorPtr const & monitor) = 0;
+};
+
+

monitorElement

+

MonitorElement holds the data for one element of a monitor queue. +It has the fields: +

+
pvStructurePtr
+
A top level structure with data values at the time the monitors occurs.
+
changedBitSet
+
Shows which fields have changed since the previous monitor.
+
overrunBitSet
+
Shows which fields have changed more han once since the previous monitor.
+
+

+

monitorElement queue

+

+A queue of monitor elements must be implemented by any channel provider that implements +Channel::createMonitor. +For an example implementation look at pvDatabaseCPP. +It has the following: +

+typedef Queue<MonitorElement> MonitorElementQueue;
+typedef std::tr1::shared_ptr<MonitorElementQueue> MonitorElementQueuePtr;
+
+class MultipleElementQueue :
+    public ElementQueue
+{
+public:
+    POINTER_DEFINITIONS(MultipleElementQueue);
+    virtual ~MultipleElementQueue(){}
+    MultipleElementQueue(
+        MonitorLocalPtr const &monitorLocal,
+        MonitorElementQueuePtr const &queue,
+        size_t nfields);
+    virtual void destroy(){}
+    virtual Status start();
+    virtual Status stop();
+    virtual bool dataChanged();
+    virtual MonitorElementPtr poll();
+    virtual void release(MonitorElementPtr const &monitorElement);
+...
+};
+
+

Monitor

+

Monitor must be implemented by any channel provider that implements +Channel::createMonitor. +Remote PVAccess also implements Monitor on the client side. +Note that each client has it's own queue that is not shared with other client. +

+

Monitor has the following methods:

+
+
start
+
+ Start monitoring. + This will result in a an inital monitor that has the current value + of all fields. +
+
stop
+
+ Stop monitoring. +
+
poll
+
+ Called to get a monitor element. + If no new elemants are available then a null pointer is returned. +
+
release
+
+ Release the monotor element. + The caller owns the monitor element between the calls to poll and release. +
+
+
+

MonitorRequester

+

This must be implemented by a pvAccess client. +It has the methods:

+
+
monitorConnect
+
+ A monitor has either connected of disconnected. +
+
monitorEvent
+
+ A new monitor element is available. +
+
unlisten
+
+ The channel is going away. The client cam no longer access the monitor. +
+
+ +

monitorPlugin

+
+class MonitorPlugin
+{
+    virtual String const & getName() = 0;
+    virtual bool causeMonitor(
+        PVFieldPtr const &pvField,
+        PVStructurePtr const &pvTop,
+        MonitorElementPtr const &monitorElement) = 0;
+    virtual void monitorDone(
+        MonitorElementPtr const &monitorElement);
+    virtual void startMonitoring();
+    virtual void stopMonitoring();
+    virtual void beginGroupPut();
+    virtual void endGroupPut();
+};
+
+class MonitorPluginCreator
+{
+    virtual MonitorPluginPtr create(
+        FieldConstPtr const &field,
+        StructureConstPtr const &top,
+        PVStructurePtr const &pvFieldOptions) = 0;
+     virtual String const & getName() = 0;
+}
+
+class MonitorPluginManager
+{
+    static MonitorPluginManagerPtr get();
+    bool addPlugin(
+         String const &pluginName,
+         MonitorPluginCreatorPtr const &creator);
+    MonitorPluginCreatorPtr findPlugin(String const &pluginName);
+    void showNames();
+};
+
+
+

MonitorPlugin

+

MonitorPlugin must be implemented by the plugin implementation. +It has methods:

+
+
getName
+
Get the name of the plugin.
+
causeMonitor
+
+ Should the value of pvField cause a monitor to be raised. + pvField and pvTop are fields in the top level structure + being monitored. monitorElement has the top level structure + for the copy. + The implementation should not modify the fields in the structure + being monitored. + Called with pvTop locked. +
+
monitorDone
+
+ Called just before monitorElement will be given to client. + The plugin can change the data values and bitSets in monitorElement. + Called with pvTop unlocked. +
+
startMonitoring
+
+ Monitoring is starting. +
+
stopMonitoring
+
+ Monitoring is being stopped. +
+
beginGroupPut
+
+ A set of puts is starting. + Called with pvTop locked. +
+
endGroupPut
+
+ The set of puts is complete. + Called with pvTop locked. +
+
+

MonitorPluginCreator

+

MonitorPluginCreator must also be implemented by the plugin implementation. +It is called for each field instance that has options of the from +[plugin=name...] where name is the name of the plugin. +Note that a plugin instance will belong to a single client. +It has methods:

+
+
getName
+
Get the name of the plugin.
+
create
+
+ Create a new plugin instance. + If the arguments are not compatible with the plugin a NULL shared pointer is + returned.
+ pvFieldOptions is + a structure with a set of PVString subfields that specify name,value + pairs. name is the subField name and value is the subField value.
+ Note that a plugin will below to a single client. +
+
+

MonitorPluginManager

+

MonitorPluginManager has the methods:

+
+
get
+
+ MonitorPluginManager is a singleton. + The first call to get will create the single instance. + Further calls will rerurn the single instance. +
+
addPlugin
+
+ Add a new plugin. +
+
findPlugin
+
+ Find a plugin. A NULL shared pointer is reurned if it has not been added. +
+
showNames
+
+ Show the names of all puugins that have been added. +
+
+

NOTE: +Should the method causeMonitor +have arguments pvField and pvTop +be defined so that they can not be modfied. +This would be posssible if the following was defined: +

+typedef std::tr1::shared_ptr<const PVField> PVFieldConstPtr;
+typedef std::tr1::shared_ptr<const PVStructure> PVStructureConstPtr;
+
+then the definition for causeMonitor could be: +
+virtual bool causeMonitor(
+        PVFieldConstPtr const &pvField,
+        PVStructureConstPtr const &pvTop,
+        MonitorElementPtr const &monitorElement) = 0;
+
+But just adding these definitions is not sufficent. +In addition all methods defined in pvDataCPP must be checked. +In particular many of the methods in Convert must have +their arguments modified. +Big job. +

+

monitorPlugin example

+

Example Plugin Overview

+

This section describes an example plugin that:

+
    +
  • Only raises monitors when a field changes value.
    + If no plugin is provided + the default is to raise a monitor when a put is issued to a field.
  • +
  • Optionally a change will not raise a monitor.
    + The change will, however, + appear if a put to another field raise a monitor.
  • +
+

As an example assume that a channel provided by pvAccess has a top level structure +that represents a power supply.

+
+structure powerSupply
+    structure alarm
+    structure timeStamp
+    structure power
+       double value
+       structure alarm
+       struvture display
+    structure voltage
+       double value
+       structure alarm
+       struvture display
+    structure current
+       double value
+       structure alarm
+       struvture display
+
+

A pvAccess client wants to create a monitor on the powerSupply as follows: +The client wants a top level structure that looks like: +

+structure powerSupply
+    structure alarm
+    structure timeStamp
+    structure power
+       double value
+    structure voltage
+       double value
+    structure current
+       double value
+
+In addition the client wants monitors to occur only when one of the monitored +fields changes value but not just because a put occured. +Also if only the timeStamp changes value then that should not cause a monitor. +

+

The example monitor plugin implements the semantics the +client wants. It can be attached to any field via the following options: +

+[plugin=onChange,raiseMonitor=value]
+
+This plugin will trigger a monitor for the field only if the field changes +value. In addition value equals false means do not raise a monotor +for changes to this field. +But if a change to another field does cause a monitor the change to this field +will be passed to the client. +

+

+Assume that the client has already connected to the channel. +The client can then issue the commands:

+
+String request("field(alarm[plugin=onChange]");
+request += ",timeStamp[plugin=onChange,raiseMonitor=false]";
+request += ",power.value[plugin=onChange";
+request += ",voltage.value[plugin=onChange";
+request += ",current.value[plugin=onChange";
+
+PVStructurePtr pvRequest = createRequest->createRequest(request);
+
+MonitorPtr monitor = channel->createMonitor(monitorRequester,pvRequest);
+
+

Example Plugin Code

+

The header file to create the example has the definition:

+
+class ExampleMonitorPlugin{
+public:
+    static void create();
+};
+
+

The implementation is:

+
+class OnChangePlugin : public MonitorPlugin
+{
+public:
+    virtual ~OnChangePlugin(){}
+    OnChangePlugin() {}
+    bool init(
+        FieldConstPtr const &field,
+        StructureConstPtr const &top,
+        PVStructurePtr const &pvFieldOptions)
+   {
+        pvField = getPVDataCreate()->createPVField(field);
+        raiseMonitor = true;
+        if(pvFieldOptions!=NULL) {
+            PVStringPtr pvString =
+                pvFieldOptions->getSubField<PVString>("raiseMonitor");
+                if(pvString!=NULL) {
+                    String value = pvString->get();
+                    if(value.compare("false")==0) raiseMonitor = false;
+                }
+        }
+        return true;
+   }
+   virtual String &getName(){return pluginName;}
+   virtual bool causeMonitor(
+        PVFieldPtr const &pvNew,
+        PVStructurePtr const &pvTop,
+        MonitorElementPtr const &monitorElement)
+   {
+       bool isSame = convert->equals(pvNew,pvField);
+       if(isSame) return false;
+       convert->copy(pvNew,pvField);
+       return raiseMonitor;
+   }
+private:
+   PVFieldPtr pvField;
+   bool raiseMonitor;
+};
+class OnChangePluginCreator : public MonitorPluginCreator
+{
+public:
+    virtual String &getName(){return pluginName;}
+    virtual MonitorPluginPtr create(
+        FieldConstPtr const &field,
+        StructureConstPtr const &top,
+        PVStructurePtr const &pvFieldOptions)
+   {
+       OnChangePluginPtr plugin(new OnChangePlugin());
+       bool result = plugin->init(field,top,pvFieldOptions);
+       if(!result) return MonitorPluginPtr();
+       return plugin;
+   }
+
+};
+
+void ExampleMonitorPlugin::create()
+{
+    static OnChangePluginCreatorPtr plugin;
+    static Mutex mutex;
+    Lock xx(mutex);
+    if(plugin==NULL) {
+        plugin = OnChangePluginCreatorPtr(new OnChangePluginCreator());
+        MonitorPluginManager::get()->addPlugin(pluginName,plugin);
+    }
+}
+
+ + +
+ + diff --git a/documentation/examples.zip b/documentation/examples.zip new file mode 100644 index 0000000..7689363 Binary files /dev/null and b/documentation/examples.zip differ diff --git a/documentation/pvDataCPP.html b/documentation/pvDataCPP.html index d352187..8323e2a 100644 --- a/documentation/pvDataCPP.html +++ b/documentation/pvDataCPP.html @@ -37,7 +37,7 @@

EPICS pvDataCPP

-

EPICS v4 Working Group, Working Draft, 28-Oct-2013

+

EPICS v4 Working Group, Working Draft, 01-May-2014

Latest version:
@@ -46,11 +46,11 @@
This version:
pvDataCPP_20131023.html + href="pvDataCPP_20140501.html">pvDataCPP_20140501.html
Previous version:
pvDataCPP_20130516.html + href="pvDataCPP_20131023.html">pvDataCPP_20131023.html
Editors:
Marty Kraimer, BNL
@@ -66,8 +66,9 @@ license.

Abstract

-

PVData is a computer software package for the efficient -storage, access, and communication, of structured data. +

EPICS Version 4 provides efficient +storage, access, and communication, of memory resident structured data. +pvData is the storage compoment. pvDataCPP is the C++ implementation of pvData. It is one part of the set of related products in the EPICS V4 control system programming environment:
@@ -77,22 +78,13 @@ V4 control system programming environment:

Status of this Document

-

This is the 28-Oct-2013 version of the C++ implementation of pvData. -This version describes the changes since the 4.3.0 release of Epics Version 4. +

This is the 01-May-2014 version of the C++ implementation of pvData.

-

The text describes software which is a complete implementation of pvData as -currently planned by the EPICS V4 Working Group.

+

RELEASE_NOTES.md provides changes since the last release. +TODO.md describes things to do before the next release. +

-

The major changes since the 4.3.0 release are:

-
-
shared_vector
-
This provides many of the features of std:vector but uses std::shared_ptr - for the raw array.
-
Arrays
-

The implementation of PVValueArray and PVStructureArray now inforce Copy On Write (COW) - and use shared_vector for the raw array.

-

Table of Contents

@@ -101,7 +93,7 @@ currently planned by the EPICS V4 Working Group.

Introduction

-

pvData is one of a set of related projects. It describes and implements the +

pvData is one of a set of related projects. It describes and implements data that the other projects support. Thus it is not useful by itself but understanding pvData is required in order to understand the other projects. The reader should also become familar with project pvAccess, which is @@ -110,8 +102,8 @@ located via the same sourceforge site as this project.

The Java and C++ implementation of pvData implement the same data model but differ in implementation because of the differences between Java and C++.

-

It is a good idea to read all of pvDataJava.html but read at least the -first two chapters:

+

It is a good idea to read all of pvDataJava.html but read at least the +first two chapters:

Introduction
A brief descripton of pvData.
@@ -123,6 +115,663 @@ first two chapters:

Doxygen documentation is available at doxygenDoc

+

The next section provides some examples of creating and accessing data. +

+

This document discusses the following:

+
+
pvDataAPP/pv
+
This subdirectory contains all the public interfaces that describe pvData. + The section from Namespace and Memory Management + through Conversion discuss these interfaces. +
+
pvDataApp/property
+
This section has support for managing "standard" fields. +
+
pvDataApp/misc
+
This section has support for facilities required by implementation code.
+
copy and monitor
+
These sections provide pvData support for implementing pvAccess providers.
+
+ +

Examples

+

This section provides some examples of creating and accessing both introspection and +data interfaces. The first time reader may not understand them but hopefully will get an +idea of how pvData works. After reading the rest of this document the examples will +be much easier to understand. +

+

The documentation directory for this project has a file examples.zip. +It has the code for the examples. +After it is unzipped just edit configure/RELEASE.local and then execute make. +

+

The examples assume that the following statements have been issued:

+
+String builder;
+FieldCreatePtr fieldCreate = getFieldCreate();
+PVDataCreatePtr pvDataCreate = getPVDataCreate();
+StandardFieldPtr standardField = getStandardField();
+StandardPVFieldPtr standardPVField = getStandardPVField();
+StructureConstPtr alarm = getStandardField()->alarm();
+StructureConstPtr timeStamp = getStandardField()->timeStamp();
+
+

These provide access to most of pvData:

+
+
fieldCreate
+
This creates instances of introspection objects. + It also provides fieldBuilder, which provides an easier way to create introspection objects. +
+
pvDataCreate
+
This creates instances of data objects. +
+
standardField
+
This provides support for introspection obects for standard fields, + Standard fields are alarm, timeStamp, display, enumerated structure, and value alarm. +
+
standardPVField
+
This provides support for data obects for standard fields, +
+
+ + +

Introspection Examples

+

The examples all produce a top level structure. +The reason is that top level structures are what pvAccess passes between client and server +and what pvDatabaseCPP supports.

+

Three ways to create a structure

+

The following is the hardest way to create structure that has a double value field and a time stamp field: +It uses only createField. +

+
+    size_t n = 3;
+    StringArray names;
+    names.reserve(n);
+    FieldConstPtrArray fields;
+    fields.reserve(n);
+    names.push_back("secsPastEpoch");
+    fields.push_back(fieldCreate->createScalar(pvLong));
+    names.push_back("nanoseconds");
+    fields.push_back(fieldCreate->createScalar(pvInt));
+    names.push_back("userTag");
+    fields.push_back(fieldCreate->createScalar(pvInt));
+    StructureConstPtr timeStamp = fieldCreate->createStructure(names,fields);
+    size_t ntop = 2;
+    StringArray topnames;
+    topnames.reserve(ntop);
+    FieldConstPtrArray topfields;
+    topfields.reserve(ntop);
+    topnames.push_back("value");
+    topfields.push_back(fieldCreate->createScalar(pvDouble));
+    topnames.push_back("timeStamp");
+    topfields.push_back(timeStamp);
+    StructureConstPtr doubleScalar = fieldCreate->createStructure(topnames,topfields);
+    builder.clear();
+    doubleScalar->toString(&builder);
+    cout << builder << "\n\n";
+
+

Using FieldBuilder the same can be done via:

+
+    StructureConstPtr doubleScalarHard =
+    getFieldCreate()->createFieldBuilder()->
+        add("value",pvDouble) ->
+        addNestedStructure("timeStamp")->
+            setId("time_t")->
+            add("secsPastEpoch", pvLong)->
+            add("nanoseconds", pvInt)->
+            add("userTag", pvInt)->
+            endNested()->
+        createStructure();
+    builder.clear();
+    doubleScalarHard->toString(&builder);
+    cout << builder << endl;
+
+Both produce: +
+structure
+    double value
+    time_t timeStamp
+        long secsPastEpoch
+        int nanoseconds
+
+

An easy way to create a structure with a string array value field and an alarm and time stamp is +via standardField:

+
+    StructureConstPtr stringArrayEasy =
+        getStandardField()->scalarArray(pvString,"alarm,timeStamp");
+    builder.clear();
+    stringArrayEasy->toString(&builder);
+    cout << builder << endl;
+
+It produces : +
+uri:ev4:nt/2012/pwd:NTScalarArray
+    string[] value
+    alarm_t alarm
+        int severity
+        int status
+        string message
+    time_t timeStamp
+        long secondsPastEpoch
+        int nanoSeconds
+        int userTag
+
+

enumerated structure

+

An enumerated structure is a structure with two sub-fields: +index, which is an int, and choices, which is an array of string. +The following examples create a structure which has a field names value, which +is an enumerated structure and additional fields. +A hard way to create an structure with an enumerated value field and a time stamp is:

+
+    StructureConstPtr enum_t =
+    getFieldCreate()->createFieldBuilder()->
+        setId("enum_t")->
+        add("index", pvInt)->
+        addArray("choices", pvString)->
+        createStructure();
+
+    StructureConstPtr ntEnumHard =
+    getFieldCreate()->createFieldBuilder()->
+        setId("uri:ev4:nt/2012/pwd/NTEnum")->
+        add("value", enum_t)->
+        addNestedStructure("timeStamp")->
+            setId("time_t")->
+            add("secsPastEpoch", pvLong)->
+            add("nanoseconds", pvInt)->
+            add("userTag", pvInt)->
+            endNested()->
+        createStructure();
+    builder.clear();
+    ntEnumHard->toString(&builder);
+    cout << builder << endl;
+
+It produces: +
+uri:ev4:nt/2012/pwd/NTEnum
+    enum_t value
+        int index
+        string[] choices
+    time_t timeStamp
+        long secsPastEpoch
+        int nanoseconds
+        int userTag
+
+

The following is an easy way. Note that it has two additional +fields: alarm and timeStamp:

+
+    StructureConstPtr ntEnumEasy = getStandardField()->enumerated("alarm,timeStamp");
+    builder.clear();
+    ntEnumEasy->toString(&builder);
+    cout << builder << endl;
+
+It produces: +
+uri:ev4:nt/2012/pwd:NTEnum
+    enum_t value
+        int index
+        string[] choices
+    alarm_t alarm
+        int severity
+        int status
+        string message
+    time_t timeStamp
+        long secondsPastEpoch
+        int nanoSeconds
+        int userTag
+
+ +

union example

+

The following creates a union and a structure with a union value field:

+ +
+    UnionConstPtr ntunion =
+    getFieldCreate()->createFieldBuilder()->
+        add("doubleValue", pvDouble)->
+        add("intValue", pvInt)->
+        add("timeStamp",timeStamp)->
+        createUnion();
+    builder.clear();
+    ntunion->toString(&builder);
+    cout << builder << endl;
+
+    StructureConstPtr unionValue = getStandardField()->regUnion(punion,"alarm,timeStamp");
+    builder.clear();
+    ntunion->toString(&builder);
+    cout << builder << endl;
+
+It produces: +
+union
+    double doubleValue
+    int intValue
+    time_t timeStamp
+        long secondsPastEpoch
+        int nanoSeconds
+        int userTag
+
+structure with value field being a union
+uri:ev4:nt/2012/pwd:NTUnion
+    union value
+        double doubleValue
+        int intValue
+        time_t timeStamp
+            long secondsPastEpoch
+            int nanoSeconds
+            int userTag
+    alarm_t alarm
+        int severity
+        int status
+        string message
+    time_t timeStamp
+        long secondsPastEpoch
+        int nanoSeconds
+        int userTag
+
+

power supply

+

The following creates a more complex structure:

+
+    StructureConstPtr powerSupply =
+    getFieldCreate()->createFieldBuilder()->
+        add("alarm_t",alarm) ->
+        add("timestamp_t",timeStamp) ->
+        addNestedStructure("power") ->
+           add("value",pvDouble) ->
+           add("alarm",alarm) ->
+           endNested()->
+        addNestedStructure("voltage") ->
+           add("value",pvDouble) ->
+           add("alarm",alarm) ->
+           endNested()->
+        addNestedStructure("current") ->
+           add("value",pvDouble) ->
+           add("alarm",alarm) ->
+           endNested()->
+        createStructure();
+    builder.clear();
+    powerSupply->toString(&builder);
+    cout << builder << endl;
+
+It produces: +
+structure
+    alarm_t alarm_t
+        int severity
+        int status
+        string message
+    time_t timestamp_t
+        long secondsPastEpoch
+        int nanoSeconds
+        int userTag
+    structure power
+        double value
+        alarm_t alarm
+            int severity
+            int status
+            string message
+    structure voltage
+        double value
+        alarm_t alarm
+            int severity
+            int status
+            string message
+    structure current
+        double value
+        alarm_t alarm
+            int severity
+            int status
+            string message
+
+

Data Examples

+

The examples all produce a top level structure.

+

scalar example

+
+    PVStructurePtr doubleValue = getPVDataCreate()->createPVStructure(
+        getStandardField()->scalar(pvDouble,"alarm,timeStamp"));
+    PVDoublePtr pvdouble =
+        doubleValue->getSubField<PVDouble>("value");
+    pvdouble->put(1e5);
+    cout << doubleValue->dumpValue(cout) << endl;
+
+This produces: +
+uri:ev4:nt/2012/pwd:NTScalar 
+    double value 100000
+    alarm_t alarm
+        int severity 0
+        int status 0
+        string message 
+    time_t timeStamp
+        long secondsPastEpoch 0
+        int nanoSeconds 0
+        int userTag 0
+0x607268
+
+

array example

+
+    PVStructurePtr doubleArrayValue = getPVDataCreate()->createPVStructure(
+        getStandardField()->scalarArray(pvDouble,"alarm,timeStamp"));
+    PVDoubleArrayPtr pvDoubleArray =s
+         doubleArrayValue->getSubField<PVDoubleArray>("value");
+    size_t len = 10;
+    shared_vector<double> xxx(len);
+    for(size_t i=0; i< len; ++i) xxx[i] = i;
+    shared_vector<const double> data(freeze(xxx));
+    pvDoubleArray->replace(data);
+    cout << doubleArrayValue->dumpValue(cout) << endl;
+    
+    shared_vector<const double>  getData = pvDoubleArray->view();
+    cout << "via getData";
+    for (size_t i=0; i< len; ++i) cout << " " << getData[i];
+    cout << endl;
+
+This produces: +
+uri:ev4:nt/2012/pwd:NTScalarArray 
+    double[] value [0,1,2,3,4,5,6,7,8,9]
+    alarm_t alarm
+        int severity 0
+        int status 0
+        string message 
+    time_t timeStamp
+        long secondsPastEpoch 0
+        int nanoSeconds 0
+        int userTag 0
+0x607268
+via getData 0 1 2 3 4 5 6 7 8 9
+
+

enumerated example

+
+    PVStructurePtr pvntenum = getPVDataCreate()->createPVStructure(
+         getStandardField()->enumerated("alarm,timeStamp"));
+    cout << pvntenum->dumpValue(cout) << "\n\n";
+
+This produces: +
+uri:ev4:nt/2012/pwd:NTEnum 
+    enum_t value
+        int index 0
+        string[] choices []
+    alarm_t alarm
+        int severity 0
+        int status 0
+        string message 
+    time_t timeStamp
+        long secondsPastEpoch 0
+        int nanoSeconds 0
+        int userTag 0
+0x607268
+
+

power supply example

+
+    StructureConstPtr powerSupply =
+    getFieldCreate()->createFieldBuilder()->
+        add("alarm_t",alarm) ->
+        add("timestamp_t",timeStamp) ->
+        addNestedStructure("power") ->
+           add("value",pvDouble) ->
+           add("alarm",alarm) ->
+           endNested()->
+        addNestedStructure("voltage") ->
+           add("value",pvDouble) ->
+           add("alarm",alarm) ->
+           endNested()->
+        addNestedStructure("current") ->
+           add("value",pvDouble) ->
+           add("alarm",alarm) ->
+           endNested()->
+        createStructure();
+    PVStructurePtr pvpowerSupply = getPVDataCreate()->createPVStructure(powerSupply);
+    cout << pvpowerSupply->dumpValue(cout) << endl;
+
+This produces: +
+structure 
+    alarm_t alarm_t
+        int severity 0
+        int status 0
+        string message 
+    time_t timestamp_t
+        long secondsPastEpoch 0
+        int nanoSeconds 0
+        int userTag 0
+    structure power
+        double value 0
+        alarm_t alarm
+            int severity 0
+            int status 0
+            string message 
+    structure voltage
+        double value 0
+        alarm_t alarm
+            int severity 0
+            int status 0
+            string message 
+    structure current
+        double value 0
+        alarm_t alarm
+            int severity 0
+            int status 0
+            string message 
+0x607268
+
+

union example

+
+    PVStructurePtr pvStructure = pvDataCreate->createPVStructure(
+        standardField->regUnion(
+            getFieldCreate()->createFieldBuilder()->
+                add("doubleValue", pvDouble)->
+                add("intValue", pvInt)->
+                add("timeStamp",timeStamp)->
+                createUnion(),
+            "alarm,timeStamp"));
+    PVStructurePtr pvTimeStamp =
+        pvStructure->getSubField<PVUnion>("value")->select<PVStructure>(2);
+    pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000);
+    cout << pvStructure->dumpValue(cout) << "\n";
+    pvStructure->getSubField<PVUnion>("value")->select<PVDouble>(0)->put(1e5);
+    cout << pvStructure->dumpValue(cout) << "\n\n";
+
+This produces: +
+uri:ev4:nt/2012/pwd:NTUnion
+    union value
+        time_t
+            long secondsPastEpoch 1000
+            int nanoSeconds 0
+            int userTag 0
+    alarm_t alarm
+        int severity 0
+        int status 0
+        string message
+    time_t timeStamp
+        long secondsPastEpoch 0
+        int nanoSeconds 0
+        int userTag 0
+0x60a2c8
+uri:ev4:nt/2012/pwd:NTUnion
+    union value
+        double  100000
+    alarm_t alarm
+        int severity 0
+        int status 0
+        string message
+    time_t timeStamp
+        long secondsPastEpoch 0
+        int nanoSeconds 0
+        int userTag 0
+0x60a2c8
+
+ +

varient union example

+
+    PVStructurePtr pvStructure = pvDataCreate->createPVStructure(
+        standardField->variantUnion("alarm,timeStamp"));
+    PVStructurePtr pvTimeStamp =
+        pvDataCreate->createPVStructure(standardField->timeStamp());
+    pvStructure->getSubField<PVUnion>("value")->set(pvTimeStamp);
+    pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000);
+    cout << pvStructure->dumpValue(cout) << "\n";
+    pvStructure->getSubField<PVUnion>("value")->set(
+        pvDataCreate->createPVScalar(pvDouble));
+    PVDoublePtr pvValue = static_pointer_cast<PVDouble>(
+        pvStructure->getSubField<PVUnion>("value")->get());
+    pvValue->put(1e5);
+    cout << pvStructure->dumpValue(cout) << "\n\n";
+
+This produces: +
+uri:ev4:nt/2012/pwd:NTUnion
+    any value
+        time_t
+            long secondsPastEpoch 1000
+            int nanoSeconds 0
+            int userTag 0
+    alarm_t alarm
+        int severity 0
+        int status 0
+        string message
+    time_t timeStamp
+        long secondsPastEpoch 0
+        int nanoSeconds 0
+        int userTag 0
+0x60a2c8
+uri:ev4:nt/2012/pwd:NTUnion
+    any value
+        double  100000
+    alarm_t alarm
+        int severity 0
+        int status 0
+        string message
+    time_t timeStamp
+        long secondsPastEpoch 0
+        int nanoSeconds 0
+        int userTag 0
+0x60a2c8
+
+ +

big union example

+
+    PVStructurePtr pvStructure = pvDataCreate->createPVStructure(
+        standardField->regUnion(
+            getFieldCreate()->createFieldBuilder()->
+                add("doubleValue", pvDouble)->
+                addArray("doubleArrayValue",pvDouble)->
+                addNestedUnion("unionValue") ->
+                    add("doubleValue", pvDouble)->
+                    add("alarm",standardField->alarm()) ->
+                    endNested() ->
+                addNestedStructure("structValue") ->
+                    add("doubleValue", pvDouble)->
+                    addArray("doubleArrayValue",pvDouble)->
+                    endNested() ->
+                addNestedUnionArray("unionArrayValue") ->
+                    add("doubleValue", pvDouble)->
+                    add("alarm",standardField->alarm()) ->
+                    endNested() ->
+                addNestedStructureArray("structArrayValue") ->
+                    add("doubleValue", pvDouble)->
+                    addArray("doubleArrayValue",pvDouble)->
+                    endNested() ->
+                createUnion(),
+            "alarm,timeStamp"));
+    builder.clear();
+    pvStructure->getStructure()->toString(&builder);
+    cout << "introspection\n";
+    cout << builder << endl;
+    cout << "data\n";
+    cout << pvStructure->dumpValue(cout) << "\n";
+    PVUnionPtr pvUnion = pvStructure->getSubField<PVUnion>("value");;
+    pvUnion->select("doubleValue");
+    PVDoublePtr pvDouble = pvUnion->get<PVDouble>();
+    pvDouble->put(1.55);
+    cout << "select valueDouble\n";
+    cout << pvStructure->dumpValue(cout) << "\n";
+    cout << "value = " << pvDouble->get() << "\n";
+    pvUnion->select("structValue");
+    pvDouble = pvUnion->get<PVStructure>()->getSubField<PVDouble>("doubleValue");
+    pvDouble->put(1.65);
+    cout << "select structValue\n";
+    cout << pvStructure->dumpValue(cout) << "\n";
+    cout << "value = " << pvDouble->get() << "\n";
+
+This produces: +
+introspection
+uri:ev4:nt/2012/pwd:NTUnion
+    union value
+        double doubleValue
+        double[] doubleArrayValue
+        union unionValue
+            double doubleValue
+            alarm_t alarm
+                int severity
+                int status
+                string message
+        structure structValue
+            double doubleValue
+            double[] doubleArrayValue
+        union[] unionArrayValue
+            union[]
+                union
+                    double doubleValue
+                    alarm_t alarm
+                        int severity
+                        int status
+                        string message
+        structure[] structArrayValue
+            structure[]
+                structure
+                    double doubleValue
+                    double[] doubleArrayValue
+    alarm_t alarm
+        int severity
+        int status
+        string message
+    time_t timeStamp
+        long secondsPastEpoch
+        int nanoSeconds
+        int userTag
+data
+uri:ev4:nt/2012/pwd:NTUnion
+    union value
+        (none)
+    alarm_t alarm
+        int severity 0
+        int status 0
+        string message
+    time_t timeStamp
+        long secondsPastEpoch 0
+        int nanoSeconds 0
+        int userTag 0
+0x60a2c8
+select valueDouble
+uri:ev4:nt/2012/pwd:NTUnion
+    union value
+        double  1.55
+    alarm_t alarm
+        int severity 0
+        int status 0
+        string message
+    time_t timeStamp
+        long secondsPastEpoch 0
+        int nanoSeconds 0
+        int userTag 0
+0x60a2c8
+value = 1.55
+select structValue
+uri:ev4:nt/2012/pwd:NTUnion
+    union value
+        structure
+            double doubleValue 1.65
+            double[] doubleArrayValue []
+    alarm_t alarm
+        int severity 0
+        int status 0
+        string message
+    time_t timeStamp
+        long secondsPastEpoch 0
+        int nanoSeconds 0
+        int userTag 0
+0x60a2c8
+value = 1.65
+

Namespace and Memory Management

@@ -135,50 +784,23 @@ href="./html/index.html">doxygenDoc

Memory Managemment

-

pvDataCPP introspection and data objects are designed to be shared. They are -made availiable via std::tr1::shared_ptr. In addition arrays are -implemented via shared_vector. The following naming conventions are used +

Many pvDataCPP introspection and data objects are designed to be shared. They are +made availiable via std::tr1::shared_ptr. +The following naming convention is used in typedefs:

Ptr
-
When Ptr appears it stands for std::tr1::shared_ptr.
-
Array
-
When Array appears it stands for std::vector.
-
- -

As an example pvType.h includes the following definitions:

-
typedef std::vector<double> DoubleArray;
-typedef std::tr1::shared_ptr<DoubleArray> DoubleArrayPtr;
-inline double * get(DoubleArray &value)
-{
-    return &value[0];
-}
-inline const double * get(const DoubleArray &value)
-{
-    return static_cast<const double *>(&value[0]);
-}
-typedef std::vector<double>::iterator DoubleArray_iterator;
-typedef std::vector<double>::const_iterator DoubleArray_const_iterator;
- -

where

-
-
DoubleArray
-
This defines a vector for an array of the primitive type "double".
-
DoubleArrayPtr
-
This devices a shared pointer to a vector for an array of the primitive - type "double".
-
get
-
This gets the raw array of doubles that the DoubleArray holds.
-
DoubleArray_iterator
-
This gets a iterator for the DoubleArray.
-
DoubleArray_const_iterator
-
This gets a constant iterator for the DoubleArray.
+
When Ptr appears it stands for std::tr1::shared_ptr. +
+

For example:

+
+typedef PVScalarValue<boolean> PVBoolean;
+typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
+

pvDataApp/pv

-

Overview

-

Directory pvDataApp/pv has header files that completely describe pvData. The implementation is provided in directory pvDataApp/factory. Test programs appears in testApp/pv.

@@ -186,9 +808,9 @@ Test programs appears in testApp/pv.

NOTES:

interface
-
The documention uses the word interface. This is an analogy for - what the Java implementation implements, i. e. package pv provides Java - interfaces. C++ does not have interfaces but directory pv defines classes +
The documention uses the word interface. + This is an analogy with how Java defines interface. + C++ does not have interfaces but directory pv defines classes with public members that are similar to the Java interfaces. Most of the implementation is in factory.
Naming Convertions
@@ -200,7 +822,7 @@ Test programs appears in testApp/pv.

A PVStructure is a field that contains an array of subfields. Each field has code for accessing the field. The interface for each field is an interface that extends PVField. Each field also has an introspection interface, which an -extension of Field. This section describes the complete set of C++ +extension of Field. The next few sections describes the complete set of C++ introspection and data interfaces for pvData.

Class FieldCreate creates introspection objects. Class PVDataCreate creates @@ -217,15 +839,22 @@ copying data between fields.

A complete description of the data interfaces.
convert.h
A facility that converts between data fields.
+
pvSubArrayCopy.h
+
This provides a facility that performs array coping between + arrays that have the same type.
standardField.h
Provides access to introspection interfaces for standard structures like timeStamp, alarm, etc.
standardPVField.h
Cteates data interfaces for standard data structures like timeStamp, alarm, etc.
+
printer.h
+
TBD This is not documented. + In addition toString and dumpValue should be reviewed. +
-

pvType.h

+

pvType.h

This provides C/C++ definitions for the pvData primitive types: boolean, byte, short, int, long, ubyte,ushort, uint,u long,float, double, and string. @@ -234,11 +863,9 @@ proper semantics for the primitive types.

pvType.h provides the proper semantics.

-

It has the definitions:

+

It includes the definitions:

-typedef detail::pick_type<int8_t, signed char,
-     detail::pick_type<uint8_t, char, unsigned char>::type
-     >::type boolean;
+typedef /*lots of stuff*/ boolean
 
 typedef int8_t   int8;
 typedef int16_t  int16;
@@ -251,30 +878,19 @@ typedef uint64_t uint64;
 // float and double are types
 typedef std::string String;
 
-/**
- * A boolean array.
- */
-typedef std::vector<uint8> BooleanArray;
-typedef std::tr1::shared_ptr<BooleanArray> BooleanArrayPtr;
-/* get is same is ubyte*/
-typedef std::vector<uint8>::iterator BooleanArray_iterator;
-typedef std::vector<uint8>::const_iterator BooleanArray_const_iterator;
+typedef std::vector StringArray;
+typedef std::tr1::shared_ptr StringArrayPtr;
+inline String * get(StringArray &value);
+inline String const * get(StringArray const &value);
+inline String * get(StringArrayPtr &value);
+inline String const * get(StringArrayPtr const &value);
+}
+inline StringArray & getVector(StringArrayPtr &value);
+inline StringArray const & getVector(StringArrayPtr const &value);
+typedef std::vector::iterator StringArray_iterator;
+typedef std::vector::const_iterator StringArray_const_iterator;
 
-/**
- * A byte array.
- */
-typedef std::vector<int8> ByteArray;
-typedef std::tr1::shared_ptr<ByteArray> ByteArrayPtr;
-inline int8 * get(ByteArray &value);
-inline int8 const * get(ByteArray const &value);
-inline int8 * get(ByteArrayPtr &value);
-inline int8 const * get(ByteArrayPtr const &value);
-inline ByteArray & getVector(ByteArrayPtr &value);
-inline ByteArray const & getVector(ByteArrayPtr const &value);
-typedef std::vector<int8>::iterator ByteArray_iterator;
-typedef std::vector<int8>::const_iterator ByteArray_const_iterator;
-
-/* similar definitions are present for ALL the primitive types */
+typedef String * StringBuilder;
 

where

@@ -295,14 +911,16 @@ typedef std::vector<int8>::const_iterator ByteArray_const_iterator; copy on write semantics, it can be used for support for immutable strings. It can also be serialized/deserialized as a UTF8 encoded string. Because it is not a C++ primitive the first letter is capitalized. This - is the same convention the Java implementation uses. + is the same convention the Java implementation uses. + Note that string is treated like a primitive type. +
StringArray definitions
+
typedefs are provided for an array of Strings, + which is a std::vector<String>. + This is used by introspection. +
StringBuilder
-
This is defined here because to is used by the toString methods defined - for both introsection and data objects. The definition above acts like - the Java StringBuilder class.
-
Array definitions
-
typedefs are provided for an array of each of the primitive types. Note - that string is treated like a primitive type/
+
This is used to implement semantics similar to the Java toString + method. It is being replaced by the C++ stream semantics.

TBD

@@ -312,38 +930,47 @@ typedef std::vector<int8>::const_iterator ByteArray_const_iterator; typedef uint8_t boolean;
StringBuilder
-
Should this go away?
-
Array definitions
-
These should all be removed.
+
Should this go away? + Note that it is used for both introspection and data. +
+
printer.h
+
Not documented. + How should printer, toString, and dumpValue be related? + Also limit number of elements to show if array is large. +

-

pvIntrospect.h

+

pvIntrospect.h

This subsection describes pvIntrospect.h This file is quite big so rather than showing the entire file, it will be described in parts.

-

A primary reason for pvData is to support network access to structured data. +

The primary purpose for pvData is to support network access to structured data. pvAccess transports top level pvStructures. In addition a pvAccess server holds -a set of pvnames, where each pvname if a unique name in the local network.

+a set of pvnames, where each name is a unique name in the local network. +This is also refered to as the channel name. +

-

Given a pvname PV), it is possible to introspect the field without requiring +

Given a pvname , it is possible to introspect the types of the associated data access to data. The reflection and data interfaces are separate because the -data may not be available. For example when a pvAccess client connects to a PV, +data may not be available. For example when a pvAccess client connects to a pvname, the client library can obtain the reflection information without obtaining any data. Only when a client issues an I/O request will data be available. This separation is especially important for arrays and structures so that a client can discover the type without requiring that a large data array or structure be transported over the network.

-

Type Description

+

Type Description

Types are defined as:

enum Type {
     scalar,
     scalarArray,
     structure,
-    structureArray;
+    structureArray,
+    union_,
+    unionArray
 };
 
 class TypeFunc {
@@ -384,6 +1011,15 @@ public:
   
structureArray
An array where each element is a structure. Each element has the same structure introspection interface.
+
union_t
+
This is like a structure that has a single subfield. + The type for the subfield can either be any type, which is called a varient union, + of can be one od a specified set of types. + In the data interfaces the type can be changed dynamically. +'
+
unionArray
+
An array where each element is a union. Each element has the same + union introspection interface.

ScalarType is one of the following:

@@ -443,20 +1079,8 @@ public:
elementSize
Returns the size in bytes of an instance of the scalarType.
-

TBD -

-
union
-
Types pvUnion and pvUnionArray should be added
-
toString
-
Should this be changed to -
-String toString(ScalarType scalarType);
-      
-
-
-

-

Introspection Description

+

Introspection Description

This section describes the reflection interfaces which provide the following:

@@ -481,20 +1105,40 @@ following:

Structure interspection interface. A pvAccess client can only get/put entire PVStructure elements NOT subfields of array elements.
Union
-
TBD
+
+ This has two flavors: a varient union or a union of a fixed set + of types. A PVUnion will have a single subfield. + If the union introspection interface is a varient union then + the single field can be of any type and has the name any. + If the union is not a varient type then the type can be one of + a fixed set of types and a name associated with the type. + The union introspection interface has a field array and a string + array that has the fixed set of types and associated names. +
UnionArray
-
TBD
+
+ This is an array of unions. A PVUnionArray is an array + of PVUnions. Each element has the same interspection interface + but the subfield of each element can have a different type. +
+
FieldBuilder
+
This is a convenience interface that makes it easier to create + top introspection interfaces. +
FieldCreate
This is an interface that provides methods to create introspection interfaces. A factory is provides to create FieldCreate.
getFieldCreate
Gets a pointer to the single instance of FieldCreate.
+

Field,Scalar,ScalarArray,Structure,StructureArray,Union,UnionArray

class Field;
 class Scalar;
 class ScalarArray;
 class Structure;
 class StructureArray;
+class Union;
+class UnionArray;
 
 typedef std::tr1::shared_ptr<const Field> FieldConstPtr;
 typedef std::vector<FieldConstPtr> FieldConstPtrArray;
@@ -502,6 +1146,8 @@ typedef std::tr1::shared_ptr<const Scalar> ScalarConstPtr;
 typedef std::tr1::shared_ptr<const ScalarArray> ScalarArrayConstPtr;
 typedef std::tr1::shared_ptr<const Structure> StructureConstPtr;
 typedef std::tr1::shared_ptr<const StructureArray> StructureArrayConstPtr;
+typedef std::tr1::shared_ptr<const Union> UnionConstPtr;
+typedef std::tr1::shared_ptr<const UnionArray> UnionArrayConstPtr;
 
 
 class Field :
@@ -584,28 +1230,51 @@ public:
  ...
 };
 
-class FieldCreate  {
+class epicsShareClass Union : public Field {
 public:
-    static FieldCreatePtr getFieldCreate();
-    ScalarConstPtr  createScalar(ScalarType scalarType) const
-    ScalarArrayConstPtr createScalarArray(ScalarType elementType) const;
-    StructureArrayConstPtr createStructureArray(StructureConstPtr const & structure) const;
-    StructureConstPtr createStructure (
-        StringArray const & fieldNames,
-        FieldConstPtrArray const & fields) const;
-    StructureConstPtr createStructure (
-        String const &id,
-        StringArray const & fieldNames,
-        FieldConstPtrArray const & fields) const;
-    FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const;
- ...
+    POINTER_DEFINITIONS(Union);
+    static epics::pvData::String DEFAULT_ID;
+    static epics::pvData::String ANY_ID;
+    virtual ~Union();
+    typedef Union& reference;
+    typedef const Union& const_reference;
+
+    std::size_t getNumberFields() const;
+    FieldConstPtr getField(String const &fieldName) const;
+    FieldConstPtr getField(std::size_t index);
+    std::size_t getFieldIndex(String const &fieldName) const;
+    FieldConstPtrArray const & getFields() const;
+    StringArray const & getFieldNames() const;
+    String getFieldName(std::size_t fieldIndex) const;
+    bool isVariant() const;
+    virtual void toString(StringBuilder buf) const;
+    virtual void toString(StringBuilder buf,int indentLevel) const;
+    virtual String getID() const;
+    virtual void serialize(
+        ByteBuffer *buffer, SerializableControl *control) const;
+    virtual void deserialize(
+        ByteBuffer *buffer, DeserializableControl *control);
+    
 };
 
-extern FieldCreatePtr getFieldCreate(); 
+class epicsShareClass UnionArray : public Field{ +public: + POINTER_DEFINITIONS(UnionArray); + typedef UnionArray& reference; + typedef const UnionArray& const_reference; + UnionConstPtr getUnion() const {return punion;} + virtual void toString(StringBuilder buf,int indentLevel=0) const; + + virtual String getID() const; + + virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const; + virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control); +}; +
-
Constructor
+
Constructors
Note that all constructors are protected or private. The only way to - create instances is via FieldCreate. The implementation manages all + create instances is via fieldBuilder or fieldCreate. The implementation manages all storage via shared pointers.
toString
Many classes provide this (actually two methods). This method is called @@ -613,7 +1282,7 @@ extern FieldCreatePtr getFieldCreate(); section.
-
Field
+

Field

getType
Get the field type.
@@ -621,7 +1290,7 @@ extern FieldCreatePtr getFieldCreate();
Get an ID for this introspection interface
-
Scalar
+

Scalar

getScalarType
Get that scalar type.
@@ -631,7 +1300,7 @@ extern FieldCreatePtr getFieldCreate();
-
ScalarArray
+

ScalarArray

getElementType
Get the element type.
@@ -641,7 +1310,7 @@ extern FieldCreatePtr getFieldCreate(); "string[]".
-
StructureArray
+

StructureArray

getStructure
Get the introspection interface that each element shares,
@@ -650,7 +1319,7 @@ extern FieldCreatePtr getFieldCreate(); structure->getID().
-
Structure
+

Structure

getNumberFields
Get the number of immediate subfields.
@@ -667,36 +1336,331 @@ extern FieldCreatePtr getFieldCreate();
getFieldName
Get the field name for the specified index.
+

Union

+
+
getNumberFields
+
Get the number of possible field types. + Both getFields and getFieldNames will return an array with getNumberFields elements. + A value of 0 is returned for invarient arrays. +
+
getField
+
Given a name ot an index the type is returned. + NULL is returned if not found. +
+
getFieldIndex
+
Get the index for name. -1 is returned if not found. +
getFields
+
Get the array of types.
+
getFieldNames
+
Get the array of names.
+
getFieldName
+
Get the name for the specified index.
+
isVariant
+
returns true if this is varient array and false otherwise. +
+

UnionArray

+
+
getUnion
+
Get the union interface for each element.
+
+

fieldBuilder and createField

+
+class epicsShareClass FieldBuilder :
+    public std::tr1::enable_shared_from_this<FieldBuilder>
+{
+public:
+    FieldBuilderPtr setId(std::string const & id);
+    FieldBuilderPtr add(std::string const & name, ScalarType scalarType);
+    FieldBuilderPtr add(std::string const & name, FieldConstPtr const & field);
+    FieldBuilderPtr addArray(std::string const & name, ScalarType scalarType);
+    FieldBuilderPtr addArray(std::string const & name, FieldConstPtr const & element);
+    StructureConstPtr createStructure();
+    UnionConstPtr createUnion();
+    FieldBuilderPtr addNestedStructure(std::string const & name); 
+    FieldBuilderPtr addNestedUnion(std::string const & name);
+    FieldBuilderPtr addNestedStructureArray(std::string const & name); 
+    FieldBuilderPtr addNestedUnionArray(std::string const & name);
+    FieldBuilderPtr endNested();
+};
 
-
FieldCreate
+class epicsShareClass FieldCreate { +public: + static FieldCreatePtr getFieldCreate(); + FieldBuilderPtr createFieldBuilder() const; + ScalarConstPtr createScalar(ScalarType scalarType) const; + ScalarArrayConstPtr createScalarArray(ScalarType elementType) const; + StructureArrayConstPtr createStructureArray(StructureConstPtr const & structure) const; + StructureConstPtr createStructure () const; + StructureConstPtr createStructure ( + StringArray const & fieldNames, + FieldConstPtrArray const & fields) const; + StructureConstPtr createStructure ( + String const & id, + StringArray const & fieldNames, + FieldConstPtrArray const & fields) const; + UnionConstPtr createUnion ( + StringArray const & fieldNames, + FieldConstPtrArray const & fields) const; + UnionConstPtr createUnion ( + String const & id, + StringArray const & fieldNames, + FieldConstPtrArray const & fields) const; + UnionConstPtr createVariantUnion() const; + UnionArrayConstPtr createVariantUnionArray() const; + UnionArrayConstPtr createUnionArray(UnionConstPtr const & punion) const; + StructureConstPtr appendField( + StructureConstPtr const & structure, + String const & fieldName, FieldConstPtr const & field) const; + StructureConstPtr appendFields( + StructureConstPtr const & structure, + StringArray const & fieldNames, + FieldConstPtrArray const & fields) const; + FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const; + +}; + +epicsShareExtern FieldCreatePtr getFieldCreate(); +
+ +

FieldBuilder

+

This is a class that makes it easier to create introspection interfaces. +It is meant to be used via stream input syntax. See the examples that follow the +description of the methods. +

+
+
setID
+
This sets an ID for the field, which is the name for the field when it is a subfield. +
+
add
+
+ Add a scalar field. +
+
addArray
+
+ Add a scalarArray field. +
+
createStructure
+
+ Create a structure from the fields that are currently present. +
+
createUnion
+
+ Create a union from the fields that are currently present. +
+
addNestedStructure
+
+ Add a nested structure. This is followed by an arbitrary number of adds + followed by a an endNested. +
+
addNestedUnion
+
+ Add a nested union. This is followed by an arbitrary number of adds + followed by a an endNested. +
+
addNestedStructureArray
+
+ Add a nested structure array. This is followed by an arbitrary number of adds + followed by a an endNested. +
+
addNestedUnionArray
+
+ Add a nested union array. This is followed by an arbitrary number of adds + followed by a an endNested. +
+
endNested
+
+ End current nested structure or union. +
+
+

A simple example is:

+
+StructureConstPtr structure =
+      getFieldCreate()->createFieldBuilder()->
+      setId("enum_t")->
+      add("index", pvDouble)->
+      addArray("choices", pvString)->
+      createStructure();
+String builder;
+structure->toString(&builder);
+cout << builder << endl;
+
+This produces: +
+enum_t
+    double index
+    string[] choices
+
+

Another example is:

+
+StructureConstPtr enum_t =
+getFieldCreate()->createFieldBuilder()->
+    setId("enum_t")->
+    add("index", pvInt)->
+    addArray("choices", pvString)->
+    createStructure();
+
+StructureConstPtr ntEnum =
+getFieldCreate()->createFieldBuilder()->
+    setId("uri:ev4:nt/2012/pwd/NTEnum")->
+    add("value", enum_t)->
+    addNestedStructure("timeStamp")->
+        setId("time_t")->
+        add("secsPastEpoch", pvLong)->
+        add("nanoseconds", pvInt)->
+        add("userTag", pvInt)->
+        endNested()->
+    createStructure();
+builder.clear();
+ntEnum->toString(&builder);
+cout << builder << endl;
+
+This produces: +
+uri:ev4:nt/2012/pwd/NTEnum
+    enum_t value
+        int index
+        string[] choices
+    time_t timeStamp
+        long secsPastEpoch
+        int nanoseconds
+        int userTag
+
+

The following example:

+
+    UnionConstPtr ntunion =
+    getFieldCreate()->createFieldBuilder()->
+        add("doubleValue", pvDouble)->
+        add("intValue", pvInt)->
+        addNestedStructure("timeStamp")->
+            setId("time_t")->
+            add("secsPastEpoch", pvLong)->
+            add("nanoseconds", pvInt)->
+            add("userTag", pvInt)->
+            endNested()->
+        createUnion();
+    builder.clear();
+    ntunion->toString(&builder);
+    cout << builder << endl;
+
+produces: +
+union
+    double doubleValue
+    int intValue
+    time_t timeStamp
+        long secsPastEpoch
+        int nanoseconds
+        int userTag
+
+

A powerSupply structure can be created as follows:

+
+StructureConstPtr alarm = getStandardField()->alarm();
+StructureConstPtr timeStamp = getStandardField()->timeStamp();
+
+StructureConstPtr powerSupply =
+getFieldCreate()->createFieldBuilder()->
+    add("alarm_t",alarm) ->
+    add("timestamp_t",timeStamp) ->
+    addNestedStructure("power") ->
+       add("value",pvDouble) ->
+       add("alarm",alarm) ->
+       endNested()->
+    addNestedStructure("voltage") ->
+       add("value",pvDouble) ->
+       add("alarm",alarm) ->
+       endNested()->
+    addNestedStructure("current") ->
+       add("value",pvDouble) ->
+       add("alarm",alarm) ->
+       endNested()->
+    createStructure();
+builder.clear();
+powerSupply->toString(&builder);
+cout << builder << endl;
+
+produces: +
+structure
+    alarm_t alarm_t
+        int severity
+        int status
+        string message
+    time_t timestamp_t
+        long secondsPastEpoch
+        int nanoSeconds
+        int userTag
+    structure power
+        double value
+        alarm_t alarm
+            int severity
+            int status
+            string message
+    structure voltage
+        double value
+        alarm_t alarm
+            int severity
+            int status
+            string message
+    structure current
+        double value
+        alarm_t alarm
+            int severity
+            int status
+            string message
+
+

FieldCreate

getFieldCreate
Get the single instance of FieldCreate.
+
createFieldBuilder
+
Create an instance of a FieldBuilder.
createScalar
Create a scalar introspection instance.
createScalarArray
Create a scalar array introspection instance.
createStructure
-
Create a structure introspection instance. Two methods are provided - where the only difference is that one provides an ID and the other does - not. The one without will result in ID "structure".
+
Create a structure introspection instance. Three methods are provided. + The first creates an empty structure, i. e. a structure with no fields. + The other two are similar. + The only difference is that one provides an ID and the other does + not. The one without will result in ID structure.
+
createUnion
+
Create a union. There are two methods. + Each has arguments for an array of types and an array of names. + One method has an id. The other results in id = union. +
+
createVariantUnion
+
+ Create a varient union. The id will be any. +
+
createUnionArray
+
Create a union array. punion is the introspection interface + for each element.
+
createVariantUnionArray
+
Create a union array where each element is a varient union.
createStructureArray
Create a structure array introspection instance.
+
appendField
+
Create a new structure that is like an existing structure but has + an extra field appended to it. +
+
appendFields
+
Create a new structure that is like an existing structure but has + extra fields appended to it. +
deserialize
Deserialize from given byte buffer.

TBD

toString
-
Should all the toString methods be changed to just return String?
+
Should support for steams exist.
ScalarTypeTraits and ScalarTypeID
These seem to only be used by shared_vector. Do they need to be documented?
-
appendField and appendFields
-
These methods of FieldCreate should be removed.

-

standardField.h

+

standardField.h

The file standardField.h has a class description for creating or sharing Field objects for standard fields. For each type of field a method is provided. @@ -735,10 +1699,15 @@ public: static StandardFieldPtr getStandardField(); ~StandardField(); StructureConstPtr scalar(ScalarType type,String const &properties); + StructureConstPtr regUnion( + UnionConstPtr const & punion, + String const & properties); + StructureConstPtr variantUnion(String const & properties); StructureConstPtr scalarArray( ScalarType elementType, String const &properties); StructureConstPtr structureArray( StructureConstPtr const & structure,String const &properties); + StructureConstPtr unionArray(UnionConstPtr const & punion,String const & properties); StructureConstPtr enumerated(); StructureConstPtr enumerated(String const &properties); StructureConstPtr alarm(); @@ -765,6 +1734,16 @@ public: will be created with the first element being a scalar with the specified scalar type and name value. The other fields in the structure will be the corresponding property structures. +

regUnion
+
A structure + will be created with the first element being a union with the specified + scalar type and name value. The other fields in the structure will be the + corresponding property structures.
+
varient`Union
+
Create a varient union. A structure + will be created with the first element being a union with the specified + scalar type and name value. The other fields in the structure will be the + corresponding property structures.
scalarArray
Create a scalarArray with each element having the specified scalar type and name. A structure will be created with the first element being a @@ -776,6 +1755,12 @@ public: structureArray with the specified structure interface and name value. The other fields in the structure will be the corresponding property structures.
+
unionArray
+
Create a unionArray with the specified union interface and + name. A structure will be created with the first element being a + unionArray with the specified structure interface and name value. The + other fields in the structure will be the corresponding property + structures.
structure
Create a structure with the specified name and fields specified by numFields and fields. A structure will be created with the first element @@ -803,20 +1788,12 @@ public:
The above provide introspection interfaces for standard properties. See the section on Properties for a description of how these are defined.
-

TBD -

-
union
-
unionArray
-
When union is supported also add these.
-
-

+

pvData.h

-

pvData.h

- -

This subsection describes pvData.h This file is quite big so rather than +

This section describes pvData.h This file is quite big so rather than showing the entire file, it will be described in parts.

-

typedefs

+

typedefs

These are typedefs for Array and Ptr for the various pvData class definitions, i.e. typdefs for "std::vector" and "std::tr1::shared_ptr".

@@ -846,6 +1823,20 @@ typedef std::tr1::shared_ptr<PVStructureArray> PVStructureArrayPtr; typedef std::vector<PVStructureArrayPtr> PVStructureArrayPtrArray; typedef std::tr1::shared_ptr<PVStructureArrayPtrArray> PVStructureArrayPtrArrayPtr; +typedef std::tr1::shared_ptr<PVUnion> PVUnionPtr; +typedef std::vector<PVUnionPtr> PVUnionPtrArray; +typedef std::vector<PVUnionPtr>::iterator PVUnionPtrArray_iterator; +typedef std::vector<PVUnionPtr>::const_iterator PVUnionPtrArray_const__iterator; + +typedef PVValueArray<PVUnionPtr> PVUnionArray; +typedef std::tr1::shared_ptr<PVUnionArray> PVUnionArrayPtr; +typedef std::vector<PVUnionArrayPtr> PVUnionArrayPtrArray; +typedef std::tr1::shared_ptr<PVUnionArrayPtrArray> PVUnionArrayPtrArrayPtr; + +class PVDataCreate; +typedef std::tr1::shared_ptr<PVDataCreate> PVDataCreatePtr; + + /** * typedefs for the various possible scalar types. */ @@ -902,18 +1893,9 @@ typedef std::tr1::shared_ptr<PVULongArray> PVULongArrayPtr; typedef std::tr1::shared_ptr<PVFloatArray> PVFloatArrayPtr; typedef std::tr1::shared_ptr<PVDoubleArray> PVDoubleArrayPtr; typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr; - -

TBD -

-
PVUnion
-
PVUnionArray
-
When union is supported.
-
WPtr
-
Should definitions for std::tr1::weak_ptr also be added.
-
-

PVField

+

PVField

PVField is the base interface for accessing data. A data structure consists of a top level PVStructure. Every field of every structure of every top level @@ -935,6 +1917,7 @@ public: POINTER_DEFINITIONS(PVField); virtual ~PVField(); String getFieldName() const ; + String getFullName() const; std::size_t getFieldOffset() const; std::size_t getNextFieldOffset() const; std::size_t getNumberFields() const; @@ -949,7 +1932,9 @@ public: virtual void toString(StringBuilder buf,int indentLevel); std::ostream& dumpValue(std::ostream& o) const; ... -} +} +std::ostream& operator<<(std::ostream& o, const PVField& f); +

The public methods for PVField are:

@@ -1012,21 +1997,14 @@ public:

TBD

-
getFullName
-
Should this be removed?
toString and dumpValue
-
Should these be replaced by: -
-virtual String toString() const;
-virtual std::ostream& operator<<(std::ostream& o) const = 0;
-
+
toString is broken
+ Should toString go away or be changed?
-
replaceField
-
This is a protected member that should be removed.

-

PVScalar

+

PVScalar

This is the base class for all scalar data.

class PVScalar : public PVField {
@@ -1057,7 +2035,7 @@ uint32 val = pv->getAs();
 
 
-

PVScalarValue

+

PVScalarValue

The interfaces for primitive data types are:

template<typename T>
@@ -1082,12 +2060,39 @@ public:
  ...
 }
 
+typedef PVScalarValue<boolean> PVBoolean;
+typedef PVScalarValue<int8> PVByte;
+typedef PVScalarValue<int16> PVShort;
+typedef PVScalarValue<int32> PVInt;
+typedef PVScalarValue<int64> PVLong;
+typedef PVScalarValue<uint8> PVUByte;
+typedef PVScalarValue<uint16> PVUShort;
+typedef PVScalarValue<uint32> PVUInt;
+typedef PVScalarValue<uint64> PVULong;
+typedef PVScalarValue<float> PVFloat;
+typedef PVScalarValue<double> PVDouble;
+typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
+typedef std::tr1::shared_ptr<PVByte> PVBytePtr;
+typedef std::tr1::shared_ptr<PVShort> PVShortPtr;
+typedef std::tr1::shared_ptr<PVInt> PVIntPtr;
+typedef std::tr1::shared_ptr<PVLong> PVLongPtr;
+typedef std::tr1::shared_ptr<PVUByte> PVUBytePtr;
+typedef std::tr1::shared_ptr<PVUShort> PVUShortPtr;
+typedef std::tr1::shared_ptr<PVUInt> PVUIntPtr;
+typedef std::tr1::shared_ptr<PVULong> PVULongPtr;
+typedef std::tr1::shared_ptr<PVFloat> PVFloatPtr;
+typedef std::tr1::shared_ptr<PVDouble> PVDoublePtr;
+
+
 // PVString is special case, since it implements SerializableArray
 class PVString : public PVScalarValue<String>, SerializableArray {
 public:
     virtual ~PVString() {}
  ...
-};
+}; + + +

where

@@ -1143,7 +2148,77 @@ pv->putFrom<pvInt>(val);

-

PVArray

+

PVUnion

+

A PVUnion has a single subfield. +The Union introspection interface determines the possible +field types for the subfield. +If it is a varient union then any type is allowed and the +subfield name is normally any. +If it is not a varient union that the Union interface determines +the possible field types and names.

+
+class PVUnion : public PVField
+{
+public:
+    POINTER_DEFINITIONS(PVUnion);
+    virtual ~PVUnion();
+    UnionConstPtr getUnion() const;
+    PVFieldPtr get() const;
+    
+    template<typename PVT>
+    std::tr1::shared_ptr<PVT> get() const {
+        return std::tr1::dynamic_pointer_cast<PVT>(get());
+    }
+
+   PVFieldPtr select(int32 index);
+
+    template<typename PVT>
+    std::tr1::shared_ptr<PVT> select(int32 index) {
+        return std::tr1::dynamic_pointer_cast<PVT>(select(index));
+    }
+
+    PVFieldPtr select(String const & fieldName);
+
+    template<typename PVT>
+    std::tr1::shared_ptr<PVT> select(String const & fieldName) {
+        return std::tr1::dynamic_pointer_cast<PVT>(select(fieldName));
+    }
+
+    int32 getSelectedIndex() const;
+    String getSelectedFieldName() const;
+    void set(PVFieldPtr const & value);
+    void set(int32 index, PVFieldPtr const & value);
+    void set(String const & fieldName, PVFieldPtr const & value);
+    virtual void serialize(
+        ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
+    PVUnion(UnionConstPtr const & punion);
+};
+
+
+
getUnion
+
Get the introspection interface.
+
get
+
Get the curent field. A template version does the conversion. + NULL is returned if no field is selected or if the caller +' asks for the wrong type. +
+
select
+
Select and get the field by index or name. + A templated version does the conversion. + If the index is out of bounds or the name is not valid this methods throws an exception. + The method set should be used for variant unions rather than select. +
+
getSelectedIndex
+
Get the index of the currently selected field.
+
getSelectedFieldName
+
Get the name of the currently selected field.
+
set
+
Set the field to the argument. If invalid type an exception is thrown. + This should always work for a variant union. +
+
+ +

PVArray

PVArray is the base interface for all the other PV Array interfaces. It extends PVField and provides the additional methods:

@@ -1188,15 +2263,10 @@ public:
dumpValue
ostream method
-

TBD -

-
dumpvalue
-
replace this with ostream operator<<
-

-

PVScalarArray

+

PVScalarArray

PVScalarArray is the base class for scalar array data. PVValueArray is a templete for the various scalar array data classes. There is a class for each @@ -1210,10 +2280,13 @@ public: typedef const PVScalarArray& const_reference; const ScalarArrayConstPtr getScalarArray() const ; + template<typename T> void getAs(shared_vector<const T>& out) const + template<typename T> void putFrom(const shared_vector<const T>& inp) + void assign(PVScalarArray& pv); ... } @@ -1242,7 +2315,77 @@ public: -

PVValueArray

+

PVStructure

+ +

The interface for a structure is:

+
class PVStructure : public PVField,public BitSetSerializable {
+public:
+    POINTER_DEFINITIONS(PVStructure);
+    virtual ~PVStructure();
+    typedef PVStructure & reference;
+    typedef const PVStructure & const_reference;
+
+    virtual void setImmutable();
+    StructureConstPtr getStructure() const;
+    const PVFieldPtrArray & getPVFields() const;
+    PVFieldPtr getSubField(String const &fieldName) const;
+
+    template<typename PVT>
+    std::tr1::shared_ptr<PVT> getSubField(String const &fieldName) const
+
+    PVFieldPtr getSubField(std::size_t fieldOffset) const;
+
+    template<typename PVT>
+    std::tr1::shared_ptr<PVT> getSubField(std::size_t fieldOffset) const
+
+    virtual void serialize(
+        ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
+    virtual void deserialize(
+        ByteBuffer *pbuffer,DeserializableControl *pflusher);
+    virtual void serialize(ByteBuffer *pbuffer,
+        SerializableControl *pflusher,BitSet *pbitSet) const;
+    virtual void deserialize(ByteBuffer *pbuffer,
+        DeserializableControl*pflusher,BitSet *pbitSet);
+    PVStructure(StructureConstPtr const & structure);
+    PVStructure(StructureConstPtr const & structure,PVFieldPtrArray const & pvFields);
+    virtual std::ostream& dumpValue(std::ostream& o) const;
+};
+ +

where

+
+
getStructure
+
Get the introspection interface for the structure.
+
getPVFields
+
Returns the array of subfields. The set of subfields must all have + different field names.
+
getSubField(String fieldName)
+
+ Get a subField of a field.d + A non-null result is + returned if fieldName is a field of the PVStructure. The fieldName can be + of the form name.name... + If the field does not exist the a Ptr to a NULL value is returned + without any error message being generated. +
+ Note that the template version replaces getBooleanField, etc.
+
+
getSubField(int fieldOffset)
+
Get the field located a fieldOffset, where fieldOffset is relative to + the top level structure. This returns null if the specified field is not + located within this PVStructure. +
+
dumpValue
+
Method for streams I/O.
+
+

TBD +

+
dumpvalue
+
replace this with ostream operator<<
+
+

+ + +

PVValueArray

This is a template class plus instances for PVBooleanArray, ..., PVStringArray.

@@ -1296,129 +2439,7 @@ public:

-

PVStructure

- -

The interface for a structure is:

-
class PVStructure : public PVField,public BitSetSerializable {
-public:
-    POINTER_DEFINITIONS(PVStructure);
-    virtual ~PVStructure();
-    typedef PVStructure & reference;
-    typedef const PVStructure & const_reference;
-
-    virtual void setImmutable();
-    StructureConstPtr getStructure() const;
-    const PVFieldPtrArray & getPVFields() const;
-    PVFieldPtr getSubField(String const &fieldName) const;
-    PVFieldPtr getSubField(std::size_t fieldOffset) const;
-    PVBooleanPtr getBooleanField(String const &fieldName) ;
-    PVBytePtr getByteField(String const &fieldName) ;
-    PVShortPtr getShortField(String const &fieldName) ;
-    PVIntPtr getIntField(String const &fieldName) ;
-    PVLongPtr getLongField(String const &fieldName) ;
-    PVUBytePtr getUByteField(String const &fieldName) ;
-    PVUShortPtr getUShortField(String const &fieldName) ;
-    PVUIntPtr getUIntField(String const &fieldName) ;
-    PVULongPtr getULongField(String const &fieldName) ;
-    PVFloatPtr getFloatField(String const &fieldName) ;
-    PVDoublePtr getDoubleField(String const &fieldName) ;
-    PVStringPtr getStringField(String const &fieldName) ;
-    PVStructurePtr getStructureField(String const &fieldName) ;
-    PVScalarArrayPtr getScalarArrayField(
-        String const &fieldName,ScalarType elementType) ;
-    PVStructureArrayPtr getStructureArrayField(String const &fieldName) ;
-    virtual void serialize(
-        ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
-    virtual void deserialize(
-        ByteBuffer *pbuffer,DeserializableControl *pflusher);
-    virtual void serialize(ByteBuffer *pbuffer,
-        SerializableControl *pflusher,BitSet *pbitSet) const;
-    virtual void deserialize(ByteBuffer *pbuffer,
-        DeserializableControl*pflusher,BitSet *pbitSet);
-    PVStructure(StructureConstPtr const & structure);
-    PVStructure(StructureConstPtr const & structure,PVFieldPtrArray const & pvFields);
-    virtual std::ostream& dumpValue(std::ostream& o) const;
-};
- -

where

-
-
getStructure
-
Get the introspection interface for the structure.
-
getPVFields
-
Returns the array of subfields. The set of subfields must all have - different field names.
-
getSubField(String fieldName)
-
Get a subField of a field. For a PVStructure a non-null result is - returned if fieldName is a field of the PVStructure. The fieldName can be - of the form name.name... - If the field does not exist the a Ptr to a NULL value is returned - without any error message being generated. -
-
getSubField(int fieldOffset)
-
Get the field located a fieldOffset, where fieldOffset is relative to - the top level structure. This returns null if the specified field is not - located within this PVStructure.
-
getBooleanField
-
Look for fieldName. If found and it has the correct type return the - interface. This and the following methods are convenience methods that - allow a user to get the interface to a subfield without requiring - introspection. fieldName can be of the form name.name... - If the field does not exist or has the wrong type then - message will be called and a Ptr to NULL is returned. -
-
getByteField
-
Look for fieldName. If found and it has the correct type return the - interface.
-
getShortField
-
Look for fieldName. If found and it has the correct type return the - interface.
-
getIntField
-
Look for fieldName. If found and it has the correct type return the - interface.
-
getLongField
-
Look for fieldName. If found and it has the correct type return the - interface.
-
getUByteField
-
Look for fieldName. If found and it has the correct type return the - interface.
-
getUShortField
-
Look for fieldName. If found and it has the correct type return the - interface.
-
getUIntField
-
Look for fieldName. If found and it has the correct type return the - interface.
-
getULongField
-
Look for fieldName. If found and it has the correct type return the - interface.
-
getFloatField
-
Look for fieldName. If found and it has the correct type return the - interface.
-
getDoubleField
-
Look for fieldName. If found and it has the correct type return the - interface.
-
getStringField
-
Look for fieldName. If found and it has the correct type return the - interface.
-
getStructureField
-
Look for fieldName. If found and it has the correct type return the - interface.
-
getScalarArrayField
-
Look for fieldName. If found and it has the correct type return the - interface.
-
getStructureArrayField
-
Look for fieldName. If found and it has the correct type return the - interface.
-
dumpValue
-
Method for streams I/O.
-
-

TBD -

-
dumpvalue
-
replace this with ostream operator<<
-
-

- -

PVStructureArray

+

PVStructureArray

The interface for an array of structures is:

@@ -1481,28 +2502,110 @@ public:
       done there are no null elements.
 
 
-

The other methods are similar to the methods for other array types.

+

The other methods are similar to the methods for other array types. + See PVArray above for details.

-

PVDataCreate

+

PVUnionArray

+

The interface for an array of unions is:

+
+template&ly;&gt;
+class epicsShareClass PVValueArray&ly;PVUnionPtr&gt; : public detail::PVVectorStorage&ly;PVUnionPtr,PVArray&gt;
+{
+    typedef detail::PVVectorStorage&ly;PVUnionPtr,PVArray&gt; base_t;
+public:
+    POINTER_DEFINITIONS(PVUnionArray);
+    typedef PVUnionPtr  value_type;
+    typedef PVUnionPtr* pointer;
+    typedef const PVUnionPtr* const_pointer;
+    typedef PVUnionArray &reference;
+    typedef const PVUnionArray& const_reference;
+
+    //TODO: full namespace can be removed along with local typedef 'shared_vector'
+    typedef ::epics::pvData::shared_vector&ly;PVUnionPtr&gt; svector;
+    typedef ::epics::pvData::shared_vector&ly;const PVUnionPtr&gt; const_svector;
+    
+    virtual ~PVValueArray() {}
+
+    virtual size_t getLength() const;
+    virtual size_t getCapacity() const;
+    virtual void setCapacity(size_t capacity);
+    virtual void setLength(std::size_t length);
+    UnionArrayConstPtr getUnionArray() const;
+    virtual std::size_t append(std::size_t number);
+    virtual bool remove(std::size_t offset,std::size_t number);
+    virtual void compress();
+    virtual const_svector view() const;
+    virtual void swap(const_svector &other);
+    virtual void replace(const const_svector &other);
+    virtual void serialize(ByteBuffer *pbuffer,
+        SerializableControl *pflusher) const;
+    virtual void deserialize(ByteBuffer *buffer,
+        DeserializableControl *pflusher);
+    virtual void serialize(ByteBuffer *pbuffer,
+        SerializableControl *pflusher, std::size_t offset, std::size_t count) const ;
+    virtual std::ostream& dumpValue(std::ostream& o) const;
+    virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const;
+};
+
+

where

+
+
getUnionArray
+
Get the introspection interface shared by each element.
+
append
+
Create new elements and append them to the end of the array. It returns + the index of the first new element.
+
remove
+
Remove the specfied set of elements. It returns (false,true) if the + elements (were not, were) removed. It will not removed any elements + unless all requested elements exist or are null. Note that this deletes + the element and sets the array element to null. It does not change the + array capacity.
+
compress
+
This moves all null elements and then changes the array capacity. When + done there are no null elements.
+
+ +

The other methods are similar to the methods for other array types. + See PVArray above for details.

+ +

PVDataCreate

PVDataCreate is an interface that provides methods that create PVField interfaces. A factory is provided that creates PVDataCreate.

class PVDataCreate {
 public:
     static PVDataCreatePtr getPVDataCreate();
+
     PVFieldPtr createPVField(FieldConstPtr const & field);
     PVFieldPtr createPVField(PVFieldPtr const & fieldToClone);
+
     PVScalarPtr createPVScalar(ScalarConstPtr const & scalar);
     PVScalarPtr createPVScalar(ScalarType scalarType);
     PVScalarPtr createPVScalar(PVScalarPtr const & scalarToClone);
+    template<typename PVT>
+    std::tr1::shared_ptr<PVT> createPVScalar();
+
+    PVStructurePtr createPVStructure(
+        StringArray const & fieldNames,PVFieldPtrArray const & pvFields);
+    PVStructurePtr createPVStructure(PVStructurePtr const & structToClone);
+    PVStructurePtr createPVStructure(StructureConstPtr const & structure);
+
+    PVUnionPtr createPVUnion(UnionConstPtr const & punion);
+    PVUnionPtr createPVUnion(PVUnionPtr const & unionToClone);
+    PVUnionPtr createPVVariantUnion();
+
     PVScalarArrayPtr createPVScalarArray(ScalarArrayConstPtr const & scalarArray);
     PVScalarArrayPtr createPVScalarArray(ScalarType elementType);
     PVScalarArrayPtr createPVScalarArray(PVScalarArrayPtr const  & scalarArrayToClone);
+    template<typename PVAT>
+    std::tr1::shared_ptr<PVAT> createPVScalarArray();
+
     PVStructureArrayPtr createPVStructureArray(StructureArrayConstPtr const & structureArray);
-    PVStructurePtr createPVStructure(StructureConstPtr const & structure);
-    PVStructurePtr createPVStructure(
-        StringArray const & fieldNames,PVFieldPtrArray const & pvFields);
-   PVStructurePtr createPVStructure(PVStructurePtr const & structToClone);
+    PVStructureArrayPtr createPVStructureArray(StructureConstPtr const ∓ structure);
+
+    PVUnionArrayPtr createPVUnionArray(UnionArrayConstPtr const & unionArray);
+    PVUnionArrayPtr createPVUnionArray(UnionConstPtr const & punion);
+    PVUnionArrayPtr createPVVariantUnionArray();
  ...
 };
 
@@ -1510,37 +2613,73 @@ extern PVDataCreatePtr getPVDataCreate();

where

+
getPVDataCreate
+
The returns the PVDataCreate implementation, which is a singleton.
createPVField
The PVField is created reusing the Field interface. Two methods are provided. Each calls the corresponding createPVScalar, createPVArray, or createPVStructure depending in the type of the last argument.
createPVScalar
-
Creates an instance of a PVScalar. Three versions are supplied. The - first is passed an introspection interface. The second provides the field - name and the scalarType. The last provides a field name and a PVScalar to - clone. The newly created PVScalar will have the same auxInfos as the - original.
-
createPVScalarArray
-
Create an instance of a PVArray. Three versions are supplied. The first - is passed an introspection interface. The second provides the field name - and the elementType. The last provides a field name and a PVArray to - clone. The newly created PVArray will have the same auxInfos as the - original.
-
createPVStructureArray
-
Create a PVStructureArray. It must be passed a structureToClone. This - will become the Structure interface for ALL elements of the - PVStructureArray. It MUST be used to create any new array elements.
+
Creates an instance of a PVScalar. Four versions are supplied. The + first is passed an introspection interface. + The second provides the scalarType. + The third provides a PVScalar to clone. + The last is a template version. PVAT must be a valid type. + For example: +
+PVDoublePtr pvDouble = getPVDataCreate()->createPVScalar<PVDouble>();
+
+
createPVStructure
-
Create an instance of a PVStructure. Three methods are provided. The - first method uses a previously created structure introspection interface. - The second uses a PVField array to initialize the sub-fields. - The third initializes the subfields by cloning the fields contained in - structToClone. The newly created sub-fields will have the same values and - auxInfos as the original. If structToClone is null then the new structure - is initialized to have 0 sub-fields.
+
Create an instance of a PVStructure. + Three methods are provided. + The first uses an array of field names and an array of PVFields to initialize the sub-fields. + The second initializes the subfields by cloning the fields contained in + structToClone. The newly created sub-fields will have the same values as the original. + If structToClone is null then the new structure is initialized to have 0 sub-fields. + The third method uses a previously created structure introspection interface. +
+
createPVUnion
+
Create an instance of a PVUnion. Two methods are provided. + The first uses a previously created union introspection interface. + The second clones an existing PVUnion. +
+
createPVVariantUnion
+
Creates an instance of a varient PVUnion. + This is a union which has a single field which can be any pvData supported type, +
+
createPVScalarArray
+
Create an instance of a PVArray. Four versions are supplied. + The first is passed an introspection interface. + The second provides the elementType. + The third provides a PVScalarArray to clone. + The last is a template version. PVAT must be a valid type. + For example: +
+PVDoubleArrayPtr pvDoubleArray = getPVDataCreate()->createPVScalarArray<PVDoubleArray>();
+
+
+
createPVStructureArray
+
Create a PVStructureArray. + Two versions are provided. + The first is passed a StructureArrayConstPtr. + The second is passed a StructureConstPtr which is used to create a StructureArrayConstPtr. + The argument provides the Structure interface for ALL elements of the PVStructureArray. +
+
createPVUnionArray
+
Create a PVUnionArray. + Two versions are provided. + The first is passed a UnionArrayConstPtr. + The second is passed a UnionConstPtr which is used to create a UnionArrayConstPtr. + The argument provides the Union interface for ALL elements of the PVUnionArray. +
+
createPVVariantUnionArray
+
Create a PVUnionArray. + No arguments are needed. +
-

standardPVField.h

+

standardPVField.h

A class StandardPVField has methods for creating standard data fields. Like class StandardField it has two forms of the methods which create a field, one @@ -1558,6 +2697,7 @@ public: PVStructurePtr scalar(ScalarType type,String const &properties); PVStructurePtr scalarArray(ScalarType elementType, String const &properties); PVStructurePtr structureArray(StructureConstPtr const &structure,String const &properties); + PVStructurePtr unionArray(UnionConstPtr const &punion,String const &properties); PVStructurePtr enumerated(StringArray const &choices); PVStructurePtr enumerated(StringArray const &choices, String const &properties); ... @@ -1566,7 +2706,7 @@ public: extern StandardPVFieldPtr getStandardPVField();

-

Conversion

+

Conversion

There are two facilities for converting between two different PVData objects:

@@ -1576,7 +2716,7 @@ objects:

This copies a subarray from one PVArray to another. The two arrays must have the same element type.
-

convert.h

+

convert.h

NOTE about copying immutable array fields. If an entire immutable array field is copied to another array that has the same elementType, both offsets @@ -1599,13 +2739,11 @@ Thus the source and target share the same primitive array.

  • Copy between PVArrays that satisfy one of the following.
  • Conversions between numeric scalar types.
  • -
  • Conversions between arrays of numeric type.
  • Conversion between compatible structures.
  • A utility method the returns the full field name of a field
  • @@ -1619,12 +2757,16 @@ bool operator==(const Scalar&, const Scalar&); bool operator==(const ScalarArray&, const ScalarArray&); bool operator==(const Structure&, const Structure&); bool operator==(const StructureArray&, const StructureArray&); +bool operator==(const Union&, const Union&); +bool operator==(const UnionArray&, const UnionArray&); static inline bool operator!=(const Field& a, const Field& b); static inline bool operator!=(const Scalar& a, const Scalar& b); static inline bool operator!=(const ScalarArray& a, const ScalarArray& b); static inline bool operator!=(const Structure& a, const Structure& b); static inline bool operator!=(const StructureArray& a, const StructureArray& b); +static inline bool operator!=(const Union& a, const Union& b); +static inline bool operator!=(const UnionArray& a, const UnionArray& b); class Convert; typedef std::tr1::shared_ptr<Convert> ConvertPtr; @@ -1665,12 +2807,6 @@ public: bool isCopyScalarArrayCompatible( ScalarArrayConstPtr const & from, ScalarArrayConstPtr const & to); - std::size_t copyScalarArray( - PVScalarArrayPtr const & from, - std::size_t offset, - PVScalarArrayPtr const & to, - std::size_t toOffset, - std::size_t length); bool isCopyStructureCompatible( StructureConstPtr const & from, StructureConstPtr const & to); void copyStructure(PVStructurePtr const & from, PVStructurePtr const & to); @@ -1678,6 +2814,14 @@ public: StructureArrayConstPtr const & from, StructureArrayConstPtr const & to); void copyStructureArray( PVStructureArrayPtr const & from, PVStructureArrayPtr const & to); + bool isCopyUnionCompatible( + UnionConstPtr const & from, UnionConstPtr const & to); + void copyUnion( + PVUnionPtr const & from, PVUnionPtr const & to); + bool isCopyUnionArrayCompatible( + UnionArrayConstPtr const & from, UnionArrayConstPtr const & to); + void copyUnionArray( + PVUnionArrayPtr const & from, PVUnionArrayPtr const & to); int8 toByte(PVScalarPtr const & pv); int16 toShort(PVScalarPtr const & pv); int32 toInt(PVScalarPtr const & pv); @@ -1708,7 +2852,7 @@ extern ConvertPtr getConvert();

    newLine is a convenience method for code that implements toString It generates a newline and inserts blanks at the beginning of the newline.

    -

    pvSubArrayCopy.h

    +

    pvSubArrayCopy.h

     template<typename T>
     void copy(
    @@ -2497,77 +3641,6 @@ public:
           structure. 
     
     
    -

    Examples

    - -

    Accessing PVData

    - -

    Assume that code wants to print two fields from a PVStructure:

    -
    -
    value
    -
    Must be a PVDouble.
    -
    timeStamp
    -
    Just look for field with this name.
    -
    - -

    The following code uses introspection to get the desired information.

    -
    void getValueAndTimeStamp(PVStructurePtr pvStructure,StringBuilder buf) {
    -   PVFieldPtr valuePV = pvStructure->getSubField(String("value"));
    -   if(valuePV.get()==NULL) {
    -       buf += "value field not found";
    -       return;
    -   }
    -   buf += "value ";
    -   valuePV->toString(&buf);
    -   PVFieldPtr timeStampPV = pvStructure->getSubField(String("timeStamp"));
    -   if(timeStampPV.get()==NULL) {
    -       buf += "timeStamp field not found";
    -       return;
    -   }
    -   buf += " timeStamp ";
    -   timeStampPV->toString(&buf);
    -}
    - -

    Creating PVData

    - -

    Example of creating a scalar field.

    -
        PVDataCreatePtr pvDataCreate = getPVDataCreate();
    -    PVDoublePtr pvValue = static_pointer_cast<PVDouble>(
    -        pvDataCreate->createPVScalar(pvDouble));
    - -

    Create a structure with a value and an alarm the hard way

    -
        FieldCreatePtr fieldCreate = getFieldCreate();
    -    PVDataCreatePtr pvDataCreate = getPVDataCreate();
    -    FieldConstPtrArray fields;
    -    StringArray names;
    -    fields.resize(3);
    -    names.resize(3);
    -    fields[0] = fieldCreate->createScalar(pvInt);
    -    fields[1] = fieldCreate->createScalar(pvInt);
    -    fields[2] = fieldCreate->createScalar(pvString);
    -    names[0] = "severity";
    -    names[0] = "status";
    -    names[0] = "message";
    -    StructureConstPtr alarmField =  
    -        fieldCreate->createStructure(names,fields);
    -    fields.resize(2);
    -    names.resize(2);
    -    fields[0] = fieldCreate->createScalar(pvDouble);
    -    fields[1] = alarmField;
    -    names[0] = "value";
    -    names[0] = "alarm";
    -    StructureConstPtr structure =
    -        fieldCreate->createStructure(names,fields);
    -    PVStructurePtr pv = pvDataCreate->createPVStructure(structure);
    - -

    Create an alarm structure the easy way.

    -
        StandardPVFieldPtr standardPVField = getStandardPVField();
    -    PVStructurePtr pv = standardPVField->scalar(pvDouble,"alarm");
    - -

    Create a PVStructure with field name example that has a double value field , -timeStamp, alarm, and display. Do it the easy way.

    -
        StandardPVFieldPtr standardPVField = getStandardPVField();
    -    PVStructurePtr pvStructure = standardPVField->scalar(
    -        pvDouble,"timeStamp,alarm.display");

    pvDataApp/factory

    @@ -2757,8 +3830,6 @@ private:

    TBD

    -
    implemantation
    -
    This should be changed so that capacity can not change.
    toString
    Should this change and also implement ostream operator?
    @@ -3825,6 +4896,642 @@ currently has only one method:

    Channel Access can call this before sending data. It can then pass entire structures if the structure offset bit is set.
    + +

    support for copy and monitor

    +

    copy and monitor are not used in this project. +They are intended for use by pvAccess and by pvAccess servers. +They are provided with this project because the code depends only on +pvData itself. +

    +

    This document describes C++ specific code. + +pvRequest.html +provides a language independent overview of copy and monitor. +

    +

    +NOTE:pvRequest.html must be updated since it is based on an earlier version of pvCopy that +had knowlege of PVRecord. The C++ version was implemented in pvDatabaseCPP +and the Java version on pvIOCJava. +At present only the C++ version of the new API for pvCopy is implemented. +

    +

    Copy provides: +

    +
    createRequest
    +
    + The Channel create methods in pvAccess all have an argument + PVStructure pvRequest.
    + Given an ascii string createRequest creates a PVStructure that provides + a pvData representation of the information from the ascii string. + It is this structure that can be passed to the channel create methods.
    + The information in a pvRequest selects an arbitrarary subset of the + fields in a top level structure that resides in the server. + In addition options can be specified. Both global and field specific + options can be specified. +
    +
    pvCopy
    +
    This is a faculity used by channel providers. + It provides client specific code that manages a copy of an arbitrary + subset of the fields in a top level structure that resides in the + provider. It also allows provider access to options specified + by the client. +
    +
    +Monitor provides: +
    +
    monitor
    +
    This is support code for channel providers that implement channel + monitor. It, together with the queue facility, provides support for + monitor queues. +
    +
    monitorPlugin
    +
    This is support for implementing monitor plugins. + A monitor plugin can be developed that has no knowledge + of pvAccess but only pvData. +
    +
    +

    + +

    support for copy

    +

    copy provides the ability to create a structure that has +a copy of an arbitrary subset of the fields in an existing top level +structure. In addition it allows global options and field specific options. +It has two main components: createRequest and pvCopy. +Given a string createRequest creates a pvRequest, which is a PVStructure +that has the format expected by pvCopy. +

    + +

    createRequest

    +

    This is mainly used by pvAccess clients. Given a request string it creates +a pvRequest structure that can be passed to the pvAccess create methods. +In turn pvAccess passes the pvRequest to a local channel provider which +then passes it to pvCopy. +

    +

    The definition of the public members is:

    +
    +class CreateRequest {
    +...
    +     static CreateRequestPtr create();
    +     virtual PVStructurePtr createRequest(String const &request);
    +     String getMessage();
    +};
    +
    +

    An example of how it is used is:

    +
    +CreateRequestPtr createRequest = CreateRequest::create();
    +PVStructurePtr pvRequest = createRequest->createRequest(request);
    +if(pvRequest==NULL) {
    +    String error = createRequest->getMessage();
    +    // take some action
    +} else {
    +    //success do something
    +}
    +
    +

    pvCopy

    +

    The definition of the public members is:

    +
    +class epicsShareClass PVCopyTraverseMasterCallback
    +{
    +...
    +    virtual void nextMasterPVField(PVFieldPtr const &pvField);
    +};
    +
    +class class epicsShareClass PVCopy
    +{
    +...
    +    static PVCopyPtr create(
    +        PVStructurePtr const &pvMaster,
    +        PVStructurePtr const &pvRequest,
    +        String const & structureName);
    +    PVStructurePtr getPVMaster();
    +    void traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback);
    +    StructureConstPtr getStructure();
    +    PVStructurePtr createPVStructure();
    +    size_t getCopyOffset(PVFieldPtr const  &masterPVField);
    +    size_t getCopyOffset(
    +        PVStructurePtr const  &masterPVStructure,
    +        PVFieldPtr const  &masterPVField);
    +     PVFieldPtr getMasterPVField(std::size_t structureOffset);
    +     void initCopy(
    +        PVStructurePtr const  &copyPVStructure,
    +        BitSetPtr const  &bitSet);
    +     void updateCopySetBitSet(
    +        PVStructurePtr const  &copyPVStructure,
    +        BitSetPtr const  &bitSet);
    +    void updateCopyFromBitSet(
    +        PVStructurePtr const  &copyPVStructure,
    +        BitSetPtr const  &bitSet);
    +    void updateMaster(
    +        PVStructurePtr const  &copyPVStructure,
    +        BitSetPtr const  &bitSet);
    +    PVStructurePtr getOptions(std::size_t fieldOffset);
    +...
    +};
    +
    +where +
    +
    PVCopyTraverseMasterCallback::nextMasterPVField
    +
    + PVCopyTraverseMasterCallback is a callback which must + be implemented by the code that uses pvCopy, normally + the channel provider. It has the single method nextMasterPVField +
    + nextMasterPVField is called for each field in the master + as a result of a call to traverseMaster. +
    +
    create
    +
    + This is the method for creating a PVCopy instance.
    +
    +
    pvMaster
    +
    the top level sructure managed by the server.
    +
    pvRequest
    +
    selects the set of subfields desired + and options for each field.
    +
    structureName
    +
    the name for the top level of any PVStructure created. +
    +
    +
    +
    getPVMaster
    +
    + Gets the top level structure from pvMaster. +
    +
    traverseMaster
    +
    + Traverse all fields of the top level structure of pvMaster. + For each field the callback is called. +
    +
    getStructure
    +
    + Get the introspection interface for a PVStructure for e copy. +
    +
    createPVStructure
    +
    Create a copy instance. + Monitors keep a queue of monitor elements. + Since each element needs a PVStructure, multiple top level structures + will be created. +
    +
    getCopyOffset
    +
    Given a field in pvMaster. + return the offset in copy for the same field. + A value of String::npos means that the copy does not have this field. + Two overloaded methods are provided. The first is called if + the field of master is not a structure. The second is for + subfields of a structure. +
    +
    getMasterPVField
    +
    + Given a offset in the copy get the corresponding field in pvMaster. +
    +
    initCopy
    +
    + Initialize the fields in copyPVStructure + by giving each field the value from the corresponding field in pvMaster. + bitSet will be set to show that all fields are changed. + This means that bit set will have the value {0}. +
    +
    updateCopySetBitSet
    +
    + Set all fields in copyPVStructure to the value of the corresponding field + in pvMaster. Each field that is changed has it's corresponding + bit set in bitSet. +
    +
    updateCopyFromBitSet
    +
    + For each set bit in bitSet set the field in copyPVStructure to the value + of the corrseponding field in pvMaster. +
    +
    updateMaster
    +
    + For each set bit in bitSet set the field in pvMaster to the value + of the corrseponding field in copyPVStructure. + +
    +
    getOptions
    +
    + Get the options for the field at the specified offset. + A NULL is returned if no options were specified for the field. + If options were specified,PVStructurePtr is + a structure with a set of PVString subfields that specify name,value + pairs. name is the subField name and value is the subField value. +
    +
    + + + + +

    support for monitor

    +

    This consists of two components: +

    +
    monitor
    +
    Used by code that implements pvAccess montors.
    +
    monitorPlugin
    +
    Code that provides special semantics for monitors.
    +
    +

    +

    monitor

    +
    +class MonitorElement {
    +    MonitorElement(PVStructurePtr const & pvStructurePtr);
    +    PVStructurePtr pvStructurePtr;
    +    BitSetPtr changedBitSet;
    +    BitSetPtr overrunBitSet;
    +};
    +
    +class Monitor {
    +    virtual Status start() = 0;
    +    virtual Status stop() = 0;
    +    virtual MonitorElementPtr poll() = 0;
    +    virtual void release(MonitorElementPtr const & monitorElement) = 0;
    +};
    +
    +class MonitorRequester : public virtual Requester {
    +    virtual void monitorConnect(Status const & status,
    +        MonitorPtr const & monitor, StructureConstPtr const & structure) = 0;
    +    virtual void monitorEvent(MonitorPtr const & monitor) = 0;
    +    virtual void unlisten(MonitorPtr const & monitor) = 0;
    +};
    +
    +

    monitorElement

    +

    MonitorElement holds the data for one element of a monitor queue. +It has the fields: +

    +
    pvStructurePtr
    +
    A top level structure with data values at the time the monitors occurs.
    +
    changedBitSet
    +
    Shows which fields have changed since the previous monitor.
    +
    overrunBitSet
    +
    Shows which fields have changed more han once since the previous monitor.
    +
    +

    +

    monitorElement queue

    +

    +A queue of monitor elements must be implemented by any channel provider that implements +Channel::createMonitor. +For an example implementation look at pvDatabaseCPP. +It has the following: +

    +typedef Queue<MonitorElement> MonitorElementQueue;
    +typedef std::tr1::shared_ptr<MonitorElementQueue> MonitorElementQueuePtr;
    +
    +class MultipleElementQueue :
    +    public ElementQueue
    +{
    +public:
    +    POINTER_DEFINITIONS(MultipleElementQueue);
    +    virtual ~MultipleElementQueue(){}
    +    MultipleElementQueue(
    +        MonitorLocalPtr const &monitorLocal,
    +        MonitorElementQueuePtr const &queue,
    +        size_t nfields);
    +    virtual void destroy(){}
    +    virtual Status start();
    +    virtual Status stop();
    +    virtual bool dataChanged();
    +    virtual MonitorElementPtr poll();
    +    virtual void release(MonitorElementPtr const &monitorElement);
    +...
    +};
    +
    +

    Monitor

    +

    Monitor must be implemented by any channel provider that implements +Channel::createMonitor. +Remote PVAccess also implements Monitor on the client side. +Note that each client has it's own queue that is not shared with other client. +

    +

    Monitor has the following methods:

    +
    +
    start
    +
    + Start monitoring. + This will result in a an inital monitor that has the current value + of all fields. +
    +
    stop
    +
    + Stop monitoring. +
    +
    poll
    +
    + Called to get a monitor element. + If no new elemants are available then a null pointer is returned. +
    +
    release
    +
    + Release the monotor element. + The caller owns the monitor element between the calls to poll and release. +
    +
    +
    +

    MonitorRequester

    +

    This must be implemented by a pvAccess client. +It has the methods:

    +
    +
    monitorConnect
    +
    + A monitor has either connected of disconnected. +
    +
    monitorEvent
    +
    + A new monitor element is available. +
    +
    unlisten
    +
    + The channel is going away. The client cam no longer access the monitor. +
    +
    + +

    monitorPlugin

    +
    +class MonitorPlugin
    +{
    +    virtual String const & getName() = 0;
    +    virtual bool causeMonitor(
    +        PVFieldPtr const &pvField,
    +        PVStructurePtr const &pvTop,
    +        MonitorElementPtr const &monitorElement) = 0;
    +    virtual void monitorDone(
    +        MonitorElementPtr const &monitorElement);
    +    virtual void startMonitoring();
    +    virtual void stopMonitoring();
    +    virtual void beginGroupPut();
    +    virtual void endGroupPut();
    +};
    +
    +class MonitorPluginCreator
    +{
    +    virtual MonitorPluginPtr create(
    +        FieldConstPtr const &field,
    +        StructureConstPtr const &top,
    +        PVStructurePtr const &pvFieldOptions) = 0;
    +     virtual String const & getName() = 0;
    +}
    +
    +class MonitorPluginManager
    +{
    +    static MonitorPluginManagerPtr get();
    +    bool addPlugin(
    +         String const &pluginName,
    +         MonitorPluginCreatorPtr const &creator);
    +    MonitorPluginCreatorPtr findPlugin(String const &pluginName);
    +    void showNames();
    +};
    +
    +
    +

    MonitorPlugin

    +

    MonitorPlugin must be implemented by the plugin implementation. +It has methods:

    +
    +
    getName
    +
    Get the name of the plugin.
    +
    causeMonitor
    +
    + Should the value of pvField cause a monitor to be raised. + pvField and pvTop are fields in the top level structure + being monitored. monitorElement has the top level structure + for the copy. + The implementation should not modify the fields in the structure + being monitored. + Called with pvTop locked. +
    +
    monitorDone
    +
    + Called just before monitorElement will be given to client. + The plugin can change the data values and bitSets in monitorElement. + Called with pvTop unlocked. +
    +
    startMonitoring
    +
    + Monitoring is starting. +
    +
    stopMonitoring
    +
    + Monitoring is being stopped. +
    +
    beginGroupPut
    +
    + A set of puts is starting. + Called with pvTop locked. +
    +
    endGroupPut
    +
    + The set of puts is complete. + Called with pvTop locked. +
    +
    +

    MonitorPluginCreator

    +

    MonitorPluginCreator must also be implemented by the plugin implementation. +It is called for each field instance that has options of the from +[plugin=name...] where name is the name of the plugin. +Note that a plugin instance will belong to a single client. +It has methods:

    +
    +
    getName
    +
    Get the name of the plugin.
    +
    create
    +
    + Create a new plugin instance. + If the arguments are not compatible with the plugin a NULL shared pointer is + returned.
    + pvFieldOptions is + a structure with a set of PVString subfields that specify name,value + pairs. name is the subField name and value is the subField value.
    + Note that a plugin will below to a single client. +
    +
    +

    MonitorPluginManager

    +

    MonitorPluginManager has the methods:

    +
    +
    get
    +
    + MonitorPluginManager is a singleton. + The first call to get will create the single instance. + Further calls will rerurn the single instance. +
    +
    addPlugin
    +
    + Add a new plugin. +
    +
    findPlugin
    +
    + Find a plugin. A NULL shared pointer is reurned if it has not been added. +
    +
    showNames
    +
    + Show the names of all puugins that have been added. +
    +
    +

    NOTE: +Should the method causeMonitor +have arguments pvField and pvTop +be defined so that they can not be modfied. +This would be posssible if the following was defined: +

    +typedef std::tr1::shared_ptr<const PVField> PVFieldConstPtr;
    +typedef std::tr1::shared_ptr<const PVStructure> PVStructureConstPtr;
    +
    +then the definition for causeMonitor could be: +
    +virtual bool causeMonitor(
    +        PVFieldConstPtr const &pvField,
    +        PVStructureConstPtr const &pvTop,
    +        MonitorElementPtr const &monitorElement) = 0;
    +
    +But just adding these definitions is not sufficent. +In addition all methods defined in pvDataCPP must be checked. +In particular many of the methods in Convert must have +their arguments modified. +Big job. +

    +

    monitorPlugin example

    +

    Example Plugin Overview

    +

    This section describes an example plugin that:

    +
      +
    • Only raises monitors when a field changes value.
      + If no plugin is provided + the default is to raise a monitor when a put is issued to a field.
    • +
    • Optionally a change will not raise a monitor.
      + The change will, however, + appear if a put to another field raise a monitor.
    • +
    +

    As an example assume that a channel provided by pvAccess has a top level structure +that represents a power supply.

    +
    +structure powerSupply
    +    structure alarm
    +    structure timeStamp
    +    structure power
    +       double value
    +       structure alarm
    +       struvture display
    +    structure voltage
    +       double value
    +       structure alarm
    +       struvture display
    +    structure current
    +       double value
    +       structure alarm
    +       struvture display
    +
    +

    A pvAccess client wants to create a monitor on the powerSupply as follows: +The client wants a top level structure that looks like: +

    +structure powerSupply
    +    structure alarm
    +    structure timeStamp
    +    structure power
    +       double value
    +    structure voltage
    +       double value
    +    structure current
    +       double value
    +
    +In addition the client wants monitors to occur only when one of the monitored +fields changes value but not just because a put occured. +Also if only the timeStamp changes value then that should not cause a monitor. +

    +

    The example monitor plugin implements the semantics the +client wants. It can be attached to any field via the following options: +

    +[plugin=onChange,raiseMonitor=value]
    +
    +This plugin will trigger a monitor for the field only if the field changes +value. In addition value equals false means do not raise a monotor +for changes to this field. +But if a change to another field does cause a monitor the change to this field +will be passed to the client. +

    +

    +Assume that the client has already connected to the channel. +The client can then issue the commands:

    +
    +String request("field(alarm[plugin=onChange]");
    +request += ",timeStamp[plugin=onChange,raiseMonitor=false]";
    +request += ",power.value[plugin=onChange";
    +request += ",voltage.value[plugin=onChange";
    +request += ",current.value[plugin=onChange";
    +
    +PVStructurePtr pvRequest = createRequest->createRequest(request);
    +
    +MonitorPtr monitor = channel->createMonitor(monitorRequester,pvRequest);
    +
    +

    Example Plugin Code

    +

    The header file to create the example has the definition:

    +
    +class ExampleMonitorPlugin{
    +public:
    +    static void create();
    +};
    +
    +

    The implementation is:

    +
    +class OnChangePlugin : public MonitorPlugin
    +{
    +public:
    +    virtual ~OnChangePlugin(){}
    +    OnChangePlugin() {}
    +    bool init(
    +        FieldConstPtr const &field,
    +        StructureConstPtr const &top,
    +        PVStructurePtr const &pvFieldOptions)
    +   {
    +        pvField = getPVDataCreate()->createPVField(field);
    +        raiseMonitor = true;
    +        if(pvFieldOptions!=NULL) {
    +            PVStringPtr pvString =
    +                pvFieldOptions->getSubField<PVString>("raiseMonitor");
    +                if(pvString!=NULL) {
    +                    String value = pvString->get();
    +                    if(value.compare("false")==0) raiseMonitor = false;
    +                }
    +        }
    +        return true;
    +   }
    +   virtual String &getName(){return pluginName;}
    +   virtual bool causeMonitor(
    +        PVFieldPtr const &pvNew,
    +        PVStructurePtr const &pvTop,
    +        MonitorElementPtr const &monitorElement)
    +   {
    +       bool isSame = convert->equals(pvNew,pvField);
    +       if(isSame) return false;
    +       convert->copy(pvNew,pvField);
    +       return raiseMonitor;
    +   }
    +private:
    +   PVFieldPtr pvField;
    +   bool raiseMonitor;
    +};
    +class OnChangePluginCreator : public MonitorPluginCreator
    +{
    +public:
    +    virtual String &getName(){return pluginName;}
    +    virtual MonitorPluginPtr create(
    +        FieldConstPtr const &field,
    +        StructureConstPtr const &top,
    +        PVStructurePtr const &pvFieldOptions)
    +   {
    +       OnChangePluginPtr plugin(new OnChangePlugin());
    +       bool result = plugin->init(field,top,pvFieldOptions);
    +       if(!result) return MonitorPluginPtr();
    +       return plugin;
    +   }
    +
    +};
    +
    +void ExampleMonitorPlugin::create()
    +{
    +    static OnChangePluginCreatorPtr plugin;
    +    static Mutex mutex;
    +    Lock xx(mutex);
    +    if(plugin==NULL) {
    +        plugin = OnChangePluginCreatorPtr(new OnChangePluginCreator());
    +        MonitorPluginManager::get()->addPlugin(pluginName,plugin);
    +    }
    +}
    +
    + + diff --git a/documentation/pvDataCPPCookbook.txt b/documentation/pvDataCPPCookbook.txt index 74302dd..6021e09 100644 --- a/documentation/pvDataCPPCookbook.txt +++ b/documentation/pvDataCPPCookbook.txt @@ -18,7 +18,7 @@ getFieldCreate()->createFieldBuilder()-> createStructure(); // create a structure (cntd.) -PVStructure::const_shared_pointer enum_t = +StructureConstPtr enum_t = getFieldCreate()->createFieldBuilder()-> setId("enum_t")-> add("index", pvInt)-> @@ -26,7 +26,7 @@ PVStructure::const_shared_pointer enum_t = createStructure(); // create a structure (cntd.) -PVStructure::const_shared_pointer ntEnum = +StructureConstPtr ntEnum = getFieldCreate()->createFieldBuilder()-> setId("uri:ev4:nt/2012/pwd/NTEnum")-> add("value", enum_t)-> diff --git a/documentation/pvDataCPP_20140501.html b/documentation/pvDataCPP_20140501.html new file mode 100644 index 0000000..8323e2a --- /dev/null +++ b/documentation/pvDataCPP_20140501.html @@ -0,0 +1,5537 @@ + + + + + + EPICS pvDataCPP + + + + + + + + +
    +

    EPICS pvDataCPP

    + + +

    EPICS v4 Working Group, Working Draft, 01-May-2014

    + +
    +
    Latest version:
    +
    pvDataCPP.html +
    +
    This version:
    +
    pvDataCPP_20140501.html +
    +
    Previous version:
    +
    pvDataCPP_20131023.html +
    +
    Editors:
    +
    Marty Kraimer, BNL
    +
    Michael Davidsaver, BNL
    +
    Matej Sekoranja, CosyLab
    +
    + + +
    +
    + +

    Abstract

    + +

    EPICS Version 4 provides efficient +storage, access, and communication, of memory resident structured data. +pvData is the storage compoment. +pvDataCPP is the C++ implementation of pvData. +It is one part of the set of related products in the EPICS +V4 control system programming environment:
    +relatedDocumentsV4.html +

    + + +

    Status of this Document

    + +

    This is the 01-May-2014 version of the C++ implementation of pvData. +

    + +

    RELEASE_NOTES.md provides changes since the last release. +TODO.md describes things to do before the next release. +

    + + +
    +

    Table of Contents

    +
    +
    + +

    Introduction

    + +

    pvData is one of a set of related projects. It describes and implements +data that the other projects support. Thus it is not useful by itself but +understanding pvData is required in order to understand the other projects. The +reader should also become familar with project pvAccess, which is +located via the same sourceforge site as this project.

    + +

    The Java and C++ implementation of pvData implement the same data model but +differ in implementation because of the differences between Java and C++.

    + +

    It is a good idea to read all of pvDataJava.html but read at least the +first two chapters:

    +
    +
    Introduction
    +
    A brief descripton of pvData.
    +
    PVData Meta Language
    +
    A language used to describe data.
    +
    + +

    The material in these two chapters is NOT repeated in this documentation.

    + +

    Doxygen documentation is available at doxygenDoc

    +

    The next section provides some examples of creating and accessing data. +

    +

    This document discusses the following:

    +
    +
    pvDataAPP/pv
    +
    This subdirectory contains all the public interfaces that describe pvData. + The section from Namespace and Memory Management + through Conversion discuss these interfaces. +
    +
    pvDataApp/property
    +
    This section has support for managing "standard" fields. +
    +
    pvDataApp/misc
    +
    This section has support for facilities required by implementation code.
    +
    copy and monitor
    +
    These sections provide pvData support for implementing pvAccess providers.
    +
    + +

    Examples

    +

    This section provides some examples of creating and accessing both introspection and +data interfaces. The first time reader may not understand them but hopefully will get an +idea of how pvData works. After reading the rest of this document the examples will +be much easier to understand. +

    +

    The documentation directory for this project has a file examples.zip. +It has the code for the examples. +After it is unzipped just edit configure/RELEASE.local and then execute make. +

    +

    The examples assume that the following statements have been issued:

    +
    +String builder;
    +FieldCreatePtr fieldCreate = getFieldCreate();
    +PVDataCreatePtr pvDataCreate = getPVDataCreate();
    +StandardFieldPtr standardField = getStandardField();
    +StandardPVFieldPtr standardPVField = getStandardPVField();
    +StructureConstPtr alarm = getStandardField()->alarm();
    +StructureConstPtr timeStamp = getStandardField()->timeStamp();
    +
    +

    These provide access to most of pvData:

    +
    +
    fieldCreate
    +
    This creates instances of introspection objects. + It also provides fieldBuilder, which provides an easier way to create introspection objects. +
    +
    pvDataCreate
    +
    This creates instances of data objects. +
    +
    standardField
    +
    This provides support for introspection obects for standard fields, + Standard fields are alarm, timeStamp, display, enumerated structure, and value alarm. +
    +
    standardPVField
    +
    This provides support for data obects for standard fields, +
    +
    + + +

    Introspection Examples

    +

    The examples all produce a top level structure. +The reason is that top level structures are what pvAccess passes between client and server +and what pvDatabaseCPP supports.

    +

    Three ways to create a structure

    +

    The following is the hardest way to create structure that has a double value field and a time stamp field: +It uses only createField. +

    +
    +    size_t n = 3;
    +    StringArray names;
    +    names.reserve(n);
    +    FieldConstPtrArray fields;
    +    fields.reserve(n);
    +    names.push_back("secsPastEpoch");
    +    fields.push_back(fieldCreate->createScalar(pvLong));
    +    names.push_back("nanoseconds");
    +    fields.push_back(fieldCreate->createScalar(pvInt));
    +    names.push_back("userTag");
    +    fields.push_back(fieldCreate->createScalar(pvInt));
    +    StructureConstPtr timeStamp = fieldCreate->createStructure(names,fields);
    +    size_t ntop = 2;
    +    StringArray topnames;
    +    topnames.reserve(ntop);
    +    FieldConstPtrArray topfields;
    +    topfields.reserve(ntop);
    +    topnames.push_back("value");
    +    topfields.push_back(fieldCreate->createScalar(pvDouble));
    +    topnames.push_back("timeStamp");
    +    topfields.push_back(timeStamp);
    +    StructureConstPtr doubleScalar = fieldCreate->createStructure(topnames,topfields);
    +    builder.clear();
    +    doubleScalar->toString(&builder);
    +    cout << builder << "\n\n";
    +
    +

    Using FieldBuilder the same can be done via:

    +
    +    StructureConstPtr doubleScalarHard =
    +    getFieldCreate()->createFieldBuilder()->
    +        add("value",pvDouble) ->
    +        addNestedStructure("timeStamp")->
    +            setId("time_t")->
    +            add("secsPastEpoch", pvLong)->
    +            add("nanoseconds", pvInt)->
    +            add("userTag", pvInt)->
    +            endNested()->
    +        createStructure();
    +    builder.clear();
    +    doubleScalarHard->toString(&builder);
    +    cout << builder << endl;
    +
    +Both produce: +
    +structure
    +    double value
    +    time_t timeStamp
    +        long secsPastEpoch
    +        int nanoseconds
    +
    +

    An easy way to create a structure with a string array value field and an alarm and time stamp is +via standardField:

    +
    +    StructureConstPtr stringArrayEasy =
    +        getStandardField()->scalarArray(pvString,"alarm,timeStamp");
    +    builder.clear();
    +    stringArrayEasy->toString(&builder);
    +    cout << builder << endl;
    +
    +It produces : +
    +uri:ev4:nt/2012/pwd:NTScalarArray
    +    string[] value
    +    alarm_t alarm
    +        int severity
    +        int status
    +        string message
    +    time_t timeStamp
    +        long secondsPastEpoch
    +        int nanoSeconds
    +        int userTag
    +
    +

    enumerated structure

    +

    An enumerated structure is a structure with two sub-fields: +index, which is an int, and choices, which is an array of string. +The following examples create a structure which has a field names value, which +is an enumerated structure and additional fields. +A hard way to create an structure with an enumerated value field and a time stamp is:

    +
    +    StructureConstPtr enum_t =
    +    getFieldCreate()->createFieldBuilder()->
    +        setId("enum_t")->
    +        add("index", pvInt)->
    +        addArray("choices", pvString)->
    +        createStructure();
    +
    +    StructureConstPtr ntEnumHard =
    +    getFieldCreate()->createFieldBuilder()->
    +        setId("uri:ev4:nt/2012/pwd/NTEnum")->
    +        add("value", enum_t)->
    +        addNestedStructure("timeStamp")->
    +            setId("time_t")->
    +            add("secsPastEpoch", pvLong)->
    +            add("nanoseconds", pvInt)->
    +            add("userTag", pvInt)->
    +            endNested()->
    +        createStructure();
    +    builder.clear();
    +    ntEnumHard->toString(&builder);
    +    cout << builder << endl;
    +
    +It produces: +
    +uri:ev4:nt/2012/pwd/NTEnum
    +    enum_t value
    +        int index
    +        string[] choices
    +    time_t timeStamp
    +        long secsPastEpoch
    +        int nanoseconds
    +        int userTag
    +
    +

    The following is an easy way. Note that it has two additional +fields: alarm and timeStamp:

    +
    +    StructureConstPtr ntEnumEasy = getStandardField()->enumerated("alarm,timeStamp");
    +    builder.clear();
    +    ntEnumEasy->toString(&builder);
    +    cout << builder << endl;
    +
    +It produces: +
    +uri:ev4:nt/2012/pwd:NTEnum
    +    enum_t value
    +        int index
    +        string[] choices
    +    alarm_t alarm
    +        int severity
    +        int status
    +        string message
    +    time_t timeStamp
    +        long secondsPastEpoch
    +        int nanoSeconds
    +        int userTag
    +
    + +

    union example

    +

    The following creates a union and a structure with a union value field:

    + +
    +    UnionConstPtr ntunion =
    +    getFieldCreate()->createFieldBuilder()->
    +        add("doubleValue", pvDouble)->
    +        add("intValue", pvInt)->
    +        add("timeStamp",timeStamp)->
    +        createUnion();
    +    builder.clear();
    +    ntunion->toString(&builder);
    +    cout << builder << endl;
    +
    +    StructureConstPtr unionValue = getStandardField()->regUnion(punion,"alarm,timeStamp");
    +    builder.clear();
    +    ntunion->toString(&builder);
    +    cout << builder << endl;
    +
    +It produces: +
    +union
    +    double doubleValue
    +    int intValue
    +    time_t timeStamp
    +        long secondsPastEpoch
    +        int nanoSeconds
    +        int userTag
    +
    +structure with value field being a union
    +uri:ev4:nt/2012/pwd:NTUnion
    +    union value
    +        double doubleValue
    +        int intValue
    +        time_t timeStamp
    +            long secondsPastEpoch
    +            int nanoSeconds
    +            int userTag
    +    alarm_t alarm
    +        int severity
    +        int status
    +        string message
    +    time_t timeStamp
    +        long secondsPastEpoch
    +        int nanoSeconds
    +        int userTag
    +
    +

    power supply

    +

    The following creates a more complex structure:

    +
    +    StructureConstPtr powerSupply =
    +    getFieldCreate()->createFieldBuilder()->
    +        add("alarm_t",alarm) ->
    +        add("timestamp_t",timeStamp) ->
    +        addNestedStructure("power") ->
    +           add("value",pvDouble) ->
    +           add("alarm",alarm) ->
    +           endNested()->
    +        addNestedStructure("voltage") ->
    +           add("value",pvDouble) ->
    +           add("alarm",alarm) ->
    +           endNested()->
    +        addNestedStructure("current") ->
    +           add("value",pvDouble) ->
    +           add("alarm",alarm) ->
    +           endNested()->
    +        createStructure();
    +    builder.clear();
    +    powerSupply->toString(&builder);
    +    cout << builder << endl;
    +
    +It produces: +
    +structure
    +    alarm_t alarm_t
    +        int severity
    +        int status
    +        string message
    +    time_t timestamp_t
    +        long secondsPastEpoch
    +        int nanoSeconds
    +        int userTag
    +    structure power
    +        double value
    +        alarm_t alarm
    +            int severity
    +            int status
    +            string message
    +    structure voltage
    +        double value
    +        alarm_t alarm
    +            int severity
    +            int status
    +            string message
    +    structure current
    +        double value
    +        alarm_t alarm
    +            int severity
    +            int status
    +            string message
    +
    +

    Data Examples

    +

    The examples all produce a top level structure.

    +

    scalar example

    +
    +    PVStructurePtr doubleValue = getPVDataCreate()->createPVStructure(
    +        getStandardField()->scalar(pvDouble,"alarm,timeStamp"));
    +    PVDoublePtr pvdouble =
    +        doubleValue->getSubField<PVDouble>("value");
    +    pvdouble->put(1e5);
    +    cout << doubleValue->dumpValue(cout) << endl;
    +
    +This produces: +
    +uri:ev4:nt/2012/pwd:NTScalar 
    +    double value 100000
    +    alarm_t alarm
    +        int severity 0
    +        int status 0
    +        string message 
    +    time_t timeStamp
    +        long secondsPastEpoch 0
    +        int nanoSeconds 0
    +        int userTag 0
    +0x607268
    +
    +

    array example

    +
    +    PVStructurePtr doubleArrayValue = getPVDataCreate()->createPVStructure(
    +        getStandardField()->scalarArray(pvDouble,"alarm,timeStamp"));
    +    PVDoubleArrayPtr pvDoubleArray =s
    +         doubleArrayValue->getSubField<PVDoubleArray>("value");
    +    size_t len = 10;
    +    shared_vector<double> xxx(len);
    +    for(size_t i=0; i< len; ++i) xxx[i] = i;
    +    shared_vector<const double> data(freeze(xxx));
    +    pvDoubleArray->replace(data);
    +    cout << doubleArrayValue->dumpValue(cout) << endl;
    +    
    +    shared_vector<const double>  getData = pvDoubleArray->view();
    +    cout << "via getData";
    +    for (size_t i=0; i< len; ++i) cout << " " << getData[i];
    +    cout << endl;
    +
    +This produces: +
    +uri:ev4:nt/2012/pwd:NTScalarArray 
    +    double[] value [0,1,2,3,4,5,6,7,8,9]
    +    alarm_t alarm
    +        int severity 0
    +        int status 0
    +        string message 
    +    time_t timeStamp
    +        long secondsPastEpoch 0
    +        int nanoSeconds 0
    +        int userTag 0
    +0x607268
    +via getData 0 1 2 3 4 5 6 7 8 9
    +
    +

    enumerated example

    +
    +    PVStructurePtr pvntenum = getPVDataCreate()->createPVStructure(
    +         getStandardField()->enumerated("alarm,timeStamp"));
    +    cout << pvntenum->dumpValue(cout) << "\n\n";
    +
    +This produces: +
    +uri:ev4:nt/2012/pwd:NTEnum 
    +    enum_t value
    +        int index 0
    +        string[] choices []
    +    alarm_t alarm
    +        int severity 0
    +        int status 0
    +        string message 
    +    time_t timeStamp
    +        long secondsPastEpoch 0
    +        int nanoSeconds 0
    +        int userTag 0
    +0x607268
    +
    +

    power supply example

    +
    +    StructureConstPtr powerSupply =
    +    getFieldCreate()->createFieldBuilder()->
    +        add("alarm_t",alarm) ->
    +        add("timestamp_t",timeStamp) ->
    +        addNestedStructure("power") ->
    +           add("value",pvDouble) ->
    +           add("alarm",alarm) ->
    +           endNested()->
    +        addNestedStructure("voltage") ->
    +           add("value",pvDouble) ->
    +           add("alarm",alarm) ->
    +           endNested()->
    +        addNestedStructure("current") ->
    +           add("value",pvDouble) ->
    +           add("alarm",alarm) ->
    +           endNested()->
    +        createStructure();
    +    PVStructurePtr pvpowerSupply = getPVDataCreate()->createPVStructure(powerSupply);
    +    cout << pvpowerSupply->dumpValue(cout) << endl;
    +
    +This produces: +
    +structure 
    +    alarm_t alarm_t
    +        int severity 0
    +        int status 0
    +        string message 
    +    time_t timestamp_t
    +        long secondsPastEpoch 0
    +        int nanoSeconds 0
    +        int userTag 0
    +    structure power
    +        double value 0
    +        alarm_t alarm
    +            int severity 0
    +            int status 0
    +            string message 
    +    structure voltage
    +        double value 0
    +        alarm_t alarm
    +            int severity 0
    +            int status 0
    +            string message 
    +    structure current
    +        double value 0
    +        alarm_t alarm
    +            int severity 0
    +            int status 0
    +            string message 
    +0x607268
    +
    +

    union example

    +
    +    PVStructurePtr pvStructure = pvDataCreate->createPVStructure(
    +        standardField->regUnion(
    +            getFieldCreate()->createFieldBuilder()->
    +                add("doubleValue", pvDouble)->
    +                add("intValue", pvInt)->
    +                add("timeStamp",timeStamp)->
    +                createUnion(),
    +            "alarm,timeStamp"));
    +    PVStructurePtr pvTimeStamp =
    +        pvStructure->getSubField<PVUnion>("value")->select<PVStructure>(2);
    +    pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000);
    +    cout << pvStructure->dumpValue(cout) << "\n";
    +    pvStructure->getSubField<PVUnion>("value")->select<PVDouble>(0)->put(1e5);
    +    cout << pvStructure->dumpValue(cout) << "\n\n";
    +
    +This produces: +
    +uri:ev4:nt/2012/pwd:NTUnion
    +    union value
    +        time_t
    +            long secondsPastEpoch 1000
    +            int nanoSeconds 0
    +            int userTag 0
    +    alarm_t alarm
    +        int severity 0
    +        int status 0
    +        string message
    +    time_t timeStamp
    +        long secondsPastEpoch 0
    +        int nanoSeconds 0
    +        int userTag 0
    +0x60a2c8
    +uri:ev4:nt/2012/pwd:NTUnion
    +    union value
    +        double  100000
    +    alarm_t alarm
    +        int severity 0
    +        int status 0
    +        string message
    +    time_t timeStamp
    +        long secondsPastEpoch 0
    +        int nanoSeconds 0
    +        int userTag 0
    +0x60a2c8
    +
    + +

    varient union example

    +
    +    PVStructurePtr pvStructure = pvDataCreate->createPVStructure(
    +        standardField->variantUnion("alarm,timeStamp"));
    +    PVStructurePtr pvTimeStamp =
    +        pvDataCreate->createPVStructure(standardField->timeStamp());
    +    pvStructure->getSubField<PVUnion>("value")->set(pvTimeStamp);
    +    pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000);
    +    cout << pvStructure->dumpValue(cout) << "\n";
    +    pvStructure->getSubField<PVUnion>("value")->set(
    +        pvDataCreate->createPVScalar(pvDouble));
    +    PVDoublePtr pvValue = static_pointer_cast<PVDouble>(
    +        pvStructure->getSubField<PVUnion>("value")->get());
    +    pvValue->put(1e5);
    +    cout << pvStructure->dumpValue(cout) << "\n\n";
    +
    +This produces: +
    +uri:ev4:nt/2012/pwd:NTUnion
    +    any value
    +        time_t
    +            long secondsPastEpoch 1000
    +            int nanoSeconds 0
    +            int userTag 0
    +    alarm_t alarm
    +        int severity 0
    +        int status 0
    +        string message
    +    time_t timeStamp
    +        long secondsPastEpoch 0
    +        int nanoSeconds 0
    +        int userTag 0
    +0x60a2c8
    +uri:ev4:nt/2012/pwd:NTUnion
    +    any value
    +        double  100000
    +    alarm_t alarm
    +        int severity 0
    +        int status 0
    +        string message
    +    time_t timeStamp
    +        long secondsPastEpoch 0
    +        int nanoSeconds 0
    +        int userTag 0
    +0x60a2c8
    +
    + +

    big union example

    +
    +    PVStructurePtr pvStructure = pvDataCreate->createPVStructure(
    +        standardField->regUnion(
    +            getFieldCreate()->createFieldBuilder()->
    +                add("doubleValue", pvDouble)->
    +                addArray("doubleArrayValue",pvDouble)->
    +                addNestedUnion("unionValue") ->
    +                    add("doubleValue", pvDouble)->
    +                    add("alarm",standardField->alarm()) ->
    +                    endNested() ->
    +                addNestedStructure("structValue") ->
    +                    add("doubleValue", pvDouble)->
    +                    addArray("doubleArrayValue",pvDouble)->
    +                    endNested() ->
    +                addNestedUnionArray("unionArrayValue") ->
    +                    add("doubleValue", pvDouble)->
    +                    add("alarm",standardField->alarm()) ->
    +                    endNested() ->
    +                addNestedStructureArray("structArrayValue") ->
    +                    add("doubleValue", pvDouble)->
    +                    addArray("doubleArrayValue",pvDouble)->
    +                    endNested() ->
    +                createUnion(),
    +            "alarm,timeStamp"));
    +    builder.clear();
    +    pvStructure->getStructure()->toString(&builder);
    +    cout << "introspection\n";
    +    cout << builder << endl;
    +    cout << "data\n";
    +    cout << pvStructure->dumpValue(cout) << "\n";
    +    PVUnionPtr pvUnion = pvStructure->getSubField<PVUnion>("value");;
    +    pvUnion->select("doubleValue");
    +    PVDoublePtr pvDouble = pvUnion->get<PVDouble>();
    +    pvDouble->put(1.55);
    +    cout << "select valueDouble\n";
    +    cout << pvStructure->dumpValue(cout) << "\n";
    +    cout << "value = " << pvDouble->get() << "\n";
    +    pvUnion->select("structValue");
    +    pvDouble = pvUnion->get<PVStructure>()->getSubField<PVDouble>("doubleValue");
    +    pvDouble->put(1.65);
    +    cout << "select structValue\n";
    +    cout << pvStructure->dumpValue(cout) << "\n";
    +    cout << "value = " << pvDouble->get() << "\n";
    +
    +This produces: +
    +introspection
    +uri:ev4:nt/2012/pwd:NTUnion
    +    union value
    +        double doubleValue
    +        double[] doubleArrayValue
    +        union unionValue
    +            double doubleValue
    +            alarm_t alarm
    +                int severity
    +                int status
    +                string message
    +        structure structValue
    +            double doubleValue
    +            double[] doubleArrayValue
    +        union[] unionArrayValue
    +            union[]
    +                union
    +                    double doubleValue
    +                    alarm_t alarm
    +                        int severity
    +                        int status
    +                        string message
    +        structure[] structArrayValue
    +            structure[]
    +                structure
    +                    double doubleValue
    +                    double[] doubleArrayValue
    +    alarm_t alarm
    +        int severity
    +        int status
    +        string message
    +    time_t timeStamp
    +        long secondsPastEpoch
    +        int nanoSeconds
    +        int userTag
    +data
    +uri:ev4:nt/2012/pwd:NTUnion
    +    union value
    +        (none)
    +    alarm_t alarm
    +        int severity 0
    +        int status 0
    +        string message
    +    time_t timeStamp
    +        long secondsPastEpoch 0
    +        int nanoSeconds 0
    +        int userTag 0
    +0x60a2c8
    +select valueDouble
    +uri:ev4:nt/2012/pwd:NTUnion
    +    union value
    +        double  1.55
    +    alarm_t alarm
    +        int severity 0
    +        int status 0
    +        string message
    +    time_t timeStamp
    +        long secondsPastEpoch 0
    +        int nanoSeconds 0
    +        int userTag 0
    +0x60a2c8
    +value = 1.55
    +select structValue
    +uri:ev4:nt/2012/pwd:NTUnion
    +    union value
    +        structure
    +            double doubleValue 1.65
    +            double[] doubleArrayValue []
    +    alarm_t alarm
    +        int severity 0
    +        int status 0
    +        string message
    +    time_t timeStamp
    +        long secondsPastEpoch 0
    +        int nanoSeconds 0
    +        int userTag 0
    +0x60a2c8
    +value = 1.65
    +
    + +

    Namespace and Memory Management

    + +

    Namespace

    + +

    All code in project pvDataCPP appears in namespace:

    +
    namespace epics { namespace pvData {
    +     // ...
    +}}
    + +

    Memory Managemment

    + +

    Many pvDataCPP introspection and data objects are designed to be shared. They are +made availiable via std::tr1::shared_ptr. +The following naming convention is used +in typedefs:

    +
    +
    Ptr
    +
    When Ptr appears it stands for std::tr1::shared_ptr. +
    +
    +

    For example:

    +
    +typedef PVScalarValue<boolean> PVBoolean;
    +typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
    +
    + +

    pvDataApp/pv

    + +

    Directory pvDataApp/pv has header files that completely describe pvData. +The implementation is provided in directory pvDataApp/factory. +Test programs appears in testApp/pv.

    + +

    NOTES:

    +
    +
    interface
    +
    The documention uses the word interface. + This is an analogy with how Java defines interface. + C++ does not have interfaces but directory pv defines classes + with public members that are similar to the Java interfaces. Most of the + implementation is in factory.
    +
    Naming Convertions
    +
    The naming convertions for variables, methods, and classes follow the + Java convertions, i. e. class name begin with an upper case letter, + variables and methods begin with a lower case letter.
    +
    + +

    A PVStructure is a field that contains an array of subfields. Each field has +code for accessing the field. The interface for each field is an interface that +extends PVField. Each field also has an introspection interface, which an +extension of Field. The next few sections describes the complete set of C++ +introspection and data interfaces for pvData.

    + +

    Class FieldCreate creates introspection objects. Class PVDataCreate creates +data objects. Class Convert provides a rich set of methods for converting and +copying data between fields.

    + +

    Directory pvDataApp/pv has the following header files:

    +
    +
    pvType.h
    +
    C++ definitions for primitive types.
    +
    pvIntrospect.h
    +
    A complete description of the introspection interfaces.
    +
    pvData.h
    +
    A complete description of the data interfaces.
    +
    convert.h
    +
    A facility that converts between data fields.
    +
    pvSubArrayCopy.h
    +
    This provides a facility that performs array coping between + arrays that have the same type.
    +
    standardField.h
    +
    Provides access to introspection interfaces for standard structures + like timeStamp, alarm, etc.
    +
    standardPVField.h
    +
    Cteates data interfaces for standard data structures like timeStamp, + alarm, etc.
    +
    printer.h
    +
    TBD This is not documented. + In addition toString and dumpValue should be reviewed. +
    +
    + +

    pvType.h

    + +

    This provides C/C++ definitions for the pvData primitive types: boolean, +byte, short, int, long, ubyte,ushort, uint,u long,float, double, and string. +Because pvData is network data, the C++ implementation must implement the +proper semantics for the primitive types.

    + +

    pvType.h provides the proper semantics.

    + +

    It includes the definitions:

    +
    +typedef /*lots of stuff*/ boolean
    +
    +typedef int8_t   int8;
    +typedef int16_t  int16;
    +typedef int32_t  int32;
    +typedef int64_t  int64;
    +typedef uint8_t   uint8;
    +typedef uint16_t  uint16;
    +typedef uint32_t uint32;
    +typedef uint64_t uint64;
    +// float and double are types
    +typedef std::string String;
    +
    +typedef std::vector StringArray;
    +typedef std::tr1::shared_ptr StringArrayPtr;
    +inline String * get(StringArray &value);
    +inline String const * get(StringArray const &value);
    +inline String * get(StringArrayPtr &value);
    +inline String const * get(StringArrayPtr const &value);
    +}
    +inline StringArray & getVector(StringArrayPtr &value);
    +inline StringArray const & getVector(StringArrayPtr const &value);
    +typedef std::vector::iterator StringArray_iterator;
    +typedef std::vector::const_iterator StringArray_const_iterator;
    +
    +typedef String * StringBuilder;
    +
    + +

    where

    +
    +
    boolean
    +
    A c++ bool has the semantics required for boolean. Only the name is + different. C++ code can use either bool or boolean.
    +
    int8,...,uint64
    +
    Integers present a problem because short, int, and long are C++ + reserved words but do not have a well defined number of bits. Thus for + C++ the definitions above are used in C++ code. The above definitions + have worked on all C++ implementations tested at present. If they break + in a future implementation they should be changes via "#ifdef" + preprocessor statements.
    +
    String
    +
    pvData requires that a string be an immutable string that is transfered + over the network as a UTF8 encoded string. Since std::string implements + copy on write semantics, it can be used for support for immutable + strings. It can also be serialized/deserialized as a UTF8 encoded string. + Because it is not a C++ primitive the first letter is capitalized. This + is the same convention the Java implementation uses. + Note that string is treated like a primitive type.
    +
    StringArray definitions
    +
    typedefs are provided for an array of Strings, + which is a std::vector<String>. + This is used by introspection. +
    +
    StringBuilder
    +
    This is used to implement semantics similar to the Java toString + method. It is being replaced by the C++ stream semantics.
    +
    +

    TBD +

    +
    boolean
    +
    Question for Michael. Why isn't the definition of boolean just +
    +typedef uint8_t boolean;
    +    
    +
    StringBuilder
    +
    Should this go away? + Note that it is used for both introspection and data. +
    +
    printer.h
    +
    Not documented. + How should printer, toString, and dumpValue be related? + Also limit number of elements to show if array is large. +
    +
    +

    + +

    pvIntrospect.h

    + +

    This subsection describes pvIntrospect.h This file is quite big so rather +than showing the entire file, it will be described in parts.

    + +

    The primary purpose for pvData is to support network access to structured data. +pvAccess transports top level pvStructures. In addition a pvAccess server holds +a set of pvnames, where each name is a unique name in the local network. +This is also refered to as the channel name. +

    + +

    Given a pvname , it is possible to introspect the types of the associated data +access to data. The reflection and data interfaces are separate because the +data may not be available. For example when a pvAccess client connects to a pvname, +the client library can obtain the reflection information without obtaining any +data. Only when a client issues an I/O request will data be available. This +separation is especially important for arrays and structures so that a client +can discover the type without requiring that a large data array or structure be +transported over the network.

    + +

    Type Description

    + +

    Types are defined as:

    +
    enum Type {
    +    scalar,
    +    scalarArray,
    +    structure,
    +    structureArray,
    +    union_,
    +    unionArray
    +};
    +
    +class TypeFunc {
    +public:
    +    const char* name(Type);
    +    static void toString(StringBuilder buf,const Type type);
    +};
    +
    +enum ScalarType {
    +    pvBoolean,
    +    pvByte, pvShort, pvInt, pvLong,
    +    pvUByte, pvUShort, pvUInt, pvULong,
    +    pvFloat,pvDouble,
    +    pvString;
    +};
    +
    +namespace ScalarTypeFunc {
    +public:
    +    bool isInteger(ScalarType type);
    +    bool isUInteger(ScalarType type);
    +    bool isNumeric(ScalarType type);
    +    bool isPrimitive(ScalarType type);
    +    ScalarType getScalarType(String const &value);
    +    const char* name(ScalarType);
    +    void toString(StringBuilder buf,ScalarType scalarType);
    +    size_t elementSize(ScalarType id);
    +};
    + +

    Type is one of the following:

    +
    +
    scalar
    +
    A scalar of one of the scalar types.
    +
    scalarArray
    +
    An array where every element has the same scalar type.
    +
    structure
    +
    A structure where each field has a name and a type. Within a structure + each field name must be unique but the types can be different.
    +
    structureArray
    +
    An array where each element is a structure. Each element has the same + structure introspection interface.
    +
    union_t
    +
    This is like a structure that has a single subfield. + The type for the subfield can either be any type, which is called a varient union, + of can be one od a specified set of types. + In the data interfaces the type can be changed dynamically. +'
    +
    unionArray
    +
    An array where each element is a union. Each element has the same + union introspection interface.
    +
    + +

    ScalarType is one of the following:

    +
    +
    pvBoolean
    +
    Has the value false or true.
    +
    pvByte
    +
    A signed 8 bit integer.
    +
    pvShort
    +
    A signed 16 bit integer.
    +
    pvInt
    +
    A signed 32 bit integer.
    +
    pvLong
    +
    A signed 64 bit integer.
    +
    pvUByte
    +
    An unsigned 8 bit integer.
    +
    pvUShort
    +
    An unsigned 16 bit integer.
    +
    pvUInt
    +
    An unsigned 32 bit integer.
    +
    pvULong
    +
    An unsigned 64 bit integer.
    +
    pvFloat
    +
    A IEEE float.
    +
    pvDouble
    +
    A IEEE double,
    +
    pvString
    +
    An immutable string.
    +
    + +

    TypeFunction is a set of convenience methods for Type

    +
    +
    name
    +
    Returns the name of the type.
    +
    toString
    +
    Convert the type to a string.
    +
    + +

    ScalarTypeFunction is a set of convenience methods for ScalarType

    +
    +
    isInteger
    +
    Is the scalarType an integer type, i.e. one of pvByte,...pvULong.
    +
    isUInteger
    +
    Is the scalarType an unsigned integer type, i.e. one of + pvUByte,...pvULong
    +
    isNumeric
    +
    Is the scalarType numeric, i.e. pvByte,...,pvDouble.
    +
    isPrimitive
    +
    Is the scalarType primitive, i.e. not pvString
    +
    name
    +
    Returns the name of the scalarType.
    +
    getScalarType
    +
    Given a string of the form String("boolean"),...,String("string") + return the scalarType.
    +
    toString
    +
    Convert the scalar type to a string.
    +
    elementSize
    +
    Returns the size in bytes of an instance of the scalarType.
    +
    + +

    Introspection Description

    + +

    This section describes the reflection interfaces which provide the +following:

    +
    +
    Field
    +
    A field: +
      +
    • Has a Type.
    • +
    • Can be converted to a string.
    • +
    • Can be shared. A reference count is kept. When it becomes 0 the + instance is automatically deleted.
    • +
    +
    +
    Scalar
    +
    A scalar has a scalarType
    +
    ScalarArray
    +
    The element type is a scalarType
    +
    Structure
    +
    Has fields that can be any of the supported types.
    +
    StructureArray
    +
    The field holds an array of structures. Each element has the same + Structure interspection interface. A pvAccess client can only get/put + entire PVStructure elements NOT subfields of array elements.
    +
    Union
    +
    + This has two flavors: a varient union or a union of a fixed set + of types. A PVUnion will have a single subfield. + If the union introspection interface is a varient union then + the single field can be of any type and has the name any. + If the union is not a varient type then the type can be one of + a fixed set of types and a name associated with the type. + The union introspection interface has a field array and a string + array that has the fixed set of types and associated names. +
    +
    UnionArray
    +
    + This is an array of unions. A PVUnionArray is an array + of PVUnions. Each element has the same interspection interface + but the subfield of each element can have a different type. +
    +
    FieldBuilder
    +
    This is a convenience interface that makes it easier to create + top introspection interfaces. +
    +
    FieldCreate
    +
    This is an interface that provides methods to create introspection + interfaces. A factory is provides to create FieldCreate.
    +
    getFieldCreate
    +
    Gets a pointer to the single instance of FieldCreate.
    +
    +

    Field,Scalar,ScalarArray,Structure,StructureArray,Union,UnionArray

    +
    class Field;
    +class Scalar;
    +class ScalarArray;
    +class Structure;
    +class StructureArray;
    +class Union;
    +class UnionArray;
    +
    +typedef std::tr1::shared_ptr<const Field> FieldConstPtr;
    +typedef std::vector<FieldConstPtr> FieldConstPtrArray;
    +typedef std::tr1::shared_ptr<const Scalar> ScalarConstPtr;
    +typedef std::tr1::shared_ptr<const ScalarArray> ScalarArrayConstPtr;
    +typedef std::tr1::shared_ptr<const Structure> StructureConstPtr;
    +typedef std::tr1::shared_ptr<const StructureArray> StructureArrayConstPtr;
    +typedef std::tr1::shared_ptr<const Union> UnionConstPtr;
    +typedef std::tr1::shared_ptr<const UnionArray> UnionArrayConstPtr;
    +
    +
    +class Field :
    +    virtual public Serializable,
    +    public std::tr1::enable_shared_from_this<Field>
    +{
    +public:
    +    POINTER_DEFINITIONS(Field);
    +    virtual ~Field();
    +    Type getType() const{return m_type;}
    +    virtual String getID() const = 0;
    +    virtual void toString(StringBuilder buf) const{toString(buf,0);}
    +    virtual void toString(StringBuilder buf,int indentLevel) const;
    + ...
    +};
    +
    +class Scalar : public Field{
    +public:
    +    POINTER_DEFINITIONS(Scalar);
    +    virtual ~Scalar();
    +    typedef Scalar& reference;
    +    typedef const Scalar& const_reference;
    +
    +    ScalarType getScalarType() const {return scalarType;}
    +    virtual void toString(StringBuilder buf) const{toString(buf,0);}
    +    virtual void toString(StringBuilder buf,int indentLevel) const;
    +    virtual String getID() const;
    +    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
    +    virtual void deserialize(ByteBuffer *buffer, DeserializableContol *control);
    + ...
    +};
    +
    +class ScalarArray : public Field{
    +public:
    +    POINTER_DEFINITIONS(ScalarArray);
    +    typedef ScalarArray& reference;
    +    typedef const ScalarArray& const_reference;
    +
    +    ScalarArray(ScalarType scalarType);
    +    ScalarType  getElementType() const {return elementType;}
    +    virtual void toString(StringBuilder buf) const{toString(buf,0);}
    +    virtual void toString(StringBuilder buf,int indentLevel) const;
    +    virtual String getID() const;
    +    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
    +    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
    + ...
    +};
    +
    +class StructureArray : public Field{
    +public:
    +    POINTER_DEFINITIONS(StructureArray);
    +    typedef StructureArray& reference;
    +    typedef const StructureArray& const_reference;
    +
    +    StructureConstPtr  getStructure() const {return pstructure;}
    +    virtual void toString(StringBuilder buf,int indentLevel=0) const;
    +    virtual String getID() const;
    +    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
    +    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
    + ...
    +};
    +
    +class Structure : public Field {
    +public:
    +    POINTER_DEFINITIONS(Structure);
    +    typedef Structure& reference;
    +    typedef const Structure& const_reference;
    +
    +   std::size_t getNumberFields() const {return numberFields;}
    +   FieldConstPtr getField(String const & fieldName) const;
    +   FieldConstPtr getField(std::size_t index) const;
    +   std::size_t getFieldIndex(String const &fieldName) const;
    +   FieldConstPtrArray const & getFields() const {return fields;}
    +   StringArray const & getFieldNames() const;
    +   String getFieldName(std::size_t fieldIndex) const;
    +   virtual void toString(StringBuilder buf,int indentLevel) const;
    +   virtual String getID() const;
    +   virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
    +   virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
    + ...
    +};
    +
    +class epicsShareClass Union : public Field {
    +public:
    +    POINTER_DEFINITIONS(Union);
    +    static epics::pvData::String DEFAULT_ID;
    +    static epics::pvData::String ANY_ID;
    +    virtual ~Union();
    +    typedef Union& reference;
    +    typedef const Union& const_reference;
    +
    +    std::size_t getNumberFields() const;
    +    FieldConstPtr getField(String const &fieldName) const;
    +    FieldConstPtr getField(std::size_t index);
    +    std::size_t getFieldIndex(String const &fieldName) const;
    +    FieldConstPtrArray const & getFields() const;
    +    StringArray const & getFieldNames() const;
    +    String getFieldName(std::size_t fieldIndex) const;
    +    bool isVariant() const;
    +    virtual void toString(StringBuilder buf) const;
    +    virtual void toString(StringBuilder buf,int indentLevel) const;
    +    virtual String getID() const;
    +    virtual void serialize(
    +        ByteBuffer *buffer, SerializableControl *control) const;
    +    virtual void deserialize(
    +        ByteBuffer *buffer, DeserializableControl *control);
    +    
    +};
    +
    +class epicsShareClass UnionArray : public Field{
    +public:
    +    POINTER_DEFINITIONS(UnionArray);
    +    typedef UnionArray& reference;
    +    typedef const UnionArray& const_reference;
    +    UnionConstPtr  getUnion() const {return punion;}
    +    virtual void toString(StringBuilder buf,int indentLevel=0) const;
    +    
    +    virtual String getID() const;
    +
    +    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
    +    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
    +};
    +
    +
    +
    Constructors
    +
    Note that all constructors are protected or private. The only way to + create instances is via fieldBuilder or fieldCreate. The implementation manages all + storage via shared pointers.
    +
    toString
    +
    Many classes provide this (actually two methods). This method is called + to get a string that uses the metadata syntax described in a previous + section.
    +
    + +

    Field

    +
    +
    getType
    +
    Get the field type.
    +
    getID
    +
    Get an ID for this introspection interface
    +
    + +

    Scalar

    +
    +
    getScalarType
    +
    Get that scalar type.
    +
    getID
    +
    For each scalarType there is one instance of Scalar. The ID for each is + the metadata name for the type, i. e. one of "boolean" , ... , "string". +
    +
    + +

    ScalarArray

    +
    +
    getElementType
    +
    Get the element type.
    +
    getID
    +
    For each elemnetType there is one instance of ScalarArray. The ID for + each is the metadata name for the type, i. e. one of "boolean[]" , ... , + "string[]".
    +
    + +

    StructureArray

    +
    +
    getStructure
    +
    Get the introspection interface that each element shares,
    +
    getID
    +
    This returns the ID[] where ID is the value returned by + structure->getID().
    +
    + +

    Structure

    +
    +
    getNumberFields
    +
    Get the number of immediate subfields.
    +
    getField
    +
    Given a name or an index get the introspection interface for the + field.
    +
    getFieldIndex
    +
    Given a name get the index, within the array returned by the next + method, of the field.
    +
    getFields
    +
    Get the array of introspection interfaces for the field,
    +
    getFieldNames
    +
    Get the array of field names for the subfields.
    +
    getFieldName
    +
    Get the field name for the specified index.
    +
    +

    Union

    +
    +
    getNumberFields
    +
    Get the number of possible field types. + Both getFields and getFieldNames will return an array with getNumberFields elements. + A value of 0 is returned for invarient arrays. +
    +
    getField
    +
    Given a name ot an index the type is returned. + NULL is returned if not found. +
    +
    getFieldIndex
    +
    Get the index for name. -1 is returned if not found. +
    getFields
    +
    Get the array of types.
    +
    getFieldNames
    +
    Get the array of names.
    +
    getFieldName
    +
    Get the name for the specified index.
    +
    isVariant
    +
    returns true if this is varient array and false otherwise. +
    +

    UnionArray

    +
    +
    getUnion
    +
    Get the union interface for each element.
    +
    +

    fieldBuilder and createField

    +
    +class epicsShareClass FieldBuilder :
    +    public std::tr1::enable_shared_from_this<FieldBuilder>
    +{
    +public:
    +    FieldBuilderPtr setId(std::string const & id);
    +    FieldBuilderPtr add(std::string const & name, ScalarType scalarType);
    +    FieldBuilderPtr add(std::string const & name, FieldConstPtr const & field);
    +    FieldBuilderPtr addArray(std::string const & name, ScalarType scalarType);
    +    FieldBuilderPtr addArray(std::string const & name, FieldConstPtr const & element);
    +    StructureConstPtr createStructure();
    +    UnionConstPtr createUnion();
    +    FieldBuilderPtr addNestedStructure(std::string const & name); 
    +    FieldBuilderPtr addNestedUnion(std::string const & name);
    +    FieldBuilderPtr addNestedStructureArray(std::string const & name); 
    +    FieldBuilderPtr addNestedUnionArray(std::string const & name);
    +    FieldBuilderPtr endNested();
    +};
    +
    +class epicsShareClass FieldCreate {
    +public:
    +    static FieldCreatePtr getFieldCreate();
    +    FieldBuilderPtr createFieldBuilder() const;
    +    ScalarConstPtr createScalar(ScalarType scalarType) const;
    +    ScalarArrayConstPtr createScalarArray(ScalarType elementType) const;
    +    StructureArrayConstPtr createStructureArray(StructureConstPtr const & structure) const;
    +    StructureConstPtr createStructure () const;
    +    StructureConstPtr createStructure (
    +        StringArray const & fieldNames,
    +        FieldConstPtrArray const & fields) const;
    +    StructureConstPtr createStructure (
    +    	String const & id,
    +        StringArray const & fieldNames,
    +        FieldConstPtrArray const & fields) const;
    +    UnionConstPtr createUnion (
    +        StringArray const & fieldNames,
    +        FieldConstPtrArray const & fields) const;
    +    UnionConstPtr createUnion (
    +    	String const & id,
    +        StringArray const & fieldNames,
    +        FieldConstPtrArray const & fields) const;
    +    UnionConstPtr createVariantUnion() const;
    +    UnionArrayConstPtr createVariantUnionArray() const;
    +    UnionArrayConstPtr createUnionArray(UnionConstPtr const & punion) const;
    +    StructureConstPtr appendField(
    +        StructureConstPtr const & structure,
    +        String const & fieldName, FieldConstPtr const & field) const;
    +    StructureConstPtr appendFields(
    +        StructureConstPtr const & structure,
    +        StringArray const & fieldNames,
    +        FieldConstPtrArray const & fields) const;
    +    FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const;
    +        
    +};
    +
    +epicsShareExtern FieldCreatePtr getFieldCreate();
    +
    + +

    FieldBuilder

    +

    This is a class that makes it easier to create introspection interfaces. +It is meant to be used via stream input syntax. See the examples that follow the +description of the methods. +

    +
    +
    setID
    +
    This sets an ID for the field, which is the name for the field when it is a subfield. +
    +
    add
    +
    + Add a scalar field. +
    +
    addArray
    +
    + Add a scalarArray field. +
    +
    createStructure
    +
    + Create a structure from the fields that are currently present. +
    +
    createUnion
    +
    + Create a union from the fields that are currently present. +
    +
    addNestedStructure
    +
    + Add a nested structure. This is followed by an arbitrary number of adds + followed by a an endNested. +
    +
    addNestedUnion
    +
    + Add a nested union. This is followed by an arbitrary number of adds + followed by a an endNested. +
    +
    addNestedStructureArray
    +
    + Add a nested structure array. This is followed by an arbitrary number of adds + followed by a an endNested. +
    +
    addNestedUnionArray
    +
    + Add a nested union array. This is followed by an arbitrary number of adds + followed by a an endNested. +
    +
    endNested
    +
    + End current nested structure or union. +
    +
    +

    A simple example is:

    +
    +StructureConstPtr structure =
    +      getFieldCreate()->createFieldBuilder()->
    +      setId("enum_t")->
    +      add("index", pvDouble)->
    +      addArray("choices", pvString)->
    +      createStructure();
    +String builder;
    +structure->toString(&builder);
    +cout << builder << endl;
    +
    +This produces: +
    +enum_t
    +    double index
    +    string[] choices
    +
    +

    Another example is:

    +
    +StructureConstPtr enum_t =
    +getFieldCreate()->createFieldBuilder()->
    +    setId("enum_t")->
    +    add("index", pvInt)->
    +    addArray("choices", pvString)->
    +    createStructure();
    +
    +StructureConstPtr ntEnum =
    +getFieldCreate()->createFieldBuilder()->
    +    setId("uri:ev4:nt/2012/pwd/NTEnum")->
    +    add("value", enum_t)->
    +    addNestedStructure("timeStamp")->
    +        setId("time_t")->
    +        add("secsPastEpoch", pvLong)->
    +        add("nanoseconds", pvInt)->
    +        add("userTag", pvInt)->
    +        endNested()->
    +    createStructure();
    +builder.clear();
    +ntEnum->toString(&builder);
    +cout << builder << endl;
    +
    +This produces: +
    +uri:ev4:nt/2012/pwd/NTEnum
    +    enum_t value
    +        int index
    +        string[] choices
    +    time_t timeStamp
    +        long secsPastEpoch
    +        int nanoseconds
    +        int userTag
    +
    +

    The following example:

    +
    +    UnionConstPtr ntunion =
    +    getFieldCreate()->createFieldBuilder()->
    +        add("doubleValue", pvDouble)->
    +        add("intValue", pvInt)->
    +        addNestedStructure("timeStamp")->
    +            setId("time_t")->
    +            add("secsPastEpoch", pvLong)->
    +            add("nanoseconds", pvInt)->
    +            add("userTag", pvInt)->
    +            endNested()->
    +        createUnion();
    +    builder.clear();
    +    ntunion->toString(&builder);
    +    cout << builder << endl;
    +
    +produces: +
    +union
    +    double doubleValue
    +    int intValue
    +    time_t timeStamp
    +        long secsPastEpoch
    +        int nanoseconds
    +        int userTag
    +
    +

    A powerSupply structure can be created as follows:

    +
    +StructureConstPtr alarm = getStandardField()->alarm();
    +StructureConstPtr timeStamp = getStandardField()->timeStamp();
    +
    +StructureConstPtr powerSupply =
    +getFieldCreate()->createFieldBuilder()->
    +    add("alarm_t",alarm) ->
    +    add("timestamp_t",timeStamp) ->
    +    addNestedStructure("power") ->
    +       add("value",pvDouble) ->
    +       add("alarm",alarm) ->
    +       endNested()->
    +    addNestedStructure("voltage") ->
    +       add("value",pvDouble) ->
    +       add("alarm",alarm) ->
    +       endNested()->
    +    addNestedStructure("current") ->
    +       add("value",pvDouble) ->
    +       add("alarm",alarm) ->
    +       endNested()->
    +    createStructure();
    +builder.clear();
    +powerSupply->toString(&builder);
    +cout << builder << endl;
    +
    +produces: +
    +structure
    +    alarm_t alarm_t
    +        int severity
    +        int status
    +        string message
    +    time_t timestamp_t
    +        long secondsPastEpoch
    +        int nanoSeconds
    +        int userTag
    +    structure power
    +        double value
    +        alarm_t alarm
    +            int severity
    +            int status
    +            string message
    +    structure voltage
    +        double value
    +        alarm_t alarm
    +            int severity
    +            int status
    +            string message
    +    structure current
    +        double value
    +        alarm_t alarm
    +            int severity
    +            int status
    +            string message
    +
    +

    FieldCreate

    +
    +
    getFieldCreate
    +
    Get the single instance of FieldCreate.
    +
    createFieldBuilder
    +
    Create an instance of a FieldBuilder.
    +
    createScalar
    +
    Create a scalar introspection instance.
    +
    createScalarArray
    +
    Create a scalar array introspection instance.
    +
    createStructure
    +
    Create a structure introspection instance. Three methods are provided. + The first creates an empty structure, i. e. a structure with no fields. + The other two are similar. + The only difference is that one provides an ID and the other does + not. The one without will result in ID structure.
    +
    createUnion
    +
    Create a union. There are two methods. + Each has arguments for an array of types and an array of names. + One method has an id. The other results in id = union. +
    +
    createVariantUnion
    +
    + Create a varient union. The id will be any. +
    +
    createUnionArray
    +
    Create a union array. punion is the introspection interface + for each element.
    +
    createVariantUnionArray
    +
    Create a union array where each element is a varient union.
    +
    createStructureArray
    +
    Create a structure array introspection instance.
    +
    appendField
    +
    Create a new structure that is like an existing structure but has + an extra field appended to it. +
    +
    appendFields
    +
    Create a new structure that is like an existing structure but has + extra fields appended to it. +
    +
    deserialize
    +
    Deserialize from given byte buffer.
    +
    +

    TBD +

    +
    toString
    +
    Should support for steams exist.
    +
    ScalarTypeTraits and ScalarTypeID
    +
    These seem to only be used by shared_vector. Do they need to be documented?
    +
    +

    + +

    standardField.h

    + +

    The file standardField.h has a class description for creating or sharing +Field objects for standard fields. For each type of field a method is provided. +Each creates a structure that has a field named "value" and a set of properyt +fields, The property field is a comma separated string of property names of the +following: alarm, timeStamp, display, control, and valueAlarm. An example is +"alarm,timeStamp,valueAlarm". The method with properties creates a structure +with fields named value and each of the property names. Each property field is +a structure defining the property. The details about each property is given in +the section named "Property". For example the call:

    +
        StructureConstPtr example = standardField->scalar(
    +        pvDouble,
    +        "value,alarm,timeStamp");
    + +

    Will result in a Field definition that has the form:

    +
    structure example
    +    double value
    +    alarm_t alarm
    +        int severity
    +        int status
    +        string message
    +    timeStamp_t timeStamp
    +        long secondsPastEpoch
    +        int  nanoSeconds
    +        int userTag
    + +

    In addition there are methods that create each of the property structures, +i.e. the methods named: alarm, .... enumeratedAlarm."

    + +

    standardField.h contains:

    +
    class StandardField;
    +typedef std::tr1::shared_ptr<StandardField> StandardFieldPtr;
    +
    +class StandardField {
    +public:
    +    static StandardFieldPtr getStandardField();
    +    ~StandardField();
    +    StructureConstPtr scalar(ScalarType type,String const &properties);
    +    StructureConstPtr regUnion(
    +        UnionConstPtr const & punion,
    +        String const & properties);
    +    StructureConstPtr variantUnion(String const & properties);
    +    StructureConstPtr scalarArray(
    +        ScalarType elementType, String const &properties);
    +    StructureConstPtr structureArray(
    +        StructureConstPtr const & structure,String const &properties);
    +    StructureConstPtr unionArray(UnionConstPtr const & punion,String const & properties);
    +    StructureConstPtr enumerated();
    +    StructureConstPtr enumerated(String const &properties);
    +    StructureConstPtr alarm();
    +    StructureConstPtr timeStamp();
    +    StructureConstPtr display();
    +    StructureConstPtr control();
    +    StructureConstPtr booleanAlarm();
    +    StructureConstPtr byteAlarm();
    +    StructureConstPtr ubyteAlarm();
    +    StructureConstPtr shortAlarm();
    +    StructureConstPtr ushortAlarm();
    +    StructureConstPtr intAlarm();
    +    StructureConstPtr uintAlarm();
    +    StructureConstPtr longAlarm();
    +    StructureConstPtr ulongAlarm();
    +    StructureConstPtr floatAlarm();
    +    StructureConstPtr doubleAlarm();
    +    StructureConstPtr enumeratedAlarm();
    + ...
    +};
    +
    +
    scalar
    +
    Create a scalar with the specified scalar type and name. A structure + will be created with the first element being a scalar with the specified + scalar type and name value. The other fields in the structure will be the + corresponding property structures.
    +
    regUnion
    +
    A structure + will be created with the first element being a union with the specified + scalar type and name value. The other fields in the structure will be the + corresponding property structures.
    +
    varient`Union
    +
    Create a varient union. A structure + will be created with the first element being a union with the specified + scalar type and name value. The other fields in the structure will be the + corresponding property structures.
    +
    scalarArray
    +
    Create a scalarArray with each element having the specified scalar type + and name. A structure will be created with the first element being a + scalarArray with name value. The other fields in the structure will be + the corresponding property structures.
    +
    structureArray
    +
    Create a structureArray with the specified structure interface and + name. A structure will be created with the first element being a + structureArray with the specified structure interface and name value. The + other fields in the structure will be the corresponding property + structures.
    +
    unionArray
    +
    Create a unionArray with the specified union interface and + name. A structure will be created with the first element being a + unionArray with the specified structure interface and name value. The + other fields in the structure will be the corresponding property + structures.
    +
    structure
    +
    Create a structure with the specified name and fields specified by + numFields and fields. A structure will be created with the first element + being a structure with the name value and fields specified by numFields + and fields. The other fields in the structure will be the corresponding + property structures.
    +
    enumerated
    +
    Create a structure with the specified name and fields for an enumerated + structure. If properties are specified then a structure will be created + with the first element being a structure with the name value and fields + for an enumerated structure. The other fields in the structure will be + the corresponding property structures.
    +
    alarm
    +
    timeStamp
    +
    display
    +
    control
    +
    booleanAlarm
    +
    byteAlarm
    +
    shortAlarm
    +
    intAlarm
    +
    longAlarm
    +
    floatAlarm
    +
    doubleAlarm
    +
    enumeratedAlarm
    +
    The above provide introspection interfaces for standard properties. See + the section on Properties for a description of how these are defined.
    +
    +

    pvData.h

    + +

    This section describes pvData.h This file is quite big so rather than +showing the entire file, it will be described in parts.

    + +

    typedefs

    + +

    These are typedefs for Array and Ptr for the various pvData class +definitions, i.e. typdefs for "std::vector" and "std::tr1::shared_ptr".

    +
    +class PVField;
    +class PVScalar;
    +class PVScalarArray;
    +class PVStructure;
    +class PVStructureArray;
    +
    +
    +typedef std::tr1::shared_ptr<PVField> PVFieldPtr;
    +typedef std::vector<PVFieldPtr> PVFieldPtrArray;
    +typedef std::vector<PVFieldPtr>::iterator PVFieldPtrArray_iterator;
    +typedef std::vector<PVFieldPtr>::const_iterator PVFieldPtrArray_const__iterator;
    +
    +typedef std::tr1::shared_ptr<PVScalar> PVScalarPtr;
    +typedef std::tr1::shared_ptr<PVScalarArray> PVScalarArrayPtr;
    +
    +typedef std::tr1::shared_ptr<PVStructure> PVStructurePtr;
    +typedef std::vector<PVStructurePtr> PVStructurePtrArray;
    +typedef std::vector<PVStructurePtr>::iterator PVStructurePtrArray_iterator;
    +typedef std::vector<PVStructurePtr>::const_iterator PVStructurePtrArray_const__iterator;
    +
    +typedef PVValueArray<PVStructurePtr> PVStructureArray;
    +typedef std::tr1::shared_ptr<PVStructureArray> PVStructureArrayPtr;
    +typedef std::vector<PVStructureArrayPtr> PVStructureArrayPtrArray;
    +typedef std::tr1::shared_ptr<PVStructureArrayPtrArray> PVStructureArrayPtrArrayPtr;
    +
    +typedef std::tr1::shared_ptr<PVUnion> PVUnionPtr;
    +typedef std::vector<PVUnionPtr> PVUnionPtrArray;
    +typedef std::vector<PVUnionPtr>::iterator PVUnionPtrArray_iterator;
    +typedef std::vector<PVUnionPtr>::const_iterator PVUnionPtrArray_const__iterator;
    +
    +typedef PVValueArray<PVUnionPtr> PVUnionArray;
    +typedef std::tr1::shared_ptr<PVUnionArray> PVUnionArrayPtr;
    +typedef std::vector<PVUnionArrayPtr> PVUnionArrayPtrArray;
    +typedef std::tr1::shared_ptr<PVUnionArrayPtrArray> PVUnionArrayPtrArrayPtr;
    +
    +class PVDataCreate;
    +typedef std::tr1::shared_ptr<PVDataCreate> PVDataCreatePtr;
    +
    +
    +/**
    + * typedefs for the various possible scalar types.
    + */
    +typedef PVScalarValue<boolean> PVBoolean;
    +typedef PVScalarValue<int8> PVByte;
    +typedef PVScalarValue<int16> PVShort;
    +typedef PVScalarValue<int32> PVInt;
    +typedef PVScalarValue<int64> PVLong;
    +typedef PVScalarValue<uint8> PVUByte;
    +typedef PVScalarValue<uint16> PVUShort;
    +typedef PVScalarValue<uint32> PVUInt;
    +typedef PVScalarValue<uint64> PVULong;
    +typedef PVScalarValue<float> PVFloat;
    +typedef PVScalarValue<double> PVDouble;
    +class PVString;
    +typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
    +typedef std::tr1::shared_ptr<PVByte> PVBytePtr;
    +typedef std::tr1::shared_ptr<PVShort> PVShortPtr;
    +typedef std::tr1::shared_ptr<PVInt> PVIntPtr;
    +typedef std::tr1::shared_ptr<PVLong> PVLongPtr;
    +typedef std::tr1::shared_ptr<PVUByte> PVUBytePtr;
    +typedef std::tr1::shared_ptr<PVUShort> PVUShortPtr;
    +typedef std::tr1::shared_ptr<PVUInt> PVUIntPtr;
    +typedef std::tr1::shared_ptr<PVULong> PVULongPtr;
    +typedef std::tr1::shared_ptr<PVFloat> PVFloatPtr;
    +typedef std::tr1::shared_ptr<PVDouble> PVDoublePtr;
    +typedef std::tr1::shared_ptr<PVString> PVStringPtr;
    +
    +/**
    + * Definitions for the various scalarArray types.
    + */
    +typedef PVValueArray<boolean> PVBooleanArray;
    +typedef PVValueArray<int8> PVByteArray;
    +typedef PVValueArray<int16> PVShortArray;
    +typedef PVValueArray<int32> PVIntArray;
    +typedef PVValueArray<int64> PVLongArray;
    +typedef PVValueArray<uint8> PVUByteArray;
    +typedef PVValueArray<uint16> PVUShortArray;
    +typedef PVValueArray<uint32> PVUIntArray;
    +typedef PVValueArray<uint64> PVULongArray;
    +typedef PVValueArray<float> PVFloatArray;
    +typedef PVValueArray<double> PVDoubleArray;
    +typedef PVValueArray<String> PVStringArray;
    +
    +typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
    +typedef std::tr1::shared_ptr<PVByteArray> PVByteArrayPtr;
    +typedef std::tr1::shared_ptr<PVShortArray> PVShortArrayPtr;
    +typedef std::tr1::shared_ptr<PVIntArray> PVIntArrayPtr;
    +typedef std::tr1::shared_ptr<PVLongArray> PVLongArrayPtr;
    +typedef std::tr1::shared_ptr<PVUByteArray> PVUByteArrayPtr;
    +typedef std::tr1::shared_ptr<PVUShortArray> PVUShortArrayPtr;
    +typedef std::tr1::shared_ptr<PVUIntArray> PVUIntArrayPtr;
    +typedef std::tr1::shared_ptr<PVULongArray> PVULongArrayPtr;
    +typedef std::tr1::shared_ptr<PVFloatArray> PVFloatArrayPtr;
    +typedef std::tr1::shared_ptr<PVDoubleArray> PVDoubleArrayPtr;
    +typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
    +
    + +

    PVField

    + +

    PVField is the base interface for accessing data. A data structure consists +of a top level PVStructure. Every field of every structure of every top level +structure has a PVField associated with it.

    +
    +class PostHandler
    +{
    +public:
    +    POINTER_DEFINITIONS(PostHandler);
    +    virtual ~PostHandler(){}
    +    virtual void postPut() = 0;
    +};
    +
    +class PVField
    +: virtual public Serializable,
    +  public std::tr1::enable_shared_from_this<PVField>
    +{
    +public:
    +   POINTER_DEFINITIONS(PVField);
    +   virtual ~PVField();
    +   String getFieldName() const ;
    +   String getFullName() const;
    +   std::size_t getFieldOffset() const;
    +   std::size_t getNextFieldOffset() const;
    +   std::size_t getNumberFields() const;
    +   bool isImmutable() const;
    +   virtual void setImmutable();
    +   const FieldConstPtr & getField() const ;
    +   PVStructure * getParent() const 
    +   void postPut();
    +   void setPostHandler(PostHandlerPtr const &postHandler);
    +   virtual bool equals(PVField &pv);
    +   virtual void toString(StringBuilder buf) ;
    +   virtual void toString(StringBuilder buf,int indentLevel);
    +   std::ostream& dumpValue(std::ostream& o) const;
    + ...
    +}
    +std::ostream& operator<<(std::ostream& o, const PVField& f);
    +
    + +

    The public methods for PVField are:

    +
    +
    ~PVField
    +
    Destructor. Since shared pointers are used it should never be called by + user code.
    +
    getFieldName
    +
    Get the field name. If the field is a top level structure the field + name will be an empty string.
    +
    getFullName
    +
    Fully expand the name of this field using the + names of its parent fields with a dot '.' seperating + each name. +
    +
    getFieldOffset
    +
    Get offset of the PVField field within top level structure. Every field + within the PVStructure has a unique offset. The top level structure has + an offset of 0. The first field within the structure has offset equal to + 1. The other offsets are determined by recursively traversing each + structure of the tree.
    +
    getNextFieldOffset
    +
    Get the next offset. If the field is a scalar or array field then this + is just offset + 1. If the field is a structure it is the offset of the + next field after this structure. Thus (nextOffset - offset) is always + equal to the total number of fields within the field.
    +
    getNumberFields
    +
    Get the total number of fields in this field. This is nextFieldOffset - + fieldOffset.
    +
    isImmutable
    +
    Is the field immutable?
    +
    setImmutable
    +
    Make the field immutable. Once a field is immutable it can never be + changed since there is no method to again make it mutable. This is an + important design decision since it allows immutable array fields to share + the internal primitive data array.
    +
    getField
    +
    Get the reflection interface for the data.
    +
    getParent
    +
    Get the interface for the parent or null if this is the top level + PVStructure.
    +
    postPut
    +
    If a postHandler is registered it is called otherwise no action is + taken.
    +
    setPostHandler
    +
    Set the postHandler for the record. Only a single handler can be + registered. + PostHandler is a class that must be implemented by any code that calls setPostHandler. + It's single virtual method. postPut is called whenever PVField::postPut is called. +
    +
    equals
    +
    Compare this field with another field. The result will be true only if + the fields have exactly the same field types and if the data values are + equal.
    +
    toString
    +
    Converts the field data to a string. This is mostly for debugging + purposes.
    +
    dumpValue
    +
    Method for streams I/O.
    +
    +

    TBD + +

    +
    toString and dumpValue
    +
    toString is broken
    + Should toString go away or be changed? +
    +
    +

    + +

    PVScalar

    + +

    This is the base class for all scalar data.

    +
    class PVScalar : public PVField {
    +public:
    +    POINTER_DEFINITIONS(PVScalar);
    +    virtual ~PVScalar();
    +    typedef PVScalar &reference;
    +    typedef const PVScalar& const_reference;
    +    const ScalarConstPtr getScalar() const ;
    +    template<typename T>
    +    T getAs() const;
    + ...
    +}
    + +

    where

    +
    +
    getScalar
    +
    Get the introspection interface for the PVScalar.
    +
    getAs
    +
    Convert and return the scalar value in the requested type. + Result type is determined from the function template argument + which must be one of the ScalarType enums. + For example: +
    +uint32 val = pv->getAs();
    +
    +
    + +
    + +

    PVScalarValue

    + +

    The interfaces for primitive data types are:

    +
    template<typename T>
    +class PVScalarValue : public PVScalar {
    +public:
    +    POINTER_DEFINITIONS(PVScalarValue);
    +    typedef T value_type;
    +    typedef T* pointer;
    +    typedef const T* const_pointer;
    +    static const ScalarType typeCode;
    +
    +    virtual ~PVScalarValue() {}
    +    virtual T get() const = 0;
    +    virtual void put(T value) = 0;
    +    std::ostream& dumpValue(std::ostream& o) const;
    +    void operator>>=(T& value) const;
    +    void operator<<=(T value);
    +    template<typename T1>
    +    T1 getAs() const;
    +    template<typename T1>
    +    void putFrom(T1 val);
    + ...
    +}
    +
    +typedef PVScalarValue<boolean> PVBoolean;
    +typedef PVScalarValue<int8> PVByte;
    +typedef PVScalarValue<int16> PVShort;
    +typedef PVScalarValue<int32> PVInt;
    +typedef PVScalarValue<int64> PVLong;
    +typedef PVScalarValue<uint8> PVUByte;
    +typedef PVScalarValue<uint16> PVUShort;
    +typedef PVScalarValue<uint32> PVUInt;
    +typedef PVScalarValue<uint64> PVULong;
    +typedef PVScalarValue<float> PVFloat;
    +typedef PVScalarValue<double> PVDouble;
    +typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
    +typedef std::tr1::shared_ptr<PVByte> PVBytePtr;
    +typedef std::tr1::shared_ptr<PVShort> PVShortPtr;
    +typedef std::tr1::shared_ptr<PVInt> PVIntPtr;
    +typedef std::tr1::shared_ptr<PVLong> PVLongPtr;
    +typedef std::tr1::shared_ptr<PVUByte> PVUBytePtr;
    +typedef std::tr1::shared_ptr<PVUShort> PVUShortPtr;
    +typedef std::tr1::shared_ptr<PVUInt> PVUIntPtr;
    +typedef std::tr1::shared_ptr<PVULong> PVULongPtr;
    +typedef std::tr1::shared_ptr<PVFloat> PVFloatPtr;
    +typedef std::tr1::shared_ptr<PVDouble> PVDoublePtr;
    +
    +
    +// PVString is special case, since it implements SerializableArray
    +class PVString : public PVScalarValue<String>, SerializableArray {
    +public:
    +    virtual ~PVString() {}
    + ...
    +};
    +
    +
    +
    + +

    where

    +
    +
    get
    +
    Get the value stored in the object.
    +
    put
    +
    Change the value stored in the object.
    +
    dumpValue
    +
    ostream method.
    +
    operator>>=
    +
    get operator. For example: +
    +double value;
    +PVDoublePtr pvDouble;
    +...
    +pvDouble>>=value;
    +
    +
    +
    operator<<=
    +
    put operator. For example: +
    +double value;
    +PVDoublePtr pvDouble;
    +...
    +pvDouble<<=value;
    +
    +
    +
    getAs
    +
    Convert and return the scalar value in the requested type. + Result type is determined from the function template argument + which must be one of the ScalarType enums. + For example: +
    +int32 val = pv->getAs<pvInt>>();
    +
    +
    +
    putFrom
    +
    Convert the scalar value in the requested type + and put the value into this PVScalarValue. + The source type is determined from the function template argument + which must be one of the ScalarType enums. + For example: +
    +int32 val;
    +pv->putFrom<pvInt>(val);
    +
    +
    +
    +

    TBD +

    +
    dumpvalue
    +
    replace this with ostream operator<<
    +
    +

    + +

    PVUnion

    +

    A PVUnion has a single subfield. +The Union introspection interface determines the possible +field types for the subfield. +If it is a varient union then any type is allowed and the +subfield name is normally any. +If it is not a varient union that the Union interface determines +the possible field types and names.

    +
    +class PVUnion : public PVField
    +{
    +public:
    +    POINTER_DEFINITIONS(PVUnion);
    +    virtual ~PVUnion();
    +    UnionConstPtr getUnion() const;
    +    PVFieldPtr get() const;
    +    
    +    template<typename PVT>
    +    std::tr1::shared_ptr<PVT> get() const {
    +        return std::tr1::dynamic_pointer_cast<PVT>(get());
    +    }
    +
    +   PVFieldPtr select(int32 index);
    +
    +    template<typename PVT>
    +    std::tr1::shared_ptr<PVT> select(int32 index) {
    +        return std::tr1::dynamic_pointer_cast<PVT>(select(index));
    +    }
    +
    +    PVFieldPtr select(String const & fieldName);
    +
    +    template<typename PVT>
    +    std::tr1::shared_ptr<PVT> select(String const & fieldName) {
    +        return std::tr1::dynamic_pointer_cast<PVT>(select(fieldName));
    +    }
    +
    +    int32 getSelectedIndex() const;
    +    String getSelectedFieldName() const;
    +    void set(PVFieldPtr const & value);
    +    void set(int32 index, PVFieldPtr const & value);
    +    void set(String const & fieldName, PVFieldPtr const & value);
    +    virtual void serialize(
    +        ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
    +    PVUnion(UnionConstPtr const & punion);
    +};
    +
    +
    +
    getUnion
    +
    Get the introspection interface.
    +
    get
    +
    Get the curent field. A template version does the conversion. + NULL is returned if no field is selected or if the caller +' asks for the wrong type. +
    +
    select
    +
    Select and get the field by index or name. + A templated version does the conversion. + If the index is out of bounds or the name is not valid this methods throws an exception. + The method set should be used for variant unions rather than select. +
    +
    getSelectedIndex
    +
    Get the index of the currently selected field.
    +
    getSelectedFieldName
    +
    Get the name of the currently selected field.
    +
    set
    +
    Set the field to the argument. If invalid type an exception is thrown. + This should always work for a variant union. +
    +
    + +

    PVArray

    + +

    PVArray is the base interface for all the other PV Array interfaces. It +extends PVField and provides the additional methods:

    +
    +class PVArray : public PVField, public SerializableArray {
    +public:
    +    POINTER_DEFINITIONS(PVArray);
    +    virtual ~PVArray();
    +    virtual void setImmutable();
    +    std::size_t getLength() const;
    +    virtual void setLength(std::size_t length);
    +    std::size_t getCapacity() const;
    +    bool isCapacityMutable() const;
    +    void setCapacityMutable(bool isMutable);
    +    virtual void setCapacity(std::size_t capacity) = 0;
    +    virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const;
    + ...
    +};
    +
    +
    setImmutable
    +
    Set the data immutable. Note that this is permanent since there is no + methods to make it mutable.
    +
    getLength
    +
    Get the current length. This is less than or equal to the capacity.
    +
    setLength
    +
    Set the length. If the PVField is not mutable then an exception is + thrown. If this is greater than the capacity setCapacity is called.
    +
    getCapacity
    +
    Get the capacity, i.e. this is the size of the underlying data + array.
    +
    setCapacity
    +
    Set the capacity. The semantics are implementation dependent but + typical semantics are as follows: If the capacity is not mutable an + exception is thrown. A new data array is created and data is copied from + the old array to the new array.
    +
    isCapacityMutable
    +
    Is the capacity mutable
    +
    setCapacityMutable
    +
    Specify if the capacity can be changed.
    +
    setCapacity
    +
    Set the capaciity.
    +
    dumpValue
    +
    ostream method
    +
    +

    + + +

    PVScalarArray

    + +

    PVScalarArray is the base class for scalar array data. PVValueArray is a +templete for the various scalar array data classes. There is a class for each +possible scalar type, i. e. PVBooleanArray, ..., PVStringArray.

    +
    +class PVScalarArray : public PVArray {
    +public:
    +    POINTER_DEFINITIONS(PVScalarArray);
    +    virtual ~PVScalarArray();
    +    typedef PVScalarArray &reference;
    +    typedef const PVScalarArray& const_reference;
    +
    +    const ScalarArrayConstPtr getScalarArray() const ;
    +
    +    template<typename T>
    +    void getAs(shared_vector<const T>& out) const
    +
    +    template<typename T>
    +    void putFrom(const shared_vector<const T>& inp)
    +
    +    void assign(PVScalarArray& pv);
    + ...
    +}
    +
    + +

    where

    +
    +
    getScalarArray
    +
    Get the introspection interface.
    +
    getAs
    +
    Fetch the current value and convert to the requested type. + A copy is made if the requested type does not match the element type. + If the types do match then no copy is made. +
    +
    putFrom
    +
    Assign the given value after conversion. + A copy and element-wise conversion is performed unless the element type + of the PVScalarArray matches the type of the provided data. + If the types do match then a new refernce to the provided data is kept. +
    +
    assign
    +
    Assign the given PVScalarArray's value. + A copy and element-wise conversion is performed unless the element type + of the PVScalarArray matches the type of the provided data. + If the types do match then a new refernce to the provided data is kept. +
    +
    + +

    PVStructure

    + +

    The interface for a structure is:

    +
    class PVStructure : public PVField,public BitSetSerializable {
    +public:
    +    POINTER_DEFINITIONS(PVStructure);
    +    virtual ~PVStructure();
    +    typedef PVStructure & reference;
    +    typedef const PVStructure & const_reference;
    +
    +    virtual void setImmutable();
    +    StructureConstPtr getStructure() const;
    +    const PVFieldPtrArray & getPVFields() const;
    +    PVFieldPtr getSubField(String const &fieldName) const;
    +
    +    template<typename PVT>
    +    std::tr1::shared_ptr<PVT> getSubField(String const &fieldName) const
    +
    +    PVFieldPtr getSubField(std::size_t fieldOffset) const;
    +
    +    template<typename PVT>
    +    std::tr1::shared_ptr<PVT> getSubField(std::size_t fieldOffset) const
    +
    +    virtual void serialize(
    +        ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
    +    virtual void deserialize(
    +        ByteBuffer *pbuffer,DeserializableControl *pflusher);
    +    virtual void serialize(ByteBuffer *pbuffer,
    +        SerializableControl *pflusher,BitSet *pbitSet) const;
    +    virtual void deserialize(ByteBuffer *pbuffer,
    +        DeserializableControl*pflusher,BitSet *pbitSet);
    +    PVStructure(StructureConstPtr const & structure);
    +    PVStructure(StructureConstPtr const & structure,PVFieldPtrArray const & pvFields);
    +    virtual std::ostream& dumpValue(std::ostream& o) const;
    +};
    + +

    where

    +
    +
    getStructure
    +
    Get the introspection interface for the structure.
    +
    getPVFields
    +
    Returns the array of subfields. The set of subfields must all have + different field names.
    +
    getSubField(String fieldName)
    +
    + Get a subField of a field.d + A non-null result is + returned if fieldName is a field of the PVStructure. The fieldName can be + of the form name.name... + If the field does not exist the a Ptr to a NULL value is returned + without any error message being generated. +
    + Note that the template version replaces getBooleanField, etc.
    +
    +
    getSubField(int fieldOffset)
    +
    Get the field located a fieldOffset, where fieldOffset is relative to + the top level structure. This returns null if the specified field is not + located within this PVStructure. +
    +
    dumpValue
    +
    Method for streams I/O.
    +
    +

    TBD +

    +
    dumpvalue
    +
    replace this with ostream operator<<
    +
    +

    + + +

    PVValueArray

    + +

    This is a template class plus instances for PVBooleanArray, ..., +PVStringArray.

    +
    template<typename T>
    +class PVValueArray : public detail::PVVectorStorage<T,PVScalarArray> 
    +{
    +public:
    +    POINTER_DEFINITIONS(PVValueArray);
    +    typedef T  value_type;
    +    typedef T* pointer;
    +    typedef const T* const_pointer;
    +    typedef ::epics::pvData::shared_vector<T> svector;
    +    typedef ::epics::pvData::shared_vector<const T> const_svector;
    +    static const ScalarType typeCode;
    +
    +    virtual ~PVValueArray() {}
    +    std::ostream& dumpValue(std::ostream& o) const;
    +    std::ostream& dumpValue(std::ostream& o, size_t index) const;
    +    // inherited from PVVectorStorage
    +    const_svector view();
    +    void swap(const_svector& other);
    +    void replace(const const_svector& next);
    +    svector reuse();
    +    ...
    +};
    +
    + +

    where

    +
    +
    dumpValue
    +
    Method for streams I/O.
    +
    view
    +
    Fetch a read-only view of the current array data.
    +
    swap
    +
    + Callers must ensure that postPut() is called after the last swap() operation. + Before you call this directly, consider using the reuse(), or replace() methods. +
    +
    replace
    +
    Discard current contents and replaced with the provided.
    +
    reuse
    +
    Remove and return the current array data or an unique copy if shared.
    +
    +

    TBD +

    +
    dumpvalue
    +
    replace this with ostream operator<<
    +
    Check for completeness
    +
    Michael should check that PVScalarArray and PVValueArray + have the correct set of methods and that the descriptions are correct.
    +
    +

    + +

    PVStructureArray

    + +

    The interface for an array of structures is:

    +
    +template<>
    +class PVValueArray<PVStructurePtr> : public detail::PVVectorStorage<PVStructurePtr,PVArray>
    +{
    +public:
    +    POINTER_DEFINITIONS(PVStructureArray);
    +    typedef PVStructurePtr  value_type;
    +    typedef PVStructurePtr* pointer;
    +    typedef const PVStructurePtr* const_pointer;
    +    typedef PVStructureArray &reference;
    +    typedef const PVStructureArray& const_reference;
    +    typedef ::epics::pvData::shared_vector<PVStructurePtr> svector;
    +    typedef ::epics::pvData::shared_vector<const PVStructurePtr> const_svector;
    +
    +    virtual ~PVStructureArray() {}
    +    virtual size_t getLength();
    +    virtual size_t getCapacity();
    +    virtual void setCapacity(size_t capacity);
    +    virtual void setLength(std::size_t length);
    +    virtual StructureArrayConstPtr getStructureArray() const ;
    +    virtual std::size_t append(std::size_t number);
    +    virtual bool remove(std::size_t offset,std::size_t number);
    +    virtual void compress();
    +    virtual void serialize(ByteBuffer *pbuffer,
    +    virtual const_svector view() const;
    +    virtual void swap(const_svector &other);
    +    virtual void replace(const const_svector &other);
    +        SerializableControl *pflusher) const;
    +    virtual void deserialize(ByteBuffer *buffer,
    +        DeserializableControl *pflusher);
    +    virtual void serialize(ByteBuffer *pbuffer,
    +        SerializableControl *pflusher, std::size_t offset, std::size_t count) const ;
    +    virtual std::ostream& dumpValue(std::ostream& o) const;
    +    virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const;
    +    // inherited from PVVectorStorage
    +    const_svector view();
    +    void swap(const_svector& other);
    +    void replace(const const_svector& next);
    +    svector reuse();
    + ...
    +}
    + +

    where

    +
    +
    getStructureArray
    +
    Get the introspection interface shared by each element.
    +
    append
    +
    Create new elements and append them to the end of the array. It returns + the index of the first new element.
    +
    remove
    +
    Remove the specfied set of elements. It returns (false,true) if the + elements (were not, were) removed. It will not removed any elements + unless all requested elements exist or are null. Note that this deletes + the element and sets the array element to null. It does not change the + array capacity.
    +
    compress
    +
    This moves all null elements and then changes the array capacity. When + done there are no null elements.
    +
    + +

    The other methods are similar to the methods for other array types. + See PVArray above for details.

    + +

    PVUnionArray

    +

    The interface for an array of unions is:

    +
    +template&ly;&gt;
    +class epicsShareClass PVValueArray&ly;PVUnionPtr&gt; : public detail::PVVectorStorage&ly;PVUnionPtr,PVArray&gt;
    +{
    +    typedef detail::PVVectorStorage&ly;PVUnionPtr,PVArray&gt; base_t;
    +public:
    +    POINTER_DEFINITIONS(PVUnionArray);
    +    typedef PVUnionPtr  value_type;
    +    typedef PVUnionPtr* pointer;
    +    typedef const PVUnionPtr* const_pointer;
    +    typedef PVUnionArray &reference;
    +    typedef const PVUnionArray& const_reference;
    +
    +    //TODO: full namespace can be removed along with local typedef 'shared_vector'
    +    typedef ::epics::pvData::shared_vector&ly;PVUnionPtr&gt; svector;
    +    typedef ::epics::pvData::shared_vector&ly;const PVUnionPtr&gt; const_svector;
    +    
    +    virtual ~PVValueArray() {}
    +
    +    virtual size_t getLength() const;
    +    virtual size_t getCapacity() const;
    +    virtual void setCapacity(size_t capacity);
    +    virtual void setLength(std::size_t length);
    +    UnionArrayConstPtr getUnionArray() const;
    +    virtual std::size_t append(std::size_t number);
    +    virtual bool remove(std::size_t offset,std::size_t number);
    +    virtual void compress();
    +    virtual const_svector view() const;
    +    virtual void swap(const_svector &other);
    +    virtual void replace(const const_svector &other);
    +    virtual void serialize(ByteBuffer *pbuffer,
    +        SerializableControl *pflusher) const;
    +    virtual void deserialize(ByteBuffer *buffer,
    +        DeserializableControl *pflusher);
    +    virtual void serialize(ByteBuffer *pbuffer,
    +        SerializableControl *pflusher, std::size_t offset, std::size_t count) const ;
    +    virtual std::ostream& dumpValue(std::ostream& o) const;
    +    virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const;
    +};
    +
    +

    where

    +
    +
    getUnionArray
    +
    Get the introspection interface shared by each element.
    +
    append
    +
    Create new elements and append them to the end of the array. It returns + the index of the first new element.
    +
    remove
    +
    Remove the specfied set of elements. It returns (false,true) if the + elements (were not, were) removed. It will not removed any elements + unless all requested elements exist or are null. Note that this deletes + the element and sets the array element to null. It does not change the + array capacity.
    +
    compress
    +
    This moves all null elements and then changes the array capacity. When + done there are no null elements.
    +
    + +

    The other methods are similar to the methods for other array types. + See PVArray above for details.

    + +

    PVDataCreate

    + +

    PVDataCreate is an interface that provides methods that create PVField +interfaces. A factory is provided that creates PVDataCreate.

    +
    class PVDataCreate {
    +public:
    +    static PVDataCreatePtr getPVDataCreate();
    +
    +    PVFieldPtr createPVField(FieldConstPtr const & field);
    +    PVFieldPtr createPVField(PVFieldPtr const & fieldToClone);
    +
    +    PVScalarPtr createPVScalar(ScalarConstPtr const & scalar);
    +    PVScalarPtr createPVScalar(ScalarType scalarType);
    +    PVScalarPtr createPVScalar(PVScalarPtr const & scalarToClone);
    +    template<typename PVT>
    +    std::tr1::shared_ptr<PVT> createPVScalar();
    +
    +    PVStructurePtr createPVStructure(
    +        StringArray const & fieldNames,PVFieldPtrArray const & pvFields);
    +    PVStructurePtr createPVStructure(PVStructurePtr const & structToClone);
    +    PVStructurePtr createPVStructure(StructureConstPtr const & structure);
    +
    +    PVUnionPtr createPVUnion(UnionConstPtr const & punion);
    +    PVUnionPtr createPVUnion(PVUnionPtr const & unionToClone);
    +    PVUnionPtr createPVVariantUnion();
    +
    +    PVScalarArrayPtr createPVScalarArray(ScalarArrayConstPtr const & scalarArray);
    +    PVScalarArrayPtr createPVScalarArray(ScalarType elementType);
    +    PVScalarArrayPtr createPVScalarArray(PVScalarArrayPtr const  & scalarArrayToClone);
    +    template<typename PVAT>
    +    std::tr1::shared_ptr<PVAT> createPVScalarArray();
    +
    +    PVStructureArrayPtr createPVStructureArray(StructureArrayConstPtr const & structureArray);
    +    PVStructureArrayPtr createPVStructureArray(StructureConstPtr const ∓ structure);
    +
    +    PVUnionArrayPtr createPVUnionArray(UnionArrayConstPtr const & unionArray);
    +    PVUnionArrayPtr createPVUnionArray(UnionConstPtr const & punion);
    +    PVUnionArrayPtr createPVVariantUnionArray();
    + ...
    +};
    +
    +extern PVDataCreatePtr getPVDataCreate();
    + +

    where

    +
    +
    getPVDataCreate
    +
    The returns the PVDataCreate implementation, which is a singleton.
    +
    createPVField
    +
    The PVField is created reusing the Field interface. Two methods are + provided. Each calls the corresponding createPVScalar, createPVArray, or + createPVStructure depending in the type of the last argument.
    +
    createPVScalar
    +
    Creates an instance of a PVScalar. Four versions are supplied. The + first is passed an introspection interface. + The second provides the scalarType. + The third provides a PVScalar to clone. + The last is a template version. PVAT must be a valid type. + For example: +
    +PVDoublePtr pvDouble = getPVDataCreate()->createPVScalar<PVDouble>();
    +
    +
    +
    createPVStructure
    +
    Create an instance of a PVStructure. + Three methods are provided. + The first uses an array of field names and an array of PVFields to initialize the sub-fields. + The second initializes the subfields by cloning the fields contained in + structToClone. The newly created sub-fields will have the same values as the original. + If structToClone is null then the new structure is initialized to have 0 sub-fields. + The third method uses a previously created structure introspection interface. +
    +
    createPVUnion
    +
    Create an instance of a PVUnion. Two methods are provided. + The first uses a previously created union introspection interface. + The second clones an existing PVUnion. +
    +
    createPVVariantUnion
    +
    Creates an instance of a varient PVUnion. + This is a union which has a single field which can be any pvData supported type, +
    +
    createPVScalarArray
    +
    Create an instance of a PVArray. Four versions are supplied. + The first is passed an introspection interface. + The second provides the elementType. + The third provides a PVScalarArray to clone. + The last is a template version. PVAT must be a valid type. + For example: +
    +PVDoubleArrayPtr pvDoubleArray = getPVDataCreate()->createPVScalarArray<PVDoubleArray>();
    +
    +
    +
    createPVStructureArray
    +
    Create a PVStructureArray. + Two versions are provided. + The first is passed a StructureArrayConstPtr. + The second is passed a StructureConstPtr which is used to create a StructureArrayConstPtr. + The argument provides the Structure interface for ALL elements of the PVStructureArray. +
    +
    createPVUnionArray
    +
    Create a PVUnionArray. + Two versions are provided. + The first is passed a UnionArrayConstPtr. + The second is passed a UnionConstPtr which is used to create a UnionArrayConstPtr. + The argument provides the Union interface for ALL elements of the PVUnionArray. +
    +
    createPVVariantUnionArray
    +
    Create a PVUnionArray. + No arguments are needed. +
    +
    + +

    standardPVField.h

    + +

    A class StandardPVField has methods for creating standard data fields. Like +class StandardField it has two forms of the methods which create a field, one +without properties and one with properties. Again the properties is some +combination of alarm, timeStamp, control, display, and valueAlarm. And just +like StandardField there are methods to create the standard properties. The +methods are:

    +
    class StandardPVField;
    +typedef std::tr1::shared_ptr<StandardPVField> StandardPVFieldPtr;
    +
    +class StandardPVField : private NoDefaultMethods {
    +public:
    +    static StandardPVFieldPtr getStandardPVField();
    +    ~StandardPVField();
    +    PVStructurePtr scalar(ScalarType type,String const &properties);
    +    PVStructurePtr scalarArray(ScalarType elementType, String const &properties);
    +    PVStructurePtr structureArray(StructureConstPtr const &structure,String const &properties);
    +    PVStructurePtr unionArray(UnionConstPtr const &punion,String const &properties);
    +    PVStructurePtr enumerated(StringArray const &choices);
    +    PVStructurePtr enumerated(StringArray const &choices, String const &properties);
    + ...
    +}
    +
    +extern StandardPVFieldPtr getStandardPVField();
    +
    + +

    Conversion

    +

    There are two facilities for converting between two different PVData +objects:

    +
    +
    Convert
    +
    This preforms all conversions except for coping subarrays.
    +
    PVSubArray
    +
    This copies a subarray from one PVArray to another. + The two arrays must have the same element type.
    +
    +

    convert.h

    + +

    NOTE about copying immutable array fields. If an entire immutable array +field is copied to another array that has the same elementType, both offsets +are 0, and the length is the length of the source array, then the shareData +method of the target array is called and the target array is set immutable. +Thus the source and target share the same primitive array.

    + +

    This section describes the supported conversions between data types.

    +
      +
    • All supported types can be converted to a string. If you ask for a 100 + megabyte array to be converted to a string expect a lot of output.
    • +
    • Conversion from a string to a scalar type.
    • +
    • Conversion from an array of strings to an array of scalar types.
    • +
    • Copy between the following types of scalar PVs +
        +
      • Numeric type to another numeric type
      • +
      • Both have the same type.
      • +
      • Either is a string
      • +
      +
    • +
    • Copy between PVArrays that satisfy one of the following. +
        +
      • Both have the same type.
      • +
      • Either is a string.
      • +
      +
    • +
    • Conversions between numeric scalar types.
    • +
    • Conversion between compatible structures.
    • +
    • A utility method the returns the full field name of a field
    • +
    +
    +bool operator==(PVField&, PVField&);
    +
    +static bool operator!=(PVField& a, PVField& b);
    +
    +bool operator==(const Field&, const Field&);
    +bool operator==(const Scalar&, const Scalar&);
    +bool operator==(const ScalarArray&, const ScalarArray&);
    +bool operator==(const Structure&, const Structure&);
    +bool operator==(const StructureArray&, const StructureArray&);
    +bool operator==(const Union&, const Union&);
    +bool operator==(const UnionArray&, const UnionArray&);
    +
    +static inline bool operator!=(const Field& a, const Field& b);
    +static inline bool operator!=(const Scalar& a, const Scalar& b);
    +static inline bool operator!=(const ScalarArray& a, const ScalarArray& b);
    +static inline bool operator!=(const Structure& a, const Structure& b);
    +static inline bool operator!=(const StructureArray& a, const StructureArray& b);
    +static inline bool operator!=(const Union& a, const Union& b);
    +static inline bool operator!=(const UnionArray& a, const UnionArray& b);
    +
    +class Convert;
    +typedef std::tr1::shared_ptr<Convert> ConvertPtr;
    +
    +class Convert {
    +public:
    +    static ConvertPtr getConvert();
    +    ~Convert();
    +    void getFullName(StringBuilder buf,PVFieldPtr const & pvField);
    +    bool equals(PVFieldPtr const &a,PVFieldPtr const &b);
    +    bool equals(PVField &a,PVField &b);
    +    void getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel);
    +    void getString(StringBuilder buf,PVFieldPtr const & pvField);
    +    void getString(StringBuilder buf,PVField const * pvField,int indentLevel);
    +    void getString(StringBuilder buf,PVField const * pvField);
    +    std::size_t fromString(
    +        PVStructurePtr const &pv,
    +        StringArray const & from,
    +        std::size_t fromStartIndex = 0);
    +    void fromString(PVScalarPtr const & pv, String const & from);
    +    std::size_t fromString(PVScalarArrayPtr const & pv, String const &from);
    +    std::size_t fromStringArray(
    +        PVScalarArrayPtr const & pv,
    +        std::size_t offset, std::size_t length,
    +        StringArray const & from,
    +        std::size_t fromOffset);
    +    std::size_t toStringArray(PVScalarArrayPtr const & pv,
    +        std::size_t offset,
    +        std::size_t length,
    +        StringArray & to,
    +        std::size_t toOffset);
    +    bool isCopyCompatible(FieldConstPtr const & from, FieldConstPtr const & to);
    +    void copy(PVFieldPtr const & from, PVFieldPtr const & to);
    +    bool isCopyScalarCompatible(
    +        ScalarConstPtr const & from,
    +        ScalarConstPtr const & to);
    +    void copyScalar(PVScalarPtr const & from, PVScalarPtr const & to);
    +    bool isCopyScalarArrayCompatible(
    +        ScalarArrayConstPtr const & from,
    +        ScalarArrayConstPtr const & to);
    +    bool isCopyStructureCompatible(
    +        StructureConstPtr const & from, StructureConstPtr const & to);
    +    void copyStructure(PVStructurePtr const & from, PVStructurePtr const & to);
    +    bool isCopyStructureArrayCompatible(
    +        StructureArrayConstPtr const & from, StructureArrayConstPtr const & to);
    +    void copyStructureArray(
    +        PVStructureArrayPtr const & from, PVStructureArrayPtr const & to);
    +    bool isCopyUnionCompatible(
    +        UnionConstPtr const & from, UnionConstPtr const & to);
    +    void copyUnion(
    +        PVUnionPtr const & from, PVUnionPtr const & to);
    +    bool isCopyUnionArrayCompatible(
    +        UnionArrayConstPtr const & from, UnionArrayConstPtr const & to);
    +    void copyUnionArray(
    +        PVUnionArrayPtr const & from, PVUnionArrayPtr const & to);
    +    int8 toByte(PVScalarPtr const & pv);
    +    int16 toShort(PVScalarPtr const & pv);
    +    int32 toInt(PVScalarPtr const & pv);
    +    int64 toLong(PVScalarPtr const & pv);
    +    uint8 toUByte(PVScalarPtr const & pv);
    +    uint16 toUShort(PVScalarPtr const & pv);
    +    uint32 toUInt(PVScalarPtr const & pv);
    +    uint64 toULong(PVScalarPtr const & pv);
    +    float toFloat(PVScalarPtr const & pv);
    +    double toDouble(PVScalarPtr const & pv);
    +    String toString(PVScalarPtr const & pv);
    +    void fromByte(PVScalarPtr const & pv,int8 from);
    +    void fromShort(PVScalarPtr const & pv,int16 from);
    +    void fromInt(PVScalarPtr const & pv, int32 from);
    +    void fromLong(PVScalarPtr const & pv, int64 from);
    +    void fromUByte(PVScalarPtr const & pv,uint8 from);
    +    void fromUShort(PVScalarPtr const & pv,uint16 from);
    +    void fromUInt(PVScalarPtr const & pv, uint32 from);
    +    void fromULong(PVScalarPtr const & pv, uint64 from);
    +    void fromFloat(PVScalarPtr const & pv, float from);
    +    void fromDouble(PVScalarPtr const & pv, double from);
    +    void newLine(StringBuilder buf, int indentLevel);
    + ...
    +}
    +
    +extern ConvertPtr getConvert();
    +
    +

    newLine is a convenience method for code that implements toString It +generates a newline and inserts blanks at the beginning of the newline.

    + +

    pvSubArrayCopy.h

    +
    +template<typename T>
    +void copy(
    +    PVValueArray<T> & pvFrom,
    +    size_t fromOffset,
    +    PVValueArray<T> & pvTo,
    +    size_t toOffset,
    +    size_t len);
    +
    +void copy(
    +    PVScalarArray & from,
    +    size_t fromOffset,
    +    PVScalarArray & to,
    +    size_t toOffset,
    +    size_t len);
    +
    +void copy(
    +    PVStructureArray & from,
    +    size_t fromOffset,
    +    PVStructureArray & to,
    +    size_t toOffset,
    +    size_t len);
    +
    +void copy(
    +    PVArray & from,
    +    size_t fromOffset,
    +    PVArray & to,
    +    size_t toOffset,
    +    size_t len);
    +
    +

    The last copy is the only one most client need to call. +It either throws an error of the element types do not match or calls the +other copy functions. The arguments are:

    +
    +
    from
    +
    The source array.
    +
    fromOffset
    +
    The offset into the source array.
    +
    to
    +
    The destination array. The element type must be the same + as for the source array. If the element type is structure then + the introspection interface for the element types must be the same. +
    +
    toOffset
    +
    The offset into the destination array.
    +
    len
    +
    The number of elements to copy.
    +
    +

    An exception is thrown if:

    +
    +
    type mismatch
    +
    The element types for the source and destination differ.
    +
    immutable
    +
    The destination array is immutable. +
    capacity immutable
    +
    The destination array needs to have it's capacity extentended + but the capacity is immutable.
    +
    + +

    pvDataApp/property

    + +

    Definition of Property

    + +

    Only fields named "value" have properties. A record can have multiple value +fields, which can appear in the top level structure of a record or in a +substructure. All other fields in the structure containing a value field are +considered properties of the value field. The fieldname is also the property +name. The value field can have any type, i.e. scalar, scalarArray, or +structure. Typical property fields are timeStamp, alarm, display, control, and +history. The timeStamp is a special case. If it appears anywhere in the +structure hieraracy above a value field it is a property of the value field.

    + +

    For example the following top level structure has a single value field. The +value field has properties alarm, timeStamp, and display.

    +
    structure counterOutput
    +    double value
    +    alarm_t
    +        int severity 0
    +        int status 0
    +        string message
    +    timeStamp_t
    +        long secondsPastEpoch
    +        int nanoSeconds
    +        int userTag
    +    display_t
    +        double limitLow 0.0
    +        double limitHigh 10.0
    +        string description "Sample Description"
    +        string format "%f"
    +        string units volts
    + +

    The following example has three value fields each with properties alarm and +timeStamp. Voltage, Current, and Power each have a different alarms but all +share the timeStamp.

    +
    structure powerSupplyValue
    +    double value
    +    alarm_t
    +        int severity 0
    +        int status 0
    +        string message
    +
    +structure powerSupplySimple
    +    alarm_t
    +        int severity 0
    +        int status 0
    +        string message
    +    timeStamp_t
    +        long secondsPastEpoch
    +        int nanoSeconds
    +        int userTag
    +    powerSupplyValue_t voltage
    +        double value
    +        alarm_t
    +            int severity 0
    +            int status 0
    +            string message
    +    powerSupplyValue_t power
    +        double value
    +        alarm_t
    +            int severity 0
    +            int status 0
    +            string message
    +    powerSupplyValue_t current
    +        double value
    +        alarm_t
    +            int severity 0
    +            int status 0
    +            string message
    + +

    Standard Properties

    + +

    The following field names have special meaning, i.e. support properties for +general purpose clients.

    +
    +
    value
    +
    This is normally defined since most general purpose clients access this + field. All other fields in the structure support or describe the value + field. The type can any supported type but is usually one of the + following: +
    +
    scalar
    +
    Any of the scalar types.
    +
    scalarArray
    +
    An array with the elementType being a scalar type
    +
    enumerated structure
    +
    A structure that includes fields named index and choices. index + is an int that selects a choice. choices is an array of strings + that defines the complete set of choices.
    +
    other
    +
    Other structure or array types can also be defined if clients and + support code agree on the meaning. Some examples are: 1) A + structure defining a 2D matrix, 2) A structure defining an image, + 3) A structure that simulates a remote method, ...
    +
    +
    +
    timeStamp
    +
    The timeStamp. The type MUST be a timeStamp structure. Also if the + PVData structure does not have a timeStamp then a search up the parent + tree is made to find a timeStamp.
    +
    alarm
    +
    The alarm. The type MUST be an alarm structure.
    +
    display
    +
    A display structure as described below. It provides display + characteristics for the value field.
    +
    control
    +
    A control structure as described below. It provides control + characteristics for the value field.
    +
    history
    +
    Provides a history buffer for the value field. Note that currently + PVData does not define history suppoprt.
    +
    other
    +
    Other standard properties can be defined.
    +
    + +

    In addition a structure can have additional fields that support the value +field but are not recognized by most general purpose client tools. Typical +examples are:

    +
    +
    input
    +
    A field with support that changes the value field. This can be + anything. It can be a channel access link. It can obtain a value from + hardware. Etc.
    +
    valueAlarm
    +
    A field with support that looks for alarm conditions based on the + value.
    +
    output
    +
    A field with support that reads the current value and sends it + somewhere else. This can be anything. It can be a channel access link. It + can write a value to hardware. Etc.
    +
    + +

    The model allows for device records. A device record has structure fields +that that support the PVData data model. For example a powerSupport record can +have fields power, voltage, current that each support the PVData data model. +

    + +

    Overview of Property Support

    + +

    Except for enumerated, each property has two files: a property.h and a +pvProperty.h . For example: timeStamp.h and pvTimeStamp.h In each case the +property.h file defined methods for manipulating the property data and the +pvProperty.h provides methods to transfer the property data to/from a pvData +structure.

    + +

    All methods copy data via copy by value semantics, i.e. not by pointer or by +reference. No property class calls new or delete and all allow the compiler to +generate default methods. All allow a class instance to be generated on the +stack. For example the following is permitted:

    +
    void example(PVFieldPtr const &pvField) {
    +    Alarm alarm;
    +    PVAlarm pvAlarm;
    +    bool result;
    +    result = pvAlarm.attach(pvField);
    +    assert(result);
    +    Alarm al;
    +    al.setMessage(String("testMessage"));
    +    al.setSeverity(majorAlarm);
    +    result = pvAlarm.set(al);
    +    assert(result);
    +    alarm = pvAlarm.get();
    +     ...
    +}
    + +

    timeStamp

    + +

    A timeStamp is represented by the following structure

    +
    structure timeStamp
    +    long secondsPartEpoch
    +    int nanoSeconds
    +    int userTag
    + +

    The Epoch is the posix epoch, i.e. Jan 1, 1970 00:00:00 UTC. Both the +seconds and nanoSeconds are signed integers and thus can be negative. Since the +seconds is kept as a 64 bit integer, it allows for a time much greater than the +present age of the universe. Since the nanoSeconds portion is kept as a 32 bit +integer it is subject to overflow if a value that corresponds to a value that +is greater than a little more than 2 seconds of less that about -2 seconds. The +support code always adjust seconds so that the nanoSecconds part is normlized, +i. e. it has is 0<=nanoSeconds<nanoSecPerSec..

    + +

    Two header files are provided for manipulating time stamps:

    +
    +
    timeStamp.h
    +
    Defines a time stamp independent of pvData, i.e. it is a generally + useful class for manipulating timeStamps.
    +
    pvTimeStamp.h
    +
    A class that can be attached to a time stamp pvData structure. It + provides get and set methods to get/set a TimeStamp as defined by + timeStamp.h
    +
    + +

    timeStamp.h

    + +

    This provides

    +
    extern int32 milliSecPerSec;
    +extern int32 microSecPerSec;
    +extern int32 nanoSecPerSec;
    +extern int64 posixEpochAtEpicsEpoch;
    +
    +class TimeStamp {
    +public:
    +    TimeStamp()
    +    :secondsPastEpoch(0), nanoSeconds(0), userTag(0) {}
    +    TimeStamp(int64 secondsPastEpoch,int32 nanoSeconds = 0,int32 userTag = 0);
    +    //default constructors and destructor are OK
    +    //This class should not be extended
    +    void normalize();
    +    void fromTime_t(const time_t &);
    +    void toTime_t(time_t &) const;
    +    int64 getSecondsPastEpoch() const {return secondsPastEpoch;}
    +    int64 getEpicsSecondsPastEpoch() const {
    +        return secondsPastEpoch - posixEpochAtEpicsEpoch;
    +    }
    +    int32 getNanoSeconds() const  {return nanoSeconds;}
    +    int32 getUserTag() const {return userTag;}
    +    void setUserTag(int userTag) {this->userTag = userTag;}
    +    void put(int64 secondsPastEpoch,int32 nanoSeconds = 0) {
    +        this->secondsPastEpoch = secondsPastEpoch;
    +        this->nanoSeconds = nanoSeconds;
    +        normalize();
    +    }
    +    void put(int64 milliseconds);
    +    void getCurrent();
    +    double toSeconds() const ;
    +    bool operator==(TimeStamp const &) const;
    +    bool operator!=(TimeStamp const &) const;
    +    bool operator<=(TimeStamp const &) const;
    +    bool operator< (TimeStamp const &) const;
    +    bool operator>=(TimeStamp const &) const;
    +    bool operator> (TimeStamp const &) const;
    +    static double diff(TimeStamp const & a,TimeStamp const & b);
    +    TimeStamp & operator+=(int64 seconds);
    +    TimeStamp & operator-=(int64 seconds);
    +    TimeStamp & operator+=(double seconds);
    +    TimeStamp & operator-=(double seconds);
    +    int64 getMilliseconds(); // milliseconds since epoch
    + ...
    +}
    + +

    where

    +
    +
    TimeStamp()
    +
    The defauly constuctor. Both seconds and nanoSeconds are set to 0.
    +
    TimeStamp(int64 secondsPastEpoch,int32 nanoSeconds = 0)
    +
    A constructor that gives initial values to seconds and nanoseconds.
    +
    normalize
    +
    Adjust seconds and nanoSeconds so that + 0<=nanoSeconds<nanoSecPerSec.
    +
    fromTime_t
    +
    Set time from standard C time.
    +
    toTime_t
    +
    Convert timeStamp to standard C time.
    +
    getSecondsPastEpoch
    +
    Get the number of seconds since the epoch.
    +
    getEpicsSecondsPastEpoch
    +
    Get the number of EPICS seconds since the epoch. EPICS uses Jan 1, 1990 + 00:00:00 UTC as the epoch.
    +
    getNanoSeconds
    +
    Get the number of nanoSeconds. This is always normalized.
    +
    getUserTag
    +
    Get the userTag.
    +
    setUserTag
    +
    Set the userTag.
    +
    put(int64 secondsPastEpoch,int32 nanoSeconds = 0)
    +
    Set the timeStamp value. If necessary it will be normalized.
    +
    put(int64 milliseconds)
    +
    Set the timeStamp with a value the is the number of milliSeconds since + the epoch.
    +
    getCurrent()
    +
    Set the timeStamp to the current time.
    +
    toSeconds()
    +
    Convert the timeStamp to a value that is the number of seconds since + the epocj
    +
    operator =
    +
    operator!=
    +
    operator<=
    +
    operator<
    +
    operator>=
    +
    operator>
    +
    Standard C++ operators.
    +
    diff
    +
    diff = a - b
    +
    getMilliseconds
    +
    Get the number of milliseconds since the epoch.
    +
    + +

    The TimeStamp class provides arithmetic operations on time stamps. The +result is always kept in normalized form, which means that the nano second +portion is 0≤=nano<nanoSecPerSec. Note that it is OK to have timeStamps +for times previous to the epoch.

    + +

    TimeStamp acts like a primitive. It can be allocated on the stack and the +compiler is free to generate default methods, i.e. copy constructor, assignment +constructor, and destructor.

    + +

    One use for TimeStamp is to time how long a section of code takes to +execute. This is done as follows:

    +
        TimeStamp startTime;
    +    TimeStamp endTime;
    +    ...
    +    startTime.getCurrent();
    +    // code to be measured for elapsed time
    +    endTime.getCurrent();
    +    double time = TimeStamp::diff(endTime,startTime);
    + +

    pvTimeStamp.h

    +
    class PVTimeStamp {
    +public:
    +    PVTimeStamp();
    +    //default constructors and destructor are OK
    +    //This class should not be extended
    +    //returns (false,true) if pvField(isNot, is valid timeStamp structure
    +    bool attach(PVFieldPtr const &pvField);
    +    void detach();
    +    bool isAttached();
    +    // following throw logic_error if not attached to PVField
    +    // a set returns false if field is immutable
    +    void get(TimeStamp &) const;
    +    bool set(TimeStamp const & timeStamp);
    +};
    + +

    where

    +
    +
    PVTimeStamp
    +
    The default constructor. Attach must be called before get or set can be + called.
    +
    attach
    +
    Attempts to attach to pvField It returns (false,true) if a timeStamp + structure is found. It looks first at pvField itself and if is not an + appropriate pvData structure but the field name is value it looks up the + parent structure tree.
    +
    detach
    +
    Detach from the pvData structure.
    +
    isAttached
    +
    Is there an attachment to a timeStamp structure?
    +
    get
    +
    Copies data from the pvData structure to a TimeStamp. An exception is + thrown if not attached to a pvData structure.
    +
    set
    +
    Copies data from TimeStamp to the pvData structure. An exception is + thrown if not attached to a pvData structure.
    +
    + +

    alarm

    + +

    An alarm structure is defined as follows:

    +
    structure alarm
    +    int severity
    +    int status
    +    string message
    + +

    Note that neither severity or status is defined as an enumerated structure. +The reason is performance, i. e. prevent passing the array of choice strings +everywhere. The file alarm.h provides the choice strings. Thus all code that +needs to know about alarms share the exact same choice strings.

    + +

    Two header files are provided for manipulating alarms:

    +
    +
    alarm.h
    +
    Defines an alarm independent of pvData, i.e. it is a generally useful + class for manipulating alarms.
    +
    pvAlarm.h
    +
    A class that can be attached to an alarm pvData structure. It provides + get and set methods to get/set alarm data as defined by alarm.h
    +
    + +

    alarm.h

    +
    enum AlarmSeverity {
    + noAlarm,minorAlarm,majorAlarm,invalidAlarm,undefinedAlarm
    +};
    +
    +enum AlarmStatus {
    +    noStatus,deviceStatus,driverStatus,recordStatus,
    +    dbStatus,confStatus,undefinedStatus,clientStatus
    +};
    +
    +
    +class AlarmSeverityFunc {
    +public:
    +    static AlarmSeverity getSeverity(int value);
    +    static StringArrayPtr getSeverityNames();
    +};
    +
    +class AlarmStatusFunc {
    +public:
    +    static AlarmStatus getStatus(int value);
    +    static StringArrayPtr getStatusNames();
    +};
    +
    +class Alarm {
    +public:
    +    Alarm();
    +    //default constructors and destructor are OK
    +    String getMessage();
    +    void setMessage(String const &value);
    +    AlarmSeverity getSeverity() const;
    +    void setSeverity(AlarmSeverity value);
    +    AlarmStatus getStatus() const;
    +    void setStatus(AlarmStatus value);
    +};
    + +

    Alarm Severity defines the possible alarm severities:

    +
    +
    getSeverity
    +
    Get the alarm severity corresponding to the integer value.
    +
    getSeverityNames
    +
    Get the array of severity choices.
    +
    + +

    Alarm Status defines the possible choices for alarm status:

    +
    +
    getStatus
    +
    Get the alarm status corresponding to the integer value.
    +
    getStatusNames
    +
    Get the array of status choices.
    +
    + +

    Alarm has the methods:

    +
    +
    Alarm
    +
    The constructor. It sets the severity to no alarm and the message to + "".
    +
    getMessage
    +
    Get the message.
    +
    setMessage
    +
    Set the message.
    +
    getSeverity
    +
    Get the severity.
    +
    setSeverity
    +
    Set the severity.
    +
    getStatus
    +
    Get the status.
    +
    setStatus
    +
    Set the status.
    +
    + +

    pvAlarm.h

    +
    class PVAlarm {
    +public:
    +    PVAlarm() : pvSeverity(0),pvMessage(0) {}
    +    //default constructors and destructor are OK
    +    //returns (false,true) if pvField(isNot, is valid enumerated structure
    +    //An automatic detach is issued if already attached.
    +    bool attach(PVFieldPtr const &pvField);
    +    void detach();
    +    bool isAttached();
    +    // each of the following throws logic_error is not attached to PVField
    +    // set returns false if field is immutable
    +    void get(Alarm & alarm) const;
    +    bool set(Alarm const & alarm); 
    +};
    + +

    where

    +
    +
    PVAlarm
    +
    The default constructor. Attach must be called before get or set can be + called.
    +
    attach
    +
    Attempts to attach to pvField It returns (false,true) if it found an + appropriate pvData structure. It looks first a pvField itself and if is + not an appropriate pvData structure but the field name is value it looks + to see if the parent structure has an appropriate sub structure.
    +
    detach
    +
    Just detaches from the pvData structure.
    +
    isAttached
    +
    Is there an attachment to an alarm structure?
    +
    get
    +
    Copies data from the pvData structure to an Alarm. An exception is + thrown if not attached to a pvData structure.
    +
    set
    +
    Copies data from Alarm to the pvData structure. An exception is thrown + if not attached to a pvData structure.
    +
    + +

    control

    + +

    Control information is represented by the following structure

    +
    structure control
    +    double limitLow
    +    double limitHigh
    +    double minStep
    + +

    Two header files are provided for manipulating control:

    +
    +
    control.h
    +
    Defines control independent of pvData, i.e. it is a generally useful + class for manipulating control.
    +
    pvControl.h
    +
    A class that can be attached to an control pvData structure. It + provides get and set methods to get/set control data as defined by + control.h
    +
    + +

    control.h

    +
    class Control {
    +public:
    +    Control();
    +    //default constructors and destructor are OK
    +    double getLow() const;
    +    double getHigh() const;
    +    double getMinStep() const;
    +    void setLow(double value);
    +    void setHigh(double value);
    +    void setMinStep(double value);
    +};
    + +

    where

    +
    +
    Control
    +
    The default constructure.
    +
    getLow
    +
    Get the low limit.
    +
    getHigh
    +
    Get the high limit.
    +
    setLow
    +
    Set the low limit.
    +
    setHigh
    +
    Set the high limit.
    +
    setMinStep
    +
    Set the minimum step size.
    +
    getMinStep
    +
    Get he minimum step size.
    +
    + +

    pvControl.h

    +
    class PVControl {
    +public:
    +    PVControl();
    +    //default constructors and destructor are OK
    +    //returns (false,true) if pvField(isNot, is valid enumerated structure
    +    //An automatic detach is issued if already attached.
    +    bool attach(PVFieldPtr const &pvField);
    +    void detach();
    +    bool isAttached();
    +    // each of the following throws logic_error is not attached to PVField
    +    // set returns false if field is immutable
    +    void get(Control &) const;
    +    bool set(Control const & control);
    +};
    + +

    where

    +
    +
    PVControl
    +
    The default constructor. Attach must be called before get or set can be + called.
    +
    attach
    +
    Attempts to attach to pvField It returns (false,true) if it found an + appropriate pvData structure. It looks first a pvField itself and if is + not an appropriate pvData structure but the field name is value it looks + to see if the parent structure has an appropriate sub structure.
    +
    detach
    +
    Just detaches from the pvData structure.
    +
    isAttached
    +
    Is there an attachment to a control structure?
    +
    get
    +
    Copies data from the pvData structure to a Control. An exception is + thrown if not attached to a pvData structure.
    +
    set
    +
    Copies data from Control to the pvData structure. An exception is + thrown if not attached to a pvData structure.
    +
    + +

    display

    + +

    Display information is represented by the following structure

    +
    structure display
    +    double limitLow
    +    double limitHigh
    +    string description
    +    string format
    +    string units
    + +

    Two header files are provided for manipulating display:

    +
    +
    display.h
    +
    Defines display independent of pvData, i.e. it is a generally useful + class for manipulating display.
    +
    pvDisplay.h
    +
    A class that can be attached to an display pvData structure. It + provides get and set methods to get/set display data as defined by + display.h
    +
    + +

    display.h

    +
    class Display {
    +public:
    +    Display();
    +    //default constructors and destructor are OK
    +    double getLow() const;
    +    double getHigh() const;
    +    void setLow(double value);
    +    void setHigh(double value);
    +    String getDescription() const;
    +    void setDescription(String const &value);
    +    String getFormat() const;
    +    void setFormat(String const &value);
    +    String getUnits() const;
    +    void setUnits(String const &value);
    +};
    + +

    where

    +
    +
    Control
    +
    The default constructure.
    +
    getLow
    +
    Get the low limit.
    +
    getHigh
    +
    Get the high limit.
    +
    setLow
    +
    Set the low limit.
    +
    setHigh
    +
    Set the high limit.
    +
    getDescription
    +
    Get the description.
    +
    setDescription
    +
    Set the description.
    +
    getFormat
    +
    Get the format.
    +
    setFormat
    +
    Set the format.
    +
    getUnits
    +
    Get the units.
    +
    setUnits
    +
    Set the units.
    +
    + +

    pvDisplay.h

    +
    class PVDisplay {
    +public:
    +    PVDisplay()
    +    : pvDescription(0),pvFormat(),pvUnits(),pvLow(),pvHigh() {}
    +    //default constructors and destructor are OK
    +    //An automatic detach is issued if already attached.
    +    bool attach(PVFieldPtr const&pvField); 
    +    void detach();
    +    bool isAttached();
    +    // each of the following throws logic_error is not attached to PVField
    +    // a set returns false if field is immutable
    +    void get(Display &) const;
    +    bool set(Display const & display);
    +};
    + +

    where

    +
    +
    PVDisplay
    +
    The default constructor. Attach must be called before get or set can be + called.
    +
    attach
    +
    Attempts to attach to pvField It returns (false,true) if it found an + appropriate pvData structure. It looks first a pvField itself and if is + not an appropriate pvData structure but the field name is value it looks + to see if the parent structure has an appropriate sub structure.
    +
    detach
    +
    Just detaches from the pvData structure.
    +
    isAttached
    +
    Is there an attachment to a display structure?
    +
    get
    +
    Copies data from the pvData structure to a Display. An exception is + thrown if not attached to a pvData structure.
    +
    set
    +
    Copies data from Display to the pvData structure. An exception is + thrown if not attached to a pvData structure.
    +
    + +

    pvEnumerated.h

    + +

    An enumerated structure is a structure that has fields:

    +
    structure
    +    int index
    +    string[] choices
    + +

    For enumerated structures a single header file pvEnumerted.h is available

    +
    class PVEnumerated {
    +public:
    +    PVEnumerated();
    +    //default constructors and destructor are OK
    +    //This class should not be extended
    +    //returns (false,true) if pvField(isNot, is valid enumerated structure
    +    //An automatic detach is issued if already attached.
    +    bool attach(PVFieldPtr const &pvField);
    +    void detach();
    +    bool isAttached();
    +    // each of the following throws logic_error is not attached to PVField
    +    // a set returns false if field is immutable
    +    bool setIndex(int32 index);
    +    int32 getIndex();
    +    String getChoice();
    +    bool choicesMutable();
    +    StringArrayPtr const & getChoices();
    +    int32 getNumberChoices();
    +    bool setChoices(StringArray &choices,int32 numberChoices);
    +};
    + +

    where

    +
    +
    PVEnumerated
    +
    The default constructor. Attach must be called before any get or set + method can be called.
    +
    attach
    +
    Attempts to attach to pvField It returns (false,true) if pvField (is + not, is) an enumerated structure.
    +
    detach
    +
    Just detaches from the pvData structure.
    +
    isAttached
    +
    Is there an attachment to an enemerated structure?
    +
    setIndex
    +
    Set the index field in the pvData structure. An exception is thrown if + not attached to a pvData structure.
    +
    getIndex
    +
    Get the index field in the pvData structure.
    +
    getChoice
    +
    Get the String value corresponding to the current index field in the + pvData structure. An exception is thrown if not attached to a pvData + structure.
    +
    choicesMutable
    +
    Can the choices be changed? Note that this is often true. An exception + is thrown if not attached to a pvData structure.
    +
    getChoices
    +
    Get the array of choices. An exception is thrown if not attached to a + pvData structure.
    +
    getNumberChoices
    +
    Get the number of choices. An exception is thrown if not attached to a + pvData structure.
    +
    setChoices
    +
    Change the choices. An exception is thrown if not attached to a pvData + structure.
    +
    + + +

    pvDataApp/factory

    + +

    Directory factory has code that implements everything described by the files +in directory pv

    + +

    TypeFunc.cpp implements the functions for the enums defined in +pvIntrospecct.h

    + +

    FieldCreateFactory.cpp automatically creates a single instance of +FieldCreate and implements getFieldCreate.

    + +

    PVDataCreateFactory.cpp automatically creates a single instance of +PVDataCreate and implements getPVDataCreate.

    + + +

    Convert.cpp automatically creates a single instance of Convert and +implements getConvert.

    + +

    Other files implement PVData base classes

    + +

    pvDataAPP/misc

    + +

    Overview

    + +

    This package provides utility code:

    +
    +
    bitSet.h
    +
    An implementation of BitSet that can be serialized.
    +
    byteBuffer.h
    +
    Used to serialize objects.
    +
    destroyable.h
    +
    Provides method destroy.
    +
    epicsException.h
    +
    Exception with stack trace.
    +
    event.h
    +
    Signal and wait for an event.
    +
    executor.h
    +
    Provides a thread for executing commands.
    +
    localStaticLock.h
    +
    TBD Matej can You explain what this does?
    +
    lock.h
    +
    Support for locking and unlocking.
    +
    messageQueue.h
    +
    Support for queuing messages to give to requesters.
    +
    noDefaultMethods.h
    +
    When privately extended prevents compiler from implementing default + methods.
    +
    queue.h
    +
    A queue implementation that allows the latest queue element to continue + to be used when no free element is available.
    +
    requester.h
    +
    Allows messages to be sent to a requester.
    +
    serialize.h
    +
    Support for serializing objects.
    +
    serializeHelper.h
    +
    More support for serializing objects.
    +
    sharedPtr.h
    +
    Defines POINTER_DEFINITIONS.
    +
    sharedVector.h +
    Like std::vector except that std::shared_ptr is used for + the data array.
    +
    status.h
    +
    A way to pass status information to a client.
    +
    templateMeta.h
    +
    TBD Michael can You provide an explaination?
    +
    thread.h
    +
    Provides thread support.
    +
    timeFunction.h
    +
    Time how long a function call requires.
    +
    timer.h
    +
    An implementation of Timer that does not require an object to be + created for each timer request.
    +
    typeCast.h
    +
    TBD Michael can You provide an explaination?
    +
    + +

    Note that directory testApp/misc has test code for all the classes in misc. +The test code also can be used as examples.

    + +

    bitSet.h

    + +

    This is adapted from the java.util.BitSet. bitSet.h is:

    +
    +class BitSet;
    +typedef std::tr1::shared_ptr<BitSet> BitSetPtr;
    +
    +class BitSet : public Serializable {
    +public:
    +    static BitSetPtr create(uint32 nbits);
    +    BitSet();
    +    BitSet(uint32 nbits);
    +    virtual ~BitSet();
    +    void flip(uint32 bitIndex);
    +    void set(uint32 bitIndex);
    +    void clear(uint32 bitIndex);
    +    void set(uint32 bitIndex, bool value);
    +    bool get(uint32 bitIndex) const;
    +    void clear();
    +    int32 nextSetBit(uint32 fromIndex) const;
    +    int32 nextClearBit(uint32 fromIndex) const;
    +    bool isEmpty() const;
    +    uint32 cardinality() const;
    +    uint32 size() const;
    +    BitSet& operator&=(const BitSet& set);
    +    BitSet& operator|=(const BitSet& set);
    +    BitSet& operator^=(const BitSet& set);
    +    BitSet& operator-=(const BitSet& set);
    +    BitSet& operator=(const BitSet &set);
    +    void or_and(const BitSet& set1, const BitSet& set2);
    +    bool operator==(const BitSet &set) const;
    +    bool operator!=(const BitSet &set) const;
    +    void toString(StringBuilder buffer, int indentLevel = 0) const;
    +    virtual void serialize(
    +        ByteBuffer *buffer,SerializableControl *flusher) const;
    +    virtual void deserialize(
    +        ByteBuffer *buffer,DeserializableControl *flusher);
    +
    +private:
    +};
    + +

    where

    +
    +
    BitSet()
    +
    Creates a bitSet of initial size 64 bits. All bits initially false.
    +
    BitSet(uint32 nbits)
    +
    Creates a bitSet with the initial of the specified number of bits. All + bits initially false.
    +
    ~BitSet()
    +
    Destructor.
    +
    flip(uint32 bitIndex)
    +
    Flip the specified bit.
    +
    set(uint32 bitIndex)
    +
    Set the specified bit true.
    +
    clear(uint32 bitIndex)
    +
    Set the specified bit false.
    +
    set(uint32 bitIndex, bool value)
    +
    Set the specified bit to value.
    +
    get(uint32 bitIndex)
    +
    Return the state of the specified bit.
    +
    clear()
    +
    Set all bits to false.
    +
    nextSetBit(uint32 fromIndex)
    +
    Get the index of the next true bit beginning with the specified + bit.
    +
    nextClearBit(uint32 fromIndex)
    +
    Get the index of the next false bit beginning with the specified + bit.
    +
    isEmpty()
    +
    Return (false,true) if (at least one bit true, all bits are false)
    +
    cardinality()
    +
    Return the number of true bits.
    +
    size()
    +
    Returns the number of bits of space actually in use.
    +
    operator&=(const BitSet& set)
    +
    Performs a logical and of this target bit set with the argument bit + set. This bit set is modified so that each bit in it has the value true + if and only if it both initially had the value true and the corresponding + bit in the bit set argument also had the value.
    +
    operator|=(const BitSet& set)
    +
    Performs a logical or of this target bit set with the argument bit + set.
    +
    operator^=(const BitSet& set)
    +
    Performs a logical exclusive or of this target bit set with the + argument bit set.
    +
    operator-=(const BitSet& set)
    +

    Clears all of the bits in this bitSet whose corresponding bit is set + in the specified bitSet.

    +
    +
    operator=(const BitSet &set)
    +
    Assignment operator.
    +
    or_and(const BitSet& set1, const BitSet& set2)
    +
    Perform AND operation on set1 and set2, and then OR this bitSet with + the result.
    +
    operator==(const BitSet &set)
    +
    Does this bitSet have the same values as the argument.
    +
    operator!=(const BitSet &set)
    +
    Is this bitSet different than the argument.
    +
    toString(StringBuilder buffer, int indentLevel)
    +
    Show the current values of the bitSet.
    +
    virtual void serialize(ByteBuffer *buffer,SerializableControl *flusher) + const;
    +
    Serialize the bitSet
    +
    virtual void deserialize(ByteBuffer *buffer,DeserializableControl + *flusher);
    +
    Deserialize the bitSet.
    +
    +

    TBD +

    +
    toString
    +
    Should this change and also implement ostream operator?
    +
    +

    + +

    byteBuffer.h

    + +

    A ByteBuffer is used to serialize and deserialize primitive data. File +byteBuffer.h is:

    +
    class ByteBuffer {
    +public:
    +    ByteBuffer(std::size_t size, int byteOrder = EPICS_BYTE_ORDER)
    +    ~ByteBuffer();
    +    void setEndianess(int byteOrder);
    +    const char* getBuffer();
    +    void clear();
    +    void flip();
    +    void rewind();
    +    std::size_t getPosition();
    +    void setPosition(std::size_t pos);
    +    std::size_t getLimit();
    +    void setLimit(std::size_t limit);
    +    std::size_t getRemaining();
    +    std::size_t getSize();
    +    template<typename T>
    +    void put(T value)
    +    template<typename T>
    +    void put(std::size_t index, T value);
    +    template<typename T>
    +    T get()
    +    template<typename T>
    +    T get(std::size_t index)
    +    void put(const char* src, std::size_t src_offset, std::size_t count);
    +    void get(char* dest, std::size_t dest_offset, std::size_t count);
    +    template<typename T>
    +    inline void putArray(T* values, std::size_t count)
    +    template<typename T>
    +    inline void getArray(T* values, std::size_t count)
    +    template<typename T>
    +    inline bool reverse();
    +    inline void align(std::size_t size)
    +    void putBoolean(  bool value);
    +    void putByte   (  int8 value);
    +    void putShort  ( int16 value);
    +    void putInt    ( int32 value);
    +    void putLong   ( int64 value);
    +    void putFloat  ( float value);
    +    void putDouble (double value);
    +    void putBoolean(std::size_t  index,  bool value);
    +    void putByte   (std::size_t  index,  int8 value);
    +    void putShort  (std::size_t  index, int16 value);
    +    void putInt    (std::size_t  index, int32 value);
    +    void putFloat  (std::size_t  index, float value);
    +    void putDouble (std::size_t  index, double value);
    +    bool getBoolean();
    +    int8 getByte   ();
    +    int16 getShort  ();
    +    int32 getInt    ();
    +    int64 getLong   ();
    +    float getFloat  ();
    +    double getDouble ();
    +    bool getBoolean(std::size_t  index);
    +    int8 getByte   (std::size_t  index);
    +    int16 getShort  (std::size_t  index);
    +    int32 getInt    (std::size_t  index);
    +    int64 getLong   (std::size_t  index);
    +    float getFloat  (std::size_t  index);
    +    double getDouble (std::size_t  index);
    +    const char* getArray();
    + ...
    +};
    + +

    destroyable.h

    +
    class Destroyable  {
    +public:
    +    POINTER_DEFINITIONS(Destroyable);
    +    virtual void destroy() = 0;
    +    virtual ~Destroyable() {};
    +};
    + +

    epicsException.h

    +
    /*
    + * Throwing exceptions w/ file+line# and, when possibly, a stack trace
    + *
    + * THROW_EXCEPTION1( std::bad_alloc );
    + *
    + * THROW_EXCEPTION2( std::logic_error, "my message" );
    + *
    + * THROW_EXCEPTION( mySpecialException("my message", 42, "hello", ...) );
    + *
    + * Catching exceptions
    + *
    + * catch(std::logic_error& e) {
    + *   fprintf(stderr, "%s happened\n", e.what());
    + *   PRINT_EXCEPTION2(e, stderr);
    + *   cout<<SHOW_EXCEPTION(e);
    + * }
    + *
    + * If the exception was not thrown with the above THROW_EXCEPTION*
    + * the nothing will be printed.
    + */
    + +

    event.h

    + +

    This class provides coordinates activity between threads. One thread can +wait for the event and the other signals the event.

    +
    class Event;
    +typedef std::tr1::shared_ptr<Event> EventPtr;
    + 
    +class Event {
    +public:
    +    POINTER_DEFINITIONS(Event);
    +    explicit Event(bool = false);
    +    ~Event();
    +    void signal();
    +    bool wait (); /* blocks until full */
    +    bool wait ( double timeOut ); /* false if empty at time out */
    +    bool tryWait (); /* false if empty */
    +...
    +}; 
    + +

    where

    +
    +
    Event
    +
    The constructor. The initial value can be full or empty. The normal + first state is empty.
    +
    signal
    +
    The event becomes full. The current or next wait will complete.
    +
    wait
    +
    Wait until event is full or until timeout. The return value is + (false,true) if the wait completed because event (was not, was) full. A + false value normally means that that a timeout occured. It is also + returned if an error occurs or because the event is being deleted.
    +
    tryWait
    +
    returns (false,true) if the event is (empty,full)
    +
    + +

    executor.h

    + +

    An Executor is a thread that can execute commands. The user can request that +a single command be executed.

    +
    +class Command;
    +class Executor;
    +typedef std::tr1::shared_ptr<Command> CommandPtr;
    +typedef std::tr1::shared_ptr<Executor> ExecutorPtr;
    +    
    +class Command {
    +public:
    +    POINTER_DEFINITIONS(Command);
    +    virtual ~Command(){}
    +    virtual void command() = 0;
    +private: 
    +    CommandPtr next;
    +    friend class Executor;
    +}; 
    + 
    +class Executor :  public Runnable{
    +public: 
    +    POINTER_DEFINITIONS(Executor);
    +    Executor(String threadName,ThreadPriority priority);
    +    ~Executor();
    +    void execute(CommandPtr const &node);
    +    virtual void run();
    + ...
    +};
    + +

    Command is a class that must be implemented by the code that calls execute. +It contains the single virtual method command, which is the command to +execute.

    + +

    Executor has the methods:

    +
    +
    Executor
    +
    The constructor. A thread name and priority must be specified.
    +
    ~Executor
    +
    The destructor. If any commands remain in the execute list they are not + called. All ExecutorNodes that have been created are deleted.
    +
    execute
    +
    Request that command be executed. If it is already on the run list + nothing is done.
    +
    + +

    localStaticLock.h

    +
    +extern epics::pvData::Mutex& getLocalStaticInitMutex();
    +
    +static class MutexInitializer {
    +  public:
    +    MutexInitializer ();
    +    ~MutexInitializer ();
    +} localStaticMutexInitializer; // Note object here in the header.
    +
    +

    TBD Matej will explain.

    + +

    lock.h

    +
    +typedef epicsMutex Mutex;
    +
    +class Lock : private NoDefaultMethods {
    +public:
    +    explicit Lock(Mutex &pm);
    +    ~Lock();
    +    void lock();
    +    void unlock();
    +    bool tryLock();
    +    bool ownsLock() ;
    + ...
    +};
    + +

    Lock is as easy to use as Java synchronize. To protect some object just +create a Mutex for the object and then in any method to be synchronized just +have code like:

    +
    class SomeClass {
    +private
    +    Mutex mutex;
    + ...
    +public
    +    SomeClass() : mutex(Mutex()) {}
    + ...
    +    void method()
    +    {
    +        Lock xx(mutex);
    +        ...
    +    }
    +
    + +

    The method will take the lock when xx is created and release the lock when +the current code block completes.

    + +

    Another example of Lock is initialization code that must initialize only +once. This can be implemented as follows:

    +
        static void init(void) {
    +        static Mutex mutex;
    +        Lock guard(mutex);
    +        if(alreadyInitialized) return;
    +        // initialization
    +    }
    +

    +

    Lock has a private variable: +

    +bool locked;
    +
    +and improves efficency by checking the local variable before calling the +mutex methods. This is not thread safe if any methods are called by a thread other than +the thread that created the Lock. +

    +

    It is thread safe if used as follows:

    +
    +{
    +    Lock guard(mutex);
    +    ...
    +    /* the following can optionally be called
    +    guard.unlock();
    +    guard.lock();
    +    */
    +}
    +
    +

    It is not thread safe if used as follows:

    +
    +class SomeClass
    +{
    +private:
    +    Mutex mutex;
    +    Lock lock;
    +public:
    +    SomeClass: lock(mutex) {}
    +    ...
    +    void someMethod() {
    +        lock.unlock();
    +        ...
    +    }
    +    ...
    +};
    +
    +

    It is only safe if all methods of Lock, including ~Lock(), +are called by the same thread. +

    + +

    messageQueue.h

    + +

    Definitions

    + +

    A messageQueue is for use by code that wants to handle messages without +blocking higher priority threads.

    +
    class MessageNode;
    +class MessageQueue;
    +typedef std::tr1::shared_ptr<MessageNode> MessageNodePtr;
    +typedef std::vector<MessageNodePtr> MessageNodePtrArray;
    +typedef std::tr1::shared_ptr<MessageQueue> MessageQueuePtr;
    +
    +class MessageNode {
    +public:
    +    String getMessage() const;
    +    MessageType getMessageType() const;
    +    void setMessageNull();
    +};
    +
    +class MessageQueue : public Queue<MessageNode> {
    +public:
    +    POINTER_DEFINITIONS(MessageQueue);
    +    static MessageQueuePtr create(int size);
    +    MessageQueue(MessageNodePtrArray &nodeArray);
    +    virtual ~MessageQueue();
    +    MessageNodePtr &get();
    +    // must call release before next get
    +    void release();
    +    // return (false,true) if message (was not, was) put into queue
    +    bool put(String message,MessageType messageType,bool replaceLast);
    +    bool isEmpty() ;
    +    bool isFull() ;
    +    int getClearOverrun();
    + ...
    +};
    + +

    A messageNode is a class with two public data members:

    +
    +
    getMessage
    +
    The message.
    +
    getMessageType
    +
    The message type.
    +
    setMessageNull
    +
    Set the message to be a null string.
    +
    + +

    A messageQueue is an interface with public methods:

    +
    +
    MessageQueue
    +
    The constructor. The queue size must be specified.
    +
    ~MessageQueue
    +
    The destructor.
    +
    put
    +
    Put a new message into the queue. False is returned if the queue was + full and true otherwise. If replaceLast is true then the last message is + replaced with this message.
    +
    get
    +
    Get the oldest queue element. If the queue is empty null is returned. + Before the next get can be issued release must be called.
    +
    release
    +
    Release the queue element returned by the last get.
    +
    isEmpty
    +
    Is the queue empty?
    +
    isFull
    +
    Is the queue full?
    +
    getClearOverrun
    +
    Get the number of times put has been called but no free element is + available.
    +
    + +

    Look at miscTest/testMessageQueue.cpp for an example.

    + +

    noDefaultMethods.h

    + +

    If a class privately extends this class then the compiler can not create any +of the following: default constructor, default copy constructror, or default +assignment contructor.

    +
    /* This is based on Item 6 of
    + * Effective C++, Third Edition, Scott Meyers
    + */
    +    class NoDefaultMethods {
    +    protected:
    +    // allow by derived objects
    +    NoDefaultMethods(){};
    +    ~NoDefaultMethods(){}
    +    private:
    +    // do not implment
    +    NoDefaultMethods(const NoDefaultMethods&);
    +    NoDefaultMethods & operator=(const NoDefaultMethods &);
    +    };
    + +

    queue.h

    + +

    This provides a bounded queue. When the queue is +full the user code is expected to keep using the current element until a new +free element becomes avalable.

    +
    +template <typename T>
    +class Queue
    +{   
    +public:
    +    POINTER_DEFINITIONS(Queue);
    +    typedef std::tr1::shared_ptr<T> queueElementPtr;
    +    typedef std::vector<queueElementPtr> queueElementPtrArray;
    +    Queue(queueElementPtrArray &);
    +    virtual ~Queue();
    +    void clear();
    +    int capacity();
    +    int getNumberFree();
    +    int getNumberUsed();
    +    queueElementPtr & getFree();
    +    void setUsed(queueElementPtr const &element);
    +    queueElementPtr & getUsed();
    +    void releaseUsed(queueElementPtr const &element);
    + ...
    +};
    + +

    testApp/misc/testQueue.cpp provides an example of how to define a queue.

    + +

    The queue methods are:

    +
    +
    clear
    +
    Make the queue empty.
    +
    getNumberFree
    +
    Get the number of free elements in the queue.
    +
    capacity
    +
    Get the capacity, i.e. the maximun number of elements the queue can + hold.
    +
    getNumberFree
    +
    Get the number of free elements.
    +
    getNumberUsed
    +
    Get the number of elements used.
    +
    getFree
    +
    Get the next free element. Null is returned if no free elements are + available. If a non null value is returned then the element belongs to + the caller until setUsed is called.
    +
    setUsed
    +
    Set a queue element used. This must be the element returned by the last + call to getFree.
    +
    getUsed
    +
    Get the next used element of null if no more used elements are + available.
    +
    releaseUsed
    +
    Set a queue element free. This must be the element returned by the last + call to getUsed.
    +
    + +

    A queue is created as follows:

    +
       class MyClass;
    +   typedef MyQueueElement<MyClass> MyElement;
    +   typedef MyQueue<MyClass> MyQueue;
    +   int numElement = 5;
    +   ...
    +   MyClass *array[numElements];
    +   for(int i=0; i<numElements; i++) {
    +        array[i] = new MyClass();
    +   }
    +   MyQueue *queue = new MyQueue(array,numElements);
    + +

    A producer calls getFree and setUsed via code like the following:

    +
       MyClass *getFree() {
    +       MyElement *element = queue->getFree();
    +       if(element==0) return 0;
    +       return element->getObject();
    +  }
    + +

    A consumer calls getUsed and releaseUsed via code like the following:

    +
         while(true) {
    +         MyElement *element = queue->getUsed();
    +         if(element==0) break;
    +         MyClass *myClass = element->getObject();
    +         // do something with myClass
    +         queue->releaseUsed(element);
    +     }
    + +

    requester.h

    + +

    Requester is present so that when +errors are found there is someplace to send a message. +At one time PVField extended Requester but it no longer does. +Requester is, however, used by pvAccess. +

    +
    +class Requester;
    +typedef std::tr1::shared_ptr<Requester> RequesterPtr;
    +
    +enum MessageType {
    +   infoMessage,warningMessage,errorMessage,fatalErrorMessage
    +};
    +
    +extern String getMessageTypeName(MessageType messageType);
    +extern const size_t messageTypeCount;
    +class Requester {
    +public:
    +    POINTER_DEFINITIONS(Requester);
    +    virtual ~Requester(){}
    +    virtual String getRequesterName() = 0;
    +    virtual void message(String const & message,MessageType messageType) = 0;
    +};
    + +

    where

    +
    +
    +
    MessageType
    +
    Type of message.
    +
    messageTypeName
    +
    An array of strings of the message type names, i.e. + String("info"),String("warning"),String("error"),String("fatalError").
    +
    getRequesterName
    +
    Returns the requester name.
    +
    message
    +
    Gives a message to the requester.
    +
    + +

    serialize.h

    +
    +    class SerializableControl;
    +    class DeserializableControl;
    +    class Serializable;
    +    class BitSetSerializable;
    +    class SerializableArray;
    +    class BitSet;
    +    class Field;
    +
    +    class SerializableControl {
    +    public:
    +        virtual ~SerializableControl(){}
    +        virtual void flushSerializeBuffer() =0;
    +        virtual void ensureBuffer(std::size_t size) =0;
    +        virtual void alignBuffer(std::size_t alignment) =0;
    +        virtual void cachedSerialize(
    +            std::tr1::shared_ptr<const Field> const & field,
    +            ByteBuffer* buffer) = 0;
    +    };
    +
    +    class DeserializableControl {
    +    public:
    +        virtual ~DeserializableControl(){}
    +        virtual void ensureData(std::size_t size) =0;
    +        virtual void alignData(std::size_t alignment) =0;
    +        virtual std::tr1::shared_ptr<const Field> cachedDeserialize(
    +            ByteBuffer* buffer) = 0;
    +    };
    +
    +    class Serializable {
    +    public:
    +        virtual ~Serializable(){}
    +        virtual void serialize(ByteBuffer *buffer,
    +            SerializableControl *flusher) const = 0;
    +        virtual void deserialize(ByteBuffer *buffer,
    +            DeserializableControl *flusher) = 0;
    +    };
    +
    +    class BitSetSerializable {
    +    public:
    +        virtual ~BitSetSerializable(){}
    +        virtual void serialize(ByteBuffer *buffer,
    +            SerializableControl *flusher,BitSet *bitSet) const = 0;
    +        virtual void deserialize(ByteBuffer *buffer,
    +            DeserializableControl *flusher,BitSet *bitSet) = 0;
    +    };
    +
    +
    +    class SerializableArray : virtual public Serializable {
    +    public:
    +        virtual ~SerializableArray(){}
    +        virtual void serialize(ByteBuffer *buffer,
    +            SerializableControl *flusher, std::size_t offset,
    +            std::size_t count) const = 0;
    +    };
    + +

    serializeHelper.h

    + +

    This is a helper class for serialization, which is required for sending and +receiving pvData over the nerwork.

    +
    class SerializeHelper : public NoDefaultMethods {
    +public:
    +    static void writeSize(int s, ByteBuffer* buffer,
    +        SerializableControl* flusher);
    +    static int readSize(ByteBuffer* buffer,
    +        DeserializableControl* control);
    +    static void serializeString(const String& value,
    +        ByteBuffer* buffer,SerializableControl* flusher);
    +    static void serializeSubstring(const String& value, int offset,
    +        int count, ByteBuffer* buffer,
    +        SerializableControl* flusher);
    +    static String deserializeString(ByteBuffer* buffer,
    +        DeserializableControl* control);
    + ...
    +};
    + +

    where

    +
    +
    writeSize
    +
    Serialize the size.
    +
    readSize
    +
    Deserialize the size.
    +
    serializeString
    +
    Serialize a String.
    +
    serializeSubstring
    +
    Serialize a substring.
    +
    deserializeString
    +
    Deserialize a string.
    +
    + +

    sharedPtr.h

    +
    +#define POINTER_DEFINITIONS(clazz) \
    +    typedef std::tr1::shared_ptr<clazz> shared_pointer; \
    +    typedef std::tr1::shared_ptr<const clazz> const_shared_pointer; \
    +    typedef std::tr1::weak_ptr<clazz> weak_pointer; \
    +    typedef std::tr1::weak_ptr<const clazz> const_weak_pointer;
    + +

    sharedVector.h

    +

    +shared_vector is a holder for a contigious piece of memory. +Data is shared, but offset and length are not. +This allows one vector to have access to only a subset of a piece of memory. +

    +

    +shared_vector differs from std::vector as follows:

    +
    +
    Differences in behavior
    +
    + shared_vector models const-ness like shared_ptr. + An equivalent of 'const std::vector<E>' is + 'const shared_vector<const E>'. + However, it is also possible to have 'const shared_vector<E>' + analogous to 'E* const' and 'shared_vector<const E>>' + which is analogous to 'const E*'.i +
    + Copying a shared_vector, by construction or assignment, does not copy + its contents. + Modifications to one such "copy" effect all + associated shared_vector instances. +
    + std::vector::reserve(N) has no effect if N<=std::vector::capacity(). + However, like resize(), shared_vector<E>::reserve() has the side effect + of always calling make_unique(). +
    +
    Parts of std::vector interface not implemented
    +
    + Mutating methods insert(), erase(), shrink_to_fit(), emplace(), and emplace_back() are not implemented. +
    + shared_vector does not model an allocator which is bound to the object. Therefore the get_allocator() method and the allocator_type typedef are not provided. +
    + The assign() method and the related constructor are not implemented at this time. +
    + The comparison operators are not implemented at this time. +
    +
    Parts not found in std::vector
    +
    + shared_vector has additional constructors from raw pointers and shared_ptr s. + The copy constructor and assignment operator allow implicit castings + from type 'shared_vector<T>' to 'shared_vector<const T>>'. + To faciliate safe modification the methods unique() and make_unique() are provided + The slice() method selects a sub-set of the shared_vector. + The low level accessors dataPtr(), dataOffset(), dataCount(), and dataTotal(). +
    +
    + + +
    +template<typename E, class Enable = void& class shared_vector;
    +
    +template<typename E, class Enable&
    +class shared_vector : public detail::shared_vector_base<E&
    +{
    +    typedef detail::shared_vector_base<E& base_t;
    +    typedef typename detail::call_with<E&::type param_type;
    +    typedef typename meta::strip_const<E&::type _E_non_const;
    +public:
    +    typedef E value_type;
    +    typedef E& reference;
    +    typedef typename meta::decorate_const<E&::type& const_reference;
    +    typedef E* pointer;
    +    typedef typename meta::decorate_const<E&::type* const_pointer;
    +    typedef E* iterator;
    +    typedef std::reverse_iterator<iterator& reverse_iterator;
    +    typedef typename meta::decorate_const<E&::type* const_iterator;
    +    typedef std::reverse_iterator<const_iterator& const_reverse_iterator;
    +    typedef ptrdiff_t difference_type;
    +    typedef size_t size_type;
    +
    +    typedef E element_type;
    +    typedef std::tr1::shared_ptr<E& shared_pointer_type;
    +
    +    // allow specialization for all E to be friends
    +    template<typename E1, class Enable1& friend class shared_vector;
    +
    +    shared_vector() :base_t();
    +    explicit shared_vector(size_t c)
    +        :base_t(new _E_non_const[c], 0, c);
    +    shared_vector(size_t c, param_type e);
    +    template<typename A&
    +    shared_vector(A v, size_t o, size_t c) :base_t(v,o,c);
    +    template<typename E1&
    +    shared_vector(const std::tr1::shared_ptr<E1&& d, size_t o, size_t c);
    +    template<typename A, typename B&
    +    shared_vector(A d, B b, size_t o, size_t c);
    +    shared_vector(const shared_vector& o) :base_t(o);
    +    
    +    size_t max_size() const;
    +    size_t capacity() const;
    +    void reserve(size_t i);
    +    void resize(size_t i);
    +    void resize(size_t i, param_type v);
    +    void make_unique();
    +    
    +    iterator begin() const;
    +    iterator end() const;
    +    reverse_iterator rbegin() const;
    +    reverse_iterator rend() const;
    +    reference front() const;
    +    reference back() const;
    +
    +    void push_back(param_type v);
    +    void pop_back();
    +    pointer data() const;
    +    reference operator[](size_t i) const;
    +    reference at(size_t i) const;
    +    // inherited from detail
    +    shared_vector_base& operator=(const shared_vector_base& o);
    +    void swap(shared_vector_base& o);
    +    void clear();
    +    bool unique() const;
    +    size_t size() const;
    +    bool empty() const;
    +    void slice(size_t offset, size_t length=(size_t)-1);
    +    const std::tr1::shared_ptr<E&& dataPtr();
    +    size_t dataOffset() const;
    +    size_t dataCount() const;
    +    size_t dataTotal() const;
    +
    +where +
    +
    shared_vector
    +
    Several flavors of constructor are provided. The most commingly used is: +
    +shared_vector(size_t c);
    +       
    + This creates a shared_vector of the specified size/ +
    +
    max_size
    +
    The maximum size the C++ implementation allows, i.e., + the maximum possible capacity. + Note that units are number of elements not number of bytes. +
    +
    capacity
    +
    The current capacity.
    +
    reserve
    +
    Set array capacity.
    +
    resize
    +
    Grow or shrink array. + It the second argument is given it is the value to assign to + and new elements. +
    +
    make_unique
    +
    Ensure (by copying) that this shared_vector + is the sole owner of the data array. +
    +
    begin,...,rend
    +
    Standard interators.
    +
    front
    +
    Return a reference to the first element.
    +
    back
    +
    Return a reference to the last element.
    +
    push_back
    +
    Add an element to the end of the array.
    +
    pop_back
    +
    Remove an element from the end of the array.
    +
    data
    +
    Return a pointer to the raw array.
    +
    operator[](size_t i)
    +
    Return a reference to the specified element.
    +
    at
    +
    Like the previous except that it throws a range-error if + the specified element is out of range.
    +
    operator=
    +
    Copy an existing shared_vector.
    +
    swap
    +
    Swap the contents of this vector with another.
    +
    clear
    +
    Clear contents.
    +
    unique
    +
    returns (true,false) if data (is not, is) shared.
    +
    size
    +
    Number of elements visible through this vector.
    +
    empty
    +
    Is the number of elements zero?
    +
    slice
    +
    Reduce the view of this shared_vector.
    +
    dataPtr
    +
    A readonly shared_ptr to the array.
    +
    dataOffset
    +
    Offset in the data array of first visible element.
    +
    dataCount
    +
    Number of visible elements between dataOffset and end of data.
    +
    dataTotal
    +
    The total number of elements between dataOffset and the end of data
    +
    +

    TBD +Michael should decide if this is the correct set of methods to describe. +Also he should check for correct descriptions. +

    + + +

    status.h

    + +

    Status provides a way to pass status back to client code:

    +
    class Status : public epics::pvData::Serializable {
    +    public:
    +   enum StatusType { 
    +         /** Operation completed successfully. */
    +         STATUSTYPE_OK,
    +         /** Operation completed successfully, but there is a warning message. */
    +         STATUSTYPE_WARNING,
    +         /** Operation failed due to an error. */
    +         STATUSTYPE_ERROR,
    +         /** Operation failed due to an unexpected error. */
    +         STATUSTYPE_FATAL
    +    }; 
    +    static const char* StatusTypeName[];
    +    static Status OK;
    +    Status();
    +    Status(StatusType type, epics::pvData::String const & message);
    +    Status(StatusType type, epics::pvData::String const & message, epics::pvData::String stackDump);
    +    ~Status()
    +    StatusType getType() const;
    +    String getMessage() const;
    +    String getStackDump() const;
    +    bool isOK() const;
    +    bool isSuccess() const;
    +    String toString() const;
    +    void toString(StringBuilder buffer, int indentLevel = 0) const;
    +    void serialize(ByteBuffer *buffer, SerializableControl *flusher) const;
    +    void serialize(ByteBuffer *buffer, SerializableControl *flusher) const;
    +};
    + +

    The Status methods are:

    +
    +
    StatusType
    +
    An enum for the status type.
    +
    getType
    +
    Get the statusType.
    +
    getMessage
    +
    Get a message explaining the error.
    +
    getStackDump
    +
    Get a stack dump.
    +
    + +

    The StatusCreate methods are:

    +
    +
    getStatusOK
    +
    Get a singleton that returns StatusType.OK and a null message and + stackDump.
    +
    createStatus
    +
    Create a new Status.
    +
    deserializeStatus
    +
    Use this method instead of Status.deserialize(), since this allows OK + status optimization.
    +
    +

    templateMeta.h

    +

    TBD Michael will explain.

    + +

    thread.h

    + +

    ThreadPriority

    +
    enum ThreadPriority {
    +    lowestPriority,
    +    lowerPriority,
    +    lowPriority,
    +    middlePriority,
    +    highPriority,
    +    higherPriority,
    +    highestPriority
    +};
    + +

    Thread

    +
    +class Thread;
    +typedef std::tr1::shared_ptr<Thread> ThreadPtr;
    +typedef std::tr1::shared_ptr<epicsThread> EpicsThreadPtr;
    +
    +class Runnable {
    +public:
    +    virtual void run() = 0;
    +};
    +
    +class Thread;
    +
    +class Thread : public epicsThread, private NoDefaultMethods {
    +public:
    +    Thread(
    +        String name,
    +        ThreadPriority priority,
    +        Runnable *runnableReady,
    +        epicsThreadStackSizeClass stkcls=epicsThreadStackSmall);
    +    ~Thread();
    + ...
    +};
    + +

    Runnable must be implement by code that wants to be run via a thread. It has +one virtual method: run. Run is the code that is run as a thread. When run +compeletes it can not be restarted. If code wants to delete a thread then it +MUST arrange that the run returns before the thread can be deleted. An +exception is thrown if run remains active when delete is called.

    + +

    Thread has the methods:

    +
    +
    Thread
    +
    The constructor. A thread name and priority must be specified. The run + methods of runnable is executed. When the run methods returns the thread + will no longer be active but the client code must still delete the + thread.
    +
    ~Thread
    +
    The destructor. This is called as the result of: +
        delete pthread;
    +
    +
    + +

    timeFunction.h

    + +

    TimeFunction is a facility that measures the average number of seconds a +function call requires. When timeCall is called, it calls function in a loop. +It starts with a loop of one iteration. If the total elapsed time is less then +.1 seconds it increases the number of iterrations by a factor of 10. It keeps +repeating until the elapsed time is greater than .1 seconds. It returns the +average number of seconds per call.

    +
    class TimeFunctionRequester;
    +class TimeFunction;
    +typedef std::tr1::shared_ptr<TimeFunctionRequester> TimeFunctionRequesterPtr;
    +typedef std::tr1::shared_ptr<TimeFunction> TimeFunctionPtr;
    +        
    +class TimeFunctionRequester {
    +public:              
    +    POINTER_DEFINITIONS(TimeFunctionRequester);
    +    virtual ~TimeFunctionRequester(){}
    +    virtual void function() = 0;
    +};  
    +
    +    
    +class TimeFunction {
    +public:    
    +    POINTER_DEFINITIONS(TimeFunction);
    +    TimeFunction(TimeFunctionRequesterPtr const & requester);
    +    ~TimeFunction(); 
    +    double timeCall();
    + ...
    +};      
    + +

    TimeFunctionRequester must be implemented by code that wants to time how +long a function takes. It has the single method:

    +
    +
    function
    +
    This is the function.
    +
    + +

    TimeFunction has the methods:

    +
    +
    TimeFunction
    +
    Constructor.
    +
    ~TimeFunction
    +
    Destructor.
    +
    timeCall
    +
    Time how long it takes to execute the function. It starts by calling + the function one time. If it takes < 1 seconds to doubles the number + of times to call the function. It repeats this until it takes at least + one second to call it ntimes.
    +
    + +

    timer.h

    + +

    This provides a general purpose timer. It allows a user callback to be +called after a delay or periodically.

    +
    class TimerCallback;
    +class Timer;
    +typedef std::tr1::shared_ptr<TimerCallback> TimerCallbackPtr;
    +typedef std::tr1::shared_ptr<Timer> TimerPtr;
    +
    +
    +class TimerCallback {
    +public:
    +    POINTER_DEFINITIONS(TimerCallback);
    +    TimerCallback();
    +    virtual ~TimerCallback(){}
    +    virtual void callback() = 0;
    +    virtual void timerStopped() = 0;
    +};
    +
    +class Timer : private Runnable {
    +public:
    +    POINTER_DEFINITIONS(Timer);
    +    Timer(String threadName, ThreadPriority priority);
    +    virtual ~Timer();
    +    virtual void run();
    +    void scheduleAfterDelay(
    +        TimerCallbackPtr const &timerCallback,
    +        double delay);
    +    void schedulePeriodic(
    +        TimerCallbackPtr const &timerCallback,
    +        double delay,
    +        double period));
    +    void cancel(TimerCallbackPtr const &timerCallback);
    +    bool isScheduled(TimerCallbackPtr const &timerCallback);
    +    void toString(StringBuilder builder);
    + ...
    +};
    + +

    TimerCallback must be implemented by the user. It has the following methods: +

    +
    +
    callback
    +
    This is called when a timer expires. This is called with no locks held. + When called a delay timer is no longer on the queue but a periodioc timer + is on a queue. Thus the callback for a delay timer can issue a new + schedule request but a periodic timer must not. Note the explaination of + TimerNode.cancel below.
    +
    timerStopped
    +
    Timer.stop was called when a timer request was queued. or if the timer + is stopped and a schedule request is made.
    +
    + +

    In order to schedule a callback client code must allocate a TimerNode It can +be used to schedule multiple callbacks. It has the methods:

    +
    +
    TimerNode
    +
    The constructor. User code must create a TimeNode in order to call a + schedule method.
    +
    ~TimerNode
    +
    The destructor. This is called as a result of the client calling: +
        delete timerNode;
    +
    +
    cancel
    +
    This is called to cancel a timer request. If a callback has been + dequeued but the callback not called when cancel is called then a + callback may still happen. New schedule requests can be made after a + cancel request has been made.
    +
    isScheduled
    +
    Is the timerNode scheduled to be called.
    +
    + +

    Timer has the methods:

    +
    +
    Timer
    +
    The consttructor.
    +
    ~Timer
    +
    The destructor. The queue is emptied and TimerCallback.timerStopped is + called for each element of the queue.
    +
    scheduleAfterDelay
    +
    A request to schedule a callback after a delay specified in + seconds.
    +
    schedulePeriodic
    +
    Schedule a periodic callback.
    +
    +

    typeCast.h

    +

    TBD Michael will explain.

    + +

    pvDataApp/pvMisc

    + +

    bitSetUtil.h

    + +

    The following is also provided:

    +
    class BitSetUtil : private NoDefaultMethods {
    +public:
    +    static bool compress(BitSet const &bitSet,PVStructure const &pvStructure);
    +};
    + +

    This provides functions that operate on a BitSet for a PVStructure. It +currently has only one method:

    +
    +
    compress
    +
    Compress the bits in a BitSet related to a structure.
    + For each structure: +
      +
    1. If the bit for the structure is set then the bit for all subfields + of the structure are cleared.
    2. +
    3. If the bit for the structure is not set but all immediate subfields + have their bit set then the bit for the structure is set and the bits + for all subfields are cleared.
    4. +
    + Note that this is a recursive algorithm. That is if every immediate + subfield has it's offset bit set then the bits for ALL fields that reside + in the structure will be cleared.
    +
    Channel Access can call this before sending data. It can then pass + entire structures if the structure offset bit is set.
    +
    + +

    support for copy and monitor

    +

    copy and monitor are not used in this project. +They are intended for use by pvAccess and by pvAccess servers. +They are provided with this project because the code depends only on +pvData itself. +

    +

    This document describes C++ specific code. + +pvRequest.html +provides a language independent overview of copy and monitor. +

    +

    +NOTE:pvRequest.html must be updated since it is based on an earlier version of pvCopy that +had knowlege of PVRecord. The C++ version was implemented in pvDatabaseCPP +and the Java version on pvIOCJava. +At present only the C++ version of the new API for pvCopy is implemented. +

    +

    Copy provides: +

    +
    createRequest
    +
    + The Channel create methods in pvAccess all have an argument + PVStructure pvRequest.
    + Given an ascii string createRequest creates a PVStructure that provides + a pvData representation of the information from the ascii string. + It is this structure that can be passed to the channel create methods.
    + The information in a pvRequest selects an arbitrarary subset of the + fields in a top level structure that resides in the server. + In addition options can be specified. Both global and field specific + options can be specified. +
    +
    pvCopy
    +
    This is a faculity used by channel providers. + It provides client specific code that manages a copy of an arbitrary + subset of the fields in a top level structure that resides in the + provider. It also allows provider access to options specified + by the client. +
    +
    +Monitor provides: +
    +
    monitor
    +
    This is support code for channel providers that implement channel + monitor. It, together with the queue facility, provides support for + monitor queues. +
    +
    monitorPlugin
    +
    This is support for implementing monitor plugins. + A monitor plugin can be developed that has no knowledge + of pvAccess but only pvData. +
    +
    +

    + +

    support for copy

    +

    copy provides the ability to create a structure that has +a copy of an arbitrary subset of the fields in an existing top level +structure. In addition it allows global options and field specific options. +It has two main components: createRequest and pvCopy. +Given a string createRequest creates a pvRequest, which is a PVStructure +that has the format expected by pvCopy. +

    + +

    createRequest

    +

    This is mainly used by pvAccess clients. Given a request string it creates +a pvRequest structure that can be passed to the pvAccess create methods. +In turn pvAccess passes the pvRequest to a local channel provider which +then passes it to pvCopy. +

    +

    The definition of the public members is:

    +
    +class CreateRequest {
    +...
    +     static CreateRequestPtr create();
    +     virtual PVStructurePtr createRequest(String const &request);
    +     String getMessage();
    +};
    +
    +

    An example of how it is used is:

    +
    +CreateRequestPtr createRequest = CreateRequest::create();
    +PVStructurePtr pvRequest = createRequest->createRequest(request);
    +if(pvRequest==NULL) {
    +    String error = createRequest->getMessage();
    +    // take some action
    +} else {
    +    //success do something
    +}
    +
    +

    pvCopy

    +

    The definition of the public members is:

    +
    +class epicsShareClass PVCopyTraverseMasterCallback
    +{
    +...
    +    virtual void nextMasterPVField(PVFieldPtr const &pvField);
    +};
    +
    +class class epicsShareClass PVCopy
    +{
    +...
    +    static PVCopyPtr create(
    +        PVStructurePtr const &pvMaster,
    +        PVStructurePtr const &pvRequest,
    +        String const & structureName);
    +    PVStructurePtr getPVMaster();
    +    void traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback);
    +    StructureConstPtr getStructure();
    +    PVStructurePtr createPVStructure();
    +    size_t getCopyOffset(PVFieldPtr const  &masterPVField);
    +    size_t getCopyOffset(
    +        PVStructurePtr const  &masterPVStructure,
    +        PVFieldPtr const  &masterPVField);
    +     PVFieldPtr getMasterPVField(std::size_t structureOffset);
    +     void initCopy(
    +        PVStructurePtr const  &copyPVStructure,
    +        BitSetPtr const  &bitSet);
    +     void updateCopySetBitSet(
    +        PVStructurePtr const  &copyPVStructure,
    +        BitSetPtr const  &bitSet);
    +    void updateCopyFromBitSet(
    +        PVStructurePtr const  &copyPVStructure,
    +        BitSetPtr const  &bitSet);
    +    void updateMaster(
    +        PVStructurePtr const  &copyPVStructure,
    +        BitSetPtr const  &bitSet);
    +    PVStructurePtr getOptions(std::size_t fieldOffset);
    +...
    +};
    +
    +where +
    +
    PVCopyTraverseMasterCallback::nextMasterPVField
    +
    + PVCopyTraverseMasterCallback is a callback which must + be implemented by the code that uses pvCopy, normally + the channel provider. It has the single method nextMasterPVField +
    + nextMasterPVField is called for each field in the master + as a result of a call to traverseMaster. +
    +
    create
    +
    + This is the method for creating a PVCopy instance.
    +
    +
    pvMaster
    +
    the top level sructure managed by the server.
    +
    pvRequest
    +
    selects the set of subfields desired + and options for each field.
    +
    structureName
    +
    the name for the top level of any PVStructure created. +
    +
    +
    +
    getPVMaster
    +
    + Gets the top level structure from pvMaster. +
    +
    traverseMaster
    +
    + Traverse all fields of the top level structure of pvMaster. + For each field the callback is called. +
    +
    getStructure
    +
    + Get the introspection interface for a PVStructure for e copy. +
    +
    createPVStructure
    +
    Create a copy instance. + Monitors keep a queue of monitor elements. + Since each element needs a PVStructure, multiple top level structures + will be created. +
    +
    getCopyOffset
    +
    Given a field in pvMaster. + return the offset in copy for the same field. + A value of String::npos means that the copy does not have this field. + Two overloaded methods are provided. The first is called if + the field of master is not a structure. The second is for + subfields of a structure. +
    +
    getMasterPVField
    +
    + Given a offset in the copy get the corresponding field in pvMaster. +
    +
    initCopy
    +
    + Initialize the fields in copyPVStructure + by giving each field the value from the corresponding field in pvMaster. + bitSet will be set to show that all fields are changed. + This means that bit set will have the value {0}. +
    +
    updateCopySetBitSet
    +
    + Set all fields in copyPVStructure to the value of the corresponding field + in pvMaster. Each field that is changed has it's corresponding + bit set in bitSet. +
    +
    updateCopyFromBitSet
    +
    + For each set bit in bitSet set the field in copyPVStructure to the value + of the corrseponding field in pvMaster. +
    +
    updateMaster
    +
    + For each set bit in bitSet set the field in pvMaster to the value + of the corrseponding field in copyPVStructure. + +
    +
    getOptions
    +
    + Get the options for the field at the specified offset. + A NULL is returned if no options were specified for the field. + If options were specified,PVStructurePtr is + a structure with a set of PVString subfields that specify name,value + pairs. name is the subField name and value is the subField value. +
    +
    + + + + +

    support for monitor

    +

    This consists of two components: +

    +
    monitor
    +
    Used by code that implements pvAccess montors.
    +
    monitorPlugin
    +
    Code that provides special semantics for monitors.
    +
    +

    +

    monitor

    +
    +class MonitorElement {
    +    MonitorElement(PVStructurePtr const & pvStructurePtr);
    +    PVStructurePtr pvStructurePtr;
    +    BitSetPtr changedBitSet;
    +    BitSetPtr overrunBitSet;
    +};
    +
    +class Monitor {
    +    virtual Status start() = 0;
    +    virtual Status stop() = 0;
    +    virtual MonitorElementPtr poll() = 0;
    +    virtual void release(MonitorElementPtr const & monitorElement) = 0;
    +};
    +
    +class MonitorRequester : public virtual Requester {
    +    virtual void monitorConnect(Status const & status,
    +        MonitorPtr const & monitor, StructureConstPtr const & structure) = 0;
    +    virtual void monitorEvent(MonitorPtr const & monitor) = 0;
    +    virtual void unlisten(MonitorPtr const & monitor) = 0;
    +};
    +
    +

    monitorElement

    +

    MonitorElement holds the data for one element of a monitor queue. +It has the fields: +

    +
    pvStructurePtr
    +
    A top level structure with data values at the time the monitors occurs.
    +
    changedBitSet
    +
    Shows which fields have changed since the previous monitor.
    +
    overrunBitSet
    +
    Shows which fields have changed more han once since the previous monitor.
    +
    +

    +

    monitorElement queue

    +

    +A queue of monitor elements must be implemented by any channel provider that implements +Channel::createMonitor. +For an example implementation look at pvDatabaseCPP. +It has the following: +

    +typedef Queue<MonitorElement> MonitorElementQueue;
    +typedef std::tr1::shared_ptr<MonitorElementQueue> MonitorElementQueuePtr;
    +
    +class MultipleElementQueue :
    +    public ElementQueue
    +{
    +public:
    +    POINTER_DEFINITIONS(MultipleElementQueue);
    +    virtual ~MultipleElementQueue(){}
    +    MultipleElementQueue(
    +        MonitorLocalPtr const &monitorLocal,
    +        MonitorElementQueuePtr const &queue,
    +        size_t nfields);
    +    virtual void destroy(){}
    +    virtual Status start();
    +    virtual Status stop();
    +    virtual bool dataChanged();
    +    virtual MonitorElementPtr poll();
    +    virtual void release(MonitorElementPtr const &monitorElement);
    +...
    +};
    +
    +

    Monitor

    +

    Monitor must be implemented by any channel provider that implements +Channel::createMonitor. +Remote PVAccess also implements Monitor on the client side. +Note that each client has it's own queue that is not shared with other client. +

    +

    Monitor has the following methods:

    +
    +
    start
    +
    + Start monitoring. + This will result in a an inital monitor that has the current value + of all fields. +
    +
    stop
    +
    + Stop monitoring. +
    +
    poll
    +
    + Called to get a monitor element. + If no new elemants are available then a null pointer is returned. +
    +
    release
    +
    + Release the monotor element. + The caller owns the monitor element between the calls to poll and release. +
    +
    +
    +

    MonitorRequester

    +

    This must be implemented by a pvAccess client. +It has the methods:

    +
    +
    monitorConnect
    +
    + A monitor has either connected of disconnected. +
    +
    monitorEvent
    +
    + A new monitor element is available. +
    +
    unlisten
    +
    + The channel is going away. The client cam no longer access the monitor. +
    +
    + +

    monitorPlugin

    +
    +class MonitorPlugin
    +{
    +    virtual String const & getName() = 0;
    +    virtual bool causeMonitor(
    +        PVFieldPtr const &pvField,
    +        PVStructurePtr const &pvTop,
    +        MonitorElementPtr const &monitorElement) = 0;
    +    virtual void monitorDone(
    +        MonitorElementPtr const &monitorElement);
    +    virtual void startMonitoring();
    +    virtual void stopMonitoring();
    +    virtual void beginGroupPut();
    +    virtual void endGroupPut();
    +};
    +
    +class MonitorPluginCreator
    +{
    +    virtual MonitorPluginPtr create(
    +        FieldConstPtr const &field,
    +        StructureConstPtr const &top,
    +        PVStructurePtr const &pvFieldOptions) = 0;
    +     virtual String const & getName() = 0;
    +}
    +
    +class MonitorPluginManager
    +{
    +    static MonitorPluginManagerPtr get();
    +    bool addPlugin(
    +         String const &pluginName,
    +         MonitorPluginCreatorPtr const &creator);
    +    MonitorPluginCreatorPtr findPlugin(String const &pluginName);
    +    void showNames();
    +};
    +
    +
    +

    MonitorPlugin

    +

    MonitorPlugin must be implemented by the plugin implementation. +It has methods:

    +
    +
    getName
    +
    Get the name of the plugin.
    +
    causeMonitor
    +
    + Should the value of pvField cause a monitor to be raised. + pvField and pvTop are fields in the top level structure + being monitored. monitorElement has the top level structure + for the copy. + The implementation should not modify the fields in the structure + being monitored. + Called with pvTop locked. +
    +
    monitorDone
    +
    + Called just before monitorElement will be given to client. + The plugin can change the data values and bitSets in monitorElement. + Called with pvTop unlocked. +
    +
    startMonitoring
    +
    + Monitoring is starting. +
    +
    stopMonitoring
    +
    + Monitoring is being stopped. +
    +
    beginGroupPut
    +
    + A set of puts is starting. + Called with pvTop locked. +
    +
    endGroupPut
    +
    + The set of puts is complete. + Called with pvTop locked. +
    +
    +

    MonitorPluginCreator

    +

    MonitorPluginCreator must also be implemented by the plugin implementation. +It is called for each field instance that has options of the from +[plugin=name...] where name is the name of the plugin. +Note that a plugin instance will belong to a single client. +It has methods:

    +
    +
    getName
    +
    Get the name of the plugin.
    +
    create
    +
    + Create a new plugin instance. + If the arguments are not compatible with the plugin a NULL shared pointer is + returned.
    + pvFieldOptions is + a structure with a set of PVString subfields that specify name,value + pairs. name is the subField name and value is the subField value.
    + Note that a plugin will below to a single client. +
    +
    +

    MonitorPluginManager

    +

    MonitorPluginManager has the methods:

    +
    +
    get
    +
    + MonitorPluginManager is a singleton. + The first call to get will create the single instance. + Further calls will rerurn the single instance. +
    +
    addPlugin
    +
    + Add a new plugin. +
    +
    findPlugin
    +
    + Find a plugin. A NULL shared pointer is reurned if it has not been added. +
    +
    showNames
    +
    + Show the names of all puugins that have been added. +
    +
    +

    NOTE: +Should the method causeMonitor +have arguments pvField and pvTop +be defined so that they can not be modfied. +This would be posssible if the following was defined: +

    +typedef std::tr1::shared_ptr<const PVField> PVFieldConstPtr;
    +typedef std::tr1::shared_ptr<const PVStructure> PVStructureConstPtr;
    +
    +then the definition for causeMonitor could be: +
    +virtual bool causeMonitor(
    +        PVFieldConstPtr const &pvField,
    +        PVStructureConstPtr const &pvTop,
    +        MonitorElementPtr const &monitorElement) = 0;
    +
    +But just adding these definitions is not sufficent. +In addition all methods defined in pvDataCPP must be checked. +In particular many of the methods in Convert must have +their arguments modified. +Big job. +

    +

    monitorPlugin example

    +

    Example Plugin Overview

    +

    This section describes an example plugin that:

    +
      +
    • Only raises monitors when a field changes value.
      + If no plugin is provided + the default is to raise a monitor when a put is issued to a field.
    • +
    • Optionally a change will not raise a monitor.
      + The change will, however, + appear if a put to another field raise a monitor.
    • +
    +

    As an example assume that a channel provided by pvAccess has a top level structure +that represents a power supply.

    +
    +structure powerSupply
    +    structure alarm
    +    structure timeStamp
    +    structure power
    +       double value
    +       structure alarm
    +       struvture display
    +    structure voltage
    +       double value
    +       structure alarm
    +       struvture display
    +    structure current
    +       double value
    +       structure alarm
    +       struvture display
    +
    +

    A pvAccess client wants to create a monitor on the powerSupply as follows: +The client wants a top level structure that looks like: +

    +structure powerSupply
    +    structure alarm
    +    structure timeStamp
    +    structure power
    +       double value
    +    structure voltage
    +       double value
    +    structure current
    +       double value
    +
    +In addition the client wants monitors to occur only when one of the monitored +fields changes value but not just because a put occured. +Also if only the timeStamp changes value then that should not cause a monitor. +

    +

    The example monitor plugin implements the semantics the +client wants. It can be attached to any field via the following options: +

    +[plugin=onChange,raiseMonitor=value]
    +
    +This plugin will trigger a monitor for the field only if the field changes +value. In addition value equals false means do not raise a monotor +for changes to this field. +But if a change to another field does cause a monitor the change to this field +will be passed to the client. +

    +

    +Assume that the client has already connected to the channel. +The client can then issue the commands:

    +
    +String request("field(alarm[plugin=onChange]");
    +request += ",timeStamp[plugin=onChange,raiseMonitor=false]";
    +request += ",power.value[plugin=onChange";
    +request += ",voltage.value[plugin=onChange";
    +request += ",current.value[plugin=onChange";
    +
    +PVStructurePtr pvRequest = createRequest->createRequest(request);
    +
    +MonitorPtr monitor = channel->createMonitor(monitorRequester,pvRequest);
    +
    +

    Example Plugin Code

    +

    The header file to create the example has the definition:

    +
    +class ExampleMonitorPlugin{
    +public:
    +    static void create();
    +};
    +
    +

    The implementation is:

    +
    +class OnChangePlugin : public MonitorPlugin
    +{
    +public:
    +    virtual ~OnChangePlugin(){}
    +    OnChangePlugin() {}
    +    bool init(
    +        FieldConstPtr const &field,
    +        StructureConstPtr const &top,
    +        PVStructurePtr const &pvFieldOptions)
    +   {
    +        pvField = getPVDataCreate()->createPVField(field);
    +        raiseMonitor = true;
    +        if(pvFieldOptions!=NULL) {
    +            PVStringPtr pvString =
    +                pvFieldOptions->getSubField<PVString>("raiseMonitor");
    +                if(pvString!=NULL) {
    +                    String value = pvString->get();
    +                    if(value.compare("false")==0) raiseMonitor = false;
    +                }
    +        }
    +        return true;
    +   }
    +   virtual String &getName(){return pluginName;}
    +   virtual bool causeMonitor(
    +        PVFieldPtr const &pvNew,
    +        PVStructurePtr const &pvTop,
    +        MonitorElementPtr const &monitorElement)
    +   {
    +       bool isSame = convert->equals(pvNew,pvField);
    +       if(isSame) return false;
    +       convert->copy(pvNew,pvField);
    +       return raiseMonitor;
    +   }
    +private:
    +   PVFieldPtr pvField;
    +   bool raiseMonitor;
    +};
    +class OnChangePluginCreator : public MonitorPluginCreator
    +{
    +public:
    +    virtual String &getName(){return pluginName;}
    +    virtual MonitorPluginPtr create(
    +        FieldConstPtr const &field,
    +        StructureConstPtr const &top,
    +        PVStructurePtr const &pvFieldOptions)
    +   {
    +       OnChangePluginPtr plugin(new OnChangePlugin());
    +       bool result = plugin->init(field,top,pvFieldOptions);
    +       if(!result) return MonitorPluginPtr();
    +       return plugin;
    +   }
    +
    +};
    +
    +void ExampleMonitorPlugin::create()
    +{
    +    static OnChangePluginCreatorPtr plugin;
    +    static Mutex mutex;
    +    Lock xx(mutex);
    +    if(plugin==NULL) {
    +        plugin = OnChangePluginCreatorPtr(new OnChangePluginCreator());
    +        MonitorPluginManager::get()->addPlugin(pluginName,plugin);
    +    }
    +}
    +
    + + +
    + + diff --git a/src/Makefile b/src/Makefile index 2859d79..d21a7a8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,6 +12,7 @@ include $(PVDATA_SRC)/misc/Makefile include $(PVDATA_SRC)/pv/Makefile include $(PVDATA_SRC)/factory/Makefile include $(PVDATA_SRC)/property/Makefile +include $(PVDATA_SRC)/copy/Makefile include $(PVDATA_SRC)/pvMisc/Makefile include $(PVDATA_SRC)/monitor/Makefile diff --git a/src/copy/createRequest.cpp b/src/copy/createRequest.cpp new file mode 100644 index 0000000..101edb6 --- /dev/null +++ b/src/copy/createRequest.cpp @@ -0,0 +1,532 @@ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * pvAccessCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ + +#include +#include + +#include +#include + +#define epicsExportSharedSymbols +#include + +using namespace epics::pvData; +using std::tr1::static_pointer_cast; +using std::cout; +using std::endl; + +namespace epics { namespace pvData { + +static PVDataCreatePtr pvDataCreate = getPVDataCreate(); +static FieldCreatePtr fieldCreate = getFieldCreate(); + +class CreateRequestImpl : public CreateRequest { +private: + + void removeBlanks(String& str) + { + while(true) { + String::size_type pos = str.find_first_of(' '); + if(pos==String::npos) return; + str.erase(pos,1); + } + } + + size_t findMatchingBrace(String& request, size_t index, int numOpen) { + size_t openBrace = request.find('{', index+1); + size_t closeBrace = request.find('}', index+1); + if(openBrace == String::npos && closeBrace == std::string::npos){ + message = request + " missing }"; + return std::string::npos; + } + if (openBrace != String::npos && openBrace!=0) { + if(openBrace=request.size()) return request.size(); + ind = closeBrace; + continue; + } + if(ind>=maxind) break; + ++ind; + } + return request.size(); + } + + std::vector split(String const & commaSeparatedList) { + String::size_type numValues = 1; + String::size_type index=0; + while(true) { + String::size_type pos = commaSeparatedList.find(',',index); + if(pos==String::npos) break; + numValues++; + index = pos +1; + } + std::vector valueList(numValues,""); + index=0; + for(size_t i=0; i items = split(request); + size_t nitems = items.size(); + StringArray fieldNames(nitems); + FieldConstPtrArray fields(nitems); + for(size_t j=0; jcreateScalar(pvString); + } + return fieldCreate->createStructure(fieldNames,fields); + } + + void initRequestOptions( + PVStructurePtr const & pvParent, + String request) + { + if(request.length()<=1) return; + std::vector items = split(request); + size_t nitems = items.size(); + for(size_t j=0; jgetSubField(name); + pvValue->put(value); + } + } + + StructureConstPtr createSubFieldRequest( + StructureConstPtr parent, + String request) + { + if(request.length()<=0) return parent; + size_t period = request.find('.'); + size_t openBracket = request.find('['); + size_t openBrace = request.find('{'); + + // name only + if(period==String::npos + && openBracket==String::npos + && openBrace==String::npos) + { + StructureConstPtr subField = fieldCreate->createStructure(); + parent = fieldCreate->appendField(parent,request,subField); + return parent; + } + + // period is first + if(period!=String::npos + && (openBracket==String::npos || periodcreateStructure(); + subField = createSubFieldRequest(subField,request.substr(period+1)); + if(subField==NULL) return subField; + parent = fieldCreate->appendField(parent,fieldName,subField); + return parent; + } + + // brace before [ or . + if(openBrace!=String::npos + && (openBracket==String::npos || openBrace= request.size()) nextChar = String::npos; + if(nextChar!=String::npos) { + message = request + " syntax error " + request[nextChar] + " after } illegal"; + return StructureConstPtr(); + } + StructureConstPtr subField = fieldCreate->createStructure(); + String subRequest = request.substr(openBrace+1,closeBrace-openBrace-1); + subField = createFieldRequest(subField,subRequest); + if(subField==NULL) return subField; + parent = fieldCreate->appendField(parent,fieldName,subField); + return parent; + } + + // [ is before brace or . + if(openBracket!=String::npos + && (openBrace==String::npos || openBracket= request.size()) nextChar = String::npos; + if(nextChar==String::npos) { + StringArray fieldNames(1); + FieldConstPtrArray fields(1); + fieldNames[0] = "_options"; + fields[0] = createRequestOptions( + request.substr(openBracket+1,closeBracket-openBracket-1)); + StructureConstPtr subField = fieldCreate->createStructure(fieldNames,fields); + parent = fieldCreate->appendField(parent,fieldName,subField); + return parent; + } + if(request[nextChar]=='.') { + StructureConstPtr subField = fieldCreate->createStructure(); + subField = createSubFieldRequest(subField,request.substr(nextChar+1)); + if(subField==NULL) return StructureConstPtr(); + if(subField->getNumberFields()!=1) { + message = request + " logic error createSubFieldRequest openBracket subField"; + return StructureConstPtr(); + } + StringArray fieldNames(2); + FieldConstPtrArray fields(2); + fieldNames[0] = "_options"; + fields[0] = createRequestOptions( + request.substr(openBracket+1,closeBracket-openBracket-1)); + fieldNames[1] = subField->getFieldNames()[0]; + fields[1] = subField; + subField = fieldCreate->createStructure(fieldNames,fields); + parent = fieldCreate->appendField(parent,fieldName,subField); + return parent; + } + if(request[nextChar]=='{') { + size_t closeBrace = findMatchingBrace(request,openBrace,1); + if(closeBrace==String::npos) return StructureConstPtr(); + StructureConstPtr subField = fieldCreate->createStructure(); + String subRequest = request.substr(openBrace+1,closeBrace-openBrace-1); + subField = createFieldRequest(subField,subRequest); + if(subField==NULL) return subField; + size_t numSub = subField->getNumberFields(); + StringArray fieldNames(numSub + 1); + FieldConstPtrArray fields(numSub+1); + fieldNames[0] = "_options"; + fields[0] = createRequestOptions( + request.substr(openBracket+1,closeBracket-openBracket-1)); + StringArray subNames = subField->getFieldNames(); + FieldConstPtrArray subFields = subField->getFields(); + for(size_t i=0; iappendFields(parent,fieldNames,fields); + parent = fieldCreate->appendField(parent,fieldName,subField); + return parent; + } + } + message = request + " logic error createSubFieldRequest"; + return StructureConstPtr(); + } + + + StructureConstPtr createFieldRequest( + StructureConstPtr parent, + String request) + { + size_t length = request.length(); + if(length<=0) return parent; + size_t end = findEndField(request); + if(end==String::npos) return StructureConstPtr(); + StringArray fieldNames; + FieldConstPtrArray fields; + StructureConstPtr subField = fieldCreate->createStructure(); + subField = createSubFieldRequest(subField,request.substr(0,end)); + if(subField==NULL) return subField; + fieldNames.push_back(subField->getFieldNames()[0]); + fields.push_back(subField->getFields()[0]); + if(end!=length) { + if(request[end]!=',') { + message = request; + message += " expected char "; + message += length; + message += " to be ,"; + return StructureConstPtr(); + } + StructureConstPtr nextSubField = fieldCreate->createStructure(); + nextSubField = createFieldRequest(nextSubField,request.substr(end+1)); + if(nextSubField==NULL) return nextSubField; + size_t numFields = nextSubField->getNumberFields(); + StringArray subNames = nextSubField->getFieldNames(); + FieldConstPtrArray subFields = nextSubField->getFields(); + for(size_t i=0; iappendFields(parent,fieldNames,fields); + return parent; + } + + void initSubFieldOptions( + PVStructurePtr const & pvParent, + String request) + { + if(request.length()<=0) return; + size_t period = request.find('.'); + size_t openBracket = request.find('['); + size_t openBrace = request.find('{'); + // name only + if(period==String::npos + && openBracket==String::npos + && openBrace==String::npos) + { + return; + } + + // period is first + if(period!=String::npos + && (openBracket==String::npos || period(pvParent->getPVFields()[0]); + initSubFieldOptions(pvSubField,request.substr(period+1)); + return; + } + + // brace before [ or . + if(openBrace!=String::npos + && (openBracket==String::npos || openBrace(pvParent->getPVFields()[0]); + size_t closeBrace = findMatchingBrace(request,openBrace,1); + String subRequest = request.substr(openBrace+1,closeBrace-openBrace-1); + initFieldOptions(pvSubField,subRequest); + return; + } + PVStructurePtr pvOptions = pvParent->getSubField("_options"); + if(pvOptions==NULL) throw std::logic_error("initSubFieldOptions pvOptions NULL"); + size_t closeBracket = findMatchingBracket(request,openBracket); + initRequestOptions(pvOptions,request.substr(openBracket+1,closeBracket-openBracket-1)); + size_t nextChar = closeBracket+1; + if(nextChar>= request.size()) nextChar = String::npos; + if(nextChar==String::npos) return; + if(request[nextChar]=='.') { + PVStructurePtr pvSubField = static_pointer_cast(pvParent->getPVFields()[1]); + initSubFieldOptions(pvSubField,request.substr(nextChar+1)); + return; + } + if(request[nextChar]!='{') throw std::logic_error("initSubFieldOptions request[nextChar]!='{'"); + size_t closeBrace = findMatchingBrace(request,openBrace,1); + const PVFieldPtrArray &pvFields = pvParent->getPVFields(); + String subRequest = request.substr(openBrace+1,closeBrace-openBrace-1); + for(size_t i=1; i(pvFields[i]); + size_t comma = subRequest.find(','); + initSubFieldOptions(pvSubField, subRequest.substr(0,comma-1)); + subRequest = subRequest.substr(comma+1); + } + } + + void initFieldOptions( + PVStructurePtr const & pvParent, + String request) + { + if(request.find('[')==String::npos) return; + size_t num = pvParent->getStructure()->getNumberFields(); + if(num==0) return; + if(num==1) { + initSubFieldOptions(pvParent,request); + return; + } + size_t end = findEndField(request); + size_t start = 0; + for(size_t i=0; i(pvParent->getPVFields()[i]); + String subRequest = request.substr(start, end - start); + initSubFieldOptions(pvSub,subRequest); + if(i==num-1) break; + start = end +1; + String xxx = request.substr(start); + end += findEndField(xxx) + 1; + } + } + + +public: + + virtual PVStructure::shared_pointer createRequest( + String const & crequest) + { + String request = crequest; + StructureConstPtr topStructure = fieldCreate->createStructure(); + + if (!request.empty()) removeBlanks(request); + if (request.empty()) + { + PVFieldPtrArray pvFields; + StringArray fieldNames; + return pvDataCreate->createPVStructure(fieldNames,pvFields); + } + size_t offsetRecord = request.find("record["); + size_t offsetField = request.find("field("); + size_t offsetPutField = request.find("putField("); + size_t offsetGetField = request.find("getField("); + if(offsetRecord==String::npos + && offsetField==String::npos + && offsetPutField==String::npos + && offsetGetField==String::npos) + { + request = "field(" + crequest + ")"; + offsetField = request.find("field("); + } + if (offsetRecord != String::npos) { + size_t openBracket = request.find('[', offsetRecord); + size_t closeBracket = request.find(']', openBracket); + if(closeBracket == String::npos) { + message = request.substr(offsetRecord) + + " record[ does not have matching ]"; + return PVStructurePtr(); + } + StructureConstPtr structure = createRequestOptions( + request.substr(openBracket+1,closeBracket-openBracket-1)); + if(structure==NULL) + { + return PVStructurePtr(); + } + topStructure = fieldCreate->appendField(topStructure,"record",structure); + } + if (offsetField != String::npos) { + size_t openBrace = request.find('(', offsetField); + size_t closeBrace = request.find(')', openBrace); + if(closeBrace == String::npos) { + message = request.substr(offsetField) + + " field( does not have matching )"; + return PVStructurePtr(); + } + StructureConstPtr structure = fieldCreate->createStructure(); + structure = createFieldRequest(structure,request.substr(openBrace+1,closeBrace-openBrace-1)); + if(structure==NULL) + { + return PVStructurePtr(); + } + topStructure = fieldCreate->appendField(topStructure,"field",structure); + } + if (offsetPutField != String::npos) { + size_t openBrace = request.find('(', offsetPutField); + size_t closeBrace = request.find(')', openBrace); + if(closeBrace == String::npos) { + message = request.substr(offsetField) + + " putField( does not have matching )"; + return PVStructurePtr(); + } + StructureConstPtr structure = fieldCreate->createStructure(); + structure = createFieldRequest(structure,request.substr(openBrace+1,closeBrace-openBrace-1)); + if(structure==NULL) + { + return PVStructurePtr(); + } + topStructure = fieldCreate->appendField(topStructure,"putField",structure); + } + if (offsetGetField != String::npos) { + size_t openBrace = request.find('(', offsetGetField); + size_t closeBrace = request.find(')', openBrace); + if(closeBrace == String::npos) { + message = request.substr(offsetField) + + " getField( does not have matching )"; + return PVStructurePtr(); + } + StructureConstPtr structure = fieldCreate->createStructure(); + structure = createFieldRequest(structure,request.substr(openBrace+1,closeBrace-openBrace-1)); + if(structure==NULL) + { + return PVStructurePtr(); + } + topStructure = fieldCreate->appendField(topStructure,"getField",structure); + } + PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure); + if (offsetRecord != String::npos) { + size_t openBracket = request.find('[', offsetRecord); + size_t closeBracket = request.find(']', openBracket); + initRequestOptions( + pvStructure->getSubField("record"), + request.substr(openBracket+1,closeBracket-openBracket-1)); + } + if (offsetField != String::npos) { + size_t openParam = request.find('(', offsetField); + size_t closeParam = request.find(')', openParam); + PVStructurePtr pvSub = pvStructure->getSubField("field"); + if(pvSub->getStructure()->getNumberFields()==1) { + pvSub = static_pointer_cast(pvSub->getPVFields()[0]); + } + if(pvSub!=NULL) initFieldOptions(pvSub,request.substr(openParam+1,closeParam-openParam-1)); + } + if (offsetPutField != String::npos) { + size_t openParam = request.find('(', offsetPutField); + size_t closeParam = request.find(')', openParam); + PVStructurePtr pvSub = pvStructure->getSubField("putField"); + if(pvSub->getStructure()->getNumberFields()==1) { + pvSub = static_pointer_cast(pvSub->getPVFields()[0]); + } + if(pvSub!=NULL) initFieldOptions(pvSub,request.substr(openParam+1,closeParam-openParam-1)); + } + if (offsetGetField != String::npos) { + size_t openParam = request.find('(', offsetGetField); + size_t closeParam = request.find(')', openParam); + PVStructurePtr pvSub = pvStructure->getSubField("getField"); + if(pvSub->getStructure()->getNumberFields()==1) { + pvSub = static_pointer_cast(pvSub->getPVFields()[0]); + } + if(pvSub!=NULL) initFieldOptions(pvSub,request.substr(openParam+1,closeParam-openParam-1)); + } + return pvStructure; + } + +}; + +CreateRequest::shared_pointer CreateRequest::create() +{ + CreateRequest::shared_pointer createRequest(new CreateRequestImpl()); + return createRequest; +} + +}} + diff --git a/src/copy/createRequest.h b/src/copy/createRequest.h new file mode 100644 index 0000000..6d4e429 --- /dev/null +++ b/src/copy/createRequest.h @@ -0,0 +1,67 @@ +/*createRequest.h*/ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * pvDataCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ + +#ifndef CREATEREQUEST_H +#define CREATEREQUEST_H +#include +#include + +#ifdef epicsExportSharedSymbols +# define pvDataEpicsExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + + +#include +#include + +#ifdef pvDataEpicsExportSharedSymbols +# define epicsExportSharedSymbols +# undef pvDataEpicsExportSharedSymbols +#endif + + + +namespace epics { namespace pvData { + +/** + * Class to create pvRequest structures to pass to pvAccess Channel methods. + */ +class epicsShareClass CreateRequest { + public: + POINTER_DEFINITIONS(CreateRequest); + /** + * Create s new instance of CreateRequest + * @returns A shared pointer to the new instance. + */ + static CreateRequest::shared_pointer create(); + virtual ~CreateRequest() {}; + /** + * Create a request structure for the create calls in Channel. + * See the package overview documentation for details. + * @param request The field request. See the package overview documentation for details. + * @param requester The requester; + * @return The request PVStructure if a valid request was given. + * If a NULL PVStructure is returned then getMessage will return + * the reason. + */ + virtual PVStructure::shared_pointer createRequest(String const & request) = 0; + /** + * Get the error message of createRequest returns NULL + * return the error message + */ + String getMessage() {return message;} +protected: + CreateRequest() {} + String message; +}; + + +}} + +#endif /* CREATEREQUEST_H */ + diff --git a/src/copy/pvCopy.cpp b/src/copy/pvCopy.cpp new file mode 100644 index 0000000..1c74b44 --- /dev/null +++ b/src/copy/pvCopy.cpp @@ -0,0 +1,644 @@ +/* pvCopy.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author Marty Kraimer + * @date 2013.04 + */ +#include +#include +#include +#include + +#include + +#include +#include + + +namespace epics { namespace pvData { + +using namespace epics::pvData; +using std::tr1::static_pointer_cast; +using std::tr1::dynamic_pointer_cast; +using std::size_t; +using std::cout; +using std::endl; + +static PVCopyPtr NULLPVCopy; +static FieldConstPtr NULLField; +static StructureConstPtr NULLStructure; +static PVStructurePtr NULLPVStructure; +static CopyNodePtr NULLCopyNode; +static CopyMasterNodePtr NULLCopyMasterNode; + +struct CopyNode { + CopyNode() + : isStructure(false), + structureOffset(0), + nfields(0) + {} + bool isStructure; + size_t structureOffset; // In the copy + size_t nfields; + PVStructurePtr options; +}; + +struct CopyMasterNode : public CopyNode{ + PVFieldPtr masterPVField; +}; + +typedef std::vector CopyNodePtrArray; +typedef std::tr1::shared_ptr CopyNodePtrArrayPtr; + +struct CopyStructureNode : public CopyNode { + CopyNodePtrArrayPtr nodes; +}; + +PVCopyPtr PVCopy::create( + PVStructurePtr const &pvMaster, + PVStructurePtr const &pvRequest, + String const & structureName) +{ + PVStructurePtr pvStructure(pvRequest); + if(structureName.size()>0) { + if(pvRequest->getStructure()->getNumberFields()>0) { + pvStructure = pvRequest->getStructureField(structureName); + if(pvStructure.get()==NULL) return NULLPVCopy; + } + } else if(pvStructure->getSubField("field")!=NULL) { + pvStructure = pvRequest->getStructureField("field"); + } + PVCopyPtr pvCopy = PVCopyPtr(new PVCopy(pvMaster)); + bool result = pvCopy->init(pvStructure); + if(!result) pvCopy.reset(); + return pvCopy; +} + +PVCopy::PVCopy( + PVStructurePtr const &pvMaster) +: pvMaster(pvMaster) +{ +} + +void PVCopy::destroy() +{ + headNode.reset(); +} + +PVStructurePtr PVCopy::getPVMaster() +{ + return pvMaster; +} + +void PVCopy::traverseMaster(CopyNodePtr const &innode, PVCopyTraverseMasterCallbackPtr const & callback) +{ + CopyNodePtr node = innode; + if(!node->isStructure) { + CopyMasterNodePtr masterNode = static_pointer_cast(node); + callback->nextMasterPVField(masterNode->masterPVField); + return; + } + CopyStructureNodePtr structNode = static_pointer_cast(node); + CopyNodePtrArrayPtr nodes = structNode->nodes; + for(size_t i=0; i< nodes->size(); i++) { + node = (*nodes)[i]; + traverseMaster(node,callback); + } +} + +StructureConstPtr PVCopy::getStructure() +{ + return structure; +} + +PVStructurePtr PVCopy::createPVStructure() +{ + if(cacheInitStructure.get()!=NULL) { + PVStructurePtr save = cacheInitStructure; + cacheInitStructure.reset(); + return save; + } + PVStructurePtr pvStructure = + getPVDataCreate()->createPVStructure(structure); + return pvStructure; +} + +PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset) +{ + if(fieldOffset==0) return headNode->options; + CopyNodePtr node = headNode; + while(true) { + if(!node->isStructure) { + if(node->structureOffset==fieldOffset) return node->options; + return NULLPVStructure; + } + CopyStructureNodePtr structNode = static_pointer_cast(node); + CopyNodePtrArrayPtr nodes = structNode->nodes; + boolean okToContinue = false; + for(size_t i=0; i< nodes->size(); i++) { + node = (*nodes)[i]; + size_t soff = node->structureOffset; + if(fieldOffset>=soff && fieldOffsetnfields) { + if(fieldOffset==soff) return node->options; + if(!node->isStructure) { + return NULLPVStructure; + } + okToContinue = true; + break; + } + } + if(okToContinue) continue; + throw std::invalid_argument("fieldOffset not valid"); + } +} + +size_t PVCopy::getCopyOffset(PVFieldPtr const &masterPVField) +{ + if(masterPVField->getFieldOffset()==0) return 0; + if(!headNode->isStructure) { + CopyMasterNodePtr masterNode = static_pointer_cast(headNode); + if((masterNode->masterPVField.get())==masterPVField.get()) { + return headNode->structureOffset; + } + PVStructure * parent = masterPVField->getParent(); + size_t offsetParent = parent->getFieldOffset(); + size_t off = masterPVField->getFieldOffset(); + size_t offdiff = off -offsetParent; + if(offdiffnfields) return headNode->structureOffset + offdiff; + return String::npos; + } + CopyStructureNodePtr node = static_pointer_cast(headNode); + CopyMasterNodePtr masterNode = getCopyOffset(node,masterPVField); + if(masterNode.get()!=NULL) return masterNode->structureOffset; + return String::npos; +} + +size_t PVCopy::getCopyOffset( + PVStructurePtr const &masterPVStructure, + PVFieldPtr const &masterPVField) +{ + CopyMasterNodePtr masterNode; + if(!headNode->isStructure) { + masterNode = static_pointer_cast(headNode); + if(masterNode->masterPVField.get()!=masterPVStructure.get()) return String::npos; + } else { + CopyStructureNodePtr node = static_pointer_cast(headNode); + masterNode = getCopyOffset(node,masterPVField); + } + if(masterNode.get()==NULL) return String::npos; + size_t diff = masterPVField->getFieldOffset() + - masterPVStructure->getFieldOffset(); + return masterNode->structureOffset + diff; +} + +PVFieldPtr PVCopy::getMasterPVField(size_t structureOffset) +{ + CopyMasterNodePtr masterNode; + if(!headNode->isStructure) { + masterNode = static_pointer_cast(headNode); + } else { + CopyStructureNodePtr node = static_pointer_cast(headNode); + masterNode = getMasterNode(node,structureOffset); + } + if(masterNode.get()==NULL) { + throw std::invalid_argument( + "PVCopy::getMasterPVField: setstructureOffset not valid"); + } + size_t diff = structureOffset - masterNode->structureOffset; + PVFieldPtr pvMasterField = masterNode->masterPVField; + if(diff==0) return pvMasterField; + PVStructurePtr pvStructure + = static_pointer_cast(pvMasterField); + return pvStructure->getSubField( + pvMasterField->getFieldOffset() + diff); +} + +void PVCopy::initCopy( + PVStructurePtr const ©PVStructure, + BitSetPtr const &bitSet) +{ + bitSet->clear(); + bitSet->set(0); + updateCopyFromBitSet(copyPVStructure,bitSet); +} + +void PVCopy::updateCopySetBitSet( + PVStructurePtr const ©PVStructure, + BitSetPtr const &bitSet) +{ + if(headNode->isStructure) { + CopyStructureNodePtr node = static_pointer_cast(headNode); + updateStructureNodeSetBitSet(copyPVStructure,node,bitSet); + } else { + CopyMasterNodePtr masterNode = static_pointer_cast(headNode); + PVFieldPtr pvMasterField= masterNode->masterPVField; + PVFieldPtr copyPVField = copyPVStructure; + PVFieldPtr pvField = pvMasterField; + if(pvField->getField()->getType()==epics::pvData::structure) { + updateSubFieldSetBitSet(copyPVField,pvMasterField,bitSet); + return; + } + ConvertPtr convert = getConvert(); + bool isEqual = convert->equals(copyPVField,pvField); + if(!isEqual) { + convert->copy(pvField, copyPVField); + bitSet->set(copyPVField->getFieldOffset()); + } + } +} + +void PVCopy::updateCopyFromBitSet( + PVStructurePtr const ©PVStructure, + BitSetPtr const &bitSet) +{ + bool doAll = bitSet->get(0); + if(headNode->isStructure) { + CopyStructureNodePtr node = static_pointer_cast(headNode); + updateStructureNodeFromBitSet(copyPVStructure,node,bitSet,true,doAll); + } else { + CopyMasterNodePtr masterNode = static_pointer_cast(headNode); + updateSubFieldFromBitSet(copyPVStructure, masterNode->masterPVField,bitSet, true,doAll); + } +} + +void PVCopy::updateMaster( + PVStructurePtr const ©PVStructure, + BitSetPtr const &bitSet) +{ + bool doAll = bitSet->get(0); + if(headNode->isStructure) { + CopyStructureNodePtr node = + static_pointer_cast(headNode); + updateStructureNodeFromBitSet( + copyPVStructure,node,bitSet,false,doAll); + } else { + CopyMasterNodePtr masterNode = + static_pointer_cast(headNode); + updateSubFieldFromBitSet( copyPVStructure,masterNode->masterPVField,bitSet,false,doAll); + } +} + +epics::pvData::String PVCopy::dump() +{ + String builder; + dump(&builder,headNode,0); + return builder; +} + +void PVCopy::dump(String *builder,CopyNodePtr const &node,int indentLevel) +{ + getConvert()->newLine(builder,indentLevel); + std::stringstream ss; + ss << (node->isStructure ? "structureNode" : "masterNode"); + ss << " structureOffset " << node->structureOffset; + ss << " nfields " << node->nfields; + *builder += ss.str(); + PVStructurePtr options = node->options; + if(options.get()!=NULL) { + getConvert()->newLine(builder,indentLevel +1); + options->toString(builder); + getConvert()->newLine(builder,indentLevel); + } + if(!node->isStructure) { + CopyMasterNodePtr masterNode = static_pointer_cast(node); + String name = masterNode->masterPVField->getFullName(); + *builder += " masterField " + name; + return; + } + CopyStructureNodePtr structureNode = + static_pointer_cast(node); + CopyNodePtrArrayPtr nodes = structureNode->nodes; + for(size_t i=0; isize(); ++i) { + if((*nodes)[i].get()==NULL) { + getConvert()->newLine(builder,indentLevel +1); + ss.str(""); + ss << "node[" << i << "] is null"; + *builder += ss.str(); + continue; + } + dump(builder,(*nodes)[i],indentLevel+1); + } +} + +bool PVCopy::init(epics::pvData::PVStructurePtr const &pvRequest) +{ + PVStructurePtr pvMasterStructure = pvMaster; + size_t len = pvRequest->getPVFields().size(); + bool entireMaster = false; + if(len==String::npos) entireMaster = true; + if(len==0) entireMaster = true; + PVStructurePtr pvOptions; + if(len==1 && pvRequest->getSubField("_options")!=NULL) { + pvOptions = pvRequest->getStructureField("_options"); + } + if(entireMaster) { + structure = pvMasterStructure->getStructure(); + CopyMasterNodePtr masterNode(new CopyMasterNode()); + headNode = masterNode; + masterNode->options = pvOptions; + masterNode->isStructure = false; + masterNode->structureOffset = 0; + masterNode->masterPVField = pvMasterStructure; + masterNode->nfields = pvMasterStructure->getNumberFields(); + return true; + } + structure = createStructure(pvMasterStructure,pvRequest); + if(structure==NULL) return false; + cacheInitStructure = createPVStructure(); + headNode = createStructureNodes( + pvMaster, + pvRequest, + cacheInitStructure); + return true; +} + +epics::pvData::String PVCopy::dump( + String const &value, + CopyNodePtr const &node, + int indentLevel) +{ + throw std::logic_error(String("Not Implemented")); +} + + +StructureConstPtr PVCopy::createStructure( + PVStructurePtr const &pvMaster, + PVStructurePtr const &pvFromRequest) +{ + if(pvFromRequest->getStructure()->getNumberFields()==0) { + return pvMaster->getStructure(); + } + PVFieldPtrArray const &pvFromRequestFields = pvFromRequest->getPVFields(); + StringArray const &fromRequestFieldNames = pvFromRequest->getStructure()->getFieldNames(); + size_t length = pvFromRequestFields.size(); + if(length==0) return NULLStructure; + FieldConstPtrArray fields; fields.reserve(length); + StringArray fieldNames; fields.reserve(length); + for(size_t i=0; igetSubField(fieldName); + if(pvMasterField==NULL) continue; + FieldConstPtr field = pvMasterField->getField(); + if(field->getType()==epics::pvData::structure) { + PVStructurePtr pvRequestStructure = static_pointer_cast( + pvFromRequestFields[i]); + if(pvRequestStructure->getNumberFields()>0) { + StringArray const &names = pvRequestStructure->getStructure()-> + getFieldNames(); + size_t num = names.size(); + if(num>0 && names[0].compare("_options")==0) --num; + if(num>0) { + if(pvMasterField->getField()->getType()!=epics::pvData::structure) continue; + fieldNames.push_back(fieldName); + fields.push_back(createStructure( + static_pointer_cast(pvMasterField), + pvRequestStructure)); + continue; + } + } + } + fieldNames.push_back(fieldName); + fields.push_back(field); + } + size_t numsubfields = fields.size(); + if(numsubfields==0) return NULLStructure; + return getFieldCreate()->createStructure(fieldNames, fields); +} + +CopyNodePtr PVCopy::createStructureNodes( + PVStructurePtr const &pvMasterStructure, + PVStructurePtr const &pvFromRequest, + PVStructurePtr const &pvFromCopy) +{ + PVFieldPtrArray const & copyPVFields = pvFromCopy->getPVFields(); + PVStructurePtr pvOptions; + PVFieldPtr pvField = pvFromRequest->getSubField("_options"); + if(pvField!=NULL) pvOptions = static_pointer_cast(pvField); + size_t number = copyPVFields.size(); + CopyNodePtrArrayPtr nodes(new CopyNodePtrArray()); + nodes->reserve(number); + for(size_t i=0; igetFieldName(); + + PVStructurePtr requestPVStructure = static_pointer_cast( + pvFromRequest->getSubField(fieldName)); + PVStructurePtr pvSubFieldOptions; + PVFieldPtr pvField = requestPVStructure->getSubField("_options"); + if(pvField!=NULL) pvSubFieldOptions = static_pointer_cast(pvField); + PVFieldPtr pvMasterField; + PVFieldPtrArray const & pvMasterFields = pvMasterStructure->getPVFields(); + for(size_t j=0; igetFieldName().compare(fieldName)==0) { + pvMasterField = pvMasterFields[j]; + break; + } + } + size_t numberRequest = requestPVStructure->getPVFields().size(); + if(pvSubFieldOptions!=NULL) numberRequest--; + if(numberRequest>0) { + nodes->push_back(createStructureNodes( + static_pointer_cast(pvMasterField), + requestPVStructure, + static_pointer_cast(copyPVField))); + continue; + } + CopyMasterNodePtr masterNode(new CopyMasterNode()); + masterNode->options = pvSubFieldOptions; + masterNode->isStructure = false; + masterNode->masterPVField = pvMasterField; + masterNode->nfields = copyPVField->getNumberFields(); + masterNode->structureOffset = copyPVField->getFieldOffset(); + nodes->push_back(masterNode); + } + CopyStructureNodePtr structureNode(new CopyStructureNode()); + structureNode->isStructure = true; + structureNode->nodes = nodes; + structureNode->structureOffset = pvFromCopy->getFieldOffset(); + structureNode->nfields = pvFromCopy->getNumberFields(); + structureNode->options = pvOptions; + return structureNode; +} + +void PVCopy::updateStructureNodeSetBitSet( + PVStructurePtr const &pvCopy, + CopyStructureNodePtr const &structureNode, + epics::pvData::BitSetPtr const &bitSet) +{ + for(size_t i=0; inodes->size(); i++) { + CopyNodePtr node = (*structureNode->nodes)[i]; + PVFieldPtr pvField = pvCopy->getSubField(node->structureOffset); + if(node->isStructure) { + PVStructurePtr xxx = static_pointer_cast(pvField); + CopyStructureNodePtr yyy = + static_pointer_cast(node); + updateStructureNodeSetBitSet(xxx,yyy,bitSet); + } else { + CopyMasterNodePtr masterNode = + static_pointer_cast(node); + updateSubFieldSetBitSet(pvField,masterNode->masterPVField,bitSet); + } + } +} + +void PVCopy::updateSubFieldSetBitSet( + PVFieldPtr const &pvCopy, + PVFieldPtr const &pvMaster, + BitSetPtr const &bitSet) +{ + FieldConstPtr field = pvCopy->getField(); + Type type = field->getType(); + if(type!=epics::pvData::structure) { + ConvertPtr convert = getConvert(); + bool isEqual = convert->equals(pvCopy,pvMaster); + if(isEqual) { + if(type==structureArray) { + // always act as though a change occurred. + // Note that array elements are shared. + bitSet->set(pvCopy->getFieldOffset()); + } + } + if(isEqual) return; + convert->copy(pvMaster, pvCopy); + bitSet->set(pvCopy->getFieldOffset()); + return; + } + PVStructurePtr pvCopyStructure = static_pointer_cast(pvCopy); + PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields(); + PVStructurePtr pvMasterStructure = + static_pointer_cast(pvMaster); + PVFieldPtrArray const & pvMasterFields = + pvMasterStructure->getPVFields(); + size_t length = pvCopyFields.size(); + for(size_t i=0; istructureOffset; + if(!doAll) { + size_t nextSet = bitSet->nextSetBit(offset); + if(nextSet==String::npos) return; + } + if(offset>=pvCopy->getNextFieldOffset()) return; + if(!doAll) doAll = bitSet->get(offset); + CopyNodePtrArrayPtr nodes = structureNode->nodes; + for(size_t i=0; isize(); i++) { + CopyNodePtr node = (*nodes)[i]; + PVFieldPtr pvField = pvCopy->getSubField(node->structureOffset); + if(node->isStructure) { + PVStructurePtr xxx = static_pointer_cast(pvField); + CopyStructureNodePtr subStructureNode = + static_pointer_cast(node); + updateStructureNodeFromBitSet( + xxx,subStructureNode,bitSet,toCopy,doAll); + } else { + CopyMasterNodePtr masterNode = + static_pointer_cast(node); + updateSubFieldFromBitSet( + pvField,masterNode->masterPVField,bitSet,toCopy,doAll); + } + } +} + +void PVCopy::updateSubFieldFromBitSet( + PVFieldPtr const &pvCopy, + PVFieldPtr const &pvMasterField, + BitSetPtr const &bitSet, + bool toCopy, + bool doAll) +{ + if(!doAll) { + doAll = bitSet->get(pvCopy->getFieldOffset()); + } + if(!doAll) { + size_t offset = pvCopy->getFieldOffset(); + size_t nextSet = bitSet->nextSetBit(offset); + if(nextSet==String::npos) return; + if(nextSet>=pvCopy->getNextFieldOffset()) return; + } + ConvertPtr convert = getConvert(); + if(pvCopy->getField()->getType()==epics::pvData::structure) { + PVStructurePtr pvCopyStructure = + static_pointer_cast(pvCopy); + PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields(); + if(pvMasterField->getField()->getType() !=epics::pvData::structure) + { + throw std::logic_error(String("Logic error")); + } + PVStructurePtr pvMasterStructure = + static_pointer_cast(pvMasterField); + PVFieldPtrArray const & pvMasterFields = + pvMasterStructure->getPVFields(); + for(size_t i=0; icopy(pvMasterField, pvCopy); + } else { + convert->copy(pvCopy, pvMasterField); + } + } +} + +CopyMasterNodePtr PVCopy::getCopyOffset( + CopyStructureNodePtr const &structureNode, + PVFieldPtr const &masterPVField) +{ + size_t offset = masterPVField->getFieldOffset(); + CopyNodePtrArrayPtr nodes = structureNode->nodes; + for(size_t i=0; i< nodes->size(); i++) { + CopyNodePtr node = (*nodes)[i]; + if(!node->isStructure) { + CopyMasterNodePtr masterNode = + static_pointer_cast(node); + size_t off = masterNode->masterPVField->getFieldOffset(); + size_t nextOffset = masterNode->masterPVField->getNextFieldOffset(); + if(offset>= off && offset(node); + CopyMasterNodePtr masterNode = + getCopyOffset(subNode,masterPVField); + if(masterNode.get()!=NULL) return masterNode; + } + } + return NULLCopyMasterNode; +} + +CopyMasterNodePtr PVCopy::getMasterNode( + CopyStructureNodePtr const &structureNode, + std::size_t structureOffset) +{ + CopyNodePtrArrayPtr nodes = structureNode->nodes; + for(size_t i=0; i< nodes->size(); i++) { + CopyNodePtr node = (*nodes)[i]; + if(structureOffset>=(node->structureOffset + node->nfields)) continue; + if(!node->isStructure) { + CopyMasterNodePtr masterNode = + static_pointer_cast(node); + return masterNode; + } + CopyStructureNodePtr subNode = + static_pointer_cast(node); + return getMasterNode(subNode,structureOffset); + } + return NULLCopyMasterNode; +} + +}} diff --git a/src/copy/pvCopy.h b/src/copy/pvCopy.h new file mode 100644 index 0000000..14d2d96 --- /dev/null +++ b/src/copy/pvCopy.h @@ -0,0 +1,230 @@ +/* pvCopy.h */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author Marty Kraimer + * @date 2013.04 + */ +#ifndef PVCOPY_H +#define PVCOPY_H +#include +#include +#include + +#include + +#include +#include + +namespace epics { namespace pvData{ + +class PVCopyTraverseMasterCallback; +typedef std::tr1::shared_ptr PVCopyTraverseMasterCallbackPtr; + +/** + * Callback for traversing master structure + * Must be implemented by code that creates pvCopy. + */ +class epicsShareClass PVCopyTraverseMasterCallback +{ +public: + POINTER_DEFINITIONS(PVCopyTraverseMasterCallback); + virtual ~PVCopyTraverseMasterCallback() {} + /** + * Called once for each field in master. + * @param pvField The field in master. + */ + virtual void nextMasterPVField(epics::pvData::PVFieldPtr const &pvField) = 0; +}; + + +class PVCopy; +typedef std::tr1::shared_ptr PVCopyPtr; + +struct CopyNode; +typedef std::tr1::shared_ptr CopyNodePtr; +struct CopyMasterNode; +typedef std::tr1::shared_ptr CopyMasterNodePtr; +struct CopyStructureNode; +typedef std::tr1::shared_ptr CopyStructureNodePtr; + + +/** + * Class that manages one or more PVStructures that holds an arbitrary subset of the fields + * in another PVStructure called master. + */ +class epicsShareClass PVCopy : + public std::tr1::enable_shared_from_this +{ +public: + POINTER_DEFINITIONS(PVCopy); + /** + * Create a new pvCopy + * @param pvMaster The top level sructure for which a copy of + * an arbritary subset of the fields in master will be created and managed. + * @param pvRequest Selects the set of subfields desired and options for each field. + * @param structureName The name for the top level of any PVStructure created. + */ + static PVCopyPtr create( + PVStructurePtr const &pvMaster, + PVStructurePtr const &pvRequest, + String const & structureName); + virtual ~PVCopy(){} + virtual void destroy(); + /** + * Get the top level structure of master + * @returns The master top level structure. + * This should not be modified. + */ + PVStructurePtr getPVMaster(); + /** + * Traverse all the fields in master. + * @param callback This is called for each field on master. + */ + void traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback) + { + traverseMaster(headNode,callback); + } + /** + * Get the introspection interface for a PVStructure for e copy. + */ + StructureConstPtr getStructure(); + /** + * Create a copy instance. Monitors keep a queue of monitor elements. + * Since each element needs a PVStructure, multiple top level structures will be created. + */ + PVStructurePtr createPVStructure(); + /** + * Given a field in pvMaster. return the offset in copy for the same field. + * A value of String::npos means that the copy does not have this field. + * @param masterPVField The field in master. + */ + std::size_t getCopyOffset(PVFieldPtr const &masterPVField); + /** + * Given a field in pvMaster. return the offset in copy for the same field. + * A value of String::npos means that the copy does not have this field. + * @param masterPVStructure A structure in master that has masterPVField. + * @param masterPVField The field in master. + */ + std::size_t getCopyOffset( + PVStructurePtr const &masterPVStructure, + PVFieldPtr const &masterPVField); + /** + * Given a offset in the copy get the corresponding field in pvMaster. + * @param offset The offset in the copy. + */ + PVFieldPtr getMasterPVField(std::size_t structureOffset); + /** + * Initialize the fields in copyPVStructure by giving each field + * the value from the corresponding field in pvMaster. + * bitSet will be set to show that all fields are changed. + * @param copyPVStructure A copy top level structure. + * @param bitSet A bitSet for copyPVStructure. + */ + void initCopy( + PVStructurePtr const ©PVStructure, + BitSetPtr const &bitSet); + /** + * Set all fields in copyPVStructure to the value of the corresponding field in pvMaster. + * Each field that is changed has it's corresponding bit set in bitSet. + * @param copyPVStructure A copy top level structure. + * @param bitSet A bitSet for copyPVStructure. + */ + void updateCopySetBitSet( + PVStructurePtr const ©PVStructure, + BitSetPtr const &bitSet); + /** + * For each set bit in bitSet + * set the field in copyPVStructure to the value of the corrseponding field in pvMaster. + * @param copyPVStructure A copy top level structure. + * @param bitSet A bitSet for copyPVStructure. + */ + void updateCopyFromBitSet( + PVStructurePtr const ©PVStructure, + BitSetPtr const &bitSet); + /** + * For each set bit in bitSet + * set the field in pvMaster to the value of the corrseponding field in copyPVStructure + * @param copyPVStructure A copy top level structure. + * @param bitSet A bitSet for copyPVStructure. + */ + void updateMaster( + PVStructurePtr const ©PVStructure, + BitSetPtr const &bitSet); + /** + * Get the options for the field at the specified offset. + * @param offset the offset in copy. + * @returns A NULL is returned if no options were specified for the field. + * If options were specified,PVStructurePtr is a structures + * with a set of PVString subfields that specify name,value pairs.s + * name is the subField name and value is the subField value. + */ + PVStructurePtr getOptions(std::size_t fieldOffset); + /** + * For debugging. + */ + String dump(); +private: + void dump( + String *builder, + CopyNodePtr const &node, + int indentLevel); + PVCopyPtr getPtrSelf() + { + return shared_from_this(); + } + void traverseMaster(CopyNodePtr const &node, PVCopyTraverseMasterCallbackPtr const & callback); + + PVStructurePtr pvMaster; + StructureConstPtr structure; + CopyNodePtr headNode; + PVStructurePtr cacheInitStructure; + PVCopy(PVStructurePtr const &pvMaster); + friend class PVCopyMonitor; + bool init(PVStructurePtr const &pvRequest); + String dump( + String const &value, + CopyNodePtr const &node, + int indentLevel); + StructureConstPtr createStructure( + PVStructurePtr const &pvMaster, + PVStructurePtr const &pvFromRequest); + CopyNodePtr createStructureNodes( + PVStructurePtr const &pvMasterStructure, + PVStructurePtr const &pvFromRequest, + PVStructurePtr const &pvFromField); + void updateStructureNodeSetBitSet( + PVStructurePtr const &pvCopy, + CopyStructureNodePtr const &structureNode, + BitSetPtr const &bitSet); + void updateSubFieldSetBitSet( + PVFieldPtr const &pvCopy, + PVFieldPtr const &pvMaster, + BitSetPtr const &bitSet); + void updateStructureNodeFromBitSet( + PVStructurePtr const &pvCopy, + CopyStructureNodePtr const &structureNode, + BitSetPtr const &bitSet, + bool toCopy, + bool doAll); + void updateSubFieldFromBitSet( + PVFieldPtr const &pvCopy, + PVFieldPtr const &pvMasterField, + BitSetPtr const &bitSet, + bool toCopy, + bool doAll); + CopyMasterNodePtr getCopyOffset( + CopyStructureNodePtr const &structureNode, + PVFieldPtr const &masterPVField); + CopyMasterNodePtr getMasterNode( + CopyStructureNodePtr const &structureNode, + std::size_t structureOffset); + +}; + +}} + +#endif /* PVCOPY_H */ diff --git a/src/factory/Convert.cpp b/src/factory/Convert.cpp index 4fdc3b4..a17d4eb 100644 --- a/src/factory/Convert.cpp +++ b/src/factory/Convert.cpp @@ -50,9 +50,10 @@ void Convert::getString(StringBuilder buf,PVField const *pvField,int /*indentLev { // TODO indextLevel ignored std::ostringstream strm; - PrinterPlain p; - p.setStream(strm); - p.print(*pvField); + strm << pvField->dumpValue(strm) << std::endl; +// PrinterPlain p; +// p.setStream(strm); +// p.print(*pvField); strm.str().swap(*buf); } @@ -470,7 +471,7 @@ void Convert::copyUnion(PVUnionPtr const & from, PVUnionPtr const & to) if (fromValue.get() == 0) to->select(PVUnion::UNDEFINED_INDEX); else - copy(fromValue, to->select(from->getSelectedIndex())); + to->set(from->getSelectedFieldName(),from->get()); } } diff --git a/src/factory/FieldCreateFactory.cpp b/src/factory/FieldCreateFactory.cpp index c88cc02..1685966 100644 --- a/src/factory/FieldCreateFactory.cpp +++ b/src/factory/FieldCreateFactory.cpp @@ -216,8 +216,15 @@ static UnionConstPtr deserializeUnionField(const FieldCreate* fieldCreate, ByteB return fieldCreate->createUnion(id, fieldNames, fields); } +Array::Array(Type type) + : Field(type) +{ +} + +Array::~Array() {} + ScalarArray::ScalarArray(ScalarType elementType) -: Field(scalarArray),elementType(elementType) +: Array(scalarArray),elementType(elementType) { if(elementType<0 || elementType>MAX_SCALAR_TYPE) throw std::invalid_argument("Can't construct ScalarArray from invalid ScalarType"); @@ -282,7 +289,7 @@ void ScalarArray::deserialize(ByteBuffer* /*buffer*/, DeserializableControl* /*c } StructureArray::StructureArray(StructureConstPtr const & structure) -: Field(structureArray),pstructure(structure) +: Array(structureArray),pstructure(structure) { } @@ -312,7 +319,7 @@ void StructureArray::deserialize(ByteBuffer* /*buffer*/, DeserializableControl* } UnionArray::UnionArray(UnionConstPtr const & _punion) -: Field(unionArray),punion(_punion) +: Array(unionArray),punion(_punion) { } @@ -781,6 +788,13 @@ ScalarArrayConstPtr FieldCreate::createScalarArray(ScalarType elementType) const return scalarArrays[elementType]; } +StructureConstPtr FieldCreate::createStructure () const +{ + StringArray fieldNames; + FieldConstPtrArray fields; + return createStructure(fieldNames,fields); +} + StructureConstPtr FieldCreate::createStructure ( StringArray const & fieldNames,FieldConstPtrArray const & fields) const { diff --git a/src/factory/Makefile b/src/factory/Makefile index 8c9678b..23f211e 100644 --- a/src/factory/Makefile +++ b/src/factory/Makefile @@ -5,7 +5,6 @@ SRC_DIRS += $(PVDATA_SRC)/factory INC += factory.h LIBSRCS += TypeFunc.cpp LIBSRCS += FieldCreateFactory.cpp -LIBSRCS += PVAuxInfoImpl.cpp LIBSRCS += PVField.cpp LIBSRCS += PVScalar.cpp LIBSRCS += PVArray.cpp diff --git a/src/factory/PVAuxInfoImpl.cpp b/src/factory/PVAuxInfoImpl.cpp deleted file mode 100644 index 907b580..0000000 --- a/src/factory/PVAuxInfoImpl.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/*PVAuxInfo.cpp*/ -/** - * Copyright - See the COPYRIGHT that is included with this distribution. - * EPICS pvData is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. - */ -/** - * @author mrk - */ -#include -#include -#include -#include - -#define epicsExportSharedSymbols -#include -#include -#include -#include -#include - -namespace epics { namespace pvData { - - -PVAuxInfo::PVAuxInfo(PVField * pvField) - : pvField(pvField), - pvInfos(std::map > ()) -{ -} - -PVAuxInfo::~PVAuxInfo() -{ -} - - -PVField * PVAuxInfo::getPVField() { - return pvField; -} - - -PVScalarPtr PVAuxInfo::createInfo(String const & key,ScalarType scalarType) -{ - PVInfoIter iter = pvInfos.find(key); - if(iter!=pvInfos.end()) { - String message = key.c_str(); - message += " already exists "; - pvField->message(message,errorMessage); - return nullPVScalar; - } - PVScalarPtr pvScalar = getPVDataCreate()->createPVScalar(scalarType); - pvInfos.insert(PVInfoPair(key,pvScalar)); - return pvScalar; -} - -PVScalarPtr PVAuxInfo::getInfo(String const & key) -{ - PVInfoIter iter; - iter = pvInfos.find(key); - if(iter==pvInfos.end()) return nullPVScalar; - return iter->second; -} - -PVAuxInfo::PVInfoMap & PVAuxInfo::getInfoMap() -{ - return pvInfos; -} - - -void PVAuxInfo::toString(StringBuilder buf) -{ - PVAuxInfo::toString(buf,0); -} - -void PVAuxInfo::toString(StringBuilder buf,int indentLevel) -{ - if(pvInfos.size()<=0) return; - ConvertPtr convert = getConvert(); - convert->newLine(buf,indentLevel); - *buf += "auxInfo"; - for(PVInfoIter iter = pvInfos.begin(); iter!= pvInfos.end(); ++iter) { - convert->newLine(buf,indentLevel+1); - PVFieldPtr value = iter->second; - value->toString(buf,indentLevel + 1); - } -} -}} diff --git a/src/factory/PVDataCreateFactory.cpp b/src/factory/PVDataCreateFactory.cpp index 497edc0..bc4c8a2 100644 --- a/src/factory/PVDataCreateFactory.cpp +++ b/src/factory/PVDataCreateFactory.cpp @@ -548,16 +548,6 @@ PVScalarPtr PVDataCreate::createPVScalar(PVScalarPtr const & scalarToClone) ScalarType scalarType = scalarToClone->getScalar()->getScalarType(); PVScalarPtr pvScalar = createPVScalar(scalarType); getConvert()->copyScalar(scalarToClone, pvScalar); - PVAuxInfoPtr from = scalarToClone->getPVAuxInfo(); - PVAuxInfoPtr to = pvScalar->getPVAuxInfo(); - PVAuxInfo::PVInfoMap & map = from->getInfoMap(); - for(PVAuxInfo::PVInfoIter iter = map.begin(); iter!= map.end(); ++iter) { - String key = iter->first; - PVScalarPtr pvFrom = iter->second; - ScalarConstPtr scalar = pvFrom->getScalar(); - PVScalarPtr pvTo = to->createInfo(key,scalar->getScalarType()); - getConvert()->copyScalar(pvFrom,pvTo); - } return pvScalar; } @@ -607,16 +597,6 @@ PVScalarArrayPtr PVDataCreate::createPVScalarArray( PVScalarArrayPtr pvArray = createPVScalarArray( arrayToClone->getScalarArray()->getElementType()); pvArray->assign(*arrayToClone.get()); - PVAuxInfoPtr from = arrayToClone->getPVAuxInfo(); - PVAuxInfoPtr to = pvArray->getPVAuxInfo(); - PVAuxInfo::PVInfoMap & map = from->getInfoMap(); - for(PVAuxInfo::PVInfoIter iter = map.begin(); iter!= map.end(); ++iter) { - String key = iter->first; - PVScalarPtr pvFrom = iter->second; - ScalarConstPtr scalar = pvFrom->getScalar(); - PVScalarPtr pvTo = to->createInfo(key,scalar->getScalarType()); - getConvert()->copyScalar(pvFrom,pvTo); - } return pvArray; } diff --git a/src/factory/PVField.cpp b/src/factory/PVField.cpp index a01c537..8a342df 100644 --- a/src/factory/PVField.cpp +++ b/src/factory/PVField.cpp @@ -35,49 +35,6 @@ PVField::PVField(FieldConstPtr field) PVField::~PVField() { } -void PVField::message( - String message, - MessageType messageType, - String fullFieldName) -{ - if(parent!=NULL) { - if(fullFieldName.length()>0) { - fullFieldName = fieldName + '.' + fullFieldName; - } else { - fullFieldName = fieldName; - } - parent->message(message,messageType,fullFieldName); - return; - } - message = fullFieldName + " " + message; - if(requester) { - requester->message(message,messageType); - } else { - printf("%s %s %s\n", - getMessageTypeName(messageType).c_str(), - fieldName.c_str(), - message.c_str()); - } -} - -void PVField::message(String message,MessageType messageType) -{ - PVField::message(message,messageType,""); -} - -void PVField::setRequester(RequesterPtr const &req) -{ - if(parent!=NULL) { - throw std::logic_error( - "PVField::setRequester only legal for top level structure"); - } - if(requester.get()!=NULL) { - if(requester.get()==req.get()) return; - throw std::logic_error( - "PVField::setRequester requester is already present"); - } - requester = req; -} size_t PVField::getFieldOffset() const { @@ -97,12 +54,6 @@ size_t PVField::getNumberFields() const return (nextFieldOffset - fieldOffset); } -PVAuxInfoPtr & PVField::getPVAuxInfo(){ - if(pvAuxInfo.get()==NULL) { - pvAuxInfo = PVAuxInfoPtr(new PVAuxInfo(this)); - } - return pvAuxInfo; -} bool PVField::isImmutable() const {return immutable;} @@ -112,46 +63,6 @@ const FieldConstPtr & PVField::getField() const {return field;} PVStructure *PVField::getParent() const {return parent;} -void PVField::replacePVField(const PVFieldPtr & newPVField) -{ - if(parent==NULL) { - throw std::logic_error("no parent"); - } - PVFieldPtrArray pvFields = parent->getPVFields(); - StructureConstPtr structure = parent->getStructure(); - StringArray fieldNames = structure->getFieldNames(); - for(size_t i=0; igetFieldName().compare(fieldNames[i]) == 0) { - pvFields[i] = newPVField; - return; - } - } - throw std::logic_error("Did not find field in parent"); -} - -void PVField::replaceField(FieldConstPtr &xxx) -{ - field = xxx; -} - -void PVField::renameField(String const & newName) -{ - if(parent==NULL) { - throw std::logic_error("no parent"); - } - std::tr1::shared_ptr parentStructure = const_pointer_cast( - parent->getStructure()); - PVFieldPtrArray pvFields = parent->getPVFields(); - for(size_t i=0; irenameField(i,newName); - fieldName = newName; - return; - } - } - throw std::logic_error("Did not find field in parent"); -} - void PVField::postPut() { if(postHandler.get()!=NULL) postHandler->postPut(); @@ -187,14 +98,11 @@ void PVField::toString(StringBuilder buf) void PVField::toString(StringBuilder buf,int indentLevel) { Convert().getString(buf,this,indentLevel); - if(pvAuxInfo.get()!=NULL) pvAuxInfo->toString(buf,indentLevel); } std::ostream& operator<<(std::ostream& o, const PVField& f) { std::ostream& ro = f.dumpValue(o); - // TODO I do not want to call getPVAuxInfo() since it lazily creates a new instance of it - //if (f.pvAuxInfo.get()!=NULL) ro << *(f.pvAuxInfo.get()); return ro; }; @@ -221,26 +129,12 @@ namespace format String PVField::getFullName() const { - size_t size=fieldName.size(); - + String ret(fieldName); for(PVField *fld=getParent(); fld; fld=fld->getParent()) { - size+=fld->fieldName.size()+1; + if(fld->getFieldName().size()==0) break; + ret = fld->getFieldName() + '.' + ret; } - - String ret(size, '.'); - size_t pos=size - fieldName.size(); - - ret.replace(pos, String::npos, fieldName); - - for(PVField *fld=getParent(); fld; fld=fld->getParent()) - { - const String& nref = fld->fieldName; - assert(pos >= nref.size()+1); - pos -= nref.size()+1; - ret.replace(pos, String::npos, nref); - } - assert(pos==0); return ret; } diff --git a/src/factory/PVStructure.cpp b/src/factory/PVStructure.cpp index 64d47cc..6ed658b 100644 --- a/src/factory/PVStructure.cpp +++ b/src/factory/PVStructure.cpp @@ -60,7 +60,7 @@ PVStructure::PVStructure(StructureConstPtr const & structurePtr) pvFields.reserve(numberFields); PVDataCreatePtr pvDataCreate = getPVDataCreate(); for(size_t i=0; icreatePVField(fields[i])); + pvFields.push_back(pvDataCreate->createPVField(fields[i])); } for(size_t i=0; isetParentAndName(this,fieldNames[i]); @@ -134,110 +134,6 @@ PVFieldPtr PVStructure::getSubField(size_t fieldOffset) const throw std::logic_error("PVStructure.getSubField: Logic error"); } -void PVStructure::fixParentStructure() -{ - PVStructure *parent = getParent(); - if(parent==NULL) return; - StructureConstPtr parentStructure = parent->structurePtr; - String fieldName = getFieldName(); - size_t index = parentStructure->getFieldIndex(fieldName); - StringArray const &fieldNames = parentStructure->getFieldNames(); - size_t num = fieldNames.size(); - FieldConstPtrArray fields(num); - FieldConstPtrArray const & oldFields = parentStructure->getFields(); - for(size_t i=0; i< num; i++) { - if(i==index) { - fields[i] = structurePtr; - } else { - fields[i] = oldFields[i]; - } - } - FieldConstPtr field = getFieldCreate()->createStructure( - parentStructure->getID(),fieldNames,fields); - parent->replaceField(field); - parent->fixParentStructure(); -} - -void PVStructure::appendPVField( - String const &fieldName, - PVFieldPtr const & pvField) -{ - size_t origLength = pvFields.size(); - size_t newLength = origLength+1; - PVFieldPtrArray * xxx = const_cast(&pvFields); - xxx->push_back(pvField); - FieldConstPtr field = getFieldCreate()->appendField( - structurePtr,fieldName,pvField->getField()); - replaceField(field); - structurePtr = static_pointer_cast(field); - StringArray fieldNames = structurePtr->getFieldNames(); - for(size_t i=0; isetParentAndName(this,fieldNames[i]); - } - fixParentStructure(); -} - -void PVStructure::appendPVFields( - StringArray const & fieldNames, - PVFieldPtrArray const & pvFields) -{ - size_t origLength = this->pvFields.size(); - size_t extra = fieldNames.size(); - if(extra==0) return; - size_t newLength = origLength + extra; - PVFieldPtrArray * xxx = const_cast(&this->pvFields); - xxx->reserve(newLength); - for(size_t i=0; ipush_back(pvFields[i]); - } - FieldConstPtrArray fields; - fields.reserve(extra); - for(size_t i=0; igetField()); - FieldConstPtr field = getFieldCreate()->appendFields( - structurePtr,fieldNames,fields); - replaceField(field); - structurePtr = static_pointer_cast(field); - StringArray names = structurePtr->getFieldNames(); - for(size_t i=0; isetParentAndName(this,names[i]); - } - fixParentStructure(); -} - -void PVStructure::removePVField(String const &fieldName) -{ - PVFieldPtr pvField = getSubField(fieldName); - if(pvField.get()==NULL) { - return; - } - size_t origLength = pvFields.size(); - size_t newLength = origLength - 1; - PVFieldPtrArray const & origPVFields = pvFields; - FieldConstPtrArray origFields = structurePtr->getFields(); - PVFieldPtrArray newPVFields; - newPVFields.reserve(newLength); - StringArray newFieldNames; - newFieldNames.reserve(newLength); - FieldConstPtrArray fields; - fields.reserve(newLength); - for(size_t i=0; igetFieldName()); - newPVFields.push_back(origPVFields[i]); - fields.push_back(origFields[i]); - } - } - PVFieldPtrArray * xxx = const_cast(&pvFields); - xxx->swap(newPVFields); - FieldConstPtr field = getFieldCreate()->createStructure( - structurePtr->getID(),newFieldNames,fields); - replaceField(field); - structurePtr = static_pointer_cast(field); - StringArray fieldNames = structurePtr->getFieldNames(); - for(size_t i=0; isetParentAndName(this,fieldNames[i]); - } -} PVBooleanPtr PVStructure::getBooleanField(String const &fieldName) { @@ -341,18 +237,6 @@ PVUnionArrayPtr PVStructure::getUnionArrayField( return getSubField(fieldName); } -String PVStructure::getExtendsStructureName() const -{ - return extendsStructureName; -} - -bool PVStructure::putExtendsStructureName( - String const &xxx) -{ - if(extendsStructureName.length()!=0) return false; - extendsStructureName = xxx; - return true; -} void PVStructure::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) const { @@ -477,10 +361,6 @@ static PVFieldPtr findSubField( std::ostream& PVStructure::dumpValue(std::ostream& o) const { o << format::indent() << getStructure()->getID() << ' ' << getFieldName(); - String extendsName = getExtendsStructureName(); - if(extendsName.length()>0) { - o << " extends " << extendsName; - } o << std::endl; { format::indent_scope s(o); diff --git a/src/factory/PVUnion.cpp b/src/factory/PVUnion.cpp index 2eaa8c5..2c9cadf 100644 --- a/src/factory/PVUnion.cpp +++ b/src/factory/PVUnion.cpp @@ -126,6 +126,7 @@ void PVUnion::set(int32 index, PVFieldPtr const & value) selector = index; this->value = value; + postPut(); } void PVUnion::set(String const & fieldName, PVFieldPtr const & value) diff --git a/src/factory/StandardField.cpp b/src/factory/StandardField.cpp index 90a2ae7..6398f9a 100644 --- a/src/factory/StandardField.cpp +++ b/src/factory/StandardField.cpp @@ -505,6 +505,20 @@ StructureConstPtr StandardField::scalar( return createProperties("uri:ev4:nt/2012/pwd:NTScalar",field,properties); } +StructureConstPtr StandardField::regUnion( + UnionConstPtr const &field, + String const & properties) +{ + return createProperties("uri:ev4:nt/2012/pwd:NTUnion",field,properties); +} + +StructureConstPtr StandardField::variantUnion( + String const & properties) +{ + UnionConstPtr field = fieldCreate->createVariantUnion(); + return createProperties("uri:ev4:nt/2012/pwd:NTUnion",field,properties); +} + StructureConstPtr StandardField::scalarArray( ScalarType elementType, String const &properties) { @@ -518,7 +532,15 @@ StructureConstPtr StandardField::structureArray( { StructureArrayConstPtr field = fieldCreate->createStructureArray( structure); - return createProperties("uri:ev4:nt/2012/pwd:NTAny",field,properties); + return createProperties("uri:ev4:nt/2012/pwd:NTStructureArray",field,properties); +} + +StructureConstPtr StandardField::unionArray( + UnionConstPtr const & punion,String const &properties) +{ + UnionArrayConstPtr field = fieldCreate->createUnionArray( + punion); + return createProperties("uri:ev4:nt/2012/pwd:NTUnionArray",field,properties); } StructureConstPtr StandardField::enumerated() diff --git a/src/factory/StandardPVField.cpp b/src/factory/StandardPVField.cpp index adb52fe..26c0328 100644 --- a/src/factory/StandardPVField.cpp +++ b/src/factory/StandardPVField.cpp @@ -53,6 +53,14 @@ PVStructurePtr StandardPVField::structureArray( return pvStructure; } +PVStructurePtr StandardPVField::unionArray( + UnionConstPtr const & punion,String const & properties) +{ + StructureConstPtr field = standardField->unionArray(punion,properties); + PVStructurePtr pvStructure = pvDataCreate->createPVStructure(field); + return pvStructure; +} + PVStructurePtr StandardPVField::enumerated(StringArray const &choices) { StructureConstPtr field = standardField->enumerated(); diff --git a/src/factory/printer.cpp b/src/factory/printer.cpp index 8d74304..37a075f 100644 --- a/src/factory/printer.cpp +++ b/src/factory/printer.cpp @@ -199,9 +199,6 @@ void PrinterPlain::beginStructure(const PVStructure& pv) { indentN(S(), ilvl); S() << pv.getStructure()->getID() << " " << pv.getFieldName(); - String ename(pv.getExtendsStructureName()); - if(!ename.empty()) - S() << " extends " << ename; S() << std::endl; ilvl++; } diff --git a/src/factory/pvSubArrayCopy.cpp b/src/factory/pvSubArrayCopy.cpp index c89aef2..45d57ba 100644 --- a/src/factory/pvSubArrayCopy.cpp +++ b/src/factory/pvSubArrayCopy.cpp @@ -15,30 +15,33 @@ #include namespace epics { namespace pvData { +using std::cout; +using std::endl; template void copy( PVValueArray & pvFrom, size_t fromOffset, + size_t fromStride, PVValueArray & pvTo, size_t toOffset, - size_t len) + size_t toStride, + size_t count) { - if(pvTo.isImmutable()) { - throw std::logic_error("pvSubArrayCopy to is immutable"); - } + if(pvTo.isImmutable()) throw std::invalid_argument("pvSubArrayCopy: pvTo is immutable"); + if(fromStride<1 || toStride<1) throw std::invalid_argument("stride must be >=1"); size_t fromLength = pvFrom.getLength(); - if(fromOffset+len>fromLength) { - throw std::length_error("pvSubArrayCopy from length error"); - } + size_t num = fromOffset + count*fromStride; + if(num>fromLength) throw std::invalid_argument("pvSubArrayCopy pvFrom length error"); + size_t newLength = toOffset + count*toStride; size_t capacity = pvTo.getCapacity(); - if(toOffset+len>capacity) capacity = toOffset + len; + if(newLength>capacity) capacity = newLength; shared_vector temp(capacity); typename PVValueArray::const_svector vecFrom = pvFrom.view(); typename PVValueArray::const_svector vecTo = pvTo.view(); - for(size_t i=0; i temp2(freeze(temp)); pvTo.replace(temp2); } @@ -46,9 +49,11 @@ void copy( void copy( PVScalarArray & from, size_t fromOffset, + size_t fromStride, PVScalarArray & to, size_t toOffset, - size_t len) + size_t toStride, + size_t count) { ScalarType scalarType = from.getScalarArray()->getElementType(); ScalarType otherType = to.getScalarArray()->getElementType(); @@ -59,146 +64,170 @@ void copy( { case pvBoolean: { - copy(dynamic_cast &>(from),fromOffset, + copy(dynamic_cast &>(from),fromOffset,fromStride, dynamic_cast& >(to), - toOffset,len); + toOffset,toStride,count); } break; case pvByte: { - copy(dynamic_cast &>(from),fromOffset, + copy(dynamic_cast &>(from),fromOffset,fromStride, dynamic_cast& >(to), - toOffset,len); + toOffset,toStride,count); } break; case pvShort: { - copy(dynamic_cast &>(from),fromOffset, + copy(dynamic_cast &>(from),fromOffset,fromStride, dynamic_cast& >(to), - toOffset,len); + toOffset,toStride,count); } break; case pvInt: { - copy(dynamic_cast &>(from),fromOffset, + copy(dynamic_cast &>(from),fromOffset,fromStride, dynamic_cast& >(to), - toOffset,len); + toOffset,toStride,count); } break; case pvLong: { - copy(dynamic_cast &>(from),fromOffset, + copy(dynamic_cast &>(from),fromOffset,fromStride, dynamic_cast& >(to), - toOffset,len); + toOffset,toStride,count); } break; case pvUByte: { - copy(dynamic_cast &>(from),fromOffset, + copy(dynamic_cast &>(from),fromOffset,fromStride, dynamic_cast& >(to), - toOffset,len); + toOffset,toStride,count); } break; case pvUShort: { - copy(dynamic_cast &>(from),fromOffset, + copy(dynamic_cast &>(from),fromOffset,fromStride, dynamic_cast& >(to), - toOffset,len); + toOffset,toStride,count); } break; case pvUInt: { - copy(dynamic_cast &>(from),fromOffset, + copy(dynamic_cast &>(from),fromOffset,fromStride, dynamic_cast& >(to), - toOffset,len); + toOffset,toStride,count); } break; case pvULong: { - copy(dynamic_cast &>(from),fromOffset, + copy(dynamic_cast &>(from),fromOffset,fromStride, dynamic_cast& >(to), - toOffset,len); + toOffset,toStride,count); } break; case pvFloat: { - copy(dynamic_cast &>(from),fromOffset, + copy(dynamic_cast &>(from),fromOffset,fromStride, dynamic_cast& >(to), - toOffset,len); + toOffset,toStride,count); } break; case pvDouble: { - copy(dynamic_cast &>(from),fromOffset, + copy(dynamic_cast &>(from),fromOffset,fromStride, dynamic_cast& >(to), - toOffset,len); + toOffset,toStride,count); } break; case pvString: { - copy(dynamic_cast &>(from),fromOffset, + copy(dynamic_cast &>(from),fromOffset,fromStride, dynamic_cast& >(to), - toOffset,len); + toOffset,toStride,count); } break; } } void copy( - PVStructureArray & from, - size_t fromOffset, - PVStructureArray & to, + PVStructureArray & pvFrom, + size_t pvFromOffset, + size_t pvFromStride, + PVStructureArray & pvTo, size_t toOffset, - size_t len) + size_t toStride, + size_t count) { - if(to.isImmutable()) { - throw std::logic_error("pvSubArrayCopy to is immutable"); + if(pvTo.isImmutable()) { + throw std::logic_error("pvSubArrayCopy pvTo is immutable"); } - StructureArrayConstPtr fromStructure = from.getStructureArray(); - StructureArrayConstPtr toStructure = to.getStructureArray(); - if(fromStructure!=toStructure) { + if(pvFromStride<1 || toStride<1) throw std::invalid_argument("stride must be >=1"); + StructureArrayConstPtr pvFromStructure = pvFrom.getStructureArray(); + StructureArrayConstPtr toStructure = pvTo.getStructureArray(); + if(pvFromStructure!=toStructure) { throw std::invalid_argument( - "pvSubArrayCopy structureArray to and from have different structures"); + "pvSubArrayCopy structureArray pvTo and pvFrom have different structures"); } - size_t fromLength = from.getLength(); - if(fromOffset+len>fromLength) { - throw std::length_error("pvSubArrayCopy from length error"); - } - size_t capacity = to.getCapacity(); - if(toOffset+len>capacity) capacity = toOffset+len; + size_t pvFromLength = pvFrom.getLength(); + size_t num = pvFromOffset + count*pvFromStride; + if(num>pvFromLength) throw std::invalid_argument("pvSubArrayCopy pvFrom length error"); + size_t newLength = toOffset + count*toStride; + size_t capacity = pvTo.getCapacity(); + if(newLength>capacity) capacity = newLength; shared_vector temp(capacity); - PVValueArray::const_svector vecFrom = from.view(); - PVValueArray::const_svector vecTo = to.view(); - for(size_t i=0; i::const_svector vecFrom = pvFrom.view(); + PVValueArray::const_svector vecTo = pvTo.view(); + for(size_t i=0; icreatePVStructure(toStructure->getStructure()); + for(size_t i=0; i temp2(freeze(temp)); - to.replace(temp2); + pvTo.replace(temp2); } void copy( - PVArray & from, - size_t fromOffset, - PVArray & to, - size_t toOffset, - size_t len) + PVArray & pvFrom, + size_t pvFromOffset, + size_t pvFromStride, + PVArray & pvTo, + size_t pvToOffset, + size_t pvToStride, + size_t count) { - Type type = from.getField()->getType(); - Type otherType = to.getField()->getType(); - if(type!=otherType) { - throw std::invalid_argument("pvSubArrayCopy types do not match"); + Type pvFromType = pvFrom.getField()->getType(); + Type pvToType = pvTo.getField()->getType(); + if(pvFromType!=pvToType) throw std::invalid_argument("pvSubArrayCopy: pvFrom and pvTo different types"); + if(pvFromType==scalarArray) { + ScalarType pvFromScalarType= static_cast(pvFromType); + ScalarType pvToScalarType = static_cast(pvToType); + if(pvFromScalarType!=pvToScalarType){ + throw std::invalid_argument("pvSubArrayCopy: pvFrom and pvTo different types"); + } } - if(type==scalarArray) { - copy(dynamic_cast(from) ,fromOffset, - dynamic_cast(to), - toOffset,len); + if(pvTo.isImmutable()) throw std::invalid_argument("pvSubArrayCopy: pvTo is immutable"); + if(pvFromType==scalarArray) { + copy(dynamic_cast(pvFrom) ,pvFromOffset,pvFromStride, + dynamic_cast(pvTo), + pvToOffset,pvToStride,count); } - if(type==structureArray) { - copy(dynamic_cast(from) ,fromOffset, - dynamic_cast(to), - toOffset,len); + if(pvFromType==structureArray) { + copy(dynamic_cast(pvFrom) ,pvFromOffset,pvFromStride, + dynamic_cast(pvTo), + pvToOffset,pvToStride,count); } } +void copy( + PVArray::shared_pointer const & pvFrom, + size_t pvFromOffset, + size_t pvFromStride, + PVArray::shared_pointer & pvTo, + size_t pvToOffset, + size_t pvToStride, + size_t count) +{ + copy(*pvFrom,pvFromOffset,pvFromStride,*pvTo,pvToOffset,pvToStride,count); +} + }} diff --git a/src/misc/bitSet.cpp b/src/misc/bitSet.cpp index 8169aff..31d6414 100644 --- a/src/misc/bitSet.cpp +++ b/src/misc/bitSet.cpp @@ -374,5 +374,20 @@ namespace epics { namespace pvData { words[i] |= (buffer->getByte() & 0xffL) << (8 * j); } + + epicsShareExtern std::ostream& operator<<(std::ostream& o, const BitSet& b) + { + o << '{'; + int32 i = b.nextSetBit(0); + if (i != -1) { + o << i; + for (i = b.nextSetBit(i+1); i >= 0; i = b.nextSetBit(i+1)) { + int32 endOfRun = b.nextClearBit(i); + do { o << ", " << i; } while (++i < endOfRun); + } + } + o << '}'; + return o; + } }}; diff --git a/src/misc/bitSet.h b/src/misc/bitSet.h index ae7357c..be6f231 100644 --- a/src/misc/bitSet.h +++ b/src/misc/bitSet.h @@ -317,6 +317,8 @@ namespace epics { namespace pvData { static uint32 bitCount(uint64 i); }; + + epicsShareExtern std::ostream& operator<<(std::ostream& o, const BitSet& b); }} #endif /* BITSET_H */ diff --git a/src/monitor/Makefile b/src/monitor/Makefile index 01670ae..7488c79 100644 --- a/src/monitor/Makefile +++ b/src/monitor/Makefile @@ -3,6 +3,7 @@ SRC_DIRS += $(PVDATA_SRC)/monitor INC += monitor.h +INC += monitorPlugin.h LIBSRCS += monitor.cpp - +LIBSRCS += monitorPlugin.cpp \ No newline at end of file diff --git a/src/monitor/monitor.h b/src/monitor/monitor.h index 74006a3..882d59d 100644 --- a/src/monitor/monitor.h +++ b/src/monitor/monitor.h @@ -15,6 +15,7 @@ #include #include #include +#include #include diff --git a/src/monitor/monitorPlugin.cpp b/src/monitor/monitorPlugin.cpp new file mode 100644 index 0000000..4c87a2c --- /dev/null +++ b/src/monitor/monitorPlugin.cpp @@ -0,0 +1,82 @@ +/* monitorPlugin.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +#include + +namespace epics { namespace pvData { +using std::cout; +using std::endl; + +MonitorPluginManagerPtr MonitorPluginManager::get() +{ + static MonitorPluginManagerPtr pluginManager; + static Mutex mutex; + Lock xx(mutex); + if(pluginManager==NULL) { + pluginManager = MonitorPluginManagerPtr(new MonitorPluginManager()); + } + return pluginManager; +} + +bool MonitorPluginManager::addPlugin( + String const &pluginName, + MonitorPluginCreatorPtr const &creator) +{ + mutex.lock(); + std::list::iterator iter; + for (iter = monitorPluginList.begin();iter!=monitorPluginList.end();iter++) + { + if(*iter==creator) + { + mutex.unlock(); + return false; + } + if(((*iter)->getName().compare(pluginName))==0) + { + mutex.unlock(); + return false; + } + } + monitorPluginList.push_back(creator); + mutex.unlock(); + return true; +} + + +MonitorPluginCreatorPtr MonitorPluginManager::findPlugin( + String const &pluginName) +{ + mutex.lock(); + std::list::iterator iter; + for (iter = monitorPluginList.begin();iter!=monitorPluginList.end();++iter) + { + if(((*iter)->getName().compare(pluginName))==0) + { + mutex.unlock(); + return *iter; + } + } + mutex.unlock(); + return MonitorPluginCreatorPtr(); +} + +void MonitorPluginManager::showNames() +{ + mutex.lock(); + std::list::iterator iter; + for (iter = monitorPluginList.begin();iter!=monitorPluginList.end();++iter) + { + std::cout << (*iter)->getName() << std::endl; + } + mutex.unlock(); +} + + +}} diff --git a/src/monitor/monitorPlugin.h b/src/monitor/monitorPlugin.h new file mode 100644 index 0000000..b106c24 --- /dev/null +++ b/src/monitor/monitorPlugin.h @@ -0,0 +1,177 @@ +/* monitorPlugin.h */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ +#ifndef MONITORPLUGIN_H +#define MONITORPLUGIN_H + +#include +#include +#include +#include +#include + +#include + +namespace epics { namespace pvData { + +/** + * typedef for a pointer to a MonitorPlugin + */ +class MonitorPlugin; +typedef std::tr1::shared_ptr MonitorPluginPtr; + + +/** + * typedef for a pointer to a MonitorPluginCreator + */ +class MonitorPluginCreator; +typedef std::tr1::shared_ptr MonitorPluginCreatorPtr; + + +/** + * typedef for a pointer to a MonitorPluginManager + */ +class MonitorPluginManager; +typedef std::tr1::shared_ptr MonitorPluginManagerPtr; + + +/** A plugin for raising monitors; + * This is for use by pvAccess servers that support monitors. + * Since the interface has only a dependence on pvData it + * can be used for other purposes. + * A monitor is assumed to be associated with a field of a top level + * structure. + */ +class MonitorPlugin +{ +public: + virtual ~MonitorPlugin(){} + /** + * getName + * @returns The name of the plugin + */ + virtual String const & getName() = 0; + /** + * Should a monitor be raised? + * @param pvField The field being monitored. + * @param pvTop The top level sructure in which the field resides. + * @param monitorElement The client data and bitSets. + * @returns true or false. + * True is returned if the change to this field should cause a monitor. + * False is returned in a change only to this field should not cause a + * monitor. + */ + virtual bool causeMonitor( + PVFieldPtr const &pvField, + PVStructurePtr const &pvTop, + MonitorElementPtr const &monitorElement) = 0; + /** + * A monitor will be sent to the client. + * @param pvField The copy of the field being monitored. + * The plugin can modify the data. + * @param pvTop The top level sructure in which the field resides. + * @param monitorElement The data for the client. + * The plugin is allowed to change the data values. + */ + virtual void monitorDone( + MonitorElementPtr const &monitorElement) + {} + /** + * Begin monitoring + */ + virtual void startMonitoring(){} + /** + * Stop monitoring + */ + virtual void stopMonitoring(){} + /** + * Begin a set of puts. + */ + virtual void beginGroupPut() {}; + /** + * End a set of puts. + */ + virtual void endGroupPut() {}; +}; + +/** A class that creates a plugin. + * Normlly a plugin is created for a single client. + */ +class MonitorPluginCreator +{ +public: + virtual ~MonitorPluginCreator() {} + /** + * Create a monitor plugin. + * @param field The introspection interface for the field monitored. + * @param top The introspsction interface for the client structure. + * @param pvFieldOptions The options the client requested. + * The structure has a set of PVString subfields. + * The options are a set of name,value pairs. + * The subfield name is the name and the subfield value is the value. + * @returns shared pointer to a MonitorPluginCreator. + */ + virtual MonitorPluginPtr create( + FieldConstPtr const &field, + StructureConstPtr const &top, + PVStructurePtr const &pvFieldOptions) = 0; + /** + * getName + * @returns The name of the plugin + */ + virtual String const & getName() = 0; +}; + + +/** + * This manages a set of monitor plugins. + * @author mrk + */ +class epicsShareClass MonitorPluginManager +{ +public: + POINTER_DEFINITIONS(MonitorPluginManager); + /** + * Factory to get the manager. + * @return shared pointer to manager. + */ + static MonitorPluginManagerPtr get(); + /** destructor + */ + ~MonitorPluginManager(){} + /* add plugin + * @param pluginName The name of the plugin. + * @param creator The creator. + * @returns true or false + * false is returned if a plugin with that name is already present + */ + bool addPlugin( + String const &pluginName, + MonitorPluginCreatorPtr const &creator); + /* find plugin + * + * @param plugin name + * @returns share pointer to plugin creator. + * If a plugin with that name is not found NULL is returned. + */ + MonitorPluginCreatorPtr findPlugin(String const &pluginName); + /* showNames + * + */ + void showNames(); +private: + MonitorPluginManager(){} + std::list monitorPluginList; + epics::pvData::Mutex mutex; +}; + + + +}} +#endif /* MONITORPLUGIN_H */ diff --git a/src/property/pvAlarm.cpp b/src/property/pvAlarm.cpp index 001fb44..6506646 100644 --- a/src/property/pvAlarm.cpp +++ b/src/property/pvAlarm.cpp @@ -25,25 +25,17 @@ String PVAlarm::notAttached("Not attached to an alarm structure"); bool PVAlarm::attach(PVFieldPtr const & pvField) { - if(pvField->getField()->getType()!=structure) { - pvField->message(noAlarmFound,errorMessage); - return false; - } + if(pvField->getField()->getType()!=structure) return false; PVStructurePtr pvStructure = static_pointer_cast(pvField); pvSeverity = pvStructure->getIntField("severity"); - if(pvSeverity.get()==NULL) { - pvField->message(noAlarmFound,errorMessage); - return false; - } + if(pvSeverity.get()==NULL) return false; pvStatus = pvStructure->getIntField("status"); if(pvStatus.get()==NULL) { - pvField->message(noAlarmFound,errorMessage); pvSeverity.reset(); return false; } pvMessage = pvStructure->getStringField("message"); if(pvMessage.get()==NULL) { - pvField->message(noAlarmFound,errorMessage); pvSeverity.reset(); pvStatus.reset(); return false; diff --git a/src/property/pvControl.cpp b/src/property/pvControl.cpp index 8f761ff..c1b8576 100644 --- a/src/property/pvControl.cpp +++ b/src/property/pvControl.cpp @@ -25,20 +25,13 @@ String PVControl::notAttached("Not attached to an control structure"); bool PVControl::attach(PVFieldPtr const & pvField) { - if(pvField->getField()->getType()!=structure) { - pvField->message(noControlFound,errorMessage); - return false; - } + if(pvField->getField()->getType()!=structure) return false; PVStructurePtr pvStructure = static_pointer_cast(pvField); pvLow = pvStructure->getDoubleField("limitLow"); - if(pvLow.get()==NULL) { - pvField->message(noControlFound,errorMessage); - return false; - } + if(pvLow.get()==NULL) return false; pvHigh = pvStructure->getDoubleField(String("limitHigh")); if(pvHigh.get()==NULL) { pvLow.reset(); - pvField->message(noControlFound,errorMessage); return false; } return true; diff --git a/src/property/pvDisplay.cpp b/src/property/pvDisplay.cpp index f7e6887..a5dd085 100644 --- a/src/property/pvDisplay.cpp +++ b/src/property/pvDisplay.cpp @@ -25,37 +25,27 @@ String PVDisplay::notAttached("Not attached to an display structure"); bool PVDisplay::attach(PVFieldPtr const & pvField) { - if(pvField->getField()->getType()!=structure) { - pvField->message(noDisplayFound,errorMessage); - return false; - } + if(pvField->getField()->getType()!=structure) return false; PVStructurePtr pvStructure = static_pointer_cast(pvField); pvDescription = pvStructure->getStringField("description"); - if(pvDescription.get()==NULL) { - pvField->message(noDisplayFound,errorMessage); - return false; - } + if(pvDescription.get()==NULL) return false; pvFormat = pvStructure->getStringField("format"); if(pvFormat.get()==NULL) { - pvField->message(noDisplayFound,errorMessage); detach(); return false; } pvUnits = pvStructure->getStringField("units"); if(pvUnits.get()==NULL) { - pvField->message(noDisplayFound,errorMessage); detach(); return false; } pvLow = pvStructure->getDoubleField(String("limitLow")); if(pvLow.get()==NULL) { - pvField->message(noDisplayFound,errorMessage); detach(); return false; } pvHigh = pvStructure->getDoubleField(String("limitHigh")); if(pvHigh.get()==NULL) { - pvField->message(noDisplayFound,errorMessage); detach(); return false; } diff --git a/src/property/pvEnumerated.cpp b/src/property/pvEnumerated.cpp index 25f883f..05ec180 100644 --- a/src/property/pvEnumerated.cpp +++ b/src/property/pvEnumerated.cpp @@ -25,21 +25,14 @@ String PVEnumerated::notAttached("Not attached to an enumerated structure"); bool PVEnumerated::attach(PVFieldPtr const & pvField) { - if(pvField->getField()->getType()!=structure) { - pvField->message(notFound,errorMessage); - return false; - } + if(pvField->getField()->getType()!=structure) return false; PVStructurePtr pvStructure = static_pointer_cast(pvField); pvIndex = pvStructure->getIntField("index"); - if(pvIndex.get()==NULL) { - pvField->message(notFound,errorMessage); - return false; - } + if(pvIndex.get()==NULL) return false; PVScalarArrayPtr pvScalarArray = pvStructure->getScalarArrayField( "choices",pvString); if(pvScalarArray.get()==NULL) { pvIndex.reset(); - pvField->message(notFound,errorMessage); return false; } pvChoices = static_pointer_cast(pvScalarArray); diff --git a/src/property/pvTimeStamp.cpp b/src/property/pvTimeStamp.cpp index daf2352..92233c9 100644 --- a/src/property/pvTimeStamp.cpp +++ b/src/property/pvTimeStamp.cpp @@ -25,10 +25,7 @@ String PVTimeStamp::notAttached("Not attached to a timeStamp structure"); bool PVTimeStamp::attach(PVFieldPtr const & pvField) { - if(pvField->getField()->getType()!=structure) { - pvField->message(noTimeStamp,errorMessage); - return false; - } + if(pvField->getField()->getType()!=structure) return false; PVStructurePtr xxx = static_pointer_cast(pvField); PVStructure* pvStructure = xxx.get(); while(true) { diff --git a/src/pv/pvData.h b/src/pv/pvData.h index 0f126e0..186e64f 100644 --- a/src/pv/pvData.h +++ b/src/pv/pvData.h @@ -14,13 +14,6 @@ #define NOMINMAX #endif -#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 -/* error attribute was introduced in gcc 4.3.x */ -#define USAGE_ERROR(MSG) __attribute__((error(MSG))) -#else -#define USAGE_ERROR(MSG) { throw std::runtime_error(MSG); } -#endif - #include #include #include @@ -30,7 +23,6 @@ #include #include -#include #include #include @@ -106,7 +98,6 @@ epicsShareExtern array_at_internal operator<<(std::ostream& str, array_at const& }; -class PVAuxInfo; class PostHandler; class PVField; @@ -124,11 +115,6 @@ template class PVScalarValue; template class PVValueArray; -/** - * typedef for a pointer to a PVAuxInfo. - */ -typedef std::tr1::shared_ptr PVAuxInfoPtr; - /** * typedef for a pointer to a PostHandler. */ @@ -198,67 +184,6 @@ typedef std::tr1::shared_ptr PVUnionArrayPtrArrayPtr; class PVDataCreate; typedef std::tr1::shared_ptr PVDataCreatePtr; -/** - * This class provides auxillary information about a PVField. - * Each item is stored as a PVScalar. - * A (key,value) is provided for accessing the items where the key is a String. - */ -class epicsShareClass PVAuxInfo : private NoDefaultMethods { -public: - typedef std::map PVInfoMap; - typedef std::map::iterator PVInfoIter; - typedef std::pair PVInfoPair; - - /** - * Constructor - * @param The fields to which the Auxinfo is attached. - */ - PVAuxInfo(PVField *pvField); - /** - * Destructor - */ - ~PVAuxInfo(); - /** - * Get the PVField to which the Auxinfo is attached. - * @return The fields to which the Auxinfo is attached. - */ - PVField * getPVField(); - /** - * Add a new auxiliary item or retrieve the interface to an existing item. - * - * @param key The key. - * @param scalarType The scalarType for the new item being added/ - * @return The new PVScalar that has been added to the Auxinfo. - */ - PVScalarPtr createInfo(String const & key,ScalarType scalarType); - /** - * Get the Auxinfo with the specified key. - * @return The PVScalar or null if it does not exist. - */ - PVScalarPtr getInfo(String const & key); - /** - * Get the map for the info. - * @return The map; - */ - PVInfoMap & getInfoMap(); - /** - * Convert the Auxinfo to a string and add it to builder. - * @param builder The string builder. - */ - void toString(StringBuilder buf); - /** - * Convert the Auxinfo to a string and add it to builder. - * @param builder The string builder. - * @param indentLevel The number of blanks at the beginning of new lines. - */ - void toString(StringBuilder buf,int indentLevel); -private: - PVScalarPtr nullPVScalar; - PVField * pvField; - PVInfoMap pvInfos; - friend class PVDataCreate; -}; - /** * This class is implemented by code that calls setPostHander */ @@ -294,12 +219,6 @@ public: * Destructor */ virtual ~PVField(); - /** - * Called to report errors associated with the field. - * @param message The message. - * @param messageType The message type. - */ - virtual void message(String message,MessageType messageType) ; /** * Get the fieldName for this field. * @return The name or empty string if top level field. @@ -311,12 +230,6 @@ public: * each name. */ String getFullName() const; - /** - * Register the message requester. - * At most one requester can be registered. - * @param prequester The requester. - */ - virtual void setRequester(RequesterPtr const &prequester); /** * Get offset of the PVField field within top level structure. * Every field within the PVStructure has a unique offset. @@ -338,11 +251,6 @@ public: * This is equal to nextFieldOffset - fieldOffset. */ std::size_t getNumberFields() const; - /** - * Get the PVAuxInfo interface for the PVField. - * @return The PVAuxInfo interface. - */ - PVAuxInfoPtr & getPVAuxInfo(); /** * Is the field immutable, i.e. does it not allow changes. * @return (false,true) if it (is not, is) immutable. @@ -363,16 +271,6 @@ public: * @return The parent interface or null if this is PVRecord */ PVStructure * getParent() const ; - /** - * Replace the data implementation for the field. - * @param newPVField The new implementation - */ - void replacePVField(const PVFieldPtr& newPVField); - /** - * Rename the field name. - * @param newName The new name. - */ - void renameField(String const & newName); /** * postPut. Called when the field is updated by the implementation. */ @@ -417,20 +315,16 @@ protected: } PVField(FieldConstPtr field); void setParentAndName(PVStructure *parent, String const & fieldName); - void replaceField(FieldConstPtr &field); private: - void message(String message,MessageType messageType,String fullFieldName); static void computeOffset(const PVField *pvField); static void computeOffset(const PVField *pvField,std::size_t offset); String notImplemented; - PVAuxInfoPtr pvAuxInfo; String fieldName; PVStructure *parent; FieldConstPtr field; size_t fieldOffset; size_t nextFieldOffset; bool immutable; - RequesterPtr requester; PostHandlerPtr postHandler; friend class PVDataCreate; friend class PVStructure; @@ -649,6 +543,11 @@ public: * Destructor */ virtual ~PVArray(){}; + /** + * Get the introspection interface + * @return The interface. + */ + virtual ArrayConstPtr getArray() const = 0; /** * Set the field to be immutable, i. e. it can no longer be modified. * This is permanent, i.e. once done the field can onot be made mutable. @@ -696,31 +595,6 @@ private: epicsShareExtern std::ostream& operator<<(format::array_at_internal const& manip, const PVArray& array); -/** - * Class provided by caller of get - */ -template -class PVArrayData { -private: - std::vector init; -public: - POINTER_DEFINITIONS(PVArrayData); - typedef T value_type; - typedef T* pointer; - typedef const T* const_pointer; - /** - * The data array. - */ - std::vector & data; - /** - * The offset. This is the offset into the actual array of the first element in data, - */ - std::size_t offset; - PVArrayData() - : data(init) - {} -}; - /** * Base class for a scalarArray. @@ -864,92 +738,86 @@ public: return std::tr1::shared_ptr(); } - /** - * Append a field to the structure. - * @param fieldName The name of the field to append. - * @param pvField The field to append. - */ - void appendPVField(String const &fieldName,PVFieldPtr const & pvField); - /** - * Append fields to the structure. - * @param fieldNames The names of the fields to add. - * @param pvFields The fields to append. - * @return Pointer to the field or null if field does not exist. - */ - void appendPVFields(StringArray const & fieldNames,PVFieldPtrArray const & pvFields); - /** - * Remove a field from the structure. - * @param fieldName The name of the field to remove. - */ - void removePVField(String const &fieldName); /** * Get a boolean field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVBooleanPtr getBooleanField(String const &fieldName) ; /** * Get a byte field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVBytePtr getByteField(String const &fieldName) ; /** * Get a short field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVShortPtr getShortField(String const &fieldName) ; /** * Get a int field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVIntPtr getIntField(String const &fieldName) ; /** * Get a long field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVLongPtr getLongField(String const &fieldName) ; /** * Get an unsigned byte field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVUBytePtr getUByteField(String const &fieldName) ; /** * Get an unsigned short field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVUShortPtr getUShortField(String const &fieldName) ; /** * Get an unsigned int field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVUIntPtr getUIntField(String const &fieldName) ; /** * Get an unsigned long field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVULongPtr getULongField(String const &fieldName) ; /** * Get a float field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVFloatPtr getFloatField(String const &fieldName) ; /** * Get a double field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVDoublePtr getDoubleField(String const &fieldName) ; /** * Get a string field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ @@ -957,18 +825,21 @@ public: /** * Get a structure field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVStructurePtr getStructureField(String const &fieldName) ; /** * Get a union field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVUnionPtr getUnionField(String const &fieldName) ; /** * Get a scalarArray field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @param elementType The element type. * @return Pointer to the field of null if a field with that name and type does not exist. @@ -977,27 +848,18 @@ public: String const &fieldName,ScalarType elementType) ; /** * Get a structureArray field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVStructureArrayPtr getStructureArrayField(String const &fieldName) ; /** * Get a unionArray field with the specified name. + * No longer needed. Use templete version of getSubField * @param fieldName The name of the field to get. * @return Pointer to the field of null if a field with that name and type does not exist. */ PVUnionArrayPtr getUnionArrayField(String const &fieldName) ; - /** - * Get the name if this structure extends another structure. - * @return The string which may be null. - */ - String getExtendsStructureName() const; - /** - * Put the extends name. - * @param extendsStructureName The name. - */ - bool putExtendsStructureName( - String const &extendsStructureName); /** * Serialize. * @param pbuffer The byte buffer. @@ -1043,7 +905,6 @@ public: virtual std::ostream& dumpValue(std::ostream& o) const; private: - void fixParentStructure(); static PVFieldPtr nullPVField; static PVBooleanPtr nullPVBoolean; static PVBytePtr nullPVByte; @@ -1070,6 +931,9 @@ private: }; +/** + * PVUnion has a single subfield which has a type specified by a union introspection interface. + */ class epicsShareClass PVUnion : public PVField { public: @@ -1225,12 +1089,6 @@ namespace detail { typedef ::epics::pvData::shared_vector svector; typedef ::epics::pvData::shared_vector const_svector; - // begin deprecated - typedef PVArrayData ArrayDataType; - typedef std::vector vector; - typedef const std::vector const_vector; - typedef std::tr1::shared_ptr shared_vector; - // end deprecated protected: PVVectorStorage() : Base() {} @@ -1279,79 +1137,6 @@ namespace detail { return thaw(result); } - /** - * Get array elements - * @param offset The offset of the first element, - * @param length The number of elements to get. - * @param data The place where the data is placed. - */ - std::size_t get( - std::size_t offset, std::size_t length, ArrayDataType &data) EPICS_DEPRECATED - { - const_svector ref = this->view(); - ref.slice(offset, length); - data.data.resize(ref.size()); - data.offset = 0; - std::copy(ref.begin(), ref.end(), data.data.begin()); - return ref.size(); - } - - /** - * Copy data into the array growing the length as needed. - * @param offset The offset of the first element, - * @param length The number of elements to get. - * @param from The new values to put into the array. - * @param fromOffset The offset in from. - * @return The number of elements put into the array. - * calls postPut() - */ - std::size_t put(std::size_t offset, - std::size_t length, const_pointer from, std::size_t fromOffset) EPICS_DEPRECATED - { - from += fromOffset; - - svector temp(this->reuse()); - if(temp.size() < length+offset) - temp.resize(length+offset); - else - temp.make_unique(); - - std::copy(from, from + length, temp.begin() + offset); - this->replace(freeze(temp)); - return length; - } - - std::size_t put(std::size_t offset, - std::size_t length, const_vector &from, std::size_t fromOffset) EPICS_DEPRECATED - { return this->put(offset,length, &from[0], fromOffset); } - - /** - * Share data from another source. - * @param value The data to share. - * @param capacity The capacity of the array. - * @param length The length of the array. - * Does @b not call postPut() - */ - void shareData( - shared_vector const & value, - std::size_t capacity, - std::size_t length) EPICS_DEPRECATED - { - vector& vref = *value.get(); - typename svector::shared_pointer_type p(&vref[0], - detail::shared_ptr_vector_deletor(value)); - const_svector temp(p, 0, std::min(length, vref.size())); - this->swap(temp); - } - - pointer get() const EPICS_DEPRECATED { - // evil unsafe cast! - return (pointer)this->view().data(); - } - - vector const & getVector() USAGE_ERROR("No longer implemented. Replace with view()"); - shared_vector const & getSharedVector() USAGE_ERROR("No longer implemented. Replace with view()"); - }; } // namespace detail @@ -1368,14 +1153,6 @@ public: typedef ::epics::pvData::shared_vector svector; typedef ::epics::pvData::shared_vector const_svector; - // begin deprecated - typedef PVArrayData ArrayDataType; - typedef std::vector vector; - typedef const std::vector const_vector; - typedef std::tr1::shared_ptr shared_vector; - typedef PVValueArray & reference; - typedef const PVValueArray & const_reference; - // end deprecated static const ScalarType typeCode; @@ -1384,6 +1161,11 @@ public: */ virtual ~PVValueArray() {} + virtual ArrayConstPtr getArray() const + { + return std::tr1::static_pointer_cast(this->getField()); + } + std::ostream& dumpValue(std::ostream& o) const { const_svector v(this->view()); @@ -1421,10 +1203,6 @@ protected: friend class PVDataCreate; }; -/** - * This is provided by code that calls get. - */ -typedef PVArrayData StructureArrayData; /** * Data class for a structureArray @@ -1438,10 +1216,6 @@ public: typedef PVStructurePtr value_type; typedef PVStructurePtr* pointer; typedef const PVStructurePtr* const_pointer; - typedef PVArrayData ArrayDataType; - typedef std::vector vector; - typedef const std::vector const_vector; - typedef std::tr1::shared_ptr shared_vector; typedef PVStructureArray &reference; typedef const PVStructureArray& const_reference; @@ -1453,6 +1227,11 @@ public: */ virtual ~PVValueArray() {} + virtual ArrayConstPtr getArray() const + { + return std::tr1::static_pointer_cast(structureArray); + } + virtual size_t getLength() const {return value.size();} virtual size_t getCapacity() const {return value.capacity();} @@ -1519,10 +1298,6 @@ private: }; -/** - * This is provided by code that calls get. - */ -typedef PVArrayData UnionArrayData; /** * Data class for a unionArray @@ -1536,10 +1311,6 @@ public: typedef PVUnionPtr value_type; typedef PVUnionPtr* pointer; typedef const PVUnionPtr* const_pointer; - typedef PVArrayData ArrayDataType; - typedef std::vector vector; - typedef const std::vector const_vector; - typedef std::tr1::shared_ptr shared_vector; typedef PVUnionArray &reference; typedef const PVUnionArray& const_reference; @@ -1551,6 +1322,11 @@ public: */ virtual ~PVValueArray() {} + virtual ArrayConstPtr getArray() const + { + return std::tr1::static_pointer_cast(unionArray); + } + virtual size_t getLength() const {return value.size();} virtual size_t getCapacity() const {return value.capacity();} @@ -1620,51 +1396,39 @@ private: /** * Definitions for the various scalarArray types. */ -typedef PVArrayData BooleanArrayData; typedef PVValueArray PVBooleanArray; typedef std::tr1::shared_ptr PVBooleanArrayPtr; -typedef PVArrayData ByteArrayData; typedef PVValueArray PVByteArray; typedef std::tr1::shared_ptr PVByteArrayPtr; -typedef PVArrayData ShortArrayData; typedef PVValueArray PVShortArray; typedef std::tr1::shared_ptr PVShortArrayPtr; -typedef PVArrayData IntArrayData; typedef PVValueArray PVIntArray; typedef std::tr1::shared_ptr PVIntArrayPtr; -typedef PVArrayData LongArrayData; typedef PVValueArray PVLongArray; typedef std::tr1::shared_ptr PVLongArrayPtr; -typedef PVArrayData UByteArrayData; typedef PVValueArray PVUByteArray; typedef std::tr1::shared_ptr PVUByteArrayPtr; -typedef PVArrayData UShortArrayData; typedef PVValueArray PVUShortArray; typedef std::tr1::shared_ptr PVUShortArrayPtr; -typedef PVArrayData UIntArrayData; typedef PVValueArray PVUIntArray; typedef std::tr1::shared_ptr PVUIntArrayPtr; -typedef PVArrayData ULongArrayData; typedef PVValueArray PVULongArray; typedef std::tr1::shared_ptr PVULongArrayPtr; -typedef PVArrayData FloatArrayData; typedef PVValueArray PVFloatArray; typedef std::tr1::shared_ptr PVFloatArrayPtr; -typedef PVArrayData DoubleArrayData; typedef PVValueArray PVDoubleArray; typedef std::tr1::shared_ptr PVDoubleArrayPtr; -typedef PVArrayData StringArrayData; typedef PVValueArray PVStringArray; typedef std::tr1::shared_ptr PVStringArrayPtr; @@ -1673,7 +1437,12 @@ typedef std::tr1::shared_ptr PVStringArrayPtr; */ class epicsShareClass PVDataCreate { public: + /** + * get the singleton + * @return The PVDataCreate implementation + */ static PVDataCreatePtr getPVDataCreate(); + /** * Create a PVField using given Field introspection data. * @param field The introspection data to be used to create PVField. @@ -1706,6 +1475,56 @@ public: * @return The PVScalar implementation. */ PVScalarPtr createPVScalar(PVScalarPtr const & scalarToClone); + /** + * template version + * @param PVT must ve a valid pvType + * @return The PVScalar implementation. + */ + template + std::tr1::shared_ptr createPVScalar() + { + return std::tr1::static_pointer_cast(createPVScalar(PVT::typeCode)); + } + + /** + * Create implementation for PVStructure. + * @param structure The introspection interface. + * @return The PVStructure implementation + */ + PVStructurePtr createPVStructure(StructureConstPtr const & structure); + /** + * Create implementation for PVStructure. + * @param fieldNames The field names. + * @param pvFields Array of PVFields + * @return The PVStructure implementation + */ + PVStructurePtr createPVStructure( + StringArray const & fieldNames,PVFieldPtrArray const & pvFields); + /** + * Create implementation for PVStructure. + * @param structToClone A structure. Each subfield and any auxInfo is cloned and added to the newly created structure. + * @return The PVStructure implementation. + */ + PVStructurePtr createPVStructure(PVStructurePtr const & structToClone); + + /** + * Create implementation for PVUnion. + * @param union The introspection interface. + * @return The PVUnion implementation + */ + PVUnionPtr createPVUnion(UnionConstPtr const & punion); + /** + * Create implementation for PVUnion. + * @param unionToClone A union. Each subfield is cloned and added to the newly created union. + * @return The PVUnion implementation. + */ + PVUnionPtr createPVUnion(PVUnionPtr const & unionToClone); + /** + * Create variant union implementation. + * @return The variant PVUnion implementation. + */ + PVUnionPtr createPVVariantUnion(); + /** * Create an implementation of an array field reusing the Array introspection interface. * @param array The introspection interface. @@ -1726,6 +1545,17 @@ public: * @return The PVScalarArray implementation. */ PVScalarArrayPtr createPVScalarArray(PVScalarArrayPtr const & scalarArrayToClone); + /** + * template version + * @param PVT must ve a valid pvType + * @return The PVScalarArray implementation. + */ + template + std::tr1::shared_ptr createPVScalarArray() + { + return std::tr1::static_pointer_cast(createPVScalarArray(PVAT::typeCode)); + } + /** * Create an implementation of an array with structure elements. * @param structureArray The introspection interface. @@ -1734,25 +1564,16 @@ public: */ PVStructureArrayPtr createPVStructureArray(StructureArrayConstPtr const & structureArray); /** - * Create implementation for PVStructure. - * @param structure The introspection interface. - * @return The PVStructure implementation + * Create an implementation of an array with structure elements. + * @param structure The introspection interface that is used to create StructureArrayConstPtr. + * All elements share the same introspection interface. + * @return The PVStructureArray implementation. */ - PVStructurePtr createPVStructure(StructureConstPtr const & structure); - /** - * Create implementation for PVStructure. - * @param fieldNames The field names. - * @param pvFields Array of PVFields - * @return The PVStructure implementation - */ - PVStructurePtr createPVStructure( - StringArray const & fieldNames,PVFieldPtrArray const & pvFields); - /** - * Create implementation for PVStructure. - * @param structToClone A structure. Each subfield and any auxInfo is cloned and added to the newly created structure. - * @return The PVStructure implementation. - */ - PVStructurePtr createPVStructure(PVStructurePtr const & structToClone); + PVStructureArrayPtr createPVStructureArray(StructureConstPtr const & structure) + { + return createPVStructureArray(fieldCreate->createStructureArray(structure)); + } + /** * Create an implementation of an array with union elements. * @param unionArray The introspection interface. @@ -1761,51 +1582,21 @@ public: */ PVUnionArrayPtr createPVUnionArray(UnionArrayConstPtr const & unionArray); /** - * Create implementation for PVUnion. - * @param union The introspection interface. - * @return The PVUnion implementation + * Create an implementation of an array with union elements. + * @param punion The introspection interface tht is used to create UnionArrayConstPtr. + * All elements share the same introspection interface. + * @return The PVUnionArray implementation. */ - PVUnionPtr createPVUnion(UnionConstPtr const & punion); - /** - * Create implementation for PVUnion. - * @param unionToClone A union. Each subfield is cloned and added to the newly created union. - * @return The PVUnion implementation. - */ - PVUnionPtr createPVUnion(PVUnionPtr const & unionToClone); - /** - * Create variant union implementation. - * @return The variant PVUnion implementation. - */ - PVUnionPtr createPVVariantUnion(); + PVUnionArrayPtr createPVUnionArray(UnionConstPtr const & punion) + { + return createPVUnionArray(fieldCreate->createUnionArray(punion)); + } /** * Create variant union array implementation. * @return The variant PVUnionArray implementation. */ PVUnionArrayPtr createPVVariantUnionArray(); - - template - std::tr1::shared_ptr createPVScalar() - { - return std::tr1::static_pointer_cast(createPVScalar(PVT::typeCode)); - } - - template - std::tr1::shared_ptr createPVScalarArray() - { - return std::tr1::static_pointer_cast(createPVScalarArray(PVAT::typeCode)); - } - - PVStructureArrayPtr createPVStructureArray(StructureConstPtr const & structure) - { - return createPVStructureArray(fieldCreate->createStructureArray(structure)); - } - - PVUnionArrayPtr createPVUnionArray(UnionConstPtr const & punion) - { - return createPVUnionArray(fieldCreate->createUnionArray(punion)); - } - private: PVDataCreate(); FieldCreatePtr fieldCreate; @@ -1818,7 +1609,5 @@ private: epicsShareExtern PVDataCreatePtr getPVDataCreate(); -#undef USAGE_ERROR - }} #endif /* PVDATA_H */ diff --git a/src/pv/pvIntrospect.h b/src/pv/pvIntrospect.h index f85d57d..3bb839f 100644 --- a/src/pv/pvIntrospect.h +++ b/src/pv/pvIntrospect.h @@ -24,6 +24,7 @@ namespace epics { namespace pvData { class Field; class Scalar; +class Array; class ScalarArray; class Structure; class StructureArray; @@ -42,6 +43,10 @@ typedef std::vector FieldConstPtrArray; * typedef for a shared pointer to an immutable Scalar. */ typedef std::tr1::shared_ptr ScalarConstPtr; +/** + * typedef for a shared pointer to an immutable Array. + */ +typedef std::tr1::shared_ptr ArrayConstPtr; /** * typedef for a shared pointer to an immutable ScalarArray. */ @@ -314,10 +319,39 @@ private: friend class FieldCreate; }; +/** + * This class implements introspection object for Array. + */ +class epicsShareClass Array : public Field{ +public: + POINTER_DEFINITIONS(Array); + /** + * Destructor. + */ + virtual ~Array(); + typedef Array& reference; + typedef const Array& const_reference; + +/* fixed-size array support + // 0 not valid value, means undefined + std::size_t getMaximumCapacity() const; + + // 0 not valid value, means undefined + std::size_t getFixedLength() const; +*/ +protected: + /** + * Constructor + * @param fieldName The field type. + */ + Array(Type type); + +}; + /** * This class implements introspection object for field. */ -class epicsShareClass ScalarArray : public Field{ +class epicsShareClass ScalarArray : public Array{ public: POINTER_DEFINITIONS(ScalarArray); typedef ScalarArray& reference; @@ -332,7 +366,7 @@ public: * Get the scalarType for the elements. * @return the scalarType */ - ScalarType getElementType() const {return elementType;} + ScalarType getElementType() const {return elementType;} /** * Convert the scalarType to a string and add it to builder. * @param builder The string builder. @@ -365,7 +399,7 @@ private: /** * This class implements introspection object for a structureArray */ -class epicsShareClass StructureArray : public Field{ +class epicsShareClass StructureArray : public Array{ public: POINTER_DEFINITIONS(StructureArray); typedef StructureArray& reference; @@ -375,7 +409,7 @@ public: * Get the introspection interface for the array elements. * @return The introspection interface. */ - StructureConstPtr getStructure() const {return pstructure;} + StructureConstPtr getStructure() const {return pstructure;} /** * Convert the scalarType to a string and add it to builder. @@ -407,7 +441,7 @@ private: /** * This class implements introspection object for a unionArray */ -class epicsShareClass UnionArray : public Field{ +class epicsShareClass UnionArray : public Array{ public: POINTER_DEFINITIONS(UnionArray); typedef UnionArray& reference; @@ -417,7 +451,7 @@ public: * Get the introspection interface for the array elements. * @return The introspection interface. */ - UnionConstPtr getUnion() const {return punion;} + UnionConstPtr getUnion() const {return punion;} /** * Convert the scalarType to a string and add it to builder. @@ -500,8 +534,6 @@ public: * @return The array of fieldNames. */ StringArray const & getFieldNames() const {return fieldNames;} - void renameField(std::size_t fieldIndex,String const & newName) - {fieldNames[fieldIndex] = newName;} /** * Get the name of the field with the specified index; * @param fieldIndex The index of the desired field. @@ -595,8 +627,6 @@ public: * @return The array of fieldNames. */ StringArray const & getFieldNames() const {return fieldNames;} - void renameField(std::size_t fieldIndex,String const & newName) - {fieldNames[fieldIndex] = newName;} /** * Get the name of the field with the specified index; * @param fieldIndex The index of the desired field. @@ -637,9 +667,6 @@ private: friend class Structure; }; -/** - * This is a singlton class for creating introspection interfaces. - */ class FieldCreate; typedef std::tr1::shared_ptr FieldCreatePtr; @@ -784,6 +811,9 @@ private: }; +/** + * This is a singleton class for creating introspection interfaces. + */ class epicsShareClass FieldCreate { public: static FieldCreatePtr getFieldCreate(); @@ -812,6 +842,11 @@ public: * @return An {@code Array} Interface for the newly created object. */ StructureArrayConstPtr createStructureArray(StructureConstPtr const & structure) const; + /** + * Create a {@code Structure} field. + * @return a {@code Structure} interface for the newly created object. + */ + StructureConstPtr createStructure () const; /** * Create a {@code Structure} field. * @param fieldNames The array of {@code fieldNames} for the structure. diff --git a/src/pv/pvSubArrayCopy.h b/src/pv/pvSubArrayCopy.h index 79110b9..04de8b6 100644 --- a/src/pv/pvSubArrayCopy.h +++ b/src/pv/pvSubArrayCopy.h @@ -17,68 +17,104 @@ namespace epics { namespace pvData { -/** @brief Copy a subarray from one PVValueArray to another. - * @warning The two PVValueArrays must both the same type - * @param from The source - * @param fromOffset The offset in the source - * @param to The destination - * @param toOffset The offset in the destination - * @param len The total number of elements to copy +/** @brief Copy a subarray from one scalar array to another. + * @warning The two scalar arrays must both be PVValueArrays of the same type. + * @param pvFrom The source array. + * @param fromOffset The offset in the source. + * @param fromStride The interval between elements in pvFrom. + * @param pvTo The destination array. + * @param toOffset The offset in the destination. + * @param toStride The interval between elements in pvTo. + * @param count The total number of elements to copy from pvFrom to pvTo. */ template -void copy( +epicsShareExtern void copy( PVValueArray & pvFrom, size_t fromOffset, + size_t fromStride, PVValueArray & pvTo, size_t toOffset, - size_t len); + size_t toStride, + size_t count); /** @brief Copy a subarray from one scalar array to another. - * @warning The two scalar arrays must both be PVValueArrays of the same type - * @param from The source - * @param fromOffset The offset in the source - * @param to The destination - * @param toOffset The offset in the destination - * @param len The total number of elements to copy + * @warning The two scalar arrays must both be PVValueArrays of the same type. + * @param pvFrom The source array. + * @param fromOffset The offset in the source. + * @param fromStride The interval between elements in pvFrom. + * @param pvTo The destination array. + * @param toOffset The offset in the destination. + * @param toStride The interval between elements in pvTo. + * @param count The total number of elements to copy from pvFrom to pvTo. */ epicsShareExtern void copy( - PVScalarArray & from, + PVScalarArray & pvFrom, size_t fromOffset, - PVScalarArray & to, + size_t fromStride, + PVScalarArray & pvTo, size_t toOffset, - size_t len); + size_t toStride, + size_t count); /** @brief Copy a subarray from one structure array to another. * @warning The two structure arrays must have the same * structure introspection interface. - * @param from The source - * @param fromOffset The offset in the source - * @param to The destination - * @param toOffset The offset in the destination - * @param len The total number of elements to copy + * @param pvFrom The source array. + * @param fromOffset The offset in the source. + * @param fromStride The interval between elements in pvFrom. + * @param pvTo The destination array. + * @param toOffset The offset in the destination. + * @param toStride The interval between elements in pvTo. + * @param count The total number of elements to copy from pvFrom to pvTo. */ epicsShareExtern void copy( - PVStructureArray & from, + PVStructureArray & pvFrom, size_t fromOffset, - PVStructureArray & to, + size_t fromStride, + PVStructureArray & pvToo, size_t toOffset, - size_t len); + size_t toStride, + size_t count); /** @brief Copy a subarray from one array to another. * @warning The two arrays must have the same * introspection interface. - * @param from The source - * @param fromOffset The offset in the source - * @param to The destination - * @param toOffset The offset in the destination - * @param len The total number of elements to copy + * @param pvFrom The source array. + * @param fromOffset The offset in the source. + * @param fromStride The interval between elements in pvFrom. + * @param pvTo The destination array. + * @param toOffset The offset in the destination. + * @param toStride The interval between elements in pvTo. + * @param count The total number of elements to copy from pvFrom to pvTo. */ epicsShareExtern void copy( - PVArray & from, + PVArray & pvFrom, size_t fromOffset, - PVArray & to, + size_t fromStride, + PVArray & pvToo, size_t toOffset, - size_t len); + size_t toStride, + size_t count); + +/** @brief Copy a subarray from one array to another. + * @warning The two arrays must have the same + * introspection interface. + * @param pvFrom The source array. + * @param fromOffset The offset in the source. + * @param fromStride The interval between elements in pvFrom. + * @param pvTo The destination array. + * @param toOffset The offset in the destination. + * @param toStride The interval between elements in pvTo. + * @param count The total number of elements to copy from pvFrom to pvTo. + */ +epicsShareExtern void copy( + PVArray::shared_pointer const & pvFrom, + size_t fromOffset, + size_t fromStride, + PVArray::shared_pointer & pvToo, + size_t toOffset, + size_t toStride, + size_t count); }} diff --git a/src/pv/pvType.h b/src/pv/pvType.h index 40c3b04..84bc17d 100644 --- a/src/pv/pvType.h +++ b/src/pv/pvType.h @@ -98,335 +98,6 @@ typedef uint64_t uint64; */ typedef std::string String; -/** - * A boolean array. - */ -typedef std::vector BooleanArray; -typedef std::tr1::shared_ptr BooleanArrayPtr; -/* get is same is ubyte*/ -typedef std::vector::iterator BooleanArray_iterator; -typedef std::vector::const_iterator BooleanArray_const_iterator; - -/** - * A byte array. - */ -typedef std::vector ByteArray; -typedef std::tr1::shared_ptr ByteArrayPtr; -inline int8 * get(ByteArray &value) -{ - return &value[0]; -} -inline int8 const * get(ByteArray const &value) -{ - return static_cast(&value[0]); -} -inline int8 * get(ByteArrayPtr &value) -{ - return get(*value.get()); -} -inline int8 const * get(ByteArrayPtr const &value) -{ - return get(*value.get()); -} -inline ByteArray & getVector(ByteArrayPtr &value) -{ - return *value.get(); -} -inline ByteArray const & getVector(ByteArrayPtr const &value) -{ - return *value.get(); -} -typedef std::vector::iterator ByteArray_iterator; -typedef std::vector::const_iterator ByteArray_const_iterator; - -/** - * A short array. - */ -typedef std::vector ShortArray; -typedef std::tr1::shared_ptr ShortArrayPtr; -inline int16 * get(ShortArray &value) -{ - return &value[0]; -} -inline int16 const * get(ShortArray const &value) -{ - return static_cast(&value[0]); -} -inline int16 * get(ShortArrayPtr &value) -{ - return get(*value.get()); -} -inline int16 const * get(ShortArrayPtr const &value) -{ - return get(*value.get()); -} -inline ShortArray & getVector(ShortArrayPtr &value) -{ - return *value.get(); -} -inline ShortArray const & getVector(ShortArrayPtr const &value) -{ - return *value.get(); -} -typedef std::vector::iterator ShortArray_iterator; -typedef std::vector::const_iterator ShortArray_const_iterator; - -/** - * A int array. - */ -typedef std::vector IntArray; -typedef std::tr1::shared_ptr IntArrayPtr; -inline int32 * get(IntArray &value) -{ - return &value[0]; -} -inline int32 const * get(IntArray const &value) -{ - return static_cast(&value[0]); -} -inline int32 * get(IntArrayPtr &value) -{ - return get(*value.get()); -} -inline int32 const * get(IntArrayPtr const &value) -{ - return get(*value.get()); -} -inline IntArray & getVector(IntArrayPtr &value) -{ - return *value.get(); -} -inline IntArray const & getVector(IntArrayPtr const &value) -{ - return *value.get(); -} -typedef std::vector::iterator IntArray_iterator; -typedef std::vector::const_iterator IntArray_const_iterator; - -/** - * A long array. - */ -typedef std::vector LongArray; -typedef std::tr1::shared_ptr LongArrayPtr; -inline int64 * get(LongArray &value) -{ - return &value[0]; -} -inline int64 const * get(LongArray const &value) -{ - return static_cast(&value[0]); -} -inline int64 * get(LongArrayPtr &value) -{ - return get(*value.get()); -} -inline int64 const * get(LongArrayPtr const &value) -{ - return get(*value.get()); -} -inline LongArray & getVector(LongArrayPtr &value) -{ - return *value.get(); -} -inline LongArray const & getVector(LongArrayPtr const &value) -{ - return *value.get(); -} -typedef std::vector::iterator LongArray_iterator; -typedef std::vector::const_iterator LongArray_const_iterator; - -/** - * An unsigned byte array. - */ -typedef std::vector UByteArray; -typedef std::tr1::shared_ptr UByteArrayPtr; -inline uint8 * get(UByteArray &value) -{ - return &value[0]; -} -inline uint8 const * get(UByteArray const &value) -{ - return static_cast(&value[0]); -} -inline uint8 * get(UByteArrayPtr &value) -{ - return get(*value.get()); -} -inline uint8 const * get(UByteArrayPtr const &value) -{ - return get(*value.get()); -} -inline UByteArray & getVector(UByteArrayPtr &value) -{ - return *value.get(); -} -inline UByteArray const & getVector(UByteArrayPtr const &value) -{ - return *value.get(); -} -typedef std::vector::iterator UByteArray_iterator; -typedef std::vector::const_iterator UByteArray_const_iterator; - -/** - * An unsigned short array. - */ -typedef std::vector UShortArray; -typedef std::tr1::shared_ptr UShortArrayPtr; -inline uint16 * get(UShortArray &value) -{ - return &value[0]; -} -inline uint16 const * get(UShortArray const &value) -{ - return static_cast(&value[0]); -} -inline uint16 * get(UShortArrayPtr &value) -{ - return get(*value.get()); -} -inline uint16 const * get(UShortArrayPtr const &value) -{ - return get(*value.get()); -} -inline UShortArray & getVector(UShortArrayPtr &value) -{ - return *value.get(); -} -inline UShortArray const & getVector(UShortArrayPtr const &value) -{ - return *value.get(); -} -typedef std::vector::iterator UShortArray_iterator; -typedef std::vector::const_iterator UShortArray_const_iterator; - -/** - * An unsigned int array. - */ -typedef std::vector UIntArray; -typedef std::tr1::shared_ptr UIntArrayPtr; -inline uint32 * get(UIntArray &value) -{ - return &value[0]; -} -inline uint32 const * get(UIntArray const &value) -{ - return static_cast(&value[0]); -} -inline uint32 * get(UIntArrayPtr &value) -{ - return get(*value.get()); -} -inline uint32 const * get(UIntArrayPtr const &value) -{ - return get(*value.get()); -} -inline UIntArray & getVector(UIntArrayPtr &value) -{ - return *value.get(); -} -inline UIntArray const & getVector(UIntArrayPtr const &value) -{ - return *value.get(); -} -typedef std::vector::iterator UIntArray_iterator; -typedef std::vector::const_iterator UIntArray_const_iterator; - -/** - * An unsigned long array. - */ -typedef std::vector ULongArray; -typedef std::tr1::shared_ptr ULongArrayPtr; -inline uint64 * get(ULongArray &value) -{ - return &value[0]; -} -inline uint64 const * get(ULongArray const &value) -{ - return static_cast(&value[0]); -} -inline uint64 * get(ULongArrayPtr &value) -{ - return get(*value.get()); -} -inline uint64 const * get(ULongArrayPtr const &value) -{ - return get(*value.get()); -} -inline ULongArray & getVector(ULongArrayPtr &value) -{ - return *value.get(); -} -inline ULongArray const & getVector(ULongArrayPtr const &value) -{ - return *value.get(); -} -typedef std::vector::iterator ULongArray_iterator; -typedef std::vector::const_iterator ULongArray_const_iterator; - -/** - * A float array. - */ -typedef std::vector FloatArray; -typedef std::tr1::shared_ptr FloatArrayPtr; -inline float * get(FloatArray &value) -{ - return &value[0]; -} -inline float const * get(FloatArray const &value) -{ - return static_cast(&value[0]); -} -inline float * get(FloatArrayPtr &value) -{ - return get(*value.get()); -} -inline float const * get(FloatArrayPtr const &value) -{ - return get(*value.get()); -} -inline FloatArray & getVector(FloatArrayPtr &value) -{ - return *value.get(); -} -inline FloatArray const & getVector(FloatArrayPtr const &value) -{ - return *value.get(); -} -typedef std::vector::iterator FloatArray_iterator; -typedef std::vector::const_iterator FloatArray_const_iterator; - -/** - * A double array. - */ -typedef std::vector DoubleArray; -typedef std::tr1::shared_ptr DoubleArrayPtr; -inline double * get(DoubleArray &value) -{ - return &value[0]; -} -inline double const * get(DoubleArray const &value) -{ - return static_cast(&value[0]); -} -inline double * get(DoubleArrayPtr &value) -{ - return get(*value.get()); -} -inline double const * get(DoubleArrayPtr const &value) -{ - return get(*value.get()); -} -inline DoubleArray & getVector(DoubleArrayPtr &value) -{ - return *value.get(); -} -inline DoubleArray const & getVector(DoubleArrayPtr const &value) -{ - return *value.get(); -} -typedef std::vector::iterator DoubleArray_iterator; -typedef std::vector::const_iterator DoubleArray_const_iterator; - /** * A string array. */ diff --git a/src/pv/standardField.h b/src/pv/standardField.h index 2652240..3f8cc2d 100644 --- a/src/pv/standardField.h +++ b/src/pv/standardField.h @@ -20,6 +20,10 @@ namespace epics { namespace pvData { + +class StandardField; +typedef std::tr1::shared_ptr StandardFieldPtr; + /** * Standard Fields is a class or creating or sharing Field objects for standard fields. * For each type of standard object two methods are defined:s @@ -57,39 +61,158 @@ namespace epics { namespace pvData { StandardField *standardField = getStandardField(); * } */ - -class StandardField; -typedef std::tr1::shared_ptr StandardFieldPtr; - class epicsShareClass StandardField { public: + /** + * getStandardField returns the singleton. + * @return Shared pointer to StandardField. + */ static StandardFieldPtr getStandardField(); ~StandardField(); + /** Create a structure that has a scalar value field. + * @param type The type. + * @param properties A comma separated list of properties. + * This is some combination of "alarm,timeStamp,display,control,valueAlarm". + * @return The const shared pointer to the structure. + */ StructureConstPtr scalar(ScalarType type,String const & properties); + /** Create a structure that has a union value field. + * @param punion The interface for value field. + * @param properties A comma separated list of properties. + * This is some combination of "alarm,timeStamp,display,control,valueAlarm". + * @return The const shared pointer to the structure. + */ + StructureConstPtr regUnion( + UnionConstPtr const & punion, + String const & properties); + /** Create a structure that has a varient union value field. + * @param properties A comma separated list of properties. + * This is some combination of "alarm,timeStamp,display,control,valueAlarm". + * @return The const shared pointer to the structure. + */ + StructureConstPtr variantUnion(String const & properties); + /** Create a structure that has a scalarArray value field. + * @param type The type. + * @param properties A comma separated list of properties. + * This is some combination of "alarm,timeStamp,display,control,valueAlarm". + * @return The const shared pointer to the structure. + */ StructureConstPtr scalarArray(ScalarType elementType, String const & properties); - StructureConstPtr structureArray(StructureConstPtr const & structure,String const & properties); + /** Create a structure that has a structureArray value field. + * @param type The type. + * @param properties A comma separated list of properties. + * This is some combination of "alarm,timeStamp,display,control,valueAlarm". + * @return The const shared pointer to the structure. + */ + StructureConstPtr structureArray( + StructureConstPtr const & structure, + String const & properties); + /** Create a structure that has a unionArray value field. + * @param type The type. + * @param properties A comma separated list of properties. + * This is some combination of "alarm,timeStamp,display,control". + * @return The const shared pointer to the structure. + */ + StructureConstPtr unionArray( + UnionConstPtr const & punion, + String const & properties); + /** Create a structure that has an enumerated structure value field. + * The id for the structure is "enum-t". + * @return The const shared pointer to the structure. + */ StructureConstPtr enumerated(); + /** Create a structure that has an enumerated structure value field + * The id for the structure is "uri:ev4:nt/2012/pwd:NTEnum". + * @param properties A comma separated list of properties. + * This is some combination of "alarm,timeStamp,display,control,valueAlarm". + * @return The const shared pointer to the structure. + */ StructureConstPtr enumerated(String const & properties); + /** + * create an alarm structure + * @return The const shared pointer to the structure. + */ StructureConstPtr alarm(); + /** + * create a timeStamp structure + * @return The const shared pointer to the structure. + */ StructureConstPtr timeStamp(); + /** + * create a display structure + * @return The const shared pointer to the structure. + */ StructureConstPtr display(); + /** + * create a control structure + * @return The const shared pointer to the structure. + */ StructureConstPtr control(); + /** + * create a boolean alarm structure + * @return The const shared pointer to the structure. + */ StructureConstPtr booleanAlarm(); + /** + * create a byte alarm structure + * @return The const shared pointer to the structure. + */ StructureConstPtr byteAlarm(); + /** + * create a unsigned byte alarm structure + * @return The const shared pointer to the structure. + */ StructureConstPtr ubyteAlarm(); + /** + * create a short alarm structure + * @return The const shared pointer to the structure. + */ StructureConstPtr shortAlarm(); + /** + * create a unsigned short alarm structure + * @return The const shared pointer to the structure. + */ StructureConstPtr ushortAlarm(); + /** + * create an int alarm structure + * @return The const shared pointer to the structure. + */ StructureConstPtr intAlarm(); + /** + * create a unsigned int alarm structure + * @return The const shared pointer to the structure. + */ StructureConstPtr uintAlarm(); + /** + * create a long alarm structure + * @return The const shared pointer to the structure. + */ StructureConstPtr longAlarm(); + /** + * create a unsigned long alarm structure + * @return The const shared pointer to the structure. + */ StructureConstPtr ulongAlarm(); + /** + * create a float alarm structure + * @return The const shared pointer to the structure. + */ StructureConstPtr floatAlarm(); + /** + * create a double alarm structure + * @return The const shared pointer to the structure. + */ StructureConstPtr doubleAlarm(); + /** + * create an enumerated alarm structure + * @return The const shared pointer to the structure. + */ StructureConstPtr enumeratedAlarm(); private: StandardField(); void init(); - StructureConstPtr createProperties(String id,FieldConstPtr field,String properties); + StructureConstPtr createProperties( + String id,FieldConstPtr field,String properties); FieldCreatePtr fieldCreate; String notImplemented; String valueFieldName; diff --git a/src/pv/standardPVField.h b/src/pv/standardPVField.h index c3c354b..31941f2 100644 --- a/src/pv/standardPVField.h +++ b/src/pv/standardPVField.h @@ -20,6 +20,10 @@ #include namespace epics { namespace pvData { + +class StandardPVField; +typedef std::tr1::shared_ptr StandardPVFieldPtr; + /** * StandardPVField is a class or creating standard data fields. * Like class StandardField it has two forms of the methods which create a fields: @@ -31,18 +35,60 @@ namespace epics { namespace pvData { StandardPVField *standardPVField = getStandardPVField(); * } */ - -class StandardPVField; -typedef std::tr1::shared_ptr StandardPVFieldPtr; - class epicsShareClass StandardPVField : private NoDefaultMethods { public: + /** + * getStandardPVField returns the singleton. + * @return Shared pointer to StandardPVField. + */ static StandardPVFieldPtr getStandardPVField(); ~StandardPVField(); + /** + * Create a structure that has a scalar value field. + * @param type The type. + * @param properties A comma separated list of properties. + * This is some combination of "alarm,timeStamp,display,control,valueAlarm". + * @return The const shared pointer to the structure. + */ PVStructurePtr scalar(ScalarType type,String const & properties); + /** + * Create a structure that has a scalar array value field. + * @param type The type. + * @param properties A comma separated list of properties. + * This is some combination of "alarm,timeStamp,display,control,valueAlarm". + * @return The const shared pointer to the structure. + */ PVStructurePtr scalarArray(ScalarType elementType, String const & properties); + /** + * Create a structure that has a structure array value field. + * @param type The type. + * @param properties A comma separated list of properties. + * This is some combination of "alarm,timeStamp,display,control,valueAlarm". + * @return The const shared pointer to the structure. + */ PVStructurePtr structureArray(StructureConstPtr const &structure,String const & properties); + /** + * Create a structure that has a union array value field. + * @param type The type. + * @param properties A comma separated list of properties. + * This is some combination of "alarm,timeStamp,display,control,valueAlarm". + * @return The const shared pointer to the structure. + */ + PVStructurePtr unionArray(UnionConstPtr const &punion,String const & properties); + /** + * Create a structure that has an enumerated structure value field. + * The id for the structure is "enum_t". + * @param choices This is a StringArray of choices. + * @return The const shared pointer to the structure. + */ PVStructurePtr enumerated(StringArray const &choices); + /** + * Create a structure that has an enumerated structure value field. + * The id for the structure is "uri:ev4:nt/2012/pwd:NTEnum". + * @param choices This is a StringArray of choices. + * @param properties A comma separated list of properties. + * @return The const shared pointer to the structure. + */ PVStructurePtr enumerated(StringArray const &choices, String const & properties); private: StandardPVField(); diff --git a/testApp/Makefile b/testApp/Makefile index a2771b3..6d49e69 100644 --- a/testApp/Makefile +++ b/testApp/Makefile @@ -3,5 +3,6 @@ include $(TOP)/configure/CONFIG DIRS += misc DIRS += pv DIRS += property +DIRS += copy include $(TOP)/configure/RULES_DIRS diff --git a/testApp/copy/Makefile b/testApp/copy/Makefile new file mode 100644 index 0000000..dab7623 --- /dev/null +++ b/testApp/copy/Makefile @@ -0,0 +1,22 @@ +TOP=../.. + +include $(TOP)/configure/CONFIG + +PROD_HOST += testCreateRequest +testCreateRequest_SRCS = testCreateRequest.cpp +testCreateRequest_LIBS = pvData Com +TESTS += testCreateRequest + +PROD_HOST += testPVCopy +testPVCopy_SRCS += testPVCopy.cpp +testPVCopy_LIBS += pvData Com +TESTS += testPVCopy + +TESTSCRIPTS_HOST += $(TESTS:%=%.t) + + + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/testApp/copy/testCreateRequest.cpp b/testApp/copy/testCreateRequest.cpp new file mode 100644 index 0000000..98fb4e2 --- /dev/null +++ b/testApp/copy/testCreateRequest.cpp @@ -0,0 +1,327 @@ +/* testCreateRequest.cpp */ +/* Author: Matej Sekoranja Date: 2010.12.27 */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +using namespace epics::pvData; +using std::cout; +using std::endl; + +static bool debug = false; + +void testCreateRequest() { + printf("testCreateRequest... \n"); + CreateRequest::shared_pointer createRequest = CreateRequest::create(); + + String out; + String request = ""; + if(debug) { cout << "request " << request <createRequest(request); + if(debug) { cout<< createRequest->getMessage() << endl;} + testOk1(pvRequest!=NULL); + if(debug) { cout << pvRequest->dumpValue(cout) << endl;} + testOk1(pvRequest->getStructure()->getNumberFields()==0); + testPass("request %s",request.c_str()); + + + request = "record[a=b,x=y]field(a) putField(a),getField(a)"; + pvRequest = createRequest->createRequest(request); + if(pvRequest==NULL) { + cout << createRequest->getMessage() << endl; + } + if(debug) { cout << "request " << request <dumpValue(cout) << endl;} + PVStringPtr pvString = pvRequest->getSubField("record.a"); + String sval = pvString->get(); + testOk(sval.compare("b")==0,"record.a = b"); + pvString = pvRequest->getSubField("record.x"); + sval = pvString->get(); + testOk(sval.compare("y")==0,"record.x = y"); + testOk1(pvRequest->getSubField("field.a")!=NULL); + testOk1(pvRequest->getSubField("putField.a")!=NULL); + testOk1(pvRequest->getSubField("getField.a")!=NULL); + testPass("request %s",request.c_str()); + + request = "field(a.b[x=y])"; + pvRequest = createRequest->createRequest(request); + if(pvRequest==NULL) { + cout << createRequest->getMessage() << endl; + } + if(debug) { cout << "request " << request <dumpValue(cout) << endl;} + pvString = pvRequest->getSubField("field.a.b._options.x"); + sval = pvString->get(); + testOk(sval.compare("y")==0,"field.a.b._options.x = y"); + testPass("request %s",request.c_str()); + + request = "field(a.b{c.d})"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << "request " << request <getMessage() << endl; + } + testOk1(pvRequest!=NULL); + testOk1(pvRequest->getSubField("field.a.b.c.d")!=NULL); + if(debug) { cout << pvRequest->dumpValue(cout) << endl;} + testPass("request %s",request.c_str()); + + request = "field(a.b[x=y]{c.d})"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << "request " << request <getMessage() << endl; + } + testOk1(pvRequest!=NULL); + pvString = pvRequest->getSubField("field.a.b._options.x"); + sval = pvString->get(); + testOk(sval.compare("y")==0,"field.a.b._options.x = y"); + testOk1(pvRequest->getSubField("field.a.b.c.d")!=NULL); + if(debug) { cout << pvRequest->dumpValue(cout) << endl;} + testPass("request %s",request.c_str()); + + request = "field(a.b[x=y]{c.d[x=y]})"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << "request " << request <getMessage() << endl; + } + testOk1(pvRequest!=NULL); + pvString = pvRequest->getSubField("field.a.b._options.x"); + sval = pvString->get(); + testOk(sval.compare("y")==0,"field.a.b._options.x = y"); + pvString = pvRequest->getSubField("field.a.b.c.d._options.x"); + sval = pvString->get(); + testOk(sval.compare("y")==0,"field.a.b.c.d._options.x = y"); + if(debug) { cout << pvRequest->dumpValue(cout) << endl;} + testPass("request %s",request.c_str()); + + request = "record[a=b,c=d] field(a.a[a=b]{a.a[a=b]},b.a[a=b]{a,b})"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << "request " << request <getMessage() << endl; + } + testOk1(pvRequest!=NULL); + pvString = pvRequest->getSubField("field.a.a._options.a"); + sval = pvString->get(); + testOk(sval.compare("b")==0,"field.a.a._options.a = b"); + pvString = pvRequest->getSubField("field.a.a.a.a._options.a"); + sval = pvString->get(); + testOk(sval.compare("b")==0,"field.a.a.a.a._options.a = b"); + pvString = pvRequest->getSubField("field.b.a._options.a"); + sval = pvString->get(); + testOk(sval.compare("b")==0,"field.b.a._options.a = b"); + testOk1(pvRequest->getSubField("field.b.a.a")!=NULL); + testOk1(pvRequest->getSubField("field.b.a.b")!=NULL); + if(debug) { cout << pvRequest->dumpValue(cout) << endl;} + testPass("request %s",request.c_str()); + + + request = "alarm,timeStamp,power.value"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << endl << String("request") <getMessage() << endl; + } + testOk1(pvRequest!=NULL); + testOk1(pvRequest->getSubField("field.alarm")!=NULL); + testOk1(pvRequest->getSubField("field.timeStamp")!=NULL); + testOk1(pvRequest->getSubField("field.power.value")!=NULL); + if(debug) { cout << pvRequest->dumpValue(cout) << endl;} + testPass("request %s",request.c_str()); + + request = "record[process=true]field(alarm,timeStamp,power.value)"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << endl << String("request") <getMessage() << endl; + } + testOk1(pvRequest!=NULL); + pvString = pvRequest->getSubField("record.process"); + sval = pvString->get(); + testOk(sval.compare("true")==0,"record.process = true"); + testOk1(pvRequest->getSubField("field.alarm")!=NULL); + testOk1(pvRequest->getSubField("field.timeStamp")!=NULL); + testOk1(pvRequest->getSubField("field.power.value")!=NULL); + if(debug) {cout << pvRequest->dumpValue(cout) << endl;} + testPass("request %s",request.c_str()); + + request = "record[process=true]field(alarm,timeStamp[algorithm=onChange,causeMonitor=false],power{value,alarm})"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << String("request") <getMessage() << endl; + } + testOk1(pvRequest!=NULL); + pvString = pvRequest->getSubField("record.process"); + sval = pvString->get(); + testOk(sval.compare("true")==0,"record.process = true"); + testOk1(pvRequest->getSubField("field.alarm")!=NULL); + testOk1(pvRequest->getSubField("field.timeStamp")!=NULL); + pvString = pvRequest->getSubField("field.timeStamp._options.algorithm"); + sval = pvString->get(); + testOk(sval.compare("onChange")==0,"field.timeStamp._options.algorithm = onChange"); + pvString = pvRequest->getSubField("field.timeStamp._options.causeMonitor"); + sval = pvString->get(); + testOk(sval.compare("false")==0,"field.timeStamp._options.causeMonitor = false"); + testOk1(pvRequest->getSubField("field.power.value")!=NULL); + testOk1(pvRequest->getSubField("field.power.alarm")!=NULL); + if(debug) {cout << pvRequest->dumpValue(cout) << endl;} + testPass("request %s",request.c_str()); + + request = "record[int=2,float=3.14159]field(alarm,timeStamp[shareData=true],power.value)"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << String("request") <getMessage() << endl; + } + testOk1(pvRequest!=NULL); + pvString = pvRequest->getSubField("record.int"); + sval = pvString->get(); + testOk(sval.compare("2")==0,"record.int = 2"); + pvString = pvRequest->getSubField("record.float"); + sval = pvString->get(); + testOk(sval.compare("3.14159")==0,"record.float = 3.14159"); + testOk1(pvRequest->getSubField("field.alarm")!=NULL); + pvString = pvRequest->getSubField("field.timeStamp._options.shareData"); + sval = pvString->get(); + testOk(sval.compare("true")==0,"field.timeStamp._options.shareData = true"); + testOk1(pvRequest->getSubField("field.power.value")!=NULL); + if(debug) {cout << pvRequest->dumpValue(cout) << endl;} + testPass("request %s",request.c_str()); + + request = String("record[process=true,xxx=yyy]") + + "putField(power.value)" + + "getField(alarm,timeStamp,power{value,alarm}," + + "current{value,alarm},voltage{value,alarm})"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << String("request") <getMessage() << endl; + } + testOk1(pvRequest!=NULL); + testOk1(pvRequest->getSubField("putField.power.value")!=NULL); + testOk1(pvRequest->getSubField("getField.alarm")!=NULL); + testOk1(pvRequest->getSubField("getField.timeStamp")!=NULL); + testOk1(pvRequest->getSubField("getField.power.value")!=NULL); + testOk1(pvRequest->getSubField("getField.power.alarm")!=NULL); + testOk1(pvRequest->getSubField("getField.current.value")!=NULL); + testOk1(pvRequest->getSubField("getField.current.alarm")!=NULL); + testOk1(pvRequest->getSubField("getField.voltage.value")!=NULL); + testOk1(pvRequest->getSubField("getField.voltage.alarm")!=NULL); + if(debug) {cout << pvRequest->dumpValue(cout) << endl;} + testPass("request %s",request.c_str()); + + request = String("field(alarm,timeStamp,supply{") + + "0{voltage.value,current.value,power.value}," + + "1{voltage.value,current.value,power.value}" + + "})"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << String("request") <getMessage() << endl; + } + testOk1(pvRequest!=NULL); + testOk1(pvRequest->getSubField("field.alarm")!=NULL); + testOk1(pvRequest->getSubField("field.timeStamp")!=NULL); + testOk1(pvRequest->getSubField("field.supply.0.voltage.value")!=NULL); + testOk1(pvRequest->getSubField("field.supply.0.current.value")!=NULL); + testOk1(pvRequest->getSubField("field.supply.0.power.value")!=NULL); + testOk1(pvRequest->getSubField("field.supply.1.voltage.value")!=NULL); + testOk1(pvRequest->getSubField("field.supply.1.current.value")!=NULL); + testOk1(pvRequest->getSubField("field.supply.1.power.value")!=NULL); + if(debug) {cout << pvRequest->dumpValue(cout) << endl;} + testPass("request %s",request.c_str()); + + request = String("record[process=true,xxx=yyy]") + + "putField(power.value)" + + "getField(alarm,timeStamp,power{value,alarm}," + + "current{value,alarm},voltage{value,alarm}," + + "ps0{alarm,timeStamp,power{value,alarm},current{value,alarm},voltage{value,alarm}}," + + "ps1{alarm,timeStamp,power{value,alarm},current{value,alarm},voltage{value,alarm}}" + + ")"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << String("request") <getMessage() << endl; + } + testOk1(pvRequest!=NULL); + testOk1(pvRequest->getSubField("putField.power.value")!=NULL); + testOk1(pvRequest->getSubField("getField.alarm")!=NULL); + testOk1(pvRequest->getSubField("getField.timeStamp")!=NULL); + testOk1(pvRequest->getSubField("getField.power.value")!=NULL); + testOk1(pvRequest->getSubField("getField.power.alarm")!=NULL); + testOk1(pvRequest->getSubField("getField.current.value")!=NULL); + testOk1(pvRequest->getSubField("getField.current.alarm")!=NULL); + testOk1(pvRequest->getSubField("getField.voltage.value")!=NULL); + testOk1(pvRequest->getSubField("getField.voltage.alarm")!=NULL); + testOk1(pvRequest->getSubField("getField.ps0.alarm")!=NULL); + testOk1(pvRequest->getSubField("getField.ps0.timeStamp")!=NULL); + testOk1(pvRequest->getSubField("getField.ps0.power.value")!=NULL); + testOk1(pvRequest->getSubField("getField.ps0.power.alarm")!=NULL); + testOk1(pvRequest->getSubField("getField.ps0.current.value")!=NULL); + testOk1(pvRequest->getSubField("getField.ps0.current.alarm")!=NULL); + testOk1(pvRequest->getSubField("getField.ps0.voltage.value")!=NULL); + testOk1(pvRequest->getSubField("getField.ps0.voltage.alarm")!=NULL); + testOk1(pvRequest->getSubField("getField.ps1.alarm")!=NULL); + testOk1(pvRequest->getSubField("getField.ps1.timeStamp")!=NULL); + testOk1(pvRequest->getSubField("getField.ps1.power.value")!=NULL); + testOk1(pvRequest->getSubField("getField.ps1.power.alarm")!=NULL); + testOk1(pvRequest->getSubField("getField.ps1.current.value")!=NULL); + testOk1(pvRequest->getSubField("getField.ps1.current.alarm")!=NULL); + testOk1(pvRequest->getSubField("getField.ps1.voltage.value")!=NULL); + testOk1(pvRequest->getSubField("getField.ps1.voltage.alarm")!=NULL); + if(debug) {cout << pvRequest->dumpValue(cout) << endl;} + testPass("request %s",request.c_str()); + + request = "a{b{c{d}}}"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << String("request") <getSubField("field.a.b.c.d")!=NULL); + if(debug) {cout << pvRequest->dumpValue(cout) << endl;} + testPass("request %s",request.c_str()); + + request = String("record[process=true,xxx=yyy]") + + "putField(power.value)" + + "getField(alarm,timeStamp,power{value,alarm}," + + "current{value,alarm},voltage{value,alarm}," + + "ps0{alarm,timeStamp,power{value,alarm},current{value,alarm},voltage{value,alarm}}," + + "ps1{alarm,timeStamp,power{value,alarm},current{value,alarm},voltage{value,alarm}" + + ")"; + if(debug) { cout << endl << "Error Expected for next call!!" << endl;} + if(debug) { cout << String("request") <createRequest(request); + assert(pvRequest.get()==NULL); + if(debug) {cout << "reason " << createRequest->getMessage() << endl;} + testPass("request %s",request.c_str()); + + request = "record[process=true,power.value"; + if(debug) { cout << String("request") <createRequest(request); + assert(pvRequest.get()==NULL); + if(debug) { cout << "reason " << createRequest->getMessage() << endl;} + testPass("request %s",request.c_str()); +} + +MAIN(testCreateRequest) +{ + testPlan(111); + testCreateRequest(); + return testDone(); +} + + diff --git a/testApp/copy/testPVCopy.cpp b/testApp/copy/testPVCopy.cpp new file mode 100644 index 0000000..b874e7c --- /dev/null +++ b/testApp/copy/testPVCopy.cpp @@ -0,0 +1,393 @@ +/*testPVCopyMain.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + + +using namespace std; +using std::tr1::static_pointer_cast; +using namespace epics::pvData; + +static bool debug = true; + +static void testPVScalar( + String const & valueNameMaster, + String const & valueNameCopy, + PVStructurePtr const & pvMaster, + PVCopyPtr const & pvCopy) +{ + PVStructurePtr pvStructureCopy; + PVFieldPtr pvField; + PVScalarPtr pvValueMaster; + PVScalarPtr pvValueCopy; + BitSetPtr bitSet; + String builder; + size_t offset; + ConvertPtr convert = getConvert(); + + pvField = pvMaster->getSubField(valueNameMaster); + pvValueMaster = static_pointer_cast(pvField); + convert->fromDouble(pvValueMaster,.04); + StructureConstPtr structure = pvCopy->getStructure(); + builder.clear(); structure->toString(&builder); + if(debug) { cout << "structure from copy" << endl << builder << endl; } + pvStructureCopy = pvCopy->createPVStructure(); + pvField = pvStructureCopy->getSubField(valueNameCopy); + pvValueCopy = static_pointer_cast(pvField); + bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields())); + pvCopy->initCopy(pvStructureCopy, bitSet); + if(debug) { cout << "after initCopy pvValueCopy " << convert->toDouble(pvValueCopy); } + if(debug) { cout << endl; } + convert->fromDouble(pvValueMaster,.06); + testOk1(convert->toDouble(pvValueCopy)==.04); + pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet); + testOk1(convert->toDouble(pvValueCopy)==.06); + testOk1(bitSet->get(pvValueCopy->getFieldOffset())); + if(debug) { cout << "after put(.06) pvValueCopy " << convert->toDouble(pvValueCopy); } + builder.clear(); + bitSet->toString(&builder); + if(debug) { cout << " bitSet " << builder; } + if(debug) { cout << endl; } + offset = pvCopy->getCopyOffset(pvValueMaster); + if(debug) { cout << "getCopyOffset() " << offset; } + if(debug) { cout << " pvValueCopy->getOffset() " << pvValueCopy->getFieldOffset(); } + if(debug) { cout << " pvValueMaster->getOffset() " << pvValueMaster->getFieldOffset(); } + if(debug) { cout << " bitSet " << builder; } + if(debug) { cout << endl; } + bitSet->clear(); + convert->fromDouble(pvValueMaster,1.0); + builder.clear(); + bitSet->toString(&builder); + if(debug) { cout << "before updateCopyFromBitSet"; } + if(debug) { cout << " masterValue " << convert->toDouble(pvValueMaster); } + if(debug) { cout << " copyValue " << convert->toDouble(pvValueCopy); } + if(debug) { cout << " bitSet " << builder; } + if(debug) { cout << endl; } + bitSet->set(0); + testOk1(convert->toDouble(pvValueCopy)==0.06); + pvCopy->updateCopyFromBitSet(pvStructureCopy,bitSet); + testOk1(convert->toDouble(pvValueCopy)==1.0); + if(debug) { cout << "after updateCopyFromBitSet"; } + if(debug) { cout << " masterValue " << convert->toDouble(pvValueMaster); } + if(debug) { cout << " copyValue " << convert->toDouble(pvValueCopy); } + if(debug) { cout << " bitSet " << builder; } + if(debug) { cout << endl; } + convert->fromDouble(pvValueCopy,2.0); + bitSet->set(0); + if(debug) { cout << "before updateMaster"; } + if(debug) { cout << " masterValue " << convert->toDouble(pvValueMaster); } + if(debug) { cout << " copyValue " << convert->toDouble(pvValueCopy); } + if(debug) { cout << " bitSet " << builder; } + if(debug) { cout << endl; } + testOk1(convert->toDouble(pvValueMaster)==1.0); + pvCopy->updateMaster(pvStructureCopy,bitSet); + testOk1(convert->toDouble(pvValueMaster)==2.0); + if(debug) { cout << "after updateMaster"; } + if(debug) { cout << " masterValue " << convert->toDouble(pvValueMaster); } + if(debug) { cout << " copyValue " << convert->toDouble(pvValueCopy); } + if(debug) { cout << " bitSet " << builder; } + if(debug) { cout << endl; } +} + +static void testPVScalarArray( + ScalarType scalarType, + String const & valueNameMaster, + String const & valueNameCopy, + PVStructurePtr const & pvMaster, + PVCopyPtr const & pvCopy) +{ + PVStructurePtr pvStructureCopy; + PVScalarArrayPtr pvValueMaster; + PVScalarArrayPtr pvValueCopy; + BitSetPtr bitSet; + String builder; + size_t offset; + size_t n = 5; + shared_vector values(n); + shared_vector cvalues; + + pvValueMaster = pvMaster->getScalarArrayField(valueNameMaster,scalarType); + for(size_t i=0; i xxx(freeze(values)); + pvValueMaster->putFrom(xxx); + StructureConstPtr structure = pvCopy->getStructure(); + builder.clear(); structure->toString(&builder); + if(debug) { cout << "structure from copy" << endl << builder << endl;} + pvStructureCopy = pvCopy->createPVStructure(); + pvValueCopy = pvStructureCopy->getScalarArrayField(valueNameCopy,scalarType); + bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields())); + pvCopy->initCopy(pvStructureCopy, bitSet); + builder.clear(); pvValueCopy->toString(&builder); + if(debug) { cout << "after initCopy pvValueCopy " << builder << endl; } + if(debug) { cout << endl; } + values.resize(n); + for(size_t i=0; i yyy(freeze(values)); + pvValueMaster->putFrom(yyy); + pvValueCopy->getAs(cvalues); + testOk1(cvalues[0]==0.0); + pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet); + pvValueCopy->getAs(cvalues); + testOk1(cvalues[0]==0.06); + builder.clear(); pvValueCopy->toString(&builder); + if(debug) { cout << "after put(i+ .06) pvValueCopy " << builder << endl; } + builder.clear(); + bitSet->toString(&builder); + if(debug) { cout << " bitSet " << builder; } + if(debug) { cout << endl; } + offset = pvCopy->getCopyOffset(pvValueMaster); + if(debug) { cout << "getCopyOffset() " << offset; } + if(debug) { cout << " pvValueCopy->getOffset() " << pvValueCopy->getFieldOffset(); } + if(debug) { cout << " pvValueMaster->getOffset() " << pvValueMaster->getFieldOffset(); } + builder.clear(); + bitSet->toString(&builder); + if(debug) { cout << " bitSet " << builder; } + if(debug) { cout << endl; } + bitSet->clear(); + values.resize(n); + for(size_t i=0; i zzz(freeze(values)); + pvValueMaster->putFrom(zzz); + builder.clear(); + bitSet->toString(&builder); + if(debug) { cout << "before updateCopyFromBitSet"; } + builder.clear(); pvValueMaster->toString(&builder); + if(debug) { cout << " masterValue " << builder << endl; } + builder.clear(); pvValueCopy->toString(&builder); + if(debug) { cout << " copyValue " << builder << endl; } + if(debug) { cout << " bitSet " << builder; } + builder.clear(); + bitSet->toString(&builder); + if(debug) { cout << endl; } + bitSet->set(0); + pvValueCopy->getAs(cvalues); + testOk1(cvalues[0]==0.06); + pvCopy->updateCopyFromBitSet(pvStructureCopy,bitSet); + pvValueCopy->getAs(cvalues); + testOk1(cvalues[0]==1.0); + if(debug) { cout << "after updateCopyFromBitSet"; } + builder.clear(); pvValueMaster->toString(&builder); + if(debug) { cout << " masterValue " << builder << endl; } + builder.clear(); pvValueCopy->toString(&builder); + if(debug) { cout << " copyValue " << builder << endl; } + builder.clear(); + bitSet->toString(&builder); + if(debug) { cout << " bitSet " << builder; } + if(debug) { cout << endl; } + values.resize(n); + for(size_t i=0; i ttt(freeze(values)); + pvValueMaster->putFrom(ttt); + bitSet->set(0); + if(debug) { cout << "before updateMaster"; } + builder.clear(); pvValueMaster->toString(&builder); + if(debug) { cout << " masterValue " << builder << endl; } + builder.clear(); pvValueCopy->toString(&builder); + if(debug) { cout << " copyValue " << builder << endl; } + builder.clear(); + bitSet->toString(&builder); + if(debug) { cout << " bitSet " << builder; } + if(debug) { cout << endl; } + pvValueMaster->getAs(cvalues); + testOk1(cvalues[0]==2.0); + pvCopy->updateMaster(pvStructureCopy,bitSet); + pvValueMaster->getAs(cvalues); + testOk1(cvalues[0]==1.0); + if(debug) { cout << "after updateMaster"; } + builder.clear(); pvValueMaster->toString(&builder); + if(debug) { cout << " masterValue " << builder << endl; } + builder.clear(); pvValueCopy->toString(&builder); + if(debug) { cout << " copyValue " << builder << endl; } + builder.clear(); + bitSet->toString(&builder); + if(debug) { cout << " bitSet " << builder; } + if(debug) { cout << endl; } +} + +static void scalarTest() +{ + if(debug) { cout << endl << endl << "****scalarTest****" << endl; } + PVStructurePtr pvMaster; + String request; + PVStructurePtr pvRequest; + PVFieldPtr pvMasterField; + PVCopyPtr pvCopy; + String valueNameMaster; + String valueNameCopy; + + StandardPVFieldPtr standardPVField = getStandardPVField(); + pvMaster = standardPVField->scalar(pvDouble,"alarm,timeStamp,display"); + + valueNameMaster = request = "value"; + CreateRequest::shared_pointer createRequest = CreateRequest::create(); + pvRequest = createRequest->createRequest(request); + if(debug) { cout << "request " << request << endl; } + if(debug) { cout << "pvRequest\n" << pvRequest->dumpValue(cout) << endl; } + pvCopy = PVCopy::create(pvMaster,pvRequest,""); + valueNameCopy = "value"; + testPVScalar(valueNameMaster,valueNameCopy,pvMaster,pvCopy); + request = ""; + valueNameMaster = "value"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << "request " << request << endl; } + if(debug) { cout << "pvRequest\n" << pvRequest->dumpValue(cout) << endl; } + pvCopy = PVCopy::create(pvMaster,pvRequest,""); + valueNameCopy = "value"; + testPVScalar(valueNameMaster,valueNameCopy,pvMaster,pvCopy); + request = "alarm,timeStamp,value"; + valueNameMaster = "value"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << "request " << request << endl; } + if(debug) { cout << "pvRequest\n" << pvRequest->dumpValue(cout) << endl; } + pvCopy = PVCopy::create(pvMaster,pvRequest,""); + valueNameCopy = "value"; + testPVScalar(valueNameMaster,valueNameCopy,pvMaster,pvCopy); +} + +static void arrayTest() +{ + if(debug) { cout << endl << endl << "****arrayTest****" << endl; } + PVStructurePtr pvMaster; + String request; + PVStructurePtr pvRequest; + PVFieldPtr pvMasterField; + PVCopyPtr pvCopy; + String valueNameMaster; + String valueNameCopy; + + CreateRequest::shared_pointer createRequest = CreateRequest::create(); + StandardPVFieldPtr standardPVField = getStandardPVField(); + pvMaster = standardPVField->scalarArray(pvDouble,"alarm,timeStamp"); + valueNameMaster = request = "value"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << "request " << request << endl; } + if(debug) { cout << "pvRequest\n" << pvRequest->dumpValue(cout) << endl; } + pvCopy = PVCopy::create(pvMaster,pvRequest,""); + valueNameCopy = "value"; + testPVScalarArray(pvDouble,valueNameMaster,valueNameCopy,pvMaster,pvCopy); + request = ""; + valueNameMaster = "value"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << "request " << request << endl; } + if(debug) { cout << "pvRequest\n" << pvRequest->dumpValue(cout) << endl; } + pvCopy = PVCopy::create(pvMaster,pvRequest,""); + valueNameCopy = "value"; + testPVScalarArray(pvDouble,valueNameMaster,valueNameCopy,pvMaster,pvCopy); + request = "alarm,timeStamp,value"; + valueNameMaster = "value"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << "request " << request << endl; } + if(debug) { cout << "pvRequest\n" << pvRequest->dumpValue(cout) << endl; } + pvCopy = PVCopy::create(pvMaster,pvRequest,""); + valueNameCopy = "value"; + testPVScalarArray(pvDouble,valueNameMaster,valueNameCopy,pvMaster,pvCopy); +} + +static PVStructurePtr createPowerSupply() +{ + FieldCreatePtr fieldCreate = getFieldCreate(); + StandardFieldPtr standardField = getStandardField(); + PVDataCreatePtr pvDataCreate = getPVDataCreate(); + + size_t nfields = 5; + StringArray names; + names.reserve(nfields); + FieldConstPtrArray powerSupply; + powerSupply.reserve(nfields); + names.push_back("alarm"); + powerSupply.push_back(standardField->alarm()); + names.push_back("timeStamp"); + powerSupply.push_back(standardField->timeStamp()); + String properties("alarm,display"); + names.push_back("voltage"); + powerSupply.push_back(standardField->scalar(pvDouble,properties)); + names.push_back("power"); + powerSupply.push_back(standardField->scalar(pvDouble,properties)); + names.push_back("current"); + powerSupply.push_back(standardField->scalar(pvDouble,properties)); + return pvDataCreate->createPVStructure( + fieldCreate->createStructure(names,powerSupply)); +} + + + +static void powerSupplyTest() +{ + if(debug) { cout << endl << endl << "****powerSupplyTest****" << endl; } + PVStructurePtr pvMaster; + String request; + PVStructurePtr pvRequest; + PVFieldPtr pvMasterField; + PVCopyPtr pvCopy; + String builder; + String valueNameMaster; + String valueNameCopy; + + CreateRequest::shared_pointer createRequest = CreateRequest::create(); + pvMaster = createPowerSupply(); + valueNameMaster = request = "power.value"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << "request " << request << endl; } + if(debug) { cout << "pvRequest\n" << pvRequest->dumpValue(cout) << endl; } + pvCopy = PVCopy::create(pvMaster,pvRequest,""); + valueNameCopy = "power.value"; + testPVScalar(valueNameMaster,valueNameCopy,pvMaster,pvCopy); + request = ""; + valueNameMaster = "power.value"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << "request " << request << endl; } + if(debug) { cout << "pvRequest\n" << pvRequest->dumpValue(cout) << endl; } + pvCopy = PVCopy::create(pvMaster,pvRequest,""); + valueNameCopy = "power.value"; + testPVScalar(valueNameMaster,valueNameCopy,pvMaster,pvCopy); + request = "alarm,timeStamp,voltage.value,power.value,current.value"; + valueNameMaster = "power.value"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << "request " << request << endl; } + if(debug) { cout << "pvRequest\n" << pvRequest->dumpValue(cout) << endl; } + pvCopy = PVCopy::create(pvMaster,pvRequest,""); + valueNameCopy = "power.value"; + testPVScalar(valueNameMaster,valueNameCopy,pvMaster,pvCopy); + request = "alarm,timeStamp,voltage{value,alarm},power{value,alarm,display},current.value"; + valueNameMaster = "power.value"; + pvRequest = createRequest->createRequest(request); + if(debug) { cout << "request " << request << endl; } + if(debug) { cout << "pvRequest\n" << pvRequest->dumpValue(cout) << endl; } + pvCopy = PVCopy::create(pvMaster,pvRequest,""); + valueNameCopy = "power.value"; + testPVScalar(valueNameMaster,valueNameCopy,pvMaster,pvCopy); +} + +MAIN(testPVCopy) +{ + testPlan(67); + scalarTest(); + arrayTest(); + powerSupplyTest(); + return testDone(); +} + diff --git a/testApp/misc/testSerialization.cpp b/testApp/misc/testSerialization.cpp index 80e485c..6c60b2a 100644 --- a/testApp/misc/testSerialization.cpp +++ b/testApp/misc/testSerialization.cpp @@ -307,8 +307,6 @@ void testScalar() { template void testArrayType(const typename PVT::value_type* rdata, size_t len) { - typedef typename PVT::value_type value_type; - typename PVT::svector empty(0), data(len); std::copy(rdata, rdata+len, data.begin()); diff --git a/testApp/pv/Makefile b/testApp/pv/Makefile index 4dc7c30..c9faf7a 100644 --- a/testApp/pv/Makefile +++ b/testApp/pv/Makefile @@ -12,21 +12,11 @@ testIntrospect_SRCS += testIntrospect.cpp testIntrospect_LIBS += pvData Com TESTS += testIntrospect -PROD_HOST += testPVAppend -testPVAppend_SRCS += testPVAppend.cpp -testPVAppend_LIBS += pvData Com -TESTS += testPVAppend - PROD_HOST += testPVType testPVType_SRCS += testPVType.cpp testPVType_LIBS += pvData Com TESTS += testPVType -PROD_HOST += testPVAuxInfo -testPVAuxInfo_SRCS += testPVAuxInfo.cpp -testPVAuxInfo_LIBS += pvData Com -TESTS += testPVAuxInfo - PROD_HOST += testStandardField testStandardField_SRCS += testStandardField.cpp testStandardField_LIBS += pvData Com diff --git a/testApp/pv/testPVAppend.cpp b/testApp/pv/testPVAppend.cpp deleted file mode 100644 index 7dd1a91..0000000 --- a/testApp/pv/testPVAppend.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* testPVAppend.cpp */ -/** - * Copyright - See the COPYRIGHT that is included with this distribution. - * EPICS pvData is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. - */ -/* Author: Marty Kraimer Date: 2010.11 */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -using namespace epics::pvData; -using std::tr1::static_pointer_cast; -using std::size_t; - -static bool debug = false; - -static FieldCreatePtr fieldCreate; -static PVDataCreatePtr pvDataCreate; -static StandardFieldPtr standardField; -static StandardPVFieldPtr standardPVField; -static ConvertPtr convert; -static String builder(""); -static String alarmTimeStamp("alarm,timeStamp"); -static String alarmTimeStampValueAlarm("alarm,timeStamp,valueAlarm"); -static String allProperties("alarm,timeStamp,display,control,valueAlarm"); - -static void checkNameAndParent( - PVStructurePtr & pvStructure, int indentLevel) -{ - builder.clear(); - if(debug) { - convert->newLine(&builder,indentLevel); - printf("%s this %p indentLevel %d", - builder.c_str(),pvStructure.get(),indentLevel); - } - PVFieldPtrArray pvFields = pvStructure->getPVFields(); - StringArray fieldNames = pvStructure->getStructure()->getFieldNames(); - for(size_t i = 0; igetParent()==pvStructure.get()); - testOk1(pvField->getFieldName().compare(fieldNames[i])==0); - builder.clear(); - if(debug) { - convert->newLine(&builder,indentLevel); - printf("%s this %p name %s parent %p", - builder.c_str(), - pvField.get(), - pvField->getFieldName().c_str(), - pvField->getParent()); - } - if(pvField->getField()->getType()==structure) { - PVStructurePtr xxx = static_pointer_cast(pvField); - checkNameAndParent(xxx,indentLevel+1); - } - } - builder.clear(); -} - -static void testAppendSimple() -{ - if(debug) printf("\ntestAppendSimple\n"); - PVFieldPtrArray fields; - StringArray names; - PVStructurePtr pvParent = pvDataCreate->createPVStructure(names,fields); - PVStringPtr pvStringField = static_pointer_cast( - pvDataCreate->createPVScalar(pvString)); - pvStringField->put("value,timeStamp"); - PVFieldPtr pvField = pvStringField; - pvParent->appendPVField("fieldlist",pvField); - pvStringField = static_pointer_cast( - pvDataCreate->createPVScalar(pvString)); - pvStringField->put("junk"); - pvField = pvStringField; - pvParent->appendPVField("extra",pvField); - builder.clear(); - pvParent->toString(&builder); - if(debug) printf("%s\n",builder.c_str()); - printf("testAppendSimple PASSED\n"); -} - -static void testAppendMore() -{ - if(debug) printf("\ntestAppendMore\n"); - PVFieldPtrArray fields; - StringArray names; - PVStructurePtr pvStructure = pvDataCreate->createPVStructure(names,fields); - PVStructurePtr pvChild1 = pvDataCreate->createPVStructure(names,fields); - PVStringPtr pvStringField = static_pointer_cast( - pvDataCreate->createPVScalar(pvString)); - pvStringField->put("bla"); - PVFieldPtr pvField = pvStringField; - pvChild1->appendPVField("value",pvField); - pvField = pvChild1; - pvStructure->appendPVField("child1",pvField); - PVStructurePtr pvChild2 = pvDataCreate->createPVStructure(names,fields); - pvStringField = static_pointer_cast( - pvDataCreate->createPVScalar(pvString)); - pvStringField->put("blabla"); - pvField = pvStringField; - pvChild2->appendPVField("value",pvField); - pvField = pvChild2; - pvStructure->appendPVField("child2",pvField); - builder.clear(); - pvStructure->toString(&builder); - if(debug) printf("%s\n",builder.c_str()); - checkNameAndParent(pvStructure,0); - printf("testAppendMore PASSED\n"); -} - -static void testAppendStructures() -{ - if(debug) printf("\ntestAppendStructures\n"); - PVFieldPtrArray fields; - StringArray names; - PVStructurePtr pvParent = pvDataCreate->createPVStructure(names,fields); - PVFieldPtrArray topFields; - StringArray topNames; - PVStructurePtr pvTop = pvDataCreate->createPVStructure(topNames,topFields); - pvParent->appendPVField("top",pvTop); - PVFieldPtrArray valueFields; - StringArray valueNames; - PVStructurePtr pvValue = pvDataCreate->createPVStructure(valueNames,valueFields); - pvTop->appendPVField("value",pvValue); - PVFieldPtrArray indexFields; - StringArray indexNames; - PVStructurePtr pvIndex = pvDataCreate->createPVStructure(indexNames,indexFields); - pvValue->appendPVField("index",pvIndex); - builder.clear(); - pvParent->toString(&builder); - if(debug) printf("%s\n",builder.c_str()); - builder.clear(); - pvParent->getField()->toString(&builder); - if(debug) printf("field\n%s\n",builder.c_str()); - printf("testAppendStructures PASSED\n"); -} - -static void append2(PVStructurePtr &pvStructure, - const char *oneName,const char *twoName, - const char *oneValue,const char *twoValue) -{ - PVFieldPtrArray pvFields; - pvFields.reserve(2); - StringArray names; - names.reserve(2); - PVStringPtr pvStringField = static_pointer_cast( - pvDataCreate->createPVScalar(pvString)); - pvStringField->put(oneValue); - names.push_back(oneName); - pvFields.push_back(pvStringField); - pvStringField = static_pointer_cast( - pvDataCreate->createPVScalar(pvString)); - pvStringField->put(twoValue); - names.push_back(twoName); - pvFields.push_back(pvStringField); - pvStructure->appendPVFields(names,pvFields); -} -static void testAppends() -{ - if(debug) printf("\ntestAppends\n"); - PVFieldPtrArray emptyPVFields; - StringArray emptyNames; - PVFieldPtrArray pvFields; - pvFields.reserve(2); - StringArray names; - names.reserve(2); - names.push_back("child1"); - PVStructurePtr pvChild = pvDataCreate->createPVStructure( - emptyNames,emptyPVFields); - append2(pvChild,"Joe","Mary","Good Guy","Good Girl"); - pvFields.push_back(pvChild); - names.push_back("child2"); - pvChild = pvDataCreate->createPVStructure( - emptyNames,emptyPVFields); - append2(pvChild,"Bill","Jane","Bad Guy","Bad Girl"); - pvFields.push_back(pvChild); - PVStructurePtr pvStructure = pvDataCreate->createPVStructure( - names,pvFields); - builder.clear(); - pvStructure->toString(&builder); - if(debug) printf("%s\n",builder.c_str()); - checkNameAndParent(pvStructure,0); - PVFieldPtr pvField = pvStructure->getSubField("child2.Bill"); - testOk1(pvField.get()!=NULL); - pvField->renameField("Joe"); - builder.clear(); - pvStructure->toString(&builder); - if(debug) printf("%s\n",builder.c_str()); - pvField->getParent()->removePVField("Joe"); - builder.clear(); - pvStructure->toString(&builder); - if(debug) printf("%s\n",builder.c_str()); - checkNameAndParent(pvStructure,0); - printf("testAppends PASSED\n"); -} - -MAIN(testPVAppend) -{ - testPlan(31); - fieldCreate = getFieldCreate(); - pvDataCreate = getPVDataCreate(); - standardField = getStandardField(); - standardPVField = getStandardPVField(); - convert = getConvert(); - testAppendStructures(); - testAppendSimple(); - testAppendMore(); - testAppends(); - return testDone(); -} - diff --git a/testApp/pv/testPVAuxInfo.cpp b/testApp/pv/testPVAuxInfo.cpp deleted file mode 100644 index 52d510b..0000000 --- a/testApp/pv/testPVAuxInfo.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* testPVAuxInfo.cpp */ -/** - * Copyright - See the COPYRIGHT that is included with this distribution. - * EPICS pvData is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. - */ -/* Author: Marty Kraimer Date: 2010.11 */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -using namespace epics::pvData; -using std::tr1::static_pointer_cast; - -static bool debug = false; - -static FieldCreatePtr fieldCreate; -static PVDataCreatePtr pvDataCreate; -static StandardFieldPtr standardField; -static StandardPVFieldPtr standardPVField; -static ConvertPtr convert; -static String buffer; - -static void printOffsets(PVStructurePtr pvStructure) -{ - printf("%s offset %lu next %lu number %lu\n", - pvStructure->getFieldName().c_str(), - (long unsigned)pvStructure->getFieldOffset(), - (long unsigned)pvStructure->getNextFieldOffset(), - (long unsigned)pvStructure->getNumberFields()); - PVFieldPtrArray fields = pvStructure->getPVFields(); - int number = (int)pvStructure->getStructure()->getNumberFields(); - for(int i=0; igetField()->getType()==structure) { - PVStructurePtr xxx = static_pointer_cast(pvField); - printOffsets(xxx); - continue; - } - printf("%s offset %lli next %lli number %lli\n", - pvField->getFieldName().c_str(), - (long long)pvField->getFieldOffset(), - (long long)pvField->getNextFieldOffset(), - (long long)pvField->getNumberFields()); - } -} - -static void testPVAuxInfo() -{ - if(debug) printf("\ntestPVAuxInfo\n"); - PVStructurePtr pvStructure = standardPVField->scalar( - pvDouble,"alarm,timeStamp,display,control"); - PVStructurePtr display - = pvStructure->getStructureField("display"); - testOk1(display.get()!=NULL); - PVAuxInfoPtr auxInfo = display->getPVAuxInfo(); - auxInfo->createInfo("factory",pvString); - auxInfo->createInfo("junk",pvDouble); - PVScalarPtr pscalar = auxInfo->getInfo(String("factory")); - testOk1(pscalar.get()!=0); - convert->fromString(pscalar,"factoryName"); - pscalar = auxInfo->getInfo("junk"); - testOk1(pscalar.get()!=0); - convert->fromString(pscalar,"3.0"); - buffer.clear(); - pvStructure->toString(&buffer); - if(debug) printf("%s\n",buffer.c_str()); - // now show field offsets - if(debug) printOffsets(pvStructure); - printf("testPVAuxInfo PASSED\n"); -} - -MAIN(testPVAuxInfo) -{ - testPlan(3); - fieldCreate = getFieldCreate(); - pvDataCreate = getPVDataCreate(); - standardField = getStandardField(); - standardPVField = getStandardPVField(); - convert = getConvert(); - testPVAuxInfo(); - return testDone(); -} - diff --git a/testApp/pv/testPVData.cpp b/testApp/pv/testPVData.cpp index 020cca8..0468293 100644 --- a/testApp/pv/testPVData.cpp +++ b/testApp/pv/testPVData.cpp @@ -24,6 +24,8 @@ using namespace epics::pvData; using std::tr1::static_pointer_cast; +using std::cout; +using std::endl; static bool debug = false; @@ -37,24 +39,6 @@ static String alarmTimeStamp("alarm,timeStamp"); static String alarmTimeStampValueAlarm("alarm,timeStamp,valueAlarm"); static String allProperties("alarm,timeStamp,display,control,valueAlarm"); -static void testAppend() -{ - if(debug) printf("\ntestAppend\n"); - PVFieldPtrArray pvFields; - StringArray fieldNames; - PVStructurePtr pvParent = pvDataCreate->createPVStructure( - fieldNames,pvFields); - PVStringPtr pvStringField = static_pointer_cast( - pvDataCreate->createPVScalar(pvString)); - pvStringField->put(String("value,timeStamp")); - PVFieldPtr pvField = pvStringField; - pvParent->appendPVField("request",pvField); - builder.clear(); - pvParent->toString(&builder); - if(debug) printf("%s\n",builder.c_str()); - printf("testAppend PASSED\n"); -} - static void testCreatePVStructure() { if(debug) printf("\ntestCreatePVStructure\n"); @@ -360,7 +344,7 @@ static void testScalarArrayCommon(String /*fieldName*/,ScalarType stype) pvStructure->toString(&builder); if(debug) printf("%s\n",builder.c_str()); PVFieldPtr pvField = pvStructure->getSubField("alarm.status"); - pvField->message("this is a test",infoMessage); + testOk1(pvField!=NULL); } static void testScalarArray() @@ -377,18 +361,81 @@ static void testScalarArray() printf("testScalarArray PASSED\n"); } +static void testRequest() +{ + if(debug) printf("\ntestScalarArray\n"); + StringArray nullNames; + FieldConstPtrArray nullFields; + StringArray optionNames(1); + FieldConstPtrArray optionFields(1); + optionNames[0] = "process"; + optionFields[0] = fieldCreate->createScalar(pvString); + StringArray recordNames(1); + FieldConstPtrArray recordFields(1); + recordNames[0] = "_options"; + recordFields[0] = fieldCreate->createStructure(optionNames,optionFields); + StringArray fieldNames(2); + FieldConstPtrArray fieldFields(2); + fieldNames[0] = "alarm"; + fieldFields[0] = fieldCreate->createStructure(nullNames,nullFields); + fieldNames[1] = "timeStamp"; + fieldFields[1] = fieldCreate->createStructure(nullNames,nullFields); + StringArray topNames(2); + FieldConstPtrArray topFields(2); + topNames[0] = "record"; + topFields[0] = fieldCreate->createStructure(recordNames,recordFields); + topNames[1] = "field"; + topFields[1] = fieldCreate->createStructure(fieldNames,fieldFields); + StructureConstPtr topStructure = fieldCreate->createStructure( + topNames,topFields); +String buffer; +topStructure->toString(&buffer); +cout << buffer.c_str() << endl; + PVStructurePtr pvTop = pvDataCreate->createPVStructure(topStructure); +buffer.clear(); +pvTop->toString(&buffer); +cout << buffer.c_str() << endl; +buffer.clear(); +pvTop->getStructure()->toString(&buffer); +cout << buffer.c_str() << endl; +PVStructurePtr xxx = pvTop->getSubField("record"); +buffer.clear(); +xxx->toString(&buffer); +cout << buffer.c_str() << endl; +xxx = pvTop->getSubField("field"); +buffer.clear(); +xxx->toString(&buffer); +cout << buffer.c_str() << endl; +PVStringPtr pvString = pvTop->getSubField("record._options.process"); +pvString->put("true"); +buffer.clear(); +pvTop->toString(&buffer); +cout << buffer.c_str() << endl; +cout << pvTop->dumpValue(cout) << endl; + +String subName("record._options.process"); +PVFieldPtr pvField = pvTop->getSubField(subName); +String fieldName = pvField->getFieldName(); +String fullName = pvField->getFullName(); +cout << "fieldName " << fieldName << " fullName " << fullName << endl; + + testOk1(fieldName.compare("process")==0); + testOk1(fullName.compare(subName)==0); + +} + MAIN(testPVData) { - testPlan(179); + testPlan(189); fieldCreate = getFieldCreate(); pvDataCreate = getPVDataCreate(); standardField = getStandardField(); standardPVField = getStandardPVField(); convert = getConvert(); - testAppend(); testCreatePVStructure(); testPVScalar(); testScalarArray(); + testRequest(); return testDone(); } diff --git a/testApp/pv/testPVScalarArray.cpp b/testApp/pv/testPVScalarArray.cpp index 206c4a2..44f21b2 100644 --- a/testApp/pv/testPVScalarArray.cpp +++ b/testApp/pv/testPVScalarArray.cpp @@ -26,6 +26,8 @@ using namespace epics::pvData; using std::tr1::static_pointer_cast; +using std::cout; +using std::endl; namespace { diff --git a/testApp/pv/testStandardField.cpp b/testApp/pv/testStandardField.cpp index cf181b9..fdb963e 100644 --- a/testApp/pv/testStandardField.cpp +++ b/testApp/pv/testStandardField.cpp @@ -66,6 +66,17 @@ MAIN(testStandardField) builder.clear(); structureArrayValue->toString(&builder); print("structureArrayValue"); + + StructureConstPtr punion = standardField->regUnion( + fieldCreate->createFieldBuilder()-> + add("doubleValue", pvDouble)-> + add("intValue", pvInt)-> + add("timeStamp",standardField->timeStamp())-> + createUnion(), + "alarm,timeStamp"); + builder.clear(); + punion->toString(&builder); + print("unionValue"); testPass("testStandardField"); return testDone(); }