completed merge

This commit is contained in:
Matej Sekoranja
2014-06-09 23:15:57 +02:00
53 changed files with 11633 additions and 1982 deletions

View File

@@ -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\..*

View File

@@ -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:
* <b>varient union</b> The field can have any type.
* <b>union</b> 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

54
documentation/TODO.md Normal file
View File

@@ -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

View File

@@ -0,0 +1,679 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>EPICS pvDataCPP: copy and monitor</title>
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/base.css" />
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
<style type="text/css">
/*<![CDATA[*/
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
table { margin-left: auto; margin-right: auto }
.diagram { text-align: center; margin: 2.5em 0 }
span.opt { color: grey }
span.nterm { font-style:italic }
span.term { font-family:courier }
span.user { font-family:courier }
span.user:before { content:"<" }
span.user:after { content:">" }
.nonnorm { font-style:italic }
p.ed { color: #AA0000 }
span.ed { color: #AA0000 }
p.ed.priv { display: inline; }
span.ed.priv { display: inline; }
/*]]>*/</style>
<!-- Script that generates the Table of Contents -->
<script type="text/javascript"
src="http://epics-pvdata.sourceforge.net/script/tocgen.js">
</script>
</head>
<body>
<div id="toc">
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
</div>
<div id="contents" class="contents">
<h2>support for copy and monitor</h2>
<p><b>copy</b> and <b>monitor</b> 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.
</p>
<p>This document describes C++ specific code.
<a href="http://epics-pvdata.sourceforge.net/informative/pvRequest.html">
pvRequest.html</a>
provides a language independent overview of <b>copy</b> and <b>monitor</b>.
</p>
<p>
<b>NOTE:pvRequest.html</b> 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.
</p>
<p>Copy provides:
<dl>
<dt>createRequest</dt>
<dd>
The Channel create methods in pvAccess all have an argument
<b>PVStructure pvRequest</b>.<br />
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.<br />
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.
</dd>
<dt>pvCopy</dt>
<dd>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.
</dd>
</dl>
Monitor provides:
<dl>
<dt>monitor</dt>
<dd>This is support code for channel providers that implement channel
monitor. It, together with the queue facility, provides support for
monitor queues.
</dd>
<dt>monitorPlugin</dt>
<dd>This is support for implementing monitor plugins.
A monitor plugin can be developed that has no knowledge
of pvAccess but only pvData.
</dd>
</dl>
</p>
<h2>support for copy</h2>
<p><b>copy</b> 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: <b>createRequest</b> and <b>pvCopy</b>.
Given a string createRequest creates a pvRequest, which is a PVStructure
that has the format expected by <b>pvCopy</b>.
</p>
<h3>createRequest</h3>
<p>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.
</p>
<p>The definition of the public members is:</p>
<pre>
class CreateRequest {
...
static CreateRequestPtr create();
virtual PVStructurePtr createRequest(String const &amp;request);
String getMessage();
};
</pre>
<p>An example of how it is used is:</p>
<pre>
CreateRequestPtr createRequest = CreateRequest::create();
PVStructurePtr pvRequest = createRequest-&gt;createRequest(request);
if(pvRequest==NULL) {
String error = createRequest-&gt;getMessage();
// take some action
} else {
//success do something
}
</pre>
<h3>pvCopy</h3>
<p>The definition of the public members is:</p>
<pre>
class epicsShareClass PVCopyTraverseMasterCallback
{
...
virtual void nextMasterPVField(PVFieldPtr const &amp;pvField);
};
class class epicsShareClass PVCopy
{
...
static PVCopyPtr create(
PVStructurePtr const &amp;pvMaster,
PVStructurePtr const &amp;pvRequest,
String const &amp; structureName);
PVStructurePtr getPVMaster();
void traverseMaster(PVCopyTraverseMasterCallbackPtr const &amp; callback);
StructureConstPtr getStructure();
PVStructurePtr createPVStructure();
size_t getCopyOffset(PVFieldPtr const &amp;masterPVField);
size_t getCopyOffset(
PVStructurePtr const &amp;masterPVStructure,
PVFieldPtr const &amp;masterPVField);
PVFieldPtr getMasterPVField(std::size_t structureOffset);
void initCopy(
PVStructurePtr const &amp;copyPVStructure,
BitSetPtr const &amp;bitSet);
void updateCopySetBitSet(
PVStructurePtr const &amp;copyPVStructure,
BitSetPtr const &amp;bitSet);
void updateCopyFromBitSet(
PVStructurePtr const &amp;copyPVStructure,
BitSetPtr const &amp;bitSet);
void updateMaster(
PVStructurePtr const &amp;copyPVStructure,
BitSetPtr const &amp;bitSet);
PVStructurePtr getOptions(std::size_t fieldOffset);
...
};
</pre>
where
<dl>
<dt>PVCopyTraverseMasterCallback::nextMasterPVField</dt>
<dd>
<b>PVCopyTraverseMasterCallback</b> is a callback which must
be implemented by the code that uses pvCopy, normally
the channel provider. It has the single method <b>nextMasterPVField</b>
<br />
<b>nextMasterPVField</b> is called for each field in the master
as a result of a call to <b>traverseMaster</b>.
</dd>
<dt>create</dt>
<dd>
This is the method for creating a PVCopy instance.<br/>
<dl>
<dt>pvMaster</dt>
<dd>the top level sructure managed by the server.</dd>
<dt>pvRequest</dt>
<dd>selects the set of subfields desired
and options for each field.</dd>
<dt>structureName</dt>
<dd>the name for the top level of any PVStructure created.
</dd>
</dl>
</dd>
<dt>getPVMaster</dt>
<dd>
Gets the top level structure from pvMaster.
</dd>
<dt>traverseMaster</dt>
<dd>
Traverse all fields of the top level structure of pvMaster.
For each field the callback is called.
</dd>
<dt>getStructure</dt>
<dd>
Get the introspection interface for a PVStructure for e copy.
</dd>
<dt>createPVStructure</dt>
<dd>Create a copy instance.
Monitors keep a queue of monitor elements.
Since each element needs a PVStructure, multiple top level structures
will be created.
</dd>
<dt>getCopyOffset</dt>
<dd>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.
</dd>
<dt>getMasterPVField</dt>
<dd>
Given a offset in the copy get the corresponding field in pvMaster.
</dd>
<dt>initCopy</dt>
<dd>
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 <b>{0}</b>.
</dd>
<dt>updateCopySetBitSet</dt>
<dd>
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.
</dd>
<dt>updateCopyFromBitSet</dt>
<dd>
For each set bit in bitSet set the field in copyPVStructure to the value
of the corrseponding field in pvMaster.
</dd>
<dt>updateMaster</dt>
<dd>
For each set bit in bitSet set the field in pvMaster to the value
of the corrseponding field in copyPVStructure.
</dd>
<dt>getOptions</dt>
<dd>
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.
</dd>
</dl>
<h2>support for monitor</h2>
<p>This consists of two components:
<dl>
<dt>monitor</dt>
<dd>Used by code that implements pvAccess montors.</dd>
<dt>monitorPlugin</dt>
<dd>Code that provides special semantics for monitors.</dd>
</dl>
</p>
<h3>monitor</h3>
<pre>
class MonitorElement {
MonitorElement(PVStructurePtr const &amp; 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 &amp; monitorElement) = 0;
};
class MonitorRequester : public virtual Requester {
virtual void monitorConnect(Status const &amp; status,
MonitorPtr const &amp; monitor, StructureConstPtr const &amp; structure) = 0;
virtual void monitorEvent(MonitorPtr const &amp; monitor) = 0;
virtual void unlisten(MonitorPtr const &amp; monitor) = 0;
};
</pre>
<h4>monitorElement</h4>
<p><b>MonitorElement</b> holds the data for one element of a monitor queue.
It has the fields:
<dl>
<dt>pvStructurePtr</dt>
<dd>A top level structure with data values at the time the monitors occurs.</dd>
<dt>changedBitSet</dt>
<dd>Shows which fields have changed since the previous monitor.</dd>
<dt>overrunBitSet</dt>
<dd>Shows which fields have changed more han once since the previous monitor.</dd>
</dl>
</p>
<h4>monitorElement queue</h4>
<p>
A queue of monitor elements must be implemented by any channel provider that implements
<b>Channel::createMonitor</b>.
For an example implementation look at pvDatabaseCPP.
It has the following:
<pre>
typedef Queue&lt;MonitorElement&gt; MonitorElementQueue;
typedef std::tr1::shared_ptr&lt;MonitorElementQueue&gt; MonitorElementQueuePtr;
class MultipleElementQueue :
public ElementQueue
{
public:
POINTER_DEFINITIONS(MultipleElementQueue);
virtual ~MultipleElementQueue(){}
MultipleElementQueue(
MonitorLocalPtr const &amp;monitorLocal,
MonitorElementQueuePtr const &amp;queue,
size_t nfields);
virtual void destroy(){}
virtual Status start();
virtual Status stop();
virtual bool dataChanged();
virtual MonitorElementPtr poll();
virtual void release(MonitorElementPtr const &amp;monitorElement);
...
};
</pre>
<h4>Monitor</h4>
<p><b>Monitor</b> must be implemented by any channel provider that implements
<b>Channel::createMonitor</b>.
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.
</p>
<p>Monitor has the following methods:</p>
<dl>
<dt>start</dt>
<dd>
Start monitoring.
This will result in a an inital monitor that has the current value
of all fields.
</dd>
<dt>stop</dt>
<dd>
Stop monitoring.
</dd>
<dt>poll</dt>
<dd>
Called to get a monitor element.
If no new elemants are available then a null pointer is returned.
</dd>
<dt>release</dt>
<dd>
Release the monotor element.
The caller owns the monitor element between the calls to poll and release.
</dd>
<dl>
</dl>
<h4>MonitorRequester</h4>
<p>This must be implemented by a pvAccess client.
It has the methods:</p>
<dl>
<dt>monitorConnect</dt>
<dd>
A monitor has either connected of disconnected.
</dd>
<dt>monitorEvent</dt>
<dd>
A new monitor element is available.
</dd>
<dt>unlisten</dt>
<dd>
The channel is going away. The client cam no longer access the monitor.
</dd>
</dl>
<h3>monitorPlugin</h3>
<pre>
class MonitorPlugin
{
virtual String const &amp; getName() = 0;
virtual bool causeMonitor(
PVFieldPtr const &amp;pvField,
PVStructurePtr const &amp;pvTop,
MonitorElementPtr const &amp;monitorElement) = 0;
virtual void monitorDone(
MonitorElementPtr const &amp;monitorElement);
virtual void startMonitoring();
virtual void stopMonitoring();
virtual void beginGroupPut();
virtual void endGroupPut();
};
class MonitorPluginCreator
{
virtual MonitorPluginPtr create(
FieldConstPtr const &amp;field,
StructureConstPtr const &amp;top,
PVStructurePtr const &amp;pvFieldOptions) = 0;
virtual String const &amp; getName() = 0;
}
class MonitorPluginManager
{
static MonitorPluginManagerPtr get();
bool addPlugin(
String const &amp;pluginName,
MonitorPluginCreatorPtr const &amp;creator);
MonitorPluginCreatorPtr findPlugin(String const &amp;pluginName);
void showNames();
};
</pre>
<h4>MonitorPlugin</h4>
<p><b>MonitorPlugin</b> must be implemented by the plugin implementation.
It has methods:</p>
<dl>
<dt>getName</dt>
<dd>Get the name of the plugin.</dd>
<dt>causeMonitor</dt>
<dd>
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</b>.
The implementation should <b>not</b> modify the fields in the structure
being monitored.
Called with pvTop locked.
</dd>
<dt>monitorDone</dt>
<dd>
Called just before monitorElement will be given to client.
The plugin can change the data values and bitSets in monitorElement.
Called with pvTop unlocked.
</dd>
<dt>startMonitoring</dt>
<dd>
Monitoring is starting.
</dd>
<dt>stopMonitoring</dt>
<dd>
Monitoring is being stopped.
</dd>
<dt>beginGroupPut</dt>
<dd>
A set of puts is starting.
Called with pvTop locked.
</dd>
<dt>endGroupPut</dt>
<dd>
The set of puts is complete.
Called with pvTop locked.
</dd>
</dl>
<h4>MonitorPluginCreator</h4>
<p><b>MonitorPluginCreator</b> must also be implemented by the plugin implementation.
It is called for each field instance that has options of the from
<b>[plugin=name...]</b> where <b>name</b> is the name of the plugin.
Note that a plugin instance will belong to a single client.
It has methods:</p>
<dl>
<dt>getName</dt>
<dd>Get the name of the plugin.</dd>
<dt>create</dt>
<dd>
Create a new plugin instance.
If the arguments are not compatible with the plugin a NULL shared pointer is
returned.<br/>
pvFieldOptions is
a structure with a set of PVString subfields that specify <b>name,value</b>
pairs. name is the subField name and value is the subField value.<br/>
Note that a plugin will below to a single client.
</dd>
<dl>
<h4>MonitorPluginManager</h4>
<p><b>MonitorPluginManager</b> has the methods:</p>
<dl>
<dt>get</dt>
<dd>
MonitorPluginManager is a singleton.
The first call to get will create the single instance.
Further calls will rerurn the single instance.
</dd>
<dt>addPlugin</dt>
<dd>
Add a new plugin.
</dd>
<dt>findPlugin</dt>
<dd>
Find a plugin. A NULL shared pointer is reurned if it has not been added.
</dd>
<dt>showNames</dt>
<dd>
Show the names of all puugins that have been added.
</dd>
</dl>
<p><b>NOTE:</b>
Should the method <b>causeMonitor</b>
have arguments <b>pvField</b> and <b>pvTop</b>
be defined so that they can not be modfied.
This would be posssible if the following was defined:
<pre>
typedef std::tr1::shared_ptr&lt;const PVField&gt; PVFieldConstPtr;
typedef std::tr1::shared_ptr&lt;const PVStructure&gt; PVStructureConstPtr;
</pre>
then the definition for causeMonitor could be:
<pre>
virtual bool causeMonitor(
PVFieldConstPtr const &amp;pvField,
PVStructureConstPtr const &amp;pvTop,
MonitorElementPtr const &amp;monitorElement) = 0;
</pre>
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 <b>Convert</b> must have
their arguments modified.
Big job.
</p>
<h2>monitorPlugin example</h2>
<h3>Example Plugin Overview</h3>
<p>This section describes an example plugin that:</p>
<ul>
<li>Only raises monitors when a field changes value.<br />
If no plugin is provided
the default is to raise a monitor when a put is issued to a field.</li>
<li>Optionally a change will not raise a monitor.<br />
The change will, however,
appear if a put to another field raise a monitor.</li>
</ul>
<p>As an example assume that a channel provided by pvAccess has a top level structure
that represents a power supply.</p>
<pre>
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
</pre>
<p>A pvAccess client wants to create a monitor on the powerSupply as follows:
The client wants a top level structure that looks like:
<pre>
structure powerSupply
structure alarm
structure timeStamp
structure power
double value
structure voltage
double value
structure current
double value
</pre>
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.
</p>
<p>The example monitor plugin implements the semantics the
client wants. It can be attached to any field via the following options:
<pre>
[plugin=onChange,raiseMonitor=value]
</pre>
This plugin will trigger a monitor for the field only if the field changes
value. In addition <b>value</b> equals <b>false</b> 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.
</p>
<p>
Assume that the client has already connected to the channel.
The client can then issue the commands:</p>
<pre>
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-&gt;createRequest(request);
MonitorPtr monitor = channel-&gt;createMonitor(monitorRequester,pvRequest);
</pre>
<h3>Example Plugin Code</h3>
<p>The header file to create the example has the definition:</p>
<pre>
class ExampleMonitorPlugin{
public:
static void create();
};
</pre>
<p>The implementation is:</p>
<pre>
class OnChangePlugin : public MonitorPlugin
{
public:
virtual ~OnChangePlugin(){}
OnChangePlugin() {}
bool init(
FieldConstPtr const &amp;field,
StructureConstPtr const &amp;top,
PVStructurePtr const &amp;pvFieldOptions)
{
pvField = getPVDataCreate()-&gt;createPVField(field);
raiseMonitor = true;
if(pvFieldOptions!=NULL) {
PVStringPtr pvString =
pvFieldOptions-&gt;getSubField&lt;PVString&gt;("raiseMonitor");
if(pvString!=NULL) {
String value = pvString-&gt;get();
if(value.compare("false")==0) raiseMonitor = false;
}
}
return true;
}
virtual String &amp;getName(){return pluginName;}
virtual bool causeMonitor(
PVFieldPtr const &amp;pvNew,
PVStructurePtr const &amp;pvTop,
MonitorElementPtr const &amp;monitorElement)
{
bool isSame = convert-&gt;equals(pvNew,pvField);
if(isSame) return false;
convert-&gt;copy(pvNew,pvField);
return raiseMonitor;
}
private:
PVFieldPtr pvField;
bool raiseMonitor;
};
class OnChangePluginCreator : public MonitorPluginCreator
{
public:
virtual String &amp;getName(){return pluginName;}
virtual MonitorPluginPtr create(
FieldConstPtr const &amp;field,
StructureConstPtr const &amp;top,
PVStructurePtr const &amp;pvFieldOptions)
{
OnChangePluginPtr plugin(new OnChangePlugin());
bool result = plugin-&gt;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()-&gt;addPlugin(pluginName,plugin);
}
}
</pre>
</div>
</body>
</html>

BIN
documentation/examples.zip Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -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)->

File diff suppressed because it is too large Load Diff

View File

@@ -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

532
src/copy/createRequest.cpp Normal file
View File

@@ -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 <string>
#include <sstream>
#include <pv/pvData.h>
#include <pv/lock.h>
#define epicsExportSharedSymbols
#include <pv/createRequest.h>
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<closeBrace) return findMatchingBrace(request,openBrace,numOpen+1);
if(numOpen==1) return closeBrace;
return findMatchingBrace(request,closeBrace,numOpen-1);
}
if(numOpen==1) return closeBrace;
return findMatchingBrace(request,closeBrace,numOpen-1);
}
size_t findMatchingBracket(String& request, size_t index) {
for(size_t i=index+1; i< request.size(); ++i) {
if(request[i] == ']') {
if(i==index+1) {
message = request + " illegal []";
return String::npos;
}
return i;
}
}
message = request + " missing ]";
return std::string::npos;
}
size_t findEndField(String& request) {
size_t ind = 0;
size_t maxind = request.size() -1;
while(true) {
if(request[ind]==',') return ind;
if(request[ind]=='[') {
size_t closeBracket = findMatchingBracket(request,ind);
if(closeBracket==String::npos) return closeBracket;
ind = closeBracket;
continue;
}
if(request[ind]=='{') {
size_t closeBrace = findMatchingBrace(request,ind,1);
if(closeBrace==String::npos) return closeBrace;
if(ind>=request.size()) return request.size();
ind = closeBrace;
continue;
}
if(ind>=maxind) break;
++ind;
}
return request.size();
}
std::vector<String> 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<String> valueList(numValues,"");
index=0;
for(size_t i=0; i<numValues; i++) {
size_t pos = commaSeparatedList.find(',',index);
String value = commaSeparatedList.substr(index,pos-index);
valueList[i] = value;
index = pos +1;
}
return valueList;
}
StructureConstPtr createRequestOptions(
String request)
{
if(request.length()<=1) return StructureConstPtr();
std::vector<String> items = split(request);
size_t nitems = items.size();
StringArray fieldNames(nitems);
FieldConstPtrArray fields(nitems);
for(size_t j=0; j<nitems; j++) {
String item = items[j];
size_t equals = item.find('=');
if(equals==String::npos || equals==0) {
message = item + " illegal option";
StructureConstPtr xxx;
return xxx;
}
fieldNames[j] = item.substr(0,equals);
fields[j] = fieldCreate->createScalar(pvString);
}
return fieldCreate->createStructure(fieldNames,fields);
}
void initRequestOptions(
PVStructurePtr const & pvParent,
String request)
{
if(request.length()<=1) return;
std::vector<String> items = split(request);
size_t nitems = items.size();
for(size_t j=0; j<nitems; j++) {
String item = items[j];
size_t equals = item.find('=');
String name = item.substr(0,equals);
String value = item.substr(equals+1);
PVStringPtr pvValue = pvParent->getSubField<PVString>(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 || period<openBracket)
&& (openBrace==String::npos || period<openBrace) )
{
String fieldName = request.substr(0,period);
StructureConstPtr subField = fieldCreate->createStructure();
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<openBracket) )
{
String fieldName = request.substr(0,openBrace);
size_t closeBrace = findMatchingBrace(request,openBrace,1);
if(closeBrace==String::npos) return StructureConstPtr();
size_t nextChar = closeBrace+1;
if(nextChar>= 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<openBrace) )
{
String fieldName = request.substr(0,openBracket);
size_t closeBracket = findMatchingBracket(request,openBracket);
if(closeBracket==String::npos) return StructureConstPtr();
size_t nextChar = closeBracket+1;
if(nextChar>= 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; i<numSub; ++i) {
fieldNames[i+1] = subNames[i];
fields[i+1] = subFields[i];
}
subField = fieldCreate->appendFields(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; i<numFields; ++i) {
fieldNames.push_back(subNames[i]);
fields.push_back(subFields[i]);
}
}
parent = fieldCreate->appendFields(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<openBracket)
&& (openBrace==String::npos || period<openBrace) )
{
PVStructurePtr pvSubField = static_pointer_cast<PVStructure>(pvParent->getPVFields()[0]);
initSubFieldOptions(pvSubField,request.substr(period+1));
return;
}
// brace before [ or .
if(openBrace!=String::npos
&& (openBracket==String::npos || openBrace<openBracket) )
{
PVStructurePtr pvSubField = static_pointer_cast<PVStructure>(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<PVStructure>("_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<PVStructure>(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.size(); ++i) {
PVStructurePtr pvSubField = static_pointer_cast<PVStructure>(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<num; ++i) {
PVStructurePtr pvSub = static_pointer_cast<PVStructure>(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<PVStructure>("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<PVStructure>("field");
if(pvSub->getStructure()->getNumberFields()==1) {
pvSub = static_pointer_cast<PVStructure>(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<PVStructure>("putField");
if(pvSub->getStructure()->getNumberFields()==1) {
pvSub = static_pointer_cast<PVStructure>(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<PVStructure>("getField");
if(pvSub->getStructure()->getNumberFields()==1) {
pvSub = static_pointer_cast<PVStructure>(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;
}
}}

67
src/copy/createRequest.h Normal file
View File

@@ -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 <string>
#include <sstream>
#ifdef epicsExportSharedSymbols
# define pvDataEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <pv/pvData.h>
#include <pv/lock.h>
#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 */

644
src/copy/pvCopy.cpp Normal file
View File

@@ -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 <string>
#include <stdexcept>
#include <memory>
#include <sstream>
#include <pv/thread.h>
#include <pv/pvCopy.h>
#include <pv/convert.h>
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<CopyNodePtr> CopyNodePtrArray;
typedef std::tr1::shared_ptr<CopyNodePtrArray> 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<CopyMasterNode>(node);
callback->nextMasterPVField(masterNode->masterPVField);
return;
}
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(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<CopyStructureNode>(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 && fieldOffset<soff+node->nfields) {
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<CopyMasterNode>(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(offdiff<masterNode->nfields) return headNode->structureOffset + offdiff;
return String::npos;
}
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(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<CopyMasterNode>(headNode);
if(masterNode->masterPVField.get()!=masterPVStructure.get()) return String::npos;
} else {
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(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<CopyMasterNode>(headNode);
} else {
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(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<PVStructure>(pvMasterField);
return pvStructure->getSubField(
pvMasterField->getFieldOffset() + diff);
}
void PVCopy::initCopy(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet)
{
bitSet->clear();
bitSet->set(0);
updateCopyFromBitSet(copyPVStructure,bitSet);
}
void PVCopy::updateCopySetBitSet(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet)
{
if(headNode->isStructure) {
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(headNode);
updateStructureNodeSetBitSet(copyPVStructure,node,bitSet);
} else {
CopyMasterNodePtr masterNode = static_pointer_cast<CopyMasterNode>(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 &copyPVStructure,
BitSetPtr const &bitSet)
{
bool doAll = bitSet->get(0);
if(headNode->isStructure) {
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(headNode);
updateStructureNodeFromBitSet(copyPVStructure,node,bitSet,true,doAll);
} else {
CopyMasterNodePtr masterNode = static_pointer_cast<CopyMasterNode>(headNode);
updateSubFieldFromBitSet(copyPVStructure, masterNode->masterPVField,bitSet, true,doAll);
}
}
void PVCopy::updateMaster(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet)
{
bool doAll = bitSet->get(0);
if(headNode->isStructure) {
CopyStructureNodePtr node =
static_pointer_cast<CopyStructureNode>(headNode);
updateStructureNodeFromBitSet(
copyPVStructure,node,bitSet,false,doAll);
} else {
CopyMasterNodePtr masterNode =
static_pointer_cast<CopyMasterNode>(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<CopyMasterNode>(node);
String name = masterNode->masterPVField->getFullName();
*builder += " masterField " + name;
return;
}
CopyStructureNodePtr structureNode =
static_pointer_cast<CopyStructureNode>(node);
CopyNodePtrArrayPtr nodes = structureNode->nodes;
for(size_t i=0; i<nodes->size(); ++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; i<length; ++i) {
String const &fieldName = fromRequestFieldNames[i];
PVFieldPtr pvMasterField = pvMaster->getSubField(fieldName);
if(pvMasterField==NULL) continue;
FieldConstPtr field = pvMasterField->getField();
if(field->getType()==epics::pvData::structure) {
PVStructurePtr pvRequestStructure = static_pointer_cast<PVStructure>(
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<PVStructure>(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<PVStructure>(pvField);
size_t number = copyPVFields.size();
CopyNodePtrArrayPtr nodes(new CopyNodePtrArray());
nodes->reserve(number);
for(size_t i=0; i<number; i++) {
PVFieldPtr copyPVField = copyPVFields[i];
String fieldName = copyPVField->getFieldName();
PVStructurePtr requestPVStructure = static_pointer_cast<PVStructure>(
pvFromRequest->getSubField(fieldName));
PVStructurePtr pvSubFieldOptions;
PVFieldPtr pvField = requestPVStructure->getSubField("_options");
if(pvField!=NULL) pvSubFieldOptions = static_pointer_cast<PVStructure>(pvField);
PVFieldPtr pvMasterField;
PVFieldPtrArray const & pvMasterFields = pvMasterStructure->getPVFields();
for(size_t j=0; i<pvMasterFields.size(); j++ ) {
if(pvMasterFields[j]->getFieldName().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<PVStructure>(pvMasterField),
requestPVStructure,
static_pointer_cast<PVStructure>(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; i<structureNode->nodes->size(); i++) {
CopyNodePtr node = (*structureNode->nodes)[i];
PVFieldPtr pvField = pvCopy->getSubField(node->structureOffset);
if(node->isStructure) {
PVStructurePtr xxx = static_pointer_cast<PVStructure>(pvField);
CopyStructureNodePtr yyy =
static_pointer_cast<CopyStructureNode>(node);
updateStructureNodeSetBitSet(xxx,yyy,bitSet);
} else {
CopyMasterNodePtr masterNode =
static_pointer_cast<CopyMasterNode>(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<PVStructure>(pvCopy);
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
PVStructurePtr pvMasterStructure =
static_pointer_cast<PVStructure>(pvMaster);
PVFieldPtrArray const & pvMasterFields =
pvMasterStructure->getPVFields();
size_t length = pvCopyFields.size();
for(size_t i=0; i<length; i++) {
updateSubFieldSetBitSet(pvCopyFields[i],pvMasterFields[i],bitSet);
}
}
void PVCopy::updateStructureNodeFromBitSet(
PVStructurePtr const &pvCopy,
CopyStructureNodePtr const &structureNode,
BitSetPtr const &bitSet,
bool toCopy,
bool doAll)
{
size_t offset = structureNode->structureOffset;
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; i<nodes->size(); i++) {
CopyNodePtr node = (*nodes)[i];
PVFieldPtr pvField = pvCopy->getSubField(node->structureOffset);
if(node->isStructure) {
PVStructurePtr xxx = static_pointer_cast<PVStructure>(pvField);
CopyStructureNodePtr subStructureNode =
static_pointer_cast<CopyStructureNode>(node);
updateStructureNodeFromBitSet(
xxx,subStructureNode,bitSet,toCopy,doAll);
} else {
CopyMasterNodePtr masterNode =
static_pointer_cast<CopyMasterNode>(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<PVStructure>(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<PVStructure>(pvMasterField);
PVFieldPtrArray const & pvMasterFields =
pvMasterStructure->getPVFields();
for(size_t i=0; i<pvCopyFields.size(); i++) {
updateSubFieldFromBitSet(
pvCopyFields[i],
pvMasterFields[i],
bitSet,toCopy,doAll);
}
} else {
if(toCopy) {
convert->copy(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<CopyMasterNode>(node);
size_t off = masterNode->masterPVField->getFieldOffset();
size_t nextOffset = masterNode->masterPVField->getNextFieldOffset();
if(offset>= off && offset<nextOffset) return masterNode;
} else {
CopyStructureNodePtr subNode =
static_pointer_cast<CopyStructureNode>(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<CopyMasterNode>(node);
return masterNode;
}
CopyStructureNodePtr subNode =
static_pointer_cast<CopyStructureNode>(node);
return getMasterNode(subNode,structureOffset);
}
return NULLCopyMasterNode;
}
}}

230
src/copy/pvCopy.h Normal file
View File

@@ -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 <string>
#include <stdexcept>
#include <memory>
#include <shareLib.h>
#include <pv/pvData.h>
#include <pv/bitSet.h>
namespace epics { namespace pvData{
class PVCopyTraverseMasterCallback;
typedef std::tr1::shared_ptr<PVCopyTraverseMasterCallback> 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<PVCopy> PVCopyPtr;
struct CopyNode;
typedef std::tr1::shared_ptr<CopyNode> CopyNodePtr;
struct CopyMasterNode;
typedef std::tr1::shared_ptr<CopyMasterNode> CopyMasterNodePtr;
struct CopyStructureNode;
typedef std::tr1::shared_ptr<CopyStructureNode> 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<PVCopy>
{
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 &copyPVStructure,
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 &copyPVStructure,
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 &copyPVStructure,
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 &copyPVStructure,
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 */

View File

@@ -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());
}
}

View File

@@ -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
{

View File

@@ -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

View File

@@ -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 <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#define epicsExportSharedSymbols
#include <pv/noDefaultMethods.h>
#include <pv/pvData.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/lock.h>
namespace epics { namespace pvData {
PVAuxInfo::PVAuxInfo(PVField * pvField)
: pvField(pvField),
pvInfos(std::map<String,std::tr1::shared_ptr<PVScalar> > ())
{
}
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);
}
}
}}

View File

@@ -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;
}

View File

@@ -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; i<fieldNames.size(); i++) {
if(newPVField->getFieldName().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<Structure> parentStructure = const_pointer_cast<Structure>(
parent->getStructure());
PVFieldPtrArray pvFields = parent->getPVFields();
for(size_t i=0; i<pvFields.size(); i++) {
if(pvFields[i].get()==this) {
parentStructure->renameField(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;
}

View File

@@ -60,7 +60,7 @@ PVStructure::PVStructure(StructureConstPtr const & structurePtr)
pvFields.reserve(numberFields);
PVDataCreatePtr pvDataCreate = getPVDataCreate();
for(size_t i=0; i<numberFields; i++) {
pvFields.push_back(pvDataCreate->createPVField(fields[i]));
pvFields.push_back(pvDataCreate->createPVField(fields[i]));
}
for(size_t i=0; i<numberFields; i++) {
pvFields[i]->setParentAndName(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<PVFieldPtrArray *>(&pvFields);
xxx->push_back(pvField);
FieldConstPtr field = getFieldCreate()->appendField(
structurePtr,fieldName,pvField->getField());
replaceField(field);
structurePtr = static_pointer_cast<const Structure>(field);
StringArray fieldNames = structurePtr->getFieldNames();
for(size_t i=0; i<newLength; i++) {
pvFields[i]->setParentAndName(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<PVFieldPtrArray *>(&this->pvFields);
xxx->reserve(newLength);
for(size_t i=0; i<extra; i++) {
xxx->push_back(pvFields[i]);
}
FieldConstPtrArray fields;
fields.reserve(extra);
for(size_t i=0; i<extra; i++) fields.push_back(pvFields[i]->getField());
FieldConstPtr field = getFieldCreate()->appendFields(
structurePtr,fieldNames,fields);
replaceField(field);
structurePtr = static_pointer_cast<const Structure>(field);
StringArray names = structurePtr->getFieldNames();
for(size_t i=0; i<newLength; i++) {
(*xxx)[i]->setParentAndName(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; i<origLength; i++) {
if(origPVFields[i]!=pvField) {
newFieldNames.push_back(origPVFields[i]->getFieldName());
newPVFields.push_back(origPVFields[i]);
fields.push_back(origFields[i]);
}
}
PVFieldPtrArray * xxx = const_cast<PVFieldPtrArray *>(&pvFields);
xxx->swap(newPVFields);
FieldConstPtr field = getFieldCreate()->createStructure(
structurePtr->getID(),newFieldNames,fields);
replaceField(field);
structurePtr = static_pointer_cast<const Structure>(field);
StringArray fieldNames = structurePtr->getFieldNames();
for(size_t i=0; i<newLength; i++) {
pvFields[i]->setParentAndName(this,fieldNames[i]);
}
}
PVBooleanPtr PVStructure::getBooleanField(String const &fieldName)
{
@@ -341,18 +237,6 @@ PVUnionArrayPtr PVStructure::getUnionArrayField(
return getSubField<PVUnionArray>(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);

View File

@@ -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)

View File

@@ -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()

View File

@@ -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();

View File

@@ -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++;
}

View File

@@ -15,30 +15,33 @@
#include <pv/pvSubArrayCopy.h>
namespace epics { namespace pvData {
using std::cout;
using std::endl;
template<typename T>
void copy(
PVValueArray<T> & pvFrom,
size_t fromOffset,
size_t fromStride,
PVValueArray<T> & 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<T> temp(capacity);
typename PVValueArray<T>::const_svector vecFrom = pvFrom.view();
typename PVValueArray<T>::const_svector vecTo = pvTo.view();
for(size_t i=0; i<toOffset; ++i) temp[i] = vecTo[i];
for(size_t i=0; i<len; ++i) temp[i + toOffset] = vecFrom[i + fromOffset];
for(size_t i=len + toOffset; i<capacity; ++i) temp[i] = vecTo[i];
for(size_t i=0; i<pvTo.getLength(); ++i) temp[i] = vecTo[i];
for(size_t i=pvTo.getLength(); i< capacity; ++i) temp[i] = T();
for(size_t i=0; i<count; ++i) temp[i*toStride + toOffset] = vecFrom[i*fromStride+fromOffset];
shared_vector<const T> 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<PVValueArray<boolean> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<boolean> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<boolean>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvByte:
{
copy(dynamic_cast<PVValueArray<int8> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<int8> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<int8>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvShort:
{
copy(dynamic_cast<PVValueArray<int16> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<int16> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<int16>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvInt:
{
copy(dynamic_cast<PVValueArray<int32> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<int32> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<int32>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvLong:
{
copy(dynamic_cast<PVValueArray<int64> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<int64> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<int64>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvUByte:
{
copy(dynamic_cast<PVValueArray<uint8> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<uint8> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<uint8>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvUShort:
{
copy(dynamic_cast<PVValueArray<uint16> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<uint16> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<uint16>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvUInt:
{
copy(dynamic_cast<PVValueArray<uint32> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<uint32> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<uint32>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvULong:
{
copy(dynamic_cast<PVValueArray<uint64> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<uint64> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<uint64>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvFloat:
{
copy(dynamic_cast<PVValueArray<float> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<float> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<float>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvDouble:
{
copy(dynamic_cast<PVValueArray<double> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<double> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<double>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvString:
{
copy(dynamic_cast<PVValueArray<String> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<String> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<String>& >(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<PVStructurePtr> temp(capacity);
PVValueArray<PVStructurePtr>::const_svector vecFrom = from.view();
PVValueArray<PVStructurePtr>::const_svector vecTo = to.view();
for(size_t i=0; i<toOffset; ++i) temp[i] = vecTo[i];
for(size_t i=0; i<len; ++i) temp[i + toOffset] = vecFrom[i + fromOffset];
for(size_t i=len + toOffset; i<capacity; ++i) temp[i] = vecTo[i];
PVValueArray<PVStructurePtr>::const_svector vecFrom = pvFrom.view();
PVValueArray<PVStructurePtr>::const_svector vecTo = pvTo.view();
for(size_t i=0; i<pvTo.getLength(); ++i) temp[i] = vecTo[i];
for(size_t i=pvTo.getLength(); i< capacity; ++i)
temp[i] = getPVDataCreate()->createPVStructure(toStructure->getStructure());
for(size_t i=0; i<count; ++i) temp[i*toStride + toOffset] = vecFrom[i*pvFromStride+pvFromOffset];
shared_vector<const PVStructurePtr> 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<ScalarType>(pvFromType);
ScalarType pvToScalarType = static_cast<ScalarType>(pvToType);
if(pvFromScalarType!=pvToScalarType){
throw std::invalid_argument("pvSubArrayCopy: pvFrom and pvTo different types");
}
}
if(type==scalarArray) {
copy(dynamic_cast<PVScalarArray &>(from) ,fromOffset,
dynamic_cast<PVScalarArray&>(to),
toOffset,len);
if(pvTo.isImmutable()) throw std::invalid_argument("pvSubArrayCopy: pvTo is immutable");
if(pvFromType==scalarArray) {
copy(dynamic_cast<PVScalarArray &>(pvFrom) ,pvFromOffset,pvFromStride,
dynamic_cast<PVScalarArray&>(pvTo),
pvToOffset,pvToStride,count);
}
if(type==structureArray) {
copy(dynamic_cast<PVStructureArray &>(from) ,fromOffset,
dynamic_cast<PVStructureArray&>(to),
toOffset,len);
if(pvFromType==structureArray) {
copy(dynamic_cast<PVStructureArray &>(pvFrom) ,pvFromOffset,pvFromStride,
dynamic_cast<PVStructureArray&>(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);
}
}}

View File

@@ -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;
}
}};

View File

@@ -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 */

View File

@@ -3,6 +3,7 @@
SRC_DIRS += $(PVDATA_SRC)/monitor
INC += monitor.h
INC += monitorPlugin.h
LIBSRCS += monitor.cpp
LIBSRCS += monitorPlugin.cpp

View File

@@ -15,6 +15,7 @@
#include <pv/pvData.h>
#include <pv/sharedPtr.h>
#include <pv/bitSet.h>
#include <pv/requester.h>
#include <shareLib.h>

View File

@@ -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 <pv/monitorPlugin.h>
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<MonitorPluginCreatorPtr>::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<MonitorPluginCreatorPtr>::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<MonitorPluginCreatorPtr>::iterator iter;
for (iter = monitorPluginList.begin();iter!=monitorPluginList.end();++iter)
{
std::cout << (*iter)->getName() << std::endl;
}
mutex.unlock();
}
}}

177
src/monitor/monitorPlugin.h Normal file
View File

@@ -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 <list>
#include <pv/pvData.h>
#include <pv/sharedPtr.h>
#include <pv/bitSet.h>
#include <pv/monitor.h>
#include <shareLib.h>
namespace epics { namespace pvData {
/**
* typedef for a pointer to a MonitorPlugin
*/
class MonitorPlugin;
typedef std::tr1::shared_ptr<MonitorPlugin> MonitorPluginPtr;
/**
* typedef for a pointer to a MonitorPluginCreator
*/
class MonitorPluginCreator;
typedef std::tr1::shared_ptr<MonitorPluginCreator> MonitorPluginCreatorPtr;
/**
* typedef for a pointer to a MonitorPluginManager
*/
class MonitorPluginManager;
typedef std::tr1::shared_ptr<MonitorPluginManager> 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<MonitorPluginCreatorPtr> monitorPluginList;
epics::pvData::Mutex mutex;
};
}}
#endif /* MONITORPLUGIN_H */

View File

@@ -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<PVStructure>(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;

View File

@@ -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<PVStructure>(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;

View File

@@ -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<PVStructure>(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;
}

View File

@@ -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<PVStructure>(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<PVStringArray>(pvScalarArray);

View File

@@ -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<PVStructure>(pvField);
PVStructure* pvStructure = xxx.get();
while(true) {

View File

@@ -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 <string>
#include <map>
#include <stdexcept>
@@ -30,7 +23,6 @@
#include <iomanip>
#include <pv/pvIntrospect.h>
#include <pv/requester.h>
#include <pv/typeCast.h>
#include <pv/sharedVector.h>
@@ -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<typename T> class PVScalarValue;
template<typename T> class PVValueArray;
/**
* typedef for a pointer to a PVAuxInfo.
*/
typedef std::tr1::shared_ptr<PVAuxInfo> PVAuxInfoPtr;
/**
* typedef for a pointer to a PostHandler.
*/
@@ -198,67 +184,6 @@ typedef std::tr1::shared_ptr<PVUnionArrayPtrArray> PVUnionArrayPtrArrayPtr;
class PVDataCreate;
typedef std::tr1::shared_ptr<PVDataCreate> 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<String,PVScalarPtr> PVInfoMap;
typedef std::map<String,PVScalarPtr>::iterator PVInfoIter;
typedef std::pair<String,PVScalarPtr> 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<typename T>
class PVArrayData {
private:
std::vector<T> init;
public:
POINTER_DEFINITIONS(PVArrayData);
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
/**
* The data array.
*/
std::vector<T> & 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<PVT>();
}
/**
* 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<T> svector;
typedef ::epics::pvData::shared_vector<const T> const_svector;
// begin deprecated
typedef PVArrayData<T> ArrayDataType;
typedef std::vector<T> vector;
typedef const std::vector<T> const_vector;
typedef std::tr1::shared_ptr<vector> 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<T>(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<T> svector;
typedef ::epics::pvData::shared_vector<const T> const_svector;
// begin deprecated
typedef PVArrayData<T> ArrayDataType;
typedef std::vector<T> vector;
typedef const std::vector<T> const_vector;
typedef std::tr1::shared_ptr<vector> 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<const Array>(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<PVStructurePtr> 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<PVStructurePtr> ArrayDataType;
typedef std::vector<PVStructurePtr> vector;
typedef const std::vector<PVStructurePtr> const_vector;
typedef std::tr1::shared_ptr<vector> 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<const Array>(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<PVUnionPtr> 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<PVUnionPtr> ArrayDataType;
typedef std::vector<PVUnionPtr> vector;
typedef const std::vector<PVUnionPtr> const_vector;
typedef std::tr1::shared_ptr<vector> 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<const Array>(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<boolean> BooleanArrayData;
typedef PVValueArray<boolean> PVBooleanArray;
typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
typedef PVArrayData<int8> ByteArrayData;
typedef PVValueArray<int8> PVByteArray;
typedef std::tr1::shared_ptr<PVByteArray> PVByteArrayPtr;
typedef PVArrayData<int16> ShortArrayData;
typedef PVValueArray<int16> PVShortArray;
typedef std::tr1::shared_ptr<PVShortArray> PVShortArrayPtr;
typedef PVArrayData<int32> IntArrayData;
typedef PVValueArray<int32> PVIntArray;
typedef std::tr1::shared_ptr<PVIntArray> PVIntArrayPtr;
typedef PVArrayData<int64> LongArrayData;
typedef PVValueArray<int64> PVLongArray;
typedef std::tr1::shared_ptr<PVLongArray> PVLongArrayPtr;
typedef PVArrayData<uint8> UByteArrayData;
typedef PVValueArray<uint8> PVUByteArray;
typedef std::tr1::shared_ptr<PVUByteArray> PVUByteArrayPtr;
typedef PVArrayData<uint16> UShortArrayData;
typedef PVValueArray<uint16> PVUShortArray;
typedef std::tr1::shared_ptr<PVUShortArray> PVUShortArrayPtr;
typedef PVArrayData<uint32> UIntArrayData;
typedef PVValueArray<uint32> PVUIntArray;
typedef std::tr1::shared_ptr<PVUIntArray> PVUIntArrayPtr;
typedef PVArrayData<uint64> ULongArrayData;
typedef PVValueArray<uint64> PVULongArray;
typedef std::tr1::shared_ptr<PVULongArray> PVULongArrayPtr;
typedef PVArrayData<float> FloatArrayData;
typedef PVValueArray<float> PVFloatArray;
typedef std::tr1::shared_ptr<PVFloatArray> PVFloatArrayPtr;
typedef PVArrayData<double> DoubleArrayData;
typedef PVValueArray<double> PVDoubleArray;
typedef std::tr1::shared_ptr<PVDoubleArray> PVDoubleArrayPtr;
typedef PVArrayData<String> StringArrayData;
typedef PVValueArray<String> PVStringArray;
typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
@@ -1673,7 +1437,12 @@ typedef std::tr1::shared_ptr<PVStringArray> 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<typename PVT>
std::tr1::shared_ptr<PVT> createPVScalar()
{
return std::tr1::static_pointer_cast<PVT>(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<typename PVAT>
std::tr1::shared_ptr<PVAT> createPVScalarArray()
{
return std::tr1::static_pointer_cast<PVAT>(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<typename PVT>
std::tr1::shared_ptr<PVT> createPVScalar()
{
return std::tr1::static_pointer_cast<PVT>(createPVScalar(PVT::typeCode));
}
template<typename PVAT>
std::tr1::shared_ptr<PVAT> createPVScalarArray()
{
return std::tr1::static_pointer_cast<PVAT>(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 */

View File

@@ -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<FieldConstPtr> FieldConstPtrArray;
* typedef for a shared pointer to an immutable Scalar.
*/
typedef std::tr1::shared_ptr<const Scalar> ScalarConstPtr;
/**
* typedef for a shared pointer to an immutable Array.
*/
typedef std::tr1::shared_ptr<const Array> 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<FieldCreate> 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.

View File

@@ -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<typename T>
void copy(
epicsShareExtern void copy(
PVValueArray<T> & pvFrom,
size_t fromOffset,
size_t fromStride,
PVValueArray<T> & 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);
}}

View File

@@ -98,335 +98,6 @@ typedef uint64_t uint64;
*/
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;
/**
* A byte array.
*/
typedef std::vector<int8> ByteArray;
typedef std::tr1::shared_ptr<ByteArray> ByteArrayPtr;
inline int8 * get(ByteArray &value)
{
return &value[0];
}
inline int8 const * get(ByteArray const &value)
{
return static_cast<int8 const *>(&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<int8>::iterator ByteArray_iterator;
typedef std::vector<int8>::const_iterator ByteArray_const_iterator;
/**
* A short array.
*/
typedef std::vector<int16> ShortArray;
typedef std::tr1::shared_ptr<ShortArray> ShortArrayPtr;
inline int16 * get(ShortArray &value)
{
return &value[0];
}
inline int16 const * get(ShortArray const &value)
{
return static_cast<int16 const *>(&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<int16>::iterator ShortArray_iterator;
typedef std::vector<int16>::const_iterator ShortArray_const_iterator;
/**
* A int array.
*/
typedef std::vector<int32> IntArray;
typedef std::tr1::shared_ptr<IntArray> IntArrayPtr;
inline int32 * get(IntArray &value)
{
return &value[0];
}
inline int32 const * get(IntArray const &value)
{
return static_cast<int32 const *>(&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<int32>::iterator IntArray_iterator;
typedef std::vector<int32>::const_iterator IntArray_const_iterator;
/**
* A long array.
*/
typedef std::vector<int64> LongArray;
typedef std::tr1::shared_ptr<LongArray> LongArrayPtr;
inline int64 * get(LongArray &value)
{
return &value[0];
}
inline int64 const * get(LongArray const &value)
{
return static_cast<int64 const *>(&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<int64>::iterator LongArray_iterator;
typedef std::vector<int64>::const_iterator LongArray_const_iterator;
/**
* An unsigned byte array.
*/
typedef std::vector<uint8> UByteArray;
typedef std::tr1::shared_ptr<UByteArray> UByteArrayPtr;
inline uint8 * get(UByteArray &value)
{
return &value[0];
}
inline uint8 const * get(UByteArray const &value)
{
return static_cast<uint8 const *>(&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<uint8>::iterator UByteArray_iterator;
typedef std::vector<uint8>::const_iterator UByteArray_const_iterator;
/**
* An unsigned short array.
*/
typedef std::vector<uint16> UShortArray;
typedef std::tr1::shared_ptr<UShortArray> UShortArrayPtr;
inline uint16 * get(UShortArray &value)
{
return &value[0];
}
inline uint16 const * get(UShortArray const &value)
{
return static_cast<uint16 const *>(&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<uint16>::iterator UShortArray_iterator;
typedef std::vector<uint16>::const_iterator UShortArray_const_iterator;
/**
* An unsigned int array.
*/
typedef std::vector<uint32> UIntArray;
typedef std::tr1::shared_ptr<UIntArray> UIntArrayPtr;
inline uint32 * get(UIntArray &value)
{
return &value[0];
}
inline uint32 const * get(UIntArray const &value)
{
return static_cast<uint32 const *>(&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<uint32>::iterator UIntArray_iterator;
typedef std::vector<uint32>::const_iterator UIntArray_const_iterator;
/**
* An unsigned long array.
*/
typedef std::vector<uint64> ULongArray;
typedef std::tr1::shared_ptr<ULongArray> ULongArrayPtr;
inline uint64 * get(ULongArray &value)
{
return &value[0];
}
inline uint64 const * get(ULongArray const &value)
{
return static_cast<uint64 const *>(&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<uint64>::iterator ULongArray_iterator;
typedef std::vector<uint64>::const_iterator ULongArray_const_iterator;
/**
* A float array.
*/
typedef std::vector<float> FloatArray;
typedef std::tr1::shared_ptr<FloatArray> FloatArrayPtr;
inline float * get(FloatArray &value)
{
return &value[0];
}
inline float const * get(FloatArray const &value)
{
return static_cast<float const *>(&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<float>::iterator FloatArray_iterator;
typedef std::vector<float>::const_iterator FloatArray_const_iterator;
/**
* A double array.
*/
typedef std::vector<double> DoubleArray;
typedef std::tr1::shared_ptr<DoubleArray> DoubleArrayPtr;
inline double * get(DoubleArray &value)
{
return &value[0];
}
inline double const * get(DoubleArray const &value)
{
return static_cast<double const *>(&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<double>::iterator DoubleArray_iterator;
typedef std::vector<double>::const_iterator DoubleArray_const_iterator;
/**
* A string array.
*/

View File

@@ -20,6 +20,10 @@
namespace epics { namespace pvData {
class StandardField;
typedef std::tr1::shared_ptr<StandardField> 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<StandardField> 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;

View File

@@ -20,6 +20,10 @@
#include <shareLib.h>
namespace epics { namespace pvData {
class StandardPVField;
typedef std::tr1::shared_ptr<StandardPVField> 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<StandardPVField> 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();

View File

@@ -3,5 +3,6 @@ include $(TOP)/configure/CONFIG
DIRS += misc
DIRS += pv
DIRS += property
DIRS += copy
include $(TOP)/configure/RULES_DIRS

22
testApp/copy/Makefile Normal file
View File

@@ -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

View File

@@ -0,0 +1,327 @@
/* testCreateRequest.cpp */
/* Author: Matej Sekoranja Date: 2010.12.27 */
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <epicsUnitTest.h>
#include <testMain.h>
#include <pv/createRequest.h>
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 <<endl;}
PVStructurePtr pvRequest = createRequest->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 <<endl;}
testOk1(pvRequest!=NULL);
if(debug) { cout << pvRequest->dumpValue(cout) << endl;}
PVStringPtr pvString = pvRequest->getSubField<PVString>("record.a");
String sval = pvString->get();
testOk(sval.compare("b")==0,"record.a = b");
pvString = pvRequest->getSubField<PVString>("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 <<endl;}
testOk1(pvRequest!=NULL);
if(debug) { cout << pvRequest->dumpValue(cout) << endl;}
pvString = pvRequest->getSubField<PVString>("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 <<endl;}
if(pvRequest==NULL) {
cout << createRequest->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 <<endl;}
if(pvRequest==NULL) {
cout << createRequest->getMessage() << endl;
}
testOk1(pvRequest!=NULL);
pvString = pvRequest->getSubField<PVString>("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 <<endl;}
if(pvRequest==NULL) {
cout << createRequest->getMessage() << endl;
}
testOk1(pvRequest!=NULL);
pvString = pvRequest->getSubField<PVString>("field.a.b._options.x");
sval = pvString->get();
testOk(sval.compare("y")==0,"field.a.b._options.x = y");
pvString = pvRequest->getSubField<PVString>("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 <<endl;}
if(pvRequest==NULL) {
cout << createRequest->getMessage() << endl;
}
testOk1(pvRequest!=NULL);
pvString = pvRequest->getSubField<PVString>("field.a.a._options.a");
sval = pvString->get();
testOk(sval.compare("b")==0,"field.a.a._options.a = b");
pvString = pvRequest->getSubField<PVString>("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<PVString>("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") <<endl << request <<endl;}
if(pvRequest==NULL) {
cout << "reason " << createRequest->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") <<endl << request <<endl;}
if(pvRequest==NULL) {
cout << "reason " << createRequest->getMessage() << endl;
}
testOk1(pvRequest!=NULL);
pvString = pvRequest->getSubField<PVString>("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") <<endl << request <<endl;}
if(pvRequest==NULL) {
cout << "reason " << createRequest->getMessage() << endl;
}
testOk1(pvRequest!=NULL);
pvString = pvRequest->getSubField<PVString>("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<PVString>("field.timeStamp._options.algorithm");
sval = pvString->get();
testOk(sval.compare("onChange")==0,"field.timeStamp._options.algorithm = onChange");
pvString = pvRequest->getSubField<PVString>("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") <<endl << request <<endl;}
if(pvRequest==NULL) {
cout << "reason " << createRequest->getMessage() << endl;
}
testOk1(pvRequest!=NULL);
pvString = pvRequest->getSubField<PVString>("record.int");
sval = pvString->get();
testOk(sval.compare("2")==0,"record.int = 2");
pvString = pvRequest->getSubField<PVString>("record.float");
sval = pvString->get();
testOk(sval.compare("3.14159")==0,"record.float = 3.14159");
testOk1(pvRequest->getSubField("field.alarm")!=NULL);
pvString = pvRequest->getSubField<PVString>("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") <<endl << request <<endl;}
if(pvRequest==NULL) {
cout << "reason " << createRequest->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") <<endl << request <<endl;}
if(pvRequest==NULL) {
cout << "reason " << createRequest->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") <<endl << request <<endl;}
if(pvRequest==NULL) {
cout << "reason " << createRequest->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") <<endl << request <<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 = 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") <<endl << request <<endl;}
pvRequest = createRequest->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") <<endl << request <<endl;}
if(debug) { cout << endl << "Error Expected for next call!!" << endl;}
pvRequest = createRequest->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();
}

393
testApp/copy/testPVCopy.cpp Normal file
View File

@@ -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 <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <iostream>
#include <epicsUnitTest.h>
#include <testMain.h>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/convert.h>
#include <pv/pvCopy.h>
#include <pv/createRequest.h>
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<PVScalar>(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<PVScalar>(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<double> values(n);
shared_vector<const double> cvalues;
pvValueMaster = pvMaster->getScalarArrayField(valueNameMaster,scalarType);
for(size_t i=0; i<n; i++) values[i] = i;
const shared_vector<const double> 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<n; i++) values[i] = i + .06;
const shared_vector<const double> 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<n; i++) values[i] = i + 1.0;
const shared_vector<const double> 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<n; i++) values[i] = i + 2.0;
const shared_vector<const double> 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();
}

View File

@@ -307,8 +307,6 @@ void testScalar() {
template<typename PVT>
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());

View File

@@ -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

View File

@@ -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 <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <epicsUnitTest.h>
#include <testMain.h>
#include <pv/requester.h>
#include <pv/pvIntrospect.h>
#include <pv/pvData.h>
#include <pv/convert.h>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
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; i<pvFields.size(); i++) {
PVFieldPtr pvField = pvFields[i];
testOk1(pvField->getParent()==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<PVStructure>(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<PVString>(
pvDataCreate->createPVScalar(pvString));
pvStringField->put("value,timeStamp");
PVFieldPtr pvField = pvStringField;
pvParent->appendPVField("fieldlist",pvField);
pvStringField = static_pointer_cast<PVString>(
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<PVString>(
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<PVString>(
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<PVString>(
pvDataCreate->createPVScalar(pvString));
pvStringField->put(oneValue);
names.push_back(oneName);
pvFields.push_back(pvStringField);
pvStringField = static_pointer_cast<PVString>(
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();
}

View File

@@ -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 <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <epicsUnitTest.h>
#include <testMain.h>
#include <pv/requester.h>
#include <pv/pvIntrospect.h>
#include <pv/pvData.h>
#include <pv/convert.h>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
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; i<number; i++) {
PVFieldPtr pvField = fields[i];
if(pvField->getField()->getType()==structure) {
PVStructurePtr xxx = static_pointer_cast<PVStructure>(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();
}

View File

@@ -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<PVString>(
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<PVStructure>("record");
buffer.clear();
xxx->toString(&buffer);
cout << buffer.c_str() << endl;
xxx = pvTop->getSubField<PVStructure>("field");
buffer.clear();
xxx->toString(&buffer);
cout << buffer.c_str() << endl;
PVStringPtr pvString = pvTop->getSubField<PVString>("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();
}

View File

@@ -26,6 +26,8 @@
using namespace epics::pvData;
using std::tr1::static_pointer_cast;
using std::cout;
using std::endl;
namespace {

View File

@@ -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();
}