EPICS pvDataCPP

Release 5.1-DEV - 2016.03.18

Editors:
Marty Kraimer, BNL
Michael Davidsaver, BNL
Matej Sekoranja, CosyLab
David Hickin, Diamond Light Source

Abstract

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

Status of this Document

This is the 18-March-2016 version for the 5.1-development release of the C++ implementation of pvData.

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

Table of Contents

Introduction

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

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

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

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

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

Doxygen documentation is available at doxygenDoc

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

This document discusses the following:

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

Examples

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

The documentation directory for this project has a file examples.zip. It has the code for the examples. After it is unzipped:

cd examples/configure
cp ExampleRELEASE.local RELEASE.local
#edit RELEASE.local
cd ..
make
Now you are ready to run the examples:
bin/linux-x86_64/introspectMain 
bin/linux-x86_64/dataMain

The examples assume that the following statements have been issued:

using std::cout;
using std::endl;
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
StandardFieldPtr standardField = getStandardField();
StandardPVFieldPtr standardPVField = getStandardPVField();

These provide access to most of pvData:

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

Introspection Examples

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

Three ways to create a structure

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

    size_t n = 3;
    StringArray names;
    names.reserve(n);
    FieldConstPtrArray fields;
    fields.reserve(n);
    names.push_back("secondsPastEpoch");
    fields.push_back(fieldCreate->createScalar(pvLong));
    names.push_back("nanoseconds");
    fields.push_back(fieldCreate->createScalar(pvInt));
    names.push_back("userTag");
    fields.push_back(fieldCreate->createScalar(pvInt));
    StructureConstPtr timeStamp = fieldCreate->createStructure(names,fields);
    size_t ntop = 2;
    StringArray topnames;
    topnames.reserve(ntop);
    FieldConstPtrArray topfields;
    topfields.reserve(ntop);
    topnames.push_back("value");
    topfields.push_back(fieldCreate->createScalar(pvDouble));
    topnames.push_back("timeStamp");
    topfields.push_back(timeStamp);
    StructureConstPtr doubleScalar =
        fieldCreate->createStructure(topnames,topfields);
    cout << *doubleScalar << endl;

Using FieldBuilder the same can be done via:

    StructureConstPtr doubleScalarHard =
    getFieldCreate()->createFieldBuilder()->
        add("value",pvDouble) ->
        addNestedStructure("timeStamp")->
            setId("time_t")->
            add("secondsPastEpoch", pvLong)->
            add("nanoseconds", pvInt)->
            add("userTag", pvInt)->
            endNested()->
        createStructure();
    cout << *doubleScalarHard << endl;

The easiest way to produce the structure is:

    StructureConstPtr stringArrayEasy =
         getStandardField()->scalarArray(pvString,"alarm,timeStamp");
    cout << *stringArrayEasy << "\n\n";
These three ways produce:
hardest way
structure
    double value
    structure timeStamp
        long secsPastEpoch
        int nanoseconds
        int userTag

hard way
structure
    double value
    time_t timeStamp
        long secsPastEpoch
        int nanoseconds
        int userTag

easy way
epics:nt/NTScalarArray:1.0
    string[] value
    alarm_t alarm
        int severity
        int status
        string message
    time_t timeStamp
        long secondsPastEpoch
        int nanoseconds
        int userTag

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

    StructureConstPtr stringArrayEasy =
        standardField->scalarArray(pvString,"alarm,timeStamp");
    cout << *stringArrayEasy << endl;
It produces :
epics:nt/NTScalarArray:1.0
    string[] value
    alarm_t alarm
        int severity
        int status
        string message
    time_t timeStamp
        long secondsPastEpoch
        int nanoseconds
        int userTag
0x607188

enumerated structure

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

    StructureConstPtr enum_t =
    fieldCreate->createFieldBuilder()->
        setId("enum_t")->
        add("index", pvInt)->
        addArray("choices", pvString)->
        createStructure();

    StructureConstPtr ntEnumHard =
    fieldCreate->createFieldBuilder()->
        setId("epics:nt/NTEnum:1.0")->
        add("value", enum_t)->
        addNestedStructure("timeStamp")->
            setId("time_t")->
            add("secondsPastEpoch", pvLong)->
            add("nanoseconds", pvInt)->
            add("userTag", pvInt)->
            endNested()->
        createStructure();
    cout << *ntEnumHard << endl;
It produces:
epics:nt/NTEnum:1.0
    enum_t value
        int index
        string[] choices
    time_t timeStamp
        long secondsPastEpoch
        int nanoseconds
        int userTag

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

    StructureConstPtr ntEnumEasy = getStandardField()->enumerated("alarm,timeStamp");
    cout << *ntEnumEasy << endl;
It produces:
epics:nt/NTEnum
    enum_t value
        int index
        string[] choices
    alarm_t alarm
        int severity
        int status
        string message
    time_t timeStamp
        long secondsPastEpoch
        int nanoseconds
        int userTag

union example

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

    UnionConstPtr ntunion =
    fieldCreate->createFieldBuilder()->
        add("doubleValue", pvDouble)->
        add("intValue", pvInt)->
        add("timeStamp",standardField->timeStamp())->
        createUnion();
    cout << *ntunion << endl;

    StructureConstPtr unionValue = standardField->regUnion(punion,"alarm,timeStamp");
    cout << *unionValue << endl;
It produces:
union
    double doubleValue
    int intValue
    time_t timeStamp
        long secondsPastEpoch
        int nanoseconds
        int userTag

structure with value field being a union
epics:nt/NTUnion:1.0
    union value
        double doubleValue
        int intValue
        time_t timeStamp
            long secondsPastEpoch
            int nanoseconds
            int userTag
    alarm_t alarm
        int severity
        int status
        string message
    time_t timeStamp
        long secondsPastEpoch
        int nanoseconds
        int userTag

union array example

The following:

    UnionArrayConstPtr unionArray = fieldCreate->createUnionArray(
        fieldCreate->createVariantUnion());
    cout << *unionArray << "\n\n";

Produces

any[]
any
0x607188

power supply

The following creates a more complex structure:

    StructureConstPtr powerSupply =
    fieldCreate->createFieldBuilder()->
        add("alarm",standardField->alarm()) ->
        add("timestamp",standardField->timeStamp()) ->
        addNestedStructure("power") ->
           add("value",pvDouble) ->
           add("alarm",standardField->alarm()) ->
           endNested()->
        addNestedStructure("voltage") ->
           add("value",pvDouble) ->
           add("alarm",standardField->alarm()) ->
           endNested()->
        addNestedStructure("current") ->
           add("value",pvDouble) ->
           add("alarm",standardField->alarm()) ->
           endNested()->
        createStructure();
    std::cout << *powerSupply <<std::endl;
It produces:
structure
    alarm_t alarm
        int severity
        int status
        string message
    time_t timestamp
        long secondsPastEpoch
        int nanoseconds
        int userTag
    structure power
        double value
        alarm_t alarm
            int severity
            int status
            string message
    structure voltage
        double value
        alarm_t alarm
            int severity
            int status
            string message
    structure current
        double value
        alarm_t alarm
            int severity
            int status
            string message

Data Examples

The examples all produce a top level structure.

scalar example

    PVStructurePtr doubleValue = getPVDataCreate()->createPVStructure(
        getStandardField()->scalar(pvDouble,"alarm,timeStamp"));
    PVDoublePtr pvdouble =
        doubleValue->getSubField<PVDouble>("value");
    pvdouble->put(1e5);
    cout << *doubleValue << endl;
    double value = doubleValue->getSubField<PVDouble>("value")->get();
    cout << "from get " << value << "\n\n";
This produces:
epics:nt/NTScalar:1.0
    double value 100000
    alarm_t alarm
        int severity 0
        int status 0
        string message 
    time_t timeStamp
        long secondsPastEpoch 0
        int nanoseconds 0
        int userTag 0
0x607268
from get 100000

array example

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

enumerated example

    PVStructurePtr pvntenum = pvDataCreate->createPVStructure(
         standardField->enumerated("alarm,timeStamp"));
    cout << *pvntenum << "\n\n";
This produces:
epics:nt/NTEnum:1.0
    enum_t value
        int index 0
        string[] choices []
    alarm_t alarm
        int severity 0
        int status 0
        string message 
    time_t timeStamp
        long secondsPastEpoch 0
        int nanoseconds 0
        int userTag 0
0x607268

power supply example

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

union example

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

variant union example

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

big union example

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

Namespace and Memory Management

Namespace

All code in project pvDataCPP appears in namespace:

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

Memory Management

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

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

For example:

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

src/pv

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

NOTES:

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

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

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

Directory src/pv has the following header files:

