ORNL / cpp-proposals-pub

Collaborating on papers for the ISO C++ committee - public repo
26 stars 27 forks source link

Issaquah (Feb 2023) P2630R2 presentation #328

Open mhoemmen opened 1 year ago

mhoemmen commented 1 year ago

P2630R2: submdspan

submdspan: multidimensional array slicing

R2 changes

Customization point mechanism

crtrott commented 1 year ago

Submdspan Recap

submdspan lets you take subsets of a an mdspan

An example:

// Some data representing 2x3 matrices
double data[6] = { 11, 12, 13,
                   21, 22, 23 };
// An rank-2 mdspan of the data
mdspan matrix(data, 2, 3);

mdspan<double,extents<size_t, dynamic_extent>, layout_stride>
   col_0 = submdspan(matrix, full_extent, 0);
// col_0 == 11, 21
// col_0.stride(0) == 3

mdspan<double,extents<size_t, dynamic_extent>, layout_right>
   row_1 = submdspan(matrix, 1, full_extent);
// row_1 == 21, 22, 23
// row_1.stride(0) == 1

// in practice this is a place where auto is your friend:
auto row_0 = submdspan(matrix, 0, full_extent);

submdspan in our proposal is effectively implemented as:

// submdspan takes and mdspan and slice specifiers
template<class T, class E, class L, class A, class ... SliceArgs)
auto submdspan(const mdspan<T,E,L,A>& src, SliceArgs ... args) {
  // get the new accessor from the old one
  typename A::offset_policy sub_acc(src.accessor());

  // get new mapping as well as linear offset from submdspan_mapping
  // This function is a customization point and will be called using ADL!
  // returns an aggregate type "submdspan_mapping_result" 
  auto sub_map = submdspan_mapping(src.mapping(), args...);

  // Check that we didn't get an invalid submdspan_mapping impl
  #ifndef NDEBUG
  // submdspan_extents is NOT a customization point.
  auto expected_extents = submdspan_extents(src.extents(), args...); 
  // check that the types match
  static_assert(is_same_v<decltype(sub_map.mapping)::extent_type, 
                        decltype(expected_extents)>);
  // check that the values match
  assert(expected_extents==sub_map.mapping.extents());
  #endif

  // Compute the new data handle
  auto sub_handle = src.accessor().offset(src.data_handle(), sub_map.offset);

  // return the new mdspan
  return mdspan(sub_handle, sub_map.mapping, sub_acc);
}

Incorporated feedback from last review:

Return Type of submdspan_mapping

Changed from pair to a specific named aggregate type.

Before:

template<class Extents, class... SliceSpecifiers>
    constexpr auto submdspan_mapping(
      const layout_left::mapping<Extents>& src, 
      SliceSpecifiers ... slices) {
   ...
   return pair{new_mapping, offset};
}

Now:

template<class LayoutMapping>
struct submdspan_mapping_result {
  LayoutMapping mapping;
  size_t offset;
};

template<class Extents, class... SliceSpecifiers>
    constexpr auto submdspan_mapping(
      const layout_left::mapping<Extents>& src, 
      SliceSpecifiers ... slices) {
   ...
   return submdspan_mapping_result{new_mapping, offset};
}

Explore Customization Point Design

General Considerations

Explicit Opt-In

Diagnose Incorrect Opt-In

Associated Types

We concluded: Pure ADL is good enough for us.

crtrott commented 1 year ago

GodBolt example of custom layout/accessor in combo with submdspan: https://godbolt.org/z/EhMrYvTfo