Merge branch 'shared-vector'

This commit is contained in:
Michael Davidsaver
2013-10-28 17:42:11 -04:00
42 changed files with 9293 additions and 5682 deletions

1621
documentation/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

1842
documentation/pvArray.html Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,792 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>EPICS pvDataDiscussion</title>
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/base.css" />
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
<style type="text/css">
/*<![CDATA[*/
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
table { margin-left: auto; margin-right: auto }
.diagram { text-align: center; margin: 2.5em 0 }
span.opt { color: grey }
span.nterm { font-style:italic }
span.term { font-family:courier }
span.user { font-family:courier }
span.user:before { content:"<" }
span.user:after { content:">" }
.nonnorm { font-style:italic }
p.ed { color: #AA0000 }
span.ed { color: #AA0000 }
p.ed.priv { display: inline; }
span.ed.priv { display: inline; }
/*]]>*/</style>
<!-- Script that generates the Table of Contents -->
<script type="text/javascript"
src="http://epics-pvdata.sourceforge.net/script/tocgen.js">
</script>
</head>
<body>
<div class="head">
<h1>EPICS pvDataDiscussion</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 03-Jul-2013</h2>
<dl>
<dt>Latest version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvDataDiscussion.html">pvDataDiscussion.html</a>
</dd>
<dt>This version:</dt>
<dd>none</dd>
<dt>Previous version:</dt>
<dd>None</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL<dd />
</dl>
<p class="copyright">This product is made available subject to acceptance of the <a
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source
license.</a></p>
<hr />
</div>
<div id="toc">
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
</div>
<div id="contents" class="contents">
<h2>Introduction</h2>
<p>As pvDataCPP progressed PVField and derived classes accumulated
more and more member functions.
These member functions have nothing to do with the primary primary
purpose for pvData:
<blockquote>pvData (Process Variable Data) defines and implements an efficent
way to store, access, and communicate memory resident data structures.</blockquote>
This statement appears as the first sentence of pvDataJava.html.
A few sentances later the document makes it clear that communication
includes efficent network communication.
Thus pvData provides an interface for network accessible structured data.
The problem of adding member functions that have nothing to do with the primary purpose
started with the Java API.
It already had extra methods that solved problems that should have had a different solution.
This document removes the extra methods so that when new problems arise in the future
the solution will not involve adding new member functions to the introspection and data API.
</p>
<p>The introspection and data API for pvData should only encapuslate methods that support the primary purpose
stated above.
The interfaces for C++ and Java should be similar so that
someone who understands the interface in one of the languages
and knows both languages will quickly understand the interface of the other language.</p>
<p>There is another problem with the existing API. There are methods that allow the "structure"
to change after an pvData object is created. An example is PVField::renameField(String newName).
Such methods should not exist.</p>
<p>There are methods regarding immutability: setImmutable, isImmutablei, setCapacityMutable, and isCapacityMutable.
Should they exists? For now lets assume no.
</p>
<p>One last issue is the interface for array data. This document proposes a simplified
version of what currently exists. It requires that the implementation always provides storage for
the complete raw array. The existing APIs allow the implementation to provide the data in
"chunks". Giving up this requirement simplifies the array interfaces.
The existing C++ implementation of PVValueArray has serious problems.
The shared_vector that is implemented in pvDataCP-md provides the solution to fixing
the problems. This document describes an API that is very similar to the new Java API
except that raw arrays are replaced by shared_vector.</p>
<p>This document will first describe changes to the existing Java interfaces
and then the corresponding C++ API.</p>
<h2>Java API</h2>
<p>The following shows which methods will be removed from the existing interfaces
and what will be added.
The methods to be removed are in <font color = "red">red</font>
and methods to add are in <font color = "blue">blue</font>
Also the removed methods are at the end with a comment above.
The new methods also have a comment.
</p>
<h3>Introspection Interfaces</h3>
<pre>interface Field extends Serializable {
String getId();
Type getType();
// following will be removed
<font color = "red">void toString(StringBuilder buf);</font>
<font color = "red">void toString(StringBuilder buf,int indentLevel);</font>
<font color = "red">String toString();</font>
}
<font color = "blue">
// new interface
interface FieldToString {
String toString(Field field);
}</font>
interface Scalar extends Field {
ScalarType getScalarType();
}
interface ScalarArray extends Field {
ScalarType getElementType();
}
interface Structure extends Field {
Field getField(String fieldName);
int getFieldIndex(String fieldName);
Field[] getFields();
Field getField(int fieldIndex);
String[] getFieldNames();
String getFieldName(int fieldIndex)
}
interface StructureArray extends Field {
Structure getStructure();
}
interface FieldCreate {
Scalar createScalar(ScalarType scalarType);
ScalarArray createScalarArray(ScalarType elementType);
StructureArray createStructureArray(Structure elementStructure);
Structure createStructure(String[] fieldNames, Field[] field);
Structure createStructure(String id,String[] fieldNames, Field[] field);
Structure createStructure(Structure structToClone);
Field deserialize(ByteBuffer buffer, DeserializableControl control);
// following will be removed
<font color = "red">Structure appendField(Structure structure,String fieldName, Field field);</font>
<font color = "red">Structure appendFields(Structure structure,String[] fieldNames, Field[] fields);</font>
}
</pre>
<h3>Data Interfaces</h3>
<pre>
interface PVField extends Requester, Serializable {
String getFieldName();
void setRequester(Requester requester);
int getFieldOffset();
int getNextFieldOffset();
int getNumberFields();
Field getField();
PVStructure getParent();
void postPut();
void setPostHandler(PostHandler postHandler);
// following will be removed
<font color = "red">PVAuxInfo getPVAuxInfo();</font>
<font color = "red">boolean isImmutable();</font>
<font color = "red">void setImmutable();</font>
<font color = "red">void renameField(String newName);</font>
<font color = "red">void toString(StringBuilder buf);</font>
<font color = "red">void toString(StringBuilder buf,int indentLevel);</font>
<font color = "red">String toString();</font>
}
<font color = "blue">
// The following is a new interface
interface PVFieldToString {
String toString(PVField pvField);
void setMaxInitialArrayElements(int num);
void setMaxFinalArrayElements(int num);
int getMaxInitialArrayElements();
int getMaxFinalArrayElements();
}</font>
interface PVScalar extends PVField{
Scalar getScalar();
}
interface PVDouble extends PVScalar{
double get();
void put(double value);
}
// also PVBoolean, PVByte, PVShort, PVInt, PVLong, PVFloat, and PVString
interface PVArray extends PVField, SerializableArray {
int getLength();
void setLength(int length);
int getCapacity();
void setCapacity(int length);
// following will be removed
<font color = "red">boolean isCapacityMutable();</font>
<font color = "red">void setCapacityMutable(boolean isMutable);</font>
}
interface PVScalarArray extends PVArray {
ScalarArray getScalarArray();
}
<font color = "red">
//following will be removed
public class DoubleArrayData {
public double[] data;
public int offset;
}</font>
interface PVDoubleArray extends PVArray {
// following are new
<font color = "blue"> double[] get();</font>
<font color = "blue"> void swap(double[] value);</font>
//following will be removed
<font color = "red"> int get(int offset, int len, DoubleArrayData data);</font>
<font color = "red"> int put(int offset,int len, double[] from, int fromOffset)</font>;
<font color = "red"> void shareData(double[] from);</font>
}
// also PVBooleanArray, ..., PVStringArray
interface PVStructure extends PVField , BitSetSerializable{
Structure getStructure();
PVField[] getPVFields();
PVField getSubField(String fieldName);
PVField getSubField(int fieldOffset);
// The following are convenience methods
PVBoolean getBooleanField(String fieldName);
PVByte getByteField(String fieldName);
PVShort getShortField(String fieldName);
PVInt getIntField(String fieldName);
PVLong getLongField(String fieldName);
PVFloat getFloatField(String fieldName);
PVDouble getDoubleField(String fieldName);
PVString getStringField(String fieldName);
PVScalarArray getScalarArrayField(String fieldName);
PVStructureArray getStructureArrayField(String fieldName);
PVStructure getStructureField(String fieldName);
PVArray getArrayField(String fieldName,ScalarType elementType);
// following will be removed
<font color = "red"> void appendPVField(String fieldName,PVField pvField);</font>
<font color = "red"> void appendPVFields(String[] fieldNames,PVField[] pvFields);</font>
<font color = "red"> void removePVField(String fieldName);</font>
<font color = "red"> void replacePVField(PVField oldPVField,PVField newPVField);</font>
<font color = "red"> String getExtendsStructureName();</font>
<font color = "red"> boolean putExtendsStructureName(String extendsStructureName);</font>
<font color = "red"> public boolean checkValid();</font>
}
<font color = "red">
//following will be removed
public class StructureArrayData {
public PVStructure[] data;
public int offset;
}
</font>
interface PVStructureArray extends PVArray{
StructureArray getStructureArray();
// following are new
<font color = "blue"> PVStructure[] get();</font>
<font color = "blue"> void swap(PVStructure[] value);</font>
// following will be removed
<font color = "red"> int get(int offset, int length, StructureArrayData data);</font>
<font color = "red"> int put(int offset,int length, PVStructure[] from, int fromOffset);</font>
<font color = "red"> void shareData(PVStructure[] from);</font>
}
public interface PVDataCreate {
PVField createPVField(Field field);
PVField createPVField(PVField fieldToClone);
PVScalar createPVScalar(Scalar scalar);
PVScalar createPVScalar(ScalarType fieldType);
PVScalar createPVScalar(PVScalar scalarToClone);
PVScalarArray createPVScalarArray(ScalarArray array);
PVScalarArray createPVScalarArray(ScalarType elementType);
PVScalarArray createPVScalarArray(PVScalarArray arrayToClone;
PVStructureArray createPVStructureArray(StructureArray structureArray);
PVStructure createPVStructure(Structure structure);
PVStructure createPVStructure(String[] fieldNames,Field[] fields);
PVStructure createPVStructure(PVStructure structToClone);
// following will be removed
<font color = "red">PVField[] flattenPVStructure(PVStructure pvStructure);</font>
}
</pre>
<h3>PVFieldToString</h3>
<p>In addition to toString this has methods to limit the number of array element to display.
The existing Java implementation of toString displayed all elements.
For large arrays this is not desirable.
The new methods provide a way for the client to limit the number of elements.
The default might be set to something like display up to 10 elements with 5 fron the beginning and 5 from the end.</p>
<p>For C++ this can be a replacement for dumpValue.</p>
<h3>PVBooleanArray, ..., PVStructureArray</h3>
<p>The old get and put are replaced by two new and simpler methods:
<dl>
<dt>get</dt>
<dd>Returns the raw array. If the client code modifies the elements in the array then
the client must call postPut. The client also has to realize that if the raw array held by the PVXXXArray changes
then the client is no longer sharing data
<dt>swap</dt>
<dd>This exchanges the old raw data with the new raw data.</dd>
</dl>
</p>
<p>
The method <b>setCapacity</b> will always create a new raw array and copy old data from the old to the new array.
This is not true now since the implementation does not create a new array if the old capacity is equal to the requested capacity.
</p>
<h2>C++ API</h2>
<p>The C++ class definitions are similar to the Java definitions with two main exceptions:
<dl>
<dt>toString</dt>
<dd>In c++ this is replaced by std::ostream.</dd>
<dt>raw array data</dt>
<dd>Java supports array data like <b>double[]</b>
The C++ replacement is shared_vector&lt;double&gt;, which is implemented
in pvDataCPP-md.</dd
</dl>
<h3>Introspection Interfaces</h3>
<pre>
class Field :
virtual public Serializable,
public std::tr1::enable_shared_from_this&lt;Field&gt;
{
public:
POINTER_DEFINITIONS(Field);
virtual ~Field();
Type getType() const{return m_type;}
virtual String getID() const = 0;
<font color = "red">
// following will be removed
virtual void toString(StringBuilder buf) const{toString(buf,0);}
virtual void toString(StringBuilder buf,int indentLevel) const;
</font>
...
};
<font color = "blue">
// new function
std::ostream &amp;toString(Field::const_reference field, std::ostream&amp; o);
</font>
class Scalar : public Field{
public:
POINTER_DEFINITIONS(Scalar);
virtual ~Scalar();
typedef Scalar&amp; reference;
typedef const Scalar&amp; const_reference;
ScalarType getScalarType() const {return scalarType;}
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableContol *control);
<font color = "red">
// following will be removed
virtual void toString(StringBuilder buf) const{toString(buf,0);}
virtual void toString(StringBuilder buf,int indentLevel) const;
virtual String getID() const;
</font>
...
};
class ScalarArray : public Field{
public:
POINTER_DEFINITIONS(ScalarArray);
typedef ScalarArray&amp; reference;
typedef const ScalarArray&amp; const_reference;
ScalarArray(ScalarType scalarType);
ScalarType getElementType() const {return elementType;}
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
<font color = "red">
// following will be removed
virtual void toString(StringBuilder buf) const{toString(buf,0);}
virtual void toString(StringBuilder buf,int indentLevel) const;
virtual String getID() const;
</font>
...
};
class Structure : public Field {
public:
POINTER_DEFINITIONS(Structure);
typedef Structure&amp; reference;
typedef const Structure&amp; const_reference;
std::size_t getNumberFields() const {return numberFields;}
FieldConstPtr getField(String const &amp; fieldName) const;
FieldConstPtr getField(std::size_t index) const;
std::size_t getFieldIndex(String const &amp;fieldName) const;
FieldConstPtrArray const &amp; getFields() const {return fields;}
StringArray const &amp; getFieldNames() const;
String getFieldName(std::size_t fieldIndex);
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
<font color = "red">
// following will be removed
void renameField(std::size_t fieldIndex,String const &amp;newName);
virtual void toString(StringBuilder buf,int indentLevel) const;
virtual String getID() const;
</font>
...
};
class StructureArray : public Field{
public:
POINTER_DEFINITIONS(StructureArray);
typedef StructureArray&amp; reference;
typedef const StructureArray&amp; const_reference;
StructureConstPtr getStructure() const {return pstructure;}
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
<font color = "red">
// following will be removed
virtual void toString(StringBuilder buf,int indentLevel=0) const;
virtual String getID() const;
</font>
...
};
class FieldCreate {
public:
static FieldCreatePtr getFieldCreate();
ScalarConstPtr createScalar(ScalarType scalarType) const
ScalarArrayConstPtr createScalarArray(ScalarType elementType) const;
StructureArrayConstPtr createStructureArray(StructureConstPtr const &amp; structure) const;
StructureConstPtr createStructure (
StringArray const &amp; fieldNames,
FieldConstPtrArray const &amp; fields) const;
StructureConstPtr createStructure (
String const &amp;id,
StringArray const &amp; fieldNames,
FieldConstPtrArray const &amp; fields) const;
FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const;
<font color = "red">
// following will be removed
StructureConstPtr appendField(
StructureConstPtr const &amp; structure,
String const &amp;fieldName, FieldConstPtr const &amp; field) const;
StructureConstPtr appendFields(
StructureConstPtr const &amp; structure,
StringArray const &amp; fieldNames,
FieldConstPtrArray const &amp; fields) const;
</font>
...
};
extern FieldCreatePtr getFieldCreate();
</pre>
<h3>Data Interfaces</h3>
<pre>
class PVField
: virtual public Serializable,
public std::tr1::enable_shared_from_this&lt;PVField&gt;
{
public:
POINTER_DEFINITIONS(PVField);
virtual ~PVField();
inline const String &amp;getFieldName() const ;
virtual void setRequester(RequesterPtr const &amp;prequester);
std::size_t getFieldOffset() const;
std::size_t getNextFieldOffset() const;
std::size_t getNumberFields() const;
const FieldConstPtr &amp; getField() const ;
PVStructure * getParent() const
void postPut() ;
void setPostHandler(PostHandlerPtr const &amp;postHandler);
// following will be removed
<font color = "red">
virtual void message(String message,MessageType messageType);
void replacePVField(const PVFieldPtr&amp; newPVField);
String getFullName() const;
virtual bool equals(PVField &amp;pv);
PVAuxInfoPtr &amp; getPVAuxInfo()
bool isImmutable() const;
virtual void setImmutable();
void replacePVField(const PVFieldPtr&amp; newPVField);
void renameField(String const &amp;newName);
virtual void toString(StringBuilder buf) ;
virtual void toString(StringBuilder buf,int indentLevel);
std::ostream&amp; dumpValue(std::ostream&amp; o) const;
</font>
...
};
<font color = "blue">
// The following is a new class
class PVFieldToString {
String toString(const PVFieldPtr &amp;pvField);
void setMaxInitialArrayElements(size_t num);
void setMaxFinalArrayElements(size_t num);
size_t getMaxInitialArrayElements();
size_t getMaxFinalArrayElements();
...
}</font>
class PVScalar : public PVField {
public:
POINTER_DEFINITIONS(PVScalar);
virtual ~PVScalar();
typedef PVScalar &amp;reference;
typedef const PVScalar&amp; const_reference;
const ScalarConstPtr getScalar() const ;
...
}
template&lt;typename T&gt;
class PVScalarValue : public PVScalar {
public:
POINTER_DEFINITIONS(PVScalarValue);
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
virtual ~PVScalarValue() {}
virtual T get() const = 0;
virtual void put(T value) = 0;
<font color = "red">
// following will be removed
std::ostream&amp; dumpValue(std::ostream&amp; o)
void operator&gt;&gt;=(T&amp; value) const;
void operator&lt;&lt;=(T value);
</font>
...
}
// PVString is special case, since it implements SerializableArray
class PVString : public PVScalarValue&lt;String&gt;, SerializableArray {
public:
virtual ~PVString() {}
...
}
class PVArray : public PVField, public SerializableArray {
public:
POINTER_DEFINITIONS(PVArray);
virtual ~PVArray();
std::size_t getLength() const;
virtual void setLength(std::size_t length);
std::size_t getCapacity() const;
virtual void setCapacity(std::size_t capacity) = 0;
<font color = "red">
// following will be removed
virtual void setImmutable();
bool isCapacityMutable() const;
void setCapacityMutable(bool isMutable);
virtual std::ostream&amp; dumpValue(std::ostream&amp; o, std::size_t index) const = 0;
</font>
...
};
class PVScalarArray : public PVArray {
public:
POINTER_DEFINITIONS(PVScalarArray);
virtual ~PVScalarArray();
typedef PVScalarArray &amp;reference;
typedef const PVScalarArray&amp; const_reference;
const ScalarArrayConstPtr getScalarArray() const ;
<font color = "red">
// following will be removed
virtual std::ostream&amp; dumpValue(std::ostream&amp; o, size_t index) const = 0;
</font>
...
}
<font color = "red">
// following will be removed
template&lt;typename T&gt;
class PVArrayData {
private:
std::vector&lt;T&gt; init;
public:
POINTER_DEFINITIONS(PVArrayData);
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
std::vector&lt;T&gt; &amp; data;
std::size_t offset;
PVArrayData()
: data(init)
{}
};
</font>
template&lt;typename T&gt;
class PVValueArray : public PVScalarArray {
public:
POINTER_DEFINITIONS(PVValueArray);
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
// following are new typeDefs
<font color = "blue">typedef shared_vector&lt;T&gt; svector;</font>
<font color = "blue">typedef shared_vector&lt;const T&gt; const_svector; </font>
virtual ~PVValueArray() {}
// following are added
<font color = "blue">svector get();</font>
<font color = "blue">void swap(svector&amp; value);</font>
<font color = "red">
// following are removed
typedef PVValueArray &amp; reference;
typedef const PVValueArray &amp; const_reference;
typedef PVArrayData&lt;T&gt; ArrayDataType;
typedef std::vector&lt;T&gt; vector;
typedef const std::vector&lt;T&gt; const_vector;
typedef std::tr1::shared_ptr&lt;vector&gt; shared_vector;
virtual std::size_t get(
std::size_t offset, std::size_t length, ArrayDataType &amp;data) = 0;
virtual std::size_t put(std::size_t offset,
std::size_t length, const_pointer from, std::size_t fromOffset) = 0;
virtual std::size_t put(std::size_t offset,
std::size_t length, const_vector &amp;from, std::size_t fromOffset);
virtual void shareData(
shared_vector const &amp; value,
std::size_t capacity,
std::size_t length) = 0;
virtual pointer get() = 0;
virtual pointer get() const = 0;
virtual vector const &amp; getVector() = 0;
virtual shared_vector const &amp; getSharedVector() = 0;
std::ostream&amp; dumpValue(std::ostream&amp; o) const;
std::ostream&amp; dumpValue(std::ostream&amp; o, size_t index) const;
</font>
...
};
typedef PVValueArray&lt;uint8&gt; PVBooleanArray;
typedef std::tr1::shared_ptr&lt;PVBooleanArray&gt; PVBooleanArrayPtr;
...
typedef PVValueArray&lt;String&gt; PVStringArray;
typedef std::tr1::shared_ptr&lt;PVStringArray&gt; PVStringArrayPtr;
class PVStructure : public PVField,public BitSetSerializable {
public:
POINTER_DEFINITIONS(PVStructure);
virtual ~PVStructure();
typedef PVStructure &amp; reference;
typedef const PVStructure &amp; const_reference;
StructureConstPtr getStructure() const;
const PVFieldPtrArray &amp; getPVFields() const;
PVFieldPtr getSubField(String const &amp;fieldName) const;
PVFieldPtr getSubField(std::size_t fieldOffset) const;
PVBooleanPtr getBooleanField(String const &amp;fieldName) ;
PVBytePtr getByteField(String const &amp;fieldName) ;
PVShortPtr getShortField(String const &amp;fieldName) ;
PVIntPtr getIntField(String const &amp;fieldName) ;
PVLongPtr getLongField(String const &amp;fieldName) ;
PVUBytePtr getUByteField(String const &amp;fieldName) ;
PVUShortPtr getUShortField(String const &amp;fieldName) ;
PVUIntPtr getUIntField(String const &amp;fieldName) ;
PVULongPtr getULongField(String const &amp;fieldName) ;
PVFloatPtr getFloatField(String const &amp;fieldName) ;
PVDoublePtr getDoubleField(String const &amp;fieldName) ;
PVStringPtr getStringField(String const &amp;fieldName) ;
PVStructurePtr getStructureField(String const &amp;fieldName) ;
PVScalarArrayPtr getScalarArrayField(
String const &amp;fieldName,ScalarType elementType) ;
PVStructureArrayPtr getStructureArrayField(String const &amp;fieldName) ;
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 &amp; structure);
PVStructure(StructureConstPtr const &amp; structure,PVFieldPtrArray const &amp; pvFields);
<font color = "red">
// following are removed
void appendPVField(
String const &amp;fieldName,
PVFieldPtr const &amp; pvField);
void appendPVFields(
StringArray const &amp; fieldNames,
PVFieldPtrArray const &amp; pvFields);
void removePVField(String const &amp;fieldName);
virtual void setImmutable();
String getExtendsStructureName() const;
bool putExtendsStructureName(
String const &amp;extendsStructureName);
</font>
};
<font color = "red">
// following will be removed
typedef PVArrayData&lt;PVStructurePtr&gt; StructureArrayData;
</font>
class PVStructureArray : public PVArray
{
public:
POINTER_DEFINITIONS(PVStructureArray);
typedef PVStructurePtr value_type;
typedef PVStructurePtr* pointer;
typedef const PVStructurePtr* const_pointer;
<font color = "blue">
// following are new typeDefs
typedef shared_vector&lt;PVStructurePtr&gt; svector;
typedef shared_vector&lt;const PVStructurePtr&gt; const_svector;
</font>
virtual ~PVStructureArray() {}
virtual void setCapacity(size_t capacity);
virtual void setLength(std::size_t length);
virtual StructureArrayConstPtr getStructureArray() const ;
virtual void serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const;
virtual void deserialize(ByteBuffer *buffer,
virtual void serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, std::size_t offset, std::size_t count) const ;
// following are new
<font color = "blue"> svector get();</font>
<font color = "blue"> void swap(svector &amp; value);</font>
<font color = "red">
// following are removed
typedef PVArrayData&lt;PVStructurePtr&gt; ArrayDataType;
typedef std::vector&lt;PVStructurePtr&gt; vector;
typedef const std::vector&lt;PVStructurePtr&gt; const_vector;
typedef std::tr1::shared_ptr&lt;vector&gt; shared_vector;
typedef PVStructureArray &amp;reference;
typedef const PVStructureArray&amp; const_reference;
virtual std::size_t append(std::size_t number);
virtual bool remove(std::size_t offset,std::size_t number);
virtual void compress();
virtual std::size_t get(std::size_t offset, std::size_t length,
StructureArrayData &amp;data);
virtual std::size_t put(std::size_t offset,std::size_t length,
const_vector const &amp; from, std::size_t fromOffset);
virtual void shareData(
shared_vector const &amp; value,
std::size_t capacity,
std::size_t length);
virtual pointer get() { return &amp;((*value.get())[0]); }
virtual pointer get() const { return &amp;((*value.get())[0]); }
virtual vector const &amp; getVector() {return *value;}
virtual shared_vector const &amp; getSharedVector() {return value;}
</font>
...
};
class PVDataCreate {
public:
static PVDataCreatePtr getPVDataCreate();
PVFieldPtr createPVField(FieldConstPtr const &amp; field);
PVFieldPtr createPVField(PVFieldPtr const &amp; fieldToClone);
PVScalarPtr createPVScalar(ScalarConstPtr const &amp; scalar);
PVScalarPtr createPVScalar(ScalarType scalarType);
PVScalarPtr createPVScalar(PVScalarPtr const &amp; scalarToClone);
PVScalarArrayPtr createPVScalarArray(ScalarArrayConstPtr const &amp; scalarArray);
PVScalarArrayPtr createPVScalarArray(ScalarType elementType);
PVScalarArrayPtr createPVScalarArray(PVScalarArrayPtr const &amp; scalarArrayToClone);
PVStructureArrayPtr createPVStructureArray(StructureArrayConstPtr const &amp; structureArray);
PVStructurePtr createPVStructure(StructureConstPtr const &amp; structure);
PVStructurePtr createPVStructure(
StringArray const &amp; fieldNames,PVFieldPtrArray const &amp; pvFields);
PVStructurePtr createPVStructure(PVStructurePtr const &amp; structToClone);
...
};
extern PVDataCreatePtr getPVDataCreate();
</pre>
</div>
</body>
</html>

View File

@@ -24,6 +24,10 @@ INC += destroyable.h
INC += status.h
INC += sharedPtr.h
INC += localStaticLock.h
INC += typeCast.h
INC += printer.h
INC += sharedVector.h
INC += templateMeta.h
LIBSRCS += byteBuffer.cpp
LIBSRCS += bitSet.cpp
@@ -37,6 +41,8 @@ LIBSRCS += timer.cpp
LIBSRCS += status.cpp
LIBSRCS += messageQueue.cpp
LIBSRCS += localStaticLock.cpp
LIBSRCS += typeCast.cpp
LIBSRCS += parseToPOD.cpp
SRC_DIRS += $(PVDATA)/pv
@@ -64,6 +70,7 @@ LIBSRCS += Convert.cpp
LIBSRCS += Compare.cpp
LIBSRCS += StandardField.cpp
LIBSRCS += StandardPVField.cpp
LIBSRCS += printer.cpp
SRC_DIRS += $(PVDATA)/property

View File

@@ -15,13 +15,6 @@
namespace epics { namespace pvData {
// PVXXX object comparison
bool operator==(PVField& left, PVField& right)
{
return getConvert()->equals(left,right);
}
// Introspection object comparision
/** Field equality conditions:
@@ -101,8 +94,142 @@ bool operator==(const StructureArray& a, const StructureArray& b)
return *(a.getStructure().get())==*(b.getStructure().get());
}
namespace nconvert {
// PVXXX object comparison
} // namespace nconvert
namespace {
// fully typed comparisons
template<typename T>
bool compareScalar(const PVScalarValue<T>* left, const PVScalarValue<T>* right)
{
return left->get()==right->get();
}
template<typename T>
bool compareArray(const PVValueArray<T>* left, const PVValueArray<T>* right)
{
typename PVValueArray<T>::const_svector lhs(left->view()), rhs(right->view());
return std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
// partially typed comparisons
bool compareField(const PVScalar* left, const PVScalar* right)
{
ScalarType lht = left->getScalar()->getScalarType();
if(lht != right->getScalar()->getScalarType())
return false;
switch(lht) {
#define OP(ENUM, TYPE) case ENUM: return compareScalar(static_cast<const PVScalarValue<TYPE>*>(left), static_cast<const PVScalarValue<TYPE>*>(right))
OP(pvBoolean, uint8);
OP(pvUByte, uint8);
OP(pvByte, int8);
OP(pvUShort, uint16);
OP(pvShort, int16);
OP(pvUInt, uint32);
OP(pvInt, int32);
OP(pvULong, uint64);
OP(pvLong, int64);
OP(pvFloat, float);
OP(pvDouble, double);
#undef OP
case pvString: {
const PVString *a=static_cast<const PVString*>(left), *b=static_cast<const PVString*>(right);
return a->get()==b->get();
}
}
throw std::logic_error("PVScalar with invalid scalar type!");
}
bool compareField(const PVScalarArray* left, const PVScalarArray* right)
{
ScalarType lht = left->getScalarArray()->getElementType();
if(lht != right->getScalarArray()->getElementType())
return false;
if(left->getLength()!=right->getLength())
return false;
switch(lht) {
#define OP(ENUM, TYPE) case ENUM: return compareArray(static_cast<const PVValueArray<TYPE>*>(left), static_cast<const PVValueArray<TYPE>*>(right))
OP(pvBoolean, uint8);
OP(pvUByte, uint8);
OP(pvByte, int8);
OP(pvUShort, uint16);
OP(pvShort, int16);
OP(pvUInt, uint32);
OP(pvInt, int32);
OP(pvULong, uint64);
OP(pvLong, int64);
OP(pvFloat, float);
OP(pvDouble, double);
OP(pvString, String);
#undef OP
}
throw std::logic_error("PVScalarArray with invalid element type!");
}
bool compareField(const PVStructure* left, const PVStructure* right)
{
StructureConstPtr ls = left->getStructure();
if(*ls!=*right->getStructure())
return false;
const PVFieldPtrArray& lf = left->getPVFields();
const PVFieldPtrArray& rf = right->getPVFields();
for(size_t i=0, nfld=ls->getNumberFields(); i<nfld; i++) {
if(*lf[i]!=*rf[i])
return false;
}
return true;
}
bool compareField(const PVStructureArray* left, const PVStructureArray* right)
{
if(*left->getStructureArray()->getStructure()
!= *right->getStructureArray()->getStructure())
return false;
PVStructureArray::const_svector ld=left->view(), rd=right->view();
if(ld.size()!=rd.size())
return false;
PVStructureArray::const_svector::const_iterator lit, lend, rit;
for(lit=ld.begin(), lend=ld.end(), rit=rd.begin();
lit!=lend;
++lit, ++rit)
{
if(**lit != **rit)
return false;
}
return true;
}
} // end namespace
// untyped comparison
bool operator==(const PVField& left, const PVField& right)
{
if(&left == &right)
return true;
Type lht = left.getField()->getType();
if(lht != right.getField()->getType())
return false;
switch(lht) {
case scalar: return compareField(static_cast<const PVScalar*>(&left), static_cast<const PVScalar*>(&right));
case scalarArray: return compareField(static_cast<const PVScalarArray*>(&left), static_cast<const PVScalarArray*>(&right));
case structure: return compareField(static_cast<const PVStructure*>(&left), static_cast<const PVStructure*>(&right));
case structureArray: return compareField(static_cast<const PVStructureArray*>(&left), static_cast<const PVStructureArray*>(&right));
}
throw std::logic_error("PVField with invalid type!");
}
}} // namespace epics::pvData

File diff suppressed because it is too large Load Diff

View File

@@ -66,7 +66,11 @@ struct StructureArrayHashFunction {
Scalar::Scalar(ScalarType scalarType)
: Field(scalar),scalarType(scalarType){}
: Field(scalar),scalarType(scalarType)
{
if(scalarType<pvBoolean || scalarType>pvString)
throw std::invalid_argument("Can't construct Scalar from invalid ScalarType");
}
Scalar::~Scalar(){}
@@ -166,7 +170,11 @@ static StructureConstPtr deserializeStructureField(const FieldCreate* fieldCreat
}
ScalarArray::ScalarArray(ScalarType elementType)
: Field(scalarArray),elementType(elementType){}
: Field(scalarArray),elementType(elementType)
{
if(elementType<pvBoolean || elementType>pvString)
throw std::invalid_argument("Can't construct ScalarArray from invalid ScalarType");
}
ScalarArray::~ScalarArray() {}
@@ -275,10 +283,12 @@ Structure::Structure (
}
size_t number = fields.size();
for(size_t i=0; i<number; i++) {
String name = fieldNames[i];
if(name.size()<1) {
const String& name = fieldNames[i];
if(name.empty()) {
throw std::invalid_argument("fieldNames has a zero length string");
}
if(fields[i].get()==NULL)
throw std::invalid_argument("Can't construct Structure with NULL Field");
// look for duplicates
for(size_t j=i+1; j<number; j++) {
String otherName = fieldNames[j];

View File

@@ -19,83 +19,32 @@ using std::size_t;
namespace epics { namespace pvData {
class PVArrayPvt {
public:
PVArrayPvt() : length(0),capacity(0),capacityMutable(true)
{}
size_t length;
size_t capacity;
bool capacityMutable;
};
PVArray::PVArray(FieldConstPtr const & field)
: PVField(field),pImpl(new PVArrayPvt())
: PVField(field),capacityMutable(true)
{ }
PVArray::~PVArray()
{
delete pImpl;
}
void PVArray::setImmutable()
{
pImpl->capacityMutable = false;
capacityMutable = false;
PVField::setImmutable();
}
size_t PVArray::getLength() const {return pImpl->length;}
size_t PVArray::getCapacity() const {return pImpl->capacity;}
static String fieldImmutable("field is immutable");
void PVArray::setLength(size_t length) {
if(length==pImpl->length) return;
if(PVField::isImmutable()) {
PVField::message(fieldImmutable,errorMessage);
return;
}
if(length>pImpl->capacity) this->setCapacity(length);
if(length>pImpl->capacity) length = pImpl->capacity;
pImpl->length = length;
}
void PVArray::setCapacityLength(size_t capacity,size_t length) {
pImpl->capacity = capacity;
pImpl->length = length;
}
bool PVArray::isCapacityMutable() const
{
if(PVField::isImmutable()) {
return false;
}
return pImpl->capacityMutable;
return capacityMutable;
}
void PVArray::setCapacityMutable(bool isMutable)
{
if(isMutable && PVField::isImmutable()) {
PVField::message(fieldImmutable,errorMessage);
return;
throw std::runtime_error("field is immutable");
}
pImpl->capacityMutable = isMutable;
capacityMutable = isMutable;
}
static String capacityImmutable("capacity is immutable");
void PVArray::setCapacity(size_t capacity) {
if(PVField::isImmutable()) {
PVField::message(fieldImmutable,errorMessage);
return;
}
if(pImpl->capacityMutable==false) {
PVField::message(capacityImmutable,errorMessage);
return;
}
pImpl->capacity = capacity;
}
std::ostream& operator<<(format::array_at_internal const& manip, const PVArray& array)
{

View File

@@ -28,6 +28,32 @@ using std::min;
namespace epics { namespace pvData {
template<> const ScalarType PVBoolean::typeCode = pvBoolean;
template<> const ScalarType PVByte::typeCode = pvByte;
template<> const ScalarType PVShort::typeCode = pvShort;
template<> const ScalarType PVInt::typeCode = pvInt;
template<> const ScalarType PVLong::typeCode = pvLong;
template<> const ScalarType PVUByte::typeCode = pvUByte;
template<> const ScalarType PVUShort::typeCode = pvUShort;
template<> const ScalarType PVUInt::typeCode = pvUInt;
template<> const ScalarType PVULong::typeCode = pvULong;
template<> const ScalarType PVFloat::typeCode = pvFloat;
template<> const ScalarType PVDouble::typeCode = pvDouble;
template<> const ScalarType PVScalarValue<String>::typeCode = pvString;
template<> const ScalarType PVBooleanArray::typeCode = pvBoolean;
template<> const ScalarType PVByteArray::typeCode = pvByte;
template<> const ScalarType PVShortArray::typeCode = pvShort;
template<> const ScalarType PVIntArray::typeCode = pvInt;
template<> const ScalarType PVLongArray::typeCode = pvLong;
template<> const ScalarType PVUByteArray::typeCode = pvUByte;
template<> const ScalarType PVUShortArray::typeCode = pvUShort;
template<> const ScalarType PVUIntArray::typeCode = pvUInt;
template<> const ScalarType PVULongArray::typeCode = pvULong;
template<> const ScalarType PVFloatArray::typeCode = pvFloat;
template<> const ScalarType PVDoubleArray::typeCode = pvDouble;
template<> const ScalarType PVStringArray::typeCode = pvString;
/** Default storage for scalar values
*/
template<typename T>
@@ -170,157 +196,79 @@ public:
typedef const std::vector<T> const_vector;
typedef std::tr1::shared_ptr<vector> shared_vector;
typedef ::epics::pvData::shared_vector<T> svector;
typedef ::epics::pvData::shared_vector<const T> const_svector;
DefaultPVArray(ScalarArrayConstPtr const & scalarArray);
virtual ~DefaultPVArray();
virtual size_t getLength() const {return value.size();}
virtual size_t getCapacity() const {return value.capacity();}
virtual void setCapacity(size_t capacity);
virtual void setLength(size_t length);
virtual size_t get(size_t offset, size_t length, PVArrayData<T> &data) ;
virtual size_t put(size_t offset,size_t length, const_pointer from,
size_t fromOffset);
virtual void shareData(
std::tr1::shared_ptr<std::vector<T> > const & value,
std::size_t capacity,
std::size_t length);
virtual pointer get() ;
virtual pointer get() const ;
virtual vector const & getVector() { return *value.get(); }
virtual shared_vector const & getSharedVector(){return value;};
virtual const_svector view() const {return value;}
virtual void swap(const_svector &other);
virtual void replace(const const_svector& next);
// from Serializable
virtual void serialize(ByteBuffer *pbuffer,SerializableControl *pflusher) const;
virtual void deserialize(ByteBuffer *pbuffer,DeserializableControl *pflusher);
virtual void serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const;
private:
shared_vector value;
const_svector value;
};
template<typename T>
T *DefaultPVArray<T>::get()
{
std::vector<T> *vec = value.get();
T *praw = &((*vec)[0]);
return praw;
}
template<typename T>
T *DefaultPVArray<T>::get() const
{
std::vector<T> *vec = value.get();
T *praw = &((*vec)[0]);
return praw;
}
template<typename T>
DefaultPVArray<T>::DefaultPVArray(ScalarArrayConstPtr const & scalarArray)
: PVValueArray<T>(scalarArray),
value(std::tr1::shared_ptr<std::vector<T> >(new std::vector<T>()))
value()
{ }
template<typename T>
DefaultPVArray<T>::~DefaultPVArray()
{ }
template<typename T>
void DefaultPVArray<T>::setCapacity(size_t capacity)
{
if(PVArray::getCapacity()==capacity) return;
if(!PVArray::isCapacityMutable()) {
std::string message("not capacityMutable");
PVField::message(message, errorMessage);
return;
if(this->isCapacityMutable()) {
value.reserve(capacity);
}
size_t length = PVArray::getLength();
if(length>capacity) length = capacity;
size_t oldCapacity = PVArray::getCapacity();
if(oldCapacity>capacity) {
std::vector<T> array;
array.reserve(capacity);
array.resize(length);
T * from = get();
for (size_t i=0; i<length; i++) array[i] = from[i];
value->swap(array);
} else {
value->reserve(capacity);
}
PVArray::setCapacityLength(capacity,length);
}
template<typename T>
void DefaultPVArray<T>::setLength(size_t length)
{
if(PVArray::getLength()==length) return;
size_t capacity = PVArray::getCapacity();
if(length>capacity) {
if(!PVArray::isCapacityMutable()) {
std::string message("not capacityMutable");
PVField::message(message, errorMessage);
return;
}
setCapacity(length);
}
value->resize(length);
PVArray::setCapacityLength(capacity,length);
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
if(length == value.size())
return;
else if(length < value.size())
value.slice(0, length);
else
value.resize(length);
}
template<typename T>
size_t DefaultPVArray<T>::get(size_t offset, size_t len, PVArrayData<T> &data)
void DefaultPVArray<T>::replace(const const_svector& next)
{
size_t n = len;
size_t length = this->getLength();
if(offset+len > length) {
n = length-offset;
//if(n<0) n = 0;
}
data.data = *value.get();
data.offset = offset;
return n;
}
template<typename T>
size_t DefaultPVArray<T>::put(size_t offset,size_t len,
const_pointer from,size_t fromOffset)
{
if(PVField::isImmutable()) {
PVField::message("field is immutable",errorMessage);
return 0;
}
T * pvalue = get();
if(from==pvalue) return len;
if(len<1) return 0;
size_t length = this->getLength();
size_t capacity = this->getCapacity();
if(offset+len > length) {
size_t newlength = offset + len;
if(newlength>capacity) {
setCapacity(newlength);
newlength = this->getCapacity();
len = newlength - offset;
if(len<=0) return 0;
}
length = newlength;
setLength(length);
}
pvalue = get();
for(size_t i=0;i<len;i++) {
pvalue[i+offset] = from[i+fromOffset];
}
this->setLength(length);
value = next;
this->postPut();
return len;
}
template<typename T>
void DefaultPVArray<T>::shareData(
std::tr1::shared_ptr<std::vector<T> > const & sharedValue,
std::size_t capacity,
std::size_t length)
void DefaultPVArray<T>::swap(const_svector &other)
{
value = sharedValue;
PVArray::setCapacityLength(capacity,length);
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
value.swap(other);
}
template<typename T>
void DefaultPVArray<T>::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const {
@@ -331,93 +279,92 @@ template<typename T>
void DefaultPVArray<T>::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
// alignment if (size>0) { pcontrol->ensureData(sizeof(T)-1); pbuffer->align(sizeof(T)); }
//if(size>=0) {
// prepare array, if necessary
if(size>this->getCapacity()) this->setCapacity(size);
// set new length
this->setLength(size);
// try to avoid deserializing from the buffer
// this is only possible if we do not need to do endian-swapping
if (!pbuffer->reverse<T>())
if (pcontrol->directDeserialize(pbuffer, (char*)(get()), size, sizeof(T)))
{
// inform about the change?
PVField::postPut();
return;
}
svector nextvalue(thaw(value));
nextvalue.resize(size); // TODO: avoid copy of stuff we will then overwrite
// retrieve value from the buffer
size_t i = 0;
T * pvalue = get();
while(true) {
/*
size_t maxIndex = min(size-i, (int)(pbuffer->getRemaining()/sizeof(T)))+i;
for(; i<maxIndex; i++)
value[i] = pbuffer->get<T>();
*/
size_t maxCount = min(size-i, (pbuffer->getRemaining()/sizeof(T)));
pbuffer->getArray(pvalue+i, maxCount);
i += maxCount;
if(i<size)
pcontrol->ensureData(sizeof(T)); // this is not OK since can exceen max local buffer (size-i)*sizeof(T));
else
break;
}
T* cur = nextvalue.data();
// try to avoid deserializing from the buffer
// this is only possible if we do not need to do endian-swapping
if (!pbuffer->reverse<T>())
if (pcontrol->directDeserialize(pbuffer, (char*)cur, size, sizeof(T)))
{
// inform about the change?
PVField::postPut();
//}
// TODO null arrays (size == -1) not supported
return;
}
// retrieve value from the buffer
size_t remaining = size;
while(remaining) {
const size_t have_bytes = pbuffer->getRemaining();
// correctly rounds down in an element is partially received
const size_t available = have_bytes/sizeof(T);
if(available == 0) {
size_t want = sizeof(T);
if(remaining==1 && sizeof(T)>1) {
// Need to wait for the last few bytes
// of the final element.
// available==0 implies have_bytes<sizeof(T)
want = sizeof(T) - have_bytes;
}
// recv() at least one element, or remaining buffer
pcontrol->ensureData(want);
continue;
}
const size_t n2read = std::min(remaining, available);
pbuffer->getArray(cur, n2read);
cur += n2read;
remaining -= n2read;
}
value = freeze(nextvalue);
// inform about the change?
PVField::postPut();
}
template<typename T>
void DefaultPVArray<T>::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const {
// cache
size_t length = this->getLength();
SerializableControl *pflusher, size_t offset, size_t count) const
{
//TODO: avoid incrementing the ref counter...
const_svector temp(value);
temp.slice(offset, count);
count = temp.size();
// check bounds
/*if(offset<0)
offset = 0;
else*/ if(offset>length) offset = length;
//if(count<0) count = length;
size_t maxCount = length-offset;
if(count>maxCount) count = maxCount;
// write
SerializeHelper::writeSize(count, pbuffer, pflusher);
//if (count == 0) return; pcontrol->ensureData(sizeof(T)-1); pbuffer->align(sizeof(T));
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
const T* cur = temp.data();
// try to avoid copying into the buffer
// this is only possible if we do not need to do endian-swapping
if (!pbuffer->reverse<T>())
if (pflusher->directSerialize(pbuffer, (const char*)(get()+offset), count, sizeof(T)))
if (pflusher->directSerialize(pbuffer, (const char*)cur, count, sizeof(T)))
return;
size_t end = offset+count;
size_t i = offset;
T * pvalue = const_cast<T *>(get());
while(true) {
/*
size_t maxIndex = min<int>(end-i, (int)(pbuffer->getRemaining()/sizeof(T)))+i;
for(; i<maxIndex; i++)
pbuffer->put<T>(value[i]);
*/
size_t maxCount = min<int>(end-i, (int)(pbuffer->getRemaining()/sizeof(T)));
pbuffer->putArray(pvalue+i, maxCount);
i += maxCount;
if(i<end)
while(count) {
const size_t empty = pbuffer->getRemaining();
const size_t space_for = empty/sizeof(T);
if(space_for==0) {
pflusher->flushSerializeBuffer();
else
break;
// Can we be certain that more space is now free???
// If not then we spinnnnnnnnn
continue;
}
const size_t n2send = std::min(count, space_for);
pbuffer->putArray(cur, n2send);
cur += n2send;
count -= n2send;
}
pflusher->flushSerializeBuffer();
}
// specializations for String
@@ -426,42 +373,37 @@ template<>
void DefaultPVArray<String>::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
//if(size>=0) {
// prepare array, if necessary
if(size>getCapacity()) setCapacity(size);
// set new length
setLength(size);
// retrieve value from the buffer
String * pvalue = get();
for(size_t i = 0; i<size; i++) {
pvalue[i] = SerializeHelper::deserializeString(pbuffer,
pcontrol);
}
// inform about the change?
postPut();
//}
// TODO null arrays (size == -1) not supported
svector nextvalue(thaw(value));
// Decide if we must re-allocate
if(size > nextvalue.size() || !nextvalue.unique())
nextvalue.resize(size);
else if(size < nextvalue.size())
nextvalue.slice(0, size);
String * pvalue = nextvalue.data();
for(size_t i = 0; i<size; i++) {
pvalue[i] = SerializeHelper::deserializeString(pbuffer,
pcontrol);
}
value = freeze(nextvalue);
// inform about the change?
postPut();
}
template<>
void DefaultPVArray<String>::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const {
size_t length = getLength();
// check bounds
/*if(offset<0)
offset = 0;
else*/ if(offset>length) offset = length;
//if(count<0) count = length;
const_svector temp(value);
temp.slice(offset, count);
size_t maxCount = length-offset;
if(count>maxCount) count = maxCount;
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
// write
SerializeHelper::writeSize(count, pbuffer, pflusher);
size_t end = offset+count;
String * pvalue = get();
for(size_t i = offset; i<end; i++) {
const String * pvalue = temp.data();
for(size_t i = 0; i<temp.size(); i++) {
SerializeHelper::serializeString(pvalue[i], pbuffer, pflusher);
}
}
@@ -646,7 +588,7 @@ PVScalarArrayPtr PVDataCreate::createPVScalarArray(
{
PVScalarArrayPtr pvArray = createPVScalarArray(
arrayToClone->getScalarArray()->getElementType());
getConvert()->copyScalarArray(arrayToClone,0, pvArray,0,arrayToClone->getLength());
pvArray->assign(*arrayToClone.get());
PVAuxInfoPtr from = arrayToClone->getPVAuxInfo();
PVAuxInfoPtr to = pvArray->getPVAuxInfo();
PVAuxInfo::PVInfoMap & map = from->getInfoMap();

View File

@@ -26,8 +26,7 @@ PVField::PVField(FieldConstPtr field)
: notImplemented("not implemented"),
parent(NULL),field(field),
fieldOffset(0), nextFieldOffset(0),
immutable(false),
convert(getConvert())
immutable(false)
{
}
@@ -64,11 +63,6 @@ void PVField::message(String message,MessageType messageType)
PVField::message(message,messageType,"");
}
String PVField::getFieldName() const
{
return fieldName;
}
void PVField::setRequester(RequesterPtr const &req)
{
if(parent!=NULL) {
@@ -180,7 +174,7 @@ void PVField::setParentAndName(PVStructure * xxx,String const & name)
bool PVField::equals(PVField &pv)
{
return convert->equals(*this,pv);
return pv==*this;
}
void PVField::toString(StringBuilder buf)
@@ -190,7 +184,7 @@ void PVField::toString(StringBuilder buf)
void PVField::toString(StringBuilder buf,int indentLevel)
{
convert->getString(buf,this,indentLevel);
Convert().getString(buf,this,indentLevel);
if(pvAuxInfo.get()!=NULL) pvAuxInfo->toString(buf,indentLevel);
}
@@ -223,6 +217,31 @@ namespace format
}
};
String PVField::getFullName() const
{
size_t size=fieldName.size();
for(PVField *fld=getParent(); fld; fld=fld->getParent())
{
size+=fld->fieldName.size()+1;
}
String ret(size, '.');
size_t pos=size - fieldName.size();
ret.replace(pos, String::npos, fieldName);
for(PVField *fld=getParent(); fld; fld=fld->getParent())
{
const String& nref = fld->fieldName;
assert(pos >= nref.size()+1);
pos -= nref.size()+1;
ret.replace(pos, String::npos, nref);
}
assert(pos==0);
return ret;
}
void PVField::computeOffset(const PVField * pvField) {
const PVStructure * pvTop = pvField->getParent();
if(pvTop==NULL) {

View File

@@ -28,16 +28,4 @@ namespace epics { namespace pvData {
return static_pointer_cast<const ScalarArray>(PVField::getField());
}
template<>
std::ostream& PVValueArray<int8>::dumpValue(std::ostream& o, size_t index) const
{
return o << static_cast<int>(*(get() + index));
}
template<>
std::ostream& PVValueArray<uint8>::dumpValue(std::ostream& o, size_t index) const
{
return o << static_cast<unsigned int>(*(get() + index));
}
}}

View File

@@ -21,44 +21,52 @@ using std::size_t;
namespace epics { namespace pvData {
PVStructureArray::PVStructureArray(StructureArrayConstPtr const & structureArray)
: PVArray(structureArray),
structureArray(structureArray),
value(std::tr1::shared_ptr<PVStructurePtrArray>(new PVStructurePtrArray()))
{
}
size_t PVStructureArray::append(size_t number)
{
size_t currentLength = getLength();
size_t newLength = currentLength + number;
setCapacity(newLength);
setLength(newLength);
svector data(reuse());
data.resize(data.size()+number);
StructureConstPtr structure = structureArray->getStructure();
PVStructurePtrArray *to = value.get();
for(size_t i=currentLength; i<newLength; i++) {
(*to)[i] =getPVDataCreate()->createPVStructure(structure);
}
for(svector::reverse_iterator it = data.rbegin(); number; ++it, --number)
*it = getPVDataCreate()->createPVStructure(structure);
size_t newLength = data.size();
const_svector cdata(freeze(data));
swap(cdata);
return newLength;
}
bool PVStructureArray::remove(size_t offset,size_t number)
{
size_t length = getLength();
if(offset+number>length) return false;
PVStructurePtrArray vec = *value.get();
if(number==0)
return true;
else if(offset+number>getLength())
return false;
svector vec(reuse());
size_t length = vec.size();
for(size_t i = offset; i+number < length; i++) {
vec[i] = vec[i + number];
vec[i].swap(vec[i + number]);
}
size_t newLength = length - number;
setCapacityLength(newLength,newLength);
vec.resize(length - number);
const_svector cdata(freeze(vec));
swap(cdata);
return true;
}
void PVStructureArray::compress() {
size_t length = getCapacity();
svector vec(reuse()); // TODO: check for first NULL before realloc
size_t length = vec.size();
size_t newLength = 0;
PVStructurePtrArray vec = *value.get();
for(size_t i=0; i<length; i++) {
if(vec[i].get()!=NULL) {
newLength++;
@@ -80,113 +88,50 @@ void PVStructureArray::compress() {
}
break;
}
setCapacityLength(newLength,newLength);
vec.resize(newLength);
const_svector cdata(freeze(vec));
swap(cdata);
}
void PVStructureArray::setCapacity(size_t capacity) {
if(getCapacity()==capacity) return;
if(!isCapacityMutable()) {
std::string message("not capacityMutable");
PVField::message(message, errorMessage);
return;
void PVStructureArray::setCapacity(size_t capacity)
{
if(this->isCapacityMutable()) {
const_svector value;
swap(value);
if(value.capacity()<capacity) {
svector mvalue(thaw(value));
mvalue.reserve(capacity);
value = freeze(mvalue);
}
swap(value);
}
size_t length = getLength();
if(length>capacity) length = capacity;
size_t oldCapacity = getCapacity();
if(oldCapacity>capacity) {
PVStructurePtrArray array;
array.reserve(capacity);
array.resize(length);
PVStructurePtr * from = get();
for (size_t i=0; i<length; i++) array[i] = from[i];
value->swap(array);
}
void PVStructureArray::setLength(size_t length)
{
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
const_svector value;
swap(value);
if(length == value.size()) {
// nothing
} else if(length < value.size()) {
value.slice(0, length);
} else {
value->reserve(capacity);
svector mvalue(thaw(value));
mvalue.resize(length);
value = freeze(mvalue);
}
setCapacityLength(capacity,length);
swap(value);
}
void PVStructureArray::setLength(size_t length) {
if(PVArray::getLength()==length) return;
size_t capacity = PVArray::getCapacity();
if(length>capacity) {
if(!PVArray::isCapacityMutable()) {
std::string message("not capacityMutable");
PVField::message(message, errorMessage);
return;
}
setCapacity(length);
}
value->resize(length);
PVArray::setCapacityLength(capacity,length);
}
StructureArrayConstPtr PVStructureArray::getStructureArray() const
void PVStructureArray::swap(const_svector &other)
{
return structureArray;
}
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
size_t PVStructureArray::get(
size_t offset, size_t len, StructureArrayData &data)
{
size_t n = len;
size_t length = getLength();
if(offset+len > length) {
n = length - offset;
//if(n<0) n = 0;
}
data.data = *value.get();
data.offset = offset;
return n;
}
size_t PVStructureArray::put(size_t offset,size_t len,
const_vector const & from, size_t fromOffset)
{
if(isImmutable()) {
message(String("field is immutable"), errorMessage);
return 0;
}
if(&from==value.get()) return 0;
if(len<1) return 0;
size_t length = getLength();
size_t capacity = getCapacity();
if(offset+len > length) {
size_t newlength = offset + len;
if(newlength>capacity) {
setCapacity(newlength);
capacity = getCapacity();
newlength = capacity;
len = newlength - offset;
if(len<=0) return 0;
}
length = newlength;
setLength(length);
}
PVStructurePtrArray *to = value.get();
StructureConstPtr structure = structureArray->getStructure();
for(size_t i=0; i<len; i++) {
PVStructurePtr frompv = from[i+fromOffset];
if(frompv.get()!=NULL) {
if(frompv->getStructure()!=structure) {
throw std::invalid_argument(String(
"Element is not a compatible structure"));
}
}
(*to)[i+offset] = frompv;
}
postPut();
setLength(length);
return len;
}
void PVStructureArray::shareData(
std::tr1::shared_ptr<std::vector<PVStructurePtr> > const & sharedValue,
std::size_t capacity,
std::size_t length)
{
value = sharedValue;
setCapacityLength(capacity,length);
value.swap(other);
}
void PVStructureArray::serialize(ByteBuffer *pbuffer,
@@ -196,56 +141,47 @@ void PVStructureArray::serialize(ByteBuffer *pbuffer,
void PVStructureArray::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
svector data(reuse());
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
//if(size>=0) {
// prepare array, if necessary
if(size>getCapacity()) setCapacity(size);
setLength(size);
PVStructurePtrArray *pvArray = value.get();
for(size_t i = 0; i<size; i++) {
pcontrol->ensureData(1);
size_t temp = pbuffer->getByte();
if(temp==0) {
(*pvArray)[i].reset();
}
else {
if((*pvArray)[i].get()==NULL) {
StructureConstPtr structure = structureArray->getStructure();
(*pvArray)[i] = getPVDataCreate()->createPVStructure(structure);
}
(*pvArray)[i]->deserialize(pbuffer, pcontrol);
}
data.resize(size);
StructureConstPtr structure = structureArray->getStructure();
for(size_t i = 0; i<size; i++) {
pcontrol->ensureData(1);
size_t temp = pbuffer->getByte();
if(temp==0) {
data[i].reset();
}
postPut();
//}
else {
if(data[i].get()==NULL) {
data[i] = getPVDataCreate()->createPVStructure(structure);
}
data[i]->deserialize(pbuffer, pcontrol);
}
}
replace(freeze(data)); // calls postPut()
}
void PVStructureArray::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const {
// cache
size_t length = getLength();
// check bounds
/*if(offset<0)
offset = 0;
else*/ if(offset>length) offset = length;
//if(count<0) count = length;
const_svector temp(view());
temp.slice(offset, count);
size_t maxCount = length-offset;
if(count>maxCount) count = maxCount;
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
PVStructurePtrArray pvArray = *value.get();
// write
SerializeHelper::writeSize(count, pbuffer, pflusher);
for(size_t i = 0; i<count; i++) {
if(pbuffer->getRemaining()<1) pflusher->flushSerializeBuffer();
PVStructurePtr pvStructure = pvArray[i+offset];
if(pvStructure.get()==NULL) {
if(pbuffer->getRemaining()<1)
pflusher->flushSerializeBuffer();
if(temp[i].get()==NULL) {
pbuffer->putByte(0);
}
else {
pbuffer->putByte(1);
pvStructure->serialize(pbuffer, pflusher);
temp[i]->serialize(pbuffer, pflusher);
}
}
}
@@ -267,9 +203,9 @@ std::ostream& PVStructureArray::dumpValue(std::ostream& o) const
std::ostream& PVStructureArray::dumpValue(std::ostream& o, std::size_t index) const
{
PVStructurePtrArray pvArray = *value.get();
PVStructurePtr pvStructure = pvArray[index];
return o << *(pvStructure.get());
const_svector temp(view());
if(index<temp.size())
o << temp[index].get();
return o;
}

View File

@@ -59,11 +59,9 @@ PVStructurePtr StandardPVField::enumerated(StringArray const &choices)
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(field);
PVScalarArrayPtr pvScalarArray = pvStructure->getScalarArrayField(
"choices",pvString);
if(pvScalarArray.get()==NULL) {
throw std::logic_error(String("StandardPVField::enumerated"));
}
PVStringArray * pvChoices = static_cast<PVStringArray *>(pvScalarArray.get());
pvChoices->put(0,choices.size(),get(choices),0);
PVStringArray::svector cdata(choices.size());
std::copy(choices.begin(), choices.end(), cdata.begin());
static_cast<PVStringArray&>(*pvScalarArray).replace(freeze(cdata));
return pvStructure;
}
@@ -74,11 +72,9 @@ PVStructurePtr StandardPVField::enumerated(
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(field);
PVScalarArrayPtr pvScalarArray = pvStructure->getScalarArrayField(
"value.choices",pvString);
if(pvScalarArray.get()==NULL) {
throw std::logic_error(String("StandardPVField::enumerated"));
}
PVStringArray * pvChoices = static_cast<PVStringArray *>(pvScalarArray.get());
pvChoices->put(0,choices.size(),get(choices),0);
PVStringArray::svector cdata(choices.size());
std::copy(choices.begin(), choices.end(), cdata.begin());
static_cast<PVStringArray&>(*pvScalarArray).replace(freeze(cdata));
return pvStructure;
}

View File

@@ -14,6 +14,7 @@
#include <pv/pvIntrospect.h>
#include <pv/epicsException.h>
#include <pv/sharedVector.h>
#include "dbDefs.h" // for NELEMENTS
@@ -61,7 +62,7 @@ namespace ScalarTypeFunc {
"ubyte", "ushort", "uint", "ulong",
"float", "double", "string",
};
ScalarType getScalarType(String pvalue) {
ScalarType getScalarType(const String& pvalue) {
for(size_t i=0; i<NELEMENTS(names); i++)
if(pvalue==names[i])
return ScalarType(i);
@@ -78,6 +79,50 @@ namespace ScalarTypeFunc {
*buf += name(scalarType);
}
size_t elementSize(ScalarType id)
{
switch(id) {
#define OP(ENUM, TYPE) case ENUM: return sizeof(TYPE)
OP(pvBoolean, boolean);
OP(pvUByte, uint8);
OP(pvByte, int8);
OP(pvUShort, uint16);
OP(pvShort, int16);
OP(pvUInt, uint32);
OP(pvInt, int32);
OP(pvULong, uint64);
OP(pvLong, int64);
OP(pvFloat, float);
OP(pvDouble, double);
OP(pvString, String);
#undef OP
default:
THROW_EXCEPTION2(std::invalid_argument, "error unknown ScalarType");
}
}
shared_vector<void> allocArray(ScalarType id, size_t len)
{
switch(id) {
#define OP(ENUM, TYPE) case ENUM: return static_shared_vector_cast<void>(shared_vector<TYPE>(len))
OP(pvBoolean, boolean);
OP(pvUByte, uint8);
OP(pvByte, int8);
OP(pvUShort, uint16);
OP(pvShort, int16);
OP(pvUInt, uint32);
OP(pvInt, int32);
OP(pvULong, uint64);
OP(pvLong, int64);
OP(pvFloat, float);
OP(pvDouble, double);
OP(pvString, String);
#undef OP
default:
throw std::bad_alloc();
}
}
} // namespace ScalarTypeFunc
}}

View File

@@ -0,0 +1,201 @@
#include <deque>
#include "pv/printer.h"
namespace {
void indentN(std::ostream& strm, size_t N)
{
while(N--)
strm.put(' ');
}
}
namespace epics { namespace pvData {
PrinterBase::PrinterBase()
:strm(NULL)
{}
PrinterBase::~PrinterBase() {}
void PrinterBase::setStream(std::ostream& s)
{
strm = &s;
}
void PrinterBase::clearStream()
{
strm = NULL;
}
void PrinterBase::print(const PVField& pv)
{
if(!strm)
throw std::runtime_error("No stream set for PV Printer");
impl_print(pv);
}
void PrinterBase::beginStructure(const PVStructure&) {}
void PrinterBase::endStructure(const PVStructure&) {}
void PrinterBase::beginStructureArray(const PVStructureArray&) {}
void PrinterBase::endStructureArray(const PVStructureArray&) {}
void PrinterBase::encodeScalar(const PVScalar& pv) {}
void PrinterBase::encodeArray(const PVScalarArray&) {}
void PrinterBase::encodeNull() {}
void PrinterBase::impl_print(const PVField& pv)
{
static const PVField* marker = (const PVField*)&marker;
/* Depth first recursive iteration.
* Each PV to be printed is appended to the todo queue.
* The last child of a structure is followed by a NULL.
* As the tree is walked structures and structarrays
* are appended to the inprog queue.
*/
std::deque<const PVField*> todo, inprog;
todo.push_back(&pv);
while(!todo.empty()) {
const PVField *next = todo.front();
todo.pop_front();
if(next==marker) {
// finished with a structure or structarray,
// now we fall back to its parent.
assert(!inprog.empty());
switch(inprog.back()->getField()->getType()) {
case structure:
endStructure(*static_cast<const PVStructure *>(inprog.back()));
break;
case structureArray:
endStructureArray(*static_cast<const PVStructureArray *>(inprog.back()));
break;
default:
assert(false); // oops!
return;
}
inprog.pop_back();
} else {
// real field
if(!next) {
// NULL entry in a structure array
encodeNull();
continue;
}
switch(next->getField()->getType()) {
case scalar:
encodeScalar(*static_cast<const PVScalar*>(next));
break;
case scalarArray:
encodeArray(*static_cast<const PVScalarArray*>(next));
break;
case structure: {
const PVStructure &fld = *static_cast<const PVStructure*>(next);
const PVFieldPtrArray& vals = fld.getPVFields();
inprog.push_back(next);
beginStructure(fld);
for(size_t i=0, nfld=fld.getStructure()->getNumberFields(); i<nfld; i++)
todo.push_back(vals[i].get());
todo.push_back(marker);
break;
}
case structureArray: {
const PVStructureArray &fld = *static_cast<const PVStructureArray*>(next);
PVStructureArray::const_svector vals(fld.view());
inprog.push_back(next);
beginStructureArray(fld);
for(PVStructureArray::const_svector::const_iterator it=vals.begin();
it!=vals.end(); ++it)
{
todo.push_back(it->get());
}
todo.push_back(marker);
break;
}
}
}
}
}
PrinterPlain::PrinterPlain()
:PrinterBase()
,ilvl(0)
{}
PrinterPlain::~PrinterPlain() {}
void PrinterPlain::beginStructure(const PVStructure& pv)
{
indentN(S(), ilvl);
S() << pv.getStructure()->getID() << " " << pv.getFieldName();
String ename(pv.getExtendsStructureName());
if(!ename.empty())
S() << " extends " << ename;
S() << std::endl;
ilvl++;
}
void PrinterPlain::endStructure(const PVStructure&) {ilvl--;}
void PrinterPlain::beginStructureArray(const PVStructureArray& pv)
{
indentN(S(), ilvl);
S() << pv.getStructureArray()->getID() << " "
<< pv.getFieldName() << "[] ";
ilvl++;
}
void PrinterPlain::endStructureArray(const PVStructureArray&) {ilvl--;}
void PrinterPlain::encodeScalar(const PVScalar& pv)
{
indentN(S(), ilvl);
S() << pv.getScalar()->getID() << " "
<< pv.getFieldName() << " "
<< pv.getAs<String>() << std::endl;
}
void PrinterPlain::encodeArray(const PVScalarArray& pv)
{
indentN(S(), ilvl);
shared_vector<const String> temp;
pv.getAs<String>(temp);
S() << pv.getScalarArray()->getID() << " "
<< pv.getFieldName() << " [";
for(size_t i=0, len=pv.getLength(); i<len; i++) {
S() << temp[i];
if(i!=len-1)
S().put(',');
}
S() << "]" << std::endl;
}
void PrinterPlain::encodeNull()
{
indentN(S(), ilvl);
S() << "NULL" << std::endl;
}
}}

View File

@@ -379,7 +379,7 @@ public:
* @param count The number of elements.
*/
template<typename T>
inline void putArray(T* values, std::size_t count);
inline void putArray(const T* values, std::size_t count);
/**
* Get an array of type {@code T} from the byte buffer.
* The position is adjusted.
@@ -842,7 +842,7 @@ private:
}
template<typename T>
inline void ByteBuffer::putArray(T* values, std::size_t count)
inline void ByteBuffer::putArray(const T* values, std::size_t count)
{
// this avoids int8 specialization, compiler will take care if optimization, -O2 or more
if (sizeof(T) == 1)

View File

@@ -103,7 +103,7 @@ namespace detail {
*
* Takes advantage of the requirement that all exception classes
* must be copy constructable. Of course this also requires
* the and extra copy be constructed...
* that an extra copy be constructed...
*/
template<typename E>
class ExceptionMixed : public E, public ExceptionMixin {

View File

@@ -0,0 +1,467 @@
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <float.h>
#include <epicsVersion.h>
#include <epicsMath.h>
#include <epicsStdlib.h>
#include <epicsString.h>
#include <epicsConvert.h>
#include "typeCast.h"
// need to use "long long" when sizeof(int)==sizeof(long)
#if ULONG_MAX == 0xfffffffful
#define NEED_LONGLONG
#endif
#ifndef EPICS_VERSION_INT
#define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
#define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL)
#endif
#if EPICS_VERSION_INT < VERSION_INT(3,15,0,1)
/* integer conversion primatives added to epicsStdlib.c in 3.15.0.1 */
#define S_stdlib_noConversion 1 /* No digits to convert */
#define S_stdlib_extraneous 2 /* Extraneous characters */
#define S_stdlib_underflow 3 /* Too small to represent */
#define S_stdlib_overflow 4 /* Too large to represent */
#define S_stdlib_badBase 5 /* Number base not supported */
static int
epicsParseLong(const char *str, long *to, int base, char **units)
{
int c;
char *endp;
long value;
while ((c = *str) && isspace(c))
++str;
errno = 0;
value = strtol(str, &endp, base);
if (endp == str)
return S_stdlib_noConversion;
if (errno == EINVAL) /* Not universally supported */
return S_stdlib_badBase;
if (errno == ERANGE)
return S_stdlib_overflow;
while ((c = *endp) && isspace(c))
++endp;
if (c && !units)
return S_stdlib_extraneous;
*to = value;
if (units)
*units = endp;
return 0;
}
static int
epicsParseULong(const char *str, unsigned long *to, int base, char **units)
{
int c;
char *endp;
unsigned long value;
while ((c = *str) && isspace(c))
++str;
errno = 0;
value = strtoul(str, &endp, base);
if (endp == str)
return S_stdlib_noConversion;
if (errno == EINVAL) /* Not universally supported */
return S_stdlib_badBase;
if (errno == ERANGE)
return S_stdlib_overflow;
while ((c = *endp) && isspace(c))
++endp;
if (c && !units)
return S_stdlib_extraneous;
*to = value;
if (units)
*units = endp;
return 0;
}
static int
epicsParseDouble(const char *str, double *to, char **units)
{
int c;
char *endp;
double value;
while ((c = *str) && isspace(c))
++str;
errno = 0;
value = epicsStrtod(str, &endp);
if (endp == str)
return S_stdlib_noConversion;
if (errno == ERANGE)
return (value == 0) ? S_stdlib_underflow : S_stdlib_overflow;
while ((c = *endp) && isspace(c))
++endp;
if (c && !units)
return S_stdlib_extraneous;
*to = value;
if (units)
*units = endp;
return 0;
}
/* These call the primitives */
static int
epicsParseInt8(const char *str, epicsInt8 *to, int base, char **units)
{
long value;
int status = epicsParseLong(str, &value, base, units);
if (status)
return status;
if (value < -0x80 || value > 0x7f)
return S_stdlib_overflow;
*to = value;
return 0;
}
static int
epicsParseUInt8(const char *str, epicsUInt8 *to, int base, char **units)
{
unsigned long value;
int status = epicsParseULong(str, &value, base, units);
if (status)
return status;
if (value > 0xff && value <= ~0xffUL)
return S_stdlib_overflow;
*to = value;
return 0;
}
static int
epicsParseInt16(const char *str, epicsInt16 *to, int base, char **units)
{
long value;
int status = epicsParseLong(str, &value, base, units);
if (status)
return status;
if (value < -0x8000 || value > 0x7fff)
return S_stdlib_overflow;
*to = value;
return 0;
}
static int
epicsParseUInt16(const char *str, epicsUInt16 *to, int base, char **units)
{
unsigned long value;
int status = epicsParseULong(str, &value, base, units);
if (status)
return status;
if (value > 0xffff && value <= ~0xffffUL)
return S_stdlib_overflow;
*to = value;
return 0;
}
static int
epicsParseInt32(const char *str, epicsInt32 *to, int base, char **units)
{
long value;
int status = epicsParseLong(str, &value, base, units);
if (status)
return status;
#if (LONG_MAX > 0x7fffffff)
if (value < -0x80000000L || value > 0x7fffffffL)
return S_stdlib_overflow;
#endif
*to = value;
return 0;
}
static int
epicsParseUInt32(const char *str, epicsUInt32 *to, int base, char **units)
{
unsigned long value;
int status = epicsParseULong(str, &value, base, units);
if (status)
return status;
#if (ULONG_MAX > 0xffffffff)
if (value > 0xffffffffUL && value <= ~0xffffffffUL)
return S_stdlib_overflow;
#endif
*to = value;
return 0;
}
static int
epicsParseFloat(const char *str, float *to, char **units)
{
double value, abs;
int status = epicsParseDouble(str, &value, units);
if (status)
return status;
abs = fabs(value);
if (value > 0 && abs <= FLT_MIN)
return S_stdlib_underflow;
if (finite(value) && abs >= FLT_MAX)
return S_stdlib_overflow;
*to = value;
return 0;
}
#endif
#if defined(NEED_LONGLONG) && defined(__vxworks)
static
long long strtoll(const char *ptr, char ** endp, int base)
{
size_t inlen = strlen(ptr);
long long result;
unsigned char offset=0;
assert(base==0);
if(ptr[0]=='-')
offset=1;
try {
std::istringstream strm(ptr);
assert(strm.rdbuf()->in_avail()>=0
&& inlen==(size_t)strm.rdbuf()->in_avail());
if(ptr[offset]=='0') {
if(ptr[offset+1]=='x')
strm >> std::hex;
else
strm >> std::oct;
}
strm >> result;
if(strm.fail())
goto noconvert;
assert(strm.rdbuf()->in_avail()>=0
&& inlen>=(size_t)strm.rdbuf()->in_avail());
size_t consumed = inlen - strm.rdbuf()->in_avail();
*endp = (char*)ptr + consumed;
return result;
} catch(...) {
goto noconvert;
}
return result;
noconvert:
*endp = (char*)ptr;
return 0;
}
static
unsigned long long strtoull(const char *ptr, char ** endp, int base)
{
size_t inlen = strlen(ptr);
unsigned long long result;
assert(base==0);
try {
std::istringstream strm(ptr);
assert(strm.rdbuf()->in_avail()>=0
&& inlen==(size_t)strm.rdbuf()->in_avail());
if(ptr[0]=='0') {
if(ptr[1]=='x')
strm >> std::hex;
else
strm >> std::oct;
}
strm >> result;
if(strm.fail())
goto noconvert;
assert(strm.rdbuf()->in_avail()>=0
&& inlen>=(size_t)strm.rdbuf()->in_avail());
size_t consumed = inlen - strm.rdbuf()->in_avail();
*endp = (char*)ptr + consumed;
return result;
} catch(...) {
goto noconvert;
}
return result;
noconvert:
*endp = (char*)ptr;
return 0;
}
#endif
/* do we need long long? */
#ifdef NEED_LONGLONG
static int
epicsParseLongLong(const char *str, long long *to, int base, char **units)
{
int c;
char *endp;
long long value;
while ((c = *str) && isspace(c))
++str;
errno = 0;
value = strtoll(str, &endp, base);
if (endp == str)
return S_stdlib_noConversion;
if (errno == EINVAL) /* Not universally supported */
return S_stdlib_badBase;
if (errno == ERANGE)
return S_stdlib_overflow;
while ((c = *endp) && isspace(c))
++endp;
if (c && !units)
return S_stdlib_extraneous;
*to = value;
if (units)
*units = endp;
return 0;
}
static int
epicsParseULongLong(const char *str, unsigned long long *to, int base, char **units)
{
int c;
char *endp;
unsigned long long value;
while ((c = *str) && isspace(c))
++str;
errno = 0;
value = strtoull(str, &endp, base);
if (endp == str)
return S_stdlib_noConversion;
if (errno == EINVAL) /* Not universally supported */
return S_stdlib_badBase;
if (errno == ERANGE)
return S_stdlib_overflow;
while ((c = *endp) && isspace(c))
++endp;
if (c && !units)
return S_stdlib_extraneous;
*to = value;
if (units)
*units = endp;
return 0;
}
#endif
static
void handleParseError(int err)
{
switch(err) {
case 0: break;
case S_stdlib_noConversion: throw std::runtime_error("parseToPOD: No digits to convert");
case S_stdlib_extraneous: throw std::runtime_error("parseToPOD: Extraneous characters");
case S_stdlib_underflow: throw std::runtime_error("parseToPOD: Too small to represent");
case S_stdlib_overflow: throw std::runtime_error("parseToPOD: Too large to represent");
case S_stdlib_badBase: throw std::runtime_error("parseToPOD: Number base not supported");
default:
throw std::runtime_error("parseToPOD: unknown error");
}
}
namespace epics { namespace pvData { namespace detail {
#define INTFN(T, S) \
void parseToPOD(const std::string& in, T *out) { \
epics ## S temp; \
int err = epicsParse ## S (in.c_str(), &temp, 0, NULL); \
if(err) handleParseError(err); \
else *out = temp; \
}
INTFN(char, Int8);
INTFN(int8_t, Int8);
INTFN(uint8_t, UInt8);
INTFN(int16_t, Int16);
INTFN(uint16_t, UInt16);
INTFN(int32_t, Int32);
INTFN(uint32_t, UInt32);
void parseToPOD(const std::string& in, int64_t *out) {
#ifdef NEED_LONGLONG
int err = epicsParseLongLong(in.c_str(), out, 0, NULL);
#else
int err = epicsParseLong(in.c_str(), out, 0, NULL);
#endif
if(err) handleParseError(err);
}
void parseToPOD(const std::string& in, uint64_t *out) {
#ifdef NEED_LONGLONG
int err = epicsParseULongLong(in.c_str(), out, 0, NULL);
#else
int err = epicsParseULong(in.c_str(), out, 0, NULL);
#endif
if(err) handleParseError(err);
}
void parseToPOD(const std::string& in, float *out) {
int err = epicsParseFloat(in.c_str(), out, NULL);
if(err) handleParseError(err);
}
void parseToPOD(const std::string& in, double *out) {
int err = epicsParseDouble(in.c_str(), out, NULL);
if(err) handleParseError(err);
}
}}}

View File

@@ -4,7 +4,7 @@
* in file LICENSE that is included with this distribution.
*/
/**
* @author Michael DavidSaver
* @author Michael Davidsaver
*/
#ifndef SHAREDPTR_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,120 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/** C++ Template meta programming helpers
*/
#ifndef TEMPLATEMETA_H
#define TEMPLATEMETA_H
// gently nudge the compiler to inline our wrappers
// Warning: Only use this when the template body is *small*.
// You have been warned!
#if defined(__GNUC__) && __GNUC__>=3
# define FORCE_INLINE __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
# define FORCE_INLINE __forceinline
#else
# define FORCE_INLINE inline
#endif
namespace epics { namespace pvData {
namespace meta {
/** If needed, add the 'const' qualifier to the provided type.
*
* Avoids adding the const qualifier twice (aka 'const const int')
@code
assert(typeid(decorate_const<int>::type)==typeid(const int));
assert(typeid(decorate_const<const int>::type)==typeid(const int));
@endcode
*/
template<typename T> struct decorate_const { typedef const T type; };
template<typename T> struct decorate_const<const T> { typedef const T type; };
/** Remove the 'const' qualifier if present
@code
assert(typeid(strip_const<int>::type)==typeid(int));
assert(typeid(strip_const<const int>::type)==typeid(int));
@endcode
*/
template<typename T> struct strip_const { typedef T type; };
template<typename T> struct strip_const<const T> { typedef T type; };
/** test to allow specialization only when A!=B
*
@code
template<typename A, typename B, class Enable = void>
struct myTemp {...};
// specialization when A==B
template<typename T>
struct myTemp<T,T> {...};
// specialization for A is 'int',
// enabler needed to remove ambiguity when B is 'int'.
template<typename B>
struct myTemp<int, B, typename meta::not_same_type<int,B>::type>
{...};
@endcode
*/
template<typename A, typename B, typename R = void>
struct not_same_type {typedef R type;};
template<typename A>
struct not_same_type<A,A> {};
//! Select if both A and B have the same root type (excluding const qualifier)
template<typename A, typename B, class R = void> struct same_root {};
template<typename T, class R> struct same_root<T,T,R> { typedef R type; };
template<typename T, class R> struct same_root<const T,T,R> { typedef R type; };
template<typename T, class R> struct same_root<T,const T,R> { typedef R type; };
namespace detail {
struct _const_yes {};
struct _const_no {};
template<typename T> struct _has_const { typedef _const_no type; };
template<typename T> struct _has_const<const T> { typedef _const_yes type; };
template<typename A, typename B, class R = void> struct _same_type {};
template<typename T, class R> struct _same_type<T,T,R> { typedef R type; };
} // namespace detail
//! Check if both A and B are either const or non-const.
template<typename A, typename B, class R = void>
struct same_const :
public detail::_same_type<typename detail::_has_const<A>::type,
typename detail::_has_const<B>::type,
R>
{};
/** test if provided type is 'void' or 'const void'
*
* Avoid having to explicitly specialize for both
@code
template<typename A, class Enable = void>
struct myTemp {...};
// specialization when A is 'void' or 'const void'
template<typename A>
struct myTemp<A, typename meta::is_void<A>::type> {...};
@endcode
*/
template<typename T, class R = void> struct is_void {};
template<class R> struct is_void<void,R> { typedef R type; };
template<class R> struct is_void<const void,R> { typedef R type; };
//! Inverse of is_void<T>
template<typename T, class R = void> struct is_not_void { typedef R type; };
template<> struct is_not_void<void> {};
template<> struct is_not_void<const void> {};
//! Enabler to ensure that both conditions A and B are true
template<typename A, typename B, class EnableA = void, class EnableB = void, class R = void>
struct _and {};
template<typename A, typename B, class R>
struct _and<A,B, typename A::type, typename B::type, R> { typedef R type; };
}}}
#endif // TEMPLATEMETA_H

230
pvDataApp/misc/typeCast.cpp Normal file
View File

@@ -0,0 +1,230 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/* Author: Michael Davidsaver */
#include <algorithm>
#include "typeCast.h"
using epics::pvData::castUnsafe;
using epics::pvData::String;
using epics::pvData::ScalarType;
using epics::pvData::pvString;
namespace {
static void noconvert(size_t, void*, const void*)
{
throw std::runtime_error("castUnsafeV: Conversion not supported");
}
template<typename TO, typename FROM>
static void castVTyped(size_t count, void *draw, const void *sraw)
{
TO *dest=(TO*)draw;
const FROM *src=(FROM*)sraw;
std::transform(src, src+count, dest, castUnsafe<TO,FROM>);
}
template<typename T>
static void copyV(size_t count, void *draw, const void *sraw)
{
T *dest=(T*)draw;
const T *src=(T*)sraw;
std::copy(src, src+count, dest);
}
typedef void (*convertfn)(size_t, void*, const void*);
/* lookup table of converter functions.
* first dimension is TO, second is FROM
*/
static convertfn converters[pvString+1][pvString+1] =
{
// to pvBoolean
{ &noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert
},
// to pvByte
{&noconvert,
&copyV<int8_t>,
&castVTyped<int8_t, int16_t>,
&castVTyped<int8_t, int32_t>,
&castVTyped<int8_t, int64_t>,
&castVTyped<int8_t, uint8_t>,
&castVTyped<int8_t, uint16_t>,
&castVTyped<int8_t, uint32_t>,
&castVTyped<int8_t, uint64_t>,
&castVTyped<int8_t, float>,
&castVTyped<int8_t, double>,
&castVTyped<int8_t, String>,
},
// to pvShort
{&noconvert,
&castVTyped<int16_t, int8_t>,
&copyV<int16_t>,
&castVTyped<int16_t, int32_t>,
&castVTyped<int16_t, int64_t>,
&castVTyped<int16_t, uint8_t>,
&castVTyped<int16_t, uint16_t>,
&castVTyped<int16_t, uint32_t>,
&castVTyped<int16_t, uint64_t>,
&castVTyped<int16_t, float>,
&castVTyped<int16_t, double>,
&castVTyped<int16_t, String>,
},
// to pvInt
{&noconvert,
&castVTyped<int32_t, int8_t>,
&castVTyped<int32_t, int16_t>,
&copyV<int32_t>,
&castVTyped<int32_t, int64_t>,
&castVTyped<int32_t, uint8_t>,
&castVTyped<int32_t, uint16_t>,
&castVTyped<int32_t, uint32_t>,
&castVTyped<int32_t, uint64_t>,
&castVTyped<int32_t, float>,
&castVTyped<int32_t, double>,
&castVTyped<int32_t, String>,
},
// to pvLong
{&noconvert,
&castVTyped<int64_t, int8_t>,
&castVTyped<int64_t, int16_t>,
&castVTyped<int64_t, int32_t>,
&copyV<int64_t>,
&castVTyped<int64_t, uint8_t>,
&castVTyped<int64_t, uint16_t>,
&castVTyped<int64_t, uint32_t>,
&castVTyped<int64_t, uint64_t>,
&castVTyped<int64_t, float>,
&castVTyped<int64_t, double>,
&castVTyped<int64_t, String>,
},
// to pvUByte
{&noconvert,
&castVTyped<uint8_t, int8_t>,
&castVTyped<uint8_t, int16_t>,
&castVTyped<uint8_t, int32_t>,
&castVTyped<uint8_t, uint64_t>,
&copyV<uint8_t>,
&castVTyped<uint8_t, uint16_t>,
&castVTyped<uint8_t, uint32_t>,
&castVTyped<uint8_t, uint64_t>,
&castVTyped<uint8_t, float>,
&castVTyped<uint8_t, double>,
&castVTyped<uint8_t, String>,
},
// to pvUShort
{&noconvert,
&castVTyped<uint16_t, int8_t>,
&castVTyped<uint16_t, int16_t>,
&castVTyped<uint16_t, int32_t>,
&castVTyped<uint16_t, uint64_t>,
&castVTyped<uint16_t, uint8_t>,
&copyV<uint16_t>,
&castVTyped<uint16_t, uint32_t>,
&castVTyped<uint16_t, uint64_t>,
&castVTyped<uint16_t, float>,
&castVTyped<uint16_t, double>,
&castVTyped<uint16_t, String>,
},
// to pvUInt
{&noconvert,
&castVTyped<uint32_t, int8_t>,
&castVTyped<uint32_t, int16_t>,
&castVTyped<uint32_t, int32_t>,
&castVTyped<uint32_t, uint64_t>,
&castVTyped<uint32_t, uint8_t>,
&castVTyped<uint32_t, uint16_t>,
&copyV<uint32_t>,
&castVTyped<uint32_t, uint64_t>,
&castVTyped<uint32_t, float>,
&castVTyped<uint32_t, double>,
&castVTyped<uint32_t, String>,
},
// to pvULong
{&noconvert,
&castVTyped<uint64_t, int8_t>,
&castVTyped<uint64_t, int16_t>,
&castVTyped<uint64_t, int32_t>,
&castVTyped<uint64_t, uint64_t>,
&castVTyped<uint64_t, uint8_t>,
&castVTyped<uint64_t, uint16_t>,
&castVTyped<uint64_t, uint32_t>,
&copyV<uint64_t>,
&castVTyped<uint64_t, float>,
&castVTyped<uint64_t, double>,
&castVTyped<uint64_t, String>,
},
// to pvFloat
{&noconvert,
&castVTyped<float, int8_t>,
&castVTyped<float, int16_t>,
&castVTyped<float, int32_t>,
&castVTyped<float, uint64_t>,
&castVTyped<float, uint8_t>,
&castVTyped<float, uint16_t>,
&castVTyped<float, uint32_t>,
&castVTyped<float, uint64_t>,
&copyV<float>,
&castVTyped<float, double>,
&castVTyped<float, String>,
},
// to pvDouble
{&noconvert,
&castVTyped<double, int8_t>,
&castVTyped<double, int16_t>,
&castVTyped<double, int32_t>,
&castVTyped<double, uint64_t>,
&castVTyped<double, uint8_t>,
&castVTyped<double, uint16_t>,
&castVTyped<double, uint32_t>,
&castVTyped<double, uint64_t>,
&castVTyped<double, float>,
&copyV<double>,
&castVTyped<double, String>,
},
// to pvString
{&noconvert,
&castVTyped<String, int8_t>,
&castVTyped<String, int16_t>,
&castVTyped<String, int32_t>,
&castVTyped<String, uint64_t>,
&castVTyped<String, uint8_t>,
&castVTyped<String, uint16_t>,
&castVTyped<String, uint32_t>,
&castVTyped<String, uint64_t>,
&castVTyped<String, float>,
&castVTyped<String, double>,
&copyV<String>,
},
};
} // end namespace
namespace epics { namespace pvData {
void castUnsafeV(size_t count, ScalarType to, void *dest, ScalarType from, const void *src)
{
unsigned int ito=to, ifrom=from;
if(ito>pvString || ifrom>pvString)
throw std::runtime_error("castUnsafeV: Invalid types");
converters[ito][ifrom](count, dest, src);
}
}}

172
pvDataApp/misc/typeCast.h Normal file
View File

@@ -0,0 +1,172 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/* Author: Michael Davidsaver */
#ifndef PVTYPECAST_H
#define PVTYPECAST_H
#include <stdexcept>
#include <sstream>
#include <epicsConvert.h>
#include <pv/pvType.h>
#include <pv/pvIntrospect.h>
#include <pv/templateMeta.h>
namespace epics { namespace pvData {
typedef std::string String;
namespace detail {
// parseToPOD wraps the epicsParse*() functions in one name
// and throws exceptions
void parseToPOD(const std::string&, char *out);
void parseToPOD(const std::string&, int8_t *out);
void parseToPOD(const std::string&, uint8_t *out);
void parseToPOD(const std::string&, int16_t *out);
void parseToPOD(const std::string&, uint16_t *out);
void parseToPOD(const std::string&, int32_t *out);
void parseToPOD(const std::string&, uint32_t *out);
void parseToPOD(const std::string&, int64_t *out);
void parseToPOD(const std::string&, uint64_t *out);
void parseToPOD(const std::string&, float *out);
void parseToPOD(const std::string&, double *out);
/* want to pass POD types by value,
* and String by const reference
*/
template<typename ARG>
struct cast_arg { typedef ARG arg; };
template<>
struct cast_arg<String> { typedef const String& arg; };
// trick std::ostream into treating char's as numbers
// by promoting char to int
template<typename T>
struct print_cast { typedef T type; };
template<>
struct print_cast<char> { typedef int type; };
template<>
struct print_cast<signed char> { typedef signed int type; };
template<>
struct print_cast<unsigned char> { typedef unsigned int type; };
// default to C++ type casting
template<typename TO, typename FROM, class Enable = void>
struct cast_helper {
static FORCE_INLINE TO op(FROM from) {
return static_cast<TO>(from);
}
};
// special handling when down-casting double to float
template<>
struct cast_helper<float, double> {
static FORCE_INLINE float op(double from) {
return epicsConvertDoubleToFloat(from);
}
};
// print POD to string
// when String!=FROM
template<typename FROM>
struct cast_helper<String, FROM, typename meta::not_same_type<String,FROM>::type> {
static String op(FROM from) {
typedef typename print_cast<FROM>::type ptype;
std::ostringstream strm;
strm << (ptype)from;
if(strm.fail())
throw std::runtime_error("Cast to string failed");
return strm.str();
}
};
// parse POD from string
// TO!=String
template<typename TO>
struct cast_helper<TO, String, typename meta::not_same_type<TO,String>::type> {
static FORCE_INLINE TO op(const String& from) {
TO ret;
parseToPOD(from, &ret);
return ret;
}
};
} // end detail
/** @brief Casting/converting between supported scalar types.
*
* Supported types: uint8_t, int8_t, uint16_t, int16_t,
* uint32_t, int32_t, uint64_t, int64_t,
* float, double, String
*
* As defined in pvType.h
*
@throws std::runtime_error when the cast is not possible.
@throws std::bad_alloc when the cast is not possible.
*
@section convertg Conversion Guarantees
*
* Conversions which always produce a correct result.
*
* - signed integer -> larger signed integer
* - unsigned integer -> larger unsigned integer
* - integer -> float or double (where sizeof(integer)<sizeof(floating))
* - float -> double
*
* Conversions where out of range inputs always produce
* a defined result, but may not be reversable.
*
* - double -> float. When abs(value) is outside the range
* [FLT_MIN, FLT_MAX] the value is clipped to FLT_MIN or FLT_MAX
* with the sign preserved.
*
* Conversions where invalid or out of range inputs result
* in an exception.
*
* - non-String -> String
* - String -> non-String
* - String -> String (throws only std::bad_alloc)
*
* Conversions where out of range inputs produce undefined
* results.
*
* - signed integer -> smaller signed integer
* - unsigned integer -> smaller unsigned integer
* - signed integer <-> unsigned integer
* - integer -> float or double (where sizeof(integer)>=sizeof(floating))
* - float or double -> integer. The floating point value
* is rounded towards zero. However, the result for values
* too large to be represented by the integer type
* is not defined.
*
@section stringf String formats
*
* - Numbers beginning with 1-9 are parsed as base-10.
* - Numbers beginning with '0x' are parsed as base-16
* - Numbers beginning with '0' are parsed as base-8.
* - Hex numbers are case insensitive.
* - Exponential numbers may use either 'e' or 'E'.
*/
template<typename TO, typename FROM>
static FORCE_INLINE TO castUnsafe(const FROM& from)
{
return detail::cast_helper<TO,FROM>::op(from);
}
void castUnsafeV(size_t count, ScalarType to, void *dest, ScalarType from, const void *src);
//! Cast value to printable type
//! A no-op except for char types, which are cast to int
//! so that they are printed as numbers std::ostream operators.
template<typename T>
static FORCE_INLINE
typename detail::print_cast<T>::type
print_cast(const T& v) { return v; }
}} // end namespace
#endif // PVTYPECAST_H

View File

@@ -78,9 +78,8 @@ String PVEnumerated::getChoice()
throw std::logic_error(notAttached);
}
int index = pvIndex->get();
StringArrayData data;
pvChoices->get(0,pvChoices->getLength(),data);
return data.data[index];
const PVStringArray::const_svector& data(pvChoices->view());
return data[index];
}
bool PVEnumerated::choicesMutable()
@@ -91,15 +90,6 @@ bool PVEnumerated::choicesMutable()
return pvChoices->isImmutable();
}
StringArrayPtr const & PVEnumerated:: getChoices()
{
if(pvIndex.get()==NULL ) {
throw std::logic_error(notAttached);
}
StringArrayData data;
return pvChoices->getSharedVector();
}
int32 PVEnumerated::getNumberChoices()
{
if(pvIndex.get()==NULL ) {
@@ -108,13 +98,15 @@ int32 PVEnumerated::getNumberChoices()
return pvChoices->getLength();
}
bool PVEnumerated:: setChoices(StringArray & choices)
bool PVEnumerated:: setChoices(const StringArray & choices)
{
if(pvIndex.get()==NULL ) {
throw std::logic_error(notAttached);
}
if(pvChoices->isImmutable()) return false;
pvChoices->put(0,choices.size(),get(choices),0);
PVStringArray::svector data(choices.size());
std::copy(choices.begin(), choices.end(), data.begin());
pvChoices->replace(freeze(data));
return true;
}

View File

@@ -30,9 +30,9 @@ public:
int32 getIndex();
String getChoice();
bool choicesMutable();
StringArrayPtr const & getChoices();
inline PVStringArray::const_svector getChoices(){return pvChoices->view();}
int32 getNumberChoices();
bool setChoices(StringArray & choices);
bool setChoices(const StringArray & choices);
private:
static String notFound;
static String notAttached;

View File

@@ -19,9 +19,9 @@
namespace epics { namespace pvData {
bool operator==(PVField&, PVField&);
bool operator==(const PVField&, const PVField&);
static inline bool operator!=(PVField& a, PVField& b)
static inline bool operator!=(const PVField& a, const PVField& b)
{return !(a==b);}
@@ -71,13 +71,16 @@ typedef std::tr1::shared_ptr<Convert> ConvertPtr;
class Convert {
public:
static ConvertPtr getConvert();
~Convert();
/**
* Get the full fieldName for the pvField.
* @param builder The builder that will have the result.
* @param pvField The pvField.
*/
void getFullName(StringBuilder buf,PVFieldPtr const & pvField);
void getFullName(StringBuilder buf,PVFieldPtr const & pvField)
{
*buf = pvField->getFullName();
}
/**
* Do fields have the same definition.
*
@@ -85,7 +88,11 @@ public:
* @param Second field
* @return (false, true) if the fields (are not, are) the same.
*/
bool equals(PVFieldPtr const &a,PVFieldPtr const &b);
inline bool equals(PVFieldPtr const &a,PVFieldPtr const &b)
{
return *a==*b;
}
/**
* Do fields have the same definition.
*
@@ -93,7 +100,11 @@ public:
* @param Second field
* @return (false, true) if the fields (are not, are) the same.
*/
bool equals(PVField &a,PVField &b);
inline bool equals(PVField &a,PVField &b)
{
return a==b;
}
/**
* Convert a PVField to a string.
* @param buf buffer for the result
@@ -101,14 +112,16 @@ public:
* If a PVField is a structure or array be prepared for a very long string.
* @param indentLevel indentation level
*/
void getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel);
inline void getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel)
{getString(buf, pvField.get(), indentLevel);}
/**
* Convert a PVField to a string.
* param buf buffer for the result
* @param pv The PVField to convert to a string.
* If the PVField is a structure or array be prepared for a very long string.
*/
void getString(StringBuilder buf,PVFieldPtr const & pvField);
inline void getString(StringBuilder buf,PVFieldPtr const & pvField)
{getString(buf, pvField.get(), 0);}
/**
* Convert a PVField to a string.
* @param buf buffer for the result
@@ -123,7 +136,8 @@ public:
* @param pv The PVField to convert to a string.
* If the PVField is a structure or array be prepared for a very long string.
*/
void getString(StringBuilder buf,PVField const * pvField);
inline void getString(StringBuilder buf,PVField const * pvField)
{getString(buf, pvField, 0);}
/**
* Convert from an array of String to a PVScalar
* @param pv The PV.
@@ -141,7 +155,11 @@ public:
* @param from The String value to convert and put into a PV.
* @throws std::logic_error if the String does not have a valid value.
*/
void fromString(PVScalarPtr const & pv, String const & from);
void fromString(PVScalarPtr const & pv, String const & from)
{
pv->putFrom<String>(from);
}
/**
* Convert from a String to a PVScalarArray.
* The String must be a comma separated set of values optionally enclosed in []
@@ -235,22 +253,6 @@ public:
bool isCopyScalarArrayCompatible(
ScalarArrayConstPtr const & from,
ScalarArrayConstPtr const & to);
/**
* Convert from a source PV array to a destination PV array.
* @param from The source array.
* @param offset Starting element in the source.
* @param to The destination array.
* @param toOffset Starting element in the array.
* @param length Number of elements to transfer.
* @return Number of elements converted.
* @throws std::invalid_argument if the arguments are not compatible.
*/
std::size_t copyScalarArray(
PVScalarArrayPtr const & from,
std::size_t offset,
PVScalarArrayPtr const & to,
std::size_t toOffset,
std::size_t length);
/**
* Are from and to valid arguments for copyStructure.
* They are only compatible if they have the same Structure description.
@@ -294,459 +296,146 @@ public:
* @param pv a PV
* @return converted value
*/
int8 toByte(PVScalarPtr const & pv);
inline int8 toByte(PVScalarPtr const & pv) { return pv->getAs<int8>();}
/**
* Convert a PV to a short.
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
int16 toShort(PVScalarPtr const & pv);
inline int16 toShort(PVScalarPtr const & pv) { return pv->getAs<int16>();}
/**
* Convert a PV to a int.
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
int32 toInt(PVScalarPtr const & pv);
inline int32 toInt(PVScalarPtr const & pv) { return pv->getAs<int32>();}
/**
* Convert a PV to an long
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
int64 toLong(PVScalarPtr const & pv);
inline int64 toLong(PVScalarPtr const & pv) { return pv->getAs<int32>();}
/**
* Convert a PV to a ubyte.
* @param pv a PV
* @return converted value
*/
uint8 toUByte(PVScalarPtr const & pv);
inline uint8 toUByte(PVScalarPtr const & pv) { return pv->getAs<uint8>();}
/**
* Convert a PV to a ushort.
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
uint16 toUShort(PVScalarPtr const & pv);
inline uint16 toUShort(PVScalarPtr const & pv) { return pv->getAs<uint16>();}
/**
* Convert a PV to a uint.
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
uint32 toUInt(PVScalarPtr const & pv);
inline uint32 toUInt(PVScalarPtr const & pv) { return pv->getAs<uint32>();}
/**
* Convert a PV to an ulong
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
uint64 toULong(PVScalarPtr const & pv);
inline uint64 toULong(PVScalarPtr const & pv) { return pv->getAs<uint64>();}
/**
* Convert a PV to a float
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
float toFloat(PVScalarPtr const & pv);
inline float toFloat(PVScalarPtr const & pv) { return pv->getAs<float>();}
/**
* Convert a PV to a double
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
double toDouble(PVScalarPtr const & pv);
inline double toDouble(PVScalarPtr const & pv) { return pv->getAs<double>();}
/**
* Convert a PV to a String
* @param pv a PV
* @return converted value
*/
String toString(PVScalarPtr const & pv);
inline String toString(PVScalarPtr const & pv) { return pv->getAs<String>();}
/**
* Convert a PV from a byte
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromByte(PVScalarPtr const & pv,int8 from);
inline void fromByte(PVScalarPtr const & pv,int8 from) { pv->putFrom<int8>(from); }
/**
* Convert a PV from a short
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromShort(PVScalarPtr const & pv,int16 from);
inline void fromShort(PVScalarPtr const & pv,int16 from) { pv->putFrom<int16>(from); }
/**
* Convert a PV from an int
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromInt(PVScalarPtr const & pv, int32 from);
inline void fromInt(PVScalarPtr const & pv, int32 from) { pv->putFrom<int32>(from); }
/**
* Convert a PV from a long
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromLong(PVScalarPtr const & pv, int64 from);
inline void fromLong(PVScalarPtr const & pv, int64 from) { pv->putFrom<int64>(from); }
/**
* Convert a PV from a ubyte
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromUByte(PVScalarPtr const & pv,uint8 from);
inline void fromUByte(PVScalarPtr const & pv,uint8 from) { pv->putFrom<uint8>(from); }
/**
* Convert a PV from a ushort
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromUShort(PVScalarPtr const & pv,uint16 from);
inline void fromUShort(PVScalarPtr const & pv,uint16 from) { pv->putFrom<uint16>(from); }
/**
* Convert a PV from an uint
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromUInt(PVScalarPtr const & pv, uint32 from);
inline void fromUInt(PVScalarPtr const & pv, uint32 from) { pv->putFrom<uint32>(from); }
/**
* Convert a PV from a ulong
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromULong(PVScalarPtr const & pv, uint64 from);
inline void fromULong(PVScalarPtr const & pv, uint64 from) { pv->putFrom<uint64>(from); }
/**
* Convert a PV from a float
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromFloat(PVScalarPtr const & pv, float from);
inline void fromFloat(PVScalarPtr const & pv, float from) { pv->putFrom<float>(from); }
/**
* Convert a PV from a double
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromDouble(PVScalarPtr const & pv, double from);
/**
* Convert a PV array to a byte array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toByteArray(PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
int8* to,
std::size_t toOffset);
/**
* Convert a PV array to a short array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toShortArray(PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
int16* to,
std::size_t toOffset);
/**
* Convert a PV array to an int array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toIntArray(PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
int32* to,
std::size_t toOffset);
/**
* Convert a PV array to a long array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toLongArray(PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
int64* to,
std::size_t toOffset);
/**
* Convert a PV array to a ubyte array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toUByteArray(PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
uint8* to,
std::size_t toOffset);
/**
* Convert a PV array to a ushort array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toUShortArray(PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
uint16* to,
std::size_t toOffset);
/**
* Convert a PV array to an uint array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toUIntArray(
PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
uint32* to,
std::size_t toOffset);
/**
* Convert a PV array to a ulong array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toULongArray(
PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
uint64* to,
std::size_t toOffset);
/**
* Convert a PV array to a float array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toFloatArray(
PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
float* to,
std::size_t toOffset);
/**
* Convert a PV array to a double array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toDoubleArray(
PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
double* to, std::size_t
toOffset);
/**
* Convert a PV array from a byte array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromByteArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const int8* from, std::size_t fromOffset);
std::size_t fromByteArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const ByteArray & from, std::size_t fromOffset);
/**
* Convert a PV array from a short array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromShortArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const int16* from, std::size_t fromOffset);
std::size_t fromShortArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const ShortArray & from, std::size_t fromOffset);
/**
* Convert a PV array from an int array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromIntArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const int32* from, std::size_t fromOffset);
std::size_t fromIntArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const IntArray & from, std::size_t fromOffset);
/**
* Convert a PV array from a long array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromLongArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const int64* from, std::size_t fromOffset);
std::size_t fromLongArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const LongArray & from, std::size_t fromOffset);
/**
* Convert a PV array from a ubyte array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromUByteArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const uint8* from, std::size_t fromOffset);
std::size_t fromUByteArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const UByteArray & from, std::size_t fromOffset);
/**
* Convert a PV array from a ushort array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromUShortArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const uint16* from, std::size_t fromOffset);
std::size_t fromUShortArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const UShortArray & from, std::size_t fromOffset);
/**
* Convert a PV array from an uint array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromUIntArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const uint32* from, std::size_t fromOffset);
std::size_t fromUIntArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const UIntArray & from, std::size_t fromOffset);
/**
* Convert a PV array from a ulong array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromULongArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const uint64* from, std::size_t fromOffset);
std::size_t fromULongArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const ULongArray & from, std::size_t fromOffset);
/**
* Convert a PV array from a float array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromFloatArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const float* from, std::size_t fromOffset);
std::size_t fromFloatArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const FloatArray & from, std::size_t fromOffset);
/**
* Convert a PV array from a double array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromDoubleArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const double* from, std::size_t fromOffset);
std::size_t fromDoubleArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const DoubleArray & from, std::size_t fromOffset);
inline void fromDouble(PVScalarPtr const & pv, double from) { pv->putFrom<double>(from); }
/**
* Convenience method for implementing toString.
* It generates a newline and inserts blanks at the beginning of the newline.
@@ -754,15 +443,9 @@ public:
* @param indentLevel Indent level, Each level is four spaces.
*/
void newLine(StringBuilder buf, int indentLevel);
private:
Convert();
PVDataCreatePtr pvDataCreate;
String trueString;
String falseString;
String illegalScalarType;
};
extern ConvertPtr getConvert();
static inline ConvertPtr getConvert() { return Convert::getConvert(); }
}}
#endif /* CONVERT_H */

60
pvDataApp/pv/printer.h Normal file
View File

@@ -0,0 +1,60 @@
#ifndef PRINTER_H
#define PRINTER_H
#include <ostream>
#include "pvData.h"
namespace epics { namespace pvData {
class PrinterBase
{
public:
virtual void setStream(std::ostream&);
virtual void clearStream();
virtual void print(const PVField&);
protected:
PrinterBase();
virtual ~PrinterBase()=0;
virtual void beginStructure(const PVStructure&);
virtual void endStructure(const PVStructure&);
virtual void beginStructureArray(const PVStructureArray&);
virtual void endStructureArray(const PVStructureArray&);
virtual void encodeScalar(const PVScalar&);
virtual void encodeArray(const PVScalarArray&);
virtual void encodeNull();
inline std::ostream& S() { return *strm; }
void impl_print(const PVField&);
private:
std::ostream *strm;
};
class PrinterPlain : public PrinterBase
{
size_t ilvl;
protected:
virtual void beginStructure(const PVStructure&);
virtual void endStructure(const PVStructure&);
virtual void beginStructureArray(const PVStructureArray&);
virtual void endStructureArray(const PVStructureArray&);
virtual void encodeScalar(const PVScalar&);
virtual void encodeArray(const PVScalarArray&);
virtual void encodeNull();
public:
PrinterPlain();
virtual ~PrinterPlain();
};
}}
#endif // PRINTER_H

View File

@@ -9,6 +9,15 @@
*/
#ifndef PVDATA_H
#define PVDATA_H
#ifdef __GNUC__
#define USAGE_DEPRECATED __attribute__((deprecated))
#define USAGE_ERROR(MSG) __attribute__((error(MSG)))
#else
#define USAGE_DEPRECATED
#define USAGE_ERROR(MSG)
#endif
#include <string>
#include <map>
#include <stdexcept>
@@ -18,6 +27,8 @@
#include <iomanip>
#include <pv/pvIntrospect.h>
#include <pv/requester.h>
#include <pv/typeCast.h>
#include <pv/sharedVector.h>
#if defined(__vxworks) && !defined(_WRS_VXWORKS_MAJOR)
typedef class std::ios std::ios_base;
@@ -96,7 +107,11 @@ class PVScalar;
class PVScalarArray;
class PVStructure;
class PVStructureArray;
template<typename T> class PVScalarValue;
template<typename T> class PVValueArray;
/**
* typedef for a pointer to a PVAuxInfo.
@@ -143,6 +158,8 @@ typedef std::vector<PVStructurePtr>::const_iterator PVStructurePtrArray_const__i
/**
* typedef for a pointer to a PVStructureArray.
*/
typedef PVValueArray<PVStructurePtr> PVStructureArray;
typedef std::tr1::shared_ptr<PVStructureArray> PVStructureArrayPtr;
typedef std::vector<PVStructureArrayPtr> PVStructureArrayPtrArray;
typedef std::tr1::shared_ptr<PVStructureArrayPtrArray> PVStructureArrayPtrArrayPtr;
@@ -249,7 +266,13 @@ public:
* Get the fieldName for this field.
* @return The name or empty string if top level field.
*/
String getFieldName() const ;
inline const String& getFieldName() const {return fieldName;}
/**
* Fully expand the name of this field using the
* names of its parent fields with a dot '.' seperating
* each name.
*/
String getFullName() const;
/**
* Register the message requester.
* At most one requester can be registered.
@@ -348,6 +371,7 @@ public:
*/
virtual std::ostream& dumpValue(std::ostream& o) const = 0;
protected:
PVField::shared_pointer getPtrSelf()
{
@@ -370,7 +394,6 @@ private:
bool immutable;
RequesterPtr requester;
PostHandlerPtr postHandler;
std::tr1::shared_ptr<class Convert> convert;
friend class PVDataCreate;
friend class PVStructure;
};
@@ -381,6 +404,10 @@ std::ostream& operator<<(std::ostream& o, const PVField& f);
* PVScalar is the base class for each scalar field.
*/
class PVScalar : public PVField {
// friend our child class(s) so that it
// can call protected methods of other
// PVScalar instances.
template<typename E> friend class PVScalarValue;
public:
POINTER_DEFINITIONS(PVScalar);
/**
@@ -394,6 +421,47 @@ public:
* @return the interface.
*/
const ScalarConstPtr getScalar() const ;
/**
* 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.
* Uses castUnsafe<TO>() for value conversion.
@code
PVScalar* pv = ...;
uint32 val = pv->getAs<pvInt>();
@endcode
*/
template<typename T>
inline T getAs() const {
T result;
this->getAs((void*)&result, (ScalarType)ScalarTypeID<T>::value);
return result;
}
protected:
virtual void getAs(void *, ScalarType) const = 0;
public:
/**
* Convert and assign the provided value.
* The value type is determined from the function template argument
* which must be one of the ScalarType enums.
* Uses castUnsafe<TO>() for value conversion.
@code
PVScalar* pv = ...;
pv->putFrom<pvInt>((int32)42);
@endcode
*/
template<typename T>
inline void putFrom(T val) {
this->putFrom((const void*)&val, (ScalarType)ScalarTypeID<T>::value);
}
protected:
virtual void putFrom(const void *, ScalarType) = 0;
public:
virtual void assign(const PVScalar&) = 0;
protected:
PVScalar(ScalarConstPtr const & scalar);
};
@@ -408,6 +476,9 @@ public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
static const ScalarType typeCode;
/**
* Destructor
*/
@@ -442,9 +513,42 @@ public:
put(value);
}
template<typename T1>
inline T1 getAs() const {
T1 result(castUnsafe<T1,T>(get()));
return result;
}
template<typename T1>
inline void putFrom(T1 val) {
put(castUnsafe<T,T1>(val));
}
protected:
PVScalarValue(ScalarConstPtr const & scalar)
: PVScalar(scalar) {}
virtual void getAs(void * result, ScalarType rtype) const
{
const T src = get();
castUnsafeV(1, rtype, result, typeCode, (const void*)&src);
}
virtual void putFrom(const void *src, ScalarType stype)
{
T result;
castUnsafeV(1, typeCode, (void*)&result, stype, src);
put(result);
}
virtual void assign(const PVScalar& scalar)
{
if(this==&scalar)
return;
if(isImmutable())
throw std::invalid_argument("Destination is immutable");
T result;
scalar.getAs((void*)&result, typeCode);
put(result);
}
private:
friend class PVDataCreate;
};
@@ -452,7 +556,7 @@ private:
/**
* typedefs for the various possible scalar types.
*/
typedef PVScalarValue<uint8> PVBoolean;
typedef PVScalarValue<boolean> PVBoolean;
typedef PVScalarValue<int8> PVByte;
typedef PVScalarValue<int16> PVShort;
typedef PVScalarValue<int32> PVInt;
@@ -500,7 +604,7 @@ public:
/**
* Destructor
*/
virtual ~PVArray();
virtual ~PVArray(){};
/**
* Set the field to be immutable, i. e. it can no longer be modified.
* This is permanent, i.e. once done the field can onot be made mutable.
@@ -510,17 +614,17 @@ public:
* Get the array length.
* @return The length.
*/
std::size_t getLength() const;
virtual std::size_t getLength() const = 0;
/**
* Set the array length.
* @param The length.
*/
virtual void setLength(std::size_t length);
virtual void setLength(std::size_t length) = 0;
/**
* Get the array capacity.
* @return The capacity.
*/
std::size_t getCapacity() const;
virtual std::size_t getCapacity() const = 0;
/**
* Can the capacity be changed.
* @return (false,true) if (can not, can) be changed.
@@ -541,9 +645,8 @@ public:
protected:
PVArray(FieldConstPtr const & field);
void setCapacityLength(std::size_t capacity,std::size_t length);
private:
class PVArrayPvt * pImpl;
bool capacityMutable;
friend class PVDataCreate;
};
@@ -594,115 +697,62 @@ public:
const ScalarArrayConstPtr getScalarArray() const ;
protected:
PVScalarArray(ScalarArrayConstPtr const & scalarArray);
private:
friend class PVDataCreate;
};
/**
* This is provided by code that calls get.
*/
typedef PVArrayData<PVStructurePtr> StructureArrayData;
/**
* Data class for a structureArray
*/
class PVStructureArray : public PVArray
{
virtual void _getAsVoid(shared_vector<const void>&) const = 0;
virtual void _putFromVoid(const shared_vector<const void>&) = 0;
public:
POINTER_DEFINITIONS(PVStructureArray);
typedef PVStructurePtr value_type;
typedef PVStructurePtr* pointer;
typedef const PVStructurePtr* const_pointer;
typedef PVArrayData<PVStructurePtr> ArrayDataType;
typedef std::vector<PVStructurePtr> vector;
typedef const std::vector<PVStructurePtr> const_vector;
typedef std::tr1::shared_ptr<vector> shared_vector;
typedef PVStructureArray &reference;
typedef const PVStructureArray& const_reference;
/**
* Destructor
*/
virtual ~PVStructureArray() {}
/**
* Set the array capacity.
* @param capacity The length.
*/
virtual void setCapacity(size_t capacity);
/**
* Set the array length.
* @param length The length.
*/
virtual void setLength(std::size_t length);
/**
* Get the introspection interface
* @return The interface.
*/
virtual StructureArrayConstPtr getStructureArray() const ;
/**
* Append new elements to the end of the array.
* @param number The number of elements to add.
* @return the new length of the array.
*/
virtual std::size_t append(std::size_t number);
/**
* Remove elements from the array.
* @param offset The offset of the first element to remove.
* @param number The number of elements to remove.
* @return (false,true) if the elements were removed.
*/
virtual bool remove(std::size_t offset,std::size_t number);
/**
* Compress. This removes all null elements from the array.
*/
virtual void compress();
/**
* Get array elements
* @param offset The offset of the first element,
* @param length The number of elements to get.
* @param data The place where the data is placed.
*/
virtual std::size_t get(std::size_t offset, std::size_t length,
StructureArrayData &data);
/**
* Put data into the array.
* @param offset The offset of the first element,
* @param length The number of elements to get.
* @param from The new values to put into the array.
* @param fromOffset The offset in from.
* @return The number of elements put into the array.
*/
virtual std::size_t put(std::size_t offset,std::size_t length,
const_vector const & from, std::size_t fromOffset);
/**
* Share data from another source.
* @param value The data to share.
* @param capacity The capacity of the array.
* @param length The length of the array.
*/
virtual void shareData(
shared_vector const & value,
std::size_t capacity,
std::size_t length);
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 pointer get() { return &((*value.get())[0]); }
virtual pointer get() const { return &((*value.get())[0]); }
virtual vector const & getVector() {return *value;}
virtual shared_vector const & getSharedVector() {return value;}
virtual std::ostream& dumpValue(std::ostream& o) const;
virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const;
/**
* 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.
*/
template<typename T>
void
getAs(shared_vector<const T>& out) const
{
shared_vector<const void> temp;
_getAsVoid(temp);
out = shared_vector_convert<const T>(temp);
}
/**
* 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 refernce to the provided
* data is kept.
*
* Calls postPut()
*/
template<typename T>
inline void putFrom(const shared_vector<const T>& inp)
{
shared_vector<const void> temp(static_shared_vector_cast<const void>(inp));
_putFromVoid(temp);
}
/**
* 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 refernce to the provided
* data is kept.
*/
void assign(PVScalarArray& pv) {
shared_vector<const void> temp;
pv._getAsVoid(temp);
_putFromVoid(temp);
}
protected:
PVStructureArray(StructureArrayConstPtr const & structureArray);
PVScalarArray(ScalarArrayConstPtr const & scalarArray);
private:
StructureArrayConstPtr structureArray;
shared_vector value;
friend class PVDataCreate;
};
@@ -934,99 +984,328 @@ private:
friend class PVDataCreate;
};
namespace detail {
// adaptor to allow epics::pvData::shared_vector to hold a reference
// to a shared_ptr<std::vector<> >
template<typename T>
struct shared_ptr_vector_deletor {
typedef std::tr1::shared_ptr<std::vector<T> > shared_vector;
shared_vector vec;
shared_ptr_vector_deletor(const shared_vector& v)
:vec(v) {}
void operator()(T*){vec.reset();}
};
template<typename T, class Base>
class PVVectorStorage : public Base
{
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
//TODO: full namespace can be removed along with local typedef 'shared_vector'
typedef ::epics::pvData::shared_vector<T> svector;
typedef ::epics::pvData::shared_vector<const T> const_svector;
// begin deprecated
typedef PVArrayData<T> ArrayDataType;
typedef std::vector<T> vector;
typedef const std::vector<T> const_vector;
typedef std::tr1::shared_ptr<vector> shared_vector;
// end deprecated
protected:
PVVectorStorage() : Base() {}
template<typename A>
PVVectorStorage(A a) : Base(a) {}
public:
virtual ~PVVectorStorage(){};
// Primative array manipulations
//! Fetch a read-only view of the current array data
virtual const_svector view() const = 0;
/** Exchange our contents for the provided.
*
@throws std::logic_error for Immutable arrays.
*
* Callers must ensure that postPut() is called
* after the last swap() operation.
*
* Before you call this directly, consider using
* the reuse(), or replace() methods.
*/
virtual void swap(const_svector& other) = 0;
//! Discard current contents and replaced with the provided.
//! Fails for Immutable arrays
//! calls postPut()
virtual void replace(const const_svector& next) = 0;
// Derived operations
/** Remove and return the current array data
* or an unique copy if shared.
*
* Does @b not (and should not) call postPut()
*
* The returned shared_vector<T> will
* have unique()==true.
*/
inline svector reuse()
{
const_svector result;
this->swap(result);
return thaw(result);
}
/**
* Get array elements
* @param offset The offset of the first element,
* @param length The number of elements to get.
* @param data The place where the data is placed.
*/
std::size_t get(
std::size_t offset, std::size_t length, ArrayDataType &data) USAGE_DEPRECATED
{
const_svector ref = this->view();
ref.slice(offset, length);
data.data.resize(ref.size());
data.offset = 0;
std::copy(ref.begin(), ref.end(), data.data.begin());
return ref.size();
}
/**
* Copy data into the array growing the length as needed.
* @param offset The offset of the first element,
* @param length The number of elements to get.
* @param from The new values to put into the array.
* @param fromOffset The offset in from.
* @return The number of elements put into the array.
* calls postPut()
*/
std::size_t put(std::size_t offset,
std::size_t length, const_pointer from, std::size_t fromOffset) USAGE_DEPRECATED
{
from += fromOffset;
svector temp(this->reuse());
if(temp.size() < length+offset)
temp.resize(length+offset);
else
temp.make_unique();
std::copy(from, from + length, temp.begin() + offset);
this->replace(freeze(temp));
return length;
}
std::size_t put(std::size_t offset,
std::size_t length, const_vector &from, std::size_t fromOffset) USAGE_DEPRECATED
{ return this->put(offset,length, &from[0], fromOffset); }
/**
* Share data from another source.
* @param value The data to share.
* @param capacity The capacity of the array.
* @param length The length of the array.
* Does @b not call postPut()
*/
void shareData(
shared_vector const & value,
std::size_t capacity,
std::size_t length) USAGE_DEPRECATED
{
vector& vref = *value.get();
typename svector::shared_pointer_type p(&vref[0],
detail::shared_ptr_vector_deletor<T>(value));
const_svector temp(p, 0, std::min(length, vref.size()));
this->swap(temp);
}
pointer get() const USAGE_DEPRECATED {
// evil unsafe cast!
return (pointer)this->view().data();
}
vector const & getVector() USAGE_ERROR("No longer implemented. Replace with view()");
shared_vector const & getSharedVector() USAGE_ERROR("No longer implemented. Replace with view()");
};
} // namespace detail
template<typename T>
class PVValueArray : public PVScalarArray {
class PVValueArray : public detail::PVVectorStorage<T,PVScalarArray> {
typedef detail::PVVectorStorage<T,PVScalarArray> base_t;
public:
POINTER_DEFINITIONS(PVValueArray);
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
//TODO: full namespace can be removed along with local typedef 'shared_vector'
typedef ::epics::pvData::shared_vector<T> svector;
typedef ::epics::pvData::shared_vector<const T> const_svector;
// begin deprecated
typedef PVArrayData<T> ArrayDataType;
typedef std::vector<T> vector;
typedef const std::vector<T> const_vector;
typedef std::tr1::shared_ptr<vector> shared_vector;
typedef PVValueArray & reference;
typedef const PVValueArray & const_reference;
// end deprecated
static const ScalarType typeCode;
/**
* Destructor
*/
virtual ~PVValueArray() {}
/**
* Get array elements
* @param offset The offset of the first element,
* @param length The number of elements to get.
* @param data The place where the data is placed.
*/
virtual std::size_t get(
std::size_t offset, std::size_t length, ArrayDataType &data) = 0;
/**
* Put data into the array.
* @param offset The offset of the first element,
* @param length The number of elements to get.
* @param from The new values to put into the array.
* @param fromOffset The offset in from.
* @return The number of elements put into the array.
*/
virtual std::size_t put(std::size_t offset,
std::size_t length, const_pointer from, std::size_t fromOffset) = 0;
virtual std::size_t put(std::size_t offset,
std::size_t length, const_vector &from, std::size_t fromOffset);
/**
* Share data from another source.
* @param value The data to share.
* @param capacity The capacity of the array.
* @param length The length of the array.
*/
virtual void shareData(
shared_vector const & value,
std::size_t capacity,
std::size_t length) = 0;
virtual pointer get() = 0;
virtual pointer get() const = 0;
virtual vector const & getVector() = 0;
virtual shared_vector const & getSharedVector() = 0;
std::ostream& dumpValue(std::ostream& o) const
{
const_svector v(this->view());
typename const_svector::const_iterator it(v.begin()),
end(v.end());
o << '[';
std::size_t len = getLength();
bool first = true;
for (std::size_t i = 0; i < len; i++)
{
if (first)
first = false;
else
o << ',';
dumpValue(o, i);
}
if(it!=end) {
o << print_cast(*it++);
for(; it!=end; ++it)
o << ',' << print_cast(*it);
}
return o << ']';
}
std::ostream& dumpValue(std::ostream& o, size_t index) const
{
return o << *(get() + index);
return o << print_cast(this->view().at(index));
}
protected:
virtual void _getAsVoid(epics::pvData::shared_vector<const void>& out) const
{
out = static_shared_vector_cast<const void>(this->view());
}
virtual void _putFromVoid(const epics::pvData::shared_vector<const void>& in)
{
// TODO: try to re-use storage
replace(shared_vector_convert<const T>(in));
}
PVValueArray(ScalarArrayConstPtr const & scalar)
: PVScalarArray(scalar) {}
: base_t(scalar) {}
friend class PVDataCreate;
};
template<typename T>
std::size_t PVValueArray<T>::put(
std::size_t offset,
std::size_t length,
const_vector &from,
std::size_t fromOffset)
{ return put(offset,length, &from[0], fromOffset); }
/**
* This is provided by code that calls get.
*/
typedef PVArrayData<PVStructurePtr> StructureArrayData;
/**
* Data class for a structureArray
*/
template<>
class PVValueArray<PVStructurePtr> : public detail::PVVectorStorage<PVStructurePtr,PVArray>
{
typedef detail::PVVectorStorage<PVStructurePtr,PVArray> base_t;
public:
POINTER_DEFINITIONS(PVStructureArray);
typedef PVStructurePtr value_type;
typedef PVStructurePtr* pointer;
typedef const PVStructurePtr* const_pointer;
typedef PVArrayData<PVStructurePtr> ArrayDataType;
typedef std::vector<PVStructurePtr> vector;
typedef const std::vector<PVStructurePtr> const_vector;
typedef std::tr1::shared_ptr<vector> shared_vector;
typedef PVStructureArray &reference;
typedef const PVStructureArray& const_reference;
//TODO: full namespace can be removed along with local typedef 'shared_vector'
typedef ::epics::pvData::shared_vector<PVStructurePtr> svector;
typedef ::epics::pvData::shared_vector<const PVStructurePtr> const_svector;
/**
* Destructor
*/
virtual ~PVValueArray() {}
virtual size_t getLength() const {return value.size();}
virtual size_t getCapacity() const {return value.capacity();}
/**
* Set the array capacity.
* @param capacity The length.
*/
virtual void setCapacity(size_t capacity);
/**
* Set the array length.
* @param length The length.
*/
virtual void setLength(std::size_t length);
/**
* Get the introspection interface
* @return The interface.
*/
StructureArrayConstPtr getStructureArray() const {return structureArray;}
/**
* Append new elements to the end of the array.
* @param number The number of elements to add.
* @return the new length of the array.
*/
virtual std::size_t append(std::size_t number);
/**
* Remove elements from the array.
* @param offset The offset of the first element to remove.
* @param number The number of elements to remove.
* @return (false,true) if the elements were removed.
*/
virtual bool remove(std::size_t offset,std::size_t number);
/**
* Compress. This removes all null elements from the array.
*/
virtual void compress();
virtual const_svector view() const { return value; }
virtual void swap(const_svector &other);
virtual void replace(const const_svector &other) {
value = other;
PVField::postPut();
}
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;
protected:
PVValueArray(StructureArrayConstPtr const & structureArray)
:base_t(structureArray)
,structureArray(structureArray)
{}
private:
StructureArrayConstPtr structureArray;
const_svector value;
friend class PVDataCreate;
};
/**
* Definitions for the various scalarArray types.
*/
typedef PVArrayData<uint8> BooleanArrayData;
typedef PVValueArray<uint8> PVBooleanArray;
typedef PVArrayData<boolean> BooleanArrayData;
typedef PVValueArray<boolean> PVBooleanArray;
typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
typedef PVArrayData<int8> ByteArrayData;
@@ -1171,6 +1450,9 @@ private:
*/
extern PVDataCreatePtr getPVDataCreate();
#undef USAGE_DEPRECATED
#undef USAGE_ERROR
}}
#endif /* PVDATA_H */

View File

@@ -191,6 +191,9 @@ namespace ScalarTypeFunc {
* @param scalarType The type.
*/
void toString(StringBuilder builder,ScalarType scalarType);
//! gives sizeof(T) where T depends on the scalar type id.
size_t elementSize(ScalarType id);
};
/**
@@ -439,7 +442,7 @@ public:
* @param fieldIndex The index of the desired field.
* @return The fieldName.
*/
String getFieldName(std::size_t fieldIndex){return fieldNames[fieldIndex];}
String getFieldName(std::size_t fieldIndex) const {return fieldNames[fieldIndex];}
/**
* Convert the structure to a string and add it to builder.
* @param builder The string builder.
@@ -555,5 +558,46 @@ private:
*/
extern FieldCreatePtr getFieldCreate();
/** Define a compile time mapping from
* type to enum value.
@code
ScalarType code = (ScalarType)ScalarTypeID<int8>::value;
assert(code==pvByte);
@endcode
*
* For unspecified types this evaluates to an invalid ScalarType
* value (eg -1).
*/
template<typename T>
struct ScalarTypeID { enum {value=-1}; };
/**
* Static mapping from ScalarType enum to value type.
@code
typename ScalarTypeTraits<pvByte>::type value = 4;
@endcode
*/
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, String)
#undef OP
}}
#endif /* PVINTROSPECT_H */

View File

@@ -21,8 +21,10 @@
(_WRS_VXWORKS_MAJOR+0 <= 6) && (_WRS_VXWORKS_MINOR+0 < 9)
typedef int intptr_t;
typedef unsigned int uintptr_t;
#ifndef INT64_MAX
#define INT64_MAX (0x7fffffffffffffffLL)
#define UINT64_MAX (0xffffffffffffffffLL)
#endif
#else
#include <stdint.h>
#endif
@@ -32,6 +34,14 @@ typedef unsigned int uintptr_t;
namespace epics { namespace pvData {
namespace detail {
// Pick either type If or type Else to not be Cond
template<typename Cond, typename If, typename Else>
struct pick_type { typedef If type; };
template<typename Cond, typename Else>
struct pick_type<Cond,Cond,Else> { typedef Else type; };
}
/**
* This is a set of typdefs used by pvData.
*/
@@ -39,7 +49,9 @@ namespace epics { namespace pvData {
/**
* boolean, i.e. can only have the values {@code false} or {@code true}
*/
typedef uint8_t boolean;
typedef detail::pick_type<int8_t, signed char,
detail::pick_type<uint8_t, char, unsigned char>::type
>::type boolean;
/**
* A 8 bit signed integer
*/

View File

@@ -2,45 +2,48 @@ TOP=../..
include $(TOP)/configure/CONFIG
PROD_LIBS += pvData Com
PROD_HOST += testThread
testThread_SRCS += testThread.cpp
testThread_LIBS += pvData Com
PROD_HOST += testTimer
testTimer_SRCS += testTimer.cpp
testTimer_LIBS += pvData Com
PROD_HOST += testBitSet
testBitSet_SRCS += testBitSet.cpp
testBitSet_LIBS += pvData Com
PROD_HOST += testByteOrder
testByteOrder_SRCS += testByteOrder.cpp
testByteOrder_LIBS += Com
PROD_HOST += testByteBuffer
testByteBuffer_SRCS += testByteBuffer.cpp
testByteBuffer_LIBS += pvData Com
PROD_HOST += testBaseException
testBaseException_SRCS += testBaseException.cpp
testBaseException_LIBS += pvData Com
PROD_HOST += testSerialization
TESTPROD += testSerialization
testSerialization_SRCS += testSerialization.cpp
testSerialization_LIBS += pvData Com
TESTS += testSerialization
PROD_HOST += testTimeStamp
testTimeStamp_SRCS += testTimeStamp.cpp
testTimeStamp_LIBS += pvData Com
PROD_HOST += testQueue
testQueue_SRCS += testQueue.cpp
testQueue_LIBS += pvData Com
PROD_HOST += testMessageQueue
testMessageQueue_SRCS += testMessageQueue.cpp
testMessageQueue_LIBS += pvData Com
TESTPROD += testTypeCast
testTypeCast_SRCS += testTypeCast.cpp
TESTS += testTypeCast
TESTPROD += testSharedVector
testSharedVector_SRCS += testSharedVector.cpp
TESTS += testSharedVector
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
include $(TOP)/configure/RULES
#----------------------------------------

View File

@@ -12,7 +12,9 @@
#include <iostream>
#include <fstream>
#include <epicsAssert.h>
#include <epicsUnitTest.h>
#include <testMain.h>
#include <dbDefs.h> // for NELEMENTS
#include <epicsExit.h>
#include <pv/pvIntrospect.h>
@@ -45,6 +47,8 @@
using namespace epics::pvData;
namespace {
static SerializableControl* flusher;
static DeserializableControl* control;
static ByteBuffer* buffer;
@@ -122,14 +126,23 @@ void serializationTest(PVFieldPtr const & field) {
deserializedField->deserialize(buffer, control);
// must equal
bool isEqual = getConvert()->equals(*field,*deserializedField);
assert(isEqual);
if(*field==*deserializedField)
testPass("Serialization round trip OK");
else {
testFail("Serialization round trip did not match!");
std::string buf;
field->toString(&buf);
testDiag("Expected: %s", buf.c_str());
buf.clear();
deserializedField->toString(&buf);
testDiag("Found: %s", buf.c_str());
}
}
void testEquals(std::ostream& ofile) {
ofile<<"Testing equals...\n";
void testEquals() {
testDiag("Testing equals...");
PVDataCreatePtr factory = getPVDataCreate();
assert(factory.get()!=NULL);
testOk1(factory.get()!=NULL);
// be sure all is covered
for (int i = pvBoolean; i < pvString; i++)
@@ -138,32 +151,63 @@ void testEquals(std::ostream& ofile) {
PVScalarPtr scalar1 = factory->createPVScalar(scalarType);
PVScalarPtr scalar2 = factory->createPVScalar(scalarType);
assert((*scalar1)==(*scalar2));
testOk1((*scalar1)==(*scalar2));
PVScalarArrayPtr array1 = factory->createPVScalarArray(scalarType);
PVScalarArrayPtr array2 = factory->createPVScalarArray(scalarType);
assert((*array1)==(*array2));
testOk1((*array1)==(*array2));
}
// and a structure
PVStructurePtr structure1 = factory->createPVStructure(getStandardField()->timeStamp());
PVStructurePtr structure2 = factory->createPVStructure(getStandardField()->timeStamp());
assert((*structure1)==(*structure2));
testOk1((*structure1)==(*structure2));
// and a structure array
PVStructureArrayPtr structureArray1 = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure1->getStructure()));
PVStructureArrayPtr structureArray2 = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure2->getStructure()));
assert((*structureArray1)==(*structureArray2));
ofile<<"!!! PASSED\n\n";
testOk1((*structureArray1)==(*structureArray2));
}
void testScalar(std::ostream& ofile) {
ofile<<"Testing scalars...\n";
PVDataCreatePtr factory = getPVDataCreate();
assert(factory.get()!=NULL);
template<typename PVT>
void testScalarType()
{
typedef typename PVT::value_type value_type;
ofile<<"\tPVBoolean\n";
testDiag("type %s", ScalarTypeFunc::name(PVT::typeCode));
typename PVT::shared_pointer pv = std::tr1::static_pointer_cast<PVT>(getPVDataCreate()->createPVScalar(PVT::typeCode));
pv->put(0);
serializationTest(pv);
pv->put(42);
serializationTest(pv);
pv->put(std::numeric_limits<value_type>::max()-1);
serializationTest(pv);
pv->put(std::numeric_limits<value_type>::max());
serializationTest(pv);
if(std::numeric_limits<value_type>::min()!=0) {
pv->put(-42);
serializationTest(pv);
pv->put(std::numeric_limits<value_type>::min()+1);
serializationTest(pv);
pv->put(std::numeric_limits<value_type>::min());
serializationTest(pv);
}
if(std::numeric_limits<value_type>::has_infinity) {
pv->put(std::numeric_limits<value_type>::infinity());
serializationTest(pv);
}
}
void testScalar() {
testDiag("Testing scalars...");
PVDataCreatePtr factory = getPVDataCreate();
testOk1(factory.get()!=NULL);
testDiag("type %s", ScalarTypeFunc::name(pvBoolean));
PVBooleanPtr pvBoolean =
std::tr1::static_pointer_cast<PVBoolean>(factory->createPVScalar(epics::pvData::pvBoolean));
pvBoolean->put(false);
@@ -171,196 +215,19 @@ void testScalar(std::ostream& ofile) {
pvBoolean->put(true);
serializationTest(pvBoolean);
ofile<<"\tPVByte\n";
PVBytePtr pvByte =
std::tr1::static_pointer_cast<PVByte>(factory->createPVScalar(epics::pvData::pvByte));
pvByte->put(0);
serializationTest(pvByte);
pvByte->put(12);
serializationTest(pvByte);
pvByte->put(BYTE_MAX_VALUE);
serializationTest(pvByte);
pvByte->put(BYTE_MIN_VALUE);
serializationTest(pvByte);
ofile<<"\tPVShort\n";
PVShortPtr pvShort =
std::tr1::static_pointer_cast<PVShort>(factory->createPVScalar(epics::pvData::pvShort));
pvShort->put(0);
serializationTest(pvShort);
pvShort->put(123);
serializationTest(pvShort);
pvShort->put(BYTE_MAX_VALUE);
serializationTest(pvShort);
pvShort->put(BYTE_MIN_VALUE);
serializationTest(pvShort);
pvShort->put(SHORT_MAX_VALUE);
serializationTest(pvShort);
pvShort->put(SHORT_MIN_VALUE);
serializationTest(pvShort);
ofile<<"\tPVInt\n";
PVIntPtr pvInt =
std::tr1::static_pointer_cast<PVInt>(factory->createPVScalar(epics::pvData::pvInt));
pvInt->put(0);
serializationTest(pvInt);
pvInt->put(123456);
serializationTest(pvInt);
pvInt->put(BYTE_MAX_VALUE);
serializationTest(pvInt);
pvInt->put(BYTE_MIN_VALUE);
serializationTest(pvInt);
pvInt->put(SHORT_MAX_VALUE);
serializationTest(pvInt);
pvInt->put(SHORT_MIN_VALUE);
serializationTest(pvInt);
pvInt->put(INT_MAX_VALUE);
serializationTest(pvInt);
pvInt->put(INT_MIN_VALUE);
serializationTest(pvInt);
ofile<<"\tPVLong\n";
PVLongPtr pvLong =
std::tr1::static_pointer_cast<PVLong>(factory->createPVScalar(epics::pvData::pvLong));
pvLong->put(0);
serializationTest(pvLong);
pvLong->put(12345678901LL);
serializationTest(pvLong);
pvLong->put(BYTE_MAX_VALUE);
serializationTest(pvLong);
pvLong->put(BYTE_MIN_VALUE);
serializationTest(pvLong);
pvLong->put(SHORT_MAX_VALUE);
serializationTest(pvLong);
pvLong->put(SHORT_MIN_VALUE);
serializationTest(pvLong);
pvLong->put(INT_MAX_VALUE);
serializationTest(pvLong);
pvLong->put(INT_MIN_VALUE);
serializationTest(pvLong);
pvLong->put(LONG_MAX_VALUE);
serializationTest(pvLong);
pvLong->put(LONG_MIN_VALUE);
serializationTest(pvLong);
testScalarType<PVByte>();
testScalarType<PVUByte>();
testScalarType<PVShort>();
testScalarType<PVUShort>();
testScalarType<PVInt>();
testScalarType<PVUInt>();
testScalarType<PVLong>();
testScalarType<PVULong>();
testScalarType<PVFloat>();
testScalarType<PVDouble>();
ofile<<"\tPVUByte\n";
PVUBytePtr pvUByte =
std::tr1::static_pointer_cast<PVUByte>(factory->createPVScalar(epics::pvData::pvUByte));
pvUByte->put(0);
serializationTest(pvUByte);
pvUByte->put(12);
serializationTest(pvUByte);
pvUByte->put(UBYTE_MAX_VALUE);
serializationTest(pvUByte);
pvUByte->put(BYTE_MAX_VALUE);
serializationTest(pvUByte);
pvUByte->put(BYTE_MIN_VALUE);
serializationTest(pvUByte);
ofile<<"\tPVUShort\n";
PVUShortPtr pvUShort =
std::tr1::static_pointer_cast<PVUShort>(factory->createPVScalar(epics::pvData::pvUShort));
pvUShort->put(0);
serializationTest(pvUShort);
pvUShort->put(1234);
serializationTest(pvUShort);
pvUShort->put(BYTE_MAX_VALUE);
serializationTest(pvUShort);
pvUShort->put(BYTE_MIN_VALUE);
serializationTest(pvUShort);
pvUShort->put(UBYTE_MAX_VALUE);
serializationTest(pvUShort);
pvUShort->put(SHORT_MAX_VALUE);
serializationTest(pvUShort);
pvUShort->put(SHORT_MIN_VALUE);
serializationTest(pvUShort);
pvUShort->put(USHORT_MAX_VALUE);
serializationTest(pvUShort);
ofile<<"\tPVInt\n";
PVIntPtr pvUInt =
std::tr1::static_pointer_cast<PVInt>(factory->createPVScalar(epics::pvData::pvUInt));
pvUInt->put(0);
serializationTest(pvUInt);
pvUInt->put(123456);
serializationTest(pvUInt);
pvUInt->put(BYTE_MAX_VALUE);
serializationTest(pvUInt);
pvUInt->put(BYTE_MIN_VALUE);
serializationTest(pvUInt);
pvUInt->put(UBYTE_MAX_VALUE);
serializationTest(pvUInt);
pvUInt->put(SHORT_MAX_VALUE);
serializationTest(pvUInt);
pvUInt->put(SHORT_MIN_VALUE);
serializationTest(pvUInt);
pvUInt->put(USHORT_MAX_VALUE);
serializationTest(pvUInt);
pvUInt->put(INT_MAX_VALUE);
serializationTest(pvUInt);
pvUInt->put(INT_MIN_VALUE);
serializationTest(pvUInt);
pvUInt->put(UINT_MAX_VALUE);
serializationTest(pvUInt);
ofile<<"\tPVLong\n";
PVLongPtr pvULong =
std::tr1::static_pointer_cast<PVLong>(factory->createPVScalar(epics::pvData::pvULong));
pvULong->put(0);
serializationTest(pvULong);
pvULong->put(12345678901LL);
serializationTest(pvULong);
pvULong->put(BYTE_MAX_VALUE);
serializationTest(pvULong);
pvULong->put(BYTE_MIN_VALUE);
serializationTest(pvULong);
pvULong->put(UBYTE_MAX_VALUE);
serializationTest(pvULong);
pvULong->put(SHORT_MAX_VALUE);
serializationTest(pvULong);
pvULong->put(SHORT_MIN_VALUE);
serializationTest(pvULong);
pvULong->put(USHORT_MAX_VALUE);
serializationTest(pvULong);
pvULong->put(INT_MAX_VALUE);
serializationTest(pvULong);
pvULong->put(INT_MIN_VALUE);
serializationTest(pvULong);
pvULong->put(UINT_MAX_VALUE);
serializationTest(pvULong);
pvULong->put(LONG_MAX_VALUE);
serializationTest(pvULong);
pvULong->put(LONG_MIN_VALUE);
serializationTest(pvULong);
pvULong->put(ULONG_MAX_VALUE);
serializationTest(pvULong);
ofile<<"\tPVFloat\n";
PVFloatPtr pvFloat =
std::tr1::static_pointer_cast<PVFloat>(factory->createPVScalar(epics::pvData::pvFloat));
pvFloat->put(0);
serializationTest(pvFloat);
pvFloat->put(12.345);
serializationTest(pvFloat);
pvFloat->put(FLOAT_MAX_VALUE);
serializationTest(pvFloat);
pvFloat->put(FLOAT_MIN_VALUE);
serializationTest(pvFloat);
ofile<<"\tPVDouble\n";
PVDoublePtr pvDouble =
std::tr1::static_pointer_cast<PVDouble>(factory->createPVScalar(epics::pvData::pvDouble));
pvDouble->put(0);
serializationTest(pvDouble);
pvDouble->put(12.345);
serializationTest(pvDouble);
pvDouble->put(DOUBLE_MAX_VALUE);
serializationTest(pvDouble);
pvDouble->put(DOUBLE_MIN_VALUE);
serializationTest(pvDouble);
ofile<<"\tPVString\n";
testDiag("type %s", ScalarTypeFunc::name(pvString));
PVStringPtr pvString =
std::tr1::static_pointer_cast<PVString>(factory->createPVScalar(epics::pvData::pvString));
pvString->put("");
@@ -377,167 +244,88 @@ void testScalar(std::ostream& ofile) {
// huge string test
pvString->put(String(10000, 'a'));
serializationTest(pvString);
// TODO unsigned test
ofile<<"!!! PASSED\n\n";
}
void testArray(std::ostream& ofile) {
ofile<<"Testing arrays...\n";
template<typename PVT>
void testArrayType(const typename PVT::value_type* rdata, size_t len)
{
typedef typename PVT::value_type value_type;
PVDataCreatePtr factory = getPVDataCreate();
assert(factory.get()!=NULL);
typename PVT::svector empty(0), data(len);
ofile<<"\tPVBooleanArray\n";
//bool boolEmpty[] = { false };
//bool bv[] = { false, true, false, true, true };
PVBooleanArrayPtr pvBoolean =
std::tr1::static_pointer_cast<PVBooleanArray>(factory->createPVScalarArray(epics::pvData::pvBoolean));
//pvBoolean->put(0, 0, boolEmpty, 0);
serializationTest(pvBoolean);
//pvBoolean->put(0, 5, bv, 0);
serializationTest(pvBoolean);
std::copy(rdata, rdata+len, data.begin());
ofile<<"\tPVByteArray\n";
int8 byteEmpty[] = { 0 };
int8 byv[] = { 0, 1, 2, -1, BYTE_MAX_VALUE, BYTE_MAX_VALUE-1,
BYTE_MIN_VALUE+1, BYTE_MIN_VALUE };
PVByteArrayPtr pvByte =
std::tr1::static_pointer_cast<PVByteArray>(factory->createPVScalarArray(epics::pvData::pvByte));
pvByte->put(0, 0, byteEmpty, 0);
serializationTest(pvByte);
pvByte->put(0, 8, byv, 0);
serializationTest(pvByte);
testDiag("type %s", ScalarTypeFunc::name(PVT::typeCode));
ofile<<"\tPVShortArray\n";
int16 shortEmpty[] = { 0 };
int16 sv[] = { 0, 1, 2, -1, SHORT_MAX_VALUE, SHORT_MAX_VALUE-1,
SHORT_MIN_VALUE+1, SHORT_MIN_VALUE };
PVShortArrayPtr pvShort =
std::tr1::static_pointer_cast<PVShortArray>(factory->createPVScalarArray(epics::pvData::pvShort));
pvShort->put(0, 0, shortEmpty, 0);
serializationTest(pvShort);
pvShort->put(0, 8, sv, 0);
serializationTest(pvShort);
typename PVT::shared_pointer pv = std::tr1::static_pointer_cast<PVT>(getPVDataCreate()->createPVScalarArray(PVT::typeCode));
ofile<<"\tPVIntArray\n";
int32 intEmpty[] = { 0 };
int32 iv[] = { 0, 1, 2, -1, INT_MAX_VALUE, INT_MAX_VALUE-1,
INT_MIN_VALUE+1, INT_MIN_VALUE };
PVIntArrayPtr pvInt =
std::tr1::static_pointer_cast<PVIntArray>(factory->createPVScalarArray(epics::pvData::pvInt));
pvInt->put(0, 0, intEmpty, 0);
serializationTest(pvInt);
pvInt->put(0, 8, iv, 0);
serializationTest(pvInt);
ofile<<"\tPVLongArray\n";
int64 longEmpty[] = { 0 };
int64 lv[] = { 0, 1, 2, -1, LONG_MAX_VALUE, LONG_MAX_VALUE-1,
LONG_MIN_VALUE+1, LONG_MIN_VALUE };
PVLongArrayPtr pvLong =
std::tr1::static_pointer_cast<PVLongArray>(factory->createPVScalarArray(epics::pvData::pvLong));
pvLong->put(0, 0, longEmpty, 0);
serializationTest(pvLong);
pvLong->put(0, 8, lv, 0);
serializationTest(pvLong);
ofile<<"\tPVUByteArray\n";
uint8 ubyteEmpty[] = { 0 };
uint8 ubyv[] = { 0, 1, 2, -1, BYTE_MAX_VALUE, BYTE_MAX_VALUE-1,
BYTE_MIN_VALUE+1, BYTE_MIN_VALUE, UBYTE_MAX_VALUE };
PVUByteArrayPtr pvUByte =
std::tr1::static_pointer_cast<PVUByteArray>(factory->createPVScalarArray(epics::pvData::pvUByte));
pvUByte->put(0, 0, ubyteEmpty, 0);
serializationTest(pvUByte);
pvUByte->put(0, 9, ubyv, 0);
serializationTest(pvUByte);
ofile<<"\tPVUShortArray\n";
uint16 ushortEmpty[] = { 0 };
uint16 usv[] = { 0, 1, 2, -1, SHORT_MAX_VALUE, SHORT_MAX_VALUE-1,
SHORT_MIN_VALUE+1, SHORT_MIN_VALUE, USHORT_MAX_VALUE };
PVUShortArrayPtr pvUShort =
std::tr1::static_pointer_cast<PVUShortArray>(factory->createPVScalarArray(epics::pvData::pvUShort));
pvUShort->put(0, 0, ushortEmpty, 0);
serializationTest(pvUShort);
pvUShort->put(0, 8, usv, 0);
serializationTest(pvUShort);
ofile<<"\tPVUIntArray\n";
uint32 uintEmpty[] = { 0 };
uint32 uiv[] = { 0, 1, 2, -1, INT_MAX_VALUE, INT_MAX_VALUE-1,
INT_MIN_VALUE+1, INT_MIN_VALUE, UINT_MAX_VALUE };
PVUIntArrayPtr pvUInt =
std::tr1::static_pointer_cast<PVUIntArray>(factory->createPVScalarArray(epics::pvData::pvUInt));
pvUInt->put(0, 0, uintEmpty, 0);
serializationTest(pvUInt);
pvUInt->put(0, 9, uiv, 0);
serializationTest(pvUInt);
ofile<<"\tPVULongArray\n";
uint64 ulongEmpty[] = { 0 };
uint64 ulv[] = { 0, 1, 2, -1, LONG_MAX_VALUE, LONG_MAX_VALUE-1,
LONG_MIN_VALUE+1, LONG_MIN_VALUE, ULONG_MAX_VALUE };
PVULongArrayPtr pvULong =
std::tr1::static_pointer_cast<PVULongArray>(factory->createPVScalarArray(epics::pvData::pvULong));
pvULong->put(0, 0, ulongEmpty, 0);
serializationTest(pvULong);
pvULong->put(0, 9, ulv, 0);
serializationTest(pvULong);
ofile<<"\tPVFloatArray\n";
float floatEmpty[] = { (float)0.0 };
float fv[] = { (float)0.0, (float)1.1, (float)2.3, (float)-1.4,
FLOAT_MAX_VALUE, FLOAT_MAX_VALUE-(float)123456.789, FLOAT_MIN_VALUE
+(float)1.1, FLOAT_MIN_VALUE };
PVFloatArrayPtr pvFloat =
std::tr1::static_pointer_cast<PVFloatArray>(factory->createPVScalarArray(epics::pvData::pvFloat));
pvFloat->put(0, 0, floatEmpty, 0);
serializationTest(pvFloat);
pvFloat->put(0, 8, fv, 0);
serializationTest(pvFloat);
ofile<<"\tPVDoubleArray\n";
double doubleEmpty[] = { (double)0.0 };
double dv[] = { (double)0.0, (double)1.1, (double)2.3, (double)-1.4,
DOUBLE_MAX_VALUE, DOUBLE_MAX_VALUE-(double)123456.789,
DOUBLE_MIN_VALUE+(double)1.1, DOUBLE_MIN_VALUE };
PVDoubleArrayPtr pvDouble =
std::tr1::static_pointer_cast<PVDoubleArray>(factory->createPVScalarArray(epics::pvData::pvDouble));
pvDouble->put(0, 0, doubleEmpty, 0);
serializationTest(pvDouble);
pvDouble->put(0, 8, dv, 0);
serializationTest(pvDouble);
ofile<<"\tPVStringArray\n";
String stringEmpty[] = { "" };
String
strv[] =
{
"",
"a",
"a b",
" ",
"test",
"smile",
"this is a little longer string... maybe a little but longer... this makes test better",
String(10000, 'b') };
PVStringArrayPtr pvString =
std::tr1::static_pointer_cast<PVStringArray>(factory->createPVScalarArray(epics::pvData::pvString));
pvString->put(0, 0, stringEmpty, 0);
serializationTest(pvString);
pvString->put(0, 8, strv, 0);
serializationTest(pvString);
ofile<<"!!! PASSED\n\n";
pv->replace(freeze(empty));
serializationTest(pv);
pv->replace(freeze(data));
serializationTest(pv);
}
void testNonInitialized(std::ostream& ofile) {
ofile<<"Testing non-initialized...\n";
static const boolean bdata[] = {0, 1, 0, 1, 1};
static const int8 i8data[] = { 0, 1, 2, -1, BYTE_MAX_VALUE, BYTE_MAX_VALUE-1,
BYTE_MIN_VALUE+1, BYTE_MIN_VALUE };
static const uint8 u8data[] = { 0, 1, 2, -1, UBYTE_MAX_VALUE, UBYTE_MAX_VALUE-1 };
static const int16 i16data[] = { 0, 1, 2, -1, SHORT_MAX_VALUE, SHORT_MAX_VALUE-1,
SHORT_MIN_VALUE+1, SHORT_MIN_VALUE };
static const uint16 u16data[] = { 0, 1, 2, -1, USHORT_MAX_VALUE, USHORT_MAX_VALUE-1 };
static const int32 i32data[] = { 0, 1, 2, -1, INT_MAX_VALUE, INT_MAX_VALUE-1,
INT_MIN_VALUE+1, INT_MIN_VALUE };
static const uint32 u32data[] = { 0, 1, 2, -1, UINT_MAX_VALUE, UINT_MAX_VALUE-1 };
static const int64 i64data[] = { 0, 1, 2, -1, LONG_MAX_VALUE, LONG_MAX_VALUE-1,
LONG_MIN_VALUE+1, LONG_MIN_VALUE };
static const uint64 u64data[] = { 0, 1, 2, -1, ULONG_MAX_VALUE, ULONG_MAX_VALUE-1 };
static const double ddata[] = { (double)0.0, (double)1.1, (double)2.3, (double)-1.4,
DOUBLE_MAX_VALUE, DOUBLE_MAX_VALUE-(double)123456.789,
DOUBLE_MIN_VALUE+(double)1.1, DOUBLE_MIN_VALUE };
static const float fdata[] = { (float)0.0, (float)1.1, (float)2.3, (float)-1.4,
FLOAT_MAX_VALUE, FLOAT_MAX_VALUE-(float)123456.789,
FLOAT_MIN_VALUE+(float)1.1, FLOAT_MIN_VALUE };
static const String sdata[] = {
"",
"a",
"a b",
" ",
"test",
"smile",
"this is a little longer string... maybe a little but longer... this makes test better",
String(10000, 'b')
};
void testArray() {
testDiag("Testing arrays...");
testArrayType<PVBooleanArray>(bdata, NELEMENTS(bdata));
testArrayType<PVByteArray>(i8data, NELEMENTS(i8data));
testArrayType<PVUByteArray>(u8data, NELEMENTS(u8data));
testArrayType<PVShortArray>(i16data, NELEMENTS(i16data));
testArrayType<PVUShortArray>(u16data, NELEMENTS(u16data));
testArrayType<PVIntArray>(i32data, NELEMENTS(i32data));
testArrayType<PVUIntArray>(u32data, NELEMENTS(u32data));
testArrayType<PVLongArray>(i64data, NELEMENTS(i64data));
testArrayType<PVULongArray>(u64data, NELEMENTS(u64data));
testArrayType<PVDoubleArray>(ddata, NELEMENTS(ddata));
testArrayType<PVFloatArray>(fdata, NELEMENTS(fdata));
testArrayType<PVStringArray>(sdata, NELEMENTS(sdata));
}
void testNonInitialized() {
testDiag("Testing non-initialized...");
PVDataCreatePtr factory = getPVDataCreate();
assert(factory.get()!=NULL);
testOk1(factory.get()!=NULL);
// be sure all is covered
for (int i = pvBoolean; i < pvString; i++)
@@ -558,17 +346,15 @@ void testNonInitialized(std::ostream& ofile) {
// and a structure array
PVStructureArrayPtr structureArray = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure->getStructure()));
serializationTest(structureArray);
ofile<<"!!! PASSED\n\n";
}
void testStructure(std::ostream& ofile) {
ofile<<"Testing structure...\n";
void testStructure() {
testDiag("Testing structure...");
PVDataCreatePtr factory = getPVDataCreate();
assert(factory.get()!=NULL);
testOk1(factory.get()!=NULL);
ofile<<"\tSimple structure serialization\n";
testDiag("\tSimple structure serialization");
PVStructurePtr pvStructure = factory->createPVStructure(getStandardField()->timeStamp());
pvStructure->getLongField("secondsPastEpoch")->put(123);
pvStructure->getIntField("nanoSeconds")->put(456);
@@ -576,21 +362,47 @@ void testStructure(std::ostream& ofile) {
serializationTest(pvStructure);
ofile<<"\tComplex structure serialization\n";
testDiag("\tComplex structure serialization");
pvStructure = factory->createPVStructure(
getStandardField()->structureArray(
getStandardField()->timeStamp(), "alarm,control,display,timeStamp")
);
// TODO fill with data
serializationTest(pvStructure);
}
ofile<<"!!! PASSED\n\n";
void testStructureArray() {
testDiag("Testing structure array...");
PVDataCreatePtr factory = getPVDataCreate();
testOk1(factory.get()!=NULL);
StructureArrayConstPtr tstype(
getFieldCreate()->createStructureArray(getStandardField()->alarm()));
PVStructureArrayPtr pvArr = getPVDataCreate()->createPVStructureArray(tstype);
testDiag("empty array");
serializationTest(pvArr);
pvArr->setLength(10);
testDiag("All NULLs");
serializationTest(pvArr);
PVStructureArray::svector data(5);
data[1] = getPVDataCreate()->createPVStructure(getStandardField()->alarm());
data[4] = getPVDataCreate()->createPVStructure(getStandardField()->alarm());
pvArr->replace(freeze(data));
testDiag("Some NULLs");
serializationTest(pvArr);
}
void testStructureId(std::ostream& ofile) {
ofile<<"Testing structureID...\n";
void testStructureId() {
testDiag("Testing structureID...");
FieldCreatePtr fieldCreate = getFieldCreate();
@@ -607,15 +419,13 @@ void testStructureId(std::ostream& ofile) {
StructureConstPtr structure2 = fieldCreate->createStructure("id2", fieldNames, fields);
assert(structureWithNoId!=structure1);
assert(structure1!=structure2);
testOk1(structureWithNoId!=structure1);
testOk1(structure1!=structure2);
//serializationTest(structure1);
PVStructurePtr pvStructure = getPVDataCreate()->createPVStructure(structure1);
serializationTest(pvStructure);
ofile<<"!!! PASSED\n\n";
}
void serializatioTest(FieldConstPtr const & field)
@@ -631,17 +441,15 @@ void serializatioTest(FieldConstPtr const & field)
FieldConstPtr deserializedField = getFieldCreate()->deserialize(buffer, control);
// must equal
bool isEqual = *field == *deserializedField;
assert(isEqual);
//assertEquals("field " + field.toString() + " serialization broken", field, deserializedField);
testOk1(*field == *deserializedField);
}
void testIntrospectionSerialization(std::ostream& ofile)
void testIntrospectionSerialization()
{
ofile<<"Testing introspection serialization...\n";
testDiag("Testing introspection serialization...");
FieldCreatePtr factory = getFieldCreate();
assert(factory.get()!=NULL);
testOk1(factory.get()!=NULL);
// be sure all is covered
for (int i = pvBoolean; i < pvString; i++)
@@ -662,42 +470,35 @@ void testIntrospectionSerialization(std::ostream& ofile)
// and a structure array
StructureArrayConstPtr structureArray = factory->createStructureArray(structure);
serializatioTest(structureArray);
ofile<<"!!! PASSED\n\n";
}
void testStringCopy(std::ostream& ofile) {
void testStringCopy() {
String s1 = "abc";
String s2 = s1;
if (s1.c_str() != s2.c_str())
ofile << "\n!!! implementation of epics::pvData::String assignment operator does not share content !!!\n\n";
testDiag("implementation of epics::pvData::String assignment operator does not share content");
}
int main(int argc, char *argv[]) {
std::ofstream outfile;
std::ostream *out=NULL;
if(argc>1) {
outfile.open(argv[1]);
if(outfile.is_open()){
out=&outfile;
}else{
fprintf(stderr, "Failed to open test output file\n");
}
}
if(!out) out=&std::cout;
} // end namespace
MAIN(testSerialization) {
testPlan(175);
flusher = new SerializableControlImpl();
control = new DeserializableControlImpl();
buffer = new ByteBuffer(1<<16);
testStringCopy(*out);
testStringCopy();
testIntrospectionSerialization(*out);
testEquals(*out);
testNonInitialized(*out);
testIntrospectionSerialization();
testEquals();
testNonInitialized();
testScalar(*out);
testArray(*out);
testStructure(*out);
testScalar();
testArray();
testStructure();
testStructureArray();
delete buffer;
@@ -705,6 +506,6 @@ int main(int argc, char *argv[]) {
delete flusher;
epicsExitCallAtExits();
return 0;
return testDone();
}

View File

@@ -0,0 +1,558 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/* Author: Michael Davidsaver */
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <vector>
#include <epicsUnitTest.h>
#include <testMain.h>
#include "pv/sharedVector.h"
static void testEmpty()
{
testDiag("Test empty vector");
epics::pvData::shared_vector<int> empty, empty2;
testOk1(empty.size()==0);
testOk1(empty.empty());
testOk1(empty.begin()==empty.end());
testOk1(empty.unique());
testOk1(empty.data()==NULL);
testOk1(empty==empty);
testOk1(!(empty!=empty));
testOk1(empty==empty2);
testOk1(!(empty!=empty2));
}
static void testInternalAlloc()
{
testDiag("Test vector alloc w/ new[]");
epics::pvData::shared_vector<int> internal(5);
testOk1(internal.size()==5);
testOk1(!internal.empty());
testOk1(internal.unique());
testOk1(internal.data()!=NULL);
testOk1(internal.begin()+5==internal.end());
testOk1(internal.begin()==internal.end()-5);
testOk1(internal.begin()+2==internal.end()-3);
testOk1(internal.end()-internal.begin()==5);
internal[2] = 42;
testOk1(internal[2]==42);
epics::pvData::shared_vector<int> internal2(15, 500);
testOk1(internal2.size()==15);
testOk1(internal2[1]==500);
internal.swap(internal2);
testOk1(internal2.size()==5);
testOk1(internal.size()==15);
internal.clear();
testOk1(internal.size()==0);
testOk1(internal.empty());
testOk1(internal.unique());
testOk1(internal.data()==NULL);
}
namespace {
//Note: STL shared_ptr requires that deletors be copy constructable
template<typename E>
struct callCounter {
std::tr1::shared_ptr<int> count;
callCounter():count(new int){*count=0;}
callCounter(const callCounter& o):count(o.count) {};
callCounter& operator=(const callCounter& o){count=o.count;}
void operator()(E){*count=1;}
};
}
static void testExternalAlloc()
{
testDiag("Test vector external alloc");
// Simulate a failed malloc() or similar
int *oops=0;
epics::pvData::shared_vector<int> nullPtr(oops, 42, 100);
testOk1(nullPtr.size()==0);
testOk1(nullPtr.empty());
testOk1(nullPtr.begin()==nullPtr.end());
testOk1(nullPtr.unique());
testOk1(nullPtr.data()==NULL);
int *raw=new int[5];
epics::pvData::shared_vector<int> newData(raw, 1, 4);
testOk1(newData.size()==4);
testOk1(!newData.empty());
// check that offset is used
raw[1]=14;
testOk1(newData[0]==14);
// Check use of custom deleter
int localVar[4] = {1,2,3,4};
callCounter<int*> tracker;
testOk1(*tracker.count==0);
epics::pvData::shared_vector<int> locvar(localVar,
tracker,
0, 4);
testOk1(locvar[1]==2);
testOk1(*tracker.count==0);
newData.swap(locvar);
testOk1(*tracker.count==0);
newData.clear();
testOk1(*tracker.count==1);
}
static void testShare()
{
testDiag("Test vector Sharing");
epics::pvData::shared_vector<int> one, two(15);
epics::pvData::shared_vector<int> three(two);
testOk1(one.unique());
testOk1(!two.unique());
testOk1(!three.unique());
testOk1(two.data() == three.data());
one = two;
testOk1(!one.unique());
testOk1(two.data() == one.data());
one = one; // no-op
testOk1(two.data() == one.data());
one[1] = 43;
testOk1(two[1]==43);
testOk1(three[1]==43);
one.make_unique();
testOk1(one[1]==43);
one[1] = 143;
testOk1(two[1]==43);
testOk1(three[1]==43);
two.resize(two.size());
testOk1(two[1]==43);
two[1] = 243;
testOk1(one[1]==143);
testOk1(three[1]==43);
testOk1(one.unique());
testOk1(two.unique());
testOk1(three.unique());
one.resize(2);
testOk1(one.size()==2);
testOk1(one[1]==143);
testOk1(two.size()==15);
testOk1(three.size()==15);
two.resize(20, 5000);
testOk1(two[1]==243);
testOk1(one.size()==2);
testOk1(two.size()==20);
testOk1(three.size()==15);
testOk1(two[19]==5000);
}
static void testConst()
{
testDiag("Test constant vector");
epics::pvData::shared_vector<int> writable(15, 100);
epics::pvData::shared_vector<int>::reference wr = writable[0];
epics::pvData::shared_vector<int>::const_reference ror = writable[0];
testOk1(wr==ror);
int *compare = writable.data();
testOk1(writable.unique());
// can re-target container, but data is R/O
epics::pvData::shared_vector<const int> rodata(freeze(writable));
epics::pvData::shared_vector<const int>::reference wcr = rodata[0];
epics::pvData::shared_vector<const int>::const_reference rocr = rodata[0];
testOk1(wcr==rocr);
testOk1(rodata.data()==compare);
writable = thaw(rodata);
testOk1(writable.data()==compare);
rodata = freeze(writable);
testOk1(rodata.data()==compare);
epics::pvData::shared_vector<const int> rodata2(rodata);
testOk1(rodata.data()==rodata2.data());
rodata2.make_unique();
testOk1(rodata.data()!=rodata2.data());
}
static void testSlice()
{
testDiag("Test vector slicing");
epics::pvData::shared_vector<int> original(10, 100);
epics::pvData::shared_vector<int> half1(original), half2(original), half2a(original);
half1.slice(0, 5);
half2.slice(5, 5);
half2a.slice(5);
testOk1(half1.dataOffset()==0);
testOk1(half2.dataOffset()==5);
testOk1(half2a.dataOffset()==5);
testOk1(half1.size()==5);
testOk1(half2.size()==5);
testOk1(half2a.size()==5);
testOk1(half1.dataTotal()==10);
testOk1(half2.dataTotal()==5);
testOk1(half2a.dataTotal()==5);
testOk1(original.data() == half1.data());
testOk1(half2.data() == half2a.data());
half1.slice(100000);
half2.slice(1);
half2a.slice(1,1);
testOk1(half1.dataOffset()==5);
testOk1(half2.dataOffset()==6);
testOk1(half2a.dataOffset()==6);
testOk1(half1.size()==0);
testOk1(half2.size()==4);
testOk1(half2a.size()==1);
testOk1(half1.dataTotal()==5);
testOk1(half2.dataTotal()==4);
testOk1(half2a.dataTotal()==4);
half2.clear();
testOk1(half2.dataOffset()==0);
testOk1(half2.dataCount()==0);
testOk1(half2.dataTotal()==0);
testOk1(half2.data()==NULL);
}
static void testCapacity()
{
testDiag("Test vector capacity");
epics::pvData::shared_vector<int> vect(10, 100);
int *peek = vect.dataPtr().get();
vect.slice(0, 5);
testOk1(vect.size()==5);
testOk1(vect.dataTotal()==10);
testOk1(vect.dataPtr().get() == peek);
vect.resize(6);
testOk1(vect.dataPtr().get() == peek);
testOk1(vect.size()==6);
testOk1(vect.dataTotal()==10);
vect.resize(10);
testOk1(vect.dataPtr().get() == peek);
testOk1(vect.size()==10);
testOk1(vect.dataTotal()==10);
vect.resize(11);
testOk1(vect.dataPtr().get() != peek);
testOk1(vect.size()==11);
testOk1(vect.dataTotal()>=11);
vect[1] = 124;
vect.reserve(15);
testOk1(vect.size()==11);
testOk1(vect.dataTotal()>=15);
testOk1(vect[1]==124);
}
static void testPush()
{
epics::pvData::shared_vector<int> vect;
testDiag("Test push_back optimizations");
size_t nallocs = 0;
size_t cap = vect.capacity();
for(size_t s=0; s<16*1024; s++) {
vect.push_back(s);
if(cap!=vect.capacity()) {
nallocs++;
cap = vect.capacity();
}
}
testDiag("push_back %ld times caused %ld re-allocations",
(unsigned long)vect.size(),
(unsigned long)nallocs);
testOk1(nallocs==26);
}
static void testVoid()
{
testDiag("Test vecter cast to/from void");
epics::pvData::shared_vector<int> typed(4);
epics::pvData::shared_vector<void> untyped2(epics::pvData::static_shared_vector_cast<void>(typed));
testOk1(typed.dataPtr().get()==untyped2.dataPtr().get());
testOk1(typed.size()*sizeof(int)==untyped2.size());
untyped2.slice(sizeof(int), 2*sizeof(int));
typed = epics::pvData::static_shared_vector_cast<int>(untyped2);
testOk1(typed.dataOffset()==1);
testOk1(typed.size()==2);
}
struct dummyStruct {};
static void testNonPOD()
{
testDiag("Test vector of non-POD types");
epics::pvData::shared_vector<std::string> strings(6);
epics::pvData::shared_vector<std::tr1::shared_ptr<dummyStruct> > structs(5);
testOk1(strings[0].empty());
testOk1(structs[0].get()==NULL);
structs[1].reset(new dummyStruct);
dummyStruct *temp = structs[1].get();
epics::pvData::shared_vector<std::tr1::shared_ptr<dummyStruct> > structs2(structs);
testOk1(!structs.unique());
testOk1(structs[1].unique());
testOk1(structs2[1].get()==temp);
structs2.make_unique();
testOk1(structs.unique());
testOk1(!structs[1].unique());
testOk1(structs2[1].get()==temp);
}
static void testVectorConvert()
{
testDiag("Test shared_vector_convert");
epics::pvData::shared_vector<int> ints(6, 42), moreints;
epics::pvData::shared_vector<float> floats;
epics::pvData::shared_vector<std::string> strings;
epics::pvData::shared_vector<void> voids;
testOk1(ints.unique());
// no-op convert. Just returns another reference
moreints = epics::pvData::shared_vector_convert<int>(ints);
testOk1(!ints.unique());
moreints.clear();
// conversion when both types are known.
// returns a new vector
floats = epics::pvData::shared_vector_convert<float>(ints);
testOk1(ints.unique());
testOk1(floats.size()==ints.size());
testOk1(floats.at(0)==42.0);
// convert to void is static_shared_vector_cast<void>()
// returns a reference
voids = epics::pvData::shared_vector_convert<void>(ints);
testOk1(!ints.unique());
testOk1(voids.size()==ints.size()*sizeof(int));
// convert from void uses shared_vector<void>::original_type()
// to find that the actual type is 'int'.
// returns a new vector
strings = epics::pvData::shared_vector_convert<std::string>(voids);
voids.clear();
testOk1(ints.unique());
testOk1(strings.size()==ints.size());
testOk1(strings.at(0)=="42");
}
static void testWeak()
{
testDiag("Test weak_ptr counting");
epics::pvData::shared_vector<int> data(6);
testOk1(data.unique());
std::tr1::shared_ptr<int> pdata(data.dataPtr());
testOk1(!data.unique());
pdata.reset();
testOk1(data.unique());
std::tr1::weak_ptr<int> wdata(data.dataPtr());
testOk1(data.unique()); // True, but I wish it wasn't!!!
pdata = wdata.lock();
testOk1(!data.unique());
}
static void testICE()
{
testDiag("Test freeze and thaw");
epics::pvData::shared_vector<int> A(6, 42), C;
epics::pvData::shared_vector<const int> B, D;
int *check = A.data();
// check freeze w/ unique reference
// clears A and moves reference to B
// no copy
B = epics::pvData::freeze(A);
testOk1(A.unique());
testOk1(B.unique());
testOk1(A.size()==0);
testOk1(B.size()==6);
testOk1(A.data()!=check);
testOk1(B.data()==check);
D = B; // create second const reference
// clears D, but reference to B refrence
// to B remains, so a copy is made
C = epics::pvData::thaw(D);
testOk1(B.unique());
testOk1(C.unique());
testOk1(B.size()==6);
testOk1(C.size()==6);
testOk1(B.data()==check);
testOk1(C.data()!=NULL);
testOk1(C.at(0)==42);
C.clear();
// clears B and moves reference to A
// no copy
A = epics::pvData::thaw(B);
testOk1(A.unique());
testOk1(B.unique());
testOk1(A.size()==6);
testOk1(B.size()==0);
testOk1(A.data()==check);
testOk1(B.data()!=check);
C = A; // create second non-const reference
testOk1(!A.unique());
try {
// would clear A, but remaining reference C
// fails operation. A not cleared
// and exception thrown
B = epics::pvData::freeze(A);
testFail("Froze non-unique vector!");
} catch(std::runtime_error& e) {
testPass("freeze of non-unique throws runtime_error as expected");
}
}
MAIN(testSharedVector)
{
testPlan(162);
testDiag("Tests for shared_vector");
testDiag("sizeof(shared_vector<int>)=%lu",
(unsigned long)sizeof(epics::pvData::shared_vector<int>));
testEmpty();
testInternalAlloc();
testExternalAlloc();
testCapacity();
testShare();
testConst();
testSlice();
testPush();
testVoid();
testNonPOD();
testVectorConvert();
testWeak();
testICE();
return testDone();
}

View File

@@ -0,0 +1,407 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/* Author: Michael Davidsaver */
#include <fstream>
#include <iostream>
#include <algorithm>
#include <limits>
#include <typeinfo>
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <float.h>
#include <epicsMath.h>
#include <epicsUnitTest.h>
#include <testMain.h>
#include "pv/typeCast.h"
using epics::pvData::String;
namespace {
template<typename T>
struct testequal {
static bool op(T A, T B) {return A==B; }
};
template<>
struct testequal<double> {
static bool op(double A, double B) {return fabs(A-B)<1e-300; }
};
template<>
struct testequal<float> {
static bool op(float A, float B) {return fabs(A-B)<1e-30; }
};
template<typename TO, typename FROM>
struct testcase {
static void op(TO expect, FROM inp)
{
std::ostringstream msg;
TO actual;
try {
actual = ::epics::pvData::castUnsafe<TO,FROM>(inp);
//actual = ::epics::pvData::detail::cast_helper<TO,FROM>::op(inp);
} catch(std::runtime_error& e) {
msg<<"Failed to cast "
<<inp<<" ("<<typeid(FROM).name()<<") -> "
<<expect<<" ("<<typeid(TO).name()<<")\n Error: "
<<typeid(e).name()<<"("<<e.what()<<")";
testFail("%s", msg.str().c_str());
return;
}
if(!testequal<TO>::op(actual, expect)) {
msg<<"Failed cast gives unexpected value "
<<inp<<" ("<<typeid(FROM).name()<<") -> "
<<expect<<" ("<<typeid(TO).name()<<") yields: "
<<actual;
testFail("%s", msg.str().c_str());
return;
}
msg<<"cast "
<<inp<<" ("<<typeid(FROM).name()<<") -> "
<<expect<<" ("<<typeid(TO).name()<<") yields: "
<<actual;
testPass("%s", msg.str().c_str());
return;
}
};
template<typename TO, typename FROM>
struct testfail {
static void op(FROM inp)
{
std::ostringstream msg;
TO actual;
try {
actual = ::epics::pvData::castUnsafe<TO,FROM>(inp);
msg<<"Failed to generate expected error "
<<inp<<" ("<<typeid(FROM).name()<<") -> ("
<<typeid(TO).name()<<") yields: "
<<actual;
testFail("%s", msg.str().c_str());
return;
} catch(std::runtime_error& e) {
msg<<"Got expected error "
<<inp<<" ("<<typeid(FROM).name()<<") -> ("
<<typeid(TO).name()<<") fails with: "
<<e.what();
testPass("%s", msg.str().c_str());
return;
}
}
};
// Test cast
#define TEST(TTO, VTO, TFRO, VFRO) testcase<TTO, TFRO>::op(VTO, VFRO)
// Test cast and reverse
#define TEST2(TTO, VTO, TFRO, VFRO) TEST(TTO, VTO, TFRO, VFRO); TEST(TFRO, VFRO, TTO, VTO)
#define FAIL(TTO, TFRO, VFRO) testfail<TTO,TFRO>::op(VFRO)
} // end namespace
MAIN(testTypeCast)
{
testPlan(110);
try {
int8_t xint8=0;
uint8_t xuint8=0;
int16_t xint16=0;
uint16_t xuint16=0;
int32_t xint32=0;
uint32_t xuint32=0;
int64_t xint64=0;
uint64_t xuint64=0;
float xfloat=0.0;
double xdouble=0.0;
epics::pvData::String xString("0");
typedef float float_t;
typedef double double_t;
typedef epics::pvData::String String_t;
// force all possibilities to be compiled
#define CHECK(M, N) x## M = ::epics::pvData::castUnsafe<M ##_t>(x## N); \
std::transform(&x ## N, &x ## N+1, &x ## M, ::epics::pvData::castUnsafe<M ##_t,N ##_t>)
//#define CHECK(M, N) x## M = ::epics::pvData::detail::cast_helper<M ##_t,N ##_t>::op(x## N)
CHECK(int8, int8);
CHECK(int8, uint8);
CHECK(int8, int16);
CHECK(int8, uint16);
CHECK(int8, int32);
CHECK(int8, uint32);
CHECK(int8, int64);
CHECK(int8, uint64);
CHECK(int8, float);
CHECK(int8, double);
CHECK(int8, String);
CHECK(uint8, int8);
CHECK(uint8, uint8);
CHECK(uint8, int16);
CHECK(uint8, uint16);
CHECK(uint8, int32);
CHECK(uint8, uint32);
CHECK(uint8, int64);
CHECK(uint8, uint64);
CHECK(uint8, float);
CHECK(uint8, double);
CHECK(uint8, String);
CHECK(int16, int8);
CHECK(int16, uint8);
CHECK(int16, int16);
CHECK(int16, uint16);
CHECK(int16, int32);
CHECK(int16, uint32);
CHECK(int16, int64);
CHECK(int16, uint64);
CHECK(int16, float);
CHECK(int16, double);
CHECK(int16, String);
CHECK(uint16, int8);
CHECK(uint16, uint8);
CHECK(uint16, int16);
CHECK(uint16, uint16);
CHECK(uint16, int32);
CHECK(uint16, uint32);
CHECK(uint16, int64);
CHECK(uint16, uint64);
CHECK(uint16, float);
CHECK(uint16, double);
CHECK(uint16, String);
CHECK(int32, int8);
CHECK(int32, uint8);
CHECK(int32, int16);
CHECK(int32, uint16);
CHECK(int32, int32);
CHECK(int32, uint32);
CHECK(int32, int64);
CHECK(int32, uint64);
CHECK(int32, float);
CHECK(int32, double);
CHECK(int32, String);
CHECK(uint32, int8);
CHECK(uint32, uint8);
CHECK(uint32, int16);
CHECK(uint32, uint16);
CHECK(uint32, int32);
CHECK(uint32, uint32);
CHECK(uint32, int64);
CHECK(uint32, uint64);
CHECK(uint32, float);
CHECK(uint32, double);
CHECK(uint32, String);
CHECK(int64, int8);
CHECK(int64, uint8);
CHECK(int64, int16);
CHECK(int64, uint16);
CHECK(int64, int32);
CHECK(int64, uint32);
CHECK(int64, int64);
CHECK(int64, uint64);
CHECK(int64, float);
CHECK(int64, double);
//CHECK(int64, String);
CHECK(uint64, int8);
CHECK(uint64, uint8);
CHECK(uint64, int16);
CHECK(uint64, uint16);
CHECK(uint64, int32);
CHECK(uint64, uint32);
CHECK(uint64, int64);
CHECK(uint64, uint64);
CHECK(uint64, float);
CHECK(uint64, double);
//CHECK(uint64, String);
CHECK(float, int8);
CHECK(float, uint8);
CHECK(float, int16);
CHECK(float, uint16);
CHECK(float, int32);
CHECK(float, uint32);
CHECK(float, int64);
CHECK(float, uint64);
CHECK(float, float);
CHECK(float, double);
CHECK(float, String);
CHECK(double, int8);
CHECK(double, uint8);
CHECK(double, int16);
CHECK(double, uint16);
CHECK(double, int32);
CHECK(double, uint32);
CHECK(double, int64);
CHECK(double, uint64);
CHECK(double, float);
CHECK(double, double);
CHECK(double, String);
CHECK(String, int8);
CHECK(String, uint8);
CHECK(String, int16);
CHECK(String, uint16);
CHECK(String, int32);
CHECK(String, uint32);
CHECK(String, int64);
CHECK(String, uint64);
CHECK(String, float);
CHECK(String, double);
CHECK(String, String);
#undef CHECK
testDiag("Integer signed <=> unsigned");
TEST2(uint8_t, std::numeric_limits<uint8_t>::max(), int8_t, -1);
TEST2(uint16_t, std::numeric_limits<uint16_t>::max(), int8_t, -1);
TEST2(uint32_t, std::numeric_limits<uint32_t>::max(), int8_t, -1);
TEST2(uint64_t, std::numeric_limits<uint64_t>::max(), int8_t, -1);
testDiag("Integer unsigned promote (and demote when in range)");
TEST2(uint16_t, 0xff, uint8_t, 0xff);
TEST2(uint32_t, 0xffff, uint16_t, 0xffff);
TEST2(uint64_t, 0xffffffffu, uint32_t, 0xffffffffu);
TEST2(int16_t, 0x7f, int8_t, 0x7f);
TEST2(int32_t, 0x7fff, int16_t, 0x7fff);
TEST2(int64_t, 0x7fffffff, int32_t, 0x7fffffff);
testDiag("Double to int w/ round towards zero (aka truncation)");
TEST(int32_t, 2, double, 2.1);
TEST(int32_t, 2, double, 2.5);
TEST(int32_t, 2, double, 2.7);
TEST(int32_t, -2, double, -2.1);
TEST(int32_t, -2, double, -2.5);
TEST(int32_t, -2, double, -2.7);
testDiag("Float to int w/ round towards zero (aka truncation)");
TEST(int32_t, 2, float, 2.1);
TEST(int32_t, 2, float, 2.5);
TEST(int32_t, 2, float, 2.7);
TEST(int32_t, -2, float, -2.1);
TEST(int32_t, -2, float, -2.5);
TEST(int32_t, -2, float, -2.7);
testDiag("String Printing/parsing");
TEST2(String, "1", int32_t, 1);
TEST2(String, "-1", int32_t, -1);
TEST2(String, "1", int8_t, 1);
TEST2(String, "-1", int8_t, -1);
TEST2(String, "1", uint8_t, 1);
TEST2(String, "-1", char, -1);
TEST2(String, "127", int32_t, std::numeric_limits<int8_t>::max());
TEST2(String, "-128", int32_t, std::numeric_limits<int8_t>::min());
TEST2(String, "255", int32_t, std::numeric_limits<uint8_t>::max());
TEST2(String, "32767", int32_t, std::numeric_limits<int16_t>::max());
TEST2(String, "-32768", int32_t, std::numeric_limits<int16_t>::min());
TEST2(String, "65535", int32_t, std::numeric_limits<uint16_t>::max());
TEST2(String, "2147483647", int32_t, std::numeric_limits<int32_t>::max());
TEST2(String, "-2147483648", int32_t, std::numeric_limits<int32_t>::min());
TEST2(String, "4294967295", uint32_t, std::numeric_limits<uint32_t>::max());
TEST2(String, "9223372036854775807", int64_t, std::numeric_limits<int64_t>::max());
TEST2(String, "-9223372036854775808", int64_t, std::numeric_limits<int64_t>::min());
TEST2(String, "18446744073709551615", uint64_t, std::numeric_limits<uint64_t>::max());
TEST2(String, "1.1", double, 1.1);
TEST2(String, "1.1e+100", double, 1.1e100);
TEST2(String, "1.1e-100", double, 1.1e-100);
TEST(double, 1.1e100, String, "1.1E+100");
testDiag("String Parsing");
TEST(int32_t, 15, String, "0xf");
TEST(int32_t, 15, String, "0xF");
TEST(int32_t, -15, String, "-0xF");
TEST(int32_t, 16, String, "0x10");
TEST(int32_t, -16, String, "-0x10");
TEST(int32_t, 7, String, "07");
TEST(int32_t, 8, String, "010");
TEST(int32_t, -7, String, "-07");
TEST(int32_t, -8, String, "-010");
TEST(int64_t, 15, String, "0xf");
TEST(int64_t, 15, String, "0xF");
TEST(int64_t, -15, String, "-0xF");
TEST(int64_t, 16, String, "0x10");
TEST(int64_t, -16, String, "-0x10");
TEST(int64_t, 7, String, "07");
TEST(int64_t, 8, String, "010");
TEST(int64_t, -7, String, "-07");
TEST(int64_t, -8, String, "-010");
testDiag("String parsing errors");
FAIL(int32_t, String, "hello!");
FAIL(int32_t, String, "42 is the answer");
FAIL(int64_t, String, "hello!");
FAIL(int64_t, String, "42 is the answer");
FAIL(double, String, "hello!");
FAIL(double, String, "42 is the answer");
FAIL(int8_t, String, "1000");
FAIL(int8_t, String, "-1000");
;
FAIL(double, String, "1e+10000000");
testDiag("Floating point overflows");
TEST(float, FLT_MAX, double, 1e300);
TEST(float, -FLT_MAX, double, -1e300);
TEST(float, FLT_MIN, double, 1e-300);
TEST(float, -FLT_MIN, double, -1e-300);
xfloat = ::epics::pvData::castUnsafe<float,double>(epicsNAN);
testOk(isnan( xfloat ), "Test cast double NAN to float NAN yields: %f", xfloat);
{
std::string result[3];
const int32_t in[3] = { 1234, 506001, 42424242 };
testDiag("Test vcast int32 -> String");
epics::pvData::castUnsafeV(3, epics::pvData::pvString, (void*)result,
epics::pvData::pvInt, (void*)in);
testDiag("Yields %s %s %s", result[0].c_str(), result[1].c_str(), result[2].c_str());
testOk1(result[0]=="1234");
testOk1(result[1]=="506001");
testOk1(result[2]=="42424242");
}
} catch(std::exception& e) {
testAbort("Uncaught exception: %s", e.what());
}
return testDone();
}

View File

@@ -229,11 +229,11 @@ static void testEnumerated(FILE * fd,FILE */*auxfd*/)
assert(result);
int32 index = pvEnumerated.getIndex();
String choice = pvEnumerated.getChoice();
StringArrayPtr const & choices = pvEnumerated.getChoices();
PVStringArray::const_svector choices = pvEnumerated.getChoices();
int32 numChoices = pvEnumerated.getNumberChoices();
if(debug) {
fprintf(fd,"index %d choice %s choices",index,choice.c_str());
for(int i=0; i<numChoices; i++ ) fprintf(fd," %s",(*choices)[i].c_str());
for(int i=0; i<numChoices; i++ ) fprintf(fd," %s",choices[i].c_str());
fprintf(fd,"\n");
}
pvEnumerated.setIndex(2);

View File

@@ -9,6 +9,7 @@ testBitSetUtil_LIBS += pvData Com
PROD_HOST += testIntrospect
testIntrospect_SRCS += testIntrospect.cpp
testIntrospect_LIBS += pvData Com
TESTS += testIntrospect
PROD_HOST += testPVAppend
testPVAppend_SRCS += testPVAppend.cpp
@@ -38,18 +39,22 @@ PROD_HOST += testConvert
testConvert_SRCS += testConvert.cpp
testConvert_LIBS += pvData Com
PROD_HOST += testPVScalarArray
TESTPROD += testPVScalarArray
testPVScalarArray_SRCS += testPVScalarArray.cpp
testPVScalarArray_LIBS += pvData Com
TESTS += testPVScalarArray
PROD_HOST += testPVStructureArray
testPVStructureArray_SRCS += testPVStructureArray.cpp
testPVStructureArray_LIBS += pvData Com
TESTS += testPVStructureArray
PROD_HOST += testOperators
testOperators_SRCS += testOperators.cpp
testOperators_LIBS += pvData Com
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE

View File

@@ -14,6 +14,8 @@
#include <epicsAssert.h>
#include <epicsExit.h>
#include <epicsUnitTest.h>
#include <testMain.h>
#include <pv/requester.h>
#include <pv/pvIntrospect.h>
@@ -23,750 +25,42 @@
#include <pv/standardPVField.h>
using namespace epics::pvData;
using std::tr1::static_pointer_cast;
static bool debug = false;
static FieldCreatePtr fieldCreate;
static PVDataCreatePtr pvDataCreate;
static StandardFieldPtr standardField;
static StandardPVFieldPtr standardPVField;
static ConvertPtr convert;
static String builder("");
static void testConvertScalar(FILE *fd) {
PVScalarPtr pvBytePtr = pvDataCreate->createPVScalar(pvByte);
PVScalarPtr pvUBytePtr = pvDataCreate->createPVScalar(pvUByte);
PVScalarPtr pvShortPtr = pvDataCreate->createPVScalar(pvShort);
PVScalarPtr pvUShortPtr = pvDataCreate->createPVScalar(pvUShort);
PVScalarPtr pvIntPtr = pvDataCreate->createPVScalar(pvInt);
PVScalarPtr pvUIntPtr = pvDataCreate->createPVScalar(pvUInt);
PVScalarPtr pvLongPtr = pvDataCreate->createPVScalar(pvLong);
PVScalarPtr pvULongPtr = pvDataCreate->createPVScalar(pvULong);
PVScalarPtr pvFloatPtr = pvDataCreate->createPVScalar(pvFloat);
PVScalarPtr pvDoublePtr = pvDataCreate->createPVScalar(pvDouble);
fprintf(fd,"testConvertScalar\n");
if(debug) fprintf(fd,"\nfromByte\n");
int8 bval = 127;
for(int i=0; i<3; i++) {
convert->fromByte(pvBytePtr, bval);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromByte(pvUBytePtr, bval);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromByte(pvShortPtr, bval);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromByte(pvUShortPtr, bval);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromByte(pvIntPtr, bval);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromByte(pvUIntPtr, bval);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromByte(pvLongPtr, bval);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromByte(pvULongPtr, bval);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromByte(pvFloatPtr, bval);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromByte(pvDoublePtr, bval);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalar(pvUBytePtr, pvFloatPtr);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalar(pvUBytePtr, pvDoublePtr);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
bval++;
}
fprintf(fd,"fromByte PASSED\n");
if(debug) fprintf(fd,"\nfromShort\n");
int16 sval = 0x7fff;
for(int i=0; i<3; i++) {
convert->fromShort(pvBytePtr, sval);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromShort(pvUBytePtr, sval);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromShort(pvShortPtr, sval);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromShort(pvUShortPtr, sval);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromShort(pvIntPtr, sval);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromShort(pvUIntPtr, sval);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromShort(pvLongPtr, sval);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromShort(pvULongPtr, sval);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromShort(pvFloatPtr, sval);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromShort(pvDoublePtr, sval);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalar(pvUShortPtr, pvFloatPtr);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalar(pvUShortPtr, pvDoublePtr);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
sval++;
}
fprintf(fd,"fromShort PASSED\n");
if(debug) fprintf(fd,"\nfromInt\n");
int32 ival = 0x7fffffff;
for(int i=0; i<3; i++) {
convert->fromInt(pvBytePtr, ival);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromInt(pvUBytePtr, ival);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromInt(pvShortPtr, ival);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromInt(pvUShortPtr, ival);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromInt(pvIntPtr, ival);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromInt(pvUIntPtr, ival);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromInt(pvLongPtr, ival);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromInt(pvULongPtr, ival);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromInt(pvFloatPtr, ival);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromInt(pvDoublePtr, ival);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalar(pvUIntPtr, pvFloatPtr);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalar(pvUIntPtr, pvDoublePtr);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
ival++;
}
fprintf(fd,"fromInt PASSED\n");
if(debug) fprintf(fd,"\nfromLong\n");
int64 lval = 0x7fffffffffffffffLL;
for(int i=0; i<3; i++) {
convert->fromLong(pvBytePtr, lval);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromLong(pvUBytePtr, lval);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromLong(pvShortPtr, lval);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromLong(pvUShortPtr, lval);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromLong(pvIntPtr, lval);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromLong(pvUIntPtr, lval);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromLong(pvLongPtr, lval);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromLong(pvULongPtr, lval);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromLong(pvFloatPtr, lval);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromLong(pvDoublePtr, lval);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalar(pvULongPtr, pvFloatPtr);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalar(pvULongPtr, pvDoublePtr);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
lval++;
}
fprintf(fd,"fromLong PASSED\n");
if(debug) fprintf(fd,"\nfromUByte\n");
uint8 ubval = 127;
for(int i=0; i<3; i++) {
convert->fromUByte(pvBytePtr, ubval);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromUByte(pvUBytePtr, ubval);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromUByte(pvShortPtr, ubval);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromUByte(pvUShortPtr, ubval);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromUByte(pvIntPtr, ubval);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromUByte(pvUIntPtr, ubval);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromUByte(pvLongPtr, ubval);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromUByte(pvULongPtr, ubval);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromUByte(pvFloatPtr, ubval);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromUByte(pvDoublePtr, ubval);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalar(pvUBytePtr, pvFloatPtr);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalar(pvUBytePtr, pvDoublePtr);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
ubval++;
}
fprintf(fd,"fromUByte PASSED\n");
if(debug) fprintf(fd,"\nfromUShort\n");
uint16 usval = 0x7fff;
for(int i=0; i<3; i++) {
convert->fromUShort(pvBytePtr, usval);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromUShort(pvUBytePtr, usval);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromUShort(pvShortPtr, usval);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromUShort(pvUShortPtr, usval);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromUShort(pvIntPtr, usval);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromUShort(pvUIntPtr, usval);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromUShort(pvLongPtr, usval);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromUShort(pvULongPtr, usval);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromUShort(pvFloatPtr, usval);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromUShort(pvDoublePtr, usval);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalar(pvUShortPtr, pvFloatPtr);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalar(pvUShortPtr, pvDoublePtr);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
usval++;
}
fprintf(fd,"fromUShort PASSED\n");
if(debug) fprintf(fd,"\nfromUInt\n");
uint32 uival = 0x7fffffff;
for(int i=0; i<3; i++) {
convert->fromUInt(pvBytePtr, uival);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromUInt(pvUBytePtr, uival);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromUInt(pvShortPtr, uival);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromUInt(pvUShortPtr, uival);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromUInt(pvIntPtr, uival);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromUInt(pvUIntPtr, uival);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromUInt(pvLongPtr, uival);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromUInt(pvULongPtr, uival);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromUInt(pvFloatPtr, uival);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromUInt(pvDoublePtr, uival);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalar(pvUIntPtr, pvFloatPtr);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalar(pvUIntPtr, pvDoublePtr);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
uival++;
}
fprintf(fd,"fromUInt PASSED\n");
if(debug) fprintf(fd,"\nfromULong\n");
uint64 ulval = 0x7fffffffffffffffLL;
for(int i=0; i<3; i++) {
convert->fromULong(pvBytePtr, ulval);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromULong(pvUBytePtr, ulval);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromULong(pvShortPtr, ulval);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromULong(pvUShortPtr, ulval);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromULong(pvIntPtr, ulval);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromULong(pvUIntPtr, ulval);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromULong(pvLongPtr, ulval);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromULong(pvULongPtr, ulval);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromULong(pvFloatPtr, ulval);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromULong(pvDoublePtr, ulval);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalar(pvULongPtr, pvFloatPtr);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalar(pvULongPtr, pvDoublePtr);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
ulval++;
}
fprintf(fd,"fromULong PASSED\n");
}
static void testConvertScalarArray(FILE *fd) {
PVScalarArrayPtr pvBytePtr = pvDataCreate->createPVScalarArray(pvByte);
PVScalarArrayPtr pvUBytePtr = pvDataCreate->createPVScalarArray(pvUByte);
PVScalarArrayPtr pvShortPtr = pvDataCreate->createPVScalarArray(pvShort);
PVScalarArrayPtr pvUShortPtr = pvDataCreate->createPVScalarArray(pvUShort);
PVScalarArrayPtr pvIntPtr = pvDataCreate->createPVScalarArray(pvInt);
PVScalarArrayPtr pvUIntPtr = pvDataCreate->createPVScalarArray(pvUInt);
PVScalarArrayPtr pvLongPtr = pvDataCreate->createPVScalarArray(pvLong);
PVScalarArrayPtr pvULongPtr = pvDataCreate->createPVScalarArray(pvULong);
PVScalarArrayPtr pvFloatPtr = pvDataCreate->createPVScalarArray(pvFloat);
PVScalarArrayPtr pvDoublePtr = pvDataCreate->createPVScalarArray(pvDouble);
fprintf(fd,"testConvertScalarArray\n");
if(debug) fprintf(fd,"\nfromByte\n");
size_t length = 4;
int8 barray[length];
int8 bval = 127;
barray[0] = bval;
for(size_t i=1; i<length; i++) barray[i] = barray[i-1] + 1;
convert->fromByteArray(pvBytePtr,0,length,barray,0);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromByteArray(pvUBytePtr,0,length,barray,0);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromByteArray(pvShortPtr,0,length,barray,0);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromByteArray(pvUShortPtr,0,length,barray,0);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromByteArray(pvIntPtr,0,length,barray,0);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromByteArray(pvUIntPtr,0,length,barray,0);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromByteArray(pvLongPtr,0,length,barray,0);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromByteArray(pvULongPtr,0,length,barray,0);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromByteArray(pvFloatPtr,0,length,barray,0);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromByteArray(pvDoublePtr,0,length,barray,0);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalarArray(pvUBytePtr,0, pvFloatPtr,0,length);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalarArray(pvUBytePtr,0, pvDoublePtr,0,length);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
fprintf(fd,"fromByte PASSED\n");
if(debug) fprintf(fd,"\nfromShort\n");
int16 sarray[length];
int16 sval = 0x7fff;
sarray[0] = sval;
for(size_t i=1; i<length; i++) sarray[i] = sarray[i-1] + 1;
convert->fromShortArray(pvBytePtr,0,length,sarray,0);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromShortArray(pvUBytePtr,0,length,sarray,0);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromShortArray(pvShortPtr,0,length,sarray,0);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromShortArray(pvUShortPtr,0,length,sarray,0);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromShortArray(pvIntPtr,0,length,sarray,0);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromShortArray(pvUIntPtr,0,length,sarray,0);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromShortArray(pvLongPtr,0,length,sarray,0);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromShortArray(pvULongPtr,0,length,sarray,0);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromShortArray(pvFloatPtr,0,length,sarray,0);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromShortArray(pvDoublePtr,0,length,sarray,0);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalarArray(pvUShortPtr,0, pvFloatPtr,0,length);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalarArray(pvUShortPtr,0, pvDoublePtr,0,length);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
fprintf(fd,"fromShort PASSED\n");
if(debug) fprintf(fd,"\nfromInt\n");
int32 iarray[length];
int32 ival = 0x7fffffff;
iarray[0] = ival;
for(size_t i=1; i<length; i++) iarray[i] = iarray[i-1] + 1;
convert->fromIntArray(pvBytePtr,0,length,iarray,0);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromIntArray(pvUBytePtr,0,length,iarray,0);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromIntArray(pvShortPtr,0,length,iarray,0);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromIntArray(pvUShortPtr,0,length,iarray,0);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromIntArray(pvIntPtr,0,length,iarray,0);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromIntArray(pvUIntPtr,0,length,iarray,0);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromIntArray(pvLongPtr,0,length,iarray,0);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromIntArray(pvULongPtr,0,length,iarray,0);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromIntArray(pvFloatPtr,0,length,iarray,0);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromIntArray(pvDoublePtr,0,length,iarray,0);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalarArray(pvUIntPtr,0, pvFloatPtr,0,length);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalarArray(pvUIntPtr,0, pvDoublePtr,0,length);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
fprintf(fd,"fromInt PASSED\n");
if(debug) fprintf(fd,"\nfromLong\n");
int64 larray[length];
int64 lval = 0x7fffffffffffffffLL;
larray[0] = lval;
for(size_t i=1; i<length; i++) larray[i] = larray[i-1] + 1;
convert->fromLongArray(pvBytePtr,0,length,larray,0);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromLongArray(pvUBytePtr,0,length,larray,0);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromLongArray(pvShortPtr,0,length,larray,0);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromLongArray(pvUShortPtr,0,length,larray,0);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromLongArray(pvIntPtr,0,length,larray,0);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromLongArray(pvUIntPtr,0,length,larray,0);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromLongArray(pvLongPtr,0,length,larray,0);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromLongArray(pvULongPtr,0,length,larray,0);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromLongArray(pvFloatPtr,0,length,larray,0);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromLongArray(pvDoublePtr,0,length,larray,0);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalarArray(pvULongPtr,0, pvFloatPtr,0,length);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalarArray(pvULongPtr,0, pvDoublePtr,0,length);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
fprintf(fd,"fromLong PASSED\n");
if(debug) fprintf(fd,"\nfromUByte\n");
uint8 ubarray[length];
uint8 ubval = 127;
ubarray[0] = ubval;
for(size_t i=1; i<length; i++) ubarray[i] = ubarray[i-1] + 1;
convert->fromUByteArray(pvBytePtr,0,length,ubarray,0);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromUByteArray(pvUBytePtr,0,length,ubarray,0);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromUByteArray(pvShortPtr,0,length,ubarray,0);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromUByteArray(pvUShortPtr,0,length,ubarray,0);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromUByteArray(pvIntPtr,0,length,ubarray,0);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromUByteArray(pvUIntPtr,0,length,ubarray,0);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromUByteArray(pvLongPtr,0,length,ubarray,0);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromUByteArray(pvULongPtr,0,length,ubarray,0);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromUByteArray(pvFloatPtr,0,length,ubarray,0);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromUByteArray(pvDoublePtr,0,length,ubarray,0);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalarArray(pvUBytePtr,0, pvFloatPtr,0,length);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalarArray(pvUBytePtr,0, pvDoublePtr,0,length);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
fprintf(fd,"fromUByte PASSED\n");
if(debug) fprintf(fd,"\nfromUShort\n");
uint16 usarray[length];
uint16 usval = 0x7fff;
usarray[0] = usval;
for(size_t i=1; i<length; i++) usarray[i] = usarray[i-1] + 1;
convert->fromUShortArray(pvBytePtr,0,length,usarray,0);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromUShortArray(pvUBytePtr,0,length,usarray,0);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromUShortArray(pvShortPtr,0,length,usarray,0);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromUShortArray(pvUShortPtr,0,length,usarray,0);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromUShortArray(pvIntPtr,0,length,usarray,0);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromUShortArray(pvUIntPtr,0,length,usarray,0);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromUShortArray(pvLongPtr,0,length,usarray,0);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromUShortArray(pvULongPtr,0,length,usarray,0);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromUShortArray(pvFloatPtr,0,length,usarray,0);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromUShortArray(pvDoublePtr,0,length,usarray,0);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalarArray(pvUShortPtr,0, pvFloatPtr,0,length);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalarArray(pvUShortPtr,0, pvDoublePtr,0,length);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
fprintf(fd,"fromUShort PASSED\n");
if(debug) fprintf(fd,"\nfromUInt\n");
uint32 uiarray[length];
uint32 uival = 0x7fffffff;
uiarray[0] = uival;
for(size_t i=1; i<length; i++) uiarray[i] = uiarray[i-1] + 1;
convert->fromUIntArray(pvBytePtr,0,length,uiarray,0);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromUIntArray(pvUBytePtr,0,length,uiarray,0);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromUIntArray(pvShortPtr,0,length,uiarray,0);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromUIntArray(pvUShortPtr,0,length,uiarray,0);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromUIntArray(pvIntPtr,0,length,uiarray,0);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromUIntArray(pvUIntPtr,0,length,uiarray,0);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromUIntArray(pvLongPtr,0,length,uiarray,0);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromUIntArray(pvULongPtr,0,length,uiarray,0);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromUIntArray(pvFloatPtr,0,length,uiarray,0);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromUIntArray(pvDoublePtr,0,length,uiarray,0);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalarArray(pvUIntPtr,0, pvFloatPtr,0,length);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalarArray(pvUIntPtr,0, pvDoublePtr,0,length);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
fprintf(fd,"fromUInt PASSED\n");
if(debug) fprintf(fd,"\nfromULong\n");
uint64 ularray[length];
uint64 ulval = 0x7fffffffffffffffLL;
ularray[0] = ulval;
for(size_t i=1; i<length; i++) ularray[i] = ularray[i-1] + 1;
convert->fromULongArray(pvBytePtr,0,length,ularray,0);
builder.clear(); pvBytePtr->toString(&builder);
if(debug) fprintf(fd,"byte %s\n",builder.c_str());
convert->fromULongArray(pvUBytePtr,0,length,ularray,0);
builder.clear(); pvUBytePtr->toString(&builder);
if(debug) fprintf(fd,"ubyte %s\n",builder.c_str());
convert->fromULongArray(pvShortPtr,0,length,ularray,0);
builder.clear(); pvShortPtr->toString(&builder);
if(debug) fprintf(fd,"short %s\n",builder.c_str());
convert->fromULongArray(pvUShortPtr,0,length,ularray,0);
builder.clear(); pvUShortPtr->toString(&builder);
if(debug) fprintf(fd,"ushort %s\n",builder.c_str());
convert->fromULongArray(pvIntPtr,0,length,ularray,0);
builder.clear(); pvIntPtr->toString(&builder);
if(debug) fprintf(fd,"int %s\n",builder.c_str());
convert->fromULongArray(pvUIntPtr,0,length,ularray,0);
builder.clear(); pvUIntPtr->toString(&builder);
if(debug) fprintf(fd,"uint %s\n",builder.c_str());
convert->fromULongArray(pvLongPtr,0,length,ularray,0);
builder.clear(); pvLongPtr->toString(&builder);
if(debug) fprintf(fd,"long %s\n",builder.c_str());
convert->fromULongArray(pvULongPtr,0,length,ularray,0);
builder.clear(); pvULongPtr->toString(&builder);
if(debug) fprintf(fd,"ulong %s\n",builder.c_str());
convert->fromULongArray(pvFloatPtr,0,length,ularray,0);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float %s\n",builder.c_str());
convert->fromULongArray(pvDoublePtr,0,length,ularray,0);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double %s\n",builder.c_str());
convert->copyScalarArray(pvULongPtr,0, pvFloatPtr,0,length);
builder.clear(); pvFloatPtr->toString(&builder);
if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str());
convert->copyScalarArray(pvULongPtr,0, pvDoublePtr,0,length);
builder.clear(); pvDoublePtr->toString(&builder);
if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str());
fprintf(fd,"fromLong PASSED\n");
}
int main(int argc,char *argv[])
static void testFromString()
{
char *fileName = 0;
if(argc>1) fileName = argv[1];
FILE * fd = stdout;
if(fileName!=0 && fileName[0]!=0) {
fd = fopen(fileName,"w+");
}
fieldCreate = getFieldCreate();
pvDataCreate = getPVDataCreate();
standardField = getStandardField();
standardPVField = getStandardPVField();
convert = getConvert();
testConvertScalar(fd);
testConvertScalarArray(fd);
fprintf(fd,"THIS NEEDS MANY MORE TESTS AND ASSERTS\n");
return(0);
StringArray inp(2);
inp[0] = "0";
inp[1] = "1";
PVScalarArrayPtr A(getPVDataCreate()->createPVScalarArray(pvInt));
PVScalarArrayPtr B(getPVDataCreate()->createPVScalarArray(pvString));
testOk1(2==getConvert()->fromStringArray(A, 0, inp.size(), inp, 0));
testOk1(2==getConvert()->fromStringArray(B, 0, inp.size(), inp, 0));
PVIntArrayPtr Ax(std::tr1::static_pointer_cast<PVIntArray>(A));
PVStringArrayPtr Bx(std::tr1::static_pointer_cast<PVStringArray>(B));
PVIntArray::const_svector Adata(Ax->view());
PVStringArray::const_svector Bdata(Bx->view());
testOk1(inp.size()==Adata.size());
if(inp.size()==Adata.size())
testOk1(Adata[0]==0 && Adata[1]==1);
else
testFail("Can't compare");
testOk1(inp.size()==Bdata.size());
if(inp.size()==Bdata.size())
testOk1(Bdata[0]=="0" && Bdata[1]=="1");
else
testFail("Can't compare");
}
MAIN(testConvert)
{
testPlan(0);
testFromString();
return testDone();
}

View File

@@ -12,8 +12,8 @@
#include <string>
#include <cstdio>
#include <epicsAssert.h>
#include <epicsExit.h>
#include <epicsUnitTest.h>
#include <testMain.h>
#include <pv/requester.h>
#include <pv/executor.h>
@@ -23,130 +23,190 @@
using namespace epics::pvData;
static bool debug = false;
static FieldCreatePtr fieldCreate;
static PVDataCreatePtr pvDataCreate;
static StandardFieldPtr standardField;
static String builder("");
static void testScalarCommon(FILE * fd,ScalarType stype,
static void testScalarCommon(ScalarType stype,
bool isInteger,bool isNumeric,bool isPrimitive)
{
String builder;
ScalarConstPtr pscalar = fieldCreate->createScalar(stype);
Type type = pscalar->getType();
assert(type==scalar);
testOk1(type==scalar);
builder.clear();
TypeFunc::toString(&builder,type);
assert(builder.compare("scalar")==0);
testOk1(builder.compare("scalar")==0);
ScalarType scalarType = pscalar->getScalarType();
assert(scalarType==stype);
assert(ScalarTypeFunc::isInteger(scalarType)==isInteger);
assert(ScalarTypeFunc::isNumeric(scalarType)==isNumeric);
assert(ScalarTypeFunc::isPrimitive(scalarType)==isPrimitive);
builder.clear();
pscalar->toString(&builder);
if(debug) fprintf(fd,"%s\n",builder.c_str());
testOk1(scalarType==stype);
testOk1(ScalarTypeFunc::isInteger(scalarType)==isInteger);
testOk1(ScalarTypeFunc::isNumeric(scalarType)==isNumeric);
testOk1(ScalarTypeFunc::isPrimitive(scalarType)==isPrimitive);
}
static void testScalar(FILE * fd) {
if(debug) fprintf(fd,"\ntestScalar\n");
testScalarCommon(fd,pvBoolean,false,false,true);
testScalarCommon(fd,pvByte,true,true,true);
testScalarCommon(fd,pvShort,true,true,true);
testScalarCommon(fd,pvInt,true,true,true);
testScalarCommon(fd,pvLong,true,true,true);
testScalarCommon(fd,pvFloat,false,true,true);
testScalarCommon(fd,pvDouble,false,true,true);
testScalarCommon(fd,pvString,false,false,false);
fprintf(fd,"testScalar PASSED\n");
static void testScalar() {
testDiag("testScalar");
testScalarCommon(pvBoolean,false,false,true);
testScalarCommon(pvByte,true,true,true);
testScalarCommon(pvShort,true,true,true);
testScalarCommon(pvInt,true,true,true);
testScalarCommon(pvLong,true,true,true);
testScalarCommon(pvFloat,false,true,true);
testScalarCommon(pvDouble,false,true,true);
testScalarCommon(pvString,false,false,false);
}
static void testScalarArrayCommon(FILE * fd,ScalarType stype,
static void testScalarArrayCommon(ScalarType stype,
bool isInteger,bool isNumeric,bool isPrimitive)
{
String builder;
ScalarArrayConstPtr pscalar = fieldCreate->createScalarArray(stype);
Type type = pscalar->getType();
assert(type==scalarArray);
testOk1(type==scalarArray);
builder.clear();
TypeFunc::toString(&builder,type);
assert(builder.compare("scalarArray")==0);
testOk1(builder.compare("scalarArray")==0);
ScalarType scalarType = pscalar->getElementType();
assert(scalarType==stype);
assert(ScalarTypeFunc::isInteger(scalarType)==isInteger);
assert(ScalarTypeFunc::isNumeric(scalarType)==isNumeric);
assert(ScalarTypeFunc::isPrimitive(scalarType)==isPrimitive);
builder.clear();
pscalar->toString(&builder);
if(debug) fprintf(fd,"%s\n",builder.c_str());
testOk1(scalarType==stype);
testOk1(ScalarTypeFunc::isInteger(scalarType)==isInteger);
testOk1(ScalarTypeFunc::isNumeric(scalarType)==isNumeric);
testOk1(ScalarTypeFunc::isPrimitive(scalarType)==isPrimitive);
}
static void testScalarArray(FILE * fd) {
if(debug) fprintf(fd,"\ntestScalarArray\n");
testScalarArrayCommon(fd,pvBoolean,false,false,true);
testScalarArrayCommon(fd,pvByte,true,true,true);
testScalarArrayCommon(fd,pvShort,true,true,true);
testScalarArrayCommon(fd,pvInt,true,true,true);
testScalarArrayCommon(fd,pvLong,true,true,true);
testScalarArrayCommon(fd,pvFloat,false,true,true);
testScalarArrayCommon(fd,pvDouble,false,true,true);
testScalarArrayCommon(fd,pvString,false,false,false);
fprintf(fd,"testScalarArray PASSED\n");
static void testScalarArray() {
testDiag("testScalarArray");
testScalarArrayCommon(pvBoolean,false,false,true);
testScalarArrayCommon(pvByte,true,true,true);
testScalarArrayCommon(pvShort,true,true,true);
testScalarArrayCommon(pvInt,true,true,true);
testScalarArrayCommon(pvLong,true,true,true);
testScalarArrayCommon(pvFloat,false,true,true);
testScalarArrayCommon(pvDouble,false,true,true);
testScalarArrayCommon(pvString,false,false,false);
}
static void testSimpleStructure(FILE * fd) {
if(debug) fprintf(fd,"\ntestSimpleStructure\n");
String properties("alarm,timeStamp,display,control,valueAlarm");
StructureConstPtr ptop = standardField->scalar(pvDouble,properties);
builder.clear();
ptop->toString(&builder);
if(debug) fprintf(fd,"%s\n",builder.c_str());
fprintf(fd,"testSimpleStructure PASSED\n");
}
static StructureConstPtr createPowerSupply() {
size_t nfields = 3;
String properties("alarm");
StringArray names;
names.reserve(nfields);
FieldConstPtrArray powerSupply;
powerSupply.reserve(nfields);
names.push_back("voltage");
powerSupply.push_back(standardField->scalar(pvDouble,properties));
names.push_back("power");
powerSupply.push_back(standardField->scalar(pvDouble,properties));
names.push_back("current");
powerSupply.push_back(standardField->scalar(pvDouble,properties));
return fieldCreate->createStructure(names,powerSupply);
}
static void testStructureArray(FILE * fd) {
if(debug) fprintf(fd,"\ntestStructureArray\n");
String properties("alarm,timeStamp");
StructureConstPtr powerSupply = createPowerSupply();
StructureConstPtr top = standardField->structureArray(
powerSupply,properties);
builder.clear();
top->toString(&builder);
if(debug) fprintf(fd,"%s\n",builder.c_str());
fprintf(fd,"testStructureArray PASSED\n");
}
int main(int argc,char *argv[])
static void testStructure()
{
char *fileName = 0;
if(argc>1) fileName = argv[1];
FILE * fd = stdout;
if(fileName!=0 && fileName[0]!=0) {
fd = fopen(fileName,"w+");
}
testDiag("testStructure");
StringArray names1(2);
names1[0] = "innerA";
names1[1] = "innerB";
FieldConstPtrArray fields1(2);
fields1[0] = fieldCreate->createScalar(pvDouble);
fields1[1] = fieldCreate->createScalarArray(pvString);
StructureConstPtr struct1 = fieldCreate->createStructure(names1, fields1);
testOk1(struct1->getNumberFields()==2);
testOk1(struct1->getField("innerA")==fields1[0]);
testOk1(struct1->getField("innerB")==fields1[1]);
testOk1(struct1->getFieldIndex("innerA")==0);
testOk1(struct1->getFieldIndex("innerB")==1);
testOk1(struct1->getField(0)==fields1[0]);
testOk1(struct1->getField(1)==fields1[1]);
testOk1(struct1->getFieldName(0)==names1[0]);
testOk1(struct1->getFieldName(1)==names1[1]);
testOk1(struct1->getID() == Structure::DEFAULT_ID);
testOk1(fields1 == struct1->getFields()); // vector equality
StringArray names2(2);
names2[0] = "outerA";
names2[1] = "outerB";
FieldConstPtrArray fields2(2);
fields2[0] = fieldCreate->createScalar(pvInt);
fields2[1] = std::tr1::static_pointer_cast<const Field>(struct1);
StructureConstPtr struct2 = fieldCreate->createStructure(names2, fields2);
testOk1(struct2->getNumberFields()==2); // not recursive
testOk1(struct2->getField(1)==fields2[1]);
StructureArrayConstPtr struct1arr = fieldCreate->createStructureArray(struct1);
testOk1(struct1arr->getStructure()==struct1);
testOk1(struct1arr->getID()=="structure[]");
}
#define testExcept(EXCEPT, CMD) try{ CMD; testFail( "No exception from: " #CMD); } \
catch(EXCEPT& e) {testPass("Got expected exception from: " #CMD);} \
catch(std::exception& e) {testFail("Got wrong exception %s(%s) from: " #CMD, typeid(e).name(),e.what());} \
catch(...) {testFail("Got unknown execption from: " #CMD);}
static void testError()
{
testDiag("testError");
ScalarType invalidtype = (ScalarType)9999;
testExcept(std::invalid_argument, ScalarTypeFunc::getScalarType("invalidtype"));
testExcept(std::invalid_argument, ScalarTypeFunc::elementSize(invalidtype));
testExcept(std::invalid_argument, ScalarTypeFunc::name(invalidtype));
testOk1(!ScalarTypeFunc::isInteger(invalidtype));
testOk1(!ScalarTypeFunc::isUInteger(invalidtype));
testOk1(!ScalarTypeFunc::isNumeric(invalidtype));
testOk1(!ScalarTypeFunc::isPrimitive(invalidtype));
testExcept(std::invalid_argument, fieldCreate->createScalar(invalidtype));
testExcept(std::invalid_argument, fieldCreate->createScalarArray(invalidtype));
StringArray names;
FieldConstPtrArray fields(1);
// fails because names.size()!=fields.size()
testExcept(std::invalid_argument, fieldCreate->createStructure(names,fields));
names.resize(1);;
// fails because names[0].size()==0
testExcept(std::invalid_argument, fieldCreate->createStructure(names,fields));
names[0] = "hello";
// fails because fields[0].get()==NULL
testExcept(std::invalid_argument, fieldCreate->createStructure(names,fields));
fields[0] = std::tr1::static_pointer_cast<const Field>(fieldCreate->createScalar(pvDouble));
testOk1(fieldCreate->createStructure(names,fields).get()!=NULL);
}
static void testMapping()
{
#define OP(TYPE, ENUM) \
testOk1(typeid(ScalarTypeTraits<ENUM>::type)==typeid(TYPE)); \
testOk1(ENUM==(ScalarType)ScalarTypeID<TYPE>::value); \
testOk1(ENUM==(ScalarType)ScalarTypeID<const TYPE>::value);
OP(boolean, pvBoolean)
OP(int8, pvByte)
OP(int16, pvShort)
OP(int32, pvInt)
OP(int64, pvLong)
OP(uint8, pvUByte)
OP(uint16, pvUShort)
OP(uint32, pvUInt)
OP(uint64, pvULong)
OP(float, pvFloat)
OP(double, pvDouble)
OP(String, pvString)
#undef OP
testOk1((ScalarType)ScalarTypeID<PVField>::value==(ScalarType)-1);
}
MAIN(testIntrospect)
{
testPlan(161);
fieldCreate = getFieldCreate();
pvDataCreate = getPVDataCreate();
standardField = getStandardField();
testScalar(fd);
testScalarArray(fd);
testSimpleStructure(fd);
testStructureArray(fd);
return(0);
testScalar();
testScalarArray();
testStructure();
testError();
testMapping();
return testDone();
}

View File

@@ -66,9 +66,10 @@ int main(int, char **)
pvStructure = standardPVField->scalarArray(pvDouble,"alarm,timeStamp");
std::cout << *pvStructure << std::endl;
double values[] = { 1.1, 2.2, 3.3 };
PVDoubleArray::svector values(3);
values[0] = 1.1; values[1] = 2.2; values[2] = 3.3;
PVDoubleArrayPtr darray = std::tr1::dynamic_pointer_cast<PVDoubleArray>(pvStructure->getScalarArrayField("value", pvDouble));
darray->put(0, 3, values, 0);
darray->replace(freeze(values));
std::cout << *darray << std::endl;
std::cout << format::array_at(1) << *darray << std::endl;
@@ -76,14 +77,13 @@ int main(int, char **)
StructureConstPtr structure = standardField->scalar(pvDouble, "alarm,timeStamp");
pvStructure = standardPVField->structureArray(structure,"alarm,timeStamp");
size_t num = 2;
PVStructurePtrArray pvStructures;
pvStructures.reserve(num);
PVStructureArray::svector pvStructures(num);
for(size_t i=0; i<num; i++) {
pvStructures.push_back(
pvDataCreate->createPVStructure(structure));
pvStructures[i]=
pvDataCreate->createPVStructure(structure);
}
PVStructureArrayPtr pvStructureArray = pvStructure->getStructureArrayField("value");
pvStructureArray->put(0, num, pvStructures, 0);
pvStructureArray->replace(freeze(pvStructures));
std::cout << *pvStructure << std::endl;
return 0;

View File

@@ -14,6 +14,8 @@
#include <epicsAssert.h>
#include <epicsExit.h>
#include <epicsUnitTest.h>
#include <testMain.h>
#include <pv/requester.h>
#include <pv/pvIntrospect.h>
@@ -25,352 +27,165 @@
using namespace epics::pvData;
using std::tr1::static_pointer_cast;
static bool debug = false;
namespace {
static FieldCreatePtr fieldCreate = getFieldCreate();
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static StandardFieldPtr standardField = getStandardField();
static StandardPVFieldPtr standardPVField = getStandardPVField();
static ConvertPtr convert = getConvert();
static String builder;
static String alarmTimeStamp("alarm,timeStamp");
static String alarmTimeStampValueAlarm("alarm,timeStamp,valueAlarm");
static String allProperties("alarm,timeStamp,display,control,valueAlarm");
static FILE * fd = NULL;
static size_t length = 4;
static void byteArray()
static void testFactory()
{
if(debug) fprintf(fd,"\nbyteArray\n");
PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvByte);;
PVByteArrayPtr pvByteArray = static_pointer_cast<PVByteArray>(pvScalarArray);
ByteArray value;
value.reserve(length);
int8 xxx = 0x7f;
for(size_t i = 0; i<length; i++) value.push_back(xxx++);
pvByteArray->put(0,length,value,0);
builder.clear();
pvByteArray->toString(&builder);
if(debug) fprintf(fd,"put\n%s\n",builder.c_str());
convert->fromByteArray(pvScalarArray,0,length,value,0);
builder.clear();
pvByteArray->toString(&builder);
if(debug) fprintf(fd,"convert\n%s\n",builder.c_str());
ByteArrayData data;
pvByteArray->get(0,length,data);
ByteArray_iterator iter = data.data.begin();
if(debug) fprintf(fd,"iter [");
for(iter=data.data.begin();iter!=data.data.end();++iter) {
if(debug) fprintf(fd,"%d ",*iter);
testDiag("Check array creation");
for(ScalarType e=pvBoolean; e<=pvString; e=(ScalarType)(1+(int)e))
{
testDiag("Check type %s", ScalarTypeFunc::name(e));
PVScalarArrayPtr arr = getPVDataCreate()->createPVScalarArray(e);
testOk1(arr.get()!=NULL);
if(!arr.get())
continue;
testOk1(arr->getScalarArray()->getElementType()==e);
testOk1(arr->getLength()==0);
arr->setLength(10);
testOk1(arr->getLength()==10);
testOk1(arr->getCapacity()>=10);
arr->setLength(0);
testOk1(arr->getLength()==0);
}
if(debug) fprintf(fd,"]\n");
if(debug) fprintf(fd,"raw [");
int8 * pdata = get(data.data);
for(size_t i=0; i<length; i++) {
int val = pdata[i];
if(debug) fprintf(fd,"%d ",val);
}
if(debug) fprintf(fd,"]\n");
if(debug) fprintf(fd,"direct[");
for(size_t i=0; i<length; i++) {
int val = data.data[i];
if(debug) fprintf(fd,"%d ",val);
}
if(debug) fprintf(fd,"]\n");
fprintf(fd,"byteArray PASSED\n");
}
static void ubyteArray()
template<typename PVT>
bool hasUniqueVector(const typename PVT::shared_pointer& pv)
{
if(debug) fprintf(fd,"\nubyteArray\n");
PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvUByte);;
PVUByteArrayPtr pvUByteArray = static_pointer_cast<PVUByteArray>(pvScalarArray);
UByteArray value;
value.reserve(length);
uint8 xxx = 0x7f;
for(size_t i = 0; i<length; i++) value.push_back(xxx++);
pvUByteArray->put(0,length,value,0);
builder.clear();
pvUByteArray->toString(&builder);
if(debug) fprintf(fd,"put\n%s\n",builder.c_str());
convert->fromUByteArray(pvScalarArray,0,length,value,0);
builder.clear();
pvUByteArray->toString(&builder);
if(debug) fprintf(fd,"convert\n%s\n",builder.c_str());
UByteArrayData data;
pvUByteArray->get(0,length,data);
UByteArray_iterator iter = data.data.begin();
if(debug) fprintf(fd,"iter [");
for(iter=data.data.begin();iter!=data.data.end();++iter) {
if(debug) fprintf(fd,"%u ",*iter);
}
if(debug) fprintf(fd,"]\n");
if(debug) fprintf(fd,"raw [");
uint8 * pdata = get(data.data);
for(size_t i=0; i<length; i++) {
unsigned int val = pdata[i];
if(debug) fprintf(fd,"%d ",val);
}
if(debug) fprintf(fd,"]\n");
if(debug) fprintf(fd,"direct[");
for(size_t i=0; i<length; i++) {
unsigned int val = data.data[i];
if(debug) fprintf(fd,"%d ",val);
}
if(debug) fprintf(fd,"]\n");
fprintf(fd,"ubyteArray PASSED\n");
typename PVT::const_svector data;
pv->swap(data);
bool ret = data.unique();
pv->swap(data);
return ret;
}
static void longArray()
template<typename PVT>
struct basicTestData {
static inline void fill(typename PVT::svector& data) {
data.resize(100);
for(size_t i=0; i<data.size(); i++)
{
data[i] = 10*i;
}
}
};
template<>
struct basicTestData<PVStringArray> {
static inline void fill(PVStringArray::svector& data) {
PVIntArray::svector idata;
basicTestData<PVIntArray>::fill(idata);
data.resize(idata.size());
castUnsafeV(data.size(), pvString, data.data(), pvInt, idata.data());
}
};
template<typename PVT>
static void testBasic()
{
if(debug) fprintf(fd,"\nlongArray\n");
PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvLong);;
PVLongArrayPtr pvLongArray = static_pointer_cast<PVLongArray>(pvScalarArray);
LongArray value;
value.reserve(length);
int64 xxx = 0x7fffffffffffffffLL;
for(size_t i = 0; i<length; i++) value.push_back(xxx++);
pvLongArray->put(0,length,value,0);
builder.clear();
pvLongArray->toString(&builder);
if(debug) fprintf(fd,"put\n%s\n",builder.c_str());
convert->fromLongArray(pvScalarArray,0,length,value,0);
builder.clear();
pvLongArray->toString(&builder);
if(debug) fprintf(fd,"convert\n%s\n",builder.c_str());
LongArrayData data;
pvLongArray->get(0,length,data);
LongArray_iterator iter = data.data.begin();
if(debug) fprintf(fd,"iter [");
for(iter=data.data.begin();iter!=data.data.end();++iter) {
if(debug) fprintf(fd,"%lli ",(long long)*iter);
testDiag("Check basic array operations for %s", typeid(PVT).name());
typename PVT::shared_pointer arr1 = static_pointer_cast<PVT>(getPVDataCreate()->createPVScalarArray(PVT::typeCode));
typename PVT::shared_pointer arr2 = static_pointer_cast<PVT>(getPVDataCreate()->createPVScalarArray(PVT::typeCode));
testOk1(*arr1==*arr2);
testOk1(*arr1==*arr1);
testOk1(*arr1->getScalarArray()==*arr2->getScalarArray());
typename PVT::svector data;
data.reserve(200);
basicTestData<PVT>::fill(data);
typename PVT::const_svector cdata(freeze(data));
testOk1(cdata.unique());
arr1->replace(cdata);
testOk1(!cdata.unique());
{
typename PVT::const_svector avoid;
arr1->PVScalarArray::getAs<typename PVT::value_type>(avoid);
testOk1(avoid.data()==cdata.data());
testOk1(avoid.data()==arr1->view().data());
}
if(debug) fprintf(fd,"]\n");
if(debug) fprintf(fd,"raw [");
int64 * pdata = get(data.data);
for(size_t i=0; i<length; i++) {
int64 val = pdata[i];
if(debug) fprintf(fd,"%lli ",(long long)val);
}
if(debug) fprintf(fd,"]\n");
if(debug) fprintf(fd,"direct[");
for(size_t i=0; i<length; i++) {
int64 val = data.data[i];
if(debug) fprintf(fd,"%lli ",(long long)val);
}
if(debug) fprintf(fd,"]\n");
fprintf(fd,"longArray PASSED\n");
testOk1(arr1->getLength()==cdata.size());
testOk1(*arr1!=*arr2);
cdata.clear();
testOk1(hasUniqueVector<PVT>(arr1));
arr2->assign(*arr1);
testOk1(*arr1==*arr2);
testOk1(!hasUniqueVector<PVT>(arr1));
arr2->swap(cdata);
arr2->postPut();
testOk1(arr2->getLength()==0);
testOk1(cdata.size()==arr1->getLength());
PVIntArray::const_svector idata;
arr1->PVScalarArray::getAs<int32>(idata);
testOk1(idata.at(1)==10);
PVIntArray::svector wdata(thaw(idata));
wdata.at(1) = 42;
idata = freeze(wdata);
arr1->PVScalarArray::putFrom<int32>(idata);
testOk1(castUnsafe<PVIntArray::value_type>(arr1->view()[1])==42);
}
static void ulongArray()
static void testShare()
{
if(debug) fprintf(fd,"\nulongArray\n");
PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvULong);;
PVULongArrayPtr pvULongArray = static_pointer_cast<PVULongArray>(pvScalarArray);
ULongArray value;
value.reserve(length);
uint64 xxx = 0x7fffffffffffffffLL;
for(size_t i = 0; i<length; i++) value.push_back(xxx++);
pvULongArray->put(0,length,value,0);
builder.clear();
pvULongArray->toString(&builder);
if(debug) fprintf(fd,"put\n%s\n",builder.c_str());
convert->fromULongArray(pvScalarArray,0,length,value,0);
builder.clear();
pvULongArray->toString(&builder);
if(debug) fprintf(fd,"convert\n%s\n",builder.c_str());
ULongArrayData data;
pvULongArray->get(0,length,data);
ULongArray_iterator iter = data.data.begin();
if(debug) fprintf(fd,"iter [");
for(iter=data.data.begin();iter!=data.data.end();++iter) {
if(debug) fprintf(fd,"%llu ",(long long unsigned)*iter);
}
if(debug) fprintf(fd,"]\n");
if(debug) fprintf(fd,"raw [");
uint64 * pdata = get(data.data);
for(size_t i=0; i<length; i++) {
uint64 val = pdata[i];
if(debug) fprintf(fd,"%llu ",(long long unsigned)val);
}
if(debug) fprintf(fd,"]\n");
if(debug) fprintf(fd,"direct[");
for(size_t i=0; i<length; i++) {
uint64 val = data.data[i];
if(debug) fprintf(fd,"%llu ",(long long unsigned)val);
}
if(debug) fprintf(fd,"]\n");
fprintf(fd,"ulongArray PASSED\n");
testDiag("Check array data sharing");
PVIntArrayPtr iarr = static_pointer_cast<PVIntArray>(getPVDataCreate()->createPVScalarArray(pvInt));
PVStringArrayPtr sarr = static_pointer_cast<PVStringArray>(getPVDataCreate()->createPVScalarArray(pvString));
PVIntArray::const_svector idata(4, 1);
sarr->PVScalarArray::putFrom<int32>(idata); // copy and convert
testOk1(idata.unique());
iarr->PVScalarArray::putFrom<int32>(idata); // take a reference
testOk1(!idata.unique());
idata.clear();
PVIntArray::const_svector cdata;
sarr->PVScalarArray::getAs<int32>(cdata); // copy and convert
testOk1(cdata.unique());
iarr->PVScalarArray::getAs<int32>(cdata); // take a reference
testOk1(!cdata.unique());
}
static void floatArray()
{
if(debug) fprintf(fd,"\nfloatArray\n");
PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvFloat);;
PVFloatArrayPtr pvFloatArray = static_pointer_cast<PVFloatArray>(pvScalarArray);
FloatArray value;
value.reserve(length);
for(size_t i = 0; i<length; i++) value.push_back(10.0*i);
pvFloatArray->put(0,length,value,0);
builder.clear();
pvFloatArray->toString(&builder);
if(debug) fprintf(fd,"put\n%s\n",builder.c_str());
convert->fromFloatArray(pvScalarArray,0,length,value,0);
builder.clear();
pvFloatArray->toString(&builder);
if(debug) fprintf(fd,"convert\n%s\n",builder.c_str());
FloatArrayData data;
pvFloatArray->get(0,length,data);
FloatArray_iterator iter = data.data.begin();
if(debug) fprintf(fd,"iter [");
for(iter=data.data.begin();iter!=data.data.end();++iter) {
if(debug) fprintf(fd,"%f ",*iter);
}
if(debug) fprintf(fd,"]\n");
if(debug) fprintf(fd,"raw [");
float * pdata = get(data.data);
for(size_t i=0; i<length; i++) {
float val = pdata[i];
if(debug) fprintf(fd,"%f ",val);
}
if(debug) fprintf(fd,"]\n");
if(debug) fprintf(fd,"direct[");
for(size_t i=0; i<length; i++) {
float val = data.data[i];
if(debug) fprintf(fd,"%f ",val);
}
if(debug) fprintf(fd,"]\n");
fprintf(fd,"floatArray PASSED\n");
}
} // end namespace
static void doubleArray()
MAIN(testPVScalarArray)
{
if(debug) fprintf(fd,"\ndoubleArray\n");
PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvDouble);;
PVDoubleArrayPtr pvDoubleArray = static_pointer_cast<PVDoubleArray>(pvScalarArray);
DoubleArray value;
value.reserve(length);
for(size_t i = 0; i<length; i++) value.push_back(10.0*i);
pvDoubleArray->put(0,length,value,0);
builder.clear();
pvDoubleArray->toString(&builder);
if(debug) fprintf(fd,"put\n%s\n",builder.c_str());
convert->fromDoubleArray(pvScalarArray,0,length,value,0);
builder.clear();
pvDoubleArray->toString(&builder);
if(debug) fprintf(fd,"convert\n%s\n",builder.c_str());
DoubleArrayData data;
pvDoubleArray->get(0,length,data);
DoubleArray_iterator iter = data.data.begin();
if(debug) fprintf(fd,"iter [");
for(iter=data.data.begin();iter!=data.data.end();++iter) {
if(debug) fprintf(fd,"%lf ",*iter);
}
if(debug) fprintf(fd,"]\n");
if(debug) fprintf(fd,"raw [");
double * pdata = get(data.data);
for(size_t i=0; i<length; i++) {
double val = pdata[i];
if(debug) fprintf(fd,"%lf ",val);
}
if(debug) fprintf(fd,"]\n");
if(debug) fprintf(fd,"direct[");
for(size_t i=0; i<length; i++) {
double val = data.data[i];
if(debug) fprintf(fd,"%lf ",val);
}
if(debug) fprintf(fd,"]\n");
fprintf(fd,"doubleArray PASSED\n");
testPlan(156);
testFactory();
testBasic<PVByteArray>();
testBasic<PVUByteArray>();
testBasic<PVIntArray>();
testBasic<PVDoubleArray>();
testBasic<PVStringArray>();
testShare();
return testDone();
}
static void stringArray()
{
if(debug) fprintf(fd,"\nstringArray\n");
PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvString);;
PVStringArrayPtr pvStringArray = static_pointer_cast<PVStringArray>(pvScalarArray);
StringArray value;
value.reserve(length);
for(size_t i = 0; i<length; i++) {
char val[20];
sprintf(val,"value%d",(int)i);
value.push_back(val);
}
pvStringArray->put(0,length,value,0);
builder.clear();
pvStringArray->toString(&builder);
if(debug) fprintf(fd,"put\n%s\n",builder.c_str());
convert->fromStringArray(pvScalarArray,0,length,value,0);
builder.clear();
pvStringArray->toString(&builder);
if(debug) fprintf(fd,"convert\n%s\n",builder.c_str());
StringArrayData data;
pvStringArray->get(0,length,data);
StringArray_iterator iter = data.data.begin();
if(debug) fprintf(fd,"iter [");
for(iter=data.data.begin();iter!=data.data.end();++iter) {
String val = *iter;
if(debug) fprintf(fd,"%s ",val.c_str());
}
if(debug) fprintf(fd,"]\n");
if(debug) fprintf(fd,"raw [");
String* pdata = get(data.data);
for(size_t i=0; i<length; i++) {
String val = pdata[i];
if(debug) fprintf(fd,"%s ",val.c_str());
}
if(debug) fprintf(fd,"]\n");
if(debug) fprintf(fd,"direct[");
for(size_t i=0; i<length; i++) {
String val = data.data[i];
if(debug) fprintf(fd,"%s ",val.c_str());
}
if(debug) fprintf(fd,"]\n");
fprintf(fd,"stringArray PASSED\n");
}
static void shareArray()
{
if(debug) fprintf(fd,"\nshareArray\n");
PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvDouble);;
PVDoubleArrayPtr pvDoubleArray = static_pointer_cast<PVDoubleArray>(pvScalarArray);
DoubleArray value;
value.reserve(length);
for(size_t i = 0; i<length; i++) value.push_back(10.0*i);
pvDoubleArray->put(0,length,value,0);
PVDoubleArrayPtr pvShareArray = static_pointer_cast<PVDoubleArray>(
pvDataCreate->createPVScalarArray(pvDouble));
pvShareArray->shareData(
pvDoubleArray->getSharedVector(),
pvDoubleArray->getCapacity(),
pvDoubleArray->getLength());
printf("pvDoubleArray->get() %p pvShareArray->get() %p\n",pvDoubleArray->get(),pvShareArray->get());
printf("pvDoubleArray->getVector() %p pvShareArray->getVector() %p\n",
&(pvDoubleArray->getVector()),&(pvShareArray->getVector()));
printf("pvDoubleArray->getSharedVector() %p pvShareArray->getSharedVector() %p\n",
&(pvDoubleArray->getSharedVector()),&(pvShareArray->getSharedVector()));
assert(pvDoubleArray->get()==pvShareArray->get());
builder.clear();
pvShareArray->toString(&builder);
if(debug) fprintf(fd,"pvShare\n%s\n",builder.c_str());
fprintf(fd,"shareArray PASSED\n");
}
int main(int argc,char *argv[])
{
char *fileName = 0;
if(argc>1) fileName = argv[1];
fd = stdout;
if(fileName!=0 && fileName[0]!=0) {
fd = fopen(fileName,"w+");
}
byteArray();
ubyteArray();
longArray();
ulongArray();
floatArray();
doubleArray();
stringArray();
shareArray();
return(0);
}

View File

@@ -22,101 +22,138 @@
#include <pv/standardField.h>
#include <pv/standardPVField.h>
using namespace epics::pvData;
#include <epicsUnitTest.h>
#include <testMain.h>
static bool debug = false;
using namespace epics::pvData;
static FieldCreatePtr fieldCreate;
static PVDataCreatePtr pvDataCreate;
static StandardFieldPtr standardField;
static StandardPVFieldPtr standardPVField;
static ConvertPtr convert;
static String buffer;
static void testPVStructureArray(FILE * fd) {
if(debug) fprintf(fd,"/ntestPVStructureArray\n");
StructureArrayConstPtr alarm(
fieldCreate->createStructureArray(standardField->alarm()));
PVStructureArrayPtr pvAlarmStructure(
pvDataCreate->createPVStructureArray(alarm));
PVStructurePtrArray palarms;
size_t na=2;
palarms.reserve(na);
for(size_t i=0; i<na; i++) {
palarms.push_back(
pvDataCreate->createPVStructure(standardField->alarm()));
}
pvAlarmStructure->put(0,2,palarms,0);
buffer.clear();
pvAlarmStructure->toString(&buffer);
if(debug) fprintf(fd,"pvAlarmStructure\n%s\n",buffer.c_str());
PVStructureArrayPtr copy(pvDataCreate->createPVStructureArray(alarm));
convert->copyStructureArray(pvAlarmStructure,copy);
buffer.clear();
copy->toString(&buffer);
if(debug) fprintf(fd,"copy\n%s\n",buffer.c_str());
fprintf(fd,"testPVStructureArray PASSED\n");
}
static StructureConstPtr getPowerSupplyStructure() {
String properties("alarm");
FieldConstPtrArray fields;
StringArray fieldNames;
fields.reserve(3);
fieldNames.reserve(3);
fieldNames.push_back("voltage");
fieldNames.push_back("power");
fieldNames.push_back("current");
fields.push_back(standardField->scalar(pvDouble,properties));
fields.push_back(standardField->scalar(pvDouble,properties));
fields.push_back(standardField->scalar(pvDouble,properties));
StructureConstPtr structure = fieldCreate->createStructure(
"powerSupply_t",fieldNames,fields);
return structure;
}
static void testPowerSupplyArray(FILE * fd) {
if(debug) fprintf(fd,"/ntestPowerSupplyArray\n");
PVStructurePtr powerSupplyArrayStruct = standardPVField->structureArray(
getPowerSupplyStructure(),String("alarm,timeStamp"));
PVStructureArrayPtr powerSupplyArray =
powerSupplyArrayStruct->getStructureArrayField(String("value"));
assert(powerSupplyArray.get()!=NULL);
int offset = powerSupplyArray->append(5);
if(debug) fprintf(fd,"offset %d\n",offset);
buffer.clear();
powerSupplyArrayStruct->toString(&buffer);
if(debug) fprintf(fd,"after append 5\n%s\n",buffer.c_str());
powerSupplyArray->remove(0,2);
buffer.clear();
powerSupplyArrayStruct->toString(&buffer);
if(debug) fprintf(fd,"after remove(0,2)\n%s\n",buffer.c_str());
powerSupplyArray->remove(2,1);
buffer.clear();
powerSupplyArrayStruct->toString(&buffer);
if(debug) fprintf(fd,"after remove 2,1%s\n",buffer.c_str());
powerSupplyArray->compress();
buffer.clear();
powerSupplyArrayStruct->toString(&buffer);
if(debug) fprintf(fd,"after compress%s\n",buffer.c_str());
fprintf(fd,"testPowerSupplyArray PASSED\n");
}
int main(int argc,char *argv[])
static void testBasic()
{
char *fileName = 0;
if(argc>1) fileName = argv[1];
FILE * fd = stdout;
if(fileName!=0 && fileName[0]!=0) {
fd = fopen(fileName,"w+");
}
testDiag("Basic structure array ops");
StructureArrayConstPtr alarmtype(
fieldCreate->createStructureArray(standardField->alarm()));
PVStructureArrayPtr alarmarr(pvDataCreate->createPVStructureArray(alarmtype));
testOk1(alarmarr->getLength()==0);
alarmarr->setLength(5);
testOk1(alarmarr->getLength()==5);
PVStructureArray::const_svector aview = alarmarr->view();
testOk1(aview.size()==5);
testOk1(aview[4].get()==NULL);
alarmarr->append(2);
testOk1(alarmarr->getLength()==7);
aview = alarmarr->view();
testOk1(aview[4].get()==NULL);
testOk1(aview[5].get()!=NULL);
testOk1(aview[6].get()!=NULL);
}
static void testCompress()
{
testDiag("Test structure array compress");
StructureArrayConstPtr alarmtype(
fieldCreate->createStructureArray(standardField->alarm()));
PVStructureArrayPtr alarmarr(pvDataCreate->createPVStructureArray(alarmtype));
alarmarr->setLength(5);
testOk1(alarmarr->getLength()==5);
alarmarr->compress();
testOk1(alarmarr->getLength()==0);
alarmarr->setLength(4);
testOk1(alarmarr->getLength()==4);
PVStructureArray::svector contents(10);
contents[2] = pvDataCreate->createPVStructure(standardField->alarm());
contents[4] = pvDataCreate->createPVStructure(standardField->alarm());
contents[5] = pvDataCreate->createPVStructure(standardField->alarm());
contents[8] = pvDataCreate->createPVStructure(standardField->alarm());
PVStructureArray::const_svector scont(freeze(contents));
alarmarr->replace(scont);
testOk1(!scont.unique());
testOk1(alarmarr->getLength()==10);
alarmarr->compress();
testOk1(scont.unique()); // a realloc happened
testOk1(alarmarr->getLength()==4);
PVStructureArray::svector compressed(alarmarr->reuse());
testOk1(scont[2]==compressed[0]);
testOk1(scont[4]==compressed[1]);
testOk1(scont[5]==compressed[2]);
testOk1(scont[8]==compressed[3]);
}
static void testRemove()
{
testDiag("Test structure array remove");
PVStructureArray::svector contents(10);
for(size_t i=0; i<contents.size(); i++)
contents[i] = pvDataCreate->createPVStructure(standardField->alarm());
StructureArrayConstPtr alarmtype(
fieldCreate->createStructureArray(standardField->alarm()));
PVStructureArrayPtr alarmarr(pvDataCreate->createPVStructureArray(alarmtype));
PVStructureArray::const_svector scont(freeze(contents));
alarmarr->replace(scont);
alarmarr->remove(0, 10); // all
testOk1(alarmarr->getLength()==0);
alarmarr->replace(scont);
alarmarr->remove(1, 1);
PVStructureArray::const_svector check(alarmarr->view());
testOk1(scont[0]==check[0]);
testOk1(scont[2]==check[1]);
testOk1(scont[3]==check[2]);
}
MAIN(testPVStructureArray)
{
testPlan(0);
testDiag("Testing structure array handling");
fieldCreate = getFieldCreate();
pvDataCreate = getPVDataCreate();
standardField = getStandardField();
standardPVField = getStandardPVField();
convert = getConvert();
testPVStructureArray(fd);
testPowerSupplyArray(fd);
return(0);
testBasic();
testCompress();
testRemove();
return testDone();
}

View File

@@ -70,14 +70,13 @@ int main(int, char **)
StructureConstPtr structure = standardField->scalar(pvDouble, "alarm,timeStamp");
pvStructure = standardPVField->structureArray(structure,"alarm,timeStamp");
size_t num = 2;
PVStructurePtrArray pvStructures;
pvStructures.reserve(num);
PVStructureArray::svector pvStructures(num);
for(size_t i=0; i<num; i++) {
pvStructures.push_back(
pvDataCreate->createPVStructure(structure));
pvStructures[i]=
pvDataCreate->createPVStructure(structure);
}
PVStructureArrayPtr pvStructureArray = pvStructure->getStructureArrayField("value");
pvStructureArray->put(0, num, pvStructures, 0);
pvStructureArray->replace(freeze(pvStructures));
builder.clear();
pvStructure->toString(&builder);
print("structureArrayTest");