pvType.h
C++ definitions for primitive types.
pvIntrospect.h
A complete description of the introspection interfaces.
pvData.h
A complete description of the data interfaces.
convert.h
A facility that converts between data fields.
pvSubArrayCopy.h
This provides a facility that performs array coping between arrays that have the same type.
standardField.h
Provides access to introspection interfaces for standard structures like timeStamp, alarm, etc.
standardPVField.h
Creates data interfaces for standard data structures like timeStamp, alarm, etc.

pvType.h

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

pvType.h provides the proper semantics.

It includes the definitions:

typedef /*lots of stuff*/ boolean

typedef int8_t   int8;
typedef int16_t  int16;
typedef int32_t  int32;
typedef int64_t  int64;
typedef uint8_t   uint8;
typedef uint16_t  uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
// float and double are types

typedef std::vector<std::string> StringArray;
typedef std::tr1::shared_ptr<StringArray> StringArrayPtr;
inline std::string * get(StringArray &value);
inline std::string const * get(StringArray const &value);
inline std::string * get(StringArrayPtr &value);
inline std::string const * get(StringArrayPtr const &value);
}
inline StringArray & getVector(StringArrayPtr &value);
inline StringArray const & getVector(StringArrayPtr const &value);
typedef std::vector<std::string>::iterator StringArray_iterator;
typedef std::vector<std::string>::const_iterator StringArray_const_iterator;

where

boolean
A c++ bool has the semantics required for boolean. Only the name is different. C++ code can use either bool or boolean.
int8,...,uint64
Integers present a problem because short, int, and long are C++ reserved words but do not have a well defined number of bits. Thus for C++ the definitions above are used in C++ code. The above definitions have worked on all C++ implementations tested at present. If they break in a future implementation they should be changes via "#ifdef" preprocessor statements.
std::string
pvData requires that a string be an immutable string that is transferred 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. Note that std::string is treated like a primitive type.
StringArray definitions
typedefs are provided for an array of std::strings, which is a std::vector<std::string>. This is used by introspection.

TBD

boolean
Question for Michael. Why isn't the definition of boolean just
typedef uint8_t boolean;
    
printer.h
Not documented. Is this needed? Nothing currently uses it.

pvIntrospect.h

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

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

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

Type Description

Types are defined as:

enum Type {
    scalar,
    scalarArray,
    structure,
    structureArray,
    union_,
    unionArray
};

class TypeFunc {
public:
    epicsShareExtern const char* name(Type type);
};

enum ScalarType {
    pvBoolean,
    pvByte, pvShort, pvInt, pvLong,
    pvUByte, pvUShort, pvUInt, pvULong,
    pvFloat,pvDouble,
    pvString;
};

namespace ScalarTypeFunc {
public:
    bool isInteger(ScalarType type);
    bool isUInteger(ScalarType type);
    bool isNumeric(ScalarType type);
    bool isPrimitive(ScalarType type);
    ScalarType getScalarType(std::string const &value);
    const char* name(ScalarType);
    size_t elementSize(ScalarType id);
};
std::ostream& operator<<(std::ostream& o, const ScalarType& scalarType);

Type is one of the following:

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

ScalarType is one of the following:

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

TypeFunction is a set of convenience methods for Type

name
Returns the name of the type.

ScalarTypeFunction is a set of convenience methods for ScalarType

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

Introspection Description

This section describes the reflection interfaces which provide the following:

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

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

class Field;
class Scalar;
class ScalarArray;
class Structure;
class StructureArray;
class Union;
class UnionArray;

typedef std::tr1::shared_ptr<const Field> FieldConstPtr;
typedef std::vector<FieldConstPtr> FieldConstPtrArray;
typedef std::tr1::shared_ptr<const Scalar> ScalarConstPtr;
typedef std::tr1::shared_ptr<const ScalarArray> ScalarArrayConstPtr;
typedef std::tr1::shared_ptr<const Structure> StructureConstPtr;
typedef std::tr1::shared_ptr<const StructureArray> StructureArrayConstPtr;
typedef std::tr1::shared_ptr<const Union> UnionConstPtr;
typedef std::tr1::shared_ptr<const UnionArray> UnionArrayConstPtr;


class Field :
    virtual public Serializable,
    public std::tr1::enable_shared_from_this<Field>
{
public:
    POINTER_DEFINITIONS(Field);
    virtual ~Field();
    Type getType() const{return m_type;}
    virtual std::string getID() const = 0;
    virtual std::ostream& dump(std::ostream& o) const = 0;
 ...
};
std::ostream& operator<<(std::ostream& o, const Field& field);

class Scalar : public Field{
public:
    POINTER_DEFINITIONS(Scalar);
    virtual ~Scalar();
    typedef Scalar& reference;
    typedef const Scalar& const_reference;

    ScalarType getScalarType() const {return scalarType;}
    virtual std::string getID() const;
    virtual std::ostream& dump(std::ostream& o) const;
    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
    virtual void deserialize(ByteBuffer *buffer, DeserializableContol *control);
 ...
};

class BoundedString : public Scalar{
public:
    POINTER_DEFINITIONS(BoundedString);
    virtual ~BoundedString();
    typedef BoundedString& reference;
    typedef const BoundedString& const_reference;

    std::size_t getMaximumLength() const;
    virtual std::string getID() const;
    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
...
};

class epicsShareClass Array : public Field{
public:
    POINTER_DEFINITIONS(Array);
    virtual ~Array();
    typedef Array& reference;
    typedef const Array& const_reference;
    enum ArraySizeType { variable, fixed, bounded };

    virtual ArraySizeType getArraySizeType() const = 0;
    virtual std::size_t getMaximumCapacity() const = 0;
 ...
};


class ScalarArray : public Field{
public:
    POINTER_DEFINITIONS(ScalarArray);
    typedef ScalarArray& reference;
    typedef const ScalarArray& const_reference;

    ScalarArray(ScalarType scalarType);
    ScalarType  getElementType() const {return elementType;}
    virtual ArraySizeType getArraySizeType() const;
    virtual std::size_t getMaximumCapacity() const;
    virtual std::string getID() const;
    virtual std::ostream& dump(std::ostream& o) const;
    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
 ...
};

class epicsShareClass BoundedScalarArray : public ScalarArray{
public:
    POINTER_DEFINITIONS(BoundedScalarArray);
    typedef BoundedScalarArray& reference;
    typedef const BoundedScalarArray& const_reference;

    BoundedScalarArray(ScalarType scalarType, std::size_t size);
    virtual ArraySizeType getArraySizeType() const;
    virtual std::size_t getMaximumCapacity() const;
    virtual std::string getID() const;
    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
...
}

class epicsShareClass FixedScalarArray : public ScalarArray{
public:
    POINTER_DEFINITIONS(FixedScalarArray);
    typedef FixedScalarArray& reference;
    typedef const FixedScalarArray& const_reference;

    FixedScalarArray(ScalarType scalarType, std::size_t size);
    virtual ArraySizeType getArraySizeType() const {return Array::fixed;}
    virtual std::size_t getMaximumCapacity() const {return size;}
    virtual std::string getID() const;
    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
...
};



class StructureArray : public Field{
public:
    POINTER_DEFINITIONS(StructureArray);
    typedef StructureArray& reference;
    typedef const StructureArray& const_reference;

    StructureConstPtr  getStructure() const {return pstructure;}
    virtual ArraySizeType getArraySizeType() const;
    virtual std::size_t getMaximumCapacity() const;
    virtual std::string getID() const;
    virtual std::ostream& dump(std::ostream& o) const;
    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
 ...
};

class epicsShareClass UnionArray : public Field{
public:
    POINTER_DEFINITIONS(UnionArray);
    typedef UnionArray& reference;
    typedef const UnionArray& const_reference;
    UnionConstPtr  getUnion() const {return punion;}
    virtual ArraySizeType getArraySizeType() const;
    virtual std::size_t getMaximumCapacity() const;
    virtual std::string getID() const;
    virtual std::ostream& dump(std::ostream& o) const;
    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
};

class Structure : public Field {
public:
    POINTER_DEFINITIONS(Structure);
    typedef Structure& reference;
    typedef const Structure& const_reference;

    std::size_t getNumberFields() const {return numberFields;}
    FieldConstPtr getField(std::string const & fieldName) const;
    FieldConstPtr getField(std::size_t index) const;
    std::size_t getFieldIndex(std::string const &fieldName) const;
    FieldConstPtrArray const & getFields() const {return fields;}
    StringArray const & getFieldNames() const;
    std::string getFieldName(std::size_t fieldIndex) const;
    virtual std::string getID() const;
    virtual std::ostream& dump(std::ostream& o) const;
    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
 ...
};

class epicsShareClass Union : public Field {
public:
    POINTER_DEFINITIONS(Union);
    static std::string DEFAULT_ID;
    static std::string ANY_ID;
    virtual ~Union();
    typedef Union& reference;
    typedef const Union& const_reference;

