V4 Design: epicsTypes
EPICS: epicsTypes
June 3 2005
Overview
This document describes the C++ definitions for storing data that can be accessed without pre-complied code, i.e. it has self describing features.
epicsTypes can be used by any code that stores data accessable via V4 Channel Access.
Some examples are:
- IOC records - Most data accessable from outside record support is stored as an epicsType.
- Channel Access Gateway - Can be used to store and transfer data.
- Channel Access Clients - Can be used to get/receive data from CA server.
Standard support can be provided to access, via dataAccess, epicsType data. For example standard support can be provided to move IOC record data between record instances and a Channel Access server.
epicsType is an enum that defines the following:
- epicsTypeUnknown - Type is unknown
- epicsTypeBoolean - true or false
- epicsTypeOctet - An eight bit byte. It is NOT an integer type
- epicsTypeInt16 - 16 bit signed integer
- epicsTypeInt32 - 32 bit signed integer
- epicsTypeInt64 - 64 bit signed integer
- epicsTypeFloat32 - 32 bit IEEE float
- epicsTypeFloat64 - 64 bit IEEE float
- epicsTypeString - A UTF-8 Encoded Character String
- epicsTypeArray - One dimensional array of any epicsType
- epicsTypeMDArray - Multidimensional array of type epicsTypeBoolean,..epicsTypeFloat64, or epicsTypeString.
- epicsTypeEnum - An index and associated set of choice strings.
- epicsTypeBitmask - A bit mask
- epicsTypeStruct - A structure with fields each of which is any epicsType
The actual types associated with the epicsTypes are:
typedef bool epicsBoolean; typedef char epicsOctet; typedef short epicsInt16; typedef int epicsInt32; typedef long long epicsInt64; typedef float epicsFloat32; typedef double epicsFloat64;
//EpicsString holds UTF-8 characters class EpicsString; // see below for details;
class EpicsArray; // see below for details;
class EpicsMDArray; // see below for details;
class EpicsEnum; // see below for details;
class EpicsBitmask; // see velow for details
class EpicsStruct; // see below for details;
NOTE: In this document primitive type means one of epicsBoolean, epicsOctet, epicsInt16, epicsInt32, epicsInt64, epicsFloat32, or epicsFloat64.
epicsTypes
epicsTypes.h contains the following:
/* The following may require OSD definitions*/ typedef bool epicsBoolean; typedef char epicsOctet; typedef short epicsInt16; typedef int epicsInt32; typedef long long epicsInt64; typedef float epicsFloat32; typedef double epicsFloat64; enum epicsType { epicsTypeUnknown, epicsTypeBoolean, epicsTypeOctet, epicsTypeInt16, epicsTypeInt32, epicsTypeInt64, epicsTypeFloat32, epicsTypeFloat64, epicsTypeString, epicsTypeArray, epicsTypeMDArray, epicsTypeEnum, epicsTypeBitmask, epicsTypeStruct };
epicsTypes provides classes for describing data that can be introspected
and can be passed between different platforms.
All data that is sent to or received from EPICS records will be composed
of epicsTypes.
The types epicsBoolean, ..., epicsFloat64 all map to a C++ standard type. It may be necessary to provide operating system dependent definitions for some of the types. For example on some architectures an epicsInt64 may have to be defined as a long rather than a long long.
epicsTypeUnknown is for anything that is not one of the other epicsTypes.
The non-primitive type, except, epicsTypeUnknown are designed so that the data they contain can be described, introspected, and passed over a network. Each is described in the following sections.
Locking Issues
epicsTypes does not provide any facilities for preventing simultaneous access by multiple threads. For example the class definitions for non-primitive types, i.e. epicsString, epicsArray, epicsStruct, and epicsMDArray, all provide a method expose which returns the address of data. In order to make expose safe, some rules must be established.
As an example of rules, a lock can be associated with each object that supports expose. Code can only call expose and access the exposed data while it holds the lock.
The rules are not specified by epicsTypes since they are application dependent.
epicsString
epicsString.h contains the following:
class EpicsUTF_8Buffer; //EpicsString holds UTF-8 characters class EpicsString : public EpicsUTF_8Buffer { public: EpicsString(); EpicsString(const char *charString); EpicsString(const char *bufferType,epicsInt32 capacity); EpicsString(epicsInt16 bufferTypeId,epicsInt32 capacity); ~EpicsString(); EpicsString(const EpicsString &e); EpicsString& operator=(const EpicsString &rhs); void allocateBuffer(const char *bufferType); void allocateBuffer(epicsInt16 bufferTypeId); void allocateBuffer(const char *bufferType,epicsInt32 capacity) void allocateBuffer(epicsInt16 bufferTypeId,epicsInt32 capacity); protected: EpicsUTF_8Buffer *pbuffer; };
struct EpicsStringSegment { epicsInt32 noctets; epicsOctet *pdata; };
class EpicsUTF_8Buffer { // interface public: virtual epicsInt32 allocate(epicsInt32 capacity) = 0; virtual void release(bool onlyStorage) = 0; virtual epicsInt32 capacity() = 0; virtual epicsInt32 noctets() = 0; virtual void noctets(epicsInt32 n) = 0; virtual bool mutable() = 0; virtual epicsInt32 get(epicsOctet *pto, epicsInt32 noctets, epicsInt32 offset = 0) = 0; virtual epicsInt32 put(const epicsOctet *pfrom, epicsInt32 noctets, epicsInt32 offset = 0) = 0; virtual bool isEqual(const EpicsUTF_8Buffer &buffer) = 0; virtual bool isEqual(const epicsOctet *pdata, epicsInt32 offset, epicsInt32 noctets) = 0; virtual bool expose(epicsInt32 offset, epicsInt32 noctets, EpicsStringSegment &segment) = 0; virtual epicsInt32 hash(epicsInt16 nBitsHashIndex) = 0; };
typedef EpicsUTF_8Buffer *(EpicsUTF_8BufferAllocate)(); class EpicsUTF_8BufferFactory { public: static EpicsUTF_8Buffer *allocate(const char *type); static epicsInt16 typeToTypeID(const char *type); static EpicsUTF_8Buffer *allocate(epicsInt16 typeId); static void register(const char *type, EpicsUTF_8BufferAllocate allocater); };
An EpicsString is an instance of an epicsTypeString.
It contains a UTF-8 encoded string, i.e. multiple octets may be needed to store
a single character.
As long as it does not assume that each character is a single byte,
most code can just ignore the fact that the string is UTF-8 encoded.
If the local computer has been internationalized for the particular UTF-8
encoding then the string can be printed via the printf family of methods.
EpicsString has the following methods:
- EpicsString
- Several constructors are provided. If the default constructor is called then, one of the allocate methods must be called. If charString constructor is called then a default buffer type is chosen. If a buffer type is specified then EpicsUTF_8BufferFactory:allocate is called to initialize pbuffer. If capacity is also specified EpicsUTF_8Buffer:allocate is called to allocate storage for data.
- ~EpicsString()
- The descructor will release the EpicsUTF_8Buffer if it has been allocated.
- void allocateBuffer
- These methods allocate an EpicsUTF_8Buffer and if capacity is specified call EpicsUTF_8Buffer:allocate.
EpicsString implements interface EpicsUTF_8Buffer. If an EpicsUTF_8Buffer has not been allocated all methods raise an exceptioon. If an EpicsUTF_8Buffer has been allocated it calls the associated EpicsUTF_8Buffer method.
EpicsUTF_8Buffer
A string buffer is a container for a UTF_8 encoded character string.
Multiple string buffer implementations are available. At least the following are available:
- contiguous - The string is stored in a contiguous set of octets.
- segmented - The string is stored in chunks. This form should be used for strings that are constantly modified.
Additional implementations can be provided. For example special implementations may be provided for managing network buffers.
A string buffer can only be accessed via interface EpicsUTF_8Buffer. In addition to holding storage for a string, a string buffer keeps the following information.
- capacity
- The number of octets allocated. Note that this is NOT the number of characters since a UTF-8 character may require several octets.
- noctets
- The current size, i.e. the number of octets currently stored in the buffer.
- mutable
- Can the string be modified? The default is true.
Implementation Note Code must always set noctets so that it is at the end of a complete character.
EpicsUTF_8Buffer has the following methods:
- allocate
- Allocate space for up to capacity octets. The number of octets allocated is returned. An implementation attempts to allocate the requested capacity but some implementations, e.g. network buffers, may impose a maximum size. If capacity is not zero when this is called and new storage is allocated then the old storage is freed or reused and the octets spanned by position, limit appear in the newly allocated storage.
- release
- Storage for the string is released. If onlyStorage is true then storage for the buffer is also released.
- capacity
- returns the capacity
- noctets
- Two methods are available, one to get the current noctets and one to set the noctets.
- mutable
- Can the buffer be modified, i.e. are puts allowed.
- get
- copies characters starting at offset to pto and returns the number of octets transfered. Complete characters are always copied.
- put
- copies characters from pfrom, puts them into the buffer starting at offset, and returns the number of octets transfered. The internal noctets value is modified.
- isEqual(EpicsUTF_8Buffer *)
- Compares the string stored in the buffer with a string stored in a different buffer. This is normally called by code that uses an EpicsUTF_8Buffer.
- isEqual(epicsOctet &string, epicsInt32 offset, epicsInt32 len)
- Compares the string stored in the buffer with a string supplied by the caller. This is normally called by EpicsUTF_8Buffer itself to compare it's string with the string stored in another buffer.
- expose
- A request to return the address of actual octets of storage. Since a buffer implementation may used segmented memory the number of octets exposed may be less than the amount requested.
- hash
- implement a hash on the octets stored in the buffer.
expose Notes
expose is provided for efficiency. The caller must follow some conventions:
- Must not modify the data if mutable is false.
- Must call pbuffer->noctets(n) if the noctets is modified.
- Must never access storage outside the noctets returned by expose. The caller may have to make multiple expose calls to read or write a complete string.
- Must never set noctets so that it specifies a partial character.
EpicsUTF_8BufferFactory
This is a class for allocating an EpicsUTF_8Buffer and also for registering EpicsUTF_8Buffer implementations. Note that allocating a buffer is different than allocating storage for the data that is stored in the buffer.
epicsArray
epicsArray.h contains the following:
class EpicsArrayBuffer;
class EpicsArray : public EpicsArrayBuffer{ EpicsArray(epicsType type); virtual ~EpicsArray(); EpicsArray(epicsType type,const char *bufferType); EpicsArray(epicsType type,epicsInt16 bufferTypeId); EpicsArray(epicsType type, const char *bufferType,,epicsInt32 capacity); virtual EpicsArray(epicsType type, epicsInt16 bufferTypeId,,epicsInt32 capacity); void allocateBuffer(const char *bufferType); void allocateBuffer(epicsInt16 bufferTypeId); void allocateBuffer(const char *bufferType, epicsInt16 elementSize, epicsInt32 capacity) void allocateBuffer(epicsInt16 bufferTypeId, epicsInt16 elementSize, epicsInt32 capacity) epicsType getType(); epicsInt16 getElementSize(); protected: epicsType type; epicsInt16 elementSize; private: EpicsArray(); // no default constructor EpicsArray(const EpicsArray &); // copy not allowed EpicsArray(const EpicsArray *); // copy not allowed };
struct EpicsArraySegment { epicsInt32 nelements; void * pdata; };
class EpicsArrayBuffer { public: virtual epicsInt32 allocate( epicsInt32 capacity,epicsInt16 elementSize) = 0; virtual void release(bool onlyStorage) = 0; virtual epicsInt32 capacity() = 0; virtual epicsInt32 elementSize() = 0; virtual epicsInt32 length() = 0; virtual void length(epicsInt32 newLength) = 0; virtual bool mutable() = 0; virtual epicsInt32 get(void *pto, epicsInt32 offset, epicsInt32 nelements) = 0; virtual epicsInt32 put(const void *pfrom, epicsInt32 offset, epicsInt32 nelements) = 0; virtual void expose(epicsInt32 offset, epicsInt32 nelements, EpicsArraySegment &segment) = 0; };
typedef EpicsArrayBuffer *(EpicsArrayBufferAllocate)(); class EpicsArrayBufferFactory { public: static EpicsArrayBuffer *allocate(const char *type); static epicsInt16 typeToTypeID(const char *type); static EpicsArrayBuffer *allocate(epicsInt16 typeId); static void register(const char *type, EpicsArrayBufferAllocate allocater); };
An EpicsArray is an instance of an epicsTypeArray.
It can contain an array of any epicsType.
EpicsArray has the following methods:
- EpicsArray
- Several constructors are available. All require an epicsType. If no buffer type is specified then, one of the allocate methods must be called. If a buffer type is specified then EpicsArrayBufferFactory:allocate is called to initialize pbuffer. If capacity is also specified EpicsArrayBuffer:allocate is called to allocate storage for data.
- ~EpicsArray
- The descructor will release the EpicsArrayBuffer if it has been allocated.
- void allocateBuffer
- These methods allocate an EpicsArrayBuffer and if capacity is specified call EpicsArrayBuffer:allocate.
EpicsArray implements interface EpicsArrayBuffer. If an EpicsArrayBuffer has not been allocated all methods raise an exceptioon. If an EpicsArrayBuffer has been allocated it calls the associated EpicsArrayBuffer method.
EpicsArrayBuffer
Multiple array buffer implementations are available. An implementation can provide the following semantics:
- contiguous - The array is stored in contiguous storage.
- segmented - The array is stored in chunks. This form should be used for arrays that are constantly modified.
- circular - The storage is contiguous but the data is stored as a circular buffer.
Since the fields can be of type epicsTypeArray arrays of arrays are supported. This is analogous to multidimensional arrays in Java.
An array buffer can only be accessed via interface EpicsArrayBuffer. In addition to holding storage for the array an array buffer keeps the following information.
- capacity
- The number of elements for which storage is allocated.
- elementSize
- the number of bytes for each element
- length
- The current number of elements.
- mutable
- Can the data be modified? The default is true.
EpicsArrayBuffer has the following methods:
- allocate
- This allocates space for up to capacity elements. The number of elements allocated is returned. An implementation attempts to allocate the requested capacity but some implemenations, e.g. network buffers, may impose a maximum size. If capacity is not zero when this is called and new storage is allocated then the old storage is freed or reused and the elements spanned by position, limit appear in the newly allocated storage.
- release
- Storage for the array is released. If onlyStorage is true then the storage for the buffer itself is also released.
- capacity
- return the capacity
- elementSize
- return the elementSize.
- length
- Two methods are available, one to get the current length and one to set the length.
- mutable
- Can the array be modified? The default is true.
- get
- copies elements to pto and returns the number of elements transfered.
- put
- copies elements from pfrom, puts them into the buffer, and returns the number of elements transfered. The internal length is modified.
- expose
- A request to return the address of actual storage. Since a buffer implementation may used segmented memory the amount of storage exposed may be less than the amount requested.
expose Notes
expose is provided for efficiency. The caller must follow some conventions:
- Must not modify the data if mutable is false.
- Must call pbuffer->length(newLength) if the length is modified.
- Must never access storage outside the limit returned by expose. The caller may have to make multiple expose calls to read or write a complete string.
- If the buffer is a circular buffer, an exception may be thrown if expose is called.
EpicsArrayBufferFactory
This is a class for allocating an EpicsArrayBuffer and also for registering EpicsArrayBuffer implementations. Note that allocating a buffer is different than allocating storage for the data that is stored in the buffer.
epicsMDArray
An EpicsMDArray is an instance of an epicsTypeMDArray It specifies the element type, has the address of the array description, type and has an associated buffer that holds the storage for the array.
epicsTypeMDArray, i.e. multidimensional array data, is a supported type, because collection and display of two and three dimensional images is a common requirement.
An EpicsMDArray can only hold primitive or string data. Thus it can be any of the types epicsTypeBoolean, ..., epicsTypeString but it can not be type epicsTypeUnknown, epicsTypeArray, epicsTypeStruct, or epicsTypeMDArray.
epicsMDArray.h contains the following:
class EpicsMDArraySlice;
class EpicsMDArray : public EpicsArrayBuffer { EpicsMDArray(epicsType type,epicsInt16 ndim); virtual ~EpicsMDArray(); EpicsMDArray(epicsType type,epicsInt16 ndim,const char *bufferType); EpicsMDArray(epicsType type,epicsInt16 ndim,epicsInt16 bufferTypeId); EpicsMDArray(epicsType type,epicsInt16 ndim, const char *bufferType,,epicsInt32 capacity); EpicsMDArray(epicsType type,epicsInt16 ndim, epicsInt16 bufferTypeId,,epicsInt32 capacity); void allocateBuffer(const char *bufferType); void allocateBuffer(epicsInt16 bufferTypeId); void allocateBuffer(const char *bufferType, epicsInt16 elementSize, epicsInt32 capacity) void allocateBuffer(epicsInt16 bufferTypeId, epicsInt16 elementSize, epicsInt32 capacity) epicsType getType(); epicsInt16 getElementSize(); protected: epicsType type; epicsInt16 elementSize; EpicsMDArraySlice *pslice; EpicsMDArrayBuffer *pbuffer; private: EpicsMDArray(); // no default constructor EpicsMDArray(const EpicsMDArray &); // copy not allowed EpicsMDArray(const EpicsMDArray *); // copy not allowed };
class EpicsMDArrayIndex { public epicsInt32 low; epicsInt32 high; }; class EpicsMDArraySlice { public: epicsType type; epicsInt16 ndim; // number of dimensions EpicsMDArrayIndex *paindex; // addr of array of EpicsMDArrayIndex };
EpicsMDArray
An EpicsMDArray is an instance of an epicsTypeMDArray. It can contain an array of any epicsType.
EpicsMDArray has the following methods:
- EpicsMDArray
- Several constructors are available. All require an epicsType and the number ofdimensions. If no buffer type is specified then, one of the allocate methods must be called. If a buffer type is specified then EpicsArrayBufferFactory:allocate is called to initialize pbuffer. If capacity is also specified EpicsArrayBuffer:allocate is called to allocate storage for data.
- ~EpicsMDArray
- The descructor will release the EpicsArrayBuffer if it has been allocated.
- void allocateBuffer
- These methods allocate an EpicsArrayBuffer and if capacity is specified call EpicsArrayBuffer:allocate.
EpicsMDArray implements interface EpicsArrayBuffer. If an EpicsArrayBuffer has not been allocated all methods raise an exceptioon. If an EpicsArrayBuffer has been allocated it calls the associated EpicsArrayBuffer method.
EpicsArrayBuffer Notes
EpicsMDArray uses the same buffer interface as EpicsArray. Code that accesses a multidimensional array should be prepared to access both contiguous and segmented buffer implementations. Circular buffer implementations may not make sense.
EpicsMDArraySlice
EpicsMDArraySlice has the following fields:
- type
- The element type which must be one of bool,...,string
- ndim
- The number of dimensions
- paindex
- addr of array(ndim) of EpicsMDArrayIndex
EpicsMDArrayIndex has the fields:
- low
- high
The definitions describe a "slice" of a multi-dimensional array.
EpicsEnum
An EpicsEnum is a 16-bit index value, with an interface to convert between choice strings and their index values.
class EpicsEnumChoices { public: virtual EpicsEnumChoices *duplicate() const = 0; virtual void release() = 0; virtual epicsInt16 nChoices() const = 0; virtual epicsInt16 index(const EpicsString &choice) const = 0; virtual void choice(epicsInt16 index, EpicsString &choice) const = 0; }; class EpicsEnum { public: enum {invalid = -1}; EpicsEnum(); EpicsEnum(const EpicsEnum &e); EpicsEnum(EpicsEnumChoices *choices); EpicsEnum(EpicsEnumChoices *choices, epicsInt16 index); virtual ~EpicsEnum(); EpicsEnum& operator=(const EpicsEnum &rhs); virtual void choices(EpicsEnumChoices *pchoices); EpicsEnumChoices *choices() const { return pchoices; } epicsInt16 nChoices() const { return pchoices ? pchoices->nChoices() : 0; } epicsInt16 get() const { return index; } virtual void get(EpicsString &choice) const; virtual void put(epicsInt16 index); virtual void put(const EpicsString &choice); protected: EpicsEnumChoices *pchoices; epicsInt16 index; };
EpicsBitmask
An EpicsBitmask defines a bit mask that is any multiple of eight bits. It allows the caller to set of up to 64 conescutive bits at a time.
class EpicsBitmask { public: EpicsBitmask(); // default will be 4 octets EpicsBitmask(epicsInt32 nbits); virtual ~EpicsBitmask(); EpicsBitmask(const EpicsBitmask &); EpicsBitmask& operator=(const EpicsBitmask &rhs); virtual epicsInt32 getNbits(); virtual epicsInt32 get(epicsInt32 nbits, epicsInt32 mask, epicsInt32 offset = 0); virtual void set(epicsInt32 value,epicsInt32 nbits, epicsInt32 mask, epicsInt64 offset); protected: epicsOctet *paoctets; // address of an array of octets };
epicsStruct
epicsStruct.h contains the following:
class EpicsStructDescription; class EpicsStructManager;
class EpicsStruct{ EpicsStruct(EpicsStructDescription &structDef); ~EpicsStruct(); protected: EpicsStructDescription *pstructDef; void *pstorage; private: EpicsStruct(); // no default cobstructor };
struct EpicsStringDefaults { // defaults for string const char * bufferType; epicsInt32 capacity; };
struct EpicsArrayDefaults { // defaults for array epicsType type; const char * bufferType; epicsInt32 capacity; epicsInt32 nelements; };
struct EpicsEnumDefaults { // defaults for enum ??? };
struct EpicsBitMaskDefaults { // defaults for enum ??? };
struct EpicsMDArrayDefaults { // defaults for mdarray epicsType type; epicsInt16 ndim const char *bufferType; epicsInt32 capacity; };
struct EpicsStructDefaults { // defaults for struct EpicsStructDescription *pdescription; };
class EpicsStructField { public: EpicsString name; epicsType type; union { EpicsStringDefaults *pstring; EpicsArrayDefaults *parray; EpicsMDArrayDefaults *pmdarray; EpicsEnumDefaults *penum; EpicsBitmaskDefaults *pbitmask; EpicsStructDefaults *pstruct; } defaults; }; class EpicsStructDescription{ public: EpicsString name; EpicsStructManager *plifetime; epicsInt16 nfields; EpicsStructField *pafield;//ptr to array of EpicsStructField };
class EpicsStructManager { public: virtual void allocate(EpicsStruct &struct) = 0; virtual void destroy(EpicsStruct &struct) = 0; virtual void *exposeField(EpicsStruct &struct, epicsInt16 index) = 0; };
An epicsStruct is a container with fields each of which is any epicsType including unknown.
The following classes are involved with an epicsStruct:
- EpicsStruct - An instance of an epicsStruct
- EpicsStructDescription - Describes an epicsStruct
- EpicsStructField - Describes a field of an epicsStruct
- EpicsStructDefaults - Provides default values for non-primitive fields. This is intended for code that initializes fields.
- EpicsStructManager - An interface that manages storage for an epicsStruct.
It is expected that each of these classes are extended. In fact if any field of an epicsStruct has type epicsTypeUnknown then it is likely that most will be extended.
epicsTypes does not specify how to locate an EpicsStructManager, i.e. the mechanism is application dependent.
An EpicsStruct contains two fields:
- pstructDef
- Address of a EpicsStructDescription that describes the structure.
- pstorage
- Address of storage for the data contained in the structure.
EpicsStructDescription
EpicsStructDescription has the fields:
- name
- The structure name.
- plifetime
- Address of a EpicsStructManager interface. See below.
- nfields
- The number of fields in the structure.
- pafield
- addresss of an array of EpicsStructField, one for each field.
EpicsStructField
EpicsStructField has the fields:
- name
- The field name.
- type
- The field type, which can be any epicsType.
- defaults
- For each of the non-primitive epicsTypes, default values can be specified. This is for use by code that must initialize field instances.
EpicsStructManager
EpicsStructManager is an interface that has three methods:
- allocate
- This sets pstructDef to the definition for the associated structure and sets pstorage to the address of storage for the fields in the structure.
- destroy
- releases the storage for the structure and sets pstructDef null.
- exposeField
- This returns the address of the storage for the data associated with the field.