# Accessor Concept

Accessor and const_accessor objects obtained via `n_container::access()` and `n_container::const_access()` provide access to read from or write to cells inside an `n_container`.

## Syntax

The following methods return objects meeting the requirements of the accessor concept.

    auto n_container::access();
    auto n_container::const_access();
    auto accessor_concept::section(n_bounds_t<…>);
    auto accessor_concept::translated_to(n_index_t<…>);
    auto accessor_concept::translated_to_zero();

## Description

Accessor objects provide read/write access to individual cells of an n-dimensional container. Index values passed to a sequence of array subscript operator calls will produce a proxy concept that can import to or export the primitive data the corresponding cell inside the container.

    auto image = make_n_container<MyStruct, layout::soa>(n_extent[128][256]);
    auto acc = image.access();
    MyStruct in_value(100.0f, 200.0f, 300.0f);

    acc[64][128] = in_value;
    MyStruct out_value = acc[64][128];

    assert(out_value == in_value);

Accessors also know their valid iteration space, which can queried using the template function bound_d<int DimensionT>(accessor).

    assert(bounds_d<0>(acc) == bounds(0_fixed,128));
    assert(bounds_d<1>(acc) == bounds(0_fixed,256));

An accessor may have a non-zero index space if it has a translation embedded into it, `bounds_d` will reflect any such translation.

    auto shifted_acc = acc.translated_to(n_index[1000][2000]);
    assert(bounds_d<0>(shifted_acc) == bounds(1000,1128));
    assert(bounds_d<1>(shifted_acc) == bounds(2000,2256));

This is useful to have a smaller sized container participate in a calculation over a portion of a larger index space, simplifying programming as the same index variable can be used, and the accessor takes care of applying the necessary translation. An accessor may represent a subsection over the original extents, bounds_d will identify the valid iteration space for that accessor.

    auto subsection_acc = a.section(n_bounds[bounds(64,96)][bounds(128,160)]);
    assert(bounds_d<0>(subsection_acc) == bounds(64, 96));
    assert(bounds_d<1>(subsection_acc) == bounds(128, 160);

It can also be useful to have subsections be translated back to start their iteration space at 0. For efficiency, the translated_to_zero() method is provided to create an accessor shifted back to zero.

    auto zb_sub_acc = a.section( n_bounds[bounds(64, 96)][bounds(128, 160)] ).translated_to_zero();
    assert(bounds_d<0>(zb_sub_acc) == bounds(0, 32));
    assert(bounds_d<1>(zb_sub_acc) == bounds(0, 32));

If fewer array subscript calls applied to an accessor than its rank, the result is another accessor of a lower rank. This can be useful to obtain accessors suitable to pass to code expecting lower rank accessors. Such as a obtaining a 3d accessor from a 4d container by specifying only a single index via array subscript. This has the effect of embedding the index value of the dimension inside accessor. When the final dimension is sliced, the result is a proxy object to the cell inside the container corresponding to the embedded index values inside the sliced accessors

    auto image4d = make_n_container<MyStruct, layout::soa>(n_extent[10][20][128][256]);

    MyStruct in_value(100.0f, 200.0f, 300.0f);
    auto acc4d = image4d.access();
    auto acc3d = acc4d[5];
    auto acc2d = acc3d[10];
    auto acc1d = acc2d[64];
    acc1d[128] = in_value;
    MyStruct out_value = acc4d[5][10][64][128];
    assert(out_value == in_value);

The following table provides information on the requirements of the accessor concept.

Pseudo-Signature | Description
--- | ---
    typedef PrimitiveT primitive_type;
| Data type inside the cells of the container.
    static constexpr int rank;
| Number of free dimensions of accessor
    accessor_concept(const accessor_concept &a_other)
| Effects: constructs a copy of another accessor of the exact same type
    template<typename IndexT>
    element_concept operator[] (const IndexT a_index) const
| Requirements: rank == 1 and IndexT is one of: int, aligned<AlignmentT>, fixed<NumberT>, linear_index, or simd_index<LaneCountT> Effects: When only 1 free dimension is left, the operator[] will construct an element_concept which is the proxy to the cell inside the container. If this accessor was obtained with const_access(), then the proxy will provide read only interface to the cell’s data. Returns: The proxy object to cell inside the container corresponding to the position identified by the a_index along with any embedded index values for other dimensions
    template<typename IndexT>
    accessor_concept operator[] (const IndexT a_index) const
| Requirements: rank > 1 and IndexT is one of: int, aligned<AlignmentT>, fixed<NumberT>, linear_index, or simd_index<LaneCountT> Effects: When 2 or more free dimensions are left, the operator[] will construct another accessor_concept of lower rank embeding a_index inside of it, effectively fixing that dimension’s index value for any accesses made through the returned accessor_concept. Returns: The accessor_concept of lower rank ( one less free dimension).
    template<int DimensionT>
    auto bounds_d() const
| Requirements: DimensionT >=0 and DimensionT < rank Effects: Determine the bounds of a free dimension using DimensionT as a 0 based index starting at the leftmost dimension. Returns: bounds_t of the DimensionT
    auto bounds_dXX() const
    where XX is 0-19
| Requirements: XX >=0 and XX < rank and XX < 20 Effects: Non templated methods to determine the bounds of a free dimension using XX as a 0 based index starting at the leftmost dimension. Returns: bounds_t of the XX dimension
    template<int DimensionT>
    auto extent_d() const
| Requirements: DimensionT >=0 and DimensionT < rank Effects: Determine the extent of a free dimension using DimensionT as a 0 based index starting at the leftmost dimension. Returns: extent of the DimensionT
    auto extent_dXX() const
    where XX is 0-19
| Requirements: XX >=0 and XX < rank and XX < 20 Effects: Non templated methods to determine the extent of a free dimension using XX as a 0 based index starting at the leftmost dimension. Returns: extent of the XX dimension
    template<typename ...IndexListT>
    accessor_concept translated_to(
        n_index_t<IndexListT...> a_n_index) const
| Requirements: a_n_index has same rank as the accessor Effects: construct an accessor_concept with an embedded translation such that accessing a_n_index will corresponds back to the current lower bounds. Easy way to think of it is that current iteration space is translated to a_n_index space. Returns: accessor_concept whose bounds have the same extents, but whose lower bounds start at the supplied a_n_index
    template<typename ...IndexListT>
    accessor_concept translated_to_zero() const
| Effects: construct an accessor_concept with an embedded translation such that accessing [0] index for all dimensions will corresponds back to the current lower bounds. Easy way to think of it is that current iteration space is translated to [0] for all free dimensions. Returns: accessor_concept whose bounds have the same extents, but whose lower bounds start [0]…[0]
    template<typename ...BoundsTypeListT>
        auto
        section(const n_bounds_t<BoundsTypeListT...> &a_n_bounds) const
| Requirements: a_n_bounds has same rank as the accessor and a_n_bounds is contained by the accessors current bounds. Effects: construct an accessor_concept with using the supplied a_n_bounds to represent its valid iteration space. Because a_n_bounds must be contained within the existing bounds, we are effictively creating an accessor over a section of the container. Easy way to think of it is that current bounds are being restricted to a_n_bounds. Note: can be useful to chain a call `translated_to_zero()` on to the return value. Returns:`accessor_concept` whose bounds are set to the supplied a_n_bounds

Parent topic: Accessors