    std::size_t getNumberFields() const;
    FieldConstPtr getField(std::string const &fieldName) const;
    FieldConstPtr getField(std::size_t index);
    std::size_t getFieldIndex(std::string const &fieldName) const;
    FieldConstPtrArray const & getFields() const;
    StringArray const & getFieldNames() const;
    std::string getFieldName(std::size_t fieldIndex) const;
    bool isVariant() const;
    virtual std::string getID() const;
    virtual std::ostream& dump(std::ostream& o) const;
    virtual void serialize(
        ByteBuffer *buffer, SerializableControl *control) const;
    virtual void deserialize(
        ByteBuffer *buffer, DeserializableControl *control);
    
};
Constructors
Note that all constructors are protected or private. The only way to create instances is via fieldBuilder or fieldCreate. The implementation manages all storage via shared pointers.
dump
Many classes provide this. This is a stream method that prints using the metadata syntax described in pvDataJava.html.

Field

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

Scalar

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

ScalarArray

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

StructureArray

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

UnionArray

getUnion
Get the union interface for each element.

Structure

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

Union

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

fieldBuilder and createField

class epicsShareClass FieldBuilder :
    public std::tr1::enable_shared_from_this<FieldBuilder>
{
public:
    FieldBuilderPtr setId(std::string const & id);
    FieldBuilderPtr add(std::string const & name, ScalarType scalarType);
    FieldBuilderPtr addBoundedString(std::string const & name, std::size_t maxLength);
    FieldBuilderPtr add(std::string const & name, FieldConstPtr const & field);
    FieldBuilderPtr addArray(std::string const & name, ScalarType scalarType);
    FieldBuilderPtr addFixedArray(
         std::string const & name,
         ScalarType scalarType,
         std::size_t size);
    FieldBuilderPtr addBoundedArray(std::string const &
         name,ScalarType scalarType,
         std::size_t bound);
    FieldBuilderPtr addArray(std::string const & name, FieldConstPtr const & element);
    StructureConstPtr createStructure();
    UnionConstPtr createUnion();
    FieldBuilderPtr addNestedStructure(std::string const & name); 
    FieldBuilderPtr addNestedUnion(std::string const & name);
    FieldBuilderPtr addNestedStructureArray(std::string const & name); 
    FieldBuilderPtr addNestedUnionArray(std::string const & name);
    FieldBuilderPtr endNested();
};

class epicsShareClass FieldCreate {
public:
    static FieldCreatePtr getFieldCreate();
    FieldBuilderPtr createFieldBuilder() const;
    ScalarConstPtr createScalar(ScalarType scalarType) const;
    BoundedStringConstPtr createBoundedString(std::size_t maxLength) const;
    ScalarArrayConstPtr createScalarArray(ScalarType elementType) const;
    ScalarArrayConstPtr createFixedScalarArray(
        ScalarType elementType, std::size_t size) const
    ScalarArrayConstPtr createBoundedScalarArray(
        ScalarType elementType, std::size_t bound) const;
    StructureArrayConstPtr createStructureArray(
        StructureConstPtr const & structure) const;
    StructureConstPtr createStructure () const;
    StructureConstPtr createStructure (
        StringArray const & fieldNames,
        FieldConstPtrArray const & fields) const;
    StructureConstPtr createStructure (
    	std::string const & id,
        StringArray const & fieldNames,
        FieldConstPtrArray const & fields) const;
    UnionConstPtr createUnion (
        StringArray const & fieldNames,
        FieldConstPtrArray const & fields) const;
    UnionConstPtr createUnion (
    	std::string const & id,
        StringArray const & fieldNames,
        FieldConstPtrArray const & fields) const;
    UnionConstPtr createVariantUnion() const;
    UnionArrayConstPtr createVariantUnionArray() const;
    UnionArrayConstPtr createUnionArray(UnionConstPtr const & punion) const;
    StructureConstPtr appendField(
        StructureConstPtr const & structure,
        std::string const & fieldName, FieldConstPtr const & field) const;
    StructureConstPtr appendFields(
        StructureConstPtr const & structure,
        StringArray const & fieldNames,
        FieldConstPtrArray const & fields) const;
    FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const;
        
};

epicsShareExtern FieldCreatePtr getFieldCreate();

FieldBuilder

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

setID
This sets an ID for the field, which is the name for the field when it is a subfield.
add
Add a scalar field.
addBoundedString
Add a scalar field that is a string that has a maximum size.
addArray
Add an array field. There are two methods: one to create a scalaArray and one to create scalarArray, unionArray, or structureArray.
addFixedArray
Add a fixed size scalarArray field.
addBoundedArray
Add a bounded scalarArray field.
createStructure
Create a structure from the fields that are currently present.
createUnion
Create a union from the fields that are currently present.
addNestedStructure
Add a nested structure. This is followed by an arbitrary number of adds followed by a an endNested.
addNestedUnion
Add a nested union. This is followed by an arbitrary number of adds followed by a an endNested.
addNestedStructureArray
Add a nested structure array. This is followed by an arbitrary number of adds followed by a an endNested.
addNestedUnionArray
Add a nested union array. This is followed by an arbitrary number of adds followed by a an endNested.
endNested
End current nested structure or union.

Examples of using fieldBuilder were given earlier in this manual.

FieldCreate

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

standardField.h

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

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

Will result in a Field definition that has the form:

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

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

standardField.h contains:

class StandardField;
typedef std::tr1::shared_ptr<StandardField> StandardFieldPtr;

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

pvData.h

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

typedefs

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

class PVField;
class PVScalar;
class PVScalarArray;
class PVStructure;
class PVStructureArray;
class PVUnion;

template<typename T> class PVScalarValue;
template<typename T> class PVValueArray;

typedef PVValueArray<PVUnionPtr> PVUnionArray;
typedef std::tr1::shared_ptr<PVUnionArray> PVUnionArrayPtr;


typedef std::tr1::shared_ptr<PostHandler> PostHandlerPtr;

typedef std::tr1::shared_ptr<PVField> PVFieldPtr;
typedef std::vector<PVFieldPtr> PVFieldPtrArray;
typedef std::vector<PVFieldPtr>::iterator PVFieldPtrArray_iterator;
typedef std::vector<PVFieldPtr>::const_iterator PVFieldPtrArray_const__iterator;

typedef std::tr1::shared_ptr<PVScalar> PVScalarPtr;
typedef std::tr1::shared_ptr<PVScalarArray> PVScalarArrayPtr;

typedef std::tr1::shared_ptr<PVStructure> PVStructurePtr;
typedef std::vector<PVStructurePtr> PVStructurePtrArray;
typedef std::vector<PVStructurePtr>::iterator PVStructurePtrArray_iterator;
typedef std::vector<PVStructurePtr>::const_iterator PVStructurePtrArray_const__iterator;

typedef PVValueArray<PVStructurePtr> PVStructureArray;
typedef std::tr1::shared_ptr<PVStructureArray> PVStructureArrayPtr;
typedef std::vector<PVStructureArrayPtr> PVStructureArrayPtrArray;
typedef std::tr1::shared_ptr<PVStructureArrayPtrArray> PVStructureArrayPtrArrayPtr;

typedef std::tr1::shared_ptr<PVUnion> PVUnionPtr;
typedef std::vector<PVUnionPtr> PVUnionPtrArray;
typedef std::vector<PVUnionPtr>::iterator PVUnionPtrArray_iterator;
typedef std::vector<PVUnionPtr>::const_iterator PVUnionPtrArray_const__iterator;

typedef PVValueArray<PVUnionPtr> PVUnionArray;
typedef std::tr1::shared_ptr<PVUnionArray> PVUnionArrayPtr;
typedef std::vector<PVUnionArrayPtr> PVUnionArrayPtrArray;
typedef std::tr1::shared_ptr<PVUnionArrayPtrArray> PVUnionArrayPtrArrayPtr;

class PVDataCreate;
typedef std::tr1::shared_ptr<PVDataCreate> PVDataCreatePtr;


/**
 * typedefs for the various possible scalar types.
 */
typedef PVScalarValue<boolean> PVBoolean;
typedef PVScalarValue<int8> PVByte;
typedef PVScalarValue<int16> PVShort;
typedef PVScalarValue<int32> PVInt;
typedef PVScalarValue<int64> PVLong;
typedef PVScalarValue<uint8> PVUByte;
typedef PVScalarValue<uint16> PVUShort;
typedef PVScalarValue<uint32> PVUInt;
typedef PVScalarValue<uint64> PVULong;
typedef PVScalarValue<float> PVFloat;
typedef PVScalarValue<double> PVDouble;
class PVString;
typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
typedef std::tr1::shared_ptr<PVByte> PVBytePtr;
typedef std::tr1::shared_ptr<PVShort> PVShortPtr;
typedef std::tr1::shared_ptr<PVInt> PVIntPtr;
typedef std::tr1::shared_ptr<PVLong> PVLongPtr;
typedef std::tr1::shared_ptr<PVUByte> PVUBytePtr;
typedef std::tr1::shared_ptr<PVUShort> PVUShortPtr;
typedef std::tr1::shared_ptr<PVUInt> PVUIntPtr;
typedef std::tr1::shared_ptr<PVULong> PVULongPtr;
typedef std::tr1::shared_ptr<PVFloat> PVFloatPtr;
typedef std::tr1::shared_ptr<PVDouble> PVDoublePtr;
typedef std::tr1::shared_ptr<PVString> PVStringPtr;

