Skip to content

Commit

Permalink
Merge pull request #113 from JimNrao/ArrayMods
Browse files Browse the repository at this point in the history
Issue #111: Added the capacity feature making it possible to resize without acquiring memory.
  • Loading branch information
gervandiepen committed Jun 25, 2015
2 parents 8c04e9f + 7add7a2 commit 26cb696
Show file tree
Hide file tree
Showing 5 changed files with 401 additions and 10 deletions.
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 adjustLastAxis (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>::adjustLastAxis (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;

} 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

0 comments on commit 26cb696

Please sign in to comment.