Files
pvData/documentation/pvArray.html
2013-06-18 10:01:52 -04:00

1131 lines
38 KiB
HTML

<?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 pvArray</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 Array</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 18-Jun-2013</h2>
<dl>
<dt>Latest version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvArray.html">pvArray.html</a>
</dd>
<dt>This version:</dt>
<dd>none</dd>
<dt>Previous version:</dt>
<dd>None</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL<br />
Michael Davidsaver, 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>This is the documentation for pvData.h as defined by pvDataCPP-md.
When complete it will be merged into pvDataCPP.html.</p>
<p>
pvData provides an interface for network accessible structured data.
The interfaces for C++ and Java are similar.
Thus someone who understands the interface in one of the languages
and knows both languages will quickly understand the interface of the other language.
With only a few exceptions the naming and other conventions do
not follow the C++ standard library conventions.
The definition of pvData is similar to the definition for Java.
The differences are mainly related to language differences.
Some differences are:
<dl>
<dt>shared pointers</dt>
<dd>Java has a garbage collector. In C++ the implementation manages
memory. The primary tool is std::tr1::shared_ptr.</dd>
<dt>PVArray</dt>
<dd>The Java garbage collector allows raw data arrays, e. g. int[],
to be shared. For C++ a shared_vector holds the raw data.
</dd>
<dt>ostream replaces toString</dt>
<dd>In Java every object has method toString.
For C++ operator&lt;&lt; replaces toString</dd>
<dt>shared_vector</dt>
<dd>This is similar to std::vector but uses a shared_ptr to wrap the raw
data and also supports a window into the raw data. It does follow
naming and other conventions for C++ standard library containers.</dd>
</dl>
<p>There is one big difference from the existing Java implelentation:
The method PVValueArray::get.
As an example the Java definition for PVDoubleArray is currently:
<pre>
int get(int offset, int length, DoubleArrayData data);
</pre>
This document assumes this be replaced by:
<pre>
double[] get();
</pre>
<p>The existing version allowed the data source to provide the array in chunks.
The new version assumes that the data source always provides contiguous storage
for the entire raw array. If this is accepted it simplifies a lot of code.
</p>
<p>Three topics not discussed in this document are:
<dl>
<dt>pvDataCreate</dt>
<dd>There should be a new method something like:
<pre>
PVScalarArrayPtr createPVScalarArray(const PVScalarArray &amp;, size_t offset, size_t length);
</pre>
This will share the raw data array but allow a new window.
</dd>
<dt>convert</dt>
<dd>This will be changed to do conversions itself instead of calling
methods like getAs. It will again support methods toXXXArray and fromXXXArray,
with a raw array replaced by a shared_vector.
Templates should be able to minimize the code required.</dd>
<dt>PVStructureArray</dt>
<dd>Can this also use shared_vector to hold elements?</dd>
</dl>
</p>
<h2>pvDataApp/pv</h2>
<h3>pvData.h</h3>
<p>This provides the interface for network accessible data.
Although templates are used to minimize the amount of code,
the interface is <b>not</b> meant to be extended.
Only the types defined by pvIntrospect are implemented.</p>
<h4>PVField</h4>
<pre>
class PVField
: virtual public Serializable,
public std::tr1::enable_shared_from_this<PVField>
{
public:
POINTER_DEFINITIONS(PVField);
virtual ~PVField();
virtual void message(String message,MessageType messageType);
const String&amp; getFieldName() const;
String getFullName() const;
virtual void setRequester(RequesterPtr const &amp;prequester);
std::size_t getFieldOffset() const;
std::size_t getNextFieldOffset() const;
std::size_t getNumberFields() const;
PVAuxInfoPtr &amp; getPVAuxInfo();
bool isImmutable() const;
void setImmutable();
const FieldConstPtr &amp; getField() const;
PVStructure * getParent() const;
void replacePVField(const PVFieldPtr&amp; newPVField);
void renameField(String const &amp; newName);
void postPut();
void setPostHandler(PostHandlerPtr const &amp;postHandler);
virtual std::ostream&amp; operator&lt;&lt;(std::ostream&amp; o) const;
std::ostream&amp; operator&lt;&lt;(std::ostream&amp; o, size_t index) const;
...
};
std::ostream&amp; operator&lt;&lt;(std::ostream&amp; o, const PVFieldPtr &amp; f);
std::ostream&amp; operator&lt;&lt;(std::ostream&amp; o, const PVFieldPtr &amp; f, size_t index);
</pre>
<p>The public methods for PVField are:</p>
<dl>
<dt>~PVField</dt>
<dd>Destructor. Since shared pointers are used it should never be called by
user code.</dd>
<dt>message</dt>
<dd>Code attached to this field can call this method to report
problems.</dd>
<dt>getFieldName</dt>
<dd>Get the field name. If the field is a top level structure the field
name will be an empty string.</dd>
<dt>setRequester</dt>
<dd>Sets a requester to be called when message or getRequesterName are
called. This is only legal for the top level PVField. </dd>
<dt>getFieldOffset</dt>
<dd>Get offset of the PVField field within top level structure. Every field
within the PVStructure has a unique offset. The top level structure has
an offset of 0. The first field within the structure has offset equal to
1. The other offsets are determined by recursively traversing each
structure of the tree. </dd>
<dt>getNextFieldOffset</dt>
<dd>Get the next offset. If the field is a scalar or array field then this
is just offset + 1. If the field is a structure it is the offset of the
next field after this structure. Thus (nextOffset - offset) is always
equal to the total number of fields within the field. </dd>
<dt>getNumberFields</dt>
<dd>Get the total number of fields in this field. This is nextFieldOffset -
fieldOffset. </dd>
<dt>getPVAuxInfo</dt>
<dd>Get the PVAuxInfo for this field. PVAuxInfo is described below.</dd>
<dt>isImmutable</dt>
<dd>Is the field immutable?</dd>
<dt>setImmutable</dt>
<dd>Make the field immutable. Once a field is immutable it can never be
changed since there is no method to again make it mutable. This is an
important design decision since it allows immutable array fields to share
the internal primitive data array.</dd>
<dt>getField</dt>
<dd>Get the reflection interface for the data.</dd>
<dt>getParent</dt>
<dd>Get the interface for the parent or null if this is the top level
PVStructure.</dd>
<dt>replacePVField</dt>
<dd>Replace the data implementation for the field.</dd>
<dt>renameField</dt>
<dd>Rename the field name. </dd>
<dt>postPut</dt>
<dd>If a postHandler is registered it is called otherwise no action is
taken.</dd>
<dt>setPostHandler</dt>
<dd>Set the postHandler for the record. Only a single handler can be
registered.</dd>
<dt>operator&lt;&lt;</dt>
<dd>Stream output</dt>
</dl>
<h4>PVScalar</h4>
<pre>
class PVScalar : public PVField {
public:
POINTER_DEFINITIONS(PVScalar);
virtual ~PVScalar();
typedef PVScalar &amp;reference;
typedef const PVScalar&amp; const_reference;
const ScalarConstPtr getScalar() const;
...
};
</pre>
<p>where</p>
<dl>
<dt>getScalar</dt>
<dd>Get the introspection interface for the PVScalar.</dd>
</dl>
<h4>PVScalarValue</h4>
<pre>
template<typename T>
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;
std::ostream&amp; operator&lt;&lt;(std::ostream&amp; o) const
std::ostream&amp; operator&lt;&lt;(std::ostream&amp; o, size_t index) const;
...
};
typedef PVScalarValue&lt;uint8&gt; PVBoolean;
typedef PVScalarValue&lt;int8&gt; PVByte;
typedef PVScalarValue&lt;int16&gt; PVShort;
typedef PVScalarValue&lt;int32&gt; PVInt;
typedef PVScalarValue&lt;int64&gt; PVLong;
typedef PVScalarValue&lt;uint8&gt; PVUByte;
typedef PVScalarValue&lt;uint16&gt; PVUShort;
typedef PVScalarValue&lt;uint32&gt; PVUInt;
typedef PVScalarValue&lt;uint64&gt; PVULong;
typedef PVScalarValue&lt;float&gt; PVFloat;
typedef PVScalarValue&lt;double&gt; PVDouble;
typedef std::tr1::shared_ptr&lt;PVBoolean&gt; PVBooleanPtr;
typedef std::tr1::shared_ptr&lt;PVByte&gt; PVBytePtr;
typedef std::tr1::shared_ptr&lt;PVShort&gt; PVShortPtr;
typedef std::tr1::shared_ptr&lt;PVInt&gt; PVIntPtr;
typedef std::tr1::shared_ptr&lt;PVLong&gt; PVLongPtr;
typedef std::tr1::shared_ptr&lt;PVUByte&gt; PVUBytePtr;
typedef std::tr1::shared_ptr&lt;PVUShort&gt; PVUShortPtr;
typedef std::tr1::shared_ptr&lt;PVUInt&gt; PVUIntPtr;
typedef std::tr1::shared_ptr&lt;PVULong&gt; PVULongPtr;
typedef std::tr1::shared_ptr&lt;PVFloat&gt; PVFloatPtr;
typedef std::tr1::shared_ptr&lt;PVDouble&gt; PVDoublePtr;
// PVString is special case, since it implements SerializableArray
class PVString : public PVScalarValue&lt;String&gt;, SerializableArray {
public:
virtual ~PVString() {}
...
};
</pre>
<p>where</p>
<dl>
<dt>get</dt>
<dd>Get the value stored in the object.</dd>
<dt>put</dt>
<dd>Change the value stored in the object.</dd>
<dt>operator&lt;&lt;</dt>
<dd>Methods for stream I/O.</dd>
</dl>
<h4>PVArray</h4>
<p>PVArray is the base interface for all the other PV Array interfaces. It
extends PVField and provides the additional methods:</p>
<pre>class PVArray : public PVField, public SerializableArray {
public:
POINTER_DEFINITIONS(PVArray);
virtual ~PVArray();
virtual std::size_t getLength() const = 0;
virtual void setLength(std::size_t length) = 0;
bool isCapacityMutable() const;
void setCapacityMutable(bool isMutable);
virtual std::size_t getCapacity() const = 0;
virtual void setCapacity(std::size_t capacity) = 0;
...
};</pre>
<dl>
<dt>getLength</dt>
<dd>Get the current length. This is less than or equal to the capacity.</dd>
<dt>setLength</dt>
<dd>Set the length. If the PVField is not mutable then an exception is
thrown. If this is greater than the capacity setCapacity is called.</dd>
<dt>isCapacityMutable</dt>
<dd>Is the capacity mutable</dd>
<dt>setCapacityMutable</dt>
<dd>Specify if the capacity can be changed.</dd>
<dt>getCapacity</dt>
<dd>Get the capacity, i.e. this is the size of the underlying data
array.</dd>
<dt>setCapacity</dt>
<dd>Set the capacity. The semantics are implementation dependent but
typical semantics are as follows: If the capacity is not mutable an
exception is thrown. A new data array is created and data is copied from
the old array to the new array. </dd>
</dl>
<h4>PVScalarArray</h4>
<p>PVScalarArray is the base class for scalar array data. PVValueArray is a
templete for the various scalar array data classes. There is a class for each
possible scalar type, i. e. PVBooleanArray, ..., PVStringArray.</p>
<pre>class PVScalarArray : public PVArray {
public:
POINTER_DEFINITIONS(PVScalarArray);
typedef PVScalarArray &amp;reference;
typedef const PVScalarArray&amp; const_reference;
virtual ~PVScalarArray();
const ScalarArrayConstPtr getScalarArray() const;
...
};
// PVString is special case, since it implements SerializableArray
class PVString : public PVScalarValue&lt;String&gt;, SerializableArray {
public:
virtual ~PVString() {}
...
};
</pre>
<p>where</p>
<dl>
<dt>getScalarArray</dt>
<dd>Get the introspection interface.</dd>
</dl>
<h4>PVValueArray</h4>
<p>This is a template class plus instances for PVBooleanArray, ...,
PVStringArray.</p>
<pre>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;
typedef PVValueArray &amp; reference;
typedef const PVValueArray &amp; const_reference;
typedef shared_vector&lt;T&gt; svector;
typedef shared_vector&lt;const T&gt; const_svector;
virtual ~PVValueArray() {}
const_svector &amp; get();
size_t put(size_t offset,size_t length, const_svector &amp;from, size_t fromOffset);
void shareData(const_svector &amp;from);
virtual std::ostream&amp; operator&lt;&lt;(std::ostream&amp; o) const;
std::ostream&amp; operator&lt;&lt;(std::ostream&amp; o, size_t index) const;
...
};
typedef PVValueArray&lt;uint8&gt; PVBooleanArray;
typedef std::tr1::shared_ptr&lt;PVBooleanArray&gt; PVBooleanArrayPtr;
typedef PVValueArray&lt;int8&gt; PVByteArray;
typedef std::tr1::shared_ptr&lt;PVByteArray&gt; PVByteArrayPtr;
typedef PVValueArray&lt;int16&gt; PVShortArray;
typedef std::tr1::shared_ptr&lt;PVShortArray&gt; PVShortArrayPtr;
typedef PVValueArray&lt;int32&gt; PVIntArray;
typedef std::tr1::shared_ptr&lt;PVIntArray&gt; PVIntArrayPtr;
typedef PVValueArray&lt;int64&gt; PVLongArray;
typedef std::tr1::shared_ptr&lt;PVLongArray&gt; PVLongArrayPtr;
typedef PVValueArray&lt;uint8&gt; PVUByteArray;
typedef std::tr1::shared_ptr&lt;PVUByteArray&gt; PVUByteArrayPtr;
typedef PVValueArray&lt;uint16&gt; PVUShortArray;
typedef std::tr1::shared_ptr&lt;PVUShortArray&gt; PVUShortArrayPtr;
typedef PVValueArray&lt;uint32&gt; PVUIntArray;
typedef std::tr1::shared_ptr&lt;PVUIntArray&gt; PVUIntArrayPtr;
typedef PVValueArray&lt;uint64&gt; PVULongArray;
typedef std::tr1::shared_ptr&lt;PVULongArray&gt; PVULongArrayPtr;
typedef PVValueArray&lt;float&gt; PVFloatArray;
typedef std::tr1::shared_ptr&lt;PVFloatArray&gt; PVFloatArrayPtr;
typedef PVValueArray&lt;double&gt; PVDoubleArray;
typedef std::tr1::shared_ptr&lt;PVDoubleArray&gt; PVDoubleArrayPtr;
typedef PVValueArray&lt;String&gt; PVStringArray;
typedef std::tr1::shared_ptr&lt;PVStringArray&gt; PVStringArrayPtr;
</pre>
<p>where</p>
<dl>
<dt>get</dt>
<dd>Get the shared_vector that holds the data.
Code that calls this is able to modify the array elements
but should be very careful if it does.
For example it must call postPut after modifying the array elements.
It must also respect isImmutable().
</dd>
<dt>put</dt>
<dd>This is the recommended method for modifying the array elements.
It may change the capacity if len asks for more elements
than the cureent capacity allows.
It does not change the current length.
</dd>
<dt>shareData</dt>
<dd>Share data with an existing shared_vector.
Note that if capacity is every changed then data will no
longer be shared.</dd>
<dt>operator&lt;&lt;</dt>
<dd>Methods for stream I/O.</dd>
</dl>
<h2>shared_vector</h2>
<h3>Status</h3>
<p>I think that all public components of sharedVector.h
are now documented, but not all have a description or example.
Thus the documentation needs more work.
</p>
<p>When <b>NOTE EXISTING</b> appears it means that there is a question about
the existing shared_vector implementation.</p>
<h3>Introduction</h3>
<p>A shared_vector is a container as defined by the C++ standard library.
It is like std::vector but provides two additional features
1) shared raw array and 2) a window into the raw array.</p>
<p>To support these two features a shared_vector keeps the following
private data:
<dl>
<dt>m_data</dt>
<dd>This is a std::tr1::shared_ptr for the actual data array.
</dd>
<dt>m_offset</dt>
<dd>This is the offset of the first element seen by the window.</dd>
<dt>m_count</dt>
<dd>This is the size, i. e. total number of elements, seen by the window.</dd>
<dt>m_total</dt>
<dd>This is the number of elements between offset and the end of the array referenced
by m_data.</dd>
</dl>
Note that only m_data is shared. Thus each shared_vector has it's own window.</p>
<p>The following subsections are organized as follows:
<dl>
<dt>shared_vector example</dt>
<dd>The example code is based on a shared_vector&lt;int32&gt;
This subsection show the C++ definitions that are assumed by
the example code.
The source that contains the example code will be part
of this project but not yet.</dd>
<dt>std::vector compatible subsections</dt>
<dd>The types and methods that have the same names as std::vector.</dd>
<dt>share_vector specific</dt>
<dd>The methods that are not part of std::vector.</dd>
</dl></p>
<p>The subsections that are compatible with std::vector are organized
and start with a brief summary modeled after Section 31.3(STL Containers) in:<br />
"The C++ Programming Language, C++11, Fourth Edition", Bjarne Stroustrup,2013<br/>
The subsection names are the same names that Stroustrup uses.
Each subsection starts with a brief summary that is similar to
the summary Stroustrup has at the beginnining of each subsection.</p>
<p>The comparison is always with std::vector.
In addition it shows what is defined by by std::vector but not by
shared_vector.</p>
<p>Someone who already understand the C++ STL can understand shared_vector
by just looking at the brief summarys.
For others the brief summary is followed by tutorial information.
</p>
<h3>shared_vector example</h3>
<p>The examples all assume that the following has been defined:</p>
<pre>
typedef shared_vector&lt;int32&gt; Int32Array;
...
static void dumpArray(String const &amp;message,Int32Array const&amp; int32Array);
</pre>
<p>The following:
<pre>
Int32Array int32Array(5);
dumpArray("example",int32Array);
</pre>
creates a shared vector that holds an array of five elements where each element is a
32 bit signed integer.
The call to dumpArray displays the message and the array elements on standard out:
<pre>
example 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</pre>
</p>
<p>exampleSharedVector is a main program that has the code for the
examples shown below.</p>
<h3>Member Types</h3>
<p>Brief Summary
<pre>
value_type Type of element
size_type Unsigned type of subscripts, element counts, etc.
difference_type Signed type of difference between iterators
iterator Behaves like value_type*
const_iterator Behaves like const value_type*
reverse_iterator Behaves like value_type*
const_reverse_iterator Behaves like const value_type*
reference value_types&amp;
const_reference const_value_type&amp;
pointer Behaves like value_type *
const_pointer Behaves like const value_type*
//not part of std::vector
element_type same as value_type
shared_pointer_type std::tr1::shared_ptr&lt;value_type&gt;
// defined by std::vector but not by shared_vector
allocator_type
</pre>
</p>
<p>
The typedefs are compatible with the STL container member types.
These define types for various types of variables that belong to a container
or are used to access a container.</p>
<h4>value_type, reference, and const_reference</h4>
<p>These three typedefs define the same types as the equivalent types for
an element of the shared_vector.
<pre>
Int32Array::value_type value;
//is the same as
int32 value;
Int32Array::reference rvalue = value;
//is the same as
int32 &amp; rvalue = value;
Int32Array::const_reference rvalue = value;
//is the same as
const int32 &amp; rvalue = value;
</pre>
</p>
<h4>pointer and const_pointer</h4>
<p>The following is an example of code that uses the
pointer typedef:</p>
<pre>
Int32Array int32Array(5);
Int32Array::pointer pint32Array = int32Array.data();
size_t len = int32Array.size();
for(size_t i=0; i&lt;len; ++i) pint32Array[i] = i;
</pre>
<p>A const_pointer is like a pointer except that only read access to the array elements
is allowed.</p>
<p><b>Dangorous: data</b> should not be used unless it is necessary to
call C code. The above code should be:</p>
<pre>
Int32Array int32Array(5);
size_t len = int32Array.size();
for(size_t i=0; i&lt;len; ++i) int32Array[i] = i;
</pre>
<h4>difference_type</h4>
<p>This is used to get the number of elements between two elements.
For example:</p>
<pre>
Int32Array::difference_type pdiff = int32Array[3] - int32Array[1];
// pdiff will have the value 2
</pre>
<h4>element_type and shared_pointer_type</h4>
<p>These are member types defined by std::tr1::shared_ptr.
These are not used by any of the client methods.</p>
<h3>Constructors, Destructor, and Assignments</h3>
<p>Brief Summary
<pre>
C c(); Default constructor; c is empty.
C c(n); c is initialized with n elementis with the value value_type{};
offset is 0; size is n;
C c(n,e); Initialize c with n copies of e.
offset is 0; size is n;
C c(c); Copy an existing shared_vector of the same type.
offset and taken same as v.
shared_ptr is copied; not the raw array
C operator=(c) Assignment constructor.
shared_ptr is copied; not the raw array
C c(c,o,n); Copy an existing std::tr1::shared_ptr&lt;value_type&gt;
offset is o; size is c;
C c(r,o,n); Use an existing raw pointer.
default deleter use "delete[]" to delete.
offset is o; size is c;
C c(r,d,o,n); Use an existing raw pointer and deleter d;
offset is o; size is c;
not implemented
~C() The C++ default destructor is used.
C++11 specific
&amp;&amp; constructor move constructor
{} constructor uniform initializer constructor
</pre>
where
<dl>
<dt>C</dt>
<dd>The class name, e. g. shared_vector&lt;int32&gt;</dd>
<dt>c</dt>
<dd>shared_vector instance</dd>
<dt>n</dt>
<dd>size, i. e. the number of elements</dd>
<dt>o</dt>
<dd>offset</dd>
<dt>e</dt>
<dd>element instance</dd>
<dt>r</dt>
<dd>raw pointer, e. g. int32 *</dd>
<dt>d</dt>
<dd>a deleter, i. e. object that destroys the raw array.</dd>
</dl>
</p>
<h4>Construct by creating new raw array</h4>
<pre>
shared_vector();
shared_vector(size_t n);
shared_vector(size_t n, value_type e);
</pre>
<p>The first three constructors all create a new shared_vector
by also creating a new raw array,
The difference is the size of the array, i.e. how many elements it contains,
and how the elements are initalized.
</p>
<dl>
<dt>shared_vector()</dt>
<dd>The array is empty, i.e. it has no elements.</dd>
<dt>shared_vector(size_t n)</dt>
<dd>The array has <b>n</b> elements. Each element is initialized
by the default constructor for the element type.
For numeric elements, like int32, this means 0.</dd>
<dt>shared_vector(size_t n, value_type e)</dt>
<dd>The array has <b>n</b> elements.
Each element has the initial value <b>e</b>.
</dd>
</dl>
<p>The following:
<pre>
cout << "***exampleConstructors***" << endl;
Int32Array emptyArray();
Int32Array zeroArray(16);
int32 value = 1;
Int32Array oneArray(8, value);
dumpArray("emptyArray",emptyArray);
dumpArray("zeroArray",zeroArray);
dumpArray("oneArray",oneArray);
</pre>
produces
<pre>
***exampleConstructors***
emptyArray 1
zeroArray {16}[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...]
oneArray {8}[1, 1, 1, 1, 1, 1, 1, 1]
</pre>
<p><b>NOTE EXISTING: </b> Why did emptyArray disply the above.
Should it be "emptyArray {0} []"?
</p>
<h4>Construct by sharing raw array from a shared_vector</h4>
<pre>
shared_vector(const shared_vector&amp; o);
shared_vector_base&amp; operator=(const shared_vector_base&amp; o);
</pre>
<p>These create a vector by coping the contents of an existing shared_vector
of the same type into the newly created vector.
Note that the complete raw array is not copied but just the std::tr1:: shared_ptr
that holds the array.</p>
<p>The following:
<pre>
cout &lt;&lt; "***exampleCopyConstructors***" &lt;&lt; endl;
size_t max = 16;
Int32Array int32Array(max);
for(size_t i=0; i&lt;max; ++i) int32Array[i] = i+1;
Int32Array xxx(int32Array); //copy constructor
Int32Array yyy = int32Array; //copy assignment
cout &lt;&lt; "dataPtr int32Array " &lt;&lt; int32Array.dataPtr();
cout &lt;&lt; " xxx " &lt;&lt; xxx.dataPtr();
cout &lt;&lt; " yyy " &lt;&lt; yyy.dataPtr() &lt;&lt; endl;
dumpArray("int32Array",emptyArray);
dumpArray("xxx",emptyArray);
dumpArray("yyy",emptyArray);
</pre>
produces
<pre>
***exampleConstructors***
dataPtr int32Array 0x136ea90 xxx 0x136ea90 yyy 0x136ea90
int32Array {16}[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...]
xxx {16}[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...]
yyy {16}[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...]
</pre>
<h4>Construct by wrapping an existing raw array</h4>
<pre>
shared_vector(A v, size_t o, size_t c)
shared_vector(A d, B b, size_t o, size_t c)
</pre>
<p><b>NOTE EXISTING:</b> Are these constructors necessary?
If code wants to wrap an existing raw array then
a std::tr1::shared_ptr can first be created
and the constructor in the next section can be called.</p>
<p>These "wrap" an existing raw pointer.
They allows access to a sub-array starting at offset <b>o></b>
and has size <b>c</b>
The second provides a destructor and the first has a default deleter.</p>
<p>The default deleter does the following:
When the shared_vector is deleted, i. e. when no code references it,
the statement "delete[] a;" is executed.</p>
<p>An example of wrapping a raw array without using these constructors is:</p>
<pre>
class Int32ArrayDeleter
{
//Note that this an example that does nothing.
//But it could have private data
public:
Int32ArrayDeleter() {}
virtual ~Int32ArrayDeleter() {}
void operator()(int32* a){
// MUST HANDLE DELETION
// default is "delete[] a;"
}
};
...
int32 *pother; // something managed by other code
size_t capacity; // size of array managed by other code
Int32Array int32Array(pother,int32array_deleter,0,capacity);
</pre>
<p>This is used to wrap arrays that are managed by other
code. This should only be used if You understand the other code
and know what your deleter has to do.
An example, exampleShareRawArray, gives a more complete example.
</p>
<h4>Create a shared_vector from an existing shared_ptr</h4>
<pre>
shared_vector(const std::tr1::shared_ptr&lt;E1&gt;&amp; d, size_t o, size_t c)
</pre>
<p>This creates a vector from an existing smart pointer.
Thus the vector will share reference counting with the existing smart
pointer. This is useful for creating "windows" into the array
that the smart pointer references.</p>
<h4>Create a shared_vector from an existing shared_vector</h4>
<pre>
template&lt;typename E1&gt;
shared_vector(const shared_vector&lt;E1&gt;&amp; o) :base_t(o) {}
</pre>
<p><b>NOTE EXISTING:</b> I do not understand how this works or what it does.</p>
<p>This create a vector by coping the contents of an existing shared_vector
of the same or a different but related type
into the newly created vector.
This constructor creates a new raw array and copies the elements from
the existing array to the new array.</p>
<h3>Size and Capacity</h3>
<p>Brief Summary
<pre>
size() Return the number of elements in the window
empty() Is the window empty? this means shared_ptr is empty
max_size() The maximum possible number of elements.
capacity() The number of possible elements without re-allocating raw array.
reserve(n) Reserve at least n elements in raw array; May cause reallocation.
resize(n) Change size to n; May cause reallocation
clear() shared_ptr is reset, Window will be empty.
not implemented
resize(n,v)
shrink_to_fit()
</pre></p>
<p>Details
<pre>
size_t size() const;
bool empty() const;
size_t max_size() const;
size_t capacity() const;
void reserve(size_t n);
void resize(size_t n);
void clear();
</pre>
</p>
<dl>
<dt>size</dt>
<dd>The current number of elements in the window.</dd>
<dt>empty</dt>
<dd>(true,false) if size is (0,&gt;0)</dd>
<dt>max_size</dt>
<dd>Maximum possible number of elements.
<b>NOTE EXISTING;</b> Should this be sizof(W)/(size_t -1) ?
</dd>
<dt>capacity</dt>
<dd>The maximum size the window can be without reallocating raw array</dd>
<dt>reserve</dt>
<dd>Set the maximum number of element that the window can see.
If the caller is the only user of the window and the number
of elements specified does not cause the number of elements to change
then this method just returns.
In all other cases a new raw array is allocated.</p>
<dt>resize</dt>
<dd>Change the window size: may cause a reallocation of the raw array.</dd>
<dt>clear</dt>
<dd>If the shared_vector is not already empty the shared_ptr will
be reset. The new size will be 0.</dd>
</dl>
<p>The following:
<pre>
static void exampleSizeEtc()
{
cout &lt;&lt; "***exampleSizeEtc***" &lt;&lt; endl;
size_t max = 16;
Int32Array int32Array(max);
size_t capacity = int32Array.capacity();
size_t size = int32Array.size();
bool empty = int32Array.empty();
size_t max_size = int32Array.max_size();
cout&lt;&lt; "capacity" &lt;&lt; capacity;
cout&lt;&lt; " size " &lt;&lt; size;
cout&lt;&lt; " empty " &lt;&lt; (empty ? true : false) ;
cout&lt;&lt; " max_size " &lt;&lt; max_size &lt;&lt; endl;
}
</pre>
produces:
<pre>
***exampleSizeEtc***
capacity16 size 16 empty 0 max_size 18446744073709551615
</pre>
</p>
<h3>Iterators</h3>
<p>Brief Summary
<pre>
begin() First element
end() One past last element
cbegin() Constant first element
cend() Constant last element
rbegin() First element of reverse sequence
rend() One past last element of reverse sequence
crbegin() Constant first element of reverse sequence
crend() Constant last element of reverse sequence
</pre></p>
<p>
shared_vector supports both iterators and reverse iterators as defined by the STL.
For both constant iterators are also defined.
A constant iterator does not allow an array elemnent to be modified.</p>
<p>The following is an example of a constant iterator.</p>
<pre>
int32 sum = 0;
for(Int32Array::const_iterator iter=int32Array.begin(); iter&lt;int32Array.end(); ++iter )
{
sum += *iter;
}
</pre>
<p>The following is an example of a non constant iterator.</p>
<pre>
int32 value = 0;
for(Int32Array::iterator iter=int32Array.begin(); iter&lt;int32Array.end(); ++iter )
{
*iter += ++value;
}
</pre>
<h3>Element Access</h3>
<p>Brief Summary
<pre>
operator[i] random element access
data() return the raw array
implemented by std::vector but not implemented
front()
back()
at()
</pre></p>
<p>Note that:
<pre>
Int32Array::pointer pint32= int32Array.data();
</pre>
<b>is NOT gauranteed to be the same as</b>
<pre>
int32 * pint32 = int32Array.data();
</pre>
</p>
<p><b>NOTE EXISTING: data()</b> should be defined to return a const_pointer.
It is currently defined to return a plain pointer.</p>
<h3>Stack Operations</h3>
<p>Brief Summary
<pre>
push_back(x) Add an element after the last element
pop_back(x) Remove the last element.
</pre></p>
<h3>List operations</h3>
<p>shared_vector does not support the standard list operations like:
<pre>
implemented by std::vector but not by shared_vector
insert(p,x) Add x before p
...
</pre>
</p>
<h3>Other Operations</h3>
<p>Brief Summary
<pre>
operator== Do all elements of both containers compare equal.
operator!= Does any element not compare equal.
operator&lt;&lt; ostream operator
swap(c2) Swap the contents of two shared_vectors of the same type.
swap(c1,c2) Swap the contents of two shared_vectors of the same type.
not implemented
operator&lt;
operator&lt;=
operator&gt;
operator&gt;=
</pre></p>
<h4>operators equals, not equals, and ostream</h4>
<pre>
template&lt;typename A, typename B&gt;
bool operator==(const epics::pvData::shared_vector&lt;A&gt;&amp; a,
const epics::pvData::shared_vector&lt;B&gt;&amp; b);
template&lt;typename A, typename B&gt;
bool operator!=(const epics::pvData::shared_vector&lt;A&gt;&amp; a,
const epics::pvData::shared_vector&lt;B&gt;&amp; b);
template&lt;typename E&gt;
std::ostream&amp; operator&lt;&lt;(
std::ostream&amp; strm, const epics::pvData::shared_vector&lt;E&gt;&amp; arr);
</pre>
<h4>swap</h4>
<p>Swap the contents of two shared_vectors. The following code:
<pre>
cout &lt;&lt; "***exampleSwap***" &lt;&lt; endl;
Int32Array first(8);
Int32Array second(16);
cout &lt;&lt; " before swap size ";
cout&lt;&lt; "first " &lt;&lt; first.size() &lt;&lt; " second " &lt;&lt; second.size() &lt;&lt; endl;
first.swap(second);
cout &lt;&lt; " after swap size ";
cout&lt;&lt; "first " &lt;&lt; first.size() &lt;&lt; " second " &lt;&lt; second.size() &lt;&lt; endl;
swap(first,second);
cout &lt;&lt; " swap again size ";
cout&lt;&lt; "first " &lt;&lt; first.size() &lt;&lt; " second " &lt;&lt; second.size() &lt;&lt; endl;
</pre>
produces:
<pre>
***exampleSwap***
before swap size first 8 second 16
after swap size first 16 second 8
swap again size first 8 second 16
</pre></p>
<h3>shared_vector specific operations</h3>
<p>Brief Summary
<pre>
void make_unique() Make caller the only user of std::tr1::shared_ptr
bool unique() Is the caller the only user of std::tr1::shared_ptr
void slice(offset,length) Change window offset andsize
// following should only be used for debugging
const std::tr1::shared_ptr&lt;E&gt;&amp;
dataPtr() Return const shared_ptr
size_t dataOffset() Return offset.
size_t dataCount() Return count which is also the size
size_t dataTotal() Return total number of elements between
offset and end of the raw array
// following converts from type FROM to type TO
shared_vector<TO> static_shared_vector_cast(const shared_vector&lt;FROM&gt;&amp; src);
// following casts from const Type to Type
shared_vector<TYPE>
const_shared_vector_cast(const shared_vector&lt;const TYPE&gt;&amp; src)
</pre></p>
<p><b>NOTE EXISTING:</b> The C++ standard library considers a slice to be every nth element
of some part of an array, i. e., slice has arguments (offset,length,stride).
shared_vector only has offset and length.
Perhaps it should have another name like rewindow.
<h4>make_unique and unique</h4>
<pre>
void make_unique();
bool unique() const;
</pre>
<dl>
<dt>make_unique</dt>
<dd>Makes sure that caller is the only user of this standard_vector.
If the caller is not already the only user a new raw array is allocated.</dd>
<dt>unique</dt>
<dd>
Returns (true,false) if there is only one user of the shared_vector.
</dd>
</dl>
<h4>slice</h4>
<pre>
void slice(size_t offset, size_t length=(size_t)-1);
</pre>
<p>This modifies the "window" into the raw array starting at offset and of
the specified length. The offset and length are forced to be
within the raw array.
Note that this method never reallocates the underlying raw array.
</p>
<p>The following code:
<pre>
static void exampleSlice()
{
cout &lt;&lt; "***exampleSlice***" &lt;&lt; endl;
size_t max = 16;
Int32Array int32Array(max);
int32 value = 0;
for(Int32Array::iterator iter = int32Array.begin(); iter!=int32Array.end(); ++iter)
{
*iter = ++value;
}
dumpArray("int32Array",int32Array);
size_t offset = 0;
size_t length = 8;
Int32Array window1(int32Array);
window1.slice(offset,length);
dumpArray("window1",window1);
offset = 8;
length = 8;
Int32Array window2(int32Array);
window2.slice(offset,length);
dumpArray("window2",window2);
offset = 2;
length = 4;
Int32Array window3(window2);
window3.slice(offset,length);
dumpArray("window3",window3);
}
</pre>
produces the following output:
<pre>
***exampleSlice***
int32Array 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
window1 1 2 3 4 5 6 7 8
window2 9 10 11 12 13 14 15 16
window3 11 12 13 14
</pre>
<h4>dataPtr, dataOffset, dataCount, and dataTotal</h4>
<dl>
<dt>dataPtr</dt>
<dd>Returns the shared_ptr that holds the raw array.
</dd>
<dt>dataOffset</dt>
<dd>Offset in the data array of first element</dd>
<dt>dataCount</dt>
<dd>Number of visible elements.
Same as size.
</dd>
<dt>dataTotal</dt>
<dd>Total number of elements between m_offset and the end of data.
Same as capacity.
</dd>
</dl>
<p>The following:
<pre>
static void exampleDataEtc()
{
cout &lt;&lt; "***exampleDataEtc***" &lt;&lt; endl;
size_t max = 16;
Int32Array int32Array(max);
long use_count = int32Array.dataPtr().use_count();
long offset = int32Array.dataOffset();
long count = int32Array.dataCount();
long total = int32Array.dataTotal();
cout &lt;&lt; "use_count " &lt;&lt; use_count;
cout &lt;&lt; " offset " &lt;&lt; offset;
cout &lt;&lt; " count " &lt;&lt; count;
cout &lt;&lt; " total " &lt;&lt; total &lt;&lt; endl;
}
</pre>
produces:
<pre>
***exampleDataEtc***
use_count 1 offset 0 count 16 total 16
</pre>
</p>
<h4>static_shared_vector_cast</h4>
<p>Not yet documented</p>
<h4>const_shared_vector_cast</h4>
<p>Not yet documented</p>
<h4>specialization for untyped pointers</h4>
<p>Not yet documented</p>
</div>
</body>
</html>