Skip to content
2 changes: 1 addition & 1 deletion include/RAJA/RAJA.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
#include "RAJA/util/StaticLayout.hpp"
#include "RAJA/util/IndexLayout.hpp"
#include "RAJA/util/View.hpp"

#include "RAJA/util/SubView.hpp"

//
// View for sequences of objects
Expand Down
268 changes: 268 additions & 0 deletions include/RAJA/util/SubView.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
/*!
******************************************************************************
*
* \file
*
* \brief RAJA header file defining the SubView class
*
******************************************************************************
*/

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC
// and RAJA project contributors. See the RAJA/LICENSE file for details.
//
// SPDX-License-Identifier: (BSD-3-Clause)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

#ifndef RAJA_SUBVIEW_HPP
#define RAJA_SUBVIEW_HPP

#include "RAJA/util/for_each.hpp"
#include "RAJA/util/macros.hpp"
#include "RAJA/util/types.hpp"
#include "camp/tuple.hpp"
#include "camp/array.hpp"

namespace RAJA
{

template<typename IndexType = Index_type>
struct RangeSlice {
IndexType start_, end_;

static constexpr bool reduces_dimension = false;

RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType map_index(const IndexType& idx) const {
return start_ + idx;
}

template<IndexType DIM, typename LayoutType>
RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType size(const LayoutType&) const {
return (end_ - start_ + 1);
}
Comment on lines +40 to +43
Copy link
Member

@MrBurmark MrBurmark Nov 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is DIM here? If its unused we should use the unused arg macro so we don't get a warning.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also why the +1, this is including end?


RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType stride() const {
return 1;
}
};

template<typename IndexType = Index_type>
struct RangeStartSlice {
IndexType start_;

static constexpr bool reduces_dimension = false;

RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType map_index(const IndexType& idx) const {
return start_ + idx;
}

template<IndexType DIM, typename LayoutType>
RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType size(const LayoutType& layout) const {
return (layout.size() - start_);
}

RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType stride() const {
return 1;
}
};

template<typename IndexType = Index_type>
struct FixedSlice {
IndexType idx_;

static constexpr bool reduces_dimension = true;

RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType map_index(const IndexType&) const {
return idx_;
}

template<IndexType DIM, typename LayoutType>
RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType size(const LayoutType&) const {
return 1;
}

RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType stride() const {
return 1;
}

};

template<typename IndexType = Index_type>
struct NoSlice {
static constexpr bool reduces_dimension = false;

RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType map_index(const IndexType& idx) const {
return idx;
}

template<IndexType DIM, typename LayoutType>
RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType size(const LayoutType& layout) const {
return layout.template get_dim_size<DIM>();
}

RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType stride() const {
return 1;
}
};

template<typename IndexType = Index_type>
struct StridedSlice {
IndexType start_, end_, stride_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this support negative strides? I'm pretty sure that the strided range supports negative strides.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does support negative strides. For example, specifying stride = -1 is how we reverse the iteration order of a loop.


static constexpr bool reduces_dimension = false;

RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType map_index(const IndexType& idx) const {
return start_ + stride_ * idx;
}

template<IndexType DIM, typename LayoutType>
RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType size(const LayoutType&) const {
return (end_ - start_) / stride_ + 1;
}

RAJA_INLINE RAJA_HOST_DEVICE constexpr IndexType stride() const {
return stride_;
}
};

template<typename IndexType, typename... Slices>
RAJA_INLINE RAJA_HOST_DEVICE constexpr auto make_slice_to_parent_index_map() {
IndexType sub_idx = 0;
IndexType i = 0;
camp::array<IndexType, sizeof...(Slices)> map = {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not do something like this?

Suggested change
camp::array<IndexType, sizeof...(Slices)> map = {};
camp::array<IndexType, sizeof...(Slices)> map{};

((map[i++] = (Slices::reduces_dimension ? -1 : sub_idx++)), ...);
Comment on lines +133 to +134
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or even do something like this?

Suggested change
camp::array<IndexType, sizeof...(Slices)> map = {};
((map[i++] = (Slices::reduces_dimension ? -1 : sub_idx++)), ...);
camp::array<IndexType, sizeof...(Slices)> map{{(Slices::reduces_dimension ? -1 : sub_idx++)...}};

return map;
}

template<typename IndexType, size_t n_parent_dims, typename... Slices>
RAJA_INLINE RAJA_HOST_DEVICE constexpr auto make_parent_to_slice_index_map() {
Comment on lines +138 to +139
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make more sense to take n_parent_dims as an argument or calculate it inside?

IndexType sub_idx = 0;
IndexType i = 0;
camp::array<IndexType, n_parent_dims> map = {};

auto process_slice = [&](auto slice_type) constexpr {
if constexpr (!decltype(slice_type)::reduces_dimension) {
map[sub_idx++] = i++;
} else {
i++;
}
};

(process_slice(Slices{}), ...);

return map;
}

template <typename LayoutType, typename SliceTypes, typename IndexType = Index_type>
struct SubRegion;

/* SubLayout is a semantic alias for a SubRegion whose parent is a layout */
template <typename LayoutType, typename SliceTypes, typename IndexType = Index_type>
using SubLayout = SubRegion<LayoutType, SliceTypes, IndexType>;

/* SubView is a semantic alias for a SubRegion whose parent is a view */
template <typename LayoutType, typename SliceTypes, typename IndexType = Index_type>
using SubView = SubRegion<LayoutType, SliceTypes, IndexType>;

template <typename LayoutType, typename IndexType, typename... Slices>
struct SubRegion<LayoutType, camp::list<Slices...>, IndexType> {

using IndexLinear = IndexType;

const LayoutType& parent_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of having a copy of the parent this has a reference? What if you make the SubRegion on the host and then copy it to the device?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also what do you think about using the member variables are named with m_ and static members are named with s_ convention?

camp::tuple<Slices...> slices_;

static inline constexpr size_t num_slices_ = sizeof...(Slices);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Static data members and functions should be above non-static data members and functions.


static inline constexpr
IndexType n_dims = ((Slices::reduces_dimension == false ? 1 : 0) + ...);
Copy link
Member

@MrBurmark MrBurmark Nov 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about using Slices::reduces_dimension as a boolean if its a boolean?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like to have all the uses of something look similar if possible. I think this is often used like this !Slices::reduces_dimension so it would be simpler to understand if this also looked the same.


static inline constexpr
camp::array<IndexType, num_slices_> slice_to_parent_map_ =
make_slice_to_parent_index_map<IndexType, Slices...>();

static inline constexpr
camp::array<IndexType, n_dims> parent_to_slice_map_ =
make_parent_to_slice_index_map<IndexType, n_dims, Slices...>();

RAJA_INLINE RAJA_HOST_DEVICE constexpr SubRegion(const LayoutType& parent, Slices... slices)
: parent_(parent), slices_(slices...) { }

RAJA_INLINE RAJA_HOST_DEVICE constexpr auto& get_parent() const {
return parent_;
}

RAJA_INLINE RAJA_HOST_DEVICE constexpr auto& get_slices() const {
return slices_;
}

template<IndexType Index>
RAJA_INLINE RAJA_HOST_DEVICE constexpr auto& get_slice() const {
return camp::get<Index>(slices_);
}
Comment on lines +192 to +203
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there are const they should probably return const references.


RAJA_INLINE RAJA_HOST_DEVICE constexpr auto size() const {

IndexType prod_dims = 1;
for_each_tuple_index( slices_,
[&](auto slice, auto index) {
const IndexType dim_size = slice.template size<index>(parent_);
prod_dims *= (dim_size == 0) ? 1 : dim_size;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there really is a dimension that is completely projected out, shouldn't the size be 0?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also do we have to consider the 0 dimension case?

});

return prod_dims;
}

RAJA_INLINE RAJA_HOST_DEVICE constexpr auto size_noproj() const {

IndexType prod_dims = 1;
for_each_tuple_index( slices_,
[&](auto slice, auto index) {
prod_dims *= slice.template size<index>(parent_);
});

return prod_dims;
}

template<IndexType DIM>
RAJA_INLINE RAJA_HOST_DEVICE constexpr auto get_dim_size() const {
constexpr auto SliceDim = parent_to_slice_map_[DIM];
return camp::get<SliceDim>(slices_).template size<DIM>(parent_);
Comment on lines +230 to +231
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be able to static_assert that DIM is in bounds.

}

template<IndexType DIM>
RAJA_INLINE RAJA_HOST_DEVICE constexpr auto get_dim_stride() const {
constexpr auto SliceDim = parent_to_slice_map_[DIM];
return camp::get<SliceDim>(slices_).stride();
}

template <typename... Idxs>
RAJA_INLINE RAJA_HOST_DEVICE constexpr auto operator()(Idxs... idxs) const {
static_assert(sizeof...(idxs) == n_dims, "Wrong number of indices");

camp::array<IndexType, n_dims> arr{idxs...};
camp::array<IndexType, num_slices_> parent_indices;

for_each_tuple_index( slices_,
[&](auto slice, auto index) {
if (slice_to_parent_map_[index] >= 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be if constexpr?

parent_indices[index] = slice.map_index(arr[slice_to_parent_map_[index]]);
} else {
// map_index will not need index values for dimension-reducing slices
// so we pass a "dummy" value.
constexpr IndexType dummy_value = -1;
parent_indices[index] = slice.map_index(dummy_value);
Comment on lines +252 to +255
Copy link
Member

@MrBurmark MrBurmark Nov 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should dimension reducing slices not take a value at all?

}
});

return camp::apply(parent_, parent_indices);
}
};

template <typename LayoutType, typename... Slices>
SubRegion(LayoutType, Slices...) -> SubRegion<LayoutType, camp::list<Slices...>>;

} // namespace RAJA

#endif
17 changes: 16 additions & 1 deletion include/RAJA/util/TypedViewBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,16 +669,31 @@ class ViewBase
constexpr layout_type const& get_layout() const { return m_layout; }

RAJA_HOST_DEVICE

RAJA_INLINE
constexpr linear_index_type size() const { return m_layout.size(); }

RAJA_HOST_DEVICE
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes to View and MultiView are still a WIP.

RAJA_INLINE
constexpr linear_index_type size_noproj() const { return m_layout.size_noproj(); }

template<camp::idx_t DIM>
RAJA_INLINE RAJA_HOST_DEVICE constexpr linear_index_type get_dim_stride() const
{
return m_layout.template get_dim_stride<DIM>();
}

template<camp::idx_t DIM>
RAJA_HOST_DEVICE RAJA_INLINE constexpr linear_index_type get_dim_size() const
{
return m_layout.template get_dim_size<DIM>();
}

template<camp::idx_t DIM>
RAJA_INLINE RAJA_HOST_DEVICE constexpr linear_index_type get_dim_begin() const
{
return m_layout.template get_dim_begin<DIM>();
}

template<typename... Args>
RAJA_HOST_DEVICE RAJA_INLINE constexpr view_return_type_t<value_type,
pointer_type,
Expand Down
27 changes: 27 additions & 0 deletions include/RAJA/util/View.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ struct MultiView
using value_type = ValueType;
using pointer_type = PointerType;
using layout_type = LayoutType;
using linear_index_type = typename layout_type::IndexLinear;
using nc_value_type = camp::decay<value_type>;
using nc_pointer_type = NonConstPointerType;
using NonConstView =
Expand Down Expand Up @@ -228,6 +229,32 @@ struct MultiView
return layout;
}

RAJA_HOST_DEVICE
RAJA_INLINE
constexpr linear_index_type size() const { return layout.size(); }

RAJA_HOST_DEVICE
RAJA_INLINE
constexpr linear_index_type size_noproj() const { return layout.size_noproj(); }

template<camp::idx_t DIM>
RAJA_INLINE RAJA_HOST_DEVICE constexpr linear_index_type get_dim_stride() const
{
return layout.template get_dim_stride<DIM>();
}

template<camp::idx_t DIM>
RAJA_HOST_DEVICE RAJA_INLINE constexpr linear_index_type get_dim_size() const
{
return layout.template get_dim_size<DIM>();
}

template<camp::idx_t DIM>
RAJA_INLINE RAJA_HOST_DEVICE constexpr linear_index_type get_dim_begin() const
{
return layout.template get_dim_begin<DIM>();
}

RAJA_HOST_DEVICE RAJA_INLINE constexpr pointer_type get_data() const
{
return pointer_type(data);
Expand Down
Loading
Loading