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 */