/**
 * Definitions for the various scalarArray types.
 */
typedef PVValueArray<boolean> PVBooleanArray;
typedef PVValueArray<int8> PVByteArray;
typedef PVValueArray<int16> PVShortArray;
typedef PVValueArray<int32> PVIntArray;
typedef PVValueArray<int64> PVLongArray;
typedef PVValueArray<uint8> PVUByteArray;
typedef PVValueArray<uint16> PVUShortArray;
typedef PVValueArray<uint32> PVUIntArray;
typedef PVValueArray<uint64> PVULongArray;
typedef PVValueArray<float> PVFloatArray;
typedef PVValueArray<double> PVDoubleArray;
typedef PVValueArray<std::string> PVStringArray;

typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
typedef std::tr1::shared_ptr<PVByteArray> PVByteArrayPtr;
typedef std::tr1::shared_ptr<PVShortArray> PVShortArrayPtr;
typedef std::tr1::shared_ptr<PVIntArray> PVIntArrayPtr;
typedef std::tr1::shared_ptr<PVLongArray> PVLongArrayPtr;
typedef std::tr1::shared_ptr<PVUByteArray> PVUByteArrayPtr;
typedef std::tr1::shared_ptr<PVUShortArray> PVUShortArrayPtr;
typedef std::tr1::shared_ptr<PVUIntArray> PVUIntArrayPtr;
typedef std::tr1::shared_ptr<PVULongArray> PVULongArrayPtr;
typedef std::tr1::shared_ptr<PVFloatArray> PVFloatArrayPtr;
typedef std::tr1::shared_ptr<PVDoubleArray> PVDoubleArrayPtr;
typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;

PVField

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

class PostHandler
{
public:
    POINTER_DEFINITIONS(PostHandler);
    virtual ~PostHandler(){}
    virtual void postPut() = 0;
};

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

The public methods for PVField are:

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

PVScalar

This is the base class for all scalar data.

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

where

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

PVScalarValue

The interfaces for primitive data types are:

template<typename T>
class PVScalarValue : public PVScalar {
public:
    POINTER_DEFINITIONS(PVScalarValue);
    typedef T value_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    static const ScalarType typeCode;

    virtual ~PVScalarValue() {}
    virtual T get() const = 0;
    virtual void put(T value) = 0;
    std::ostream& dumpValue(std::ostream& o) const;
    void operator>>=(T& value) const;
    void operator<<=(T value);
    template<typename T1>
    T1 getAs() const;
    template<typename T1>
    void putFrom(T1 val);
 ...
}

typedef PVScalarValue<boolean> PVBoolean;
typedef PVScalarValue<int8> PVByte;
typedef PVScalarValue<int16> PVShort;
typedef PVScalarValue<int32> PVInt;
typedef PVScalarValue<int64> PVLong;
typedef PVScalarValue<uint8> PVUByte;
typedef PVScalarValue<uint16> PVUShort;
typedef PVScalarValue<uint32> PVUInt;
typedef PVScalarValue<uint64> PVULong;
typedef PVScalarValue<float> PVFloat;
typedef PVScalarValue<double> PVDouble;
typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
typedef std::tr1::shared_ptr<PVByte> PVBytePtr;
typedef std::tr1::shared_ptr<PVShort> PVShortPtr;
typedef std::tr1::shared_ptr<PVInt> PVIntPtr;
typedef std::tr1::shared_ptr<PVLong> PVLongPtr;
typedef std::tr1::shared_ptr<PVUByte> PVUBytePtr;
typedef std::tr1::shared_ptr<PVUShort> PVUShortPtr;
typedef std::tr1::shared_ptr<PVUInt> PVUIntPtr;
typedef std::tr1::shared_ptr<PVULong> PVULongPtr;
typedef std::tr1::shared_ptr<PVFloat> PVFloatPtr;
typedef std::tr1::shared_ptr<PVDouble> PVDoublePtr;


// PVString is special case, since it implements SerializableArray
class PVString : public PVScalarValue<std::string>, SerializableArray {
public:
    virtual ~PVString() {}
 ...
};


where

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

PVUnion

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

class PVUnion : public PVField
{
public:
    POINTER_DEFINITIONS(PVUnion);
    virtual ~PVUnion();
    typedef PVUnion & reference;
    typedef const PVUnion & const_reference;

    UnionConstPtr getUnion() const;
    PVFieldPtr get() const;
    
    template<typename PVT>
    std::tr1::shared_ptr<PVT> get() const;

   PVFieldPtr select(int32 index);

    template<typename PVT>
    std::tr1::shared_ptr<PVT> select(int32 index);

    PVFieldPtr select(std::string const & fieldName);

    template<typename PVT>
    std::tr1::shared_ptr<PVT> select(std::string const & fieldName);

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

PVArray

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

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

PVScalarArray

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

class PVScalarArray : public PVArray {
public:
    POINTER_DEFINITIONS(PVScalarArray);
    virtual ~PVScalarArray();
    typedef PVScalarArray &reference;
    typedef const PVScalarArray& const_reference;

    const ScalarArrayConstPtr getScalarArray() const ;

    template<typename T>
    void getAs(shared_vector<const T>& out) const

    template<typename T>
    void putFrom(const shared_vector<const T>& inp)

    void assign(PVScalarArray& pv);
 ...
}

where

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

PVStructure

The interface for a structure is:

class PVStructure : public PVField,public BitSetSerializable {
public:
    POINTER_DEFINITIONS(PVStructure);
    virtual ~PVStructure();
    typedef PVStructure & reference;
    typedef const PVStructure & const_reference;

    virtual void setImmutable();
    StructureConstPtr getStructure() const;
    const PVFieldPtrArray & getPVFields() const;
    PVFieldPtr getSubField(std::string const &fieldName) const;

    template<typename PVT>
    std::tr1::shared_ptr<PVT> getSubField(std::string const &fieldName) const

    PVFieldPtr getSubField(std::size_t fieldOffset) const;

    template<typename PVT>
    std::tr1::shared_ptr<PVT> getSubField(std::size_t fieldOffset) const

    PVFieldPtr getSubFieldT(std::string const &fieldName) const;

    template<typename PVT>
    std::tr1::shared_ptr<PVT> getSubFieldT(std::string const &fieldName) const

    PVFieldPtr getSubFieldT(std::size_t fieldOffset) const;

    template<typename PVT>
    std::tr1::shared_ptr<PVT> getSubFieldT(std::size_t fieldOffset) const

    virtual void serialize(
        ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
    virtual void deserialize(
        ByteBuffer *pbuffer,DeserializableControl *pflusher);
    virtual void serialize(ByteBuffer *pbuffer,
        SerializableControl *pflusher,BitSet *pbitSet) const;
    virtual void deserialize(ByteBuffer *pbuffer,
        DeserializableControl*pflusher,BitSet *pbitSet);
    PVStructure(StructureConstPtr const & structure);
    PVStructure(StructureConstPtr const & structure,PVFieldPtrArray const & pvFields);
    virtual std::ostream& dumpValue(std::ostream& o) const;
};

where

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

PVValueArray

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

template<typename T>
class PVValueArray : public detail::PVVectorStorage<T,PVScalarArray> 
{
public:
    POINTER_DEFINITIONS(PVValueArray);
    typedef T  value_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef ::epics::pvData::shared_vector<T> svector;
    typedef ::epics::pvData::shared_vector<const T> const_svector;
    static const ScalarType typeCode;

    virtual ~PVValueArray() {}
    virtual ArrayConstPtr getArray() const
    std::ostream& dumpValue(std::ostream& o) const;
    std::ostream& dumpValue(std::ostream& o, size_t index) const;
    // inherited from PVVectorStorage
    const_svector view();
    void swap(const_svector& other);
    void replace(const const_svector& next);
    svector reuse();
    ...
};

where

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

TBD

Check for completeness
Michael should check that PVScalarArray and PVValueArray have the correct set of methods and that the descriptions are correct.

PVStructureArray

The interface for an array of structures is:

template<>
class PVValueArray<PVStructurePtr> : public detail::PVVectorStorage<PVStructurePtr,PVArray>
{
public:
    POINTER_DEFINITIONS(PVStructureArray);
    typedef PVStructurePtr  value_type;
    typedef PVStructurePtr* pointer;
    typedef const PVStructurePtr* const_pointer;
    typedef PVStructureArray &reference;
    typedef const PVStructureArray& const_reference;
    typedef ::epics::pvData::shared_vector<PVStructurePtr> svector;
    typedef ::epics::pvData::shared_vector<const PVStructurePtr> const_svector;

