WWC snapshot of http://www.alw.nih.gov/Docs/NIHCL/nihcl_52.html taken on Sat Jun 10 19:14:05 1995

Go to the previous, next section.

Vector--APL-like Vectors

SYNOPSIS

#include <nihcl/BitVec.h>
#include <nihcl/ByteVec.h>
#include <nihcl/ShortVec.h>
#include <nihcl/IntVec.h>
#include <nihcl/LongVec.h>
#include <nihcl/FloatVec.h>
#include <nihcl/DoubleVec.h>

BASE CLASS

Object

DERIVED CLASSES

BitVec, ByteVec, ShortVec, IntVec, LongVec, FloatVec, DoubleVec

RELATED CLASSES

None

DESCRIPTION

Class Vector and its derived classes, BitVec, ByteVec, ShortVec, IntVec, LongVec, FloatVec, and DoubleVec, provide a convenient notation for vector operations. In the following discussion, variable names consisting of a single capital letter (e.g. V) represent vector objects, variable names consisting of a single lowercase letter (e.g. i) represent scalar values, and a sequence of numbers enclosed by square brackets (e.g. [1 5 7 9]) represents a vector constant.

The Vector classes overload almost all possible operators to apply to vectors and vectors combined with scalars. Specifically, a unary operator applied to a vector is applied to each element of the vector to produce a vector result. A binary arithmetic operator applied to two vectors, which must be of equal length, is applied to the corresponding pairs of elements of the vectors to produce a vector result. A binary relational operator applied to two vectors is applied to the corresponding pairs of elements of the vectors to produce a BitVec result in which a 1 indicates that the relation is true for the corresponding pair and a 0 indicates that it is false. A binary operator applied to a vector and a scalar is applied to each element and the scalar to produce a vector result. For example:

if V = [1 2 3 4 5 6 7 8]
and W = [8 7 6 5 4 3 2 1]
then:

-V = [-1 -2 -3 -4 -5 -6 -7 -8]
V-W = [-7 -5 -3 -1 1 3 5 7]
V<W = [1 1 1 1 0 0 0 0]

V+1 = [2 3 4 5 6 7 8 9]
V>3 = [0 0 0 1 1 1 1 1]

A slice operator allows operations on multidimensional arrays to be more easily implemented on an array processor. A slice of a vector is defined by the starting position of the slice, the number of elements in the slice, and the stride, or the increment between successive elements of the slice. The slice operator of a vector V is written as: V(position,length,stride). Note that vectors are indexed starting at 0, in keeping with the C convention. Thus:

if V = [1 2 3 4 5 6 7 8]
then V(0,4,2) = [1 3 5 7]
and V(2,3,1) = [3 4 5]

Vectors can be indexed by integer scalars (ints), integer vectors (IntVecs), and bit vectors (BitVecs). Integer scalar indexing is available both with and without range checking. Indexing a vector by an IntVec produces a vector result by indexing the vector by each element of the IntVec. The result thus has the same length as the index vector. Indexing a vector by a BitVec of the same length produces a vector result by selecting those elements of the indexed vector that correspond to 1s in the BitVec index vector. Thus, the length of the result is equal to the number of 1s in the index vector. For example:

if V = [1 2 3 4 5 6 7 8]
and I = [1 3 7 2]
then:

V[1] = 2                // index range checking done
V(0) = 1                // no index range checking
V[I] = [2 4 8 3]
V[V>4] = [5 6 7 8]

The slice, IntVec index, and BitVec index operators may all appear to the left of an assignment operator as well, in which case the vector elements addressed by the operator are assigned the value of the expression to the right of the assignment operator. This value may be either a scalar or a vector. If it is a vector, its length must be the same as the number of elements addressed on the left side of the assignment; if it is a scalar, all addressed elements are assigned its value. For example:

if V = [1 2 3 4 5 6 7 8]
and I = [1 3 7 2]
and J = [-1 -2 -3 -4]
then:

V(1,4,2) = I;   // V = [1 1 3 3 5 7 7 2]
V[I] = J;       // V = [1 -1 -4 -2 5 6 7 -3]
V[V>4] = 0;     // V = [1 2 3 4 0 0 0 0]

Private classes are used to implement the slice, IntVec index, and BitVec index operators. For example, the IntVec index operator is defined using a private class IntPick to save pointers to the operand vectors:

class IntPick {
    IntVec* V;      // pointer to the indexed vector
    IntVec* X;      // pointer to the index vector
    IntPick(IntVec& v, const IntVec& x) { V = &v;  X = &x; }
    friend IntVec;
public:
    void operator=(const IntVec&);
    void operator=(int);
    operator IntVec();
// ...
};

class IntVec : public Vector {
// ...
public:
    IntPick IntVec::operator[](const IntVec& I) {
        return IntPick(*this,I); }
    void operator=(const IntPick&);
// ...
};

Thus, C++ interprets the expression V[I], where V and I are instances of class IntVec, as a call to the function IntVec::operator[](const IntVec&), which returns a result of type IntPick. The functions IntPick::operator=(const IntVec&) and IntPick::operator=(int) define assignments such as V[I] = W and V[I] = s, respectively. The function IntPick::operator IntVec() enables implicit conversion to type IntVec so that expressions such as V[I]+W are permissible. The function IntVec::operator=(IntPick&) defines assignments of the form W = V[I]. Note that class IntPick is not a derived class, and it has no public constructor, so client programs cannot use it directly.

The vector classes are still experimental, and have not been tested on a real application. The major problems with these classes are:

Go to the previous, next section.