Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Array mods #113

Merged
merged 8 commits into from
Jun 25, 2015
53 changes: 51 additions & 2 deletions casa/Arrays/Array.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
//# 520 Edgemont Road
//# Charlottesville, VA 22903-2475 USA
//#
//# $Id$
//# $Id: Array.h 21545 2015-01-22 19:36:35Z gervandiepen $

#ifndef CASA_ARRAY_H
#define CASA_ARRAY_H
Expand Down Expand Up @@ -343,7 +343,56 @@ template<class T> class Array : public ArrayBase
// // "square"'s storage may now be accessed through Vector "line"
// </srcblock>
Array<T> reform(const IPosition &shape) const;


// Having an array that can be reused without requiring reallocation can
// be useful for large arrays. The method reformOrResize permits this
// usage.
//
// The reformOrResize method first attempts to reform the matrix so that
// it reuses the existing storage for an array with a new shape. If the
// existing storage will not hold the new shape, then the method will
// resize the array when resizeIfNeeded is true; if a resize is needed and
// resizeIfNeeded is false, then an ArrayConformanceError is thrown. The
// copyDataIfNeeded parameter is passed to resize if resizing is performed.
// resizePercentage is the percent of additional storage to be addeed when
// a resize is performed; this allows the allocations to be amortized when
// the caller expects to be calling this method again in the future. The
// parameter is used to define an allocation shape which is larger than
// the newShape by increasing the last dimension by resizePercentage percent
// (i.e., lastDim = (lastDim * (100 + resizePercentage)) / 100). If
// resizePercentage <= 0 then resizing uses newShape as-is. Returns true
// if resizing (allocation) was performed.
//
// To truncate the array so that it no longer holds additional storage,
// use the resize method.
//
// Array may not be shared with another Array object during this call.
// Exception thrown if it is shared.

bool reformOrResize (const IPosition & newShape,
uInt resizePercentage = 0,
Bool resizeIfNeeded = True);

// Use this method to extend or reduce the last dimension of an array. If
// sufficient excess capacity exists then the bookkeeping is adjusted to
// support the new shape. If insufficient storage exists then a new array
// is allocated (unless resizeIfNeeded is false; then an exception is thrown).
// If resizing is not required then the data remains untouched; if resizing
// is required then the data is copied into the new storage. The resizePercentage
// works the same as for reformOrResize (see above). This method never releases
// extra storage; use "resize" to do this. Array may not be sharing storage
// with another array at call time; an exception will be thrown if the array is shared.
// Returns true if the array was extension required a Array<T>::resize operation.

bool extend (const IPosition & newShape,
uInt resizePercentage = 0,
bool resizeIfNeeded = True);

// Returns the number of elements allocated. This value is >= to the value returned
// by size().

size_t capacity () const;

// These member functions remove degenerate (ie. length==1) axes from
// Arrays. Only axes greater than startingAxis are considered (normally
// one wants to remove trailing axes). The first two of these functions
Expand Down
63 changes: 62 additions & 1 deletion casa/Arrays/Array.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
//# 520 Edgemont Road
//# Charlottesville, VA 22903-2475 USA
//#
//# $Id$
//# $Id: Array.tcc 21561 2015-02-16 06:57:35Z gervandiepen $

#ifndef CASA_ARRAY_TCC
#define CASA_ARRAY_TCC
Expand Down Expand Up @@ -459,6 +459,67 @@ template<class T> Array<T> Array<T>::reform(const IPosition &len) const
return tmp;
}

template <typename T>
bool
Array<T>::extend (const IPosition & newShape,
uInt resizePercentage,
bool resizeIfNeeded)
{
DebugAssert(ok(), ArrayError);

IPosition currentShape = shape();
if (newShape.size() == currentShape.size()){ // Let base method handle attempt dimensionality changes
for (uInt i = 0; i < newShape.size() - 1; i++){
if (currentShape (i) != newShape (i)){
String message =
String::format ("Array<T>::extend - New shape can only change last dimension:"
" current=%s, new=%s",
currentShape.toString().c_str(), newShape.toString().c_str());
throw ArrayConformanceError (message);
}
}
}

Int64 originalElements = data_p->nelements();

Bool resetEnd = ArrayBase::reformOrResize (newShape, resizeIfNeeded, data_p.nrefs(), data_p->nelements(),
true, resizePercentage);

if (resetEnd){
setEndIter();
}

return originalElements != (Int64) data_p->nelements();
}


template<class T>
bool
Array<T>::reformOrResize (const IPosition & newShape,
uInt resizePercentage,
Bool resizeIfNeeded)
{
DebugAssert(ok(), ArrayError);

Int64 originalElements = data_p->nelements();

Bool resetEnd = ArrayBase::reformOrResize (newShape, resizeIfNeeded, data_p.nrefs(), data_p->nelements(),
false, resizePercentage);

if (resetEnd){
setEndIter();
}

return originalElements != (Int64) data_p->nelements();
}

template<class T>
inline size_t
Array<T>::capacity () const
{
return data_p->nelements(); // returns the number of elements allocated.
}

