Commit 92702e6c authored by Kenneth Leiter's avatar Kenneth Leiter

ENH: Add ArrayPointer Variant to allow users to use XdmfArray merely as a...

ENH: Add ArrayPointer Variant to allow users to use XdmfArray merely as a "pointer holder" for output using Xdmf.  See the docs for a more clear explanation.  Modify XdmfArray methods to correctly use the ArrayPointer.
parent 13ce79fd
......@@ -64,158 +64,197 @@ private:
class XdmfArray::GetHDF5Type : public boost::static_visitor <hid_t> {
public:
GetHDF5Type()
{
}
hid_t operator()(const boost::shared_ptr<std::vector<char> > & array) const
hid_t getHDF5Type(const char * const) const
{
return H5T_NATIVE_CHAR;
}
hid_t operator()(const boost::shared_ptr<std::vector<short> > & array) const
hid_t getHDF5Type(const short * const) const
{
return H5T_NATIVE_SHORT;
}
hid_t operator()(const boost::shared_ptr<std::vector<int> > & array) const
hid_t getHDF5Type(const int * const) const
{
return H5T_NATIVE_INT;
}
hid_t operator()(const boost::shared_ptr<std::vector<long> > & array) const
hid_t getHDF5Type(const long * const) const
{
return H5T_NATIVE_LONG;
}
hid_t operator()(const boost::shared_ptr<std::vector<float> > & array) const
hid_t getHDF5Type(const float * const) const
{
return H5T_NATIVE_FLOAT;
}
hid_t operator()(const boost::shared_ptr<std::vector<double> > & array) const
hid_t getHDF5Type(const double * const) const
{
return H5T_NATIVE_DOUBLE;
}
hid_t operator()(const boost::shared_ptr<std::vector<unsigned char> > & array) const
hid_t getHDF5Type(const unsigned char * const) const
{
return H5T_NATIVE_UCHAR;
}
hid_t operator()(const boost::shared_ptr<std::vector<unsigned short> > & array) const
hid_t getHDF5Type(const unsigned short * const) const
{
return H5T_NATIVE_USHORT;
}
hid_t operator()(const boost::shared_ptr<std::vector<unsigned int> > & array) const
hid_t getHDF5Type(const unsigned int * const) const
{
return H5T_NATIVE_UINT;
}
template<typename T>
hid_t operator()(const boost::shared_ptr<std::vector<T> > & array) const
{
return this->getHDF5Type(&(array.get()->operator[](0)));
}
template<typename T>
hid_t operator()(const boost::shared_array<const T> & array) const
{
return this->getHDF5Type(array.get());
}
};
class XdmfArray::GetPrecision : public boost::static_visitor <int> {
public:
GetPrecision()
{
}
int operator()(const boost::shared_ptr<std::vector<char> > & array) const
int getPrecision(const char * const) const
{
return 1;
}
int operator()(const boost::shared_ptr<std::vector<short> > & array) const
int getPrecision(const short * const) const
{
return 2;
}
int operator()(const boost::shared_ptr<std::vector<int> > & array) const
int getPrecision(const int * const) const
{
return 4;
}
int operator()(const boost::shared_ptr<std::vector<long> > & array) const
int getPrecision(const long * const) const
{
return 8;
}
int operator()(const boost::shared_ptr<std::vector<float> > & array) const
int getPrecision(const float * const) const
{
return 4;
}
int operator()(const boost::shared_ptr<std::vector<double> > & array) const
int getPrecision(const double * const) const
{
return 8;
}
int operator()(const boost::shared_ptr<std::vector<unsigned char> > & array) const
int getPrecision(const unsigned char * const) const
{
return 1;
}
int operator()(const boost::shared_ptr<std::vector<unsigned short> > & array) const
int getPrecision(const unsigned short * const) const
{
return 2;
}
int operator()(const boost::shared_ptr<std::vector<unsigned int> > & array) const
int getPrecision(const unsigned int * const) const
{
return 4;
}
template<typename T>
int operator()(const boost::shared_ptr<std::vector<T> > & array) const
{
return this->getPrecision(&(array.get()->operator[](0)));
}
template<typename T>
int operator()(const boost::shared_array<const T> & array) const
{
return this->getPrecision(array.get());
}
};
class XdmfArray::GetType : public boost::static_visitor <std::string> {
public:
GetType()
{
}
std::string operator()(const boost::shared_ptr<std::vector<char> > & array) const
std::string getType(const char * const) const
{
return "Char";
}
std::string operator()(const boost::shared_ptr<std::vector<short> > & array) const
std::string getType(const short * const) const
{
return "Short";
}
std::string operator()(const boost::shared_ptr<std::vector<int> > & array) const
std::string getType(const int * const) const
{
return "Int";
}
std::string operator()(const boost::shared_ptr<std::vector<long> > & array) const
std::string getType(const long * const) const
{
return "Int";
}
std::string operator()(const boost::shared_ptr<std::vector<float> > & array) const
std::string getType(const float * const) const
{
return "Float";
}
std::string operator()(const boost::shared_ptr<std::vector<double> > & array) const
std::string getType(const double * const) const
{
return "Float";
}
std::string operator()(const boost::shared_ptr<std::vector<unsigned char> > & array) const
std::string getType(const unsigned char * const) const
{
return "UChar";
}
std::string operator()(const boost::shared_ptr<std::vector<unsigned short> > & array) const
std::string getType(const unsigned short * const) const
{
return "UShort";
}
std::string operator()(const boost::shared_ptr<std::vector<unsigned int> > & array) const
std::string getType(const unsigned int * const) const
{
return "UInt";
}
template<typename T>
std::string operator()(const boost::shared_ptr<std::vector<T> > & array) const
{
return this->getType(&(array.get()->operator[](0)));
}
template<typename T>
std::string operator()(const boost::shared_array<const T> & array) const
{
return this->getType(array.get());
}
};
class XdmfArray::GetSize : public boost::static_visitor <int> {
......@@ -244,35 +283,80 @@ public:
{
return &array->operator[](0);
}
template<typename T>
const void* const operator()(const boost::shared_array<const T> & array) const
{
return array.get();
}
};
class XdmfArray::GetValuesString : public boost::static_visitor <std::string> {
public:
GetValuesString()
GetValuesString(const int arrayPointerNumValues) :
mArrayPointerNumValues(arrayPointerNumValues)
{
}
std::string operator()(const boost::shared_ptr<std::vector<char> > & array) const
std::string getValuesString(const char * const array, const int numValues) const
{
std::stringstream toReturn;
for(int i=0; i<array->size(); ++i)
for(int i=0; i<numValues; ++i)
{
toReturn << (int)(array->operator[](i)) << " ";
toReturn << (int)array[i] << " ";
}
return toReturn.str();
}
template<typename T>
std::string operator()(const boost::shared_ptr<std::vector<T> > & array) const
std::string getValuesString(const T * const array, const int numValues) const
{
std::stringstream toReturn;
for(int i=0; i<array->size(); ++i)
for(int i=0; i<numValues; ++i)
{
toReturn << array->operator[](i) << " ";
toReturn << array[i] << " ";
}
return toReturn.str();
}
template<typename T>
std::string operator()(const boost::shared_ptr<std::vector<T> > & array) const
{
return getValuesString(&(array->operator[](0)), array->size());
}
template<typename T>
std::string operator()(const boost::shared_array<const T> & array) const
{
return getValuesString(array.get(), mArrayPointerNumValues);
}
private:
const int mArrayPointerNumValues;
};
class XdmfArray::InternalizeArrayPointer : public boost::static_visitor <void> {
public:
InternalizeArrayPointer(XdmfArray * const array) :
mArray(array)
{
}
template<typename T>
void operator()(const boost::shared_array<const T> & array) const
{
mArray->mHaveArrayPointer = false;
mArray->copyValues(0, array.get(), mArray->mArrayPointerNumValues);
mArray->mArrayPointer = boost::shared_array<const T>();
mArray->mArrayPointerNumValues = 0;
}
private:
XdmfArray * const mArray;
};
class XdmfArray::NewArray : public boost::static_visitor <void> {
......@@ -291,7 +375,9 @@ public:
};
XdmfArray::XdmfArray() :
mInitialized(false)
mHaveArray(false),
mHaveArrayPointer(false),
mArrayPointerNumValues(0)
{
std::cout << "Created Array " << this << std::endl;
}
......@@ -301,53 +387,115 @@ XdmfArray::~XdmfArray()
std::cout << "Deleted Array " << this << std::endl;
}
void XdmfArray::copyValues(int startIndex, boost::shared_ptr<XdmfArray> values, int valuesStartIndex, int numValues, int arrayStride, int valuesStride)
void XdmfArray::copyValues(const int startIndex, const boost::shared_ptr<const XdmfArray> values, const int valuesStartIndex, const int numValues, const int arrayStride, const int valuesStride)
{
if(!mInitialized)
if(mHaveArrayPointer)
{
internalizeArrayPointer();
}
if(!mHaveArray)
{
// Copy the values variant in order to get the type (only taking smart pointer so no worries about large copies)
mArray = values->mArray;
// Reinitialize variant array to contain new array with same type.
boost::apply_visitor( NewArray(), mArray);
mInitialized = true;
boost::apply_visitor(NewArray(), mArray);
mHaveArray = true;
}
boost::apply_visitor( CopyArrayValues(startIndex, valuesStartIndex, numValues, arrayStride, valuesStride), mArray, values->mArray);
boost::apply_visitor(CopyArrayValues(startIndex, valuesStartIndex, numValues, arrayStride, valuesStride), mArray, values->mArray);
}
void XdmfArray::clear()
{
mInitialized = false;
return boost::apply_visitor( Clear(), mArray);
if(mHaveArray)
{
return boost::apply_visitor(Clear(), mArray);
}
}
hid_t XdmfArray::getHDF5Type() const
{
return boost::apply_visitor( GetHDF5Type(), mArray);
if(mHaveArray)
{
return boost::apply_visitor(GetHDF5Type(), mArray);
}
else if(mHaveArrayPointer)
{
return boost::apply_visitor(GetHDF5Type(), mArrayPointer);
}
return -1;
}
int XdmfArray::getPrecision() const
{
return boost::apply_visitor( GetPrecision(), mArray);
if(mHaveArray)
{
return boost::apply_visitor(GetPrecision(), mArray);
}
else if(mHaveArrayPointer)
{
return boost::apply_visitor(GetPrecision(), mArrayPointer);
}
return 0;
}
int XdmfArray::getSize() const
{
return boost::apply_visitor( GetSize(), mArray);
if(mHaveArray)
{
return boost::apply_visitor(GetSize(), mArray);
}
else if(mHaveArrayPointer)
{
return mArrayPointerNumValues;
}
return 0;
}
std::string XdmfArray::getType() const
{
return boost::apply_visitor( GetType(), mArray);
if(mHaveArray)
{
return boost::apply_visitor(GetType(), mArray);
}
else if(mHaveArrayPointer)
{
return boost::apply_visitor(GetType(), mArrayPointer);
}
return "";
}
const void* const XdmfArray::getValuesPointer() const
{
return boost::apply_visitor( GetValuesPointer(), mArray);
if(mHaveArray)
{
return boost::apply_visitor(GetValuesPointer(), mArray);
}
else if(mHaveArrayPointer)
{
return boost::apply_visitor(GetValuesPointer(), mArrayPointer);
}
return NULL;
}
std::string XdmfArray::getValuesString() const
{
return boost::apply_visitor( GetValuesString(), mArray);
if(mHaveArray)
{
return boost::apply_visitor(GetValuesString(mArrayPointerNumValues), mArray);
}
else if(mHaveArrayPointer)
{
return boost::apply_visitor(GetValuesString(mArrayPointerNumValues), mArrayPointer);
}
return "";
}
void XdmfArray::internalizeArrayPointer()
{
if(mHaveArrayPointer)
{
boost::apply_visitor(InternalizeArrayPointer(this), mArrayPointer);
}
}
std::string XdmfArray::printSelf() const
......@@ -355,12 +503,39 @@ std::string XdmfArray::printSelf() const
return "";
}
void XdmfArray::releaseArray()
{
boost::shared_ptr<std::vector<char> > emptyArray;
mArray = emptyArray;
mHaveArray = false;
}
void XdmfArray::releaseArrayPointer()
{
boost::shared_array<const char> emptyArrayPointer;
mArrayPointer = emptyArrayPointer;
mHaveArrayPointer = false;
}
void XdmfArray::swap(boost::shared_ptr<XdmfArray> array)
{
array->mArray.swap(mArray);
bool initialized = array->mInitialized;
array->mInitialized = mInitialized;
mInitialized = initialized;
ArrayVariant tmpArray = array->mArray;
ArrayPointerVariant tmpArrayPointer = array->mArrayPointer;
int tmpArrayPointerNumValues = array->mArrayPointerNumValues;
bool tmpHaveArray = array->mHaveArray;
bool tmpHaveArrayPointer = array->mHaveArrayPointer;
array->mArray = mArray;
array->mArrayPointer = mArrayPointer;
array->mArrayPointerNumValues = mArrayPointerNumValues;
array->mHaveArray = mHaveArray;
array->mHaveArrayPointer = mHaveArrayPointer;
mArray = tmpArray;
mArrayPointer = tmpArrayPointer;
mArrayPointerNumValues = tmpArrayPointerNumValues;
mHaveArray = tmpHaveArray;
mHaveArrayPointer = tmpHaveArrayPointer;
}
void XdmfArray::write(boost::shared_ptr<XdmfVisitor> visitor) const
......
......@@ -3,6 +3,7 @@
// Includes
#include "XdmfItem.hpp"
#include <boost/shared_array.hpp>
#include <boost/variant.hpp>
#include <hdf5.h>
#include <vector>
......@@ -57,7 +58,7 @@ public:
* @param arrayStride number of values to stride in this array between each copy.
* @param valuesStride number of values to stride in the XdmfArray between each copy.
*/
void copyValues(const int startIndex, const boost::shared_ptr<XdmfArray> values, const int valuesStartIndex= 0, const int numValues = 1, const int arrayStride = 1, const int valuesStride = 1);
void copyValues(const int startIndex, const boost::shared_ptr<const XdmfArray> values, const int valuesStartIndex= 0, const int numValues = 1, const int arrayStride = 1, const int valuesStride = 1);
/**
* Copy values from an array into this array.
......@@ -118,8 +119,8 @@ public:
*
* @return a smart pointer to the internal vector of values stored in this array.
*/
template <typename T>
const boost::shared_ptr<const std::vector<T> > getValues() const;
//template <typename T>
//const boost::shared_ptr<const std::vector<T> > getValues() const;
/**
* Get a pointer to the values stored in this array.
......@@ -145,6 +146,32 @@ public:
virtual std::string printSelf() const;
/**
* Releases all data held by this XdmfArray.
*/
void releaseData()
{
releaseArray();
releaseArrayPointer();
}
/**
* Sets the values of this array to the values stored in the arrayPointer array. No copy is made. Modifications to the array are
* not permitted through the XdmfArray API. Any calls through the XdmfArray API to modify the array (i.e. any non-const function)
* will result in the array being copied into internal storage. The internal copy is then modified.
* This prevents situations where a realloc of the pointer could cause other references to become invalid.
* The caller of this method can continue to modify the values stored in arrayPointer on its own.
* This function is meant for applications that have their own array data structures that merely use Xdmf to output the data,
* an operation that should not require a copy. Other applications that use Xdmf for in memory data storage should avoid
* this function.
*
* @param arrayPointer a pointer to an array to store in this XdmfArray.
* @param numValues the number of values in the array.
* @param transferOwnership whether to transfer responsibility for deletion of the array to XdmfArray.
*/
template<typename T>
void setValues(const T * const arrayPointer, const int numValues, const bool transferOwnership = 0);
/**
* Sets the values of this array to the values stored in the vector. No copy is made. The caller of this method retains
* ownership of the data and must ensure that the array is still valid for the entire time Xdmf needs it.
......@@ -213,10 +240,29 @@ private:
class GetType;
class GetValuesPointer;
class GetValuesString;
class InternalizeArrayPointer;
class NewArray;
struct NullDeleter;
/**
* After setValues(const T * const array) is called, XdmfArray stores a pointer that is not allowed to be modified through
* the XdmfArray API. If the user desires to modify the contents of the pointer, they must do so without calling any
* non-const functions of XdmfArray. If they do call non-const functions of XdmfArray, we try to accommodate by copying
* the array pointer into internal data structures.
*/
void internalizeArrayPointer();
/**
* Release references to internal data.
*/
void releaseArray();
/**
* Release references to held array pointer internal data;
*/
void releaseArrayPointer();
typedef boost::variant<
boost::shared_ptr<std::vector<char> >,
boost::shared_ptr<std::vector<short> >,
......@@ -228,8 +274,22 @@ private:
boost::shared_ptr<std::vector<unsigned short> >,
boost::shared_ptr<std::vector<unsigned int> > > ArrayVariant;
typedef boost::variant<
boost::shared_array<const char>,
boost::shared_array<const short>,
boost::shared_array<const int>,
boost::shared_array<const long>,
boost::shared_array<const float>,
boost::shared_array<const double>,
boost::shared_array<const unsigned char>,
boost::shared_array<const unsigned short>,
boost::shared_array<const unsigned int> > ArrayPointerVariant;
ArrayVariant mArray;
bool mInitialized;
ArrayPointerVariant mArrayPointer;
int mArrayPointerNumValues;
bool mHaveArray;
bool mHaveArrayPointer;
};
#include "XdmfArray.tpp"
......
......@@ -51,7 +51,11 @@ struct XdmfArray::NullDeleter
template<typename T>
void XdmfArray::copyValues(const int startIndex, const T * const valuesPointer, const int numValues, const int arrayStride, const int valuesStride)
{
if(!mInitialized)
if(mHaveArrayPointer)
{
internalizeArrayPointer();
}
if(!mHaveArray)
{
initialize<T>();
}
......@@ -61,20 +65,10 @@ void XdmfArray::copyValues(const int startIndex, const T * const valuesPointer,
template <typename T>
boost::shared_ptr<std::vector<T> > XdmfArray::getValues()
{
try
if(mHaveArrayPointer)
{
boost::shared_ptr<std::vector<T> > currArray = boost::get<boost::shared_ptr<std::vector<T> > >(mArray);
return currArray;
}
catch(const boost::bad_get& exception)
{
return boost::shared_ptr<std::vector<T> >();
internalizeArrayPointer();
}
}