Files
pvData/documentation/pvDataCPP.html

3831 lines
132 KiB
HTML

<?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</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 class="head">
<h1>EPICS pvDataCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 28-Oct-2013</h2>
<dl>
<dt>Latest version:</dt>
<dd><a
href="pvDataCPP.html">pvDataCPP.html</a>
</dd>
<dt>This version:</dt>
<dd><a
href="pvDataCPP_20131023.html">pvDataCPP_20131023.html</a>
</dd>
<dt>Previous version:</dt>
<dd><a
href="pvDataCPP_20130516.html">pvDataCPP_20130516.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
<dd>Michael Davidsaver, BNL</dd>
<dd>Matej Sekoranja, CosyLab</dd>
</dl>
<p class="copyright">This product is made available subject to acceptance of the <a
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source
license.</a></p>
<hr />
</div>
<h2 class="nocount">Abstract</h2>
<p>PVData is a computer software package for the efficient
storage, access, and communication, of structured data.
pvDataCPP is the C++ implementation of pvData.
It is one part of the set of related products in the EPICS
V4 control system programming environment:<br />
<a href="http://epics-pvdata.sourceforge.net/relatedDocumentsV4.html">relatedDocumentsV4.html</a>
</p>
<h2 class="nocount">Status of this Document</h2>
<p>This is the 28-Oct-2013 version of the C++ implementation of pvData.
This version describes the changes since the 4.3.0 release of Epics Version 4.
</p>
<p> The text describes software which is a complete implementation of pvData as
currently planned by the EPICS V4 Working Group. </p> </p>
<p>The major changes since the 4.3.0 release are:</p>
<dl>
<dt>shared_vector</dt>
<dd>This provides many of the features of std:vector but uses std::shared_ptr
for the raw array.</dd>
<dt>Arrays</dt>
<p>The implementation of PVValueArray and PVStructureArray now inforce Copy On Write (COW)
and use shared_vector for the raw array.</p>
</dl>
<div id="toc">
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
</div>
<div id="contents" class="contents">
<h2>Introduction</h2>
<p>pvData is one of a set of related projects. It describes and implements the
data that the other projects support. Thus it is not useful by itself but
understanding pvData is required in order to understand the other projects. The
reader should also become familar with project pvAccess, which is
located via the same sourceforge site as this project.</p>
<p>The Java and C++ implementation of pvData implement the same data model but
differ in implementation because of the differences between Java and C++.</p>
<p>It is a good idea to read all of pvDataJava.html but <b>read at least the
first two chapters:</b></p>
<dl>
<dt>Introduction</dt>
<dd>A brief descripton of pvData.</dd>
<dt>PVData Meta Language</dt>
<dd>A language used to describe data.</dd>
</dl>
<p>The material in these two chapters is NOT repeated in this documentation.</p>
<p>Doxygen documentation is available at <a
href="./html/index.html">doxygenDoc</a></p>
<h2>Namespace and Memory Management</h2>
<h3>Namespace</h3>
<p>All code in project pvDataCPP appears in namespace: </p>
<pre>namespace epics { namespace pvData {
// ...
}}</pre>
<h3>Memory Managemment</h3>
<p>pvDataCPP introspection and data objects are designed to be shared. They are
made availiable via <b>std::tr1::shared_ptr</b>. In addition arrays are
implemented via <b>shared_vector</b>. The following naming conventions are used
in typedefs:</p>
<dl>
<dt>Ptr</dt>
<dd>When <b>Ptr</b> appears it stands for <b>std::tr1::shared_ptr</b>.</dd>
<dt>Array</dt>
<dd>When <b>Array</b> appears it stands for <b>std::vector</b>.</dd>
</dl>
<p>As an example pvType.h includes the following definitions:</p>
<pre>typedef std::vector&lt;double&gt; DoubleArray;
typedef std::tr1::shared_ptr&lt;DoubleArray&gt; DoubleArrayPtr;
inline double * get(DoubleArray &amp;value)
{
return &amp;value[0];
}
inline const double * get(const DoubleArray &amp;value)
{
return static_cast&lt;const double *&gt;(&amp;value[0]);
}
typedef std::vector&lt;double&gt;::iterator DoubleArray_iterator;
typedef std::vector&lt;double&gt;::const_iterator DoubleArray_const_iterator;</pre>
<p>where</p>
<dl>
<dt>DoubleArray</dt>
<dd>This defines a vector for an array of the primitive type "double".</dd>
<dt>DoubleArrayPtr</dt>
<dd>This devices a shared pointer to a vector for an array of the primitive
type "double".</dd>
<dt>get</dt>
<dd>This gets the raw array of doubles that the DoubleArray holds.</dd>
<dt>DoubleArray_iterator</dt>
<dd>This gets a iterator for the DoubleArray.</dd>
<dt>DoubleArray_const_iterator</dt>
<dd>This gets a constant iterator for the DoubleArray.</dd>
</dl>
<h2>pvDataApp/pv</h2>
<h3>Overview</h3>
<p>Directory <b>pvDataApp/pv</b> has header files that completely describe pvData.
The implementation is provided in directory <b>pvDataApp/factory</b>.
Test programs appears in <b>testApp/pv</b>.</p>
<p><b>NOTES</b>:</p>
<dl>
<dt>interface</dt>
<dd>The documention uses the word <b>interface</b>. This is an analogy for
what the Java implementation implements, i. e. package pv provides Java
interfaces. C++ does not have interfaces but directory pv defines classes
with public members that are similar to the Java interfaces. Most of the
implementation is in factory.</dd>
<dt>Naming Convertions</dt>
<dd>The naming convertions for variables, methods, and classes follow the
Java convertions, i. e. class name begin with an upper case letter,
variables and methods begin with a lower case letter.</dd>
</dl>
<p>A PVStructure is a field that contains an array of subfields. Each field has
code for accessing the field. The interface for each field is an interface that
extends PVField. Each field also has an introspection interface, which an
extension of Field. This section describes the complete set of C++
introspection and data interfaces for pvData. </p>
<p>Class FieldCreate creates introspection objects. Class PVDataCreate creates
data objects. Class Convert provides a rich set of methods for converting and
copying data between fields.</p>
<p>Directory pvDataApp/pv has the following header files:</p>
<dl>
<dt>pvType.h</dt>
<dd>C++ definitions for primitive types.</dd>
<dt>pvIntrospect.h</dt>
<dd>A complete description of the introspection interfaces.</dd>
<dt>pvData.h</dt>
<dd>A complete description of the data interfaces.</dd>
<dt>convert.h</dt>
<dd>A facility that converts between data fields.</dd>
<dt>standardField.h</dt>
<dd>Provides access to introspection interfaces for standard structures
like timeStamp, alarm, etc.</dd>
<dt>standardPVField.h</dt>
<dd>Cteates data interfaces for standard data structures like timeStamp,
alarm, etc.</dd>
</dl>
<h3>pvType.h</h3>
<p>This provides C/C++ definitions for the pvData primitive types: boolean,
byte, short, int, long, ubyte,ushort, uint,u long,float, double, and string.
Because pvData is network data, the C++ implementation must implement the
proper semantics for the primitive types.</p>
<p>pvType.h provides the proper semantics.</p>
<p>It has the definitions:</p>
<pre>
typedef detail::pick_type&lt;int8_t, signed char,
detail::pick_type&lt;uint8_t, char, unsigned char&gt;::type
&gt;::type boolean;
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
// float and double are types
typedef std::string String;
/**
* A boolean array.
*/
typedef std::vector&lt;uint8&gt; BooleanArray;
typedef std::tr1::shared_ptr&lt;BooleanArray&gt; BooleanArrayPtr;
/* get is same is ubyte*/
typedef std::vector&lt;uint8&gt;::iterator BooleanArray_iterator;
typedef std::vector&lt;uint8&gt;::const_iterator BooleanArray_const_iterator;
/**
* A byte array.
*/
typedef std::vector&lt;int8&gt; ByteArray;
typedef std::tr1::shared_ptr&lt;ByteArray&gt; ByteArrayPtr;
inline int8 * get(ByteArray &amp;value);
inline int8 const * get(ByteArray const &amp;value);
inline int8 * get(ByteArrayPtr &amp;value);
inline int8 const * get(ByteArrayPtr const &amp;value);
inline ByteArray &amp; getVector(ByteArrayPtr &amp;value);
inline ByteArray const &amp; getVector(ByteArrayPtr const &amp;value);
typedef std::vector&lt;int8&gt;::iterator ByteArray_iterator;
typedef std::vector&lt;int8&gt;::const_iterator ByteArray_const_iterator;
/* similar definitions are present for ALL the primitive types */
</pre>
<p>where</p>
<dl>
<dt>boolean</dt>
<dd>A c++ bool has the semantics required for boolean. Only the name is
different. C++ code can use either bool or boolean.</dd>
<dt>int8,...,uint64</dt>
<dd>Integers present a problem because short, int, and long are C++
reserved words but do not have a well defined number of bits. Thus for
C++ the definitions above are used in C++ code. The above definitions
have worked on all C++ implementations tested at present. If they break
in a future implementation they should be changes via "#ifdef"
preprocessor statements.</dd>
<dt>String</dt>
<dd>pvData requires that a string be an immutable string that is transfered
over the network as a UTF8 encoded string. Since std::string implements
copy on write semantics, it can be used for support for immutable
strings. It can also be serialized/deserialized as a UTF8 encoded string.
Because it is not a C++ primitive the first letter is capitalized. This
is the same convention the Java implementation uses. </dd>
<dt>StringBuilder</dt>
<dd>This is defined here because to is used by the toString methods defined
for both introsection and data objects. The definition above acts like
the Java StringBuilder class.</dd>
<dt>Array definitions</dt>
<dd>typedefs are provided for an array of each of the primitive types. Note
that string is treated like a primitive type/</dd>
</dl>
<p><b>TBD</b>
<dl>
<dt>boolean</dt>
<dd>Question for Michael. Why isn't the definition of <b>boolean</b> just
<pre>
typedef uint8_t boolean;
</pre>
<dt>StringBuilder</dt>
<dd>Should this go away?</dd>
<dt>Array definitions</dt>
<dd>These should all be removed.</dd>
</dl>
</p>
<h3>pvIntrospect.h</h3>
<p>This subsection describes pvIntrospect.h This file is quite big so rather
than showing the entire file, it will be described in parts. </p>
<p>A primary reason for pvData is to support network access to structured data.
pvAccess transports top level pvStructures. In addition a pvAccess server holds
a set of pvnames, where each pvname if a unique name in the local network.</p>
<p>Given a pvname PV), it is possible to introspect the field without requiring
access to data. The reflection and data interfaces are separate because the
data may not be available. For example when a pvAccess client connects to a PV,
the client library can obtain the reflection information without obtaining any
data. Only when a client issues an I/O request will data be available. This
separation is especially important for arrays and structures so that a client
can discover the type without requiring that a large data array or structure be
transported over the network.</p>
<h4>Type Description</h4>
<p>Types are defined as:</p>
<pre>enum Type {
scalar,
scalarArray,
structure,
structureArray;
};
class TypeFunc {
public:
const char* name(Type);
static void toString(StringBuilder buf,const Type type);
};
enum ScalarType {
pvBoolean,
pvByte, pvShort, pvInt, pvLong,
pvUByte, pvUShort, pvUInt, pvULong,
pvFloat,pvDouble,
pvString;
};
namespace ScalarTypeFunc {
public:
bool isInteger(ScalarType type);
bool isUInteger(ScalarType type);
bool isNumeric(ScalarType type);
bool isPrimitive(ScalarType type);
ScalarType getScalarType(String const &amp;value);
const char* name(ScalarType);
void toString(StringBuilder buf,ScalarType scalarType);
size_t elementSize(ScalarType id);
};</pre>
<p>Type is one of the following:</p>
<dl>
<dt>scalar</dt>
<dd>A scalar of one of the scalar types.</dd>
<dt>scalarArray</dt>
<dd>An array where every element has the same scalar type.</dd>
<dt>structure</dt>
<dd>A structure where each field has a name and a type. Within a structure
each field name must be unique but the types can be different.</dd>
<dt>structureArray</dt>
<dd>An array where each element is a structure. Each element has the same
structure introspection interface.</dd>
</dl>
<p>ScalarType is one of the following:</p>
<dl>
<dt>pvBoolean</dt>
<dd>Has the value false or true.</dd>
<dt>pvByte</dt>
<dd>A signed 8 bit integer.</dd>
<dt>pvShort</dt>
<dd>A signed 16 bit integer.</dd>
<dt>pvInt</dt>
<dd>A signed 32 bit integer.</dd>
<dt>pvLong</dt>
<dd>A signed 64 bit integer.</dd>
<dt>pvUByte</dt>
<dd>An unsigned 8 bit integer.</dd>
<dt>pvUShort</dt>
<dd>An unsigned 16 bit integer.</dd>
<dt>pvUInt</dt>
<dd>An unsigned 32 bit integer.</dd>
<dt>pvULong</dt>
<dd>An unsigned 64 bit integer.</dd>
<dt>pvFloat</dt>
<dd>A IEEE float.</dd>
<dt>pvDouble</dt>
<dd>A IEEE double,</dd>
<dt>pvString</dt>
<dd>An immutable string.</dd>
</dl>
<p>TypeFunction is a set of convenience methods for Type</p>
<dl>
<dt>name</dt>
<dd>Returns the name of the type.</dd>
<dt>toString</dt>
<dd>Convert the type to a string.</dd>
</dl>
<p>ScalarTypeFunction is a set of convenience methods for ScalarType</p>
<dl>
<dt>isInteger</dt>
<dd>Is the scalarType an integer type, i.e. one of pvByte,...pvULong.</dd>
<dt>isUInteger</dt>
<dd>Is the scalarType an unsigned integer type, i.e. one of
pvUByte,...pvULong</dd>
<dt>isNumeric</dt>
<dd>Is the scalarType numeric, i.e. pvByte,...,pvDouble.</dd>
<dt>isPrimitive</dt>
<dd>Is the scalarType primitive, i.e. not pvString</dd>
<dt>name</dt>
<dd>Returns the name of the scalarType.</dd>
<dt>getScalarType</dt>
<dd>Given a string of the form String("boolean"),...,String("string")
return the scalarType.</dd>
<dt>toString</dt>
<dd>Convert the scalar type to a string.</dd>
<dt>elementSize</dt>
<dd>Returns the size in bytes of an instance of the scalarType.</dd>
</dl>
<p><b>TBD</b>
<dl>
<dt>union</dt>
<dd>Types pvUnion and pvUnionArray should be added</dd>
<dt>toString</dt>
<dd>Should this be changed to
<pre>
String toString(ScalarType scalarType);
</pre>
</dd>
</dl>
</p>
<h4>Introspection Description</h4>
<p>This section describes the reflection interfaces which provide the
following: </p>
<dl>
<dt>Field</dt>
<dd>A field:
<ul>
<li>Has a Type.</li>
<li>Can be converted to a string.</li>
<li>Can be shared. A reference count is kept. When it becomes 0 the
instance is automatically deleted.</li>
</ul>
</dd>
<dt>Scalar</dt>
<dd>A scalar has a scalarType</dd>
<dt>ScalarArray</dt>
<dd>The element type is a scalarType</dd>
<dt>Structure</dt>
<dd>Has fields that can be any of the supported types.</dd>
<dt>StructureArray</dt>
<dd>The field holds an array of structures. Each element has the same
Structure interspection interface. A pvAccess client can only get/put
entire PVStructure elements NOT subfields of array elements.</dd>
<dt>Union</dt>
<dd><b>TBD</b></dd>
<dt>UnionArray</dt>
<dd><b>TBD</b></dd>
<dt>FieldCreate</dt>
<dd>This is an interface that provides methods to create introspection
interfaces. A factory is provides to create FieldCreate.</dd>
<dt>getFieldCreate</dt>
<dd>Gets a pointer to the single instance of FieldCreate.</dd>
</dl>
<pre>class Field;
class Scalar;
class ScalarArray;
class Structure;
class StructureArray;
typedef std::tr1::shared_ptr&lt;const Field&gt; FieldConstPtr;
typedef std::vector&lt;FieldConstPtr&gt; FieldConstPtrArray;
typedef std::tr1::shared_ptr&lt;const Scalar&gt; ScalarConstPtr;
typedef std::tr1::shared_ptr&lt;const ScalarArray&gt; ScalarArrayConstPtr;
typedef std::tr1::shared_ptr&lt;const Structure&gt; StructureConstPtr;
typedef std::tr1::shared_ptr&lt;const StructureArray&gt; StructureArrayConstPtr;
class Field :
virtual public Serializable,
public std::tr1::enable_shared_from_this&lt;Field&gt;
{
public:
POINTER_DEFINITIONS(Field);
virtual ~Field();
Type getType() const{return m_type;}
virtual String getID() const = 0;
virtual void toString(StringBuilder buf) const{toString(buf,0);}
virtual void toString(StringBuilder buf,int indentLevel) const;
...
};
class Scalar : public Field{
public:
POINTER_DEFINITIONS(Scalar);
virtual ~Scalar();
typedef Scalar&amp; reference;
typedef const Scalar&amp; const_reference;
ScalarType getScalarType() const {return scalarType;}
virtual void toString(StringBuilder buf) const{toString(buf,0);}
virtual void toString(StringBuilder buf,int indentLevel) const;
virtual String getID() const;
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableContol *control);
...
};
class ScalarArray : public Field{
public:
POINTER_DEFINITIONS(ScalarArray);
typedef ScalarArray&amp; reference;
typedef const ScalarArray&amp; const_reference;
ScalarArray(ScalarType scalarType);
ScalarType getElementType() const {return elementType;}
virtual void toString(StringBuilder buf) const{toString(buf,0);}
virtual void toString(StringBuilder buf,int indentLevel) const;
virtual String getID() const;
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
...
};
class StructureArray : public Field{
public:
POINTER_DEFINITIONS(StructureArray);
typedef StructureArray&amp; reference;
typedef const StructureArray&amp; const_reference;
StructureConstPtr getStructure() const {return pstructure;}
virtual void toString(StringBuilder buf,int indentLevel=0) const;
virtual String getID() const;
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
...
};
class Structure : public Field {
public:
POINTER_DEFINITIONS(Structure);
typedef Structure&amp; reference;
typedef const Structure&amp; const_reference;
std::size_t getNumberFields() const {return numberFields;}
FieldConstPtr getField(String const &amp; fieldName) const;
FieldConstPtr getField(std::size_t index) const;
std::size_t getFieldIndex(String const &amp;fieldName) const;
FieldConstPtrArray const &amp; getFields() const {return fields;}
StringArray const &amp; getFieldNames() const;
String getFieldName(std::size_t fieldIndex) const;
virtual void toString(StringBuilder buf,int indentLevel) const;
virtual String getID() const;
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
...
};
class FieldCreate {
public:
static FieldCreatePtr getFieldCreate();
ScalarConstPtr createScalar(ScalarType scalarType) const
ScalarArrayConstPtr createScalarArray(ScalarType elementType) const;
StructureArrayConstPtr createStructureArray(StructureConstPtr const &amp; structure) const;
StructureConstPtr createStructure (
StringArray const &amp; fieldNames,
FieldConstPtrArray const &amp; fields) const;
StructureConstPtr createStructure (
String const &amp;id,
StringArray const &amp; fieldNames,
FieldConstPtrArray const &amp; fields) const;
FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const;
...
};
extern FieldCreatePtr getFieldCreate(); </pre>
<dl>
<dt>Constructor</dt>
<dd>Note that all constructors are protected or private. The only way to
create instances is via FieldCreate. The implementation manages all
storage via shared pointers.</dd>
<dt>toString</dt>
<dd>Many classes provide this (actually two methods). This method is called
to get a string that uses the metadata syntax described in a previous
section.</dd>
</dl>
<h5>Field</h5>
<dl>
<dt>getType</dt>
<dd>Get the field type.</dd>
<dt>getID</dt>
<dd>Get an ID for this introspection interface</dd>
</dl>
<h5>Scalar</h5>
<dl>
<dt>getScalarType</dt>
<dd>Get that scalar type.</dd>
<dt>getID</dt>
<dd>For each scalarType there is one instance of Scalar. The ID for each is
the metadata name for the type, i. e. one of "boolean" , ... , "string".
</dd>
</dl>
<h5>ScalarArray</h5>
<dl>
<dt>getElementType</dt>
<dd>Get the element type.</dd>
<dt>getID</dt>
<dd>For each elemnetType there is one instance of ScalarArray. The ID for
each is the metadata name for the type, i. e. one of "boolean[]" , ... ,
"string[]". </dd>
</dl>
<h5>StructureArray</h5>
<dl>
<dt>getStructure</dt>
<dd>Get the introspection interface that each element shares,</dd>
<dt>getID</dt>
<dd>This returns the ID[] where ID is the value returned by
structure-&gt;getID(). </dd>
</dl>
<h5>Structure</h5>
<dl>
<dt>getNumberFields</dt>
<dd>Get the number of immediate subfields.</dd>
<dt>getField</dt>
<dd>Given a name or an index get the introspection interface for the
field.</dd>
<dt>getFieldIndex</dt>
<dd>Given a name get the index, within the array returned by the next
method, of the field.</dd>
<dt>getFields</dt>
<dd>Get the array of introspection interfaces for the field,</dd>
<dt>getFieldNames</dt>
<dd>Get the array of field names for the subfields.</dd>
<dt>getFieldName</dt>
<dd>Get the field name for the specified index.</dd>
</dl>
<h5>FieldCreate</h5>
<dl>
<dt>getFieldCreate</dt>
<dd>Get the single instance of FieldCreate.</dd>
<dt>createScalar</dt>
<dd>Create a scalar introspection instance.</dd>
<dt>createScalarArray</dt>
<dd>Create a scalar array introspection instance.</dd>
<dt>createStructure</dt>
<dd>Create a structure introspection instance. Two methods are provided
where the only difference is that one provides an ID and the other does
not. The one without will result in ID "structure".</dd>
<dt>createStructureArray</dt>
<dd>Create a structure array introspection instance. </dd>
<dt>deserialize</dt>
<dd>Deserialize from given byte buffer.</dd>
</dl>
<p><b>TBD</b>
<dl>
<dt>toString</dt>
<dd>Should all the toString methods be changed to just return String?</dd>
<dt>ScalarTypeTraits and ScalarTypeID</dt>
<dd>These seem to only be used by shared_vector. Do they need to be documented?</dd>
<dt>appendField and appendFields</dt>
<dd>These methods of FieldCreate should be removed.</dd>
</dl>
</p>
<h3>standardField.h</h3>
<p>The file standardField.h has a class description for creating or sharing
Field objects for standard fields. For each type of field a method is provided.
Each creates a structure that has a field named "value" and a set of properyt
fields, The property field is a comma separated string of property names of the
following: alarm, timeStamp, display, control, and valueAlarm. An example is
"alarm,timeStamp,valueAlarm". The method with properties creates a structure
with fields named value and each of the property names. Each property field is
a structure defining the property. The details about each property is given in
the section named "Property". For example the call:</p>
<pre> StructureConstPtr example = standardField-&gt;scalar(
pvDouble,
"value,alarm,timeStamp");</pre>
<p>Will result in a Field definition that has the form:</p>
<pre>structure example
double value
alarm_t alarm
int severity
int status
string message
timeStamp_t timeStamp
long secondsPastEpoch
int nanoSeconds
int userTag</pre>
<p>In addition there are methods that create each of the property structures,
i.e. the methods named: alarm, .... enumeratedAlarm."</p>
<p>standardField.h contains:</p>
<pre>class StandardField;
typedef std::tr1::shared_ptr&lt;StandardField&gt; StandardFieldPtr;
class StandardField {
public:
static StandardFieldPtr getStandardField();
~StandardField();
StructureConstPtr scalar(ScalarType type,String const &amp;properties);
StructureConstPtr scalarArray(
ScalarType elementType, String const &amp;properties);
StructureConstPtr structureArray(
StructureConstPtr const &amp; structure,String const &amp;properties);
StructureConstPtr enumerated();
StructureConstPtr enumerated(String const &amp;properties);
StructureConstPtr alarm();
StructureConstPtr timeStamp();
StructureConstPtr display();
StructureConstPtr control();
StructureConstPtr booleanAlarm();
StructureConstPtr byteAlarm();
StructureConstPtr ubyteAlarm();
StructureConstPtr shortAlarm();
StructureConstPtr ushortAlarm();
StructureConstPtr intAlarm();
StructureConstPtr uintAlarm();
StructureConstPtr longAlarm();
StructureConstPtr ulongAlarm();
StructureConstPtr floatAlarm();
StructureConstPtr doubleAlarm();
StructureConstPtr enumeratedAlarm();
...
};</pre>
<dl>
<dt>scalar</dt>
<dd>Create a scalar with the specified scalar type and name. A structure
will be created with the first element being a scalar with the specified
scalar type and name value. The other fields in the structure will be the
corresponding property structures.</dd>
<dt>scalarArray</dt>
<dd>Create a scalarArray with each element having the specified scalar type
and name. A structure will be created with the first element being a
scalarArray with name value. The other fields in the structure will be
the corresponding property structures.</dd>
<dt>structureArray</dt>
<dd>Create a structureArray with the specified structure interface and
name. A structure will be created with the first element being a
structureArray with the specified structure interface and name value. The
other fields in the structure will be the corresponding property
structures.</dd>
<dt>structure</dt>
<dd>Create a structure with the specified name and fields specified by
numFields and fields. A structure will be created with the first element
being a structure with the name value and fields specified by numFields
and fields. The other fields in the structure will be the corresponding
property structures.</dd>
<dt>enumerated</dt>
<dd>Create a structure with the specified name and fields for an enumerated
structure. If properties are specified then a structure will be created
with the first element being a structure with the name value and fields
for an enumerated structure. The other fields in the structure will be
the corresponding property structures.</dd>
<dt>alarm</dt>
<dt>timeStamp</dt>
<dt>display</dt>
<dt>control</dt>
<dt>booleanAlarm</dt>
<dt>byteAlarm</dt>
<dt>shortAlarm</dt>
<dt>intAlarm</dt>
<dt>longAlarm</dt>
<dt>floatAlarm</dt>
<dt>doubleAlarm</dt>
<dt>enumeratedAlarm</dt>
<dd>The above provide introspection interfaces for standard properties. See
the section on Properties for a description of how these are defined.</dd>
</dl>
<p><b>TBD</b>
<dl>
<dt>union</dt>
<dt>unionArray</dt>
<dd>When union is supported also add these.</dd>
</dl>
</p>
<h3>pvData.h</h3>
<p>This subsection describes pvData.h This file is quite big so rather than
showing the entire file, it will be described in parts. </p>
<h4>typedefs</h4>
<p>These are typedefs for Array and Ptr for the various pvData class
definitions, i.e. typdefs for "std::vector" and "std::tr1::shared_ptr".</p>
<pre>
class PVField;
class PVScalar;
class PVScalarArray;
class PVStructure;
class PVStructureArray;
typedef std::tr1::shared_ptr&lt;PVField&gt; PVFieldPtr;
typedef std::vector&lt;PVFieldPtr&gt; PVFieldPtrArray;
typedef std::vector&lt;PVFieldPtr&gt;::iterator PVFieldPtrArray_iterator;
typedef std::vector&lt;PVFieldPtr&gt;::const_iterator PVFieldPtrArray_const__iterator;
typedef std::tr1::shared_ptr&lt;PVScalar&gt; PVScalarPtr;
typedef std::tr1::shared_ptr&lt;PVScalarArray&gt; PVScalarArrayPtr;
typedef std::tr1::shared_ptr&lt;PVStructure&gt; PVStructurePtr;
typedef std::vector&lt;PVStructurePtr&gt; PVStructurePtrArray;
typedef std::vector&lt;PVStructurePtr&gt;::iterator PVStructurePtrArray_iterator;
typedef std::vector&lt;PVStructurePtr&gt;::const_iterator PVStructurePtrArray_const__iterator;
typedef PVValueArray&lt;PVStructurePtr&gt; PVStructureArray;
typedef std::tr1::shared_ptr&lt;PVStructureArray&gt; PVStructureArrayPtr;
typedef std::vector&lt;PVStructureArrayPtr&gt; PVStructureArrayPtrArray;
typedef std::tr1::shared_ptr&lt;PVStructureArrayPtrArray&gt; PVStructureArrayPtrArrayPtr;
/**
* typedefs for the various possible scalar types.
*/
typedef PVScalarValue&lt;boolean&gt; PVBoolean;
typedef PVScalarValue&lt;int8&gt; PVByte;
typedef PVScalarValue&lt;int16&gt; PVShort;
typedef PVScalarValue&lt;int32&gt; PVInt;
typedef PVScalarValue&lt;int64&gt; PVLong;
typedef PVScalarValue&lt;uint8&gt; PVUByte;
typedef PVScalarValue&lt;uint16&gt; PVUShort;
typedef PVScalarValue&lt;uint32&gt; PVUInt;
typedef PVScalarValue&lt;uint64&gt; PVULong;
typedef PVScalarValue&lt;float&gt; PVFloat;
typedef PVScalarValue&lt;double&gt; PVDouble;
class PVString;
typedef std::tr1::shared_ptr&lt;PVBoolean&gt; PVBooleanPtr;
typedef std::tr1::shared_ptr&lt;PVByte&gt; PVBytePtr;
typedef std::tr1::shared_ptr&lt;PVShort&gt; PVShortPtr;
typedef std::tr1::shared_ptr&lt;PVInt&gt; PVIntPtr;
typedef std::tr1::shared_ptr&lt;PVLong&gt; PVLongPtr;
typedef std::tr1::shared_ptr&lt;PVUByte&gt; PVUBytePtr;
typedef std::tr1::shared_ptr&lt;PVUShort&gt; PVUShortPtr;
typedef std::tr1::shared_ptr&lt;PVUInt&gt; PVUIntPtr;
typedef std::tr1::shared_ptr&lt;PVULong&gt; PVULongPtr;
typedef std::tr1::shared_ptr&lt;PVFloat&gt; PVFloatPtr;
typedef std::tr1::shared_ptr&lt;PVDouble&gt; PVDoublePtr;
typedef std::tr1::shared_ptr&lt;PVString&gt; PVStringPtr;
/**
* Definitions for the various scalarArray types.
*/
typedef PVValueArray&lt;boolean&gt; PVBooleanArray;
typedef PVValueArray&lt;int8&gt; PVByteArray;
typedef PVValueArray&lt;int16&gt; PVShortArray;
typedef PVValueArray&lt;int32&gt; PVIntArray;
typedef PVValueArray&lt;int64&gt; PVLongArray;
typedef PVValueArray&lt;uint8&gt; PVUByteArray;
typedef PVValueArray&lt;uint16&gt; PVUShortArray;
typedef PVValueArray&lt;uint32&gt; PVUIntArray;
typedef PVValueArray&lt;uint64&gt; PVULongArray;
typedef PVValueArray&lt;float&gt; PVFloatArray;
typedef PVValueArray&lt;double&gt; PVDoubleArray;
typedef PVValueArray&lt;String&gt; PVStringArray;
typedef std::tr1::shared_ptr&lt;PVBooleanArray&gt; PVBooleanArrayPtr;
typedef std::tr1::shared_ptr&lt;PVByteArray&gt; PVByteArrayPtr;
typedef std::tr1::shared_ptr&lt;PVShortArray&gt; PVShortArrayPtr;
typedef std::tr1::shared_ptr&lt;PVIntArray&gt; PVIntArrayPtr;
typedef std::tr1::shared_ptr&lt;PVLongArray&gt; PVLongArrayPtr;
typedef std::tr1::shared_ptr&lt;PVUByteArray&gt; PVUByteArrayPtr;
typedef std::tr1::shared_ptr&lt;PVUShortArray&gt; PVUShortArrayPtr;
typedef std::tr1::shared_ptr&lt;PVUIntArray&gt; PVUIntArrayPtr;
typedef std::tr1::shared_ptr&lt;PVULongArray&gt; PVULongArrayPtr;
typedef std::tr1::shared_ptr&lt;PVFloatArray&gt; PVFloatArrayPtr;
typedef std::tr1::shared_ptr&lt;PVDoubleArray&gt; PVDoubleArrayPtr;
typedef std::tr1::shared_ptr&lt;PVStringArray&gt; PVStringArrayPtr;
</pre>
<p><b>TBD</b>
<dl>
<dt>PVUnion</dt>
<dt>PVUnionArray</dt>
<dd>When union is supported.</dd>
<dt>WPtr</dt>
<dd>Should definitions for std::tr1::weak_ptr also be added.</dd>
</dl>
<h4>PVField</h4>
<p>PVField is the base interface for accessing data. A data structure consists
of a top level PVStructure. Every field of every structure of every top level
structure has a PVField associated with it.</p>
<pre>
class PostHandler
{
public:
POINTER_DEFINITIONS(PostHandler);
virtual ~PostHandler(){}
virtual void postPut() = 0;
};
class PVField
: virtual public Serializable,
public std::tr1::enable_shared_from_this&lt;PVField&gt;
{
public:
POINTER_DEFINITIONS(PVField);
virtual ~PVField();
String getFieldName() const ;
std::size_t getFieldOffset() const;
std::size_t getNextFieldOffset() const;
std::size_t getNumberFields() const;
bool isImmutable() const;
virtual void setImmutable();
const FieldConstPtr &amp; getField() const ;
PVStructure * getParent() const
void postPut();
void setPostHandler(PostHandlerPtr const &amp;postHandler);
virtual bool equals(PVField &amp;pv);
virtual void toString(StringBuilder buf) ;
virtual void toString(StringBuilder buf,int indentLevel);
std::ostream&amp; dumpValue(std::ostream&amp; o) const;
...
}</pre>
<p>The public methods for PVField are:</p>
<dl>
<dt>~PVField</dt>
<dd>Destructor. Since shared pointers are used it should never be called by
user code.</dd>
<dt>getFieldName</dt>
<dd>Get the field name. If the field is a top level structure the field
name will be an empty string.</dd>
<dt>getFullName</dt>
<dd>Fully expand the name of this field using the
names of its parent fields with a dot '.' seperating
each name.
</dd>
<dt>getFieldOffset</dt>
<dd>Get offset of the PVField field within top level structure. Every field
within the PVStructure has a unique offset. The top level structure has
an offset of 0. The first field within the structure has offset equal to
1. The other offsets are determined by recursively traversing each
structure of the tree. </dd>
<dt>getNextFieldOffset</dt>
<dd>Get the next offset. If the field is a scalar or array field then this
is just offset + 1. If the field is a structure it is the offset of the
next field after this structure. Thus (nextOffset - offset) is always
equal to the total number of fields within the field. </dd>
<dt>getNumberFields</dt>
<dd>Get the total number of fields in this field. This is nextFieldOffset -
fieldOffset. </dd>
<dt>isImmutable</dt>
<dd>Is the field immutable?</dd>
<dt>setImmutable</dt>
<dd>Make the field immutable. Once a field is immutable it can never be
changed since there is no method to again make it mutable. This is an
important design decision since it allows immutable array fields to share
the internal primitive data array.</dd>
<dt>getField</dt>
<dd>Get the reflection interface for the data.</dd>
<dt>getParent</dt>
<dd>Get the interface for the parent or null if this is the top level
PVStructure.</dd>
<dt>postPut</dt>
<dd>If a postHandler is registered it is called otherwise no action is
taken.</dd>
<dt>setPostHandler</dt>
<dd>Set the postHandler for the record. Only a single handler can be
registered.
PostHandler is a class that must be implemented by any code that calls setPostHandler.
It's single virtual method. postPut is called whenever PVField::postPut is called.
</dd>
<dt>equals</dt>
<dd>Compare this field with another field. The result will be true only if
the fields have exactly the same field types and if the data values are
equal.</dd>
<dt>toString</dt>
<dd>Converts the field data to a string. This is mostly for debugging
purposes.</dd>
<dt>dumpValue</dt>
<dd>Method for streams I/O.</dd>
</dl>
<p><b>TBD</b>
<dl>
<dt>getFullName</dt>
<dd>Should this be removed?</dd>
<dt>toString and dumpValue</dt>
<dd>Should these be replaced by:
<pre>
virtual String toString() const;
virtual std::ostream&amp; operator&lt;&lt;(std::ostream&amp; o) const = 0;
</pre>
</dd>
<dt>replaceField</dt>
<dd>This is a protected member that should be removed.</dd>
</dl>
</p>
<h4>PVScalar</h4>
<p>This is the base class for all scalar data.</p>
<pre>class PVScalar : public PVField {
public:
POINTER_DEFINITIONS(PVScalar);
virtual ~PVScalar();
typedef PVScalar &amp;reference;
typedef const PVScalar&amp; const_reference;
const ScalarConstPtr getScalar() const ;
template&lt;typename T&gt;
T getAs() const;
...
}</pre>
<p>where</p>
<dl>
<dt>getScalar</dt>
<dd>Get the introspection interface for the PVScalar.</dd>
<dt>getAs</dt>
<dd>Convert and return the scalar value in the requested type.
Result type is determined from the function template argument
which must be one of the ScalarType enums.
For example:
<pre>
uint32 val = pv-&gt;getAs<pvInt>();
</pre>
</dd>
</dl>
<h4>PVScalarValue</h4>
<p>The interfaces for primitive data types are:</p>
<pre>template&lt;typename T&gt;
class PVScalarValue : public PVScalar {
public:
POINTER_DEFINITIONS(PVScalarValue);
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
static const ScalarType typeCode;
virtual ~PVScalarValue() {}
virtual T get() const = 0;
virtual void put(T value) = 0;
std::ostream&amp; dumpValue(std::ostream&amp; o) const;
void operator&gt;&gt;=(T&amp; value) const;
void operator&lt;&lt;=(T value);
template&lt;typename T1&gt;
T1 getAs() const;
template&lt;typename T1&gt;
void putFrom(T1 val);
...
}
// PVString is special case, since it implements SerializableArray
class PVString : public PVScalarValue&lt;String&gt;, SerializableArray {
public:
virtual ~PVString() {}
...
};</pre>
<p>where</p>
<dl>
<dt>get</dt>
<dd>Get the value stored in the object.</dd>
<dt>put</dt>
<dd>Change the value stored in the object.</dd>
<dt>dumpValue</dt>
<dd>ostream method.</dd>
<dt>operator&gt;&gt;=</dt>
<dd>get operator. For example:
<pre>
double value;
PVDoublePtr pvDouble;
...
pvDouble&gt;&gt;=value;
</pre>
</dd>
<dt>operator&lt;&lt;=</dt>
<dd>put operator. For example:
<pre>
double value;
PVDoublePtr pvDouble;
...
pvDouble&lt;&lt;=value;
</pre>
</dd>
<dt>getAs</dt>
<dd>Convert and return the scalar value in the requested type.
Result type is determined from the function template argument
which must be one of the ScalarType enums.
For example:
<pre>
int32 val = pv-&gt;getAs&lt;pvInt&gt;>();
</pre>
</dd>
<dt>putFrom</dt>
<dd>Convert the scalar value in the requested type
and put the value into this PVScalarValue.
The source type is determined from the function template argument
which must be one of the ScalarType enums.
For example:
<pre>
int32 val;
pv-&gt;putFrom&lt;pvInt&gt;(val);
</pre>
</dd>
</dl>
<p><b>TBD</b>
<dl>
<dt>dumpvalue</dt>
<dd>replace this with ostream operator&lt;&lt;</dd>
</dl>
</p>
<h4>PVArray</h4>
<p>PVArray is the base interface for all the other PV Array interfaces. It
extends PVField and provides the additional methods:</p>
<pre>
class PVArray : public PVField, public SerializableArray {
public:
POINTER_DEFINITIONS(PVArray);
virtual ~PVArray();
virtual void setImmutable();
std::size_t getLength() const;
virtual void setLength(std::size_t length);
std::size_t getCapacity() const;
bool isCapacityMutable() const;
void setCapacityMutable(bool isMutable);
virtual void setCapacity(std::size_t capacity) = 0;
virtual std::ostream&amp; dumpValue(std::ostream&amp; o, std::size_t index) const;
...
};</pre>
<dl>
<dt>setImmutable</dt>
<dd>Set the data immutable. Note that this is permanent since there is no
methods to make it mutable.</dd>
<dt>getLength</dt>
<dd>Get the current length. This is less than or equal to the capacity.</dd>
<dt>setLength</dt>
<dd>Set the length. If the PVField is not mutable then an exception is
thrown. If this is greater than the capacity setCapacity is called.</dd>
<dt>getCapacity</dt>
<dd>Get the capacity, i.e. this is the size of the underlying data
array.</dd>
<dt>setCapacity</dt>
<dd>Set the capacity. The semantics are implementation dependent but
typical semantics are as follows: If the capacity is not mutable an
exception is thrown. A new data array is created and data is copied from
the old array to the new array. </dd>
<dt>isCapacityMutable</dt>
<dd>Is the capacity mutable</dd>
<dt>setCapacityMutable</dt>
<dd>Specify if the capacity can be changed.</dd>
<dt>setCapacity</dt>
<dd>Set the capaciity.</dd>
<dt>dumpValue</dt>
<dd>ostream method</dd>
</dl>
<p><b>TBD</b>
<dl>
<dt>dumpvalue</dt>
<dd>replace this with ostream operator&lt;&lt;</dd>
</dl>
</p>
<h4>PVScalarArray</h4>
<p>PVScalarArray is the base class for scalar array data. PVValueArray is a
templete for the various scalar array data classes. There is a class for each
possible scalar type, i. e. PVBooleanArray, ..., PVStringArray.</p>
<pre>
class PVScalarArray : public PVArray {
public:
POINTER_DEFINITIONS(PVScalarArray);
virtual ~PVScalarArray();
typedef PVScalarArray &amp;reference;
typedef const PVScalarArray&amp; const_reference;
const ScalarArrayConstPtr getScalarArray() const ;
template&lt;typename T&gt;
void getAs(shared_vector&lt;const T&gt;&amp; out) const
template&lt;typename T&gt;
void putFrom(const shared_vector&lt;const T&gt;&amp; inp)
void assign(PVScalarArray&amp; pv);
...
}
</pre>
<p>where</p>
<dl>
<dt>getScalarArray</dt>
<dd>Get the introspection interface.</dd>
<dt>getAs</dt>
<dd>Fetch the current value and convert to the requested type.
A copy is made if the requested type does not match the element type.
If the types do match then no copy is made.
</dd>
<dt>putFrom</dt>
<dd>Assign the given value after conversion.
A copy and element-wise conversion is performed unless the element type
of the PVScalarArray matches the type of the provided data.
If the types do match then a new refernce to the provided data is kept.
</dd>
<dt>assign</dt>
<dd>Assign the given PVScalarArray's value.
A copy and element-wise conversion is performed unless the element type
of the PVScalarArray matches the type of the provided data.
If the types do match then a new refernce to the provided data is kept.
</dd>
</dl>
<h4>PVValueArray</h4>
<p>This is a template class plus instances for PVBooleanArray, ...,
PVStringArray.</p>
<pre>template&lt;typename T&gt;
class PVValueArray : public detail::PVVectorStorage&lt;T,PVScalarArray&gt;
{
public:
POINTER_DEFINITIONS(PVValueArray);
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef ::epics::pvData::shared_vector&lt;T&gt; svector;
typedef ::epics::pvData::shared_vector&lt;const T&gt; const_svector;
static const ScalarType typeCode;
virtual ~PVValueArray() {}
std::ostream&amp; dumpValue(std::ostream&amp; o) const;
std::ostream&amp; dumpValue(std::ostream&amp; o, size_t index) const;
// inherited from PVVectorStorage
const_svector view();
void swap(const_svector& other);
void replace(const const_svector& next);
svector reuse();
...
};
</pre>
<p>where</p>
<dl>
<dt>dumpValue</dt>
<dd>Method for streams I/O.</dd>
<dt>view</dt>
<dd>Fetch a read-only view of the current array data.</dd>
<dt>swap</dt>
<dd>
Callers must ensure that postPut() is called after the last swap() operation.
Before you call this directly, consider using the reuse(), or replace() methods.
</dd>
<dt>replace</dt>
<dd> Discard current contents and replaced with the provided.</dd>
<dt>reuse</dt>
<dd>Remove and return the current array data or an unique copy if shared.</dd>
</dl>
<p><b>TBD</b>
<dl>
<dt>dumpvalue</dt>
<dd>replace this with ostream operator&lt;&lt;</dd>
<dt>Check for completeness</dt>
<dd>Michael should check that PVScalarArray and PVValueArray
have the correct set of methods and that the descriptions are correct.</dd>
</dl>
</p>
<h4>PVStructure</h4>
<p>The interface for a structure is:</p>
<pre>class PVStructure : public PVField,public BitSetSerializable {
public:
POINTER_DEFINITIONS(PVStructure);
virtual ~PVStructure();
typedef PVStructure &amp; reference;
typedef const PVStructure &amp; const_reference;
virtual void setImmutable();
StructureConstPtr getStructure() const;
const PVFieldPtrArray &amp; getPVFields() const;
PVFieldPtr getSubField(String const &amp;fieldName) const;
PVFieldPtr getSubField(std::size_t fieldOffset) const;
PVBooleanPtr getBooleanField(String const &amp;fieldName) ;
PVBytePtr getByteField(String const &amp;fieldName) ;
PVShortPtr getShortField(String const &amp;fieldName) ;
PVIntPtr getIntField(String const &amp;fieldName) ;
PVLongPtr getLongField(String const &amp;fieldName) ;
PVUBytePtr getUByteField(String const &amp;fieldName) ;
PVUShortPtr getUShortField(String const &amp;fieldName) ;
PVUIntPtr getUIntField(String const &amp;fieldName) ;
PVULongPtr getULongField(String const &amp;fieldName) ;
PVFloatPtr getFloatField(String const &amp;fieldName) ;
PVDoublePtr getDoubleField(String const &amp;fieldName) ;
PVStringPtr getStringField(String const &amp;fieldName) ;
PVStructurePtr getStructureField(String const &amp;fieldName) ;
PVScalarArrayPtr getScalarArrayField(
String const &amp;fieldName,ScalarType elementType) ;
PVStructureArrayPtr getStructureArrayField(String const &amp;fieldName) ;
virtual void serialize(
ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
virtual void deserialize(
ByteBuffer *pbuffer,DeserializableControl *pflusher);
virtual void serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher,BitSet *pbitSet) const;
virtual void deserialize(ByteBuffer *pbuffer,
DeserializableControl*pflusher,BitSet *pbitSet);
PVStructure(StructureConstPtr const &amp; structure);
PVStructure(StructureConstPtr const &amp; structure,PVFieldPtrArray const &amp; pvFields);
virtual std::ostream&amp; dumpValue(std::ostream&amp; o) const;
};</pre>
<p>where</p>
<dl>
<dt>getStructure</dt>
<dd>Get the introspection interface for the structure.</dd>
<dt>getPVFields</dt>
<dd>Returns the array of subfields. The set of subfields must all have
different field names.</dd>
<dt>getSubField(String fieldName)</dt>
<dd>Get a subField of a field. For a PVStructure a non-null result is
returned if fieldName is a field of the PVStructure. The fieldName can be
of the form name.name...
If the field does not exist the a Ptr to a NULL value is returned
without any error message being generated.
</dd>
<dt>getSubField(int fieldOffset)</dt>
<dd>Get the field located a fieldOffset, where fieldOffset is relative to
the top level structure. This returns null if the specified field is not
located within this PVStructure.</dd>
<dt>getBooleanField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface. This and the following methods are convenience methods that
allow a user to get the interface to a subfield without requiring
introspection. fieldName can be of the form name.name...
If the field does not exist or has the wrong type then
message will be called and a Ptr to NULL is returned.
</dd>
<dt>getByteField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt>getShortField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt>getIntField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt>getLongField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt>getUByteField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt>getUShortField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt>getUIntField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt>getULongField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt>getFloatField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt>getDoubleField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt>getStringField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt>getStructureField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt>getScalarArrayField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt>getStructureArrayField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt>dumpValue</dt>
<dd>Method for streams I/O.</dd>
</dl>
<p><b>TBD</b>
<dl>
<dt>dumpvalue</dt>
<dd>replace this with ostream operator&lt;&lt;</dd>
</dl>
</p>
<h4>PVStructureArray</h4>
<p>The interface for an array of structures is:</p>
<pre>
template&lt;&gt;
class PVValueArray&lt;PVStructurePtr&gt; : public detail::PVVectorStorage&lt;PVStructurePtr,PVArray&gt;
{
public:
POINTER_DEFINITIONS(PVStructureArray);
typedef PVStructurePtr value_type;
typedef PVStructurePtr* pointer;
typedef const PVStructurePtr* const_pointer;
typedef PVStructureArray &amp;reference;
typedef const PVStructureArray&amp; const_reference;
typedef ::epics::pvData::shared_vector&lt;PVStructurePtr&gt; svector;
typedef ::epics::pvData::shared_vector&lt;const PVStructurePtr&gt; const_svector;
virtual ~PVStructureArray() {}
virtual size_t getLength();
virtual size_t getCapacity();
virtual void setCapacity(size_t capacity);
virtual void setLength(std::size_t length);
virtual StructureArrayConstPtr getStructureArray() const ;
virtual std::size_t append(std::size_t number);
virtual bool remove(std::size_t offset,std::size_t number);
virtual void compress();
virtual void serialize(ByteBuffer *pbuffer,
virtual const_svector view() const;
virtual void swap(const_svector &amp;other);
virtual void replace(const const_svector &amp;other);
SerializableControl *pflusher) const;
virtual void deserialize(ByteBuffer *buffer,
DeserializableControl *pflusher);
virtual void serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, std::size_t offset, std::size_t count) const ;
virtual std::ostream&amp; dumpValue(std::ostream&amp; o) const;
virtual std::ostream&amp; dumpValue(std::ostream&amp; o, std::size_t index) const;
// inherited from PVVectorStorage
const_svector view();
void swap(const_svector& other);
void replace(const const_svector& next);
svector reuse();
...
}</pre>
<p>where</p>
<dl>
<dt>getStructureArray</dt>
<dd>Get the introspection interface shared by each element.</dd>
<dt>append</dt>
<dd>Create new elements and append them to the end of the array. It returns
the index of the first new element.</dd>
<dt>remove</dt>
<dd>Remove the specfied set of elements. It returns (false,true) if the
elements (were not, were) removed. It will not removed any elements
unless all requested elements exist or are null. Note that this deletes
the element and sets the array element to null. It does not change the
array capacity. </dd>
<dt>compress</dt>
<dd>This moves all null elements and then changes the array capacity. When
done there are no null elements.</dd>
</dl>
<p>The other methods are similar to the methods for other array types.</p>
<h4>PVDataCreate</h4>
<p>PVDataCreate is an interface that provides methods that create PVField
interfaces. A factory is provided that creates PVDataCreate.</p>
<pre>class PVDataCreate {
public:
static PVDataCreatePtr getPVDataCreate();
PVFieldPtr createPVField(FieldConstPtr const &amp; field);
PVFieldPtr createPVField(PVFieldPtr const &amp; fieldToClone);
PVScalarPtr createPVScalar(ScalarConstPtr const &amp; scalar);
PVScalarPtr createPVScalar(ScalarType scalarType);
PVScalarPtr createPVScalar(PVScalarPtr const &amp; scalarToClone);
PVScalarArrayPtr createPVScalarArray(ScalarArrayConstPtr const &amp; scalarArray);
PVScalarArrayPtr createPVScalarArray(ScalarType elementType);
PVScalarArrayPtr createPVScalarArray(PVScalarArrayPtr const &amp; scalarArrayToClone);
PVStructureArrayPtr createPVStructureArray(StructureArrayConstPtr const &amp; structureArray);
PVStructurePtr createPVStructure(StructureConstPtr const &amp; structure);
PVStructurePtr createPVStructure(
StringArray const &amp; fieldNames,PVFieldPtrArray const &amp; pvFields);
PVStructurePtr createPVStructure(PVStructurePtr const &amp; structToClone);
...
};
extern PVDataCreatePtr getPVDataCreate();</pre>
<p>where </p>
<dl>
<dt>createPVField</dt>
<dd>The PVField is created reusing the Field interface. Two methods are
provided. Each calls the corresponding createPVScalar, createPVArray, or
createPVStructure depending in the type of the last argument.</dd>
<dt>createPVScalar</dt>
<dd>Creates an instance of a PVScalar. Three versions are supplied. The
first is passed an introspection interface. The second provides the field
name and the scalarType. The last provides a field name and a PVScalar to
clone. The newly created PVScalar will have the same auxInfos as the
original.</dd>
<dt>createPVScalarArray</dt>
<dd>Create an instance of a PVArray. Three versions are supplied. The first
is passed an introspection interface. The second provides the field name
and the elementType. The last provides a field name and a PVArray to
clone. The newly created PVArray will have the same auxInfos as the
original.</dd>
<dt>createPVStructureArray</dt>
<dd>Create a PVStructureArray. It must be passed a structureToClone. This
will become the Structure interface for ALL elements of the
PVStructureArray. It MUST be used to create any new array elements.</dd>
<dt>createPVStructure</dt>
<dd>Create an instance of a PVStructure. Three methods are provided. The
first method uses a previously created structure introspection interface.
The second uses a PVField array to initialize the sub-fields.
The third initializes the subfields by cloning the fields contained in
structToClone. The newly created sub-fields will have the same values and
auxInfos as the original. If structToClone is null then the new structure
is initialized to have 0 sub-fields.</dd>
</dl>
<h3>standardPVField.h</h3>
<p>A class StandardPVField has methods for creating standard data fields. Like
class StandardField it has two forms of the methods which create a field, one
without properties and one with properties. Again the properties is some
combination of alarm, timeStamp, control, display, and valueAlarm. And just
like StandardField there are methods to create the standard properties. The
methods are:</p>
<pre>class StandardPVField;
typedef std::tr1::shared_ptr&lt;StandardPVField&gt; StandardPVFieldPtr;
class StandardPVField : private NoDefaultMethods {
public:
static StandardPVFieldPtr getStandardPVField();
~StandardPVField();
PVStructurePtr scalar(ScalarType type,String const &amp;properties);
PVStructurePtr scalarArray(ScalarType elementType, String const &amp;properties);
PVStructurePtr structureArray(StructureConstPtr const &amp;structure,String const &amp;properties);
PVStructurePtr enumerated(StringArray const &amp;choices);
PVStructurePtr enumerated(StringArray const &amp;choices, String const &amp;properties);
...
}
extern StandardPVFieldPtr getStandardPVField();
</pre>
<h3>Conversion</h3>
<p>There are two facilities for converting between two different PVData
objects:</p>
<dl>
<dt>Convert</dt>
<dd>This preforms all conversions except for coping subarrays.</dd>
<dt>PVSubArray</dt>
<dd>This copies a subarray from one PVArray to another.
The two arrays must have the same element type.</dd>
</dl>
<h4>convert.h</h4>
<p>NOTE about copying immutable array fields. If an entire immutable array
field is copied to another array that has the same elementType, both offsets
are 0, and the length is the length of the source array, then the shareData
method of the target array is called and the target array is set immutable.
Thus the source and target share the same primitive array.</p>
<p>This section describes the supported conversions between data types.</p>
<ul>
<li>All supported types can be converted to a string. If you ask for a 100
megabyte array to be converted to a string expect a lot of output.</li>
<li>Conversion from a string to a scalar type.</li>
<li>Conversion from an array of strings to an array of scalar types.</li>
<li>Copy between the following types of scalar PVs
<ul>
<li>Numeric type to another numeric type</li>
<li>Both have the same type.</li>
<li>Either is a string</li>
</ul>
</li>
<li>Copy between PVArrays that satisfy one of the following.
<ul>
<li>Numeric to numeric</li>
<li>Both have the same type.</li>
<li>Either is a string.</li>
</ul>
</li>
<li>Conversions between numeric scalar types.</li>
<li>Conversions between arrays of numeric type.</li>
<li>Conversion between compatible structures.</li>
<li>A utility method the returns the full field name of a field</li>
</ul>
<pre>
bool operator==(PVField&amp;, PVField&amp;);
static bool operator!=(PVField&amp; a, PVField&amp; b);
bool operator==(const Field&amp;, const Field&amp;);
bool operator==(const Scalar&amp;, const Scalar&amp;);
bool operator==(const ScalarArray&amp;, const ScalarArray&amp;);
bool operator==(const Structure&amp;, const Structure&amp;);
bool operator==(const StructureArray&amp;, const StructureArray&amp;);
static inline bool operator!=(const Field&amp; a, const Field&amp; b);
static inline bool operator!=(const Scalar&amp; a, const Scalar&amp; b);
static inline bool operator!=(const ScalarArray&amp; a, const ScalarArray&amp; b);
static inline bool operator!=(const Structure&amp; a, const Structure&amp; b);
static inline bool operator!=(const StructureArray&amp; a, const StructureArray&amp; b);
class Convert;
typedef std::tr1::shared_ptr&lt;Convert&gt; ConvertPtr;
class Convert {
public:
static ConvertPtr getConvert();
~Convert();
void getFullName(StringBuilder buf,PVFieldPtr const &amp; pvField);
bool equals(PVFieldPtr const &amp;a,PVFieldPtr const &amp;b);
bool equals(PVField &amp;a,PVField &amp;b);
void getString(StringBuilder buf,PVFieldPtr const &amp; pvField,int indentLevel);
void getString(StringBuilder buf,PVFieldPtr const &amp; pvField);
void getString(StringBuilder buf,PVField const * pvField,int indentLevel);
void getString(StringBuilder buf,PVField const * pvField);
std::size_t fromString(
PVStructurePtr const &amp;pv,
StringArray const &amp; from,
std::size_t fromStartIndex = 0);
void fromString(PVScalarPtr const &amp; pv, String const &amp; from);
std::size_t fromString(PVScalarArrayPtr const &amp; pv, String const &amp;from);
std::size_t fromStringArray(
PVScalarArrayPtr const &amp; pv,
std::size_t offset, std::size_t length,
StringArray const &amp; from,
std::size_t fromOffset);
std::size_t toStringArray(PVScalarArrayPtr const &amp; pv,
std::size_t offset,
std::size_t length,
StringArray &amp; to,
std::size_t toOffset);
bool isCopyCompatible(FieldConstPtr const &amp; from, FieldConstPtr const &amp; to);
void copy(PVFieldPtr const &amp; from, PVFieldPtr const &amp; to);
bool isCopyScalarCompatible(
ScalarConstPtr const &amp; from,
ScalarConstPtr const &amp; to);
void copyScalar(PVScalarPtr const &amp; from, PVScalarPtr const &amp; to);
bool isCopyScalarArrayCompatible(
ScalarArrayConstPtr const &amp; from,
ScalarArrayConstPtr const &amp; to);
std::size_t copyScalarArray(
PVScalarArrayPtr const &amp; from,
std::size_t offset,
PVScalarArrayPtr const &amp; to,
std::size_t toOffset,
std::size_t length);
bool isCopyStructureCompatible(
StructureConstPtr const &amp; from, StructureConstPtr const &amp; to);
void copyStructure(PVStructurePtr const &amp; from, PVStructurePtr const &amp; to);
bool isCopyStructureArrayCompatible(
StructureArrayConstPtr const &amp; from, StructureArrayConstPtr const &amp; to);
void copyStructureArray(
PVStructureArrayPtr const &amp; from, PVStructureArrayPtr const &amp; to);
int8 toByte(PVScalarPtr const &amp; pv);
int16 toShort(PVScalarPtr const &amp; pv);
int32 toInt(PVScalarPtr const &amp; pv);
int64 toLong(PVScalarPtr const &amp; pv);
uint8 toUByte(PVScalarPtr const &amp; pv);
uint16 toUShort(PVScalarPtr const &amp; pv);
uint32 toUInt(PVScalarPtr const &amp; pv);
uint64 toULong(PVScalarPtr const &amp; pv);
float toFloat(PVScalarPtr const &amp; pv);
double toDouble(PVScalarPtr const &amp; pv);
String toString(PVScalarPtr const &amp; pv);
void fromByte(PVScalarPtr const &amp; pv,int8 from);
void fromShort(PVScalarPtr const &amp; pv,int16 from);
void fromInt(PVScalarPtr const &amp; pv, int32 from);
void fromLong(PVScalarPtr const &amp; pv, int64 from);
void fromUByte(PVScalarPtr const &amp; pv,uint8 from);
void fromUShort(PVScalarPtr const &amp; pv,uint16 from);
void fromUInt(PVScalarPtr const &amp; pv, uint32 from);
void fromULong(PVScalarPtr const &amp; pv, uint64 from);
void fromFloat(PVScalarPtr const &amp; pv, float from);
void fromDouble(PVScalarPtr const &amp; pv, double from);
void newLine(StringBuilder buf, int indentLevel);
...
}
extern ConvertPtr getConvert();
</pre>
<p>newLine is a convenience method for code that implements toString It
generates a newline and inserts blanks at the beginning of the newline.</p>
<h4>pvSubArrayCopy.h</h4>
<pre>
template&lt;typename T&gt;
void copy(
PVValueArray&lt;T&gt; &amp; pvFrom,
size_t fromOffset,
PVValueArray&lt;T&gt; &amp; pvTo,
size_t toOffset,
size_t len);
void copy(
PVScalarArray &amp; from,
size_t fromOffset,
PVScalarArray &amp; to,
size_t toOffset,
size_t len);
void copy(
PVStructureArray &amp; from,
size_t fromOffset,
PVStructureArray &amp; to,
size_t toOffset,
size_t len);
void copy(
PVArray &amp; from,
size_t fromOffset,
PVArray &amp; to,
size_t toOffset,
size_t len);
</pre>
<p>The last copy is the only one most client need to call.
It either throws an error of the element types do not match or calls the
other copy functions. The arguments are:</p>
<dl>
<dt>from</dt>
<dd>The source array.</dd>
<dt>fromOffset</dt>
<dd>The offset into the source array.</dd>
<dt>to</dt>
<dd>The destination array. The element type must be the same
as for the source array. If the element type is structure then
the introspection interface for the element types must be the same.
</dd>
<dt>toOffset</dt>
<dd>The offset into the destination array.</dd>
<dt>len</dt>
<dd>The number of elements to copy.</dd>
</dl>
<p>An exception is thrown if:</p>
<dl>
<dt>type mismatch</dt>
<dd>The element types for the source and destination differ.</dd>
<dt>immutable</dt>
<dd>The destination array is immutable.</dt>
<dt>capacity immutable</dt>
<dd>The destination array needs to have it's capacity extentended
but the capacity is immutable.</dd>
</dl>
<h2>pvDataApp/property</h2>
<h3>Definition of Property</h3>
<p>Only fields named "value" have properties. A record can have multiple value
fields, which can appear in the top level structure of a record or in a
substructure. All other fields in the structure containing a value field are
considered properties of the value field. The fieldname is also the property
name. The value field can have any type, i.e. scalar, scalarArray, or
structure. Typical property fields are timeStamp, alarm, display, control, and
history. The timeStamp is a special case. If it appears anywhere in the
structure hieraracy above a value field it is a property of the value field.</p>
<p>For example the following top level structure has a single value field. The
value field has properties alarm, timeStamp, and display.</p>
<pre>structure counterOutput
double value
alarm_t
int severity 0
int status 0
string message
timeStamp_t
long secondsPastEpoch
int nanoSeconds
int userTag
display_t
double limitLow 0.0
double limitHigh 10.0
string description "Sample Description"
string format "%f"
string units volts</pre>
<p>The following example has three value fields each with properties alarm and
timeStamp. Voltage, Current, and Power each have a different alarms but all
share the timeStamp.</p>
<pre>structure powerSupplyValue
double value
alarm_t
int severity 0
int status 0
string message
structure powerSupplySimple
alarm_t
int severity 0
int status 0
string message
timeStamp_t
long secondsPastEpoch
int nanoSeconds
int userTag
powerSupplyValue_t voltage
double value
alarm_t
int severity 0
int status 0
string message
powerSupplyValue_t power
double value
alarm_t
int severity 0
int status 0
string message
powerSupplyValue_t current
double value
alarm_t
int severity 0
int status 0
string message</pre>
<h3>Standard Properties</h3>
<p>The following field names have special meaning, i.e. support properties for
general purpose clients.</p>
<dl>
<dt>value</dt>
<dd>This is normally defined since most general purpose clients access this
field. All other fields in the structure support or describe the value
field. The type can any supported type but is usually one of the
following:
<dl>
<dt>scalar</dt>
<dd>Any of the scalar types.</dd>
<dt>scalarArray</dt>
<dd>An array with the elementType being a scalar type</dd>
<dt>enumerated structure</dt>
<dd>A structure that includes fields named index and choices. index
is an int that selects a choice. choices is an array of strings
that defines the complete set of choices.</dd>
<dt>other</dt>
<dd>Other structure or array types can also be defined if clients and
support code agree on the meaning. Some examples are: 1) A
structure defining a 2D matrix, 2) A structure defining an image,
3) A structure that simulates a remote method, ...</dd>
</dl>
</dd>
<dt>timeStamp</dt>
<dd>The timeStamp. The type MUST be a timeStamp structure. Also if the
PVData structure does not have a timeStamp then a search up the parent
tree is made to find a timeStamp.</dd>
<dt>alarm</dt>
<dd>The alarm. The type MUST be an alarm structure. </dd>
<dt>display</dt>
<dd>A display structure as described below. It provides display
characteristics for the value field.</dd>
<dt>control</dt>
<dd>A control structure as described below. It provides control
characteristics for the value field.</dd>
<dt>history</dt>
<dd>Provides a history buffer for the value field. Note that currently
PVData does not define history suppoprt.</dd>
<dt>other</dt>
<dd>Other standard properties can be defined.</dd>
</dl>
<p>In addition a structure can have additional fields that support the value
field but are not recognized by most general purpose client tools. Typical
examples are:</p>
<dl>
<dt>input</dt>
<dd>A field with support that changes the value field. This can be
anything. It can be a channel access link. It can obtain a value from
hardware. Etc.</dd>
<dt>valueAlarm</dt>
<dd>A field with support that looks for alarm conditions based on the
value.</dd>
<dt>output</dt>
<dd>A field with support that reads the current value and sends it
somewhere else. This can be anything. It can be a channel access link. It
can write a value to hardware. Etc.</dd>
</dl>
<p>The model allows for device records. A device record has structure fields
that that support the PVData data model. For example a powerSupport record can
have fields power, voltage, current that each support the PVData data model.
</p>
<h3>Overview of Property Support</h3>
<p>Except for enumerated, each property has two files: a property.h and a
pvProperty.h . For example: timeStamp.h and pvTimeStamp.h In each case the
property.h file defined methods for manipulating the property data and the
pvProperty.h provides methods to transfer the property data to/from a pvData
structure. </p>
<p>All methods copy data via copy by value semantics, i.e. not by pointer or by
reference. No property class calls new or delete and all allow the compiler to
generate default methods. All allow a class instance to be generated on the
stack. For example the following is permitted:</p>
<pre>void example(PVFieldPtr const &amp;pvField) {
Alarm alarm;
PVAlarm pvAlarm;
bool result;
result = pvAlarm.attach(pvField);
assert(result);
Alarm al;
al.setMessage(String("testMessage"));
al.setSeverity(majorAlarm);
result = pvAlarm.set(al);
assert(result);
alarm = pvAlarm.get();
...
}</pre>
<h3>timeStamp</h3>
<p>A timeStamp is represented by the following structure</p>
<pre>structure timeStamp
long secondsPartEpoch
int nanoSeconds
int userTag</pre>
<p>The Epoch is the posix epoch, i.e. Jan 1, 1970 00:00:00 UTC. Both the
seconds and nanoSeconds are signed integers and thus can be negative. Since the
seconds is kept as a 64 bit integer, it allows for a time much greater than the
present age of the universe. Since the nanoSeconds portion is kept as a 32 bit
integer it is subject to overflow if a value that corresponds to a value that
is greater than a little more than 2 seconds of less that about -2 seconds. The
support code always adjust seconds so that the nanoSecconds part is normlized,
i. e. it has is 0&lt;=nanoSeconds&lt;nanoSecPerSec..</p>
<p>Two header files are provided for manipulating time stamps:</p>
<dl>
<dt>timeStamp.h</dt>
<dd>Defines a time stamp independent of pvData, i.e. it is a generally
useful class for manipulating timeStamps.</dd>
<dt>pvTimeStamp.h</dt>
<dd>A class that can be attached to a time stamp pvData structure. It
provides get and set methods to get/set a TimeStamp as defined by
timeStamp.h</dd>
</dl>
<h4>timeStamp.h</h4>
<p>This provides </p>
<pre>extern int32 milliSecPerSec;
extern int32 microSecPerSec;
extern int32 nanoSecPerSec;
extern int64 posixEpochAtEpicsEpoch;
class TimeStamp {
public:
TimeStamp()
:secondsPastEpoch(0), nanoSeconds(0), userTag(0) {}
TimeStamp(int64 secondsPastEpoch,int32 nanoSeconds = 0,int32 userTag = 0);
//default constructors and destructor are OK
//This class should not be extended
void normalize();
void fromTime_t(const time_t &amp;);
void toTime_t(time_t &amp;) const;
int64 getSecondsPastEpoch() const {return secondsPastEpoch;}
int64 getEpicsSecondsPastEpoch() const {
return secondsPastEpoch - posixEpochAtEpicsEpoch;
}
int32 getNanoSeconds() const {return nanoSeconds;}
int32 getUserTag() const {return userTag;}
void setUserTag(int userTag) {this-&gt;userTag = userTag;}
void put(int64 secondsPastEpoch,int32 nanoSeconds = 0) {
this-&gt;secondsPastEpoch = secondsPastEpoch;
this-&gt;nanoSeconds = nanoSeconds;
normalize();
}
void put(int64 milliseconds);
void getCurrent();
double toSeconds() const ;
bool operator==(TimeStamp const &amp;) const;
bool operator!=(TimeStamp const &amp;) const;
bool operator&lt;=(TimeStamp const &amp;) const;
bool operator&lt; (TimeStamp const &amp;) const;
bool operator&gt;=(TimeStamp const &amp;) const;
bool operator&gt; (TimeStamp const &amp;) const;
static double diff(TimeStamp const &amp; a,TimeStamp const &amp; b);
TimeStamp &amp; operator+=(int64 seconds);
TimeStamp &amp; operator-=(int64 seconds);
TimeStamp &amp; operator+=(double seconds);
TimeStamp &amp; operator-=(double seconds);
int64 getMilliseconds(); // milliseconds since epoch
...
}</pre>
<p>where</p>
<dl>
<dt>TimeStamp()</dt>
<dd>The defauly constuctor. Both seconds and nanoSeconds are set to 0.</dd>
<dt>TimeStamp(int64 secondsPastEpoch,int32 nanoSeconds = 0)</dt>
<dd>A constructor that gives initial values to seconds and nanoseconds.</dd>
<dt>normalize</dt>
<dd>Adjust seconds and nanoSeconds so that
0&lt;=nanoSeconds&lt;nanoSecPerSec.</dd>
<dt>fromTime_t</dt>
<dd>Set time from standard C time.</dd>
<dt>toTime_t</dt>
<dd>Convert timeStamp to standard C time.</dd>
<dt>getSecondsPastEpoch</dt>
<dd>Get the number of seconds since the epoch.</dd>
<dt>getEpicsSecondsPastEpoch</dt>
<dd>Get the number of EPICS seconds since the epoch. EPICS uses Jan 1, 1990
00:00:00 UTC as the epoch.</dd>
<dt>getNanoSeconds</dt>
<dd>Get the number of nanoSeconds. This is always normalized.</dd>
<dt>getUserTag</dt>
<dd>Get the userTag.</dd>
<dt>setUserTag</dt>
<dd>Set the userTag.</dd>
<dt>put(int64 secondsPastEpoch,int32 nanoSeconds = 0)</dt>
<dd>Set the timeStamp value. If necessary it will be normalized.</dd>
<dt>put(int64 milliseconds)</dt>
<dd>Set the timeStamp with a value the is the number of milliSeconds since
the epoch.</dd>
<dt>getCurrent()</dt>
<dd>Set the timeStamp to the current time.</dd>
<dt>toSeconds()</dt>
<dd>Convert the timeStamp to a value that is the number of seconds since
the epocj</dd>
<dt>operator =</dt>
<dt>operator!=</dt>
<dt>operator&lt;=</dt>
<dt>operator&lt;</dt>
<dt>operator&gt;=</dt>
<dt>operator&gt; </dt>
<dd>Standard C++ operators.</dd>
<dt>diff</dt>
<dd>diff = a - b</dd>
<dt>getMilliseconds</dt>
<dd>Get the number of milliseconds since the epoch.</dd>
</dl>
<p>The TimeStamp class provides arithmetic operations on time stamps. The
result is always kept in normalized form, which means that the nano second
portion is 0&le;=nano&lt;nanoSecPerSec. Note that it is OK to have timeStamps
for times previous to the epoch.</p>
<p>TimeStamp acts like a primitive. It can be allocated on the stack and the
compiler is free to generate default methods, i.e. copy constructor, assignment
constructor, and destructor.</p>
<p>One use for TimeStamp is to time how long a section of code takes to
execute. This is done as follows:</p>
<pre> TimeStamp startTime;
TimeStamp endTime;
...
startTime.getCurrent();
// code to be measured for elapsed time
endTime.getCurrent();
double time = TimeStamp::diff(endTime,startTime);</pre>
<h4>pvTimeStamp.h</h4>
<pre>class PVTimeStamp {
public:
PVTimeStamp();
//default constructors and destructor are OK
//This class should not be extended
//returns (false,true) if pvField(isNot, is valid timeStamp structure
bool attach(PVFieldPtr const &amp;pvField);
void detach();
bool isAttached();
// following throw logic_error if not attached to PVField
// a set returns false if field is immutable
void get(TimeStamp &amp;) const;
bool set(TimeStamp const &amp; timeStamp);
};</pre>
<p>where</p>
<dl>
<dt>PVTimeStamp</dt>
<dd>The default constructor. Attach must be called before get or set can be
called.</dd>
<dt>attach</dt>
<dd>Attempts to attach to pvField It returns (false,true) if a timeStamp
structure is found. It looks first at pvField itself and if is not an
appropriate pvData structure but the field name is value it looks up the
parent structure tree.</dd>
<dt>detach</dt>
<dd>Detach from the pvData structure.</dd>
<dt>isAttached</dt>
<dd>Is there an attachment to a timeStamp structure?</dd>
<dt>get</dt>
<dd>Copies data from the pvData structure to a TimeStamp. An exception is
thrown if not attached to a pvData structure. </dd>
<dt>set</dt>
<dd>Copies data from TimeStamp to the pvData structure. An exception is
thrown if not attached to a pvData structure. </dd>
</dl>
<h3>alarm</h3>
<p>An alarm structure is defined as follows:</p>
<pre>structure alarm
int severity
int status
string message</pre>
<p>Note that neither severity or status is defined as an enumerated structure.
The reason is performance, i. e. prevent passing the array of choice strings
everywhere. The file alarm.h provides the choice strings. Thus all code that
needs to know about alarms share the exact same choice strings.</p>
<p>Two header files are provided for manipulating alarms:</p>
<dl>
<dt>alarm.h</dt>
<dd>Defines an alarm independent of pvData, i.e. it is a generally useful
class for manipulating alarms.</dd>
<dt>pvAlarm.h</dt>
<dd>A class that can be attached to an alarm pvData structure. It provides
get and set methods to get/set alarm data as defined by alarm.h</dd>
</dl>
<h4>alarm.h</h4>
<pre>enum AlarmSeverity {
noAlarm,minorAlarm,majorAlarm,invalidAlarm,undefinedAlarm
};
enum AlarmStatus {
noStatus,deviceStatus,driverStatus,recordStatus,
dbStatus,confStatus,undefinedStatus,clientStatus
};
class AlarmSeverityFunc {
public:
static AlarmSeverity getSeverity(int value);
static StringArrayPtr getSeverityNames();
};
class AlarmStatusFunc {
public:
static AlarmStatus getStatus(int value);
static StringArrayPtr getStatusNames();
};
class Alarm {
public:
Alarm();
//default constructors and destructor are OK
String getMessage();
void setMessage(String const &amp;value);
AlarmSeverity getSeverity() const;
void setSeverity(AlarmSeverity value);
AlarmStatus getStatus() const;
void setStatus(AlarmStatus value);
};</pre>
<p>Alarm Severity defines the possible alarm severities:</p>
<dl>
<dt>getSeverity</dt>
<dd>Get the alarm severity corresponding to the integer value.</dd>
<dt>getSeverityNames</dt>
<dd>Get the array of severity choices.</dd>
</dl>
<p>Alarm Status defines the possible choices for alarm status:</p>
<dl>
<dt>getStatus</dt>
<dd>Get the alarm status corresponding to the integer value.</dd>
<dt>getStatusNames</dt>
<dd>Get the array of status choices.</dd>
</dl>
<p>Alarm has the methods:</p>
<dl>
<dt>Alarm</dt>
<dd>The constructor. It sets the severity to no alarm and the message to
"".</dd>
<dt>getMessage</dt>
<dd>Get the message.</dd>
<dt>setMessage</dt>
<dd>Set the message.</dd>
<dt>getSeverity</dt>
<dd>Get the severity.</dd>
<dt>setSeverity</dt>
<dd>Set the severity.</dd>
<dt>getStatus</dt>
<dd>Get the status.</dd>
<dt>setStatus</dt>
<dd>Set the status.</dd>
</dl>
<h4>pvAlarm.h</h4>
<pre>class PVAlarm {
public:
PVAlarm() : pvSeverity(0),pvMessage(0) {}
//default constructors and destructor are OK
//returns (false,true) if pvField(isNot, is valid enumerated structure
//An automatic detach is issued if already attached.
bool attach(PVFieldPtr const &amp;pvField);
void detach();
bool isAttached();
// each of the following throws logic_error is not attached to PVField
// set returns false if field is immutable
void get(Alarm &amp; alarm) const;
bool set(Alarm const &amp; alarm);
};</pre>
<p>where</p>
<dl>
<dt>PVAlarm</dt>
<dd>The default constructor. Attach must be called before get or set can be
called.</dd>
<dt>attach</dt>
<dd>Attempts to attach to pvField It returns (false,true) if it found an
appropriate pvData structure. It looks first a pvField itself and if is
not an appropriate pvData structure but the field name is value it looks
to see if the parent structure has an appropriate sub structure.</dd>
<dt>detach</dt>
<dd>Just detaches from the pvData structure.</dd>
<dt>isAttached</dt>
<dd>Is there an attachment to an alarm structure?</dd>
<dt>get</dt>
<dd>Copies data from the pvData structure to an Alarm. An exception is
thrown if not attached to a pvData structure. </dd>
<dt>set</dt>
<dd>Copies data from Alarm to the pvData structure. An exception is thrown
if not attached to a pvData structure. </dd>
</dl>
<h3>control</h3>
<p>Control information is represented by the following structure</p>
<pre>structure control
double limitLow
double limitHigh
double minStep</pre>
<p>Two header files are provided for manipulating control:</p>
<dl>
<dt>control.h</dt>
<dd>Defines control independent of pvData, i.e. it is a generally useful
class for manipulating control.</dd>
<dt>pvControl.h</dt>
<dd>A class that can be attached to an control pvData structure. It
provides get and set methods to get/set control data as defined by
control.h</dd>
</dl>
<h4>control.h</h4>
<pre>class Control {
public:
Control();
//default constructors and destructor are OK
double getLow() const;
double getHigh() const;
double getMinStep() const;
void setLow(double value);
void setHigh(double value);
void setMinStep(double value);
};</pre>
<p>where</p>
<dl>
<dt>Control</dt>
<dd>The default constructure.</dd>
<dt>getLow</dt>
<dd>Get the low limit.</dd>
<dt>getHigh</dt>
<dd>Get the high limit.</dd>
<dt>setLow</dt>
<dd>Set the low limit.</dd>
<dt>setHigh</dt>
<dd>Set the high limit.</dd>
<dt>setMinStep</dt>
<dd>Set the minimum step size.</dd>
<dt>getMinStep</dt>
<dd>Get he minimum step size.</dd>
</dl>
<h4>pvControl.h</h4>
<pre>class PVControl {
public:
PVControl();
//default constructors and destructor are OK
//returns (false,true) if pvField(isNot, is valid enumerated structure
//An automatic detach is issued if already attached.
bool attach(PVFieldPtr const &amp;pvField);
void detach();
bool isAttached();
// each of the following throws logic_error is not attached to PVField
// set returns false if field is immutable
void get(Control &amp;) const;
bool set(Control const &amp; control);
};</pre>
<p>where</p>
<dl>
<dt>PVControl</dt>
<dd>The default constructor. Attach must be called before get or set can be
called.</dd>
<dt>attach</dt>
<dd>Attempts to attach to pvField It returns (false,true) if it found an
appropriate pvData structure. It looks first a pvField itself and if is
not an appropriate pvData structure but the field name is value it looks
to see if the parent structure has an appropriate sub structure.</dd>
<dt>detach</dt>
<dd>Just detaches from the pvData structure.</dd>
<dt>isAttached</dt>
<dd>Is there an attachment to a control structure?</dd>
<dt>get</dt>
<dd>Copies data from the pvData structure to a Control. An exception is
thrown if not attached to a pvData structure. </dd>
<dt>set</dt>
<dd>Copies data from Control to the pvData structure. An exception is
thrown if not attached to a pvData structure. </dd>
</dl>
<h3>display</h3>
<p>Display information is represented by the following structure</p>
<pre>structure display
double limitLow
double limitHigh
string description
string format
string units</pre>
<p>Two header files are provided for manipulating display:</p>
<dl>
<dt>display.h</dt>
<dd>Defines display independent of pvData, i.e. it is a generally useful
class for manipulating display.</dd>
<dt>pvDisplay.h</dt>
<dd>A class that can be attached to an display pvData structure. It
provides get and set methods to get/set display data as defined by
display.h</dd>
</dl>
<h4>display.h</h4>
<pre>class Display {
public:
Display();
//default constructors and destructor are OK
double getLow() const;
double getHigh() const;
void setLow(double value);
void setHigh(double value);
String getDescription() const;
void setDescription(String const &amp;value);
String getFormat() const;
void setFormat(String const &amp;value);
String getUnits() const;
void setUnits(String const &amp;value);
};</pre>
<p>where</p>
<dl>
<dt>Control</dt>
<dd>The default constructure.</dd>
<dt>getLow</dt>
<dd>Get the low limit.</dd>
<dt>getHigh</dt>
<dd>Get the high limit.</dd>
<dt>setLow</dt>
<dd>Set the low limit.</dd>
<dt>setHigh</dt>
<dd>Set the high limit.</dd>
<dt>getDescription</dt>
<dd>Get the description.</dd>
<dt>setDescription</dt>
<dd>Set the description.</dd>
<dt>getFormat</dt>
<dd>Get the format.</dd>
<dt>setFormat</dt>
<dd>Set the format.</dd>
<dt>getUnits</dt>
<dd>Get the units.</dd>
<dt>setUnits</dt>
<dd>Set the units.</dd>
</dl>
<h4>pvDisplay.h</h4>
<pre>class PVDisplay {
public:
PVDisplay()
: pvDescription(0),pvFormat(),pvUnits(),pvLow(),pvHigh() {}
//default constructors and destructor are OK
//An automatic detach is issued if already attached.
bool attach(PVFieldPtr const&amp;pvField);
void detach();
bool isAttached();
// each of the following throws logic_error is not attached to PVField
// a set returns false if field is immutable
void get(Display &amp;) const;
bool set(Display const &amp; display);
};</pre>
<p>where</p>
<dl>
<dt>PVDisplay</dt>
<dd>The default constructor. Attach must be called before get or set can be
called.</dd>
<dt>attach</dt>
<dd>Attempts to attach to pvField It returns (false,true) if it found an
appropriate pvData structure. It looks first a pvField itself and if is
not an appropriate pvData structure but the field name is value it looks
to see if the parent structure has an appropriate sub structure.</dd>
<dt>detach</dt>
<dd>Just detaches from the pvData structure.</dd>
<dt>isAttached</dt>
<dd>Is there an attachment to a display structure?</dd>
<dt>get</dt>
<dd>Copies data from the pvData structure to a Display. An exception is
thrown if not attached to a pvData structure.</dd>
<dt>set</dt>
<dd>Copies data from Display to the pvData structure. An exception is
thrown if not attached to a pvData structure. </dd>
</dl>
<h3>pvEnumerated.h</h3>
<p>An enumerated structure is a structure that has fields:</p>
<pre>structure
int index
string[] choices</pre>
<p>For enumerated structures a single header file pvEnumerted.h is available</p>
<pre>class PVEnumerated {
public:
PVEnumerated();
//default constructors and destructor are OK
//This class should not be extended
//returns (false,true) if pvField(isNot, is valid enumerated structure
//An automatic detach is issued if already attached.
bool attach(PVFieldPtr const &amp;pvField);
void detach();
bool isAttached();
// each of the following throws logic_error is not attached to PVField
// a set returns false if field is immutable
bool setIndex(int32 index);
int32 getIndex();
String getChoice();
bool choicesMutable();
StringArrayPtr const &amp; getChoices();
int32 getNumberChoices();
bool setChoices(StringArray &amp;choices,int32 numberChoices);
};</pre>
<p>where</p>
<dl>
<dt>PVEnumerated</dt>
<dd>The default constructor. Attach must be called before any get or set
method can be called.</dd>
<dt>attach</dt>
<dd>Attempts to attach to pvField It returns (false,true) if pvField (is
not, is) an enumerated structure.</dd>
<dt>detach</dt>
<dd>Just detaches from the pvData structure.</dd>
<dt>isAttached</dt>
<dd>Is there an attachment to an enemerated structure?</dd>
<dt>setIndex</dt>
<dd>Set the index field in the pvData structure. An exception is thrown if
not attached to a pvData structure. </dd>
<dt>getIndex</dt>
<dd>Get the index field in the pvData structure. </dd>
<dt>getChoice</dt>
<dd>Get the String value corresponding to the current index field in the
pvData structure. An exception is thrown if not attached to a pvData
structure. </dd>
<dt>choicesMutable</dt>
<dd>Can the choices be changed? Note that this is often true. An exception
is thrown if not attached to a pvData structure. </dd>
<dt>getChoices</dt>
<dd>Get the array of choices. An exception is thrown if not attached to a
pvData structure. </dd>
<dt>getNumberChoices</dt>
<dd>Get the number of choices. An exception is thrown if not attached to a
pvData structure. </dd>
<dt>setChoices</dt>
<dd>Change the choices. An exception is thrown if not attached to a pvData
structure. </dd>
</dl>
<h2>Examples</h2>
<h3>Accessing PVData</h3>
<p>Assume that code wants to print two fields from a PVStructure:</p>
<dl>
<dt>value</dt>
<dd>Must be a PVDouble.</dd>
<dt>timeStamp</dt>
<dd>Just look for field with this name.</dd>
</dl>
<p>The following code uses introspection to get the desired information.</p>
<pre>void getValueAndTimeStamp(PVStructurePtr pvStructure,StringBuilder buf) {
PVFieldPtr valuePV = pvStructure-&gt;getSubField(String("value"));
if(valuePV.get()==NULL) {
buf += "value field not found";
return;
}
buf += "value ";
valuePV-&gt;toString(&amp;buf);
PVFieldPtr timeStampPV = pvStructure-&gt;getSubField(String("timeStamp"));
if(timeStampPV.get()==NULL) {
buf += "timeStamp field not found";
return;
}
buf += " timeStamp ";
timeStampPV-&gt;toString(&amp;buf);
}</pre>
<h3>Creating PVData</h3>
<p>Example of creating a scalar field.</p>
<pre> PVDataCreatePtr pvDataCreate = getPVDataCreate();
PVDoublePtr pvValue = static_pointer_cast&lt;PVDouble&gt;(
pvDataCreate-&gt;createPVScalar(pvDouble));</pre>
<p>Create a structure with a value and an alarm the hard way</p>
<pre> FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
FieldConstPtrArray fields;
StringArray names;
fields.resize(3);
names.resize(3);
fields[0] = fieldCreate-&gt;createScalar(pvInt);
fields[1] = fieldCreate-&gt;createScalar(pvInt);
fields[2] = fieldCreate-&gt;createScalar(pvString);
names[0] = "severity";
names[0] = "status";
names[0] = "message";
StructureConstPtr alarmField =
fieldCreate-&gt;createStructure(names,fields);
fields.resize(2);
names.resize(2);
fields[0] = fieldCreate-&gt;createScalar(pvDouble);
fields[1] = alarmField;
names[0] = "value";
names[0] = "alarm";
StructureConstPtr structure =
fieldCreate-&gt;createStructure(names,fields);
PVStructurePtr pv = pvDataCreate-&gt;createPVStructure(structure);</pre>
<p>Create an alarm structure the easy way.</p>
<pre> StandardPVFieldPtr standardPVField = getStandardPVField();
PVStructurePtr pv = standardPVField-&gt;scalar(pvDouble,"alarm");</pre>
<p>Create a PVStructure with field name example that has a double value field ,
timeStamp, alarm, and display. Do it the easy way.</p>
<pre> StandardPVFieldPtr standardPVField = getStandardPVField();
PVStructurePtr pvStructure = standardPVField-&gt;scalar(
pvDouble,"timeStamp,alarm.display");</pre>
<h2>pvDataApp/factory</h2>
<p>Directory factory has code that implements everything described by the files
in directory pv</p>
<p>TypeFunc.cpp implements the functions for the enums defined in
pvIntrospecct.h</p>
<p>FieldCreateFactory.cpp automatically creates a single instance of
FieldCreate and implements getFieldCreate.</p>
<p>PVDataCreateFactory.cpp automatically creates a single instance of
PVDataCreate and implements getPVDataCreate.</p>
<p>Convert.cpp automatically creates a single instance of Convert and
implements getConvert.</p>
<p>Other files implement PVData base classes</p>
<h2>pvDataAPP/misc</h2>
<h3>Overview</h3>
<p>This package provides utility code:</p>
<dl>
<dt>bitSet.h</dt>
<dd>An implementation of BitSet that can be serialized.</dd>
<dt>byteBuffer.h</dt>
<dd>Used to serialize objects.</dd>
<dt>destroyable.h</dt>
<dd>Provides method destroy.</dd>
<dt>epicsException.h</dt>
<dd>Exception with stack trace.</dd>
<dt>event.h</dt>
<dd>Signal and wait for an event.</dd>
<dt>executor.h</dt>
<dd>Provides a thread for executing commands.</dd>
<dt>localStaticLock.h</dt>
<dd><b>TBD</b> Matej can You explain what this does?</dd>
<dt>lock.h</dt>
<dd>Support for locking and unlocking.</dd>
<dt>messageQueue.h</dt>
<dd>Support for queuing messages to give to requesters.</dd>
<dt>noDefaultMethods.h</dt>
<dd>When privately extended prevents compiler from implementing default
methods.</dd>
<dt>queue.h</dt>
<dd>A queue implementation that allows the latest queue element to continue
to be used when no free element is available.</dd>
<dt>requester.h</dt>
<dd>Allows messages to be sent to a requester.</dd>
<dt>serialize.h</dt>
<dd>Support for serializing objects.</dd>
<dt>serializeHelper.h</dt>
<dd>More support for serializing objects.</dd>
<dt>sharedPtr.h</dt>
<dd>Defines POINTER_DEFINITIONS.</dd>
<dt>sharedVector.h</dd>
<dd>Like std::vector except that std::shared_ptr is used for
the data array.</dd>
<dt>status.h</dt>
<dd>A way to pass status information to a client.</dd>
<dt>templateMeta.h</dt>
<dd><b>TBD</b> Michael can You provide an explaination?</dd>
<dt>thread.h</dt>
<dd>Provides thread support.</dd>
<dt>timeFunction.h</dt>
<dd>Time how long a function call requires.</dd>
<dt>timer.h</dt>
<dd>An implementation of Timer that does not require an object to be
created for each timer request.</dd>
<dt>typeCast.h</dt>
<dd><b>TBD</b> Michael can You provide an explaination?</dd>
</dl>
<p>Note that directory testApp/misc has test code for all the classes in misc.
The test code also can be used as examples.</p>
<h3>bitSet.h</h3>
<p>This is adapted from the java.util.BitSet. bitSet.h is:</p>
<pre>
class BitSet;
typedef std::tr1::shared_ptr&lt;BitSet&gt; BitSetPtr;
class BitSet : public Serializable {
public:
static BitSetPtr create(uint32 nbits);
BitSet();
BitSet(uint32 nbits);
virtual ~BitSet();
void flip(uint32 bitIndex);
void set(uint32 bitIndex);
void clear(uint32 bitIndex);
void set(uint32 bitIndex, bool value);
bool get(uint32 bitIndex) const;
void clear();
int32 nextSetBit(uint32 fromIndex) const;
int32 nextClearBit(uint32 fromIndex) const;
bool isEmpty() const;
uint32 cardinality() const;
uint32 size() const;
BitSet&amp; operator&amp;=(const BitSet&amp; set);
BitSet&amp; operator|=(const BitSet&amp; set);
BitSet&amp; operator^=(const BitSet&amp; set);
BitSet&amp; operator-=(const BitSet&amp; set);
BitSet&amp; operator=(const BitSet &amp;set);
void or_and(const BitSet&amp; set1, const BitSet&amp; set2);
bool operator==(const BitSet &amp;set) const;
bool operator!=(const BitSet &amp;set) const;
void toString(StringBuilder buffer, int indentLevel = 0) const;
virtual void serialize(
ByteBuffer *buffer,SerializableControl *flusher) const;
virtual void deserialize(
ByteBuffer *buffer,DeserializableControl *flusher);
private:
};</pre>
<p>where</p>
<dl>
<dt>BitSet()</dt>
<dd>Creates a bitSet of initial size 64 bits. All bits initially false.</dd>
<dt>BitSet(uint32 nbits)</dt>
<dd>Creates a bitSet with the initial of the specified number of bits. All
bits initially false.</dd>
<dt>~BitSet()</dt>
<dd>Destructor.</dd>
<dt>flip(uint32 bitIndex)</dt>
<dd>Flip the specified bit.</dd>
<dt>set(uint32 bitIndex)</dt>
<dd>Set the specified bit true.</dd>
<dt>clear(uint32 bitIndex)</dt>
<dd>Set the specified bit false.</dd>
<dt>set(uint32 bitIndex, bool value)</dt>
<dd>Set the specified bit to value.</dd>
<dt>get(uint32 bitIndex)</dt>
<dd>Return the state of the specified bit.</dd>
<dt>clear()</dt>
<dd>Set all bits to false.</dd>
<dt>nextSetBit(uint32 fromIndex)</dt>
<dd>Get the index of the next true bit beginning with the specified
bit.</dd>
<dt>nextClearBit(uint32 fromIndex)</dt>
<dd>Get the index of the next false bit beginning with the specified
bit.</dd>
<dt>isEmpty()</dt>
<dd>Return (false,true) if (at least one bit true, all bits are false)</dd>
<dt>cardinality()</dt>
<dd>Return the number of true bits.</dd>
<dt>size()</dt>
<dd>Returns the number of bits of space actually in use.</dd>
<dt>operator&amp;=(const BitSet&amp; set)</dt>
<dd>Performs a logical and of this target bit set with the argument bit
set. This bit set is modified so that each bit in it has the value true
if and only if it both initially had the value true and the corresponding
bit in the bit set argument also had the value.</dd>
<dt>operator|=(const BitSet&amp; set)</dt>
<dd>Performs a logical or of this target bit set with the argument bit
set.</dd>
<dt>operator^=(const BitSet&amp; set)</dt>
<dd>Performs a logical exclusive or of this target bit set with the
argument bit set.</dd>
<dt>operator-=(const BitSet&amp; set)</dt>
<dd><p>Clears all of the bits in this bitSet whose corresponding bit is set
in the specified bitSet.</p>
</dd>
<dt>operator=(const BitSet &amp;set)</dt>
<dd>Assignment operator.</dd>
<dt>or_and(const BitSet&amp; set1, const BitSet&amp; set2)</dt>
<dd>Perform AND operation on set1 and set2, and then OR this bitSet with
the result.</dd>
<dt>operator==(const BitSet &amp;set)</dt>
<dd>Does this bitSet have the same values as the argument.</dd>
<dt>operator!=(const BitSet &amp;set)</dt>
<dd>Is this bitSet different than the argument.</dd>
<dt>toString(StringBuilder buffer, int indentLevel)</dt>
<dd>Show the current values of the bitSet.</dd>
<dt>virtual void serialize(ByteBuffer *buffer,SerializableControl *flusher)
const;</dt>
<dd>Serialize the bitSet</dd>
<dt>virtual void deserialize(ByteBuffer *buffer,DeserializableControl
*flusher);</dt>
<dd>Deserialize the bitSet.</dd>
</dl>
<p><b>TBD</b>
<dl>
<dt>implemantation</dt>
<dd>This should be changed so that capacity can not change.</dd>
<dt>toString</dt>
<dd>Should this change and also implement ostream operator?</dd>
</dl>
</p>
<h3>byteBuffer.h</h3>
<p>A ByteBuffer is used to serialize and deserialize primitive data. File
byteBuffer.h is:</p>
<pre>class ByteBuffer {
public:
ByteBuffer(std::size_t size, int byteOrder = EPICS_BYTE_ORDER)
~ByteBuffer();
void setEndianess(int byteOrder);
const char* getBuffer();
void clear();
void flip();
void rewind();
std::size_t getPosition();
void setPosition(std::size_t pos);
std::size_t getLimit();
void setLimit(std::size_t limit);
std::size_t getRemaining();
std::size_t getSize();
template&lt;typename T&gt;
void put(T value)
template&lt;typename T&gt;
void put(std::size_t index, T value);
template&lt;typename T&gt;
T get()
template&lt;typename T&gt;
T get(std::size_t index)
void put(const char* src, std::size_t src_offset, std::size_t count);
void get(char* dest, std::size_t dest_offset, std::size_t count);
template&lt;typename T&gt;
inline void putArray(T* values, std::size_t count)
template&lt;typename T&gt;
inline void getArray(T* values, std::size_t count)
template&lt;typename T&gt;
inline bool reverse();
inline void align(std::size_t size)
void putBoolean( bool value);
void putByte ( int8 value);
void putShort ( int16 value);
void putInt ( int32 value);
void putLong ( int64 value);
void putFloat ( float value);
void putDouble (double value);
void putBoolean(std::size_t index, bool value);
void putByte (std::size_t index, int8 value);
void putShort (std::size_t index, int16 value);
void putInt (std::size_t index, int32 value);
void putFloat (std::size_t index, float value);
void putDouble (std::size_t index, double value);
bool getBoolean();
int8 getByte ();
int16 getShort ();
int32 getInt ();
int64 getLong ();
float getFloat ();
double getDouble ();
bool getBoolean(std::size_t index);
int8 getByte (std::size_t index);
int16 getShort (std::size_t index);
int32 getInt (std::size_t index);
int64 getLong (std::size_t index);
float getFloat (std::size_t index);
double getDouble (std::size_t index);
const char* getArray();
...
};</pre>
<h3>destroyable.h</h3>
<pre>class Destroyable {
public:
POINTER_DEFINITIONS(Destroyable);
virtual void destroy() = 0;
virtual ~Destroyable() {};
};</pre>
<h3>epicsException.h</h3>
<pre>/*
* Throwing exceptions w/ file+line# and, when possibly, a stack trace
*
* THROW_EXCEPTION1( std::bad_alloc );
*
* THROW_EXCEPTION2( std::logic_error, "my message" );
*
* THROW_EXCEPTION( mySpecialException("my message", 42, "hello", ...) );
*
* Catching exceptions
*
* catch(std::logic_error&amp; e) {
* fprintf(stderr, "%s happened\n", e.what());
* PRINT_EXCEPTION2(e, stderr);
* cout&lt;&lt;SHOW_EXCEPTION(e);
* }
*
* If the exception was not thrown with the above THROW_EXCEPTION*
* the nothing will be printed.
*/</pre>
<h3>event.h</h3>
<p>This class provides coordinates activity between threads. One thread can
wait for the event and the other signals the event.</p>
<pre>class Event;
typedef std::tr1::shared_ptr&lt;Event&gt; EventPtr;
class Event {
public:
POINTER_DEFINITIONS(Event);
explicit Event(bool = false);
~Event();
void signal();
bool wait (); /* blocks until full */
bool wait ( double timeOut ); /* false if empty at time out */
bool tryWait (); /* false if empty */
...
}; </pre>
<p>where</p>
<dl>
<dt>Event</dt>
<dd>The constructor. The initial value can be full or empty. The normal
first state is empty.</dd>
<dt>signal</dt>
<dd>The event becomes full. The current or next wait will complete.</dd>
<dt>wait</dt>
<dd>Wait until event is full or until timeout. The return value is
(false,true) if the wait completed because event (was not, was) full. A
false value normally means that that a timeout occured. It is also
returned if an error occurs or because the event is being deleted.</dd>
<dt>tryWait</dt>
<dd>returns (false,true) if the event is (empty,full)</dd>
</dl>
<h3>executor.h</h3>
<p>An Executor is a thread that can execute commands. The user can request that
a single command be executed.</p>
<pre>
class Command;
class Executor;
typedef std::tr1::shared_ptr&lt;Command&gt; CommandPtr;
typedef std::tr1::shared_ptr&lt;Executor&gt; ExecutorPtr;
class Command {
public:
POINTER_DEFINITIONS(Command);
virtual ~Command(){}
virtual void command() = 0;
private:
CommandPtr next;
friend class Executor;
};
class Executor : public Runnable{
public:
POINTER_DEFINITIONS(Executor);
Executor(String threadName,ThreadPriority priority);
~Executor();
void execute(CommandPtr const &amp;node);
virtual void run();
...
};</pre>
<p>Command is a class that must be implemented by the code that calls execute.
It contains the single virtual method command, which is the command to
execute.</p>
<p>Executor has the methods:</p>
<dl>
<dt>Executor</dt>
<dd>The constructor. A thread name and priority must be specified.</dd>
<dt>~Executor</dt>
<dd>The destructor. If any commands remain in the execute list they are not
called. All ExecutorNodes that have been created are deleted.</dd>
<dt>execute</dt>
<dd>Request that command be executed. If it is already on the run list
nothing is done.</dd>
</dl>
<h3>localStaticLock.h</h3>
<pre>
extern epics::pvData::Mutex&amp; getLocalStaticInitMutex();
static class MutexInitializer {
public:
MutexInitializer ();
~MutexInitializer ();
} localStaticMutexInitializer; // Note object here in the header.
</pre>
<p><b>TBD</b> Matej will explain. </p>
<h3>lock.h</h3>
<pre>
typedef epicsMutex Mutex;
class Lock : private NoDefaultMethods {
public:
explicit Lock(Mutex &amp;pm);
~Lock();
void lock();
void unlock();
bool tryLock();
bool ownsLock() ;
...
};</pre>
<p>Lock is as easy to use as Java synchronize. To protect some object just
create a Mutex for the object and then in any method to be synchronized just
have code like:</p>
<pre>class SomeClass {
private
Mutex mutex;
...
public
SomeClass() : mutex(Mutex()) {}
...
void method()
{
Lock xx(mutex);
...
}
</pre>
<p>The method will take the lock when xx is created and release the lock when
the current code block completes.</p>
<p>Another example of Lock is initialization code that must initialize only
once. This can be implemented as follows:</p>
<pre> static void init(void) {
static Mutex mutex;
Lock guard(mutex);
if(alreadyInitialized) return;
// initialization
}</pre>
<p>
<p>Lock has a private variable:
<pre>
bool locked;
</pre>
and improves efficency by checking the local variable before calling the
mutex methods. This is <b>not</b> thread safe if any methods are called by a thread other than
the thread that created the Lock.
</p>
<p>It is thread safe if used as follows:</p>
<pre>
{
Lock guard(mutex);
...
/* the following can optionally be called
guard.unlock();
guard.lock();
*/
}
</pre>
<p>It is <b>not</b> thread safe if used as follows:</p>
<pre>
class SomeClass
{
private:
Mutex mutex;
Lock lock;
public:
SomeClass: lock(mutex) {}
...
void someMethod() {
lock.unlock();
...
}
...
};
</pre>
<p>It is only safe if all methods of Lock, including <b>~Lock()</b>,
are called by the same thread.
</p>
<h3>messageQueue.h</h3>
<h4>Definitions</h4>
<p>A messageQueue is for use by code that wants to handle messages without
blocking higher priority threads.</p>
<pre>class MessageNode;
class MessageQueue;
typedef std::tr1::shared_ptr&lt;MessageNode&gt; MessageNodePtr;
typedef std::vector&lt;MessageNodePtr&gt; MessageNodePtrArray;
typedef std::tr1::shared_ptr&lt;MessageQueue&gt; MessageQueuePtr;
class MessageNode {
public:
String getMessage() const;
MessageType getMessageType() const;
void setMessageNull();
};
class MessageQueue : public Queue&lt;MessageNode&gt; {
public:
POINTER_DEFINITIONS(MessageQueue);
static MessageQueuePtr create(int size);
MessageQueue(MessageNodePtrArray &amp;nodeArray);
virtual ~MessageQueue();
MessageNodePtr &amp;get();
// must call release before next get
void release();
// return (false,true) if message (was not, was) put into queue
bool put(String message,MessageType messageType,bool replaceLast);
bool isEmpty() ;
bool isFull() ;
int getClearOverrun();
...
};</pre>
<p>A messageNode is a class with two public data members:</p>
<dl>
<dt>getMessage</dt>
<dd>The message.</dd>
<dt>getMessageType</dt>
<dd>The message type.</dd>
<dt>setMessageNull</dt>
<dd>Set the message to be a null string.</dd>
</dl>
<p>A messageQueue is an interface with public methods:</p>
<dl>
<dt>MessageQueue</dt>
<dd>The constructor. The queue size must be specified.</dd>
<dt>~MessageQueue</dt>
<dd>The destructor.</dd>
<dt>put</dt>
<dd>Put a new message into the queue. False is returned if the queue was
full and true otherwise. If replaceLast is true then the last message is
replaced with this message. </dd>
<dt>get</dt>
<dd>Get the oldest queue element. If the queue is empty null is returned.
Before the next get can be issued release must be called.</dd>
<dt>release</dt>
<dd>Release the queue element returned by the last get.</dd>
<dt>isEmpty</dt>
<dd>Is the queue empty?</dd>
<dt>isFull</dt>
<dd>Is the queue full?</dd>
<dt>getClearOverrun</dt>
<dd>Get the number of times put has been called but no free element is
available.</dd>
</dl>
<p>Look at miscTest/testMessageQueue.cpp for an example.</p>
<h3>noDefaultMethods.h</h3>
<p>If a class privately extends this class then the compiler can not create any
of the following: default constructor, default copy constructror, or default
assignment contructor.</p>
<pre>/* This is based on Item 6 of
* Effective C++, Third Edition, Scott Meyers
*/
class NoDefaultMethods {
protected:
// allow by derived objects
NoDefaultMethods(){};
~NoDefaultMethods(){}
private:
// do not implment
NoDefaultMethods(const NoDefaultMethods&amp;);
NoDefaultMethods &amp; operator=(const NoDefaultMethods &amp;);
};</pre>
<h3>queue.h</h3>
<p>This provides a bounded queue. When the queue is
full the user code is expected to keep using the current element until a new
free element becomes avalable.</p>
<pre>
template &lt;typename T&gt;
class Queue
{
public:
POINTER_DEFINITIONS(Queue);
typedef std::tr1::shared_ptr&lt;T&gt; queueElementPtr;
typedef std::vector&lt;queueElementPtr&gt; queueElementPtrArray;
Queue(queueElementPtrArray &amp;);
virtual ~Queue();
void clear();
int capacity();
int getNumberFree();
int getNumberUsed();
queueElementPtr &amp; getFree();
void setUsed(queueElementPtr const &amp;element);
queueElementPtr &amp; getUsed();
void releaseUsed(queueElementPtr const &amp;element);
...
};</pre>
<p>testApp/misc/testQueue.cpp provides an example of how to define a queue.</p>
<p>The queue methods are:</p>
<dl>
<dt>clear</dt>
<dd>Make the queue empty.</dd>
<dt>getNumberFree</dt>
<dd>Get the number of free elements in the queue.</dd>
<dt>capacity</dt>
<dd>Get the capacity, i.e. the maximun number of elements the queue can
hold.</dd>
<dt>getNumberFree</dt>
<dd>Get the number of free elements.</dd>
<dt>getNumberUsed</dt>
<dd>Get the number of elements used.</dd>
<dt>getFree</dt>
<dd>Get the next free element. Null is returned if no free elements are
available. If a non null value is returned then the element belongs to
the caller until setUsed is called.</dd>
<dt>setUsed</dt>
<dd>Set a queue element used. This must be the element returned by the last
call to getFree. </dd>
<dt>getUsed</dt>
<dd>Get the next used element of null if no more used elements are
available.</dd>
<dt>releaseUsed</dt>
<dd>Set a queue element free. This must be the element returned by the last
call to getUsed. </dd>
</dl>
<p>A queue is created as follows:</p>
<pre> class MyClass;
typedef MyQueueElement&lt;MyClass&gt; MyElement;
typedef MyQueue&lt;MyClass&gt; MyQueue;
int numElement = 5;
...
MyClass *array[numElements];
for(int i=0; i&lt;numElements; i++) {
array[i] = new MyClass();
}
MyQueue *queue = new MyQueue(array,numElements);</pre>
<p>A producer calls getFree and setUsed via code like the following:</p>
<pre> MyClass *getFree() {
MyElement *element = queue-&gt;getFree();
if(element==0) return 0;
return element-&gt;getObject();
}</pre>
<p>A consumer calls getUsed and releaseUsed via code like the following:</p>
<pre> while(true) {
MyElement *element = queue-&gt;getUsed();
if(element==0) break;
MyClass *myClass = element-&gt;getObject();
// do something with myClass
queue-&gt;releaseUsed(element);
}</pre>
<h3>requester.h</h3>
<p>Requester is present so that when
errors are found there is someplace to send a message.
At one time PVField extended Requester but it no longer does.
Requester is, however, used by pvAccess.
</p>
<pre>
class Requester;
typedef std::tr1::shared_ptr&lt;Requester&gt; RequesterPtr;
enum MessageType {
infoMessage,warningMessage,errorMessage,fatalErrorMessage
};
extern String getMessageTypeName(MessageType messageType);
extern const size_t messageTypeCount;
class Requester {
public:
POINTER_DEFINITIONS(Requester);
virtual ~Requester(){}
virtual String getRequesterName() = 0;
virtual void message(String const &amp; message,MessageType messageType) = 0;
};</pre>
<p>where</p>
<dl>
<dt></dt>
<dt>MessageType</dt>
<dd>Type of message.</dd>
<dt>messageTypeName</dt>
<dd>An array of strings of the message type names, i.e.
String("info"),String("warning"),String("error"),String("fatalError").</dd>
<dt>getRequesterName</dt>
<dd>Returns the requester name.</dd>
<dt>message</dt>
<dd>Gives a message to the requester.</dd>
</dl>
<h3>serialize.h</h3>
<pre>
class SerializableControl;
class DeserializableControl;
class Serializable;
class BitSetSerializable;
class SerializableArray;
class BitSet;
class Field;
class SerializableControl {
public:
virtual ~SerializableControl(){}
virtual void flushSerializeBuffer() =0;
virtual void ensureBuffer(std::size_t size) =0;
virtual void alignBuffer(std::size_t alignment) =0;
virtual void cachedSerialize(
std::tr1::shared_ptr&lt;const Field&gt; const &amp; field,
ByteBuffer* buffer) = 0;
};
class DeserializableControl {
public:
virtual ~DeserializableControl(){}
virtual void ensureData(std::size_t size) =0;
virtual void alignData(std::size_t alignment) =0;
virtual std::tr1::shared_ptr&lt;const Field&gt; cachedDeserialize(
ByteBuffer* buffer) = 0;
};
class Serializable {
public:
virtual ~Serializable(){}
virtual void serialize(ByteBuffer *buffer,
SerializableControl *flusher) const = 0;
virtual void deserialize(ByteBuffer *buffer,
DeserializableControl *flusher) = 0;
};
class BitSetSerializable {
public:
virtual ~BitSetSerializable(){}
virtual void serialize(ByteBuffer *buffer,
SerializableControl *flusher,BitSet *bitSet) const = 0;
virtual void deserialize(ByteBuffer *buffer,
DeserializableControl *flusher,BitSet *bitSet) = 0;
};
class SerializableArray : virtual public Serializable {
public:
virtual ~SerializableArray(){}
virtual void serialize(ByteBuffer *buffer,
SerializableControl *flusher, std::size_t offset,
std::size_t count) const = 0;
};</pre>
<h3>serializeHelper.h</h3>
<p>This is a helper class for serialization, which is required for sending and
receiving pvData over the nerwork.</p>
<pre>class SerializeHelper : public NoDefaultMethods {
public:
static void writeSize(int s, ByteBuffer* buffer,
SerializableControl* flusher);
static int readSize(ByteBuffer* buffer,
DeserializableControl* control);
static void serializeString(const String&amp; value,
ByteBuffer* buffer,SerializableControl* flusher);
static void serializeSubstring(const String&amp; value, int offset,
int count, ByteBuffer* buffer,
SerializableControl* flusher);
static String deserializeString(ByteBuffer* buffer,
DeserializableControl* control);
...
};</pre>
<p>where</p>
<dl>
<dt>writeSize</dt>
<dd>Serialize the size.</dd>
<dt>readSize</dt>
<dd>Deserialize the size.</dd>
<dt>serializeString</dt>
<dd>Serialize a String.</dd>
<dt>serializeSubstring</dt>
<dd>Serialize a substring.</dd>
<dt>deserializeString</dt>
<dd>Deserialize a string.</dd>
</dl>
<h3>sharedPtr.h</h3>
<pre>
#define POINTER_DEFINITIONS(clazz) \
typedef std::tr1::shared_ptr&lt;clazz&gt; shared_pointer; \
typedef std::tr1::shared_ptr&lt;const clazz&gt; const_shared_pointer; \
typedef std::tr1::weak_ptr&lt;clazz&gt; weak_pointer; \
typedef std::tr1::weak_ptr&lt;const clazz&gt; const_weak_pointer;</pre>
<h3>sharedVector.h</h3>
<p>
shared_vector is a holder for a contigious piece of memory.
Data is shared, but offset and length are not.
This allows one vector to have access to only a subset of a piece of memory.
</p>
<p>
shared_vector differs from std::vector as follows:</p>
<dl>
<dt>Differences in behavior</dt>
<dd>
shared_vector models const-ness like shared_ptr.
An equivalent of 'const std::vector&lt;E&gt;' is
'const shared_vector&lt;const E&gt;'.
However, it is also possible to have 'const shared_vector&lt;E&gt;'
analogous to 'E* const' and 'shared_vector&lt;const E&gt;&gt;'
which is analogous to 'const E*'.i
<br />
Copying a shared_vector, by construction or assignment, does not copy
its contents.
Modifications to one such "copy" effect all
associated shared_vector instances.
<br />
std::vector::reserve(N) has no effect if N&lt;=std::vector::capacity().
However, like resize(), shared_vector&lt;E&gt;::reserve() has the side effect
of always calling make_unique().
</dd>
<dt>Parts of std::vector interface not implemented</dt>
<dd>
Mutating methods insert(), erase(), shrink_to_fit(), emplace(), and emplace_back() are not implemented.
<br />
shared_vector does not model an allocator which is bound to the object. Therefore the get_allocator() method and the allocator_type typedef are not provided.
<br />
The assign() method and the related constructor are not implemented at this time.
<br />
The comparison operators are not implemented at this time.
</dd>
<dt>Parts not found in std::vector</dt>
<dd>
shared_vector has additional constructors from raw pointers and shared_ptr s.
The copy constructor and assignment operator allow implicit castings
from type 'shared_vector&lt;T&gt;' to 'shared_vector&lt;const T>&gt;'.
To faciliate safe modification the methods unique() and make_unique() are provided
The slice() method selects a sub-set of the shared_vector.
The low level accessors dataPtr(), dataOffset(), dataCount(), and dataTotal().
</dd>
</dl>
<pre>
template&lt;typename E, class Enable = void&amp; class shared_vector;
template&lt;typename E, class Enable&amp;
class shared_vector : public detail::shared_vector_base&lt;E&amp;
{
typedef detail::shared_vector_base&lt;E&amp; base_t;
typedef typename detail::call_with&lt;E&amp;::type param_type;
typedef typename meta::strip_const&lt;E&amp;::type _E_non_const;
public:
typedef E value_type;
typedef E&amp; reference;
typedef typename meta::decorate_const&lt;E&amp;::type&amp; const_reference;
typedef E* pointer;
typedef typename meta::decorate_const&lt;E&amp;::type* const_pointer;
typedef E* iterator;
typedef std::reverse_iterator&lt;iterator&amp; reverse_iterator;
typedef typename meta::decorate_const&lt;E&amp;::type* const_iterator;
typedef std::reverse_iterator&lt;const_iterator&amp; const_reverse_iterator;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
typedef E element_type;
typedef std::tr1::shared_ptr&lt;E&amp; shared_pointer_type;
// allow specialization for all E to be friends
template&lt;typename E1, class Enable1&amp; friend class shared_vector;
shared_vector() :base_t();
explicit shared_vector(size_t c)
:base_t(new _E_non_const[c], 0, c);
shared_vector(size_t c, param_type e);
template&lt;typename A&amp;
shared_vector(A v, size_t o, size_t c) :base_t(v,o,c);
template&lt;typename E1&amp;
shared_vector(const std::tr1::shared_ptr&lt;E1&amp;&amp; d, size_t o, size_t c);
template&lt;typename A, typename B&amp;
shared_vector(A d, B b, size_t o, size_t c);
shared_vector(const shared_vector&amp; o) :base_t(o);
size_t max_size() const;
size_t capacity() const;
void reserve(size_t i);
void resize(size_t i);
void resize(size_t i, param_type v);
void make_unique();
iterator begin() const;
iterator end() const;
reverse_iterator rbegin() const;
reverse_iterator rend() const;
reference front() const;
reference back() const;
void push_back(param_type v);
void pop_back();
pointer data() const;
reference operator[](size_t i) const;
reference at(size_t i) const;
// inherited from detail
shared_vector_base&amp; operator=(const shared_vector_base&amp; o);
void swap(shared_vector_base&amp; o);
void clear();
bool unique() const;
size_t size() const;
bool empty() const;
void slice(size_t offset, size_t length=(size_t)-1);
const std::tr1::shared_ptr&lt;E&amp;&amp; dataPtr();
size_t dataOffset() const;
size_t dataCount() const;
size_t dataTotal() const;
</pre>
where
<dl>
<dt>shared_vector</dt>
<dd>Several flavors of constructor are provided. The most commingly used is:
<pre>
shared_vector(size_t c);
</pre>
This creates a shared_vector of the specified size/
</dd>
<dt>max_size</dt>
<dd>The maximum size the C++ implementation allows, i.e.,
the maximum possible capacity.
Note that units are number of elements not number of bytes.
</dd>
<dt>capacity</dt>
<dd>The current capacity.</dd>
<dt>reserve</dt>
<dd>Set array capacity.</dd>
<dt>resize</dt>
<dd>Grow or shrink array.
It the second argument is given it is the value to assign to
and new elements.
</dd>
<dt>make_unique</dt>
<dd>Ensure (by copying) that this shared_vector
is the sole owner of the data array.
</dd>
<dt>begin,...,rend</dt>
<dd>Standard interators.</dd>
<dt>front</dt>
<dd>Return a reference to the first element.</dd>
<dt>back</dt>
<dd>Return a reference to the last element.</dd>
<dt>push_back</dt>
<dd>Add an element to the end of the array.</dd>
<dt>pop_back</dt>
<dd>Remove an element from the end of the array.</dd>
<dt>data</dt>
<dd>Return a pointer to the raw array.</dd>
<dt>operator[](size_t i)</dt>
<dd>Return a reference to the specified element.</dd>
<dt>at</dt>
<dd>Like the previous except that it throws a range-error if
the specified element is out of range.</dd>
<dt>operator=</dt>
<dd>Copy an existing shared_vector.</dd>
<dt>swap</dt>
<dd>Swap the contents of this vector with another.</dd>
<dt>clear</dt>
<dd>Clear contents.</dd>
<dt>unique</dt>
<dd>returns (true,false) if data (is not, is) shared.</dd>
<dt>size</dt>
<dd>Number of elements visible through this vector.</dd>
<dt>empty</dt>
<dd>Is the number of elements zero?</dd>
<dt>slice</dt>
<dd>Reduce the view of this shared_vector.</dd>
<dt>dataPtr</dt>
<dd>A readonly shared_ptr to the array.</dd>
<dt>dataOffset</dt>
<dd>Offset in the data array of first visible element.</dd>
<dt>dataCount</dt>
<dd>Number of visible elements between dataOffset and end of data.</dd>
<dt>dataTotal</dt>
<dd>The total number of elements between dataOffset and the end of data</dd>
</dl>
<p><b>TBD</b>
Michael should decide if this is the correct set of methods to describe.
Also he should check for correct descriptions.
</p>
<h3>status.h</h3>
<p>Status provides a way to pass status back to client code:</p>
<pre>class Status : public epics::pvData::Serializable {
public:
enum StatusType {
/** Operation completed successfully. */
STATUSTYPE_OK,
/** Operation completed successfully, but there is a warning message. */
STATUSTYPE_WARNING,
/** Operation failed due to an error. */
STATUSTYPE_ERROR,
/** Operation failed due to an unexpected error. */
STATUSTYPE_FATAL
};
static const char* StatusTypeName[];
static Status OK;
Status();
Status(StatusType type, epics::pvData::String const &amp; message);
Status(StatusType type, epics::pvData::String const &amp; message, epics::pvData::String stackDump);
~Status()
StatusType getType() const;
String getMessage() const;
String getStackDump() const;
bool isOK() const;
bool isSuccess() const;
String toString() const;
void toString(StringBuilder buffer, int indentLevel = 0) const;
void serialize(ByteBuffer *buffer, SerializableControl *flusher) const;
void serialize(ByteBuffer *buffer, SerializableControl *flusher) const;
};</pre>
<p>The Status methods are:</p>
<dl>
<dt>StatusType</dt>
<dd>An enum for the status type.</dd>
<dt>getType</dt>
<dd>Get the statusType.</dd>
<dt>getMessage</dt>
<dd>Get a message explaining the error.</dd>
<dt>getStackDump</dt>
<dd>Get a stack dump.</dd>
</dl>
<p>The StatusCreate methods are:</p>
<dl>
<dt>getStatusOK</dt>
<dd>Get a singleton that returns StatusType.OK and a null message and
stackDump.</dd>
<dt>createStatus</dt>
<dd>Create a new Status.</dd>
<dt>deserializeStatus</dt>
<dd>Use this method instead of Status.deserialize(), since this allows OK
status optimization.</dd>
</dl>
<h3>templateMeta.h</h3>
<p><b>TBD</b> Michael will explain.</p>
<h3>thread.h</h3>
<h4>ThreadPriority</h4>
<pre>enum ThreadPriority {
lowestPriority,
lowerPriority,
lowPriority,
middlePriority,
highPriority,
higherPriority,
highestPriority
};</pre>
<h4>Thread</h4>
<pre>
class Thread;
typedef std::tr1::shared_ptr&lt;Thread&gt; ThreadPtr;
typedef std::tr1::shared_ptr&lt;epicsThread&gt; EpicsThreadPtr;
class Runnable {
public:
virtual void run() = 0;
};
class Thread;
class Thread : public epicsThread, private NoDefaultMethods {
public:
Thread(
String name,
ThreadPriority priority,
Runnable *runnableReady,
epicsThreadStackSizeClass stkcls=epicsThreadStackSmall);
~Thread();
...
};</pre>
<p>Runnable must be implement by code that wants to be run via a thread. It has
one virtual method: run. Run is the code that is run as a thread. When run
compeletes it can not be restarted. If code wants to delete a thread then it
MUST arrange that the run returns before the thread can be deleted. An
exception is thrown if run remains active when delete is called. </p>
<p>Thread has the methods:</p>
<dl>
<dt>Thread</dt>
<dd>The constructor. A thread name and priority must be specified. The run
methods of runnable is executed. When the run methods returns the thread
will no longer be active but the client code must still delete the
thread.</dd>
<dt>~Thread</dt>
<dd>The destructor. This is called as the result of:
<pre> delete pthread;</pre>
</dd>
</dl>
<h3>timeFunction.h</h3>
<p>TimeFunction is a facility that measures the average number of seconds a
function call requires. When timeCall is called, it calls function in a loop.
It starts with a loop of one iteration. If the total elapsed time is less then
.1 seconds it increases the number of iterrations by a factor of 10. It keeps
repeating until the elapsed time is greater than .1 seconds. It returns the
average number of seconds per call.</p>
<pre>class TimeFunctionRequester;
class TimeFunction;
typedef std::tr1::shared_ptr&lt;TimeFunctionRequester&gt; TimeFunctionRequesterPtr;
typedef std::tr1::shared_ptr&lt;TimeFunction&gt; TimeFunctionPtr;
class TimeFunctionRequester {
public:
POINTER_DEFINITIONS(TimeFunctionRequester);
virtual ~TimeFunctionRequester(){}
virtual void function() = 0;
};
class TimeFunction {
public:
POINTER_DEFINITIONS(TimeFunction);
TimeFunction(TimeFunctionRequesterPtr const &amp; requester);
~TimeFunction();
double timeCall();
...
}; </pre>
<p>TimeFunctionRequester must be implemented by code that wants to time how
long a function takes. It has the single method:</p>
<dl>
<dt>function</dt>
<dd>This is the function.</dd>
</dl>
<p>TimeFunction has the methods:</p>
<dl>
<dt>TimeFunction</dt>
<dd>Constructor.</dd>
<dt>~TimeFunction</dt>
<dd>Destructor.</dd>
<dt>timeCall</dt>
<dd>Time how long it takes to execute the function. It starts by calling
the function one time. If it takes &lt; 1 seconds to doubles the number
of times to call the function. It repeats this until it takes at least
one second to call it ntimes.</dd>
</dl>
<h3>timer.h</h3>
<p>This provides a general purpose timer. It allows a user callback to be
called after a delay or periodically. </p>
<pre>class TimerCallback;
class Timer;
typedef std::tr1::shared_ptr&lt;TimerCallback&gt; TimerCallbackPtr;
typedef std::tr1::shared_ptr&lt;Timer&gt; TimerPtr;
class TimerCallback {
public:
POINTER_DEFINITIONS(TimerCallback);
TimerCallback();
virtual ~TimerCallback(){}
virtual void callback() = 0;
virtual void timerStopped() = 0;
};
class Timer : private Runnable {
public:
POINTER_DEFINITIONS(Timer);
Timer(String threadName, ThreadPriority priority);
virtual ~Timer();
virtual void run();
void scheduleAfterDelay(
TimerCallbackPtr const &amp;timerCallback,
double delay);
void schedulePeriodic(
TimerCallbackPtr const &amp;timerCallback,
double delay,
double period));
void cancel(TimerCallbackPtr const &amp;timerCallback);
bool isScheduled(TimerCallbackPtr const &amp;timerCallback);
void toString(StringBuilder builder);
...
};</pre>
<p>TimerCallback must be implemented by the user. It has the following methods:
</p>
<dl>
<dt>callback</dt>
<dd>This is called when a timer expires. This is called with no locks held.
When called a delay timer is no longer on the queue but a periodioc timer
is on a queue. Thus the callback for a delay timer can issue a new
schedule request but a periodic timer must not. Note the explaination of
TimerNode.cancel below.</dd>
<dt>timerStopped</dt>
<dd>Timer.stop was called when a timer request was queued. or if the timer
is stopped and a schedule request is made.</dd>
</dl>
<p>In order to schedule a callback client code must allocate a TimerNode It can
be used to schedule multiple callbacks. It has the methods:</p>
<dl>
<dt>TimerNode</dt>
<dd>The constructor. User code must create a TimeNode in order to call a
schedule method.</dd>
<dt>~TimerNode</dt>
<dd>The destructor. This is called as a result of the client calling:
<pre> delete timerNode;</pre>
</dd>
<dt>cancel</dt>
<dd>This is called to cancel a timer request. If a callback has been
dequeued but the callback not called when cancel is called then a
callback may still happen. New schedule requests can be made after a
cancel request has been made.</dd>
<dt>isScheduled</dt>
<dd>Is the timerNode scheduled to be called.</dd>
</dl>
<p>Timer has the methods:</p>
<dl>
<dt>Timer</dt>
<dd>The consttructor.</dd>
<dt>~Timer</dt>
<dd>The destructor. The queue is emptied and TimerCallback.timerStopped is
called for each element of the queue.</dd>
<dt>scheduleAfterDelay</dt>
<dd>A request to schedule a callback after a delay specified in
seconds.</dd>
<dt>schedulePeriodic</dt>
<dd>Schedule a periodic callback.</dd>
</dl>
<h3>typeCast.h</h3>
<p><b>TBD</b> Michael will explain.</p>
<h2>pvDataApp/pvMisc</h2>
<h3>bitSetUtil.h</h3>
<p>The following is also provided:</p>
<pre>class BitSetUtil : private NoDefaultMethods {
public:
static bool compress(BitSet const &amp;bitSet,PVStructure const &amp;pvStructure);
};</pre>
<p>This provides functions that operate on a BitSet for a PVStructure. It
currently has only one method:</p>
<dl>
<dt>compress</dt>
<dd>Compress the bits in a BitSet related to a structure.<br />
For each structure:
<ol>
<li>If the bit for the structure is set then the bit for all subfields
of the structure are cleared. </li>
<li>If the bit for the structure is not set but all immediate subfields
have their bit set then the bit for the structure is set and the bits
for all subfields are cleared. </li>
</ol>
Note that this is a recursive algorithm. That is if every immediate
subfield has it's offset bit set then the bits for ALL fields that reside
in the structure will be cleared.</dd>
<dd>Channel Access can call this before sending data. It can then pass
entire structures if the structure offset bit is set. </dd>
</dl>
</div>
</body>
</html>