Block.h

Classes

Block -- simple 1-D array (full description)
PtrBlock -- A drop-in replacement for Block<T*>. (full description)

template<class T> class Block

Interface

Public Members
Block() : npts(0), array(0), destroyPointer(True)
explicit Block(uInt n) : npts(n), array(n>0 ? new T[n] : 0), destroyPointer(True)
Block(uInt n, T val) : npts(n), array(n > 0 ? new T[n] : 0), destroyPointer(True)
Block(uInt n, T *&storagePointer, Bool takeOverStorage = True) : npts(n), array(storagePointer), destroyPointer(takeOverStorage)
Block(const Block<T> &other) : npts(other.npts), array(npts > 0 ? new T[npts] : 0), destroyPointer(True)
Block<T> &operator=(const Block<T> &other)
~Block()
void resize(uInt n, Bool forceSmaller=False, Bool copyElements=True)
void remove(uInt whichOne, Bool forceSmaller=True)
void replaceStorage(uInt n, T *&storagePointer, Bool takeOverStorage=True)
T &operator[](uInt index)
const T &operator[](uInt index) const
Block<T> &operator=(const T &val)
void set(const T &val)
T *storage()
const T *storage() const
uInt nelements() const
See Also
Global Block IO functions

Description

Review Status

Reviewed By:
UNKNOWN
Date Reviewed:
before2004/08/25

Etymology

This should be viewed as a block of memory without sophisticated manipulation functions. Thus it is called Block.

Synopsis

Block<T> is a simple templated 1-D array class. Indices are always 0-based. For efficiency reasons, no index checking is done unless the preprocessor symbol AIPS_ARRAY_INDEX_CHECK is defined. Block<T>'s may be assigned to and constructed from other Block<T>'s. As no reference counting is done this can be an expensive operation, however.

The net effect of this class is meant to be unsurprising to users who think of arrays as first class objects. The name "Block" is intended to convey the concept of a solid "chunk" of things without any intervening "fancy" memory management, etc. This class was written to be used in the implementations of more functional Vector, Matrix, etc. classes, although it is expected Block<T> will be useful on its own.

The Block class should be efficient. You should normally use Block.

Warning If you use the assignment operator on an element of this class, you may leave dangling references to pointers released from storage(). Resizing the array will also have this effect if the underlying storage is actually affected.
If index checking is turned on, an out-of-bounds index will generate an indexError<uInt> exception.

Example

 Block<Int> a(100,0);  // 100 ints initialized to 0
 Block<Int> b;         // 0-length Block
 // ...
 b = a;                // resize b and copy a into it
 for (uInt i=0; i < a.nelements(); i++) {
     a[i] = i;    // Generate a sequence
                  // with Vectors, could simply say "indgen(myVector);"
 }
 b.set(-1);       // All positions in b have the value -1
 b.resize(b.nelements()*2); // Make b twice as long, by default the old
                            // elements are copied over, although this can
                            // be defeated.
 some_c_function(b.storage());  // Use a fn that takes an
                                // <src>Int * pointer
  
 

Member Description

Block() : npts(0), array(0), destroyPointer(True)

Create a zero-length Block. Note that any index into this Block is an error.

explicit Block(uInt n) : npts(n), array(n>0 ? new T[n] : 0), destroyPointer(True)

Create a Block with the given number of points. The values in Block are uninitialized. Note that indices range between 0 and n-1.

Block(uInt n, T val) : npts(n), array(n > 0 ? new T[n] : 0), destroyPointer(True)

Create a Block of the given length, and initialize (via operator= for objects of type T) with the provided value.

Block(uInt n, T *&storagePointer, Bool takeOverStorage = True) : npts(n), array(storagePointer), destroyPointer(takeOverStorage)

Create a Block from a C-array (i.e. pointer). If takeOverStorage is True, The Block assumes that it owns the pointer, i.e. that it is safe to delet[] it when the Block is destructed, otherwise the actual storage is not destroyed. If true, storagePointer is set to 0.

Block(const Block<T> &other) : npts(other.npts), array(npts > 0 ? new T[npts] : 0), destroyPointer(True)

Copy the other block into this one. Uses copy, not reference, semantics.

Block<T> &operator=(const Block<T> &other)

Assign other to this. this resizes itself to the size of other, so after the assignment, this->nelements() == other.elements() always.

~Block()

Frees up the storage pointed contained in the Block.

void resize(uInt n, Bool forceSmaller=False, Bool copyElements=True)

