Program Listing for File pvIntrospect.h

Return to documentation for file (src/pv/pvIntrospect.h)

/* pvIntrospect.h */
/*
 * Copyright information and license terms for this software can be
 * found in the file LICENSE that is included with the distribution
 */
#ifndef PVINTROSPECT_H
#define PVINTROSPECT_H

#include <string>
#include <stdexcept>
#include <iostream>
#include <map>

#include <epicsAssert.h>

#include <pv/lock.h>
#include <pv/noDefaultMethods.h>
#include <pv/pvType.h>
#include <pv/byteBuffer.h>
#include <pv/serialize.h>
#include <pv/pvdVersion.h>

#include <shareLib.h>
#define PVD_DEPRECATED_52 PVD_DEPRECATED("See https://github.com/epics-base/pvDataCPP/issues/52")

/* C++11 keywords
 @code
 struct Base {
   virtual void foo();
 };
 struct Class : public Base {
   virtual void foo() OVERRIDE FINAL;
 };
 @endcode
 */
#ifndef FINAL
#  if __cplusplus>=201103L
#    define FINAL final
#  else
#    define FINAL
#  endif
#endif
#ifndef OVERRIDE
#  if __cplusplus>=201103L
#    define OVERRIDE override
#  else
#    define OVERRIDE
#  endif
#endif

namespace epics { namespace pvData {

namespace format {

struct indent_level
{
    long level;

    indent_level(long l) : level(l) {}
};

epicsShareExtern long& indent_value(std::ios_base& ios);

epicsShareExtern std::ostream& operator<<(std::ostream& os, indent_level const& indent);

struct indent_scope
{
    long saved_level;
    std::ios_base& stream;

    indent_scope(std::ios_base& ios) :
        stream(ios)
    {
        long& l = indent_value(ios);
        saved_level = l;
        l = saved_level + 1;
    }

    ~indent_scope()
    {
        indent_value(stream) = saved_level;
    }
};

struct indent
{
};

epicsShareExtern std::ostream& operator<<(std::ostream& os, indent const&);

struct array_at
{
    std::size_t index;

    array_at(std::size_t ix) : index(ix) {}
};

struct array_at_internal
{
    std::size_t index;
    std::ostream& stream;

    array_at_internal(std::size_t ix, std::ostream& str) : index(ix), stream(str) {}
};

epicsShareExtern array_at_internal operator<<(std::ostream& str, array_at const& manip);

};

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

class BoundedString;

class PVField;
class PVScalar;
class PVScalarArray;
class PVStructure;
class PVUnion;
template<typename T> class PVValueArray;

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 Array> ArrayConstPtr;
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;
typedef std::tr1::shared_ptr<const BoundedString> BoundedStringConstPtr;

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

namespace TypeFunc {
    epicsShareExtern const char* name(Type type);
};

epicsShareExtern std::ostream& operator<<(std::ostream& o, const Type& type);


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

#define MAX_SCALAR_TYPE pvString

namespace ScalarTypeFunc {
    epicsShareExtern bool isInteger(ScalarType scalarType);
    epicsShareExtern bool isUInteger(ScalarType scalarType);
    epicsShareExtern bool isNumeric(ScalarType scalarType);
    epicsShareExtern bool isPrimitive(ScalarType scalarType);
    epicsShareExtern ScalarType getScalarType(std::string const &value);
    epicsShareExtern const char* name(ScalarType scalarType);

    epicsShareExtern size_t elementSize(ScalarType id);
};

epicsShareExtern std::ostream& operator<<(std::ostream& o, const ScalarType& scalarType);


class epicsShareClass Field :
    virtual public Serializable,
    public std::tr1::enable_shared_from_this<Field> {
public:
   static size_t num_instances;

   POINTER_DEFINITIONS(Field);
   virtual ~Field();
   Type getType() const{return m_fieldType;}
   virtual std::string getID() const = 0;

    virtual std::ostream& dump(std::ostream& o) const = 0;

    std::tr1::shared_ptr<PVField> build() const;

    enum {isField=1};

protected:
   Field(Type type);
   void cacheCleanup();
private:
   const Type m_fieldType;
   unsigned int m_hash;
   struct Helper;
   friend struct Helper;

   friend class StructureArray;
   friend class Structure;
   friend class PVFieldPvt;
   friend class StandardField;
   friend class BasePVStructureArray;
   friend class FieldCreate;
   EPICS_NOT_COPYABLE(Field)
};

epicsShareExtern std::ostream& operator<<(std::ostream& o, const Field& field);


class epicsShareClass 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 OVERRIDE;

