diff --git a/.hgtags b/.hgtags index 6d497b9..c7d6a57 100644 --- a/.hgtags +++ b/.hgtags @@ -14,3 +14,7 @@ d70c5ad29163306f50979a95b5aebbe9a93cfe76 2.0-BETA 1348c22b125861ecb9da95b23f20314b167ee155 4.0.0 1348c22b125861ecb9da95b23f20314b167ee155 4.0.0 9c62aaa83b9db6ad69740a6bb46d6529e0e60b78 4.0.0 +9c62aaa83b9db6ad69740a6bb46d6529e0e60b78 4.0.0 +f9f187685032ebf4b108c759be196fda055c9e42 4.0.0 +b0d39d12d743b82038066955db6bb957b1f2f767 4.0.1 +af82285f71aae5d08fa8cf333b03772c5e689aff 4.0.2 diff --git a/configure/CONFIG_SITE b/configure/CONFIG_SITE index 3e3e0d5..64fc0fd 100644 --- a/configure/CONFIG_SITE +++ b/configure/CONFIG_SITE @@ -20,8 +20,8 @@ CHECK_RELEASE = YES # INSTALL_LOCATION here. #INSTALL_LOCATION= +-include $(TOP)/../CONFIG_SITE.local -include $(TOP)/configure/CONFIG_SITE.local --include $(TOP)/../CONFIG.local ifdef WITH_COVERAGE USR_CPPFLAGS += --coverage diff --git a/documentation/pvDataCPP.html b/documentation/pvDataCPP.html index c430a2c..a60e561 100644 --- a/documentation/pvDataCPP.html +++ b/documentation/pvDataCPP.html @@ -37,7 +37,7 @@

EPICS pvDataCPP

-

EPICS v4 Working Group, Working Draft, 08-Oct-2014

+

EPICS v4 Working Group, Working Draft, 10-Nov-2014

Latest version:
@@ -46,11 +46,11 @@
This version:
pvDataCPP_20140723.html + href="pvDataCPP_20141110.html">pvDataCPP_20141110.html
Previous version:
pvDataCPP_20140708.html + href="pvDataCPP_20140723.html">pvDataCPP_20140723.html
Editors:
Marty Kraimer, BNL
@@ -79,7 +79,7 @@ V4 control system programming environment:

Status of this Document

-

This is the 08-Oct-2014 version of the C++ implementation of pvData. +

This is the 10-Nov-2014 version of the C++ implementation of pvData.

RELEASE_NOTES.md provides changes since the last release. @@ -2662,12 +2662,6 @@ objects:

convert.h

-

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

-

This section describes the supported conversions between data types.