    virtual ~PVStructureArray() {}
    virtual ArrayConstPtr getArray() const;
    virtual size_t getLength();
    virtual size_t getCapacity();
    virtual void setCapacity(size_t capacity);
    virtual void setLength(std::size_t length);
    virtual StructureArrayConstPtr getStructureArray() const ;
    virtual std::size_t append(std::size_t number);
    virtual bool remove(std::size_t offset,std::size_t number);
    virtual void compress();
    virtual const_svector view() const;
    virtual void swap(const_svector &other);
    virtual void replace(const const_svector &other);
    virtual void serialize(ByteBuffer *pbuffer,
        SerializableControl *pflusher) const;
    virtual void serialize(ByteBuffer *pbuffer,
        SerializableControl *pflusher, std::size_t offset, std::size_t count) const ;
    virtual void deserialize(ByteBuffer *buffer,
        DeserializableControl *pflusher);
    virtual std::ostream& dumpValue(std::ostream& o) const;
    virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const;
 ...
}

where

getStructureArray
Get the introspection interface shared by each element.
compress
This moves all null elements and then changes the array capacity. When done there are no null elements.

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

PVUnionArray

The interface for an array of unions is:

template<>
class epicsShareClass PVValueArray<PVUnionPtr> : public detail::PVVectorStorage<PVUnionPtr,PVArray>
{
    typedef detail::PVVectorStorage<PVUnionPtr,PVArray> base_t;
public:
    POINTER_DEFINITIONS(PVUnionArray);
    typedef PVUnionPtr  value_type;
    typedef PVUnionPtr* pointer;
    typedef const PVUnionPtr* const_pointer;
    typedef PVUnionArray &reference;
    typedef const PVUnionArray& const_reference;

    //TODO: full namespace can be removed along with local typedef 'shared_vector'
    typedef ::epics::pvData::shared_vector<PVUnionPtr> svector;
    typedef ::epics::pvData::shared_vector<const PVUnionPtr> const_svector;
    
    virtual ~PVValueArray() {}
    virtual ArrayConstPtr getArray() const;
    virtual size_t getLength() const;
    virtual size_t getCapacity() const;
    virtual void setCapacity(size_t capacity);
    virtual void setLength(std::size_t length);
    UnionArrayConstPtr getUnionArray() const;
    virtual std::size_t append(std::size_t number);
    virtual bool remove(std::size_t offset,std::size_t number);
    virtual void compress();
    virtual const_svector view() const;
    virtual void swap(const_svector &other);
    virtual void replace(const const_svector &other);
    virtual void serialize(ByteBuffer *pbuffer,
        SerializableControl *pflusher) const;
    virtual void deserialize(ByteBuffer *buffer,
        DeserializableControl *pflusher);
    virtual void serialize(ByteBuffer *pbuffer,
        SerializableControl *pflusher, std::size_t offset, std::size_t count) const ;
    virtual std::ostream& dumpValue(std::ostream& o) const;
    virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const;
};

where

getUnionArray
Get the introspection interface shared by each element.
compress
This moves all null elements and then changes the array capacity. When done there are no null elements.

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

PVDataCreate

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

class PVDataCreate {
public:
    static PVDataCreatePtr getPVDataCreate();

    PVFieldPtr createPVField(FieldConstPtr const & field);
    PVFieldPtr createPVField(PVFieldPtr const & fieldToClone);

    PVScalarPtr createPVScalar(ScalarConstPtr const & scalar);
    PVScalarPtr createPVScalar(ScalarType scalarType);
    PVScalarPtr createPVScalar(PVScalarPtr const & scalarToClone);
    template<typename PVT>
    std::tr1::shared_ptr<PVT> createPVScalar();

    PVStructurePtr createPVStructure(
        StringArray const & fieldNames,PVFieldPtrArray const & pvFields);
    PVStructurePtr createPVStructure(PVStructurePtr const & structToClone);
    PVStructurePtr createPVStructure(StructureConstPtr const & structure);

    PVUnionPtr createPVUnion(UnionConstPtr const & punion);
    PVUnionPtr createPVUnion(PVUnionPtr const & unionToClone);
    PVUnionPtr createPVVariantUnion();

    PVScalarArrayPtr createPVScalarArray(ScalarArrayConstPtr const & scalarArray);
    PVScalarArrayPtr createPVScalarArray(ScalarType elementType);
    PVScalarArrayPtr createPVScalarArray(PVScalarArrayPtr const  & scalarArrayToClone);
    template<typename PVAT>
    std::tr1::shared_ptr<PVAT> createPVScalarArray();

    PVStructureArrayPtr createPVStructureArray(StructureArrayConstPtr const & structureArray);
    PVStructureArrayPtr createPVStructureArray(StructureConstPtr const & structure);