    virtual std::ostream& dump(std::ostream& o) const OVERRIDE FINAL;

    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE;
    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL;

    std::tr1::shared_ptr<PVScalar> build() const;

protected:
    Scalar(ScalarType scalarType);
private:
    static int8 getTypeCodeLUT(ScalarType scalarType);
    ScalarType scalarType;
    friend class FieldCreate;
    friend class ScalarArray;
    friend class BoundedScalarArray;
    friend class FixedScalarArray;
    friend class BoundedString;
    EPICS_NOT_COPYABLE(Scalar)
};

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

    virtual std::string getID() const OVERRIDE FINAL;

    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL;

    std::size_t getMaximumLength() const;

protected:
    BoundedString(std::size_t maxStringLength);
private:
    std::size_t maxLength;
    friend class FieldCreate;
    EPICS_NOT_COPYABLE(BoundedString)
};

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;

protected:
   Array(Type type);

   EPICS_NOT_COPYABLE(Array)
};

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

    ScalarArray(ScalarType scalarType);
    ScalarType getElementType() const {return elementType;}

    virtual ArraySizeType getArraySizeType() const OVERRIDE {return Array::variable;}

    virtual std::size_t getMaximumCapacity() const OVERRIDE {return 0;}

    virtual std::string getID() const OVERRIDE;

    virtual std::ostream& dump(std::ostream& o) const OVERRIDE FINAL;

    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE;
    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL;

     std::tr1::shared_ptr<PVScalarArray> build() const;

    virtual ~ScalarArray();
private:
    const std::string getIDScalarArrayLUT() const;
    ScalarType elementType;
    friend class FieldCreate;
    EPICS_NOT_COPYABLE(ScalarArray)
};



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 OVERRIDE FINAL {return Array::bounded;}

    virtual std::size_t getMaximumCapacity() const OVERRIDE FINAL {return size;}

    virtual std::string getID() const OVERRIDE FINAL;

    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL;

    virtual ~BoundedScalarArray();
private:
    std::size_t size;
    friend class FieldCreate;
    EPICS_NOT_COPYABLE(BoundedScalarArray)
};

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 OVERRIDE FINAL {return Array::fixed;}

    virtual std::size_t getMaximumCapacity() const OVERRIDE FINAL {return size;}

    virtual std::string getID() const OVERRIDE FINAL;

    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL;

    virtual ~FixedScalarArray();
private:
    std::size_t size;
    friend class FieldCreate;
    EPICS_NOT_COPYABLE(FixedScalarArray)
};

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

    const StructureConstPtr& getStructure() const {return pstructure;}

    virtual ArraySizeType getArraySizeType() const OVERRIDE FINAL {return Array::variable;}

    virtual std::size_t getMaximumCapacity() const OVERRIDE FINAL {return 0;}

    virtual std::string getID() const OVERRIDE FINAL;

    virtual std::ostream& dump(std::ostream& o) const OVERRIDE FINAL;

    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL;
    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL;

     std::tr1::shared_ptr<PVValueArray<std::tr1::shared_ptr<PVStructure> > > build() const;

protected:
    StructureArray(StructureConstPtr const & structure);
public:
    virtual ~StructureArray();
private:
    StructureConstPtr pstructure;
    friend class FieldCreate;
    EPICS_NOT_COPYABLE(StructureArray)
};

class epicsShareClass UnionArray : public Array{
public:
    POINTER_DEFINITIONS(UnionArray);
    typedef UnionArray& reference;
    typedef const UnionArray& const_reference;

    UnionConstPtr getUnion() const {return punion;}

    virtual ArraySizeType getArraySizeType() const OVERRIDE FINAL {return Array::variable;}

    virtual std::size_t getMaximumCapacity() const OVERRIDE FINAL {return 0;}

    virtual std::string getID() const OVERRIDE FINAL;

    virtual std::ostream& dump(std::ostream& o) const OVERRIDE FINAL;

    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL;
    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL;

     std::tr1::shared_ptr<PVValueArray<std::tr1::shared_ptr<PVUnion> > > build() const;

protected:
    UnionArray(UnionConstPtr const & _punion);
public:
    virtual ~UnionArray();
private:
    UnionConstPtr punion;
    friend class FieldCreate;
    EPICS_NOT_COPYABLE(UnionArray)
};