template<class T>
Array<T> Array<T>::nonDegenerate (uInt startingAxis, Bool throwIfError) const
{
Expand Down
99 changes: 96 additions & 3 deletions casa/Arrays/ArrayBase.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
//# 520 Edgemont Road
//# Charlottesville, VA 22903-2475 USA
//#
//# $Id$
//# $Id: ArrayBase.cc 21521 2014-12-10 08:06:42Z gervandiepen $

#include <casacore/casa/Arrays/ArrayBase.h>
#include <casacore/casa/Arrays/ArrayError.h>
Expand Down Expand Up @@ -92,10 +92,10 @@ ArrayBase& ArrayBase::operator= (const ArrayBase& other)
ArrayBase::~ArrayBase()
{}

void ArrayBase::baseReform (ArrayBase& tmp, const IPosition& len) const
void ArrayBase::baseReform (ArrayBase& tmp, const IPosition& len, Bool strict) const
{
// Check if reform can be done.
if (len.product() != Int64(nelements())) {
if (strict && len.product() != Int64(nelements())) {
throw(ArrayConformanceError("ArrayBase::reform() - "
"total elements differ"));
}
Expand All @@ -114,6 +114,7 @@ void ArrayBase::baseReform (ArrayBase& tmp, const IPosition& len) const
tmp.inc_p = 1;
tmp.originalLength_p.resize (newNdim);
tmp.originalLength_p = tmp.length_p;
tmp.nels_p = len.product();
tmp.baseMakeSteps();
return;
}
Expand Down Expand Up @@ -273,6 +274,98 @@ void ArrayBase::baseAddDegenerate (ArrayBase& tmp, uInt numAxes)
tmp.baseMakeSteps();
}

Bool
ArrayBase::reformOrResize (const IPosition & newShape,
Bool resizeIfNeeded,
uInt nReferences,
Int64 nElementsAllocated,
Bool copyDataIfNeeded,
uInt resizePercentage)
{
DebugAssert(ok(), ArrayError);

if (newShape.isEqual (shape())){
return False; // No op
}

// Check to see if the operation is legal in this context
// ======================================================

// The operation must not change the dimensionality as this could cause a base class
// such as a vector to become a Matrix, etc.

if (newShape.size() != shape().size()){
String message = "ArrayBase::reformOrResize() - Cannot change number of dimensions.";
throw ArrayConformanceError (message);
}

// This operation only makes sense if the storage is contiguous.

if (! contiguousStorage()){
String message = "ArrayBase::reformOrResize() - array must be contiguous";
throw ArrayConformanceError(message);
}

// If the array is sharing storage, then the other array could become dangerously invalid
// as the result of this operation, so prohibit sharing while this operation is being
// performed.

if (nReferences != 1){
String message = "ArrayBase::reformOrResize() - array must not be shared during this call";
throw ArrayConformanceError(message);
}

Bool resizeNeeded = (newShape.product() > nElementsAllocated);

if (resizeNeeded && ! resizeIfNeeded){

// User did not permit resizing but it is required so throw and exception.

String message =
String::format ("ArrayBase::reformOrResize() - insufficient storage for reform: "
"nElementInAllocation=%d, nElementsRequested=%d",
nElementsAllocated, newShape.product());
throw ArrayConformanceError(message);
}

// The operation is legal, so perform it
// =====================================

Bool resetEnd = True; // Caller will need to reset the end iterator

if (resizeNeeded){

// Insufficient storage so resize required, with or without padding

if (resizePercentage <= 0){

// Perform an exact resize

resize (newShape, copyDataIfNeeded);
resetEnd = False;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think setEndIter needs to be done by the caller when the array is resized.


} else {

// Padding was requested so resize to match the padded shape
// and then reform it to use the desired shape.

IPosition paddedShape;
paddedShape = newShape;
paddedShape.last() = (paddedShape.last() * (100 + resizePercentage)) / 100;
resize (paddedShape, copyDataIfNeeded);

// Reform it

baseReform (* this, newShape, False);
}
} else {

baseReform (* this, newShape, False);
}

return resetEnd;
}


// <thrown>
// <item> ArrayError
Expand Down
17 changes: 14 additions & 3 deletions casa/Arrays/ArrayBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
//# 520 Edgemont Road
//# Charlottesville, VA 22903-2475 USA
//#
//# $Id$
//# $Id: ArrayBase.h 21521 2014-12-10 08:06:42Z gervandiepen $

#ifndef CASA_ARRAYBASE_H
#define CASA_ARRAYBASE_H
Expand Down Expand Up @@ -177,6 +177,16 @@ class ArrayBase
void baseCopy (const ArrayBase& that)
{ operator= (that); }

// Either reforms the array if size permits or resizes it to the new shape.
// Implementation of Array<T>::reformOrResize (slightly different signature).

Bool reformOrResize (const IPosition & newShape,
Bool resizeIfNeeded,
uInt nReferences,
Int64 nElementsAllocated,
Bool copyDataIfNeeded,
uInt resizePercentage);

// Determine if the storage of a subset is contiguous.
Bool isStorageContiguous() const;

Expand All @@ -190,8 +200,9 @@ class ArrayBase
// Check if the shape of a cube is correct. Adjust it if smaller.
void checkCubeShape();

// Reform the array to a shape with the same nr of elements.
void baseReform (ArrayBase& tmp, const IPosition& shape) const;
// Reform the array to a shape with the same nr of elements. If nonStrict then
// caller assumes responsibility for not overrunning storage (avoid or use with extreme care).
void baseReform (ArrayBase& tmp, const IPosition& shape, Bool strict=True) const;

// Remove the degenerate axes from the Array object.
// This is the implementation of the nonDegenerate functions.
Expand Down
Loading