Go to the previous, next section.
#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>
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 (int
s), integer vectors (IntVec
s), and bit vectors (BitVec
s). 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.