class epicsShareClass Structure : public Field {
public:
    POINTER_DEFINITIONS(Structure);

    static const std::string DEFAULT_ID;

    static const std::string & defaultId();

    virtual ~Structure();
    typedef Structure& reference;
    typedef const Structure& const_reference;

    std::size_t getNumberFields() const {return fieldNames.size();}

    FieldConstPtr getField(std::string const &fieldName) const;

    template<typename FT>
    std::tr1::shared_ptr<const FT> getField(std::string const &fieldName) const
    {
        STATIC_ASSERT(FT::isField); // only allow cast from Field sub-class
        return std::tr1::dynamic_pointer_cast<const FT>(getField(fieldName));
    }

    FieldConstPtr getFieldT(std::string const &fieldName) const {return getFieldImpl(fieldName, true);};

    template<typename FT>
    std::tr1::shared_ptr<const FT> getFieldT(std::string const &fieldName) const
    {
        STATIC_ASSERT(FT::isField); // only allow cast from Field sub-class
        std::tr1::shared_ptr<const FT> result(
            std::tr1::dynamic_pointer_cast<const FT>(getFieldT(fieldName))
        );

        if (!result)
            throw std::runtime_error("Wrong Field type");

        return result;
    }

    const FieldConstPtr& getField(std::size_t index) const {return fields.at(index);}

    template<typename FT>
    std::tr1::shared_ptr<const FT> getField(std::size_t index) const
    {
        STATIC_ASSERT(FT::isField); // only allow cast from Field sub-class
        return std::tr1::dynamic_pointer_cast<const FT>(getField(index));
    }

    FieldConstPtr getFieldT(std::size_t index) const {return fields.at(index);}

    template<typename FT>
    std::tr1::shared_ptr<const FT> getFieldT(std::size_t index) const
    {
        STATIC_ASSERT(FT::isField); // only allow cast from Field sub-class
        std::tr1::shared_ptr<const FT> result(
            std::tr1::dynamic_pointer_cast<const FT>(getFieldT(index))
        );

        if (!result)
            throw std::runtime_error("Wrong Field type");

        return result;
    }

    std::size_t getFieldIndex(std::string const &fieldName) const;
    FieldConstPtrArray const & getFields() const {return fields;}
    StringArray const & getFieldNames() const {return fieldNames;}
    const std::string& getFieldName(std::size_t fieldIndex) const {return fieldNames.at(fieldIndex);}

    virtual std::string getID() const OVERRIDE FINAL;

    virtual std::ostream& dump(std::ostream& o) const OVERRIDE FINAL;

    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL;
    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL;

    std::tr1::shared_ptr<PVStructure> build() const;

protected:
    Structure(StringArray const & fieldNames, FieldConstPtrArray const & fields, std::string const & id = defaultId());
private:
    StringArray fieldNames;
    FieldConstPtrArray fields;
    std::string id;

    FieldConstPtr getFieldImpl(const std::string& fieldName, bool throws) const;
    void dumpFields(std::ostream& o) const;

    friend class FieldCreate;
    friend class Union;
    EPICS_NOT_COPYABLE(Structure)
};

class epicsShareClass Union : public Field {
public:
    POINTER_DEFINITIONS(Union);

    static const std::string DEFAULT_ID;

    static const std::string & defaultId();

    static const std::string ANY_ID;

    static const std::string & anyId();

    virtual ~Union();
    typedef Union& reference;
    typedef const Union& const_reference;

    std::size_t getNumberFields() const {return fieldNames.size();}

    FieldConstPtr getField(std::string const &fieldName) const;

    template<typename FT>
    std::tr1::shared_ptr<const FT> getField(std::string const &fieldName) const
    {
        STATIC_ASSERT(FT::isField); // only allow cast from Field sub-class
        return std::tr1::dynamic_pointer_cast<const FT>(getField(fieldName));
    }

    FieldConstPtr getFieldT(std::string const &fieldName) const {return getFieldImpl(fieldName, true);};

    template<typename FT>
    std::tr1::shared_ptr<const FT> getFieldT(std::string const &fieldName) const
    {
        STATIC_ASSERT(FT::isField); // only allow cast from Field sub-class
        std::tr1::shared_ptr<const FT> result(
            std::tr1::dynamic_pointer_cast<const FT>(getFieldT(fieldName))
        );

        if (!result)
            throw std::runtime_error("Wrong Field type");

        return result;
    }