    PVUnionArrayPtr createPVUnionArray(UnionArrayConstPtr const & unionArray);
    PVUnionArrayPtr createPVUnionArray(UnionConstPtr const & punion);
    PVUnionArrayPtr createPVVariantUnionArray();
 ...
};

extern PVDataCreatePtr getPVDataCreate();

where

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

standardPVField.h

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

class StandardPVField;
typedef std::tr1::shared_ptr<StandardPVField> StandardPVFieldPtr;

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

extern StandardPVFieldPtr getStandardPVField();

Conversion

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

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

convert.h

This section describes the supported conversions between data types.

bool operator==(PVField&, PVField&);

static bool operator!=(PVField& a, PVField& b);

bool operator==(const Field&, const Field&);
bool operator==(const Scalar&, const Scalar&);
bool operator==(const ScalarArray&, const ScalarArray&);
bool operator==(const Structure&, const Structure&);
bool operator==(const StructureArray&, const StructureArray&);
bool operator==(const Union&, const Union&);
bool operator==(const UnionArray&, const UnionArray&);

static inline bool operator!=(const Field& a, const Field& b);
static inline bool operator!=(const Scalar& a, const Scalar& b);
static inline bool operator!=(const ScalarArray& a, const ScalarArray& b);
static inline bool operator!=(const Structure& a, const Structure& b);
static inline bool operator!=(const StructureArray& a, const StructureArray& b);
static inline bool operator!=(const Union& a, const Union& b);
static inline bool operator!=(const UnionArray& a, const UnionArray& b);

class Convert;
typedef std::tr1::shared_ptr<Convert> ConvertPtr;

class Convert {
public:
    static ConvertPtr getConvert();
    ~Convert();
    void getFullName(std::string * buf,PVFieldPtr const & pvField);
    bool equals(PVFieldPtr const &a,PVFieldPtr const &b);
    bool equals(PVField &a,PVField &b);
    void getString(std::string * buf,PVFieldPtr const & pvField,int indentLevel);
    void getString(std::string * buf,PVFieldPtr const & pvField);
    void getString(std::string * buf,PVField const * pvField,int indentLevel);
    void getString(std::string * buf,PVField const * pvField);
    std::size_t fromString(
        PVStructurePtr const &pv,
        StringArray const & from,
        std::size_t fromStartIndex = 0);
    void fromString(PVScalarPtr const & pv, std::string const & from);
    std::size_t fromString(PVScalarArrayPtr const & pv, std::string const &from);
    std::size_t fromStringArray(
        PVScalarArrayPtr const & pv,
        std::size_t offset, std::size_t length,
        StringArray const & from,
        std::size_t fromOffset);
    std::size_t toStringArray(PVScalarArrayPtr const & pv,
        std::size_t offset,
        std::size_t length,
        StringArray & to,
        std::size_t toOffset);
    bool isCopyCompatible(FieldConstPtr const & from, FieldConstPtr const & to);
    void copy(PVFieldPtr const & from, PVFieldPtr const & to);
    bool isCopyScalarCompatible(
        ScalarConstPtr const & from,
        ScalarConstPtr const & to);
    void copyScalar(PVScalarPtr const & from, PVScalarPtr const & to);
    bool isCopyScalarArrayCompatible(
        ScalarArrayConstPtr const & from,
        ScalarArrayConstPtr const & to);
    bool isCopyStructureCompatible(
        StructureConstPtr const & from, StructureConstPtr const & to);
    void copyStructure(PVStructurePtr const & from, PVStructurePtr const & to);
    bool isCopyStructureArrayCompatible(
        StructureArrayConstPtr const & from, StructureArrayConstPtr const & to);
    void copyStructureArray(
        PVStructureArrayPtr const & from, PVStructureArrayPtr const & to);
    bool isCopyUnionCompatible(
        UnionConstPtr const & from, UnionConstPtr const & to);
    void copyUnion(
        PVUnionPtr const & from, PVUnionPtr const & to);
    bool isCopyUnionArrayCompatible(
        UnionArrayConstPtr const & from, UnionArrayConstPtr const & to);
    void copyUnionArray(
        PVUnionArrayPtr const & from, PVUnionArrayPtr const & to);
    int8 toByte(PVScalarPtr const & pv);
    int16 toShort(PVScalarPtr const & pv);
    int32 toInt(PVScalarPtr const & pv);
    int64 toLong(PVScalarPtr const & pv);
    uint8 toUByte(PVScalarPtr const & pv);
    uint16 toUShort(PVScalarPtr const & pv);
    uint32 toUInt(PVScalarPtr const & pv);
    uint64 toULong(PVScalarPtr const & pv);
    float toFloat(PVScalarPtr const & pv);
    double toDouble(PVScalarPtr const & pv);
    std::string toString(PVScalarPtr const & pv);
    void fromByte(PVScalarPtr const & pv,int8 from);
    void fromShort(PVScalarPtr const & pv,int16 from);
    void fromInt(PVScalarPtr const & pv, int32 from);
    void fromLong(PVScalarPtr const & pv, int64 from);
    void fromUByte(PVScalarPtr const & pv,uint8 from);
    void fromUShort(PVScalarPtr const & pv,uint16 from);
    void fromUInt(PVScalarPtr const & pv, uint32 from);
    void fromULong(PVScalarPtr const & pv, uint64 from);
    void fromFloat(PVScalarPtr const & pv, float from);
    void fromDouble(PVScalarPtr const & pv, double from);
    void newLine(std::string * buf, int indentLevel);
 ...
}

extern ConvertPtr getConvert();

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

pvSubArrayCopy.h

template<typename T>
void copy(
    PVValueArray<T> & pvFrom,
    size_t fromOffset,
    size_t fromStride,
    PVValueArray<T> & pvTo,
    size_t toOffset,
    size_t toStride,
    size_t count);

void copy(
    PVScalarArray & from,
    size_t fromOffset,
    size_t fromStride,
    PVScalarArray & to,
    size_t toOffset,
    size_t toStride,
    size_t count);

void copy(
    PVStructureArray & from,
    size_t fromOffset,
    size_t fromStride,
    PVStructureArray & to,
    size_t toOffset,
    size_t toStride,
    size_t count);

void copy(
    PVArray & from,
    size_t fromOffset,
    size_t fromStride,
    PVArray & to,
    size_t toOffset,
    size_t toStride,
    size_t count);

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

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

An exception is thrown if:

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

src/property

Definition of Property

Often a field named "value" has 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 hierarchy above a value field it is a property of the value field.

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

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

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

structure powerSupplyValue
    double value
    alarm_t
        int severity 0
        int status 0
        string message

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

Standard Properties

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

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

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

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

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

Overview of Property Support

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

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

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

timeStamp

A timeStamp is represented by the following structure

structure timeStamp
    long secondsPastEpoch
    int nanoseconds
    int userTag

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

Two header files are provided for manipulating time stamps:

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

timeStamp.h

This provides

extern int32 milliSecPerSec;
extern int32 microSecPerSec;
extern int32 nanoSecPerSec;
extern int64 posixEpochAtEpicsEpoch;

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

where

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

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

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

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

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

pvTimeStamp.h

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

where

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

alarm

An alarm structure is defined as follows:

structure alarm
    int severity
    int status
    string message

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

Two header files are provided for manipulating alarms:

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

alarm.h

enum AlarmSeverity {
 noAlarm,minorAlarm,majorAlarm,invalidAlarm,undefinedAlarm
};

enum AlarmStatus {
    noStatus,deviceStatus,driverStatus,recordStatus,
    dbStatus,confStatus,undefinedStatus,clientStatus
};


class AlarmSeverityFunc {
public:
    static AlarmSeverity getSeverity(int value);
    static StringArrayPtr getSeverityNames();
};

class AlarmStatusFunc {
public:
    static AlarmStatus getStatus(int value);
    static StringArrayPtr getStatusNames();
};

class Alarm {
public:
    Alarm();
    //default constructors and destructor are OK
    std::string getMessage();
    void setMessage(std::string const &value);
    AlarmSeverity getSeverity() const;
    void setSeverity(AlarmSeverity value);
    AlarmStatus getStatus() const;
    void setStatus(AlarmStatus value);
};

Alarm Severity defines the possible alarm severities:

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

Alarm Status defines the possible choices for alarm status:

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

Alarm has the methods:

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

pvAlarm.h

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

where

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

control

Control information is represented by the following structure

structure control
    double limitLow
    double limitHigh
    double minStep

Two header files are provided for manipulating control:

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

control.h

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

where

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

pvControl.h

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

where

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

display

Display information is represented by the following structure

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

Two header files are provided for manipulating display:

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

display.h

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

where

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

pvDisplay.h

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

where

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

pvEnumerated.h

An enumerated structure is a structure that has fields:

structure
    int index
    string[] choices

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

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

where

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

src/factory

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

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

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

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

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

Other files implement PVData base classes

src/misc

Overview

This package provides utility code:

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

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

bitSet.h

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

class BitSet;
typedef std::tr1::shared_ptr<BitSet> BitSetPtr;

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

std::ostream& operator<<(std::ostream& o, const BitSet& b);

where

BitSet()
Creates a bitSet of initial size 64 bits. All bits initially false.
BitSet(uint32 nbits)
Creates a bitSet with the initial of the specified number of bits. All bits initially false.
~BitSet()
Destructor.
flip(uint32 bitIndex)
Flip the specified bit.
set(uint32 bitIndex)
Set the specified bit true.
clear(uint32 bitIndex)
Set the specified bit false.
set(uint32 bitIndex, bool value)
Set the specified bit to value.
get(uint32 bitIndex)
Return the state of the specified bit.
clear()
Set all bits to false.
nextSetBit(uint32 fromIndex)
Get the index of the next true bit beginning with the specified bit.
nextClearBit(uint32 fromIndex)
Get the index of the next false bit beginning with the specified bit.
isEmpty()
Return (false,true) if (at least one bit true, all bits are false)
cardinality()
Return the number of true bits.
size()
Returns the number of bits of space actually in use.
operator&=(const BitSet& set)
Performs a logical and of this target bit set with the argument bit set. This bit set is modified so that each bit in it has the value true if and only if it both initially had the value true and the corresponding bit in the bit set argument also had the value.
operator|=(const BitSet& set)
Performs a logical or of this target bit set with the argument bit set.
operator^=(const BitSet& set)
Performs a logical exclusive or of this target bit set with the argument bit set.
operator=(const BitSet &set)
Assignment operator.
or_and(const BitSet& set1, const BitSet& set2)
Perform AND operation on set1 and set2, and then OR this bitSet with the result.
operator==(const BitSet &set)
Does this bitSet have the same values as the argument.
operator!=(const BitSet &set)
Is this bitSet different than the argument.
virtual void serialize(ByteBuffer *buffer,SerializableControl *flusher) const;
Serialize the bitSet
virtual void deserialize(ByteBuffer *buffer,DeserializableControl *flusher);
Deserialize the bitSet.

byteBuffer.h

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

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

destroyable.h

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

epicsException.h

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

event.h

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

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

where

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

executor.h

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

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

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

Executor has the methods:

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

localStaticLock.h

extern epics::pvData::Mutex& getLocalStaticInitMutex();

static class MutexInitializer {
  public:
    MutexInitializer ();
    ~MutexInitializer ();
} localStaticMutexInitializer; // Note object here in the header.

TBD Matej will explain.

lock.h

typedef epicsMutex Mutex;

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

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

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

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

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

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

Lock has a private variable:

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

It is thread safe if used as follows:

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

It is not thread safe if used as follows:

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

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

messageQueue.h

Definitions

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

class MessageNode;
class MessageQueue;
typedef std::tr1::shared_ptr<MessageNode> MessageNodePtr;
typedef std::vector<MessageNodePtr> MessageNodePtrArray;
typedef std::tr1::shared_ptr<MessageQueue> MessageQueuePtr;

class MessageNode {
public:
    std::string getMessage() const;
    MessageType getMessageType() const;
    void setMessageNull();
};

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

A messageNode is a class with two public data members:

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

A messageQueue is an interface with public methods:

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

Look at miscTest/testMessageQueue.cpp for an example.

noDefaultMethods.h

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

/* 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 implement
    NoDefaultMethods(const NoDefaultMethods&);
    NoDefaultMethods & operator=(const NoDefaultMethods &);
    };

queue.h

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

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

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

The queue methods are:

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

A queue is created as follows:

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

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

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

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

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

requester.h

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

class Requester;
typedef std::tr1::shared_ptr<Requester> RequesterPtr;

enum MessageType {
   infoMessage,warningMessage,errorMessage,fatalErrorMessage
};

extern std::string getMessageTypeName(MessageType messageType);
extern const size_t messageTypeCount;
class Requester {
public:
    POINTER_DEFINITIONS(Requester);
    virtual ~Requester(){}
    virtual std::string getRequesterName() = 0;
    virtual void message(std::string const & message,MessageType messageType) = 0;
};

where

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

serialize.h

    class SerializableControl;
    class DeserializableControl;
    class Serializable;
    class BitSetSerializable;
    class SerializableArray;
    class BitSet;
    class Field;

    class SerializableControl {
    public:
        virtual ~SerializableControl(){}
        virtual void flushSerializeBuffer() =0;
        virtual void ensureBuffer(std::size_t size) =0;
        virtual void alignBuffer(std::size_t alignment) =0;
        virtual void cachedSerialize(
            std::tr1::shared_ptr<const Field> const & field,
            ByteBuffer* buffer) = 0;
    };

    class DeserializableControl {
    public:
        virtual ~DeserializableControl(){}
        virtual void ensureData(std::size_t size) =0;
        virtual void alignData(std::size_t alignment) =0;
        virtual std::tr1::shared_ptr<const Field> cachedDeserialize(
            ByteBuffer* buffer) = 0;
    };

    class Serializable {
    public:
        virtual ~Serializable(){}
        virtual void serialize(ByteBuffer *buffer,
            SerializableControl *flusher) const = 0;
        virtual void deserialize(ByteBuffer *buffer,
            DeserializableControl *flusher) = 0;
    };

    class BitSetSerializable {
    public:
        virtual ~BitSetSerializable(){}
        virtual void serialize(ByteBuffer *buffer,
            SerializableControl *flusher,BitSet *bitSet) const = 0;
        virtual void deserialize(ByteBuffer *buffer,
            DeserializableControl *flusher,BitSet *bitSet) = 0;
    };


    class SerializableArray : virtual public Serializable {
    public:
        virtual ~SerializableArray(){}
        virtual void serialize(ByteBuffer *buffer,
            SerializableControl *flusher, std::size_t offset,
            std::size_t count) const = 0;
    };

serializeHelper.h

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

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 std::string& value,
        ByteBuffer* buffer,SerializableControl* flusher);
    static void serializeSubstring(const std::string& value, int offset,
        int count, ByteBuffer* buffer,
        SerializableControl* flusher);
    static std::string deserializeString(ByteBuffer* buffer,
        DeserializableControl* control);
 ...
};

where

writeSize
Serialize the size.
readSize
Deserialize the size.
serializeString
Serialize a std::string.
serializeSubstring
Serialize a substring.
deserializeString
Deserialize a string.

sharedPtr.h

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

sharedVector.h

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

shared_vector differs from std::vector as follows:

Differences in behavior
shared_vector models const-ness like shared_ptr. An equivalent of 'const std::vector<E>' is 'const shared_vector<const E>'. However, it is also possible to have 'const shared_vector<E>' analogous to 'E* const' and 'shared_vector<const E>>' which is analogous to 'const E*'.i
Copying a shared_vector, by construction or assignment, does not copy its contents. Modifications to one such "copy" effect all associated shared_vector instances.
std::vector::reserve(N) has no effect if N<=std::vector::capacity(). However, like resize(), shared_vector<E>::reserve() has the side effect of always calling make_unique().
Parts of std::vector interface not implemented
Mutating methods insert(), erase(), shrink_to_fit(), emplace(), and emplace_back() are not implemented.
shared_vector does not model an allocator which is bound to the object. Therefore the get_allocator() method and the allocator_type typedef are not provided.
The assign() method and the related constructor are not implemented at this time.
The comparison operators are not implemented at this time.
Parts not found in std::vector
shared_vector has additional constructors from raw pointers and shared_ptr s. The copy constructor and assignment operator allow implicit castings from type 'shared_vector<T>' to 'shared_vector<const T>>'. To facilitate safe modification the methods unique() and make_unique() are provided The slice() method selects a sub-set of the shared_vector. The low level accessors dataPtr(), dataOffset(), dataCount(), and dataTotal().
template<typename E, class Enable = void& class shared_vector;

template<typename E, class Enable&
class shared_vector : public detail::shared_vector_base<E&
{
    typedef detail::shared_vector_base<E& base_t;
    typedef typename detail::call_with<E&::type param_type;
    typedef typename meta::strip_const<E&::type _E_non_const;
public:
    typedef E value_type;
    typedef E& reference;
    typedef typename meta::decorate_const<E&::type& const_reference;
    typedef E* pointer;
    typedef typename meta::decorate_const<E&::type* const_pointer;
    typedef E* iterator;
    typedef std::reverse_iterator<iterator& reverse_iterator;
    typedef typename meta::decorate_const<E&::type* const_iterator;
    typedef std::reverse_iterator<const_iterator& const_reverse_iterator;
    typedef ptrdiff_t difference_type;
    typedef size_t size_type;

    typedef E element_type;
    typedef std::tr1::shared_ptr<E& shared_pointer_type;

    // allow specialization for all E to be friends
    template<typename E1, class Enable1& friend class shared_vector;

    shared_vector() :base_t();
    explicit shared_vector(size_t c)
        :base_t(new _E_non_const[c], 0, c);
    shared_vector(size_t c, param_type e);
    template<typename A&
    shared_vector(A v, size_t o, size_t c) :base_t(v,o,c);
    template<typename E1&
    shared_vector(const std::tr1::shared_ptr<E1&& d, size_t o, size_t c);
    template<typename A, typename B&
    shared_vector(A d, B b, size_t o, size_t c);
    shared_vector(const shared_vector& o) :base_t(o);
    
    size_t max_size() const;
    size_t capacity() const;
    void reserve(size_t i);
    void resize(size_t i);
    void resize(size_t i, param_type v);
    void make_unique();
    
    iterator begin() const;
    iterator end() const;
    reverse_iterator rbegin() const;
    reverse_iterator rend() const;
    reference front() const;
    reference back() const;

    void push_back(param_type v);
    void pop_back();
    pointer data() const;
    reference operator[](size_t i) const;
    reference at(size_t i) const;
    // inherited from detail
    shared_vector_base& operator=(const shared_vector_base& o);
    void swap(shared_vector_base& o);
    void clear();
    bool unique() const;
    size_t size() const;
    bool empty() const;
    void slice(size_t offset, size_t length=(size_t)-1);
    const std::tr1::shared_ptr<E&& dataPtr();
    size_t dataOffset() const;
    size_t dataCount() const;
    size_t dataTotal() const;
where
shared_vector
Several flavors of constructor are provided. The most commonly used is:
shared_vector(size_t c);
       
This creates a shared_vector of the specified size/
max_size
The maximum size the C++ implementation allows, i.e., the maximum possible capacity. Note that units are number of elements not number of bytes.
capacity
The current capacity.
reserve
Set array capacity.
resize
Grow or shrink array. It the second argument is given it is the value to assign to and new elements.
make_unique
Ensure (by copying) that this shared_vector is the sole owner of the data array.
begin,...,rend
Standard iterators.
front
Return a reference to the first element.
back
Return a reference to the last element.
push_back
Add an element to the end of the array.
pop_back
Remove an element from the end of the array.
data
Return a pointer to the raw array.
operator[](size_t i)
Return a reference to the specified element.
at
Like the previous except that it throws a range-error if the specified element is out of range.
operator=
Copy an existing shared_vector.
swap
Swap the contents of this vector with another.
clear
Clear contents.
unique
returns (true,false) if data (is not, is) shared.
size
Number of elements visible through this vector.
empty
Is the number of elements zero?
slice
Reduce the view of this shared_vector.
dataPtr
A read-only shared_ptr to the array.
dataOffset
Offset in the data array of first visible element.
dataCount
Number of visible elements between dataOffset and end of data.
dataTotal
The total number of elements between dataOffset and the end of data

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

status.h

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

class Status : public epics::pvData::Serializable {
    public:
   enum StatusType { 
         /** Operation completed successfully. */
         STATUSTYPE_OK,
         /** Operation completed successfully, but there is a warning message. */
         STATUSTYPE_WARNING,
         /** Operation failed due to an error. */
         STATUSTYPE_ERROR,
         /** Operation failed due to an unexpected error. */
         STATUSTYPE_FATAL
    }; 
    static const char* StatusTypeName[];
    static Status Ok;
    Status();
    Status(StatusType type, std::string const & message);
    Status(StatusType type, std::string const & message, std::string stackDump);
    ~Status()
    StatusType getType() const;
    std::string getMessage() const;
    std::string getStackDump() const;
    bool isOK() const;
    bool isSuccess() const;
    void serialize(ByteBuffer *buffer, SerializableControl *flusher) const;
    void deserialize(ByteBuffer *buffer, DeserializableControl *flusher);
    void dump(std::ostream& o) const;
};

