Apache C++ Standard Library User's Guide

## 22.4 Element and Subset Access

### 22.4.1 Ordinary Index Operators

Class valarray provides `const` and non-`const` versions of `operator[](size_t)`. The const version returns the value of the indicated index, while the non-const version returns a reference to the value.

For example, continuing the example from Section 22.2:

    v1[2] = 5;            // change the element at position 2 using
                          // the non-const index operator

### 22.4.2 Subset Operators

Along with the ordinary subscript operators, valarray provides four different subset operations. Each of these also has both `const` and non-`const` versions. The `const` version always returns a new valarray initialized with data appropriate to the subset operation. The non-`const` version returns an auxiliary array class that references directly the data in the original valarray. Thus each non-`const` version provides a view into the original array by which specific elements may be accessed. Note that an instance of any of these auxiliary classes can only be obtained from the operator. A program cannot instantiate one of these classes directly as they lack a public constructor.

The four subset operations are the `slice` operation, the `gslice` operation, the `mask` operation, and the `indirect` operation. Both `slice` and `gslice` use a special auxiliary class to specify the intent of the operation. These classes are called slice and gslice respectively.

#### 22.4.2.1 The Slice Operation

The `slice` operation provides a view into a valarray that is like the same operation defined in Basic Linear Algebra Subprograms (BLAS). A slice is defined by a starting index, a length, and a stride. To call the `slice` subscript operator, a program passes a slice object initialized with a constructor taking these three parameters: `std::slice(size_t start, size_t length, size_t stride)`. The returned array consists only of length elements, starting with the element at the starting index and continuing with each element's stride steps after the previously selected one. The following example illustrates this process:

    using std::slice;

    int a[9] = {1,2,3,4,5,6,7,8,9};
    valarray<int> all(a,9);                 //all = {1,2,3,4,5,6,7,8,9}
    valarray<int> odd = all[slice(0,5,2)];  //odd = {1,3,5,7,9}

In this example, the subscript operation actually returns a slice_array. Class valarray contains conversion constructors for this class as well as the auxiliary classes returned by other subset operations. Note, however, that the reference semantics are lost in the conversion since odd is an entirely new array. Class slice_array and the other auxiliary classes exist only to help in the selection of a view and the creation of a new valarray based on that view.

#### 22.4.2.2 The gslice Operation

The `gslice` operation differs from the `slice` in that it defines a set of strides and an associated set of lengths. This set of lengths and strides allows a program to treat a single-dimensional valarray as a multidimensional array and to pull multi-dimensional slices from that array. Note that the `gslice` subset operator takes a `gslice` argument and returns a gslice_array in the same manner that the `slice` operation takes a slice and returns a slice_array.

Here is a simple example that uses gslices to represent a three-dimensional array. In this example, the first three numbers form the top row of a two-dimensional array whose center and bottom rows are completed with the next six numbers. The next nine numbers represent the second or middle two-dimensional array, and the last nine the back two-dimensional array. Taken together they form a three- dimensional cube. See the Apache C++ Standard Library Reference Guide for an extended version of this example that uses additional gslices to pull slices along several different axes of the three-dimensional cube defined by this first slice.

    using std::gslice;
    using std::valarray;

    int a[27] =   {0,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,9,2,3,4,5,6,7,8,9,10};
    size_t lengths[2] = {3,3};
    size_t strides[2] = {3,1};

    valarray<int>  v(a,27);                  // initial valarray

    valarray<size_t> len(lengths,2);         // valarray of lengths

    valarray<size_t> stride(strides,2);      // valarray of strides

    valarray<int> v2(0,9);                   // valarray to hold the
                                             // generalized slice

    v2 = (v[gslice(0,len,stride)]);          //  slice off the front  =
                                             // {0,1,2,3,4,5,6,7,8}

    v2 = (v[gslice(9,len,stride)]);          // slice off the middle
                                             //  = {1,2,3,4,5,6,7,8,9}

                                Back two-dimensional array = 2  3  4
                                                             5  6  7
                                                             8  9  10
                Middle two-dimensional array = 1  2  3
                                               4  5  6
                                               7  8  9
     Front two-dimensional array = 0  1  2
                                   3  4  5
                                   6  7  8

#### 22.4.2.3 Boolean Mask

The third operation is a boolean `mask`, which selects certain elements of a valarray based on whether or not the corresponding element of a boolean valarray is set to `true`. The size of the boolean valarray must equal the size of the subscripted valarray. Like the slice example, the following code snippet also selects all the odd numbers in all. Note that the operation actually returns a mask_array.

    int a[9] = {1,2,3,4,5,6,7,8,9};
    std::valarray<int> all(a,9);          // all = {1,2,3,4,5,6,7,8,9}

    bool b[9]= {true,false,true,false,true,false,true,false,true};
    std::valarray<bool> vb(b,9);
    std::valarray<int> odd2 = all[vb];    // odd2 = {1,3,5,7,9}

#### 22.4.2.4 Indirect Operation

Finally, the `indirect` operation selects elements of a valarray dependent on whether or not a given index is present in a valarray of size_t. For instance, if we use valarray<size_t>() as our subscripting argument, then we select `0` elements, returning a valarray or indirect_array (if the sub-scripted array is `const`) of `0` elements. On the other hand, if we use valarray<size_t>(3,1), we select only the third element, thus returning a valarray or indirect array of `1` element. Once again, the following example selects all odd-valued elements from all:

    int a[9] = {1,2,3,4,5,6,7,8,9};
    std::valarray<int> all(a,9);          // all = {1,2,3,4,5,6,7,8,9}

    std::size_t c[5] = {0,2,4,6,8};
    std::valarray<size_t> in(c,5);

    std::valarray<int> oddity = all[in];  // oddity = {1,3,5,7}

Each of the auxiliary array classes, slice_array, gslice_array, mask_array, and indirect_array, has a set of arithmetic and logical computed assignment operators that when applied affect the selected elements in the original non-`const` array. In each case, these operators take a valarray as a parameter. Since the valarray itself contains conversion constructors for each of the auxiliary classes, these arithmetic and logical operators can be applied freely across valarray objects and auxiliary classes and between the auxiliary classes. Note, however, that reference semantics are lost in the conversion from auxiliary class to valarray. A valarray never references data in another valarray, reference-counting optimization notwithstanding.

### 22.4.3 Unary Operators

Class valarray provides four unary operations: `operator+()`, `operator-()`, `operator~(),` and `operator!()`. These operators are not available for types for which they are not defined. Each operator returns a new valarray with the result of applying the operation to each element of the original. For instance, the following negates all values in a valarray.

    float a[4] = {1.0, -2.3, -4.5, 9.0};
    std::valarray<float> v(a,4);
    std::valarray<float> neg = -v;      // neg = {-1.0, 2.3, 4.5, -9.0}