    FieldConstPtr getField(std::size_t index) const {return fields.at(index);}

    template<typename FT>
    std::tr1::shared_ptr<const FT> getField(std::size_t index) const
    {
        STATIC_ASSERT(FT::isField); // only allow cast from Field sub-class
        return std::tr1::dynamic_pointer_cast<const FT>(getField(index));
    }

    FieldConstPtr getFieldT(std::size_t index) const {return fields.at(index);}

    template<typename FT>
    std::tr1::shared_ptr<const FT> getFieldT(std::size_t index) const
    {
        STATIC_ASSERT(FT::isField); // only allow cast from Field sub-class
        std::tr1::shared_ptr<const FT> result(
            std::tr1::dynamic_pointer_cast<const FT>(getFieldT(index))
        );

        if (!result)
            throw std::runtime_error("Wrong Field type");

        return result;
    }

    std::size_t getFieldIndex(std::string const &fieldName) const;
    FieldConstPtrArray const & getFields() const {return fields;}
    StringArray const & getFieldNames() const {return fieldNames;}
    std::string getFieldName(std::size_t fieldIndex) const {return fieldNames.at(fieldIndex);}
    bool isVariant() const {return (fieldNames.size() == 0);}

    int32 guess(Type t, ScalarType s) const;

    virtual std::string getID() const OVERRIDE FINAL;

    virtual std::ostream& dump(std::ostream& o) const OVERRIDE FINAL;

    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL;
    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL;

    std::tr1::shared_ptr<PVUnion> build() const;

protected:
   Union();
   Union(StringArray const & fieldNames, FieldConstPtrArray const & fields, std::string const & id = defaultId());
private:
   StringArray fieldNames;
   FieldConstPtrArray fields;
   std::string id;

   FieldConstPtr getFieldImpl(const std::string& fieldName, bool throws) const;
   void dumpFields(std::ostream& o) const;

   friend class FieldCreate;
   friend class Structure;
   EPICS_NOT_COPYABLE(Union)
};

class FieldCreate;
typedef std::tr1::shared_ptr<FieldCreate> FieldCreatePtr;

class FieldBuilder;
typedef std::tr1::shared_ptr<FieldBuilder> FieldBuilderPtr;

class epicsShareClass FieldBuilder :
    public std::tr1::enable_shared_from_this<FieldBuilder>
{
public:
    static FieldBuilderPtr begin();
    static FieldBuilderPtr begin(StructureConstPtr S);

        FieldBuilderPtr setId(std::string const & id);

    FieldBuilderPtr add(std::string const & name, ScalarType scalarType);

    FieldBuilderPtr addBoundedString(std::string const & name, std::size_t maxLength) PVD_DEPRECATED_52;

    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) PVD_DEPRECATED_52;

    FieldBuilderPtr addBoundedArray(std::string const & name, ScalarType scalarType, std::size_t bound) PVD_DEPRECATED_52;

    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();

private:
    FieldBuilder();
    FieldBuilder(const Structure*);
    FieldBuilder(const FieldBuilderPtr & _parentBuilder, const std::string& name, const Structure*);
    FieldBuilder(const FieldBuilderPtr & _parentBuilder, const std::string& name, const StructureArray*);
    FieldBuilder(const FieldBuilderPtr & _parentBuilder, const std::string& name, const Union*);
    FieldBuilder(const FieldBuilderPtr & _parentBuilder, const std::string& name, const UnionArray*);
    FieldBuilder(FieldBuilderPtr const & parentBuilder,
                        std::string const & nestedName,
                        Type nestedClassToBuild, bool nestedArray);

    const Field *findField(const std::string& name, Type ftype);

        void reset();
        FieldConstPtr createFieldInternal(Type type);

    friend class FieldCreate;

    const FieldCreatePtr fieldCreate;

        std::string id;
        bool idSet;

    StringArray fieldNames;
    FieldConstPtrArray fields;

    const FieldBuilderPtr parentBuilder;
    const Type nestedClassToBuild;
    const std::string nestedName;
    const bool nestedArray;
    const bool createNested; // true - endNested() creates in parent, false - endNested() appends to parent
};

namespace detail {
struct field_factory;
}