The Status methods are:

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

The StatusCreate methods are:

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

templateMeta.h

TBD Michael will explain.

thread.h

ThreadPriority

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

Thread

class Thread;
typedef std::tr1::shared_ptr<Thread> ThreadPtr;
typedef std::tr1::shared_ptr<epicsThread> EpicsThreadPtr;

class Runnable {
public:
    virtual void run() = 0;
};

class Thread;

class Thread : public epicsThread, private NoDefaultMethods {
public:
    Thread(
        std::string name,
        ThreadPriority priority,
        Runnable *runnableReady,
        epicsThreadStackSizeClass stkcls=epicsThreadStackSmall);
    ~Thread();
 ...
};

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

Thread has the methods:

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

timeFunction.h

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

class TimeFunctionRequester;
class TimeFunction;
typedef std::tr1::shared_ptr<TimeFunctionRequester> TimeFunctionRequesterPtr;
typedef std::tr1::shared_ptr<TimeFunction> TimeFunctionPtr;
        
class TimeFunctionRequester {
public:              
    POINTER_DEFINITIONS(TimeFunctionRequester);
    virtual ~TimeFunctionRequester(){}
    virtual void function() = 0;
};  

    
class TimeFunction {
public:    
    POINTER_DEFINITIONS(TimeFunction);
    TimeFunction(TimeFunctionRequesterPtr const & requester);
    ~TimeFunction(); 
    double timeCall();
 ...
};      

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

