Files
pvData/documentation/pvDataCPP.html
Marty Kraimer 04dc3a18ba change abstract
2011-12-20 08:22:28 -05:00

4027 lines
160 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 }
body { margin-right: 10% }
/*]]>*/</style>
</head>
<body>
<div class="head">
<h1>EPICS pvDataCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount" id="L50">EPICS v4 Working Group, Working Draft,
20-Dec-2011</h2>
<dl>
<dt>This version:</dt>
<dd><a
href="http://epics-pvdata.sourceforge.net/pvDataCPP_20111220.html">pvDataCPP_20111220.html</a></dd>
<dt>Latest version:</dt>
<dd><a
href="http://epics-pvdata.sourceforge.net/pvDataCPP_20111220.html">pvDataCPP_20111220.html</a></dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
</dl>
<hr />
</div>
<h2 class="nocount" id="L72">Abstract</h2>
<p>pvDataCPP is the Java implementation of pvData, which is one of a related
set of products:</p>
<dl>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvDataCPP.html">pvData</a></dt>
<dd>pvData (Process Variable Daata) defines and implements an efficent way
to store, access, and transmit memory resident structured data</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvAccessCPP/raw-file/tip/documentation/pvAccessCPP.html">pvAccess</a></dt>
<dd>pvAccess is network support for transmitting pvData.</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvIOCCPP/raw-file/tip/documentation/pvIOCCPP.html">pvIOC</a></dt>
<dd>A pvIOC is a network accessable smart real time database. The database
consists of memory resident records. Each record has a name that is
uniquie within the local area network and contains a top level pvData
structure. Each field of a record can optionally have support code
attached to it. The support is called when a request is made to process
the record. The support code is what makes the record "smart". A pvAccess
server is provided so that the records can be accesed via the network.
</dd>
</dl>
<p>Each of the products has a Java and a C++ implementation.</p>
<p>The products are all part of the <a
href="http://epics-pvdata.sourceforge.net/">V4</a> implementation of <a
href="http://www.aps.anl.gov/epics/">Experimental Physics and Industrial
Control System.</a></p>
<h2 class="nocount" id="L80">Status of this Document</h2>
<p>This is the 20-Dec-2011 version of the C++ implementation of pvData. It is a
complete implementation of pvData as currently defined. </p>
<p>TODO</p>
<ul>
<li>rename epicsException to Exception. Do we want assert under pvData? I
think yes. Can it generate stack trace?</li>
<li>pvMiscBitSetUtil has not been tested.</li>
<li>Change all throw statements so that they generated stack trace.</li>
</ul>
<p>CONTENTS</p>
<div class="toc">
<ul>
<li><a href="#L50">EPICS v4 Working Group, Working Draft, 20-Dec-2011</a></li>
<li><a href="#L72">Abstract</a></li>
<li><a href="#L80">Status of this Document</a></li>
<li><a href="#L100">Preface</a>
<ul>
<li><a href="#L130">pvData</a>
<ul>
<li><a href="#L134">Introspection</a></li>
<li><a href="#L202">Data</a></li>
<li><a href="#L227">Property Structures</a></li>
</ul>
</li>
<li><a href="#L257">pvAccess</a></li>
<li><a href="#L318">pvIOC</a></li>
</ul>
</li>
<li><a href="#L365">Introduction</a></li>
<li><a href="#L457">PVData Meta Language</a>
<ul>
<li><a href="#L463">Definition</a></li>
<li><a href="#L657">Examples</a></li>
</ul>
</li>
<li><a href="#L701">PV - User Description</a>
<ul>
<li><a href="#L705">Overview</a></li>
<li><a href="#L746">pvType</a></li>
<li><a href="#L782">Process Variable Reflection</a>
<ul>
<li><a href="#L790">Type Description</a></li>
<li><a href="#L920">Reflection Description</a></li>
</ul>
</li>
<li><a href="#L1135">Standard Fields</a></li>
<li><a href="#L1219">PVField - Data Interfaces</a>
<ul>
<li><a href="#L1223">PVField</a></li>
<li><a href="#L1333">PVAuxInfo</a></li>
<li><a href="#L1367">PVScalar and extensions</a>
<ul>
<li><a href="#L1371">Primitive PVField types</a></li>
</ul>
</li>
<li><a href="#L1377">PVArray and Extensions</a>
<ul>
<li><a href="#L1416">PVArray Extensions</a></li>
</ul>
</li>
<li><a href="#L1460">PVStructure</a></li>
<li><a href="#L1564">PVStructureArray</a></li>
<li><a href="#L1595">PVDataCreate</a></li>
</ul>
</li>
<li><a href="#L1629">Standard Data Fields</a></li>
<li><a href="#L1635">Convert</a></li>
</ul>
</li>
<li><a href="#L1705">Namespace and Memory Management</a>
<ul>
<li><a href="#L1709">Namespace</a></li>
<li><a href="#L1715">Memory Managemment</a>
<ul>
<li><a href="#L1717">NoDefaultMethods</a></li>
</ul>
</li>
<li><a href="#L1723">PVData introspection objects</a></li>
<li><a href="#L1727">PVData data objects</a></li>
<li><a href="#L1731">Other code in this project</a></li>
</ul>
</li>
<li><a href="#L1739">Examples</a>
<ul>
<li><a href="#L1743">Accessing PVData</a></li>
<li><a href="#L1762">Creating PVData</a></li>
</ul>
</li>
<li><a href="#L1782">Property</a>
<ul>
<li><a href="#L1786">Definition of Property</a></li>
<li><a href="#L1798">Standard Properties</a></li>
<li><a href="#L1879">Overview of Property Support</a></li>
<li><a href="#L1899">timeStamp</a>
<ul>
<li><a href="#L1923">timeStamp.h</a></li>
<li><a href="#L2039">pvTimeStamp.h</a></li>
</ul>
</li>
<li><a href="#L2079">alarm</a>
<ul>
<li><a href="#L2106">alarm.h</a></li>
<li><a href="#L2178">pvAlarm.h</a></li>
</ul>
</li>
<li><a href="#L2218">control</a>
<ul>
<li><a href="#L2240">control.h</a></li>
<li><a href="#L2272">pvControl.h</a></li>
</ul>
</li>
<li><a href="#L2312">display</a>
<ul>
<li><a href="#L2334">display.h</a></li>
<li><a href="#L2396">pvDisplay.h</a></li>
</ul>
</li>
<li><a href="#L2436">pvEnumerated</a></li>
</ul>
</li>
<li><a href="#L2512">PVData Factories</a></li>
<li><a href="#L2532">Miscellanous Classes</a>
<ul>
<li><a href="#L2536">Overview</a></li>
<li><a href="#L2628">BitSet</a></li>
<li><a href="#L2752">ByteBuffer</a></li>
<li><a href="#L2760">Event</a></li>
<li><a href="#L2789">Exception</a></li>
<li><a href="#L2797">Executor</a></li>
<li><a href="#L2828">Linked List</a></li>
<li><a href="#L2942">Lock and Mutex</a></li>
<li><a href="#L2958">Message Queue</a>
<ul>
<li><a href="#L2960">Definitions</a></li>
<li><a href="#L2964">MessageQueue</a></li>
</ul>
</li>
<li><a href="#L3037">NoDefaultMethods</a></li>
<li><a href="#L3043">Requester</a></li>
<li><a href="#L3074">Serialize</a></li>
<li><a href="#L3114">CDRMonitor - Monitor and Report Construction and
Destruction</a></li>
<li><a href="#L3120">Status</a></li>
<li><a href="#L3167">Thread</a>
<ul>
<li><a href="#L3169">ThreadPriority</a></li>
<li><a href="#L3173">Thread</a></li>
</ul>
</li>
<li><a href="#L3214">Time Function Call</a></li>
<li><a href="#L3246">Timer</a></li>
<li><a href="#L3313">Queue</a></li>
</ul>
</li>
<li><a href="#L3376">pvMisc</a>
<ul>
<li><a href="#L3380">BitSetUtil</a></li>
<li><a href="#L3410">MultiChoice</a></li>
</ul>
</li>
</ul>
</div>
<hr />
<h2 style="text-align: center" id="L100">Preface</h2>
<hr />
<p>This product is available via an <a
href="http://epics-pvdata.sourceforge.net/LICENSE.html">open source
license</a></p>
<p>This is the overview for pvDataCPP. Doxygen documentation is available at <a
href="./html/index.html">doxygenDoc</a></p>
<p>pvData is one of a set of related projects:</p>
<dl>
<dt>pvData</dt>
<dd>Describes and implements structured data.</dd>
<dt>pvAccess</dt>
<dd>Provides networking for pvData.</dd>
<dt>pvIOC</dt>
<dd>Provides a database based on pvData together with record processing,
record scanning, and extensible support.</dd>
</dl>
<h3 id="L130">pvData</h3>
<p>pvData describes and implements structured data. Interspection interfaces
are used to describe the data and for each type of data a data interface
provides a container to hold the data.</p>
<h4 id="L134">Introspection</h4>
<p>pvData is modeled as a structured set of fields. A field has a name are a
type. The type must be one of:</p>
<dl>
<dt>scalar</dt>
<dd>A scalar has a scalar type which must be one of the following:
<dl>
<dt>boolean</dt>
<dd>Is always either true or false.</dd>
<dt>byte</dt>
<dd>An 8 bit signed integer.</dd>
<dt>short</dt>
<dd>A 16 bit signed integer.</dd>
<dt>int</dt>
<dd>A 32 bit signed integer.</dd>
<dt>long</dt>
<dd>A 64 bit signed integer.</dd>
<dt>float</dt>
<dd>A IEEE 32 bit float.</dd>
<dt>double</dt>
<dd>A IEEE 64 bit float.</dd>
<dt>string</dt>
<dd>A UTF8 string.</dd>
</dl>
</dd>
<dt>scalarArray</dt>
<dd>An array where all elements have the same scalar type.</dd>
<dt>structure</dt>
<dd>An array of fields. Each field can have a different type including
structure. Thus complex structured data is supported.</dd>
<dt>structureArray</dt>
<dd>An array of structure fields where each element has the exact same
introspection interface.</dd>
</dl>
<p>Introspection interface Field provides the name and type for the field. In
addition each type has an introspection interface: Scalar, ScalarArray,
Structure, and StructureArray.</p>
<h4 id="L202">Data</h4>
<p>Interface PVField provides access to the common information of every data
container. In addition every possible type has an interface for accessing the
data:</p>
<dl>
<dt>scalar</dt>
<dd>The interfaces are PVBoolean, PVByte, PVShort, PVInt, PVLong, PVFloat,
PVDouble, and PVString.</dd>
<dt>scalarArray</dt>
<dd>The interfaces are PVBooleanArray, PVByteArray, PVShortArray,
PVIntArray, PVLongArray, PVFloatArray, PVDoubleArray, and
PVStringArray.</dd>
<dt>structure</dt>
<dd>The interface is PVStructure.</dd>
<dt>structureArray</dt>
<dd>The interface is PVStructureArray.</dd>
</dl>
<h4 id="L227">Property Structures</h4>
<p>pvData provides support, via pvData structures and associated support, for
the following:</p>
<dl>
<dt>timeStamp</dt>
<dd>Time since the POSIX Epoch.</dd>
<dt>alarm</dt>
<dd>Alarm information.</dd>
<dt>display</dt>
<dd>Display Info</dd>
<dt>control</dt>
<dd>Control Info.</dd>
<dt>enumerated structrure</dt>
<dd>This is a pvData structure with two field: index and choices.</dd>
</dl>
<h3 id="L257">pvAccess</h3>
<p>pvAccess provides client/server support for transmitting pvData objects. The
server must provide access to objects identified by name. Each object must have
a network wide unique name. A client issues a create channel request,
specifying the channel name in order to connect to the object on the server.
After the client has connected, it can issue the following types of request.</p>
<dl>
<dt>process</dt>
<dd>Asks that the channel process. The process semantics are determined by
the server.</dd>
<dt>get</dt>
<dd>Ask the get data from the server. The client can optionally ask the
server to process before returning data.</dd>
<dt>put</dt>
<dd>Puts data to the server. The server can optionally be asked to process
after receiving the data.</dd>
<dt>putGet</dt>
<dd>Puts data to the server, optionally ask the server to process, and then
get data from the server.</dd>
<dt>monitor</dt>
<dd>Request that the server send data to the client when new data is
available.</dd>
<dt>channelArray</dt>
<dd>This can get and put a sub- array.</dd>
<dt>channelRPC</dt>
<dd>This is similar to a putGet except that the server will create a new
PVStructure and send it to the client.</dd>
</dl>
<p>Associated with each type of request is a create method. The method has an
argument that allows the client to specify options. This argument is a top
level PVStructure called a pvRequest. The pvRequest is sent to the server. The
server side looks at what is requested and creates a top level PVStructrure
that will hold the data that is transfered between client and server. It then
sends the introspection info to the client side of pvAccess, which also creates
a top level PVStructure for holding data. At this time the client is notified
that it can start making requests. Thus when data is passed between client and
server it flows between the two top level PVStructures without requiring the
creation on new objects.</p>
<p>pvAccess provides many of the features of systems like CORBA and ICE
(Internet Communication Engine) but is designed to provide the following
features:</p>
<dl>
<dt>No IDL (Interface Definition Language) or associated compiler</dt>
<dd>The introspection interfaces replace the IDL.</dd>
<dt>Efficent use of network</dt>
<dd>Introspection info is only passed at creation time. For data requests
data is passed without any interspection information.<br />
Multiple small objects are automatically combined into a single network
packet.<br />
Large objects automatically span network packets.</dd>
</dl>
<h3 id="L318">pvIOC</h3>
<p>IOC means Input/Output Controller, which is an EPICS term. A pvIOC is
modeled after an EPICS IOC but supports pvData instead of flat record
structures. At the present time the only implementation is in Java and called
javaIOC. The c++ implementaion will be called pvIOC and will be able to run in
an existing EPICS IOC.</p>
<p>Like an EPICS IOC a pvIOC provides the followig features:</p>
<dl>
<dt>Record Processing</dt>
<dd>A record can be processed, i.e. records are "smart". Each field can
optionally have attached support. When a record is asked to process the
support attacked to the top level PVStructure is called.</dd>
<dt>Record Scanning</dt>
<dd>A record can be scanned. Two types are supported: periodic and event.
The way event scanning is implemented provides both the I/O Intr scanning
and event scanning implemented by a EPICS IOC.</dd>
<dt>Extensible Support</dt>
<dd>Each field can optionally have support attached. Support is written to
process particular types of fields. At initilization support uses
interspection to look at the fields to which it is attached. If the
fields are not what it expects it reports a problem and terminates.</dd>
</dl>
<p>For pvAccess, the pvIOC provides the following:</p>
<dl>
<dt>Local channel implementation</dt>
<dd>The way the remote pvAccess server code works is to find one or more
local implementations of the Channel interface. It calls this to
implement the various operations it supports.</dd>
<dt>Access to data</dt>
<dd>Support is a available that allows a client to access an arbitrary set
of fields in a record. From this it creates a top level structure that
holds the copy of the fields. It also provides the support to copy date
between the copy and the record. It also provides support for monitor
queues and algortihms.</dd>
<dt>Access to EPICS V3 records</dt>
<dd>This is a local Channel implementation that privides support for
attaching to V3 records. It makes the V3 fields look like a pvData
structure.</dd>
<dt>Access to pvIOC records</dt>
<dd>This is a local Channel implementation that privides support for
attaching to pvIOC records.</dd>
</dl>
<hr />
<h2 style="text-align: center" id="L365">Introduction</h2>
<hr />
<p>PVData is one of a set of related projects: pvData, pvAccess, and javaIOC.
It describes and implements the data that the other projects use. 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
pvAccess and javaIOC, which are located via the same sourceforge site as this
project. Project PVAccess provides network support for transporting pvData.
Project javaIOC provides a memory resident "smart" database of pvData data.</p>
<p>This document describes the C++ implementation of pvData, which was first
implemented in Java. A C++ implementation of pvAccess is being developed in
parallel with pvDataCPP. In the future a C++ implementation of javaIOC will be
developed and the name javaIOC will become pvIOC.</p>
<p>pvData (Process Variable Data) defines and implements an efficent way to
store, access, and transmit memory resident structured data.</p>
<dl>
<dt>description</dt>
<dd>The header files pvIntrospect.h and pvData.h provide the C++
description of pvData.</dd>
<dt>implementation</dt>
<dd>Directory factory provides a complete C++ definition for pvData. It
also provides abstract and base classes that support specialized
implementations of the data classes.</dd>
<dt>efficient</dt>
<dd>Small memory footprint, low cpu overhead, and concise code base.</dd>
<dt>data storage</dt>
<dd>pvData provides introspection and data interfaces. The introspection
interfaces provide access to immutable objects, which allows
introspection instances to be freely shared. The introspection interface
for a process variable can be accessed without requiring access to the
data.</dd>
<dt>data access</dt>
<dd>Client code can access pvData via the introspection and data
interfaces. For "well known" data, e.g. timeStamp, specialized interfaces
can be implemented without requiring any changes to the core
software.</dd>
<dt>data transfer</dt>
<dd>The separation of introspection and data interfaces allows for
efficient network data transfer. At connection time introspection
information is passed from server to client. Each side creates a data
instance. The data is transferred between these instances. The data in
the network packets does not have to be self describing since each side
has the introspection information.</dd>
<dt>memory resident</dt>
<dd>pvData only defines memory resident data.</dd>
<dt>structured data</dt>
<dd>pvData has four types: scalar, scalar array, structure, and structure
array. A scalar can be one of the following: boolean, byte, short, int,
long, float, double, string. A scalar array is a one dimensional array
with the element type being one of the scalar types. A structure is an
ordered set of fields where each field has a name and type. A structure
array is a one dimensional array of structures where each element has the
same introspection interface. Since a field can have type structure
complex structures are supported. No other types are needed since
structures can be defined that simulate types.</dd>
</dl>
<p>The javaIOC implements a Process Variable (PV) Database, which is a memory
resident database holding pvData with the following features:</p>
<ul>
<li>A database has records.</li>
<li>Each record has a unique record name.</li>
<li>A record has a top level pvData structure.</li>
</ul>
<p>pvData was initially created to support the javaIOC and was part of the
javaIOC project. It is now a separate project that is used by the javaIOC. In
addition to the javaIOC, pvData is intended for use by 1) channel access
clients, 2) Interface between client and network, 3) Interface between network
and channel access server, 4) Interface between server and IOC database. Since
it is an interface to data, it could also be used by other systems, e.g. TANGO,
TINE, etc. A high level Physics application can hold data as pvData. By
starting a channel access server, the data can made available to network
clients.</p>
<p>pvData contains everything required to support Channel Access and Channel
Access clients and servers. </p>
<p>This project has many concepts that are similar to EPICS (Experimental
Physics and Industrial Control System). This C++ implementation uses the EPICS
build system and also EPICS libCom. The directory structure for this project is
a standard EPICS application. The following source directories appear under
pvDataApp:</p>
<dl>
<dt>misc</dt>
<dd>Support for pvData. This support is described in a major section
below.</dd>
<dt>pv</dt>
<dd>The C++ introspection and data descriptions for pvData.</dd>
<dt>factory</dt>
<dd>The C++ definitions for pvData.</dd>
<dt>property</dt>
<dd>Support code for "standard" pvData structures, e.g. timeStamp and
alarm.</dd>
</dl>
<hr />
<h2 style="text-align: center" id="L457">PVData Meta Language</h2>
<hr />
<p>This section describes a meta language for describing pvData. Currently
there are no plans for a parser for the meta language. It is used for
documentation. The toString introspection and data methods described below do
present data in a format similar to the metadata syntax. The meta language is
used to describe both introspection interfaces and data interfaces.</p>
<h3 id="L463">Definition</h3>
<p>PVData supports structured data. All data appears as a top level structure.
A structure has an ordered set of fields where each field has a <span
style="font-family: courier;">fieldDef</span> defined as follows:</p>
<pre>type fieldName value // comment</pre>
<p>where <span style="font-family: courier;">value</span> is present for data
objects and <span style="font-family: courier;">//</span> indicates the the
rest of the line is a comment. </p>
<p>type is one of the following:</p>
<dl>
<dt>scalar</dt>
<dd>A scalar field can be any of the following:
<dl>
<dt style="font-family: courier;">boolean</dt>
<dd>Has the value<span style="font-family: courier;">true</span> or
<span style="font-family: courier;">false</span></dd>
<dt style="font-family: courier;">byte</dt>
<dd>An 8 bit signed integer.</dd>
<dt style="font-family: courier;">short</dt>
<dd>An 16 bit signed integer.</dd>
<dt style="font-family: courier;">int</dt>
<dd>An 32 bit signed integer.</dd>
<dt style="font-family: courier;">long</dt>
<dd>An 64 bit signed integer.</dd>
<dt style="font-family: courier;">float</dt>
<dd>A IEEE float.</dd>
<dt style="font-family: courier;">double</dt>
<dd>A IEEE double.</dd>
<dt style="font-family: courier;">string</dt>
<dd>An immutable string.</dd>
</dl>
</dd>
<dt>scalarArray</dt>
<dd>A scalarArray field is an array of any of the scalar types.
<dl>
<dt style="font-family: courier;">boolean[]</dt>
<dt style="font-family: courier;">byte[]</dt>
<dt style="font-family: courier;">short[]</dt>
<dt style="font-family: courier;">int[]</dt>
<dt style="font-family: courier;">long[]</dt>
<dt style="font-family: courier;">float[]</dt>
<dt style="font-family: courier;">double[]</dt>
<dt style="font-family: courier;">string[]</dt>
</dl>
</dd>
<dt>structure</dt>
<dd>A structure field has the definition:
<pre> structure fieldName
fieldDef
...
</pre>
or
<pre> xxx_t fieldName
// if data object then following appear
fieldDef
...
</pre>
For <span style="font-family: courier;">structure fieldName</span> each
<span style="font-family: courier;">fieldDef</span> must have a unique
<span style="font-family: courier;">fieldName</span> within the <span
style="font-family: courier;">structure</span> For <span
style="font-family: courier;">"xxx_t fieldName"</span> xxx_t must be a
previously structure definition of the form:
<pre> structure xxx_t
...</pre>
</dd>
<dt>structureArray</dt>
<dd>A structureArray field has the definition:
<pre> structure[] fieldName
structureDef
...
</pre>
<p>or</p>
<pre> xxx_t[] fieldName</pre>
<pre> </pre>
<p>Thus a structure array is an array where each element is a structure
but all elements have the same introspection interface. For introspection
the structureDef appears once without any data valuies.</p>
</dd>
</dl>
<p>The above is used to describe introspection objects. Data objects are
describe in a similar way but each scalar field and each array field has data
values. The definition of the data values depends on the type. For scalars the
data value is whatever is valid for the type. </p>
<dl>
<dt style="font-family: courier;">boolean</dt>
<dd>The value must be <span style="font-family: courier;">true</span> or
<span style="font-family: courier;">false</span> </dd>
<dt style="font-family: courier;">byte,...long</dt>
<dd>Any valid integer or hex value, e.g. <span
style="font-family: courier;">3 0xff</span> are valid values</dd>
<dt style="font-family: courier;">float,double</dt>
<dd>Any valid integer or real e.g. <span style="font-family: courier;">3
3.0 3e0</span> are valid values</dd>
<dt style="font-family: courier;">string</dt>
<dd>The value can be an alphanumeric value or any set of characters
enclosed in <span style="font-family: courier;">""</span> Within quotes a
quote is expressed as <span style="font-family: courier;">\"</span>
Examples are <span style="font-family: courier;">aValue "a value" "a\"
xxx"</span> are valid values. </dd>
</dl>
<p>For scalar arrays the syntax is:</p>
<pre> = [value,...,value]</pre>
<p>where each <span style="font-family: courier;">value</span> is a valid
scalar data value depending on the type. Thus it is a comma separated set of
values enclosed in <span style="font-family: courier;">[]</span> White space is
permitted surrounding each comma.</p>
<h3 id="L657">Examples</h3>
<p>Define the following top level structure:</p>
<pre>structure timeStamp_t
long secondsPastEpoch
int nanoSeconds </pre>
<p>Then the following introspection objects can be defined:</p>
<pre>structure scalarDoubleExample // introspection object
double value
timeStamp_t timeStamp</pre>
or
<pre>structure scalarDoubleExample // introspection object
double value
structure timeStamp
long secondsPastEpoch
int nanoSeconds</pre>
<p>The following data objects can be defined:</p>
<pre>structure scalarDoubleExample // data object
double value 1.0
timeStamp_t timeStamp
long secondsPastEpoch 0
int nanoSeconds 0</pre>
or
<pre>scalar arrayDoubleExample
double[] value [1.0,2.0]
structure timeStamp
long secondsPastEpoch 0
int nanoSeconds 0</pre>
<p>If the following interface is defined:</p>
<pre>structure point_t
double x
double y</pre>
<p>Then the following introspection objects can be defined: </p>
<pre>structure lineExample
point_t begin
point_t end
structure pointArrayExample
point_t[] points
</pre>
or
<pre>structure lineExample
structure begin
double x
double y
structure end
double x
double y
structure pointArrayExample
structure[] points
structure point
double x
double y</pre>
<p>And the following data objects can be defined:</p>
<pre>structure lineExample
point_t begin
double x 0.0
double y 0.0
point_t end
double x 10
double y 10
structure pointArrayExample
point_t[] value
structure point
double x 0.0
double y 0.0
structure point
double x 10.0
double y 10.0</pre>
<p>or</p>
<pre>structure lineExample
structure begin
double x 0
double y 0
structure end
double x 10
double y 10
structure pointArrayExample
structure[] value
structure point
double x 0.0
double y 0.0
structure point
double x 10.0
double y 10.0</pre>
<hr />
<h2 style="text-align: center" id="L701">PV - User Description</h2>
<hr />
<h3 style="text-align: center" id="L705">Overview</h3>
<p>Directory pvDataApp/pv has header files that completely describe pvData. The
implementation is provided in directory pvDataApp/factory. Test programs
appears on testApp/pvTest.</p>
<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 PVField or an
interface that extends PVField. Each field also has an introspection interface,
which is Field or an extension of Field. This section describes the complete
set of data and introspection interfaces for pvData.</p>
<p>A class FieldCreate creates introspection objects. A class PVDataCreate
creates data objects. A 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 style="font-family: courier;">pvType.h</dt>
<dd>C++ definitions for the pvData primitive types.</dd>
<dt style="font-family: courier;">pvIntrospect.h</dt>
<dd>A complete description of the introspection interfaces.</dd>
<dt style="font-family: courier;">pvData.h</dt>
<dd>A complete description of the data interfaces.</dd>
<dt style="font-family: courier;">convert.h</dt>
<dd>A facility that converts between data fields.</dd>
<dt style="font-family: courier;">standardField.h</dt>
<dd>Provides access to introspection interfaces for standard structures
like timeStamp, alarm, etc.</dd>
<dt style="font-family: courier;">standardPVField.h</dt>
<dd>Cteates data interfaces for standard data structures like timeStamp,
alarm, etc.</dd>
</dl>
<h3 style="text-align: center;" id="L746">pvType</h3>
<p>This provides C/C++ definitions for the pvData primitive types: boolean,
byte, short, int, 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. It has the definitions:</p>
<pre>typedef bool boolean;
typedef int8_t byte;
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint32_t uint32;
typedef uint64_t uint64;
// float and double are types
typedef std::string String;
typedef bool * BooleanArray;
typedef int8 * ByteArray;
typedef int16 * ShortArray;
typedef int32 * IntArray;
typedef int64 * LongArray;
typedef float * FloatArray;
typedef double * DoubleArray;
typedef String* StringArray;
// convenience definition for toString methods
typedef std::string * StringBuilder;</pre>
<p>where</p>
<dl>
<dt style="font-family: courier;">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 style="font-family: courier;">int8,...,int64</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. Note that byte and int8
are both defined just for consistency. The unsigned 32 and 64 bit integer
definitions are provided because the serialization/deserialization code
uses them. Thus they must be compatable over the network.</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">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>A typedef is provided for an array of each of the primitive types.</dd>
</dl>
<h3 style="text-align: center" id="L782">Process Variable Reflection</h3>
<p>This subsection describes <span
style="font-family: Courier New,Courier,monospace">pvIntrospect.h</span></p>
<p>Given a pvname, which consists of a record name and field name, 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 id="L790">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,
pvFloat,pvDouble,
pvString;
};
class ScalarTypeFunc {
public:
static bool isInteger(ScalarType type);
static bool isNumeric(ScalarType type);
static bool isPrimitive(ScalarType type);
static ScalarType getScalarType(String value);
const char* name(ScalarType);
static void toString(StringBuilder buf,ScalarType scalarType);
};</pre>
<p><span style="font-family: courier;">Type</span> is one of the following:</p>
<dl>
<dt style="font-family: courier;">scalar</dt>
<dd>A scalar of one of the scalar types.</dd>
<dt style="font-family: courier;">scalarArray</dt>
<dd>An array where every element has the same scalar type.</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">structureArray</dt>
<dd>An array where each element is a structure. Each element has the same
structure introspection interface.</dd>
</dl>
<p><span style="font-family: courier;">ScalarType</span> is one of the
following:</p>
<dl>
<dt style="font-family: courier;">pvBoolean</dt>
<dd>Has the value false or true.</dd>
<dt style="font-family: courier;">pvByte</dt>
<dd>A signed 8 bit integer.</dd>
<dt style="font-family: courier;">pvShort</dt>
<dd>A signed 16 bit integer.</dd>
<dt style="font-family: courier;">pvInt</dt>
<dd>A signed 32 bit integer.</dd>
<dt style="font-family: courier;">pvLong</dt>
<dd>A signed 64 bit integer.</dd>
<dt style="font-family: courier;">pvFloat</dt>
<dd>A IEEE float.</dd>
<dt style="font-family: courier;">pvDouble</dt>
<dd>A IEEE double,</dd>
<dt style="font-family: courier;">pvString</dt>
<dd>An immutable string.</dd>
</dl>
<p><span style="font-family: courier;">TypeFunction</span> is a set of
convenience methods for <span style="font-family: courier;">Type</span></p>
<dl>
<dt style="font-family: courier;">name</dt>
<dd>Returns the name of the type.</dd>
<dt style="font-family: courier;">toString</dt>
<dd>Convert the type to a string.</dd>
</dl>
<p><span style="font-family: courier;">ScalarTypeFunction</span> is a set of
convenience methods for <span
style="font-family: courier;">ScalarType</span></p>
<dl>
<dt style="font-family: courier;">isInteger</dt>
<dd>Is the scalarType an integer type, i.e. one of pvByte,...pvlong.</dd>
<dt style="font-family: courier;">isNumeric</dt>
<dd>Is the scalarType numeric, i.e. pvByte,...,pvDouble.</dd>
<dt style="font-family: courier;">isPrimitive</dt>
<dd>Is the scvalarType primitive, i.e. not pvString</dd>
<dt style="font-family: courier;">name</dt>
<dd>Returns the name of the scalarType.</dd>
<dt style="font-family: courier;">getScalarType</dt>
<dd>Given a string of the form String("boolean"),...,String("string")
return the scalarType.</dd>
<dt style="font-family: courier;">toString</dt>
<dd>Convert the scalar type to a string.</dd>
</dl>
<h4 id="L920">Reflection Description</h4>
<p>This section describes the reflection interfaces which provide the
following: </p>
<dl>
<dt style="font-family: courier;">Field</dt>
<dd>A field:
<dl>
<dt>Has a name.</dt>
<dt>Has a Type.</dt>
<dt>Can be converted to a string.<br />
Can be shared. A reference count is kept. When it becomes 0 the
instance is automatically deleted.</dt>
</dl>
</dd>
<dt style="font-family: courier;">Scalar</dt>
<dd>A scalar has a scalarType</dd>
<dt style="font-family: courier;">ScalarArray</dt>
<dd>The element type is a scalarType</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">Structure</dt>
<dd>Has fields that can be any of the supported types.</dd>
<dt style="font-family: courier;">FieldCreate</dt>
<dd>This is an interface that provides methods to create introspection
interfaces. A factory is provides to create FieldCreate.</dd>
<dt style="font-family: courier;">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 FieldConstPtr * 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;
protected:class Field : public std::tr1::enable_shared_from_this&lt;Field&gt; {
public:
typedef std::tr1::shared_ptr&lt;Field&gt; shared_pointer;
typedef std::tr1::shared_ptr&lt;const Field&gt; const_shared_pointer;
String getFieldName() const{return m_fieldName;}
Type getType() const{return m_type;}
virtual void toString(StringBuilder buf) const{toString(buf,0);}
virtual void toString(StringBuilder buf,int indentLevel) const;
void renameField(String newName);
Field(String fieldName,Type type);
virtual ~Field();
};
class Scalar : public Field{
public:
typedef std::tr1::shared_ptr&lt;Scalar&gt; shared_pointer;
typedef std::tr1::shared_ptr&lt;const Scalar&gt; const_shared_pointer;
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;
protected:
Scalar(String fieldName,ScalarType scalarType);
virtual ~Scalar();
...
};
class ScalarArray : public Field{
public:
typedef std::tr1::shared_ptr&lt;ScalarArray&gt; shared_pointer;
typedef std::tr1::shared_ptr&lt;const ScalarArray&gt; const_shared_pointer;
typedef ScalarArray&amp; reference;
typedef const ScalarArray&amp; const_reference;
ScalarType getElementType() const {return elementType;}
virtual void toString(StringBuilder buf) const{toString(buf,0);}
virtual void toString(StringBuilder buf,int indentLevel) const;
protected:
ScalarArray(String fieldName,ScalarType scalarType);
virtual ~ScalarArray();
...
};
class StructureArray : public Field{
public:
typedef std::tr1::shared_ptr&lt;StructureArray&gt; shared_pointer;
typedef std::tr1::shared_ptr&lt;const StructureArray&gt; const_shared_pointer;
typedef StructureArray&amp; reference;
typedef const StructureArray&amp; const_reference;
const Structure&amp; structure() const {return *pstructure;}
StructureConstPtr getStructure() const {return pstructure;}
virtual void toString(StringBuilder buf,int indentLevel=0) const;
};
class Structure : public Field {
public:
typedef std::tr1::shared_ptr&lt;Structure&gt; shared_pointer;
typedef std::tr1::shared_ptr&lt;const Structure&gt; const_shared_pointer;
typedef Structure&amp; reference;
typedef const Structure&amp; const_reference;
int getNumberFields() const {return numberFields;}
FieldConstPtr getField(String fieldName) const;
int getFieldIndex(String fieldName) const;
FieldConstPtrArray getFields() const {return fields;}
void appendField(FieldConstPtr field);
void appendFields(int numberFields,FieldConstPtrArray fields);
void removeField(int index);
virtual void toString(StringBuilder buf) const{toString(buf,0);}
virtual void toString(StringBuilder buf,int indentLevel) const;
protected:
Structure(String fieldName, int numberFields,FieldConstPtrArray fields);
virtual ~Structure();
...
};
class FieldCreate : NoDefaultMethods {
public:
FieldConstPtr create(String fieldName,FieldConstPtr field) const;
ScalarConstPtr createScalar(String fieldName,ScalarType scalarType) const;
ScalarArrayConstPtr createScalarArray(String fieldName,
ScalarType elementType) const;
StructureConstPtr createStructure (String fieldName,
int numberFields,FieldConstPtrArray fields) const;
StructureArrayConstPtr createStructureArray(String fieldName,
StructureConstPtr structure) const;
};
extern FieldCreate * getFieldCreate();</pre>
<p>The following methods are common to all of the reflection class
descriptions:</p>
<dl>
<dt>Constructor and Destructor</dt>
<dd>Note that all constructors and destructors are protected or private.
The only way to create instances is via FieldCreate. The implementation
manages all storage and automatically calls delete when no client is
attached. A few details are discussed in a later section.</dd>
<dt style="font-family: courier;">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>
<p><span style="font-family: courier;">Field</span> has the methods:</p>
<dl>
<dt style="font-family: courier;">getReferenceCount</dt>
<dd>Get the total number of current references to this field instance.</dd>
<dt style="font-family: courier;">getFieldName</dt>
<dd>Get the name of the field.</dd>
<dt style="font-family: courier;">getType</dt>
<dd>Get the field type.</dd>
<dt style="font-family: courier;">renameField</dt>
<dd>Rename the field name.</dd>
<dt style="font-family: courier;">incReferenceCount</dt>
<dd>Increment the reference count. This must be called by any code that
wants to "clone" an instance of the introspection interface and use it as
the introspection interface for a data field. The library that creates
data instances usually calls this so user code almost never calls this.
If the field is a structure then this is recursively called for each sub
field of the structure.</dd>
<dt style="font-family: courier;">decReferenceCount</dt>
<dd>This must be called to match each incReferenceCount. It is called when
the "cloned" version is no longer needed. This is almost always called by
a PVField instance when it is being deleted for a field that has no
parents. If the field is a structure then this is recursively called for
each sub field of the structure. OTHER code should not call this.</dd>
<dt style="font-family: courier;">dumpReferenceCount</dt>
<dd>Adds a report of the the current reference count for this field. If the
field is a structure then dumpReferenceCount is called for each sub
field.</dd>
<dt style="font-family: courier;">operator==</dt>
<dd>Returns (false,true) if the two objects (do not,do) have the same
values. Thus means the same types and names.</dd>
<dt style="font-family: courier;">operator!=</dt>
<dd>Returns (false,true) if the two objects (do,do not) have the same
values.</dd>
</dl>
<p><span style="font-family: courier;">Scalar</span> has the methods:</p>
<dl>
<dt style="font-family: courier;">getScalarType</dt>
<dd>Get that scalar type.</dd>
</dl>
<p><span style="font-family: courier;">ScalarArray</span> has the methods:</p>
<dl>
<dt style="font-family: courier;">getElementType</dt>
<dd>Get the element type.</dd>
</dl>
<p><span style="font-family: courier;">StructureArray</span> has the
methods:</p>
<dl>
<dt style="font-family: courier;">getStructure</dt>
<dd>Get the introspection interface that each element shares,</dd>
</dl>
<p><span style="font-family: courier;">Structure</span> has the methods:</p>
<dl>
<dt style="font-family: courier;">getNumberFields</dt>
<dd>Get the number of immediate subfields.</dd>
<dt style="font-family: courier;">getField</dt>
<dd>Given a name get the introspection interface for the field.</dd>
<dt style="font-family: courier;">getFieldIndex</dt>
<dd>Given a name get the index, within the array returned by the next
method, of the field.</dd>
<dt style="font-family: courier;">getFields</dt>
<dd>Get the array of introspection interfaces for the field,</dd>
<dt style="font-family: courier;">appendField</dt>
<dd>Append a field to the Structure.</dd>
<dt style="font-family: courier;">appendFields</dt>
<dd>Append the fields to the Structure. The caller is responsible for the
storage for the array for the fields. It is OK if the array is allocate
on the stack.</dd>
<dt style="font-family: courier;">removeField</dt>
<dd>Remove the field at the specified index. An exception is thrown if the
index is out of bounds.</dd>
</dl>
<p><span style="font-family: courier;">FieldCreate</span> has the methods:</p>
<dl>
<dt style="font-family: courier;">create</dt>
<dd>Given a field name and an existing introspection interface create a new
introspection object. The existing introspection interface can be any of
the allowed types. If the argument field is shared, i.e. has been
obtained from an existing oject, then field-&gt;incReferenceCount() must
be called before this method.</dd>
<dt style="font-family: courier;">createScalar</dt>
<dd>Create a scalar introspection instance.</dd>
<dt style="font-family: courier;">createScalarArray</dt>
<dd>Create a scalar array introspection instance.</dd>
<dt style="font-family: courier;">createStructure</dt>
<dd>Create a structure introspection instance. The FieldConstPtrArray
fields MUST be allocated on the heap NOT on the stack. It will
automatically be deleted when the structure instance is deleted. For any
element of fields that is shared, i.e. has been obtained from an existing
onject, then fields[index]-&gt;incReferenceCount() must be called before
this method.</dd>
<dt style="font-family: courier;">createStructureArray</dt>
<dd>Create a structure array introspection instance. If the argument
structure is shared, i.e. has been obtained from an existing object, then
structure-&gt;incReferenceCount() must be called before this method.</dd>
</dl>
<h3 style="text-align: center" id="L1135">Standard Fields</h3>
<p>The file standardField.h has a class description for creating or sharing
Field objects for standard fields. For each type of standard object two methods
are defined: one with no properties and with properties. 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 fieldName 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(
String("value"),
pvDouble,
String("value,alarm,timeStamp"));</pre>
<p>Will result in a Field definition that has the form:</p>
<pre>structure example
double value
structure alarm
structure severity
int index
string[] choices
structure timeStamp
long secondsPastEpoch
int nanoSeconds</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 : private NoDefaultMethods {
public:
StandardField();
~StandardField();
ScalarConstPtr scalar(String fieldName,ScalarType type);
StructureConstPtr scalar(String fieldName,
ScalarType type,String properties);
ScalarArrayConstPtr scalarArray(String fieldName,
ScalarType elementType);
StructureConstPtr scalarArray(String fieldName,
ScalarType elementType, String properties);
StructureArrayConstPtr structureArray(String fieldName,
StructureConstPtr structure);
StructureConstPtr structureArray(String fieldName,
StructureConstPtr structure,String properties);
StructureConstPtr structure(String fieldName,
int numFields,FieldConstPtrArray fields);
StructureConstPtr enumerated(String fieldName);
StructureConstPtr enumerated(String fieldName, String properties);
ScalarConstPtr scalarValue(ScalarType type);
StructureConstPtr scalarValue(ScalarType type,String properties);
ScalarArrayConstPtr scalarArrayValue(ScalarType elementType);
StructureConstPtr scalarArrayValue(ScalarType elementType,
String properties);
StructureArrayConstPtr structureArrayValue(StructureConstPtr structure);
StructureConstPtr structureArrayValue(StructureConstPtr structure,
String properties);
StructureConstPtr structureValue(
int numFields,FieldConstPtrArray fields);
StructureConstPtr enumeratedValue(StringArray choices);
StructureConstPtr enumeratedValue(StringArray choices,
String properties);
StructureConstPtr alarm();
StructureConstPtr timeStamp();
StructureConstPtr display();
StructureConstPtr control();
StructureConstPtr booleanAlarm();
StructureConstPtr byteAlarm();
StructureConstPtr shortAlarm();
StructureConstPtr intAlarm();
StructureConstPtr longAlarm();
StructureConstPtr floatAlarm();
StructureConstPtr doubleAlarm();
StructureConstPtr enumeratedAlarm();
private:
static void init();
};
extern StandardField * getStandardField();</pre>
<p>Where</p>
<dl>
<dt style="font-family: courier;">scalar</dt>
<dd>Create a scalar with the specified scalar type and name. If properties
are specified then 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 style="font-family: courier;">scalarArray</dt>
<dd>Create a scalarArray with each element having the specified scalar type
and name. If properties are specified then 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 style="font-family: courier;">structureArray</dt>
<dd>Create a structureArray with the specified structure interface and
name. If properties are specified then 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 style="font-family: courier;">structure</dt>
<dd>Create a structure with the specified name and fields specified by
numFields and fields. If properties are specified then 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 style="font-family: courier;">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 style="font-family: courier;">scalarValue</dt>
<dt style="font-family: courier;">scalarArrayValue</dt>
<dt style="font-family: courier;">structureArrayValue</dt>
<dt style="font-family: courier;">structureValue</dt>
<dt style="font-family: courier;">enumeratedValue</dt>
<dd>These are all like the version without the "Value" suffix. The field
name will always be "value"</dd>
<dt style="font-family: courier;">alarm</dt>
<dt style="font-family: courier;">timeStamp</dt>
<dt style="font-family: courier;">display</dt>
<dt style="font-family: courier;">control</dt>
<dt style="font-family: courier;">booleanAlarm</dt>
<dt style="font-family: courier;">byteAlarm</dt>
<dt style="font-family: courier;">shortAlarm</dt>
<dt style="font-family: courier;">intAlarm</dt>
<dt style="font-family: courier;">longAlarm</dt>
<dt style="font-family: courier;">floatAlarm</dt>
<dt style="font-family: courier;">doubleAlarm</dt>
<dt style="font-family: courier;">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>
<h3 style="text-align: center" id="L1219">PVField - Data Interfaces</h3>
<p>This section defines the Java Interfaces for accessing the data within a PV
record.</p>
<h4 id="L1223">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:
virtual void postPut() = 0;
};
class PVField
: public Serializable,
private NoDefaultMethods
{
public:
virtual ~PVField();
virtual void message(String message,MessageType messageType) ;
virtual void setRequester(Requester *prequester);
int getFieldOffset() ;
int getNextFieldOffset() ;
int getNumberFields() ;
PVAuxInfo * getPVAuxInfo();
bool isImmutable() ;
virtual void setImmutable();
FieldConstPtr getField() ;
PVStructure * getParent() ;
bool renameField(String newName);
void postPut() ;
void setPostHandler(PostHandler *postHandler);
virtual bool equals(PVField &amp;pv);
virtual void toString(StringBuilder buf) ;
virtual void toString(StringBuilder buf,int indentLevel) ;
protected:
PVField(PVStructure *parent,FieldConstPtr field);
void setParent(PVStructure *parent);
private:
};</pre>
<p><span style="font-family: courier;">PostHandler</span> is a class that must
be implemented by any code that calls setPostHandler. It's single virtual
method. <span style="font-family: courier;">postPut</span> is called whenever
<span style="font-family: courier;">PVField::postPut</span> is called.</p>
<p><span style="font-family: courier;">Serializable, and
NoDefaultMethods</span> are described in a later section.</p>
<p>The public methods for <span style="font-family: courier;">PVField</span>
are:</p>
<dl>
<dt style="font-family: courier;">~PVField</dt>
<dd>destructor which must be called by whatever created the PVfield via a
call to one of the methods of <span
style="font-family: courier;">PVDataCreate</span> </dd>
<dt style="font-family: courier;">message</dt>
<dd>Code attached to this field can call this method to report
problems.</dd>
<dt style="font-family: courier;">setRequester</dt>
<dd>Sets a requester to be called when message or getRequesterName are
called. This is only legal for the top level PVField. </dd>
<dt style="font-family: courier;">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 style="font-family: courier;">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 style="font-family: courier;">getNumberFields</dt>
<dd>Get the total number of fields in this field. This is nextFieldOffset -
fieldOffset. </dd>
<dt style="font-family: courier;">getPVAuxInfo</dt>
<dd>Get the PVAuxInfo for this field. PVAuxInfo is described below.</dd>
<dt style="font-family: courier;">isImmutable</dt>
<dd>Is the field immutable?</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">getField</dt>
<dd>Get the reflection interface for the data.</dd>
<dt style="font-family: courier;">getParent</dt>
<dd>Get the interface for the parent or null if this is the top level
PVStructure.</dd>
<dt style="font-family: courier;">renameField</dt>
<dd>Rename the field name. (false,true) is returned if the name (was
not,was) changed. It is not changed if the field is an an element of a
structure that already has a field with the same name. </dd>
<dt style="font-family: courier;">postPut</dt>
<dd>If a postHandler is registered it is called otherwise no action is
taken.</dd>
<dt style="font-family: courier;">setPostHandler</dt>
<dd>Set the postHandler for the record. Only a single handler can be
registered.</dd>
<dt style="font-family: courier;">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>
</dl>
<dl>
<dt style="font-family: courier;">toString</dt>
<dd>Converts the field data to a string. This is mostly for debugging
purposes.</dd>
</dl>
<h4 id="L1333">PVAuxInfo</h4>
<p>AuxInfo (Auxillary Information) is information about a field that is
application specific. It will not be available outside the application that
implements the database. In particular it will not be made available to Channel
Access. It is used by the database itself to override the default
implementation of fields. The JavaIOC uses it for attaching support code.
Database Configuration and other tools can use it for configuration
information. Each Field and each PVField can have have an arbitrary number of
auxInfos. An auxInfo is a (key,PVScalar) pair where key is a string.</p>
<pre>class PVAuxInfo : private NoDefaultMethods {
public:
PVAuxInfo(PVField *pvField);
~PVAuxInfo();
PVField * getPVField();
PVScalar * createInfo(String key,ScalarType scalarType);
PVScalarMap getInfos();
PVScalar * getInfo(String key);
void toString(StringBuilder buf);
void toString(StringBuilder buf,int indentLevel);
private:
};</pre>
<p>where</p>
<dl>
<dt style="font-family: courier;">getPVField</dt>
<dd>Get the PVField to which this PVAuxInfo is attached.</dd>
<dt style="font-family: courier;">createInfo</dt>
<dd>Create a new PVScalar of type scalarType.</dd>
<dt style="font-family: courier;">getInfos</dt>
<dd>Get a map of all the auxInfos.</dd>
<dt style="font-family: courier;">getInfo</dt>
<dd>Get the PVScalar with the specified key.</dd>
<dt style="font-family: courier;">toString</dt>
<dd>Print all the auxInfos</dd>
</dl>
<h4 id="L1367">PVScalar and extensions</h4>
<pre>class PVScalar : public PVField {
public:
virtual ~PVScalar();
ScalarConstPtr getScalar() ;
protected:
PVScalar(PVStructure *parent,ScalarConstPtr scalar);
};</pre>
<h5 id="L1371">Primitive PVField types</h5>
<p>The interfaces for primitive data types are:</p>
<pre>template&lt;typename T&gt;
class PVScalarValue : public PVScalar {
public:
typedef std::tr1::shared_ptr&lt;PVScalarValue&gt; shared_pointer;
typedef std::tr1::shared_ptr&lt;const PVScalarValue&gt; const_shared_pointer;
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
virtual ~PVScalarValue() {}
virtual T get() = 0;
virtual void put(T value) = 0;
protected:
PVScalarValue(PVStructure *parent,ScalarConstPtr scalar)
: PVScalar(parent,scalar) {}
private:
};
typedef PVScalarValue&lt;bool&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;float&gt; PVFloat;
typedef PVScalarValue&lt;double&gt; PVDouble;
// PVString is special case, since it implements SerializableArray
class PVString : public PVScalarValue&lt;String&gt;, SerializableArray {
public:
virtual ~PVString() {}
protected:
PVString(PVStructure *parent,ScalarConstPtr scalar)
: PVScalarValue&lt;String&gt;(parent,scalar) {}
};</pre>
<h4 id="L1377">PVArray and Extensions</h4>
<p><span style="font-family: courier">PVArray</span> 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:
virtual ~PVArray();
int getLength() ;
void setLength(int length);
int getCapacity() ;
bool isCapacityMutable() ;
void setCapacityMutable(bool isMutable);
virtual void setCapacity(int capacity) = 0;
protected:
PVArray(PVStructure *parent,FieldConstPtr field);
void setCapacityLength(int capacity,int length);
};</pre>
<dl>
<dt style="font-family: courier;">getLength</dt>
<dd>Get the current length. This is less than or equal to the capacity.</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">getCapacity</dt>
<dd>Get the capacity, i.e. this is the size of the underlying data
array.</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">isCapacityMutable</dt>
<dd>Is the capacity mutable</dd>
<dt style="font-family: courier;">setCapacityMutable</dt>
<dd>Specify if the capacity can be changed.</dd>
</dl>
<h5 id="L1416">PVArray Extensions</h5>
<p>The interface for each array type has get and put methods which have the
same arguments except for the data type. For example PVDoubleArray is:</p>
<pre>template&lt;typename T&gt;
class PVArrayData {
public:
typedef std::tr1::shared_ptr&lt;PVArrayData&gt; shared_pointer;
typedef std::tr1::shared_ptr&lt;const PVArrayData&gt; const_shared_pointer;
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
pointer data;
int offset;
};
class PVScalarArray : public PVArray {
public:
typedef std::tr1::shared_ptr&lt;PVScalarArray&gt; shared_pointer;
typedef std::tr1::shared_ptr&lt;const PVScalarArray&gt; const_shared_pointer;
virtual ~PVScalarArray();
ScalarArrayConstPtr getScalarArray() ;
protected:
PVScalarArray(PVStructure *parent,ScalarArrayConstPtr scalarArray);
private:
};
template&lt;typename T&gt;
class PVValueArray : public PVScalarArray {
public:
typedef std::tr1::shared_ptr&lt;PVValueArray&gt; shared_pointer;
typedef std::tr1::shared_ptr&lt;const PVValueArray&gt; const_shared_pointer;
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef PVArrayData&lt;T&gt; ArrayDataType;
virtual ~PVValueArray() {}
virtual int get(int offset, int length, ArrayDataType *data) = 0;
virtual int put(int offset,int length, pointer from, int fromOffset) = 0;
virtual void shareData(pointer value,int capacity,int length) = 0;
protected:
PVValueArray(PVStructure *parent,ScalarArrayConstPtr scalar)
: PVScalarArray(parent,scalar) {}
private:
};
typedef PVArrayData&lt;bool&gt; BooleanArrayData;
typedef PVValueArray&lt;bool&gt; PVBooleanArray;
typedef PVArrayData&lt;int8&gt; ByteArrayData;
typedef PVValueArray&lt;int8&gt; PVByteArray;
typedef PVArrayData&lt;int16&gt; ShortArrayData;
typedef PVValueArray&lt;int16&gt; PVShortArray;
typedef PVArrayData&lt;int32&gt; IntArrayData;
typedef PVValueArray&lt;int32&gt; PVIntArray;
typedef PVArrayData&lt;int64&gt; LongArrayData;
typedef PVValueArray&lt;int64&gt; PVLongArray;
typedef PVArrayData&lt;float&gt; FloatArrayData;
typedef PVValueArray&lt;float&gt; PVFloatArray;
typedef PVArrayData&lt;double&gt; DoubleArrayData;
typedef PVValueArray&lt;double&gt; PVDoubleArray;
typedef PVArrayData&lt;String&gt; StringArrayData;
typedef PVValueArray&lt;String&gt; PVStringArray;</pre>
<p>Get "exposes" it's internal array by setting data.data and data.offset. The
caller is responsible for copying the array elements. This violates the
principle that objects should not expose their internal data but is done for
efficency. For example it makes it possible to copy between arrays with
identical element types without requiring an intermediate array.</p>
<p>Both get and put return the number of elements actually transfered. The
arguments are:</p>
<dl>
<dt style="font-family: courier;">offset</dt>
<dd>The offset in the PV array.</dd>
<dt style="font-family: courier;">len</dt>
<dd>The maximum number of elements to transfer. The number actually
transfered will be less than or equal to this value.</dd>
<dt style="font-family: courier;">data</dt>
<dd>Get sets data.data to it's internal array and data.offset to the offset
into the array. The caller is responsible for the actual data
transfer.</dd>
<dt style="font-family: courier;">from</dt>
<dd>The array from which the data is taken. This array is supplied by the
caller</dd>
<dt style="font-family: courier;">fromOffset</dt>
<dd>The offset in <span style="font-family: courier;">from</span></dd>
</dl>
<p>The caller must be prepared to make multiple calls to retrieve or put an
entire array. A caller should accept or put partial arrays. For example the
following reads an entire array:</p>
<pre> void doubleArray getArray(PVDoubleArray *pv,doubleArray *to,int lenArray)
{
int len = pv-&gt;getLength();
if(lenArray&lt;len) len = lenArray;
DoubleArrayData data;
int offset = 0;
while(offset &lt; len) {
int num = pv-&gt;get(offset,(len-offset),&amp;data);
doubleArray from = &amp;data.data[data.offset];
doubleArray to = &amp;to[offset]
int numbytes = num*sizeof(double);
memcopy(from,to,numBytes);
offset += num;
}
} </pre>
<p>shareData results in the PVArray using the primitive array that is passed to
this method. This is most useful for immutable arrays. In this case the caller
must set the PVArray to be immutable. In the PVArray is not immutable then it
is the applications responsibility to coordinate access to the array. Again
this violates the principle that objects should not expose their internal data
but is important for immutable arrays. For example pvData and the javaIOC
define many enumerated structures where an enumerated structure has two fields:
index and choices. Choices is a PVStringArray that holds the enumerated
choices. Index is a PVInt that is the index of the currently selected choice.
For many enumerated structures choices is immutable. Allowing the choices
internal String[] to be shared between all the instances of an enumerated
structure saves on storage. Another reason for allowing shared data is so that
an application which processes an array can be separated into multiple modules
that directly access the internal data array of a PVArray. This can be required
for minimizing CPU overhead. In this case it is the applications responsibility
to coordinate access to the array.</p>
<h4 id="L1460">PVStructure</h4>
<p>The interface for a structure is:</p>
<pre>class PVStructure : public PVField,public BitSetSerializable {
public:
};virtual ~PVStructure();
StructureConstPtr getStructure();
PVFieldPtrArray getPVFields();
PVField *getSubField(String fieldName);
PVField *getSubField(int fieldOffset);
void appendPVField(PVField *pvField);
void appendPVFields(int numberFields,PVFieldPtrArray pvFields);
void removePVField(String fieldName);
PVBoolean *getBooleanField(String fieldName);
PVByte *getByteField(String fieldName);
PVShort *getShortField(String fieldName);
PVInt *getIntField(String fieldName);
PVLong *getLongField(String fieldName);
PVFloat *getFloatField(String fieldName);
PVDouble *getDoubleField(String fieldName);
PVString *getStringField(String fieldName);
PVStructure *getStructureField(String fieldName);
PVScalarArray *getScalarArrayField(
String fieldName,ScalarType elementType);
PVStructureArray *getStructureArrayField(String fieldName);
String getExtendsStructureName();
bool putExtendsStructureName(
String extendsStructureName);
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(PVStructure *parent,StructureConstPtr structure);
PVStructure(
PVStructure *parent,
StructureConstPtr structure,
PVFieldPtrArray pvFields);
};</pre>
<p>where</p>
<dl>
<dt style="font-family: courier;">getStructure</dt>
<dd>Get the introspection interface for the structure.</dd>
<dt style="font-family: courier;">getPVFields</dt>
<dd>Returns the array of subfields. The set of subfields must all have
different field names.</dd>
<dt style="font-family: courier;">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...</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">appendPVField</dt>
<dd>Append pvField to the end of this PVStructure. This should NOT be
called if any code is attached to any of the fields in the top level
structure.</dd>
<dt style="font-family: courier;">appendPVFields</dt>
<dd>Append an array of pvFields to the end of this structure. Note that if
the original number of fields is 0 than pvFields replaces the original.
Thus the caller must NOT reuse pvFields after calling this method. This
should NOT be called if any code is attached to any of the fields in the
top level structure</dd>
<dt style="font-family: courier;">removePVField</dt>
<dd>Remove the specified field from this structure. This should NOT be
called if any code is attached to any of the fields in the top level
structure.</dd>
<dt style="font-family: courier;">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...</dd>
<dt style="font-family: courier;">getByteField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt style="font-family: courier;">getShortField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt style="font-family: courier;">getIntField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt style="font-family: courier;">getLongField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt style="font-family: courier;">getFloatField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt style="font-family: courier;">getDoubleField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt style="font-family: courier;">getStringField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt style="font-family: courier;">getScalarArrayField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt style="font-family: courier;">getStructureArrayField</dt>
<dd>Look for fieldName. If found and it has the correct type return the
interface.</dd>
<dt style="font-family: courier;">getExtendsStructureName</dt>
<dd>Get the name of structure that this structure extends.</dd>
<dt style="font-family: courier;">putExtendsStructureName</dt>
<dd>Specify the structure that this structure extends.</dd>
</dl>
<h4 id="L1564">PVStructureArray</h4>
<p>The interface for an array of structures is:</p>
<pre>class StructureArrayData {
public:
PVStructurePtrArray data;
int offset;
};
class PVStructureArray : public PVArray {
public:
virtual ~PVStructureArray() {}
virtual StructureArrayConstPtr getStructureArray() = 0;
virtual int append(int number) = 0;
virtual bool remove(int offset,int number) = 0;
virtual void compress() = 0;
virtual int get(int offset, int length,
StructureArrayData *data) = 0;
virtual int put(int offset,int length,
PVStructurePtrArray from, int fromOffset) = 0;
virtual void shareData( PVStructurePtrArray value,int capacity,int length) = 0;
protected:
PVStructureArray(PVStructure *parent,
StructureArrayConstPtr structureArray);
};</pre>
<p>where</p>
<dl>
<dt style="font-family: courier;">getStructureArray</dt>
<dd>Get the introspection interface shared by each element.</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">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 style="font-family: courier;">compres</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 id="L1595">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:
PVField *createPVField(PVStructure *parent,
FieldConstPtr field);
PVField *createPVField(PVStructure *parent,
String fieldName,PVField * fieldToClone);
PVScalar *createPVScalar(PVStructure *parent,ScalarConstPtr scalar);
PVScalar *createPVScalar(PVStructure *parent,
String fieldName,ScalarType scalarType);
PVScalar *createPVScalar(PVStructure *parent,
String fieldName,PVScalar * scalarToClone);
PVScalarArray *createPVScalarArray(PVStructure *parent,
ScalarArrayConstPtr scalarArray);
PVScalarArray *createPVScalarArray(PVStructure *parent,
String fieldName,ScalarType elementType);
PVScalarArray *createPVScalarArray(PVStructure *parent,
String fieldName,PVScalarArray * scalarArrayToClone);
PVStructureArray *createPVStructureArray(PVStructure *parent,
StructureArrayConstPtr structureArray);
PVStructure *createPVStructure(PVStructure *parent,
StructureConstPtr structure);
PVStructure *createPVStructure(PVStructure *parent,
String fieldName,int numberFields,FieldConstPtrArray fields);
PVStructure *createPVStructure(PVStructure *parent,
String fieldName,int numberFields,PVFieldPtrArray pvFields);
PVStructure *createPVStructure(PVStructure *parent,
String fieldName,PVStructure *structToClone);
protected:
PVDataCreate();
friend PVDataCreate * getPVDataCreate();
};
extern PVDataCreate * getPVDataCreate();</pre>
<p>where </p>
<dl>
<dt style="font-family: courier;">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. WARNING If
the FieldConstPtr field argument is passed and field is already used by
another data object then the caller MUST call
field-&gt;incReferenceCount() before calling this method.</dd>
<dt style="font-family: courier;">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. WARNING If the ScalarAConstPtr scalar argument is passed and
scalar is already used by another data object then the caller MUST call
scalar-&gt;incReferenceCount() before calling this method.</dd>
<dt style="font-family: courier;">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. WARNING If the ScalarArrayConstPtr scalarArray argument is
passed and scalarArray is already used by another data object then the
caller MUST call scalarArray-&gt;incReferenceCount() before calling this
method.</dd>
<dt style="font-family: courier;">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. If
structureArray is alreadt used by another data object than
structureArray-&gt;incReferenceCount() MUST be called before calling this
method.</dd>
<dt style="font-family: courier;">createPVStructure</dt>
<dd>Create an instance of a PVStructure. Four methods are provided. The
first method uses a previously created structure introspection interface.
The second uses a Field array to initialize the sub-fields. For the third
the PVField array is the subfields for the PVStructure. The parent of
each PVField array element is set to the PVStructure being created. The
forth 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. WARNING If theStructureConstPtr
structure argument is passed and structure is already used by another
data object then the caller MUST call structure-&gt;incReferenceCount()
before calling this method.</dd>
</dl>
<h3 style="text-align: center" id="L1629">Standard Data Fields</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 : private NoDefaultMethods {
public:
StandardPVField();
~StandardPVField();
PVScalar * scalar(PVStructure *parent,String fieldName,ScalarType type);
PVStructure * scalar(PVStructure *parent,
String fieldName,ScalarType type,String properties);
PVScalarArray * scalarArray(PVStructure *parent,
String fieldName,ScalarType elementType);
PVStructure * scalarArray(PVStructure *parent,
String fieldName,ScalarType elementType, String properties);
PVStructureArray * structureArray(PVStructure *parent,
String fieldName,StructureConstPtr structure);
PVStructure* structureArray(PVStructure *parent,
String fieldName,StructureConstPtr structure,String properties);
PVStructure * enumerated(PVStructure *parent,
String fieldName,StringArray choices, int number);
PVStructure * enumerated(PVStructure *parent,
String fieldName,StringArray choices, int number, String properties);
PVScalar * scalarValue(PVStructure *parent,ScalarType type);
PVStructure * scalarValue(PVStructure *parent,
ScalarType type,String properties);
PVScalarArray * scalarArrayValue(PVStructure *parent,ScalarType elementType);
PVStructure * scalarArrayValue(PVStructure *parent,
ScalarType elementType, String properties);
PVStructureArray * structureArrayValue(PVStructure *parent,
StructureConstPtr structure);
PVStructure * structureArrayValue(PVStructure *parent,
StructureConstPtr structure,String properties);
PVStructure * enumeratedValue(PVStructure *parent,StringArray choices);
PVStructure * enumeratedValue(PVStructure *parent,
StringArray choices, String properties);
PVStructure * alarm(PVStructure *parent);
PVStructure * timeStamp(PVStructure *parent);
PVStructure * display(PVStructure *parent);
PVStructure * control(PVStructure *parent);
PVStructure * booleanAlarm(PVStructure *parent);
PVStructure * byteAlarm(PVStructure *parent);
PVStructure * shortAlarm(PVStructure *parent);
PVStructure * intAlarm(PVStructure *parent);
PVStructure * longAlarm(PVStructure *parent);
PVStructure * floatAlarm(PVStructure *parent);
PVStructure * doubleAlarm(PVStructure *parent);
PVStructure * enumeratedAlarm(PVStructure *parent);
PVStructure * powerSupply(PVStructure *parent);
};</pre>
<h3 style="text-align: center" id="L1635">Convert</h3>
<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 inline bool operator!=(PVField&amp; a, PVField&amp; b)
{return !(a==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)
{return !(a==b);}
static inline bool operator!=(const Scalar&amp; a, const Scalar&amp; b)
{return !(a==b);}
static inline bool operator!=(const ScalarArray&amp; a, const ScalarArray&amp; b)
{return !(a==b);}
static inline bool operator!=(const Structure&amp; a, const Structure&amp; b)
{return !(a==b);}
static inline bool operator!=(const StructureArray&amp; a, const StructureArray&amp; b)
{return !(a==b);}
class Convert : NoDefaultMethods {
public:
Convert();
~Convert();
void getFullName(StringBuilder buf,PVField *pvField);
bool equals(PVField &amp;a,PVField &amp;b);
void getString(StringBuilder buf,PVField * pvField,int indentLevel);
void getString(StringBuilder buf,PVField *pvField);
void fromString(PVScalar *pv, String from);
int fromString(PVScalarArray *pv, String from);
int fromStringArray(PVScalarArray *pv, int offset, int length,
StringArray from, int fromOffset);
int toStringArray(PVScalarArray *pv, int offset, int length,
StringArray to, int toOffset);
bool isCopyCompatible(FieldConstPtr from, FieldConstPtr to);
void copy(PVField *from,PVField *to);
bool isCopyScalarCompatible(
ScalarConstPtr from, ScalarConstPtr to);
void copyScalar(PVScalar *from, PVScalar *to);
bool isCopyScalarArrayCompatible(ScalarArrayConstPtr from,
ScalarArrayConstPtr to);
int copyScalarArray(PVScalarArray *from, int offset,
PVScalarArray *to, int toOffset, int length);
bool isCopyStructureCompatible(
StructureConstPtr from, StructureConstPtr to);
void copyStructure(PVStructure *from, PVStructure *to);
bool isCopyStructureArrayCompatible(
StructureArrayConstPtr from, StructureArrayConstPtr to);
void copyStructureArray(
PVStructureArray *from, PVStructureArray *to);
int8 toByte(PVScalar *pv);
int16 toShort(PVScalar *pv);
int32 toInt(PVScalar *pv);
int64 toLong(PVScalar *pv);
float toFloat(PVScalar *pv);
double toDouble(PVScalar *pv);
String toString(PVScalar *pv);
void fromByte(PVScalar *pv,int8 from);
void fromShort(PVScalar *pv,int16 from);
void fromInt(PVScalar *pv, int32 from);
void fromLong(PVScalar *pv, int64 from);
void fromFloat(PVScalar* pv, float from);
void fromDouble(PVScalar *pv, double from);
int toByteArray(PVScalarArray *pv, int offset, int length,
ByteArray to, int toOffset);
int toShortArray(PVScalarArray *pv, int offset, int length,
ShortArray to, int toOffset);
int toIntArray(PVScalarArray *pv, int offset, int length,
IntArray to, int toOffset);
int toLongArray(PVScalarArray *pv, int offset, int length,
LongArray to, int toOffset);
int toFloatArray(PVScalarArray *pv, int offset, int length,
FloatArray to, int toOffset);
int toDoubleArray(PVScalarArray *pv, int offset, int length,
DoubleArray to, int toOffset);
int fromByteArray(PVScalarArray *pv, int offset, int length,
ByteArray from, int fromOffset);
int fromShortArray(PVScalarArray *pv, int offset, int length,
ShortArray from, int fromOffset);
int fromIntArray(PVScalarArray *pv, int offset, int length,
IntArray from, int fromOffset);
int fromLongArray(PVScalarArray *pv, int offset, int length,
LongArray from, int fromOffset);
int fromFloatArray(PVScalarArray *pv, int offset, int length,
FloatArray from, int fromOffset);
int fromDoubleArray(PVScalarArray *pv, int offset, int length,
DoubleArray from, int fromOffset);
void newLine(StringBuilder buf, int indentLevel);
};
extern Convert * getConvert();</pre>
<p>The array methods all return the number of elements copied or converted.
This can be less than <span style="font-family: courier;">len</span> if the
PVField array contains less than len elements.</p>
<p><span style="font-family: courier;">newLine</span> is a convenience method
for code that implements <span style="font-family: courier;">toString</span> It
generates a newline and inserts blanks at the beginning of the newline.</p>
<hr />
<h2 style="text-align: center" id="L1705">Namespace and Memory Management</h2>
<hr />
<h3 style="text-align: center" id="L1709">Namespace</h3>
<p>All code in project pvDataCPP appears in namespace: </p>
<pre>namespace epics { namespace pvData {
// ...
}}</pre>
<h3 style="text-align: center" id="L1715">Memory Managemment</h3>
<h4 id="L1717">NoDefaultMethods</h4>
<p>Any class that does not want the compiler to generate default methods can
privately extend the following class which is defined in file
noDefaultMethods.h:</p>
<pre>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 id="L1723">PVData introspection objects</h3>
<p>Introspection objects are meant to be shared. They are all made available
via std::tri::shared_pointer.</p>
<h3 id="L1727">PVData data objects</h3>
<p>All PVData data objects must publically extend PVField, which does not allow
default methods but does have a virtual destructor. It is expected that each
data object is "owned" by some entity. For example a pvIOC (not implemented)
database will own all records and thus all PVData data objects in the database.
It is the ONLY entity that will create and destroy the data objects. All other
code only receives pointers to the data objects. Before a record is deleted any
code that is connected to a record is notified before the record is deleted.
After deletion all pointers to data in the record are invalid. Similarly
pvAccess creates and destroys PVData objects and notifies clients before
destroying PVData data objects.</p>
<h3 id="L1731">Other code in this project</h3>
<p>The classes in property, i.e. alarm, timeStamp, display, and control are all
meant to be free copied and shared. They can be created on the stack. In most
cases it is not necessary to create them on the heap.</p>
<p>Other clases privately extend NoDefaultClasses and are not normally meant to
be extended. Thus they can only be created via "new" and must be destroyed via
"delete".</p>
<hr />
<h2 style="text-align: center" id="L1739">Examples</h2>
<hr />
<h3 id="L1743">Accessing PVData</h3>
<p>Assume that code wants to print two fields from a PVStructure:</p>
<dl>
<dt style="font-family: courier;">value</dt>
<dd>Must be a PVDouble.</dd>
<dt style="font-family: courier;">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) {
PVField *valuePV = pvStructure-&gt;getSubField(String("value"));
if(valuePV==0) {
buf += "value field not found";
return;
}
buf += "value ";
valuePV-&gt;toString(buf);
PVField *timeStampPV = pvStructure-&gt;getSubField(String("timeStamp"));
if(timeStampPV==0) {
buf += "timeStamp field not found";
return;
}
buf += " timeStamp ";
timeStampPV-&gt;toString(buf);
}</pre>
<h3 id="L1762">Creating PVData</h3>
<p>Example of creating a scalar field.</p>
<pre> PVDataCreate *pvDataCreate = getPVDataCreate();
PVDouble *pvValue = pvDataCreate-&gt;createPVScalar(
0,
String("value"),
pvDouble);</pre>
<p>Create an alarm structure the hard way</p>
<pre> FieldCreate *fieldCreate = getFieldCreate();
PVDataCreate *pvDataCreate = getPVDataCreate();
FieldConstPtrArray fields = new FieldConstPtr[2];
fields[0] = fieldCreate-&gt;createScalar(String("severity"),pvInt);
fields[1] = fieldCreate-&gt;createScalar(String("message"),pvString);
StructureConstPtralarmField = fieldCreate-&gt;createStructure(String("alarm"),2,fields);</pre>
<p>Create an alarm structure the easy way.</p>
<pre> StandardPVField *standardPVField = getStandardPVField();
PVStructure *pvAlarm = standardPVField-&gt;alarm(parent);</pre>
<p>Create a PVStructure with field name example that has a double value field
and a timeStamp and alarm. Do it the easy way.</p>
<pre> StandardPVField *standardPVField = getStandardPVField();
PVStructure *pvStructure = standardPVField-&gt;scalar(
0, //parent is null
String("example"),
String("timeStamp,alarm"))</pre>
<hr />
<h2 style="text-align: center" id="L1782">Property</h2>
<hr />
<h3 style="text-align: center" id="L1786">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
structure alarm
structure timeStamp
double value
structure display
string description "Sample Description"
string format "%f"
string units volts
structure limit
double low 0.0
double high 10.0</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 powerSupplyValueStructure
double value
structure alarm
structure powerSupplySimple
structure alarm
structure timeStamp
powerSupplyValueStructure voltage
powerSupplyValueStructure power
powerSupplyValueStructure current</pre>
<h3 style="text-align: center" id="L1798">Standard Properties</h3>
<p>The following field names have special meaning, i.e. support properties for
general purpose clients.</p>
<dl>
<dt style="font-family: courier;">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 style="font-family: courier;">scalar</dt>
<dd>One of boolean, byte, short, int, long, float, double, or
string</dd>
<dt style="font-family: courier;">scalarArray</dt>
<dd>An array with the elementType being a scalar type</dd>
<dt style="font-family: courier;">enumerated structure</dt>
<dd>A structure that includes fields named index, choice, and
choices. index is an int that selects a choice. choice is the
currently selected choice. choices is an array of strings that
defines the complete set of choices.</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">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 style="font-family: courier;">alarm</dt>
<dd>The alarm. The type MUST be an alarm structure. </dd>
<dt style="font-family: courier;">display</dt>
<dd>A display structure as described below. It provides display
characteristics for the value field.</dd>
<dt style="font-family: courier;">control</dt>
<dd>A control structure as described below. It provides control
characteristics for the value field.</dd>
<dt style="font-family: courier;">history</dt>
<dd>Provides a history buffer for the value field. Note that currently
PVData does not define history support.</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">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 style="font-family: courier;">valueAlarm</dt>
<dd>A field with support that looks for alarm conditions based on the
value.</dd>
<dt style="font-family: courier;">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 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 style="text-align: center" id="L1879">Overview of Property Support</h3>
<p>Except for enumerated, each property has two files: a property.h and a
pvProperty.h . For example: <span style="text-align: center">timeStamp.h</span>
and <span style="text-align: center">pvTimeStamp.h</span> 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 <span style="text-align: center">new</span>
or <span style="text-align: center">delete</span> 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(PVField *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 style="text-align: center" id="L1899">timeStamp</h3>
<p>A timeStamp is represented by the following structure</p>
<pre>structure timeStamp
int64 secondsPartEpoch
int32 nanoSeconds
int32 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: <span
style="font-family: courier;">timeStamp.h</span> and <span
style="font-family: courier;">pvTimeStamp.h</span> <span
style="font-family: courier;">timeStamp.h</span> defines a time stamp
independent of pvData, i.e. it is a generally useful class for manipulating
timeStamps. <span style="font-family: courier;">pvTimeStamp.h</span> is 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 <span
style="font-family: courier;">timeStamp.h</span></p>
<h4 id="L1923">timeStamp.h</h4>
<p>This provides </p>
<pre>extern int32 milliSecPerSec;
extern int32 microSecPerSec;
extern int32 ;
extern int64 posixEpochAtEpicsEpoch;
class TimeStamp {
public:
TimeStamp();
TimeStamp(int64 secondsPastEpoch,int32 nanoSeconds = 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();
int64 getEpicsSecondsPastEpoch() const;
int32 getNanoSeconds() const;
int32 getUserTag() const;
void setUserTag(int userTag);
void put(int64 secondsPastEpoch,int32 nanoSeconds = 0);
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 style="font-family: courier;">TimeStamp()</dt>
<dd>The defauly constuctor. Both seconds and nanoSeconds are set to 0.</dd>
<dt style="font-family: courier;">TimeStamp(int64 secondsPastEpoch,int32
nanoSeconds = 0)</dt>
<dd>A constructor that gives initial values to seconds and nanoseconds.</dd>
<dt style="font-family: courier;">normalize</dt>
<dd>Adjust seconds and nanoSeconds so that
0&lt;=nanoSeconds&lt;nanoSecPerSec.</dd>
<dt style="font-family: courier;">fromTime_t</dt>
<dd>Set time from standard C time.</dd>
<dt style="font-family: courier;">toTime_t</dt>
<dd>Convert timeStamp to standard C time.</dd>
<dt style="font-family: courier;">getSecondsPastEpoch</dt>
<dd>Get the number of seconds since the epoch.</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">getNanoSeconds</dt>
<dd>Get the number of nanoSeconds. This is always normalized.</dd>
<dt><span
style="font-family: Courier New,Courier,monospace">getUserTag</span></dt>
<dd>Get the userTag.</dd>
<dt><span
style="font-family: Courier New,Courier,monospace">setUserTag</span></dt>
<dd>Set the userTag.</dd>
<dt style="font-family: courier;">put(int64 secondsPastEpoch,int32
nanoSeconds = 0)</dt>
<dd>Set the timeStamp value. If necessary it will be normalized.</dd>
<dt style="font-family: courier;">put(int64 milliseconds)</dt>
<dd>Set the timeStamp with a value the is the number of milliSeconds since
the epoch.</dd>
<dt style="font-family: courier;">getCurrent()</dt>
<dd>Set the timeStamp to the current time.</dd>
<dt style="font-family: courier;">toSeconds()</dt>
<dd>Convert the timeStamp to a value that is the number of seconds since
the epocj</dd>
<dt style="font-family: courier;">operator =</dt>
<dt style="font-family: courier;">operator!=</dt>
<dt style="font-family: courier;">operator&lt;=</dt>
<dt style="font-family: courier;">operator&lt;</dt>
<dt style="font-family: courier;">operator&gt;=</dt>
<dt style="font-family: courier;">operator&gt; </dt>
<dd>Standard C++ operators.</dd>
<dt style="font-family: courier;">diff</dt>
<dd>diff = a - b</dd>
<dt style="font-family: courier;">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 id="L2039">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(PVField *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 style="font-family: courier;">PVTimeStamp</dt>
<dd>The default constructor. Attach must be called before get or set can be
called.</dd>
<dt style="font-family: courier;">attach</dt>
<dd>Attempts to attach to <span
style="font-family: courier;">pvField</span> 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 style="font-family: courier;">detach</dt>
<dd>Detach from the pvData structure.</dd>
<dt style="font-family: courier;">isAttached</dt>
<dd>Is there an attachment to a timeStamp structure?</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">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 style="text-align: center" id="L2079">alarm</h3>
<p>An alarm structure is defined as follows:</p>
<pre>structure alarm
int32 severity
int32 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 <span style="font-family: courier;">alarm.h</span>
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: <span
style="font-family: courier;">alarm.h</span> and <span
style="font-family: courier;">pvAlarm.h</span> <span
style="font-family: courier;">alarm.h</span> defines a time stamp independent
of pvData, i.e. it is a generally useful class for manipulating alarms. <span
style="font-family: courier;">pvAlarm.h</span> is a class that can be attached
to a time stamp pvData structure. It provides get and set methods to get/set a
Alarm as defined by <span style="font-family: courier;">alarm.h</span></p>
<h4 id="L2106">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 StringArray getSeverityNames();
};
enum AlarmStatus {
noStatus,deviceStatus,driverStatus,recordStatus,
dbStatus,confStatus,undefinedStatus,clientStatus
};
class Alarm {
public:
Alarm();
//default constructors and destructor are OK
String getMessage();
void setMessage(String 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 style="font-family: courier;">getSeverity</dt>
<dd>Get the alarm severity corresponding to the integer value.</dd>
<dt style="font-family: courier;">getSeverityNames</dt>
<dd>Get the array of severity choices.</dd>
</dl>
<p>Alarm Status defines the possible choices for alarm status:</p>
<dl>
<dt><span
style="font-family: Courier New,Courier,monospace">getStatus</span></dt>
<dd>Get the alarm status corresponding to the integer value.</dd>
<dt><span
style="font-family: Courier New,Courier,monospace">getStatusNames</span></dt>
<dd>Get the array of status choices.</dd>
</dl>
<p>Alarm has the methods:</p>
<dl>
<dt style="font-family: courier;">Alarm</dt>
<dd>The constructor. It sets the severity to no alarm and the message to
"".</dd>
<dt style="font-family: courier;">getMessage</dt>
<dd>Get the message.</dd>
<dt style="font-family: courier;">setMessage</dt>
<dd>Set the message.</dd>
<dt style="font-family: courier;">getSeverity</dt>
<dd>Get the severity.</dd>
<dt style="font-family: courier;">setSeverity</dt>
<dd>Set the severity.</dd>
<dt><span
style="font-family: Courier New,Courier,monospace">getStatus</span></dt>
<dd>Get the status.</dd>
<dt><span
style="font-family: Courier New,Courier,monospace">setStatus</span></dt>
<dd>Set the status.</dd>
</dl>
<h4 id="L2178">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(PVField *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;) const;
bool set(Alarm const &amp; alarm);
};</pre>
<p>where</p>
<dl>
<dt style="font-family: courier;">PVAlarm</dt>
<dd>The default constructor. Attach must be called before get or set can be
called.</dd>
<dt style="font-family: courier;">attach</dt>
<dd>Attempts to attach to <span
style="font-family: courier;">pvField</span> 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 style="font-family: courier;">detach</dt>
<dd>Just detaches from the pvData structure.</dd>
<dt style="font-family: courier;">isAttached</dt>
<dd>Is there an attachment to an alarm structure?</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">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 style="text-align: center" id="L2218">control</h3>
<p>Control information is represented by the following structure</p>
<pre>structure control
structure limit
double low
double high</pre>
<p>Two header files are provided for manipulating controls: <span
style="font-family: courier;">control.h</span> and <span
style="font-family: courier;">pvControl.h</span> <span
style="font-family: courier;">control.h</span> defines a time stamp independent
of pvData, i.e. it is a generally useful class for manipulating controls. <span
style="font-family: courier;">pvControl.h</span> is a class that can be
attached to a time stamp pvData structure. It provides get and set methods to
get/set a Control as defined by <span
style="font-family: courier;">control.h</span></p>
<h4 id="L2240">control.h</h4>
<pre>class Control {
public:
Control();
//default constructors and destructor are OK
double getLow() const;
double getHigh() const;
void setLow(double value);
void setHigh(double value);
};</pre>
<p>where</p>
<dl>
<dt style="font-family: courier;">Control</dt>
<dd>The default constructure.</dd>
<dt style="font-family: courier;">getLow</dt>
<dd>Get the low limit.</dd>
<dt style="font-family: courier;">getHigh</dt>
<dd>Get the high limit.</dd>
<dt style="font-family: courier;">setLow</dt>
<dd>Set the low limit.</dd>
<dt style="font-family: courier;">setHigh</dt>
<dd>Set the high limit.</dd>
</dl>
<h4 id="L2272">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(PVField *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 style="font-family: courier;">PVControl</dt>
<dd>The default constructor. Attach must be called before get or set can be
called.</dd>
<dt style="font-family: courier;">attach</dt>
<dd>Attempts to attach to <span
style="font-family: courier;">pvField</span> 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 style="font-family: courier;">detach</dt>
<dd>Just detaches from the pvData structure.</dd>
<dt style="font-family: courier;">isAttached</dt>
<dd>Is there an attachment to a control structure?</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">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 style="text-align: center" id="L2312">display</h3>
<p>Display information is represented by the following structure</p>
<pre>structure display
structure limit
double low
double high
string description
string format
string units</pre>
<p>Two header files are provided for manipulating controls: <span
style="font-family: courier;">display.h</span> and <span
style="font-family: courier;">pvDisplay.h</span> <span
style="font-family: courier;">display.h</span> defines display information
independent of pvData, i.e. it is a generally useful class for manipulating
display infomation. <span style="font-family: courier;">pvDisplay.h</span> is a
class that can be attached to a display pvData structure. It provides get and
set methods to get/set a Diaplay as defined by <span
style="font-family: courier;">diaplay.h</span></p>
<h4 id="L2334">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 value);
String getFormat() const;
void setFormat(String value);
String getUnits() const;
void setUnits(String value);
};</pre>
<p>where</p>
<dl>
<dt style="font-family: courier;">Control</dt>
<dd>The default constructure.</dd>
<dt style="font-family: courier;">getLow</dt>
<dd>Get the low limit.</dd>
<dt style="font-family: courier;">getHigh</dt>
<dd>Get the high limit.</dd>
<dt style="font-family: courier;">setLow</dt>
<dd>Set the low limit.</dd>
<dt style="font-family: courier;">setHigh</dt>
<dd>Set the high limit.</dd>
<dt style="font-family: courier;">getDescription</dt>
<dd>Get the description.</dd>
<dt style="font-family: courier;">setDescription</dt>
<dd>Set the description.</dd>
<dt style="font-family: courier;">getFormat</dt>
<dd>Get the format.</dd>
<dt style="font-family: courier;">setFormat</dt>
<dd>Set the format.</dd>
<dt style="font-family: courier;">getUnits</dt>
<dd>Get the units.</dd>
<dt style="font-family: courier;">setUnits</dt>
<dd>Set the units.</dd>
</dl>
<h4 id="L2396">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(PVField *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 style="font-family: courier;">PVDisplay</dt>
<dd>The default constructor. Attach must be called before get or set can be
called.</dd>
<dt style="font-family: courier;">attach</dt>
<dd>Attempts to attach to <span
style="font-family: courier;">pvField</span> 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 style="font-family: courier;">detach</dt>
<dd>Just detaches from the pvData structure.</dd>
<dt style="font-family: courier;">isAttached</dt>
<dd>Is there an attachment to a display structure?</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">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 style="text-align: center" id="L2436">pvEnumerated</h3>
<p>An enumerated structure is a structure that has fields:</p>
<pre>structure
int32 index
string[] choices</pre>
<p>For enumerated structures a single header file <span
style="font-family: courier;">pvEnumerted.h</span> 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(PVField *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();
StringArray getChoices();
int32 getNumberChoices();
bool setChoices(StringArray choices,int32 numberChoices);
};</pre>
<p>where</p>
<dl>
<dt style="font-family: courier;">PVEnumerated</dt>
<dd>The default constructor. Attach must be called before any get or set
method can be called.</dd>
<dt style="font-family: courier;">attach</dt>
<dd>Attempts to attach to <span
style="font-family: courier;">pvField</span> It returns (false,true) if
pvField (is not, is) an enumerated structure.</dd>
<dt style="font-family: courier;">detach</dt>
<dd>Just detaches from the pvData structure.</dd>
<dt style="font-family: courier;">isAttached</dt>
<dd>Is there an attachment to an enemerated structure?</dd>
<dt style="font-family: courier;">setIndex</dt>
<dd>Set the index field in the pvData structure. An exception is thrown if
not attached to a pvData structure. </dd>
<dt style="font-family: courier;">getIndex</dt>
<dd>Get the index field in the pvData structure. </dd>
<dt style="font-family: courier;">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 style="font-family: courier;">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 style="font-family: courier;">getChoices</dt>
<dd>Get the array of choices. An exception is thrown if not attached to a
pvData structure. </dd>
<dt style="font-family: courier;">getNumberChoices</dt>
<dd>Get the number of choices. An exception is thrown if not attached to a
pvData structure. </dd>
<dt style="font-family: courier;">setChoices</dt>
<dd>Change the choices. An exception is thrown if not attached to a pvData
structure. </dd>
</dl>
<hr />
<h2 style="text-align: center" id="L2512">PVData Factories</h2>
<hr />
<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>PVAuxInfoImpl.cpp implements auxInfo.</p>
<p>Convert.cpp automatically creates a single instance of Convert and
implements getConvert.</p>
<p>Other files implement PVData base classes</p>
<hr />
<h2 style="text-align: center" id="L2532">Miscellanous Classes</h2>
<hr />
<h3 style="text-align: center" id="L2536">Overview</h3>
<p>This package provides utility code:</p>
<dl>
<dt style="font-family: courier;">bitSet.h</dt>
<dd>An implementation of BitSet that can be serialized.</dd>
<dt style="font-family: courier;">byteBuffer.h</dt>
<dd>Used to serialize objects.</dd>
<dt style="font-family: courier;">event.h</dt>
<dd>Signal and wait for an event.</dd>
<dt style="font-family: courier;">exception.h</dt>
<dd>Exception with stack trace.</dd>
<dt style="font-family: courier;">executor.h</dt>
<dd>Provides a thread for executing commands.</dd>
<dt style="font-family: courier;">linkedList.h</dt>
<dd>A double linked list facility that requires the user to allocate a
node. It is more efficient that std::list and does not require the
implementation to allocate storage for the nodes.</dd>
<dt style="font-family: courier;">lock.h</dt>
<dd>Support for locking and unlocking.</dd>
<dt style="font-family: courier;">messageQueue.h</dt>
<dd>Support for queuing messages to give to requesters.</dd>
<dt style="font-family: courier;">noDefaultMethods.h</dt>
<dd>When privately extended prevents compiler from implementing default
methods.</dd>
<dt style="font-family: courier;">requester.h</dt>
<dd>Allows messages to be sent to a requester.</dd>
<dt style="font-family: courier;">serialize.h</dt>
<dd>Support for serializing objects.</dd>
<dt style="font-family: courier;">CDRMonitor.h</dt>
<dd>Provides support monitoring memory usage for objects of a class.</dd>
<dt style="font-family: courier;">status.h</dt>
<dd>A way to pass status information to a client.</dd>
<dt style="font-family: courier;">thread.h</dt>
<dd>Provides thread support.</dd>
<dt style="font-family: courier;">timeFunction.h</dt>
<dd>Time how long a function call requires.</dd>
<dt style="font-family: courier;">timer.h</dt>
<dd>An implementation of Timer that does not require an object to be
created for each timer request.</dd>
<dt style="font-family: courier;">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>
</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 style="text-align: center;" id="L2628">BitSet</h3>
<p>This is adapted from the java.util.BitSet. bitSet.h is:</p>
<pre>class BitSet /*: public Serializable*/ {
public:
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;
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);
void toString(StringBuilder buffer, int indentLevel) const;
private:
};</pre>
<p>where</p>
<dl>
<dt style="font-family: courier;">BitSet()</dt>
<dd>Creates a bitSet of initial size 64 bits. All bits initially false.</dd>
<dt style="font-family: courier;">BitSet(uint32 nbits)</dt>
<dd>Creates a bitSet with the initial of the specified number of bits. All
bits initially false.</dd>
<dt style="font-family: courier;">~BitSet()</dt>
<dd>Destructor.</dd>
<dt style="font-family: courier;">flip(uint32 bitIndex)</dt>
<dd>Flip the specified bit.</dd>
<dt style="font-family: courier;">set(uint32 bitIndex)</dt>
<dd>Set the specified bit true.</dd>
<dt style="font-family: courier;">clear(uint32 bitIndex)</dt>
<dd>Set the specified bit false.</dd>
<dt style="font-family: courier;">set(uint32 bitIndex, bool value)</dt>
<dd>Set the specified bit to value.</dd>
<dt style="font-family: courier;">get(uint32 bitIndex)</dt>
<dd>Return the state of the specified bit.</dd>
<dt style="font-family: courier;">clear()</dt>
<dd>Set all bits to false.</dd>
<dt style="font-family: courier;">nextSetBit(uint32 fromIndex)</dt>
<dd>Get the index of the next true bit beginning with the specified
bit.</dd>
<dt style="font-family: courier;">nextClearBit(uint32 fromIndex)</dt>
<dd>Get the index of the next false bit beginning with the specified
bit.</dd>
<dt style="font-family: courier;">isEmpty()</dt>
<dd>Return (false,true) if (at least one bit true, all bits are false)</dd>
<dt style="font-family: courier;">cardinality()</dt>
<dd>Return the number of true bits.</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">operator|=(const BitSet&amp; set)</dt>
<dd>Performs a logical or of this target bit set with the argument bit
set.</dd>
<dt style="font-family: courier;">operator^=(const BitSet&amp; set)</dt>
<dd>Performs a logical exclusive or of this target bit set with the
argument bit set.</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">operator=(const BitSet &amp;set)</dt>
<dd>Assignment operator.</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">operator==(const BitSet &amp;set)</dt>
<dd>Does this bitSet have the same values as the argument.</dd>
<dt style="font-family: courier;">operator!=(const BitSet &amp;set)</dt>
<dd>Is this bitSet different than the argument.</dd>
<dt style="font-family: courier;">toString(StringBuilder buffer)</dt>
<dd>Show the current values of the bitSet.</dd>
<dt style="font-family: courier;">toString(StringBuilder buffer, int
indentLevel)</dt>
<dd>Show the current values of the bitSet.</dd>
</dl>
<h3 style="text-align: center;" id="L2752">ByteBuffer</h3>
<p>A ByteBuffer is used to serialize and deserialize primitive data. File
byteBuffer.h is:</p>
<pre>class ByteBuffer {
public:
ByteBuffer(int size = 32, int byteOrder = EPICS_BYTE_ORDER);
~ByteBuffer();
ByteBuffer* clear();
ByteBuffer* flip();
ByteBuffer* rewind();
bool getBoolean();
int8 getByte();
int16 getShort();
int32 getInt();
int64 getLong();
float getFloat();
double getDouble();
void get(char* dst, int offset, int count);
ByteBuffer* put(const char* src, int offset, int count);
ByteBuffer* putBoolean(bool value);
ByteBuffer* putByte(int8 value);
ByteBuffer* putShort(int16 value);
ByteBuffer* putInt(int32 value);
ByteBuffer* putLong(int64 value);
ByteBuffer* putFloat(float value);
ByteBuffer* putDouble(double value);
inline int getSize() const;
inline int getArrayOffset() const;
inline int getPosition() const;
inline int getLimit() const;
inline int getRemaining() const;
inline int getByteOrder() const;
inline const char* getArray() const;
// TODO must define arrays
private:
};</pre>
<p>x</p>
<h3 style="text-align: center;" id="L2760">Event</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 : private NoDefaultMethods {
public:
Event(bool full);
~Event();
void signal();
bool wait (); /* blocks until full */
bool wait ( double timeOut ); /* false if empty at time out */
bool tryWait (); /* false if empty */
private:
epicsEventId id;
};</pre>
<p>where</p>
<dl>
<dt style="font-family: courier;">Event</dt>
<dd>The constructor. The initial value can be full or empty. The normal
first state is empty.</dd>
<dt style="font-family: courier;">signal</dt>
<dd>The event becomes full. The current or next wait will complete.</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">tryWait</dt>
<dd>returns (false,true) if the event is (empty,full)</dd>
</dl>
<h3 style="text-align: center;" id="L2789">Exception</h3>
<p>File epicsException.h describes:</p>
<pre>class BaseException : public std::exception {
public:
BaseException(const char* message, const char* file,
int line, std::exception* cause = 0);
virtual ~BaseException();
virtual const char* what();
void toString(std::string&amp; str, unsigned int depth = 0);
static inline void getStackTrace(
std::string* trace, unsigned int skip_frames = 0, unsigned int max_frames = 63)
private:
// ...
}</pre>
<p>x</p>
<h3 style="text-align: center;" id="L2797">Executor</h3>
<p>An Executor is a thread that can execute commands. The user can request that
a single command be executed.</p>
<pre>class ExecutorNode;
class Command {
public:
virtual void command() = 0;
};
class Executor : private NoDefaultMethods {
public:
Executor(String threadName,ThreadPriority priority);
~Executor();
ExecutorNode * createNode(Command *command);
void execute(ExecutorNode *node);
private:
class ExecutorPvt *pImpl;
};</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 style="font-family: courier;">Executor</dt>
<dd>The constructor. A thread name and priority must be specified.</dd>
<dt style="font-family: courier;">~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 style="font-family: courier;">createNode</dt>
<dd>Create a ExecutorNode that can be passed to execute.</dd>
<dt style="font-family: courier;">execute</dt>
<dd>Request that command be executed. If it is already on the run list
nothing is done.</dd>
</dl>
<h3 style="text-align: center;" id="L2828">Linked List</h3>
<p>LinkedList implements a double linked list that requires a user to allocate
the nodes. It is more efficent that std::list. linkedList.h is a template that
is both a complete description and definition. It uses linkedListVoid for
method definitions. linkedListVoid is not meant for use except via
linkedList.</p>
<p>A node can only be on one list at a time but can be put, at different times,
on different lists as long as they all hold the same type of objects. An
exception is thrown if an attempt is made to put a node on a list if the node
is already on a list. </p>
<pre>template &lt;typename T&gt;
class LinkedList;
template &lt;typename T&gt;
class LinkedListNode : private LinkedListVoidNode {
public:
LinkedListNode(T &amp;object) : LinkedListVoidNode(&amp;object){}
~LinkedListNode() {}
T &amp;getObject() { return *static_cast&lt;T *&gt;(LinkedListVoidNode::getObject());}
bool isOnList() {return LinkedListVoidNode::isOnList();}
friend class LinkedList&lt;T&gt;;
};
template &lt;typename T&gt;
class LinkedList : private LinkedListVoid {
public:
LinkedList() : LinkedListVoid() {}
~LinkedList() {}
int getLength();
void addTail(LinkedListNode&lt;T&gt; &amp;listNode);
void addHead(LinkedListNode&lt;T&gt; &amp;listNode);
void insertAfter(LinkedListNode&lt;T&gt; &amp;listNode,LinkedListNode&lt;T&gt; &amp;addNode);
void insertBefore(LinkedListNode&lt;T&gt; &amp;listNode,LinkedListNode&lt;T&gt; &amp;addNode);
LinkedListNode&lt;T&gt; *removeTail();
LinkedListNode&lt;T&gt; *removeHead();
void remove(LinkedListNode&lt;T&gt; &amp;listNode);
LinkedListNode&lt;T&gt; *getHead();
LinkedListNode&lt;T&gt; *getTail();
LinkedListNode&lt;T&gt; *getNext(LinkedListNode&lt;T&gt; &amp;listNode);
LinkedListNode&lt;T&gt; *getPrev(LinkedListNode&lt;T&gt; &amp;listNode);
bool isEmpty();
};</pre>
<p>LinkedListNode has the methods:</p>
<dl>
<dt style="font-family: courier;">LinkedListNode</dt>
<dd>The constructor. The object must be specified.</dd>
<dt style="font-family: courier;">~LinkedListNode</dt>
<dd>The destructor.</dd>
<dt style="font-family: courier;">getObject</dt>
<dd>Returns the nobject.</dd>
<dt style="font-family: courier;">isOnList</dt>
<dd>returns (false,true) if the node (is not, is) on a list.</dd>
</dl>
<p>LinkedList has the methods:</p>
<dl>
<dt style="font-family: courier;">LinkedList</dt>
<dd>The constructor.</dd>
<dt style="font-family: courier;">~LinkedList</dt>
<dd>The destructor.</dd>
<dt style="font-family: courier;">getLength</dt>
<dd>Get the numbet of nodes currently on the list.</dd>
<dt style="font-family: courier;">addTail</dt>
<dd>Add a node to the end of the list. An exception is thrown if the node
is already on a list.</dd>
<dt style="font-family: courier;">addHead</dt>
<dd>Add a node to the beginning of the list. An exception is thrown if the
node is already on a list.</dd>
<dt style="font-family: courier;">insertAfter</dt>
<dd>Insert addNode after node. An exception is thrown if the addNode is
already on a list or if node is not on this list..</dd>
<dt style="font-family: courier;">insertBefore</dt>
<dd>Insert addNode before node. An exception is thrown if the addNode is
already on a list or if node is not on this list.</dd>
<dt style="font-family: courier;">removeTail</dt>
<dd>Remove and return the last node. Null is returned if the list is
empty.</dd>
<dt style="font-family: courier;">removeHead</dt>
<dd>Remove and return the first node. Null is returned if the list is
empty.</dd>
<dt style="font-family: courier;">remove</dt>
<dd>Remove the specified node or object. An exception is thrown if the node
is not on a list.</dd>
<dt style="font-family: courier;">getHead</dt>
<dd>Get the first list node. Null is returned if the list is empty.</dd>
<dt style="font-family: courier;">getTail</dt>
<dd>Get the last list node. Null is returned if the list is empty.</dd>
<dt style="font-family: courier;">getNext</dt>
<dd>Get the node after node. An exception is thrown if node is not on this
list. Null is returned if the is node is the last node on the list.</dd>
<dt style="font-family: courier;">getPrev</dt>
<dd>Get the node before node. An exception is thrown if node is not on this
list. Null is returned if the is node is the first node on the list.</dd>
<dt style="font-family: courier;">isEmpty</dt>
<dd>Is the list empty.</dd>
<dt style="font-family: courier;">contains</dt>
<dd>Does the list contain the specified object?</dd>
</dl>
<h3 style="text-align: center;" id="L2942">Lock and Mutex</h3>
<p>lock.h is:</p>
<pre>class Mutex {
public:
Mutex();
~Mutex();
void lock();
void unlock();
};
class Lock : private NoDefaultMethods {
public:
explicit Lock(Mutex &amp;pm);
~Lock();
void lock();
void unlock();
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 xx(mutex);
if(alreadyInitialized) return;
// initialization
}</pre>
<h3 style="text-align: center;" id="L2958">Message Queue</h3>
<h4 id="L2960">Definitions</h4>
<pre>class MessageNode {
public:
String getMessage() const;
MessageType getMessageType() const;
void setMessageNull();
};
class MessageQueue : private NoDefaultMethods {
public:
MessageQueue(int size);
~MessageQueue();
MessageNode *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() const;
bool isFull() const;
int getClearOverrun();
};</pre>
<h4 id="L2964">MessageQueue</h4>
<p>This is for use by code that wants to handle messages without blocking
higher priority threads.</p>
<p>A messageNode is a class with two public data members:</p>
<dl>
<dt style="font-family: courier;">getMessage</dt>
<dd>The message.</dd>
<dt style="font-family: courier;">getMessageType</dt>
<dd>The message type.</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">MessageQueue</dt>
<dd>The constructor. The queue size must be specified.</dd>
<dt style="font-family: courier;">~MessageQueue</dt>
<dd>The destructor.</dd>
<dt style="font-family: courier;">put</dt>
<dd>Put a new message into the queue. False is returned if the queue was
full and true otherwise. If <span
style="font-family: courier;">replaceLast</span> is <span
style="font-family: courier;">true</span> then the last message is
replaced with this message. </dd>
<dt style="font-family: courier;">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 style="font-family: courier;">release</dt>
<dd>Release the queue element returned by the last get.</dd>
<dt style="font-family: courier;">isEmpty</dt>
<dd>Is the queue empty?</dd>
<dt style="font-family: courier;">isFull</dt>
<dd>Is the queue full?</dd>
<dt style="font-family: courier;">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 style="text-align: center;" id="L3037">NoDefaultMethods</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 style="text-align: center;" id="L3043">Requester</h3>
<p>A PVField extends Requester. Requester is present so that when database
errors are found there is someplace to send a message.</p>
<pre>enum MessageType {
infoMessage,warningMessage,errorMessage,fatalErrorMessage
};
extern StringArray messageTypeName;
class Requester {
public:
virtual String getRequesterName() = 0;
virtual void message(String message,MessageType messageType) = 0;
};</pre>
<p>where</p>
<dl>
<dt style="font-family: courier;"></dt>
<dt style="font-family: courier;">MessageType</dt>
<dd>Type of message.</dd>
<dt style="font-family: courier;">messageTypeName</dt>
<dd>An array of strings of the message type names, i.e.
String("info"),String("warning"),String("error"),String("fatalError").</dd>
<dt style="font-family: courier;">getRequesterName</dt>
<dd>Returns the requester name.</dd>
<dt style="font-family: courier;">message</dt>
<dd>Gives a message to the requester.</dd>
</dl>
<h3 style="text-align: center" id="L3074">Serialize</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);
private:
};
class SerializableControl {
public:
virtual void flushSerializeBuffer() =0;
virtual void ensureBuffer(int size) =0;
};
class DeserializableControl {
public:
virtual void ensureData(int size) =0;
};
class Serializable {
public:
virtual void serialize(ByteBuffer *buffer,
SerializableControl *flusher) = 0;
virtual void deserialize(ByteBuffer *buffer,
DeserializableControl *flusher) = 0;
};
class BitSetSerializable {
public:
virtual void serialize(ByteBuffer *buffer,
SerializableControl *flusher,BitSet *bitSet) = 0;
virtual void deserialize(ByteBuffer *buffer,
DeserializableControl *flusher,BitSet *bitSet) = 0;
};
class SerializableArray : public Serializable {
public:
virtual void serialize(ByteBuffer *buffer,
SerializableControl *flusher, int offset, int count) = 0;
};</pre>
<p>where</p>
<dl>
<dt style="font-family: courier;">writeSize</dt>
<dd>Serialize the size.</dd>
<dt style="font-family: courier;">readSize</dt>
<dd>Deserialize the size.</dd>
<dt style="font-family: courier;">serializeString</dt>
<dd>Serialize a String.</dd>
<dt style="font-family: courier;">serializeSubstring</dt>
<dd>Serialize a substring.</dd>
<dt style="font-family: courier;">deserializeString</dt>
<dd>Deserialize a string.</dd>
</dl>
<p>The following interfaces are called by pvAccess for transporting data over
the network. The abstract and base classes ensure that these methods are
properly implemented. </p>
<pre>x</pre>
<p>x</p>
<h3 style="text-align: center;" id="L3114">CDRMonitor - Monitor and Report
Construction and Destruction</h3>
<p>This is a facility that allows a class to report how many objects of that
class have been created and destroyed. This can help find memory leaks.</p>
<pre>struct CDRCount {
size_t cons, dtys;
long refs;
};
class CDRMonitor : private NoDefaultMethods {
public:
static CDRMonitor&amp; get();
CDRNode* addNode(CDRNode&amp; next);
CDRCount current();
CDRNode* first();
CDRNode* first();
void show(FILE*)
void show(std::ostream&amp;) const;
};
class CDRNode : private NoDefaultMethods {
public:
CDRNode(const String&amp; name);
void construct();
void destruct(){Lock x(guard);
void incRef();
void decRef();
CDRNode* next();
CDRCount get();
void show(FILE*);
void show(std::ostream&amp;);
};
static inline CDRNode* getNode(CDRNodeInstance *inst);</pre>
<h3 style="text-align: center" id="L3120">Status</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 message);
Status(StatusType type, epics::pvData::String 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 style="font-family: courier;">StatusType</dt>
<dd>An enum for the status type.</dd>
<dt style="font-family: courier;">getType</dt>
<dd>Get the statusType.</dd>
<dt style="font-family: courier;">getMessage</dt>
<dd>Get a message explaining the error.</dd>
<dt style="font-family: courier;">getStackDump</dt>
<dd>Get a stack dump.</dd>
</dl>
<p>The StatusCreate methods are:</p>
<dl>
<dt style="font-family: courier;">getStatusOK</dt>
<dd>Get a singleton that returns StatusType.OK and a null message and
stackDump.</dd>
<dt style="font-family: courier;">createStatus</dt>
<dd>Create a new Status.</dd>
<dt style="font-family: courier;">deserializeStatus</dt>
<dd>Use this method instead of Status.deserialize(), since this allows OK
status optimization.</dd>
</dl>
<h3 style="text-align: center;" id="L3167">Thread</h3>
<h4 id="L3169">ThreadPriority</h4>
<pre>enum ThreadPriority {
lowestPriority,
lowerPriority,
lowPriority,
middlePriority,
highPriority,
higherPriority,
highestPriority
};
class ThreadPriorityFunc {
public:
static unsigned int const * const getEpicsPriorities();
static int getEpicsPriority(ThreadPriority threadPriority);
};</pre>
<h4 id="L3173">Thread</h4>
<pre>class Runnable {
public:
virtual void run() = 0;
};
class Thread;
class Thread : private NoDefaultMethods {
public:
Thread(String name,ThreadPriority priority,Runnable *runnableReady);
~Thread();
String getName();
ThreadPriority getPriority();
static void showThreads(StringBuilder buf);
static void sleep(double seconds);
private:
};</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 style="font-family: courier;">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 style="font-family: courier;">~Thread</dt>
<dd>The destructor. This is called as the result of:
<pre> delete pthread;</pre>
</dd>
<dt style="font-family: courier;">getName</dt>
<dd>Get the thread name.</dd>
<dt style="font-family: courier;">getPriority</dt>
<dd>Get the thread priority.</dd>
<dt style="font-family: courier;">showThreads</dt>
<dd>Get a String that has the name and priority of all currently allocated
threads.</dd>
<dt style="font-family: courier;">sleep</dt>
<dd>Make the current thread sleep for the specified number of seconds.</dd>
</dl>
<h3 style="text-align: center;" id="L3214">Time Function Call</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 {
public:
virtual void function() = 0;
};
class TimeFunction : private NoDefaultMethods {
public:
TimeFunction(TimeFunctionRequester *requester);
~TimeFunction();
double timeCall();
private:
TimeFunctionRequester *requester;
};</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 style="font-family: courier;">function</dt>
<dd>This is the function.</dd>
</dl>
<p>TimeFunction has the methods:</p>
<dl>
<dt style="font-family: courier;">TimeFunction</dt>
<dd>Constructor.</dd>
<dt style="font-family: courier;">~TimeFunction</dt>
<dd>Destructor.</dd>
<dt style="font-family: courier;">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 style="text-align: center;" id="L3246">Timer</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 {
public:
virtual void callback() = 0;
virtual void timerStopped() = 0;
};
class TimerNode : private NoDefaultMethods {
public:
TimerNode(TimerCallback *timerCallback);
~TimerNode();
void cancel();
bool isScheduled();
private:
};
class Timer : private NoDefaultMethods {
public:
Timer(String threadName, ThreadPriority priority);
~Timer();
void scheduleAfterDelay(TimerNode &amp;timerNode,double delay);
void schedulePeriodic(TimerNode &amp;timerNode,double delay,double period);
private:
};</pre>
<p>TimerCallback must be implemented by the user. It has the following methods:
</p>
<dl>
<dt style="font-family: courier;">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 style="font-family: courier;">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 style="font-family: courier;">TimerNode</dt>
<dd>The constructor. User code must create a TimeNode in order to call a
schedule method.</dd>
<dt style="font-family: courier;">~TimerNode</dt>
<dd>The destructor. This is called as a result of the client calling:
<pre> delete timerNode;</pre>
</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">isScheduled</dt>
<dd>Is the timerNode scheduled to be called.</dd>
</dl>
<p>Timer has the methods:</p>
<dl>
<dt style="font-family: courier;">Timer</dt>
<dd>The consttructor.</dd>
<dt style="font-family: courier;">~Timer</dt>
<dd>The destructor. The queue is emptied and TimerCallback.timerStopped is
called for each element of the queue.</dd>
<dt style="font-family: courier;">scheduleAfterDelay</dt>
<dd>A request to schedule a callback after a delay specified in
seconds.</dd>
<dt style="font-family: courier;">schedulePeriodic</dt>
<dd>Schedule a periodic callback.</dd>
</dl>
<h3 style="text-align: center;" id="L3313">Queue</h3>
<p>This provides a queue which has an immutable capacity. 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 QueueElement : private QueueElementVoid {
public:
T *getObject() { return static_cast&lt;T *&gt;(QueueElementVoid::getObject());}
protected:
};
template &lt;typename T&gt;
class Queue : private QueueVoid {
public:
Queue(T *array[],int number);
~Queue();
void clear();
int getNumberFree();
int capacity();
QueueElement&lt;T&gt; *getFree();
void setUsed(QueueElement&lt;T&gt; *queueElement);
QueueElement&lt;T&gt; *getUsed();
void releaseUsed(QueueElement&lt;T&gt; *queueElement);
};</pre>
<p>miscTest/queueTest.cpp provides an example of how to define a queue.</p>
<p>The queue methods are:</p>
<dl>
<dt style="font-family: courier;">clear</dt>
<dd>Make the queue empty.</dd>
<dt style="font-family: courier;">getNumberFree</dt>
<dd>Get the number of free elements in the queue.</dd>
<dt style="font-family: courier;">capacity</dt>
<dd>Get the capacity, i.e. the maximun number of elements the queue can
hold.</dd>
<dt style="font-family: courier;">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 style="font-family: courier;">setUsed</dt>
<dd>Set a queue element used. This <span
style="font-weight:bold;">must</span> be the element returned by the last
call to getFree. </dd>
<dt style="font-family: courier;">getUsed</dt>
<dd>Get the next used element of null if no more used elements are
available.</dd>
<dt style="font-family: courier;">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>
<hr />
<h2 style="text-align: center" id="L3376">pvMisc</h2>
<hr />
<h3 id="L3380">BitSetUtil</h3>
<p>The following is also provided:</p>
<pre>class BitSetUtil : private NoDefaultMethods {
public:
static bool compress(BitSet *bitSet,PVStructure *pvStructure);
};</pre>
<p>This provides functions that operate on a BitSet for a PVStructure. It
currently has only one method:</p>
<dl>
<dt style="font-family: courier;"><span
style="font-family: Courier">compress</span></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>
<h3 style="text-align: center;" id="L3410">MultiChoice</h3>
<p>MultiChoice defines an array of strings and a bit set that selects an
arbitrary set of the choices. This will be implemented if the java version is
accepted.</p>
<pre>NOT DONE</pre>
</body>
</html>