Resizes the Block. If n == nelements() resize just returns. If a larger size is requested (n > nelements()) the Block always resizes. If the requested size is smaller (n < nelements()), by default the Block does not resize smaller, although it can be forced to with forceSmaller. The reasoning behind this is that often the user will just want a buffer of at least a certain size, and won't want to pay the cost of multiple resizings.

    Block<float> bf(100, 0.0);
    bf.resize(10);        // bf.nelements() == 100
    bf.resize(10, True)   // bf.nelements() == 10
    bf.resize(200)        // bf.nelements() == 200
    
Normally the old elements are copied over (although if the Block is lengthened the trailing elements will have undefined values), however this can be turned off by setting copyElements to False.

This is written as three functions because default parameters do not always work properly with templates.

void remove(uInt whichOne, Bool forceSmaller=True)

Remove a single element from the Block. If forceSmaller is True this will resize the Block and hence involve new memory allocations. This is relatively expensive so setting forceSmaller to False is preferred. When forcesmaller is False the Block is not resized but the elements with an index above the removed element are shuffled down by one. For backward compatibility forceSmaller is True by default.

void replaceStorage(uInt n, T *&storagePointer, Bool takeOverStorage=True)

Replace the internal storage with a C-array (i.e. pointer). If takeOverStorage is True, The Block assumes that it owns the pointer, i.e. that it is safe to delete[] it when the Blockis destructed, otherwise the actual storage is not destroyed. If true, storagePointer is set to NULL.

T &operator[](uInt index)
const T &operator[](uInt index) const

Index into the block (0-based). If the preprocessor symbol AIPS_ARRAY_INDEX_CHECK is defined, index checking will be done and an out-of-bounds index will cause an indexError<uInt> to be thrown. Note that valid indices range between 0 and nelements()-1.

Thrown Exceptions

Block<T> &operator=(const T &val)
void set(const T &val)

Set all values in the block to "val".

T *storage()
const T *storage() const

If you really, really, need a "raw" pointer to the beginning of the storage area this will give it to you. This may leave dangling pointers if the block is destructed or if the assignment operator or resize is used. Returns a null pointer if nelements() == 0. It is best to only use this if you completely control the extent and lifetime of the Block.

Examples of misuse

    Block<Int> *bp = new Block<Int>(100);
    Int *ip = bp->storage();
    delete bp;      // Oops, ip is now dangling
    Block<Int> a(100),b(100);
    Int *ip = a.storage();
    a = b;          // Likewise
    

uInt nelements() const

The number of elements contained in this Block<T>.


template<class T> class PtrBlock

Interface

PtrBlock() : block_p()
explicit PtrBlock(uInt n) : block_p(n)
PtrBlock(uInt n, T val) : block_p(n, (void *)val)
PtrBlock(uInt n, T *&storagePointer, Bool takeOverStorage = True) : block_p(n, (void **&)storagePointer, takeOverStorage)
PtrBlock(const PtrBlock<T> &other) : block_p(other.block_p)
PtrBlock<T> &operator=(const PtrBlock<T> &other)
~PtrBlock()
void resize(uInt n, Bool forceSmaller, Bool copyElements)
void resize(uInt n)
void resize(uInt n, Bool forceSmaller)
void remove(uInt whichOne, Bool forceSmaller)
void remove(uInt whichOne)
void replaceStorage(uInt n, T *&storagePointer, Bool takeOverStorage=True)
T &operator[](uInt index)
const T &operator[](uInt index) const
void set(const T &val)
PtrBlock<T> &operator=(const T &val)
T *storage()
const T *storage() const
uInt nelements() const

Description

Prerequisite

Synopsis

PtrBlock<T*> has exactly the same interface as Block<T*> and should be used in preference to the latter. It's purpose is solely to reduce the number of template instantiations.

To Do

Member Description

PtrBlock() : block_p()

explicit PtrBlock(uInt n) : block_p(n)

PtrBlock(uInt n, T val) : block_p(n, (void *)val)

PtrBlock(uInt n, T *&storagePointer, Bool takeOverStorage = True) : block_p(n, (void **&)storagePointer, takeOverStorage)

PtrBlock(const PtrBlock<T> &other) : block_p(other.block_p)

PtrBlock<T> &operator=(const PtrBlock<T> &other)

~PtrBlock()

void resize(uInt n, Bool forceSmaller, Bool copyElements)

void resize(uInt n)

void resize(uInt n, Bool forceSmaller)

void remove(uInt whichOne, Bool forceSmaller)

void remove(uInt whichOne)

void replaceStorage(uInt n, T *&storagePointer, Bool takeOverStorage=True)

T &operator[](uInt index)

const T &operator[](uInt index) const

void set(const T &val)

PtrBlock<T> &operator=(const T &val)

T *storage()

const T *storage() const

uInt nelements() const