-
  • Copy between PVArrays that satisfy one of the following. - -
  • Conversions between numeric scalar types.
  • Conversion between compatible structures.
  • A utility method the returns the full field name of a field
  • diff --git a/documentation/pvDataCPP_20141110.html b/documentation/pvDataCPP_20141110.html new file mode 100644 index 0000000..dc7e2ea --- /dev/null +++ b/documentation/pvDataCPP_20141110.html @@ -0,0 +1,5478 @@ + + + + + + EPICS pvDataCPP + + + + + + + + +
    +

    EPICS pvDataCPP

    + + +

    EPICS v4 Working Group, Working Draft, 10-Nov-2014

    + +
    +
    Latest version:
    +
    pvDataCPP.html +
    +
    This version:
    +
    pvDataCPP_20141110.html +
    +
    Previous version:
    +
    pvDataCPP_20140723.html +
    +
    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 10-Nov-2014 version of the C++ implementation of pvData. +

    + +

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

    + + + +
    +

    Table of Contents

    +
    +
    + +

    Introduction

    + +

    pvData is one of a set of related projects. It describes and implements +data that the other projects support. Thus it is not useful by itself but +understanding pvData is required in order to understand the other projects. The +reader should also become 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
    +
    +    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 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. +
    + Note The template version replaces getBooleanField, etc.
    +
    +
    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

    + +

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

    + +

    This section describes the supported conversions between data types.

    + +
    +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. +
    3. If the bit for the structure is not set but all immediate subfields + have their bit set then the bit for the structure is set and the bits + for all subfields are cleared.
    4. +
    + Note that this is a recursive algorithm. That is if every immediate + subfield has it's offset bit set then the bits for ALL fields that reside + in the structure will be cleared.
    +
    Channel Access can call this before sending data. It can then pass + entire structures if the structure offset bit is set.
    +
    + +

    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);
    +    }
    +}
    +
    + + +
    + + diff --git a/src/copy/createRequest.cpp b/src/copy/createRequest.cpp index 67c246d..6260162 100644 --- a/src/copy/createRequest.cpp +++ b/src/copy/createRequest.cpp @@ -322,149 +322,155 @@ public: virtual PVStructurePtr createRequest( string const & crequest) { - string request = crequest; - if (!request.empty()) removeBlanks(request); - if (request.empty()) - { - return pvDataCreate->createPVStructure(fieldCreate->createStructure()); - } - size_t offsetRecord = request.find("record["); - size_t offsetField = request.find("field("); - size_t offsetPutField = request.find("putField("); - size_t offsetGetField = request.find("getField("); - if(offsetRecord==string::npos - && offsetField==string::npos - && offsetPutField==string::npos - && offsetGetField==string::npos) - { - request = "field(" + request + ")"; - offsetField = request.find("field("); - } - int numParan = 0; - int numBrace = 0; - int numBracket = 0; - for(size_t i=0; i< request.length() ; ++i) { - char chr = request[i]; - if(chr=='(') numParan++; - if(chr==')') numParan--; - if(chr=='{') numBrace++; - if(chr=='}') numBrace--; - if(chr=='[') numBracket++; - if(chr==']') numBracket--; - } - if(numParan!=0) { - ostringstream oss; - oss << "mismatched () " << numParan; - message = oss.str(); - return PVStructurePtr(); - } - if(numBrace!=0) { - ostringstream oss; - oss << "mismatched {} " << numBrace; - message = oss.str(); - return PVStructurePtr(); - } - if(numBracket!=0) { - ostringstream oss; - oss << "mismatched [] " << numBracket; - message = oss.str(); - return PVStructurePtr(); - } - vector top; try { - if(offsetRecord!=string::npos) { - fullFieldName = "record"; - size_t openBracket = request.find('[', offsetRecord); - size_t closeBracket = request.find(']', openBracket); - if(closeBracket==string::npos) { - message = request.substr(offsetRecord) + - "record[ does not have matching ]"; - return PVStructurePtr(); + string request = crequest; + if (!request.empty()) removeBlanks(request); + if (request.empty()) + { + return pvDataCreate->createPVStructure(fieldCreate->createStructure()); + } + size_t offsetRecord = request.find("record["); + size_t offsetField = request.find("field("); + size_t offsetPutField = request.find("putField("); + size_t offsetGetField = request.find("getField("); + if(offsetRecord==string::npos + && offsetField==string::npos + && offsetPutField==string::npos + && offsetGetField==string::npos) + { + request = "field(" + request + ")"; + offsetField = request.find("field("); + } + int numParan = 0; + int numBrace = 0; + int numBracket = 0; + for(size_t i=0; i< request.length() ; ++i) { + char chr = request[i]; + if(chr=='(') numParan++; + if(chr==')') numParan--; + if(chr=='{') numBrace++; + if(chr=='}') numBrace--; + if(chr=='[') numBracket++; + if(chr==']') numBracket--; + } + if(numParan!=0) { + ostringstream oss; + oss << "mismatched () " << numParan; + message = oss.str(); + return PVStructurePtr(); + } + if(numBrace!=0) { + ostringstream oss; + oss << "mismatched {} " << numBrace; + message = oss.str(); + return PVStructurePtr(); + } + if(numBracket!=0) { + ostringstream oss; + oss << "mismatched [] " << numBracket; + message = oss.str(); + return PVStructurePtr(); + } + vector top; + try { + if(offsetRecord!=string::npos) { + fullFieldName = "record"; + size_t openBracket = request.find('[', offsetRecord); + size_t closeBracket = request.find(']', openBracket); + if(closeBracket==string::npos) { + message = request.substr(offsetRecord) + + "record[ does not have matching ]"; + return PVStructurePtr(); + } + if(closeBracket-openBracket > 3) { + Node node("record"); + Node optNode = createRequestOptions( + request.substr(openBracket+1,closeBracket-openBracket-1)); + node.nodes.push_back(optNode); + top.push_back(node); + } } - if(closeBracket-openBracket > 3) { - Node node("record"); - Node optNode = createRequestOptions( - request.substr(openBracket+1,closeBracket-openBracket-1)); - node.nodes.push_back(optNode); + if(offsetField!=string::npos) { + fullFieldName = "field"; + Node node("field"); + size_t openParan = request.find('(', offsetField); + size_t closeParan = request.find(')', openParan); + if(closeParan==string::npos) { + message = request.substr(offsetField) + + " field( does not have matching )"; + return PVStructurePtr(); + } + if(closeParan>openParan+1) { + createSubNode(node,request.substr(openParan+1,closeParan-openParan-1)); + } top.push_back(node); } + if(offsetGetField!=string::npos) { + fullFieldName = "getField"; + Node node("getField"); + size_t openParan = request.find('(', offsetGetField); + size_t closeParan = request.find(')', openParan); + if(closeParan==string::npos) { + message = request.substr(offsetField) + + " getField( does not have matching )"; + return PVStructurePtr(); + } + if(closeParan>openParan+1) { + createSubNode(node,request.substr(openParan+1,closeParan-openParan-1)); + } + top.push_back(node); + } + if(offsetPutField!=string::npos) { + fullFieldName = "putField"; + Node node("putField"); + size_t openParan = request.find('(', offsetPutField); + size_t closeParan = request.find(')', openParan); + if(closeParan==string::npos) { + message = request.substr(offsetField) + + " putField( does not have matching )"; + return PVStructurePtr(); + } + if(closeParan>openParan+1) { + createSubNode(node,request.substr(openParan+1,closeParan-openParan-1)); + } + top.push_back(node); + } + } catch (std::exception &e) { + string xxx = e.what(); + message = "while creating Structure exception " + xxx; + return PVStructurePtr(); } - if(offsetField!=string::npos) { - fullFieldName = "field"; - Node node("field"); - size_t openParan = request.find('(', offsetField); - size_t closeParan = request.find(')', openParan); - if(closeParan==string::npos) { - message = request.substr(offsetField) - + " field( does not have matching )"; - return PVStructurePtr(); + size_t num = top.size(); + StringArray names(num); + FieldConstPtrArray fields(num); + for(size_t i=0; i subNode = node.nodes; + if(subNode.empty()) { + fields[i] = fieldCreate->createStructure(); + } else { + fields[i] = createSubStructure(subNode); } - if(closeParan>openParan+1) { - createSubNode(node,request.substr(openParan+1,closeParan-openParan-1)); - } - top.push_back(node); } - if(offsetGetField!=string::npos) { - fullFieldName = "getField"; - Node node("getField"); - size_t openParan = request.find('(', offsetGetField); - size_t closeParan = request.find(')', openParan); - if(closeParan==string::npos) { - message = request.substr(offsetField) - + " getField( does not have matching )"; - return PVStructurePtr(); - } - if(closeParan>openParan+1) { - createSubNode(node,request.substr(openParan+1,closeParan-openParan-1)); - } - top.push_back(node); - } - if(offsetPutField!=string::npos) { - fullFieldName = "putField"; - Node node("putField"); - size_t openParan = request.find('(', offsetPutField); - size_t closeParan = request.find(')', openParan); - if(closeParan==string::npos) { - message = request.substr(offsetField) - + " putField( does not have matching )"; - return PVStructurePtr(); - } - if(closeParan>openParan+1) { - createSubNode(node,request.substr(openParan+1,closeParan-openParan-1)); - } - top.push_back(node); + StructureConstPtr structure = fieldCreate->createStructure(names, fields); + PVStructurePtr pvStructure = pvDataCreate->createPVStructure(structure); + for(size_t i=0; igetSubField(name); + pvField->put(value); } + optionList.clear(); + return pvStructure; } catch (std::exception &e) { - string xxx = e.what(); - message = "while creating Structure exception " + xxx; - return PVStructurePtr(); + message = e.what(); + return PVStructurePtr(); } - size_t num = top.size(); - StringArray names(num); - FieldConstPtrArray fields(num); - for(size_t i=0; i subNode = node.nodes; - if(subNode.empty()) { - fields[i] = fieldCreate->createStructure(); - } else { - fields[i] = createSubStructure(subNode); - } - } - StructureConstPtr structure = fieldCreate->createStructure(names, fields); - PVStructurePtr pvStructure = pvDataCreate->createPVStructure(structure); - for(size_t i=0; igetSubField(name); - pvField->put(value); - } - optionList.clear(); - return pvStructure; } + }; CreateRequest::shared_pointer CreateRequest::create() diff --git a/testApp/copy/testCreateRequest.cpp b/testApp/copy/testCreateRequest.cpp index 3c0db1c..4df1b89 100644 --- a/testApp/copy/testCreateRequest.cpp +++ b/testApp/copy/testCreateRequest.cpp @@ -30,7 +30,7 @@ static void testCreateRequestInternal() { string request = ""; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); testOk1(pvRequest->getStructure()->getNumberFields()==0); @@ -39,7 +39,7 @@ static void testCreateRequestInternal() { request = "record[]field()getField()putField()"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); testOk1(pvRequest->getSubField("field").get()!=NULL); @@ -50,7 +50,7 @@ static void testCreateRequestInternal() { request = "record[a=b,x=y]field(a) putField(a),getField(a)"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); pvString = pvRequest->getSubField("record._options.a"); @@ -67,7 +67,7 @@ static void testCreateRequestInternal() { request = "field(a.b[x=y])"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); pvString = pvRequest->getSubField("field.a.b._options.x"); @@ -78,7 +78,7 @@ static void testCreateRequestInternal() { request = "field(a.b{c.d})"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); testOk1(pvRequest->getSubField("field.a.b.c.d").get()!=NULL); @@ -87,7 +87,7 @@ static void testCreateRequestInternal() { request = "field(a.b[x=y]{c.d})"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); pvString = pvRequest->getSubField("field.a.b._options.x"); @@ -99,7 +99,7 @@ static void testCreateRequestInternal() { request = "field(a.b[x=y]{c.d[x=y]})"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); pvString = pvRequest->getSubField("field.a.b._options.x"); @@ -113,7 +113,7 @@ static void testCreateRequestInternal() { request = "record[a=b,c=d] field(a.a[a=b]{a.a[a=b]},b.a[a=b]{a,b})"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); pvString = pvRequest->getSubField("field.a.a._options.a"); @@ -133,7 +133,7 @@ static void testCreateRequestInternal() { request = "alarm,timeStamp,power.value"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); testOk1(pvRequest->getSubField("field.alarm").get()!=NULL); @@ -144,7 +144,7 @@ static void testCreateRequestInternal() { request = "record[process=true]field(alarm,timeStamp,power.value)"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); pvString = pvRequest->getSubField("record._options.process"); @@ -158,7 +158,7 @@ static void testCreateRequestInternal() { request = "record[process=true]field(alarm,timeStamp[algorithm=onChange,causeMonitor=false],power{value,alarm})"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); pvString = pvRequest->getSubField("record._options.process"); @@ -179,7 +179,7 @@ static void testCreateRequestInternal() { request = "record[int=2,float=3.14159]field(alarm,timeStamp[shareData=true],power.value)"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); pvString = pvRequest->getSubField("record._options.int"); @@ -201,7 +201,7 @@ static void testCreateRequestInternal() { + "current{value,alarm},voltage{value,alarm})"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); testOk1(pvRequest->getSubField("putField.power.value").get()!=NULL); @@ -221,7 +221,7 @@ static void testCreateRequestInternal() { + "})"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); testOk1(pvRequest->getSubField("field.alarm").get()!=NULL); @@ -243,7 +243,7 @@ static void testCreateRequestInternal() { + ")"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); testOk1(pvRequest->getSubField("putField.power.value").get()!=NULL); @@ -276,7 +276,7 @@ static void testCreateRequestInternal() { request = "a{b{c{d}}}"; if(debug) { cout << "request " << request <createRequest(request); - if(pvRequest.get()==NULL) { cout<< createRequest->getMessage() << endl;} + if(!pvRequest) { cout<< createRequest->getMessage() << endl;} if(debug) { cout << *pvRequest << endl;} testOk1(pvRequest.get()!=NULL); testOk1(pvRequest->getSubField("field.a.b.c.d").get()!=NULL); @@ -302,11 +302,19 @@ static void testCreateRequestInternal() { cout << "reason " << createRequest->getMessage() << endl; testOk1(pvRequest.get()==NULL); testPass("request %s",request.c_str()); + + request = "field(alarm.status,alarm.severity)"; + if(debug) { cout << "request " << request <createRequest(request); + cout << "reason " << createRequest->getMessage() << endl; + testOk1(pvRequest.get()==NULL); + testPass("request %s",request.c_str()); } MAIN(testCreateRequest) { - testPlan(117); + testPlan(119); testCreateRequestInternal(); return testDone(); }