class epicsShareClass FieldCreate {
    friend struct detail::field_factory;
public:
    static const FieldCreatePtr &getFieldCreate();
        FieldBuilderPtr createFieldBuilder() const;
    FieldBuilderPtr createFieldBuilder(StructureConstPtr S) const;
    ScalarConstPtr createScalar(ScalarType scalarType) const;
    BoundedStringConstPtr createBoundedString(std::size_t maxLength) const PVD_DEPRECATED_52;
    ScalarArrayConstPtr createScalarArray(ScalarType elementType) const;
    /*
     * Create an @c Array field, fixed size array.
     * @param elementType The @c ScalarType for array elements
     * @param size Fixed array size.
     * @return An @c Array Interface for the newly created object.
     */
    ScalarArrayConstPtr createFixedScalarArray(ScalarType elementType, std::size_t size) const PVD_DEPRECATED_52;
     ScalarArrayConstPtr createBoundedScalarArray(ScalarType elementType, std::size_t bound) const PVD_DEPRECATED_52;
    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;
    UnionArrayConstPtr createUnionArray(UnionConstPtr const & punion) const;
    UnionArrayConstPtr createVariantUnionArray() const;
    UnionConstPtr createVariantUnion() const;
    UnionConstPtr createUnion (
        StringArray const & fieldNames,
        FieldConstPtrArray const & fields) const;
    UnionConstPtr createUnion (
        std::string const & id,
        StringArray const & fieldNames,
        FieldConstPtrArray const & fields) 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;

private:
    FieldCreate();

    // const after ctor
    std::vector<ScalarConstPtr> scalars;
    std::vector<ScalarArrayConstPtr> scalarArrays;
    UnionConstPtr variantUnion;
    UnionArrayConstPtr variantUnionArray;

    mutable Mutex mutex;
    typedef std::multimap<unsigned int, Field*> cache_t;
    mutable cache_t cache;

    struct Helper;
    friend class Field;
    EPICS_NOT_COPYABLE(FieldCreate)
};

FORCE_INLINE const FieldCreatePtr& getFieldCreate() {
    return FieldCreate::getFieldCreate();
}

template<typename T>
struct ScalarTypeID {};

template<ScalarType ID>
struct ScalarTypeTraits {};

#define OP(ENUM, TYPE) \
template<> struct ScalarTypeTraits<ENUM> {typedef TYPE type;}; \
template<> struct ScalarTypeID<TYPE> { enum {value=ENUM}; }; \
template<> struct ScalarTypeID<const TYPE> { enum {value=ENUM}; };

OP(pvBoolean, boolean)
OP(pvByte, int8)
OP(pvShort, int16)
OP(pvInt, int32)
OP(pvLong, int64)
OP(pvUByte, uint8)
OP(pvUShort, uint16)
OP(pvUInt, uint32)
OP(pvULong, uint64)
OP(pvFloat, float)
OP(pvDouble, double)
OP(pvString, std::string)
#undef OP

bool epicsShareExtern compare(const Field&, const Field&);
bool epicsShareExtern compare(const Scalar&, const Scalar&);
bool epicsShareExtern compare(const ScalarArray&, const ScalarArray&);
bool epicsShareExtern compare(const Structure&, const Structure&);
bool epicsShareExtern compare(const StructureArray&, const StructureArray&);
bool epicsShareExtern compare(const Union&, const Union&);
bool epicsShareExtern compare(const UnionArray&, const UnionArray&);
bool epicsShareExtern compare(const BoundedString&, const BoundedString&);

#define MAKE_COMPARE(CLASS) \
static FORCE_INLINE bool operator==(const CLASS& a, const CLASS& b) {return (void*)&a==(void*)&b;} \
static FORCE_INLINE bool operator!=(const CLASS& a, const CLASS& b) {return !(a==b);}

MAKE_COMPARE(Field)
MAKE_COMPARE(Scalar)
MAKE_COMPARE(ScalarArray)
MAKE_COMPARE(Structure)
MAKE_COMPARE(StructureArray)
MAKE_COMPARE(Union)
MAKE_COMPARE(UnionArray)
MAKE_COMPARE(BoundedString)

#undef MAKE_COMPARE
}}

namespace std{
    epicsShareExtern std::ostream& operator<<(std::ostream& o, const epics::pvData::Field *ptr);
}

#endif  /* PVINTROSPECT_H */