V4 Requirements for Standard Types

From EPICSWIKI

The purpose of this page is to discuss and agree on a set of standard basic data types that will be supported throughout EPICS V4.

epicsTypes.h

This C++ header will include a set of typedefs (OS dependent if necessary) as follows:

epicsBoolean

A boolean type.

typedef bool epicsBoolean;

epicsInt16

A signed 16-bit integer type.

typedef short epicsInt16;

epicsInt32

A signed 32-bit integer type.

typedef int epicsInt32;

epicsInt64

A signed 64-bit integer type.

typedef long long epicsInt64;

On some architectures, this may be defined as:

typedef long epicsInt64;

epicsFloat32

A 32-bit IEEE floating-point numeric type.

typedef float epicsFloat32;

epicsFloat64

A 64-bit IEEE floating-point numeric type.

typedef double epicsFloat64

epicsOctet

An 8-bit character type which may be signed or unsigned depending on the particular platform. This is not intended to be used for numeric operations, just for storing and manipulating raw data bytes, including use for Unicode/UTF-8 encoded strings.

typedef char epicsOctet;

Below here, things become a little more speculative...

EpicsString

A Unicode/UTF-8 encoded string.

Requirements for EpicsString

To be adopted widely, an EpicsString should be usable like any regular C++ type, although we don't need it to be anywhere near as rich as the C++ std::string class. This is my list of requirements for EpicsString:

  1. Must provide a default constructor so instances can be created without any initialization parameters.
  2. Must be able to support different kinds of underlying buffer storage, such as:
    • Read only - immutable, used to hold string literals.
      • The constructor EpicsString(const char *) should create a string that just stores the given pointer as its buffer.
      • Attempts to modify the string will probably throw an exception.
      • On some architectures overwriting a string literal causes a SEGV, so this protection is worth doing to avoid crashes.
    • Fixed capacity - mutable and contiguous, for things like record names that don't get changed after being set.
      • The character buffer is intended to be allocated just once.
      • The string contents can be modified, but cannot be extended beyond the allocated capacity.
    • Variable capacity - mutable and segmented, for strings that might change quite often.
      • Uses a freelist to manage its buffer as a series of string segments.
      • ...
  3. Strings must be assignable (if the target string is mutable).
  4. Assignment never changes the target string's buffer type or capacity, it just copies character data from the source to the target string.
  5. We need to provide access to the underlying character data in a unified way that will work for all buffer types.
    • We've designed an API that works for segmented strings, which the other types can also use.
  6. The EpicsString class must implement a comparison function that works between segmented and non-segmented strings
  7. Strings should also be comparable using operator == and operator !=.
    • However these operators will be non-member functions that takes two const EpicsString& parameters; this permits the LHS to undergo type conversion from a literal.
  8. We're probably not going to provide less-than or greater-than comparisons because the correct ordering of characters is language specific.
    • However this makes it impossible to do binary searches or create tree structures.
    • We might want to revisit this point later.
  9. This list not yet complete...

The above requirements ensure that the following code snippets (or something very like these) will do what it looks like they should do:

EpicsString hello = "World!";  // create a readonly string
EpicsString msg(...);          // create a variable length string
msg = hello;                   // copy the readonly data
if (msg == hello) { ... }      // compare strings
if ("hello" != hello) { ... }  // implicit type conversion

EpicsEnum

A 16-bit index value, with an interface to convert between choice strings and their index values. Here's a proposal:

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 *ib);
    EpicsEnum(EpicsEnumChoices *ib, 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;
}

EpicsBits

A way to store a collection of named bits. This might even be able to reuse EpicsEnumBase to define the bit name to bit number conversion process.