function
This is the function.

TimeFunction has the methods:

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

timer.h

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

class TimerCallback;
class Timer;
typedef std::tr1::shared_ptr<TimerCallback> TimerCallbackPtr;
typedef std::tr1::shared_ptr<Timer> TimerPtr;


class TimerCallback {
public:
    POINTER_DEFINITIONS(TimerCallback);
    TimerCallback();
    virtual ~TimerCallback(){}
    virtual void callback() = 0;
    virtual void timerStopped() = 0;
};

class Timer : private Runnable {
public:
    POINTER_DEFINITIONS(Timer);
    Timer(std::string threadName, ThreadPriority priority);
    virtual ~Timer();
    virtual void run();
    void scheduleAfterDelay(
        TimerCallbackPtr const &timerCallback,
        double delay);
    void schedulePeriodic(
        TimerCallbackPtr const &timerCallback,
        double delay,
        double period));
    void cancel(TimerCallbackPtr const &timerCallback);
    bool isScheduled(TimerCallbackPtr const &timerCallback);
    void dump(std::ostream& o);
 ...
};

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

callback
This is called when a timer expires. This is called with no locks held. When called a delay timer is no longer on the queue but a periodic 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 explanation of TimerNode.cancel below.
timerStopped
Timer.stop was called when a timer request was queued. or if the timer is stopped and a schedule request is made.

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

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

Timer has the methods:

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

typeCast.h

TBD Michael will explain.

src/pvMisc

bitSetUtil.h

The following is also provided:

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

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

compress
Compress the bits in a BitSet related to a structure.
For each structure:
  1. If the bit for the structure is set then the bit for all subfields of the structure are cleared.
  2. 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.
Note that this is a recursive algorithm. That is if every immediate subfield has it's offset bit set then the bits for ALL fields that reside in the structure will be cleared.
Channel Access can call this before sending data. It can then pass entire structures if the structure offset bit is set.

src/copy and src/monitor

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

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

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

Copy provides:

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

src/copy

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

createRequest

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

The definition of the public members is:

class CreateRequest {
...
     static CreateRequestPtr create();
     virtual PVStructurePtr createRequest(std::string const &request);
     std::string getMessage();
};

An example of how it is used is:

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

pvCopy

The definition of the public members is:

class epicsShareClass PVCopyTraverseMasterCallback
{
...
    virtual void nextMasterPVField(PVFieldPtr const &pvField);
};

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

src/monitor

This consists of two components:

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

monitor

class MonitorElement {
    MonitorElement(PVStructurePtr const & pvStructurePtr);
    PVStructurePtr pvStructurePtr;
    BitSetPtr changedBitSet;
    BitSetPtr overrunBitSet;
};

class Monitor {
    virtual Status start() = 0;
    virtual Status stop() = 0;
    virtual MonitorElementPtr poll() = 0;
    virtual void release(MonitorElementPtr const & monitorElement) = 0;
};

class MonitorRequester : public virtual Requester {
    virtual void monitorConnect(Status const & status,
        MonitorPtr const & monitor, StructureConstPtr const & structure) = 0;
    virtual void monitorEvent(MonitorPtr const & monitor) = 0;
    virtual void unlisten(MonitorPtr const & monitor) = 0;
};

monitorElement

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

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

monitorElement queue

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

typedef Queue<MonitorElement> MonitorElementQueue;
typedef std::tr1::shared_ptr<MonitorElementQueue> MonitorElementQueuePtr;

class MultipleElementQueue :
    public ElementQueue
{
public:
    POINTER_DEFINITIONS(MultipleElementQueue);
    virtual ~MultipleElementQueue(){}
    MultipleElementQueue(
        MonitorLocalPtr const &monitorLocal,
        MonitorElementQueuePtr const &queue,
        size_t nfields);
    virtual void destroy(){}
    virtual Status start();
    virtual Status stop();
    virtual bool dataChanged();
    virtual MonitorElementPtr poll();
    virtual void release(MonitorElementPtr const &monitorElement);
...
};

Monitor

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

Monitor has the following methods:

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

MonitorRequester

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

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

monitorPlugin

class MonitorPlugin
{
    virtual std::string const & getName() = 0;
    virtual bool causeMonitor(
        PVFieldPtr const &pvField,
        PVStructurePtr const &pvTop,
        MonitorElementPtr const &monitorElement) = 0;
    virtual void monitorDone(
        MonitorElementPtr const &monitorElement);
    virtual void startMonitoring();
    virtual void stopMonitoring();
    virtual void beginGroupPut();
    virtual void endGroupPut();
};

class MonitorPluginCreator
{
    virtual MonitorPluginPtr create(
        FieldConstPtr const &field,
        StructureConstPtr const &top,
        PVStructurePtr const &pvFieldOptions) = 0;
     virtual std::string const & getName() = 0;
}

class MonitorPluginManager
{
    static MonitorPluginManagerPtr get();
    bool addPlugin(
         std::string const &pluginName,
         MonitorPluginCreatorPtr const &creator);
    MonitorPluginCreatorPtr findPlugin(std::string const &pluginName);
    void showNames();
};

MonitorPlugin

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

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

MonitorPluginCreator

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

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

MonitorPluginManager

MonitorPluginManager has the methods:

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

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

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

monitorPlugin example

Example Plugin Overview

This section describes an example plugin that:

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

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

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

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

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

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

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

std::string request("field(alarm[plugin=onChange]");
request += ",timeStamp[plugin=onChange,raiseMonitor=false]";
request += ",power.value[plugin=onChange";
request += ",voltage.value[plugin=onChange";
request += ",current.value[plugin=onChange";

PVStructurePtr pvRequest = createRequest->createRequest(request);

MonitorPtr monitor = channel->createMonitor(monitorRequester,pvRequest);

Example Plugin Code

The header file to create the example has the definition:

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

The implementation is:

class OnChangePlugin : public MonitorPlugin
{
public:
    virtual ~OnChangePlugin(){}
    OnChangePlugin() {}
    bool init(
        FieldConstPtr const &field,
        StructureConstPtr const &top,
        PVStructurePtr const &pvFieldOptions)
   {
        pvField = getPVDataCreate()->createPVField(field);
        raiseMonitor = true;
        if(pvFieldOptions!=NULL) {
            PVStringPtr pvString =
                pvFieldOptions->getSubField<PVString>("raiseMonitor");
                if(pvString!=NULL) {
                    std::string value = pvString->get();
                    if(value.compare("false")==0) raiseMonitor = false;
                }
        }
        return true;
   }
   virtual std::string &getName(){return pluginName;}
   virtual bool causeMonitor(
        PVFieldPtr const &pvNew,
        PVStructurePtr const &pvTop,
        MonitorElementPtr const &monitorElement)
   {
       bool isSame = convert->equals(pvNew,pvField);
       if(isSame) return false;
       convert->copy(pvNew,pvField);
       return raiseMonitor;
   }
private:
   PVFieldPtr pvField;
   bool raiseMonitor;
};
class OnChangePluginCreator : public MonitorPluginCreator
{
public:
    virtual std::string &getName(){return pluginName;}
    virtual MonitorPluginPtr create(
        FieldConstPtr const &field,
        StructureConstPtr const &top,
        PVStructurePtr const &pvFieldOptions)
   {
       OnChangePluginPtr plugin(new OnChangePlugin());
       bool result = plugin->init(field,top,pvFieldOptions);
       if(!result) return MonitorPluginPtr();
       return plugin;
   }

};

void ExampleMonitorPlugin::create()
{
    static OnChangePluginCreatorPtr plugin;
    static Mutex mutex;
    Lock xx(mutex);
    if(plugin==NULL) {
        plugin = OnChangePluginCreatorPtr(new OnChangePluginCreator());
        MonitorPluginManager::get()->addPlugin(pluginName,plugin);
    }
}