ORNL / ORNL/cpp-proposals-pub

Notes for mdarray Review

Open
#284 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
HTML
Stars
29
Forks
26
PR merge metrics
No merged PRs in 30d

Description

Super Brief mdarray introduction

Why we want mdarray

Creating a simple 2D array with mdspan requires multiple steps because mdspan is non-owning.

// Create a mapping:
layout_left map(extents(N,M));

// Create an allocation
vector<int> data(map.required_span_size());

// Create mdspan:
mdspan a(data.data(), map);

mdarray is a multidimensional array with value-semantics and makes the above simpler

// default layout
mdarray a(N,M);
// other layout
mdarray b(layout_left(extents(N,M))); 
What aspects of mdspan does mdarray have

mdarray has the

  • element_type,
  • extents and
  • layout policy aspects of mdspan

The accessor policy is replaced by a container type.

template<class ElementType, class Extents, class Layout, class Accessor>
class mdspan {
   public:
   ...
     template<class ... Indices>
     reference operator [] (Indices ... idx) const { return acc_.access(ptr_, map_(idx...)); }
   private:
     typename Accessor::data_handle_type ptr_;
     Layout::mapping<Extents> map_;
     Accessor acc_;
};

template<class ElementType, class Extents, class Layout, class Container>
class mdarray {
   public:
   ...
     template<class ... Indices>
     reference operator [] (Indices ... idx) { return ctr_[map_(idx...)]); }

   private:
     Layout::mapping<Extents> map_;
     Container ctr_;
};

This means mdarray does not have the kind of access modality customization point functionality of mdspan, but that functionality is anyway intended for local specialization of accesses, and thus more suited for the view-like class.

Design considerations
Constructors

mdarray is like a container adaptor (e.g. queue). It provides a different interface for the underlying container.
Now the question is what does that mean for constructors.

Due to its mdspan roots it should be constructible from the size like arguments, e.g.

  • integer packs,
  • extents, and
  • mappings.

For analogy with containers, and container adaptors we also gain construction from the

  • underlying container,
  • initializer lists,
  • iterator pairs and
  • ranges.

However, mdarray always needs the size information in addition, since these arguments are simple 1D ranges, making this problem combinatorial.

Furthermore, we likely want versions of each of these with an allocator argument, providing a factor of 2

And then we want all the usual copy/move/conversion constructors.

Putting that all together makes us implement 41 constructors ...

An alternative to explicitly spelling them all out is having pack forwarding constructors:

template<class ... Args>
requires(is_constructible_v<container_type, Args...>)
mdarray(mapping_type map, Args ... args):map_(map), ctr_(args...) {}
Deduction Guides

We like want deduction guides for most all of those constructors, but we haven't added them yet.

An issue with custom containers

Generally, we will construct containers from sizes or iterators, ranges etc.
We need to know that the container is actually large enough after construction to be indexed into up to map_.required_span_size().

mdarray(const mapping_type& map):map_(map),ctr_(map.required_span_size()) {}

template<class InputIterator>
mdarray(InputIterator first, InputIterator last, const mapping_type& map):
  map_(map), ctr_(first, last) {}

Generally we can know the intended size:

  • map.required_span_size()
  • distance(first, last)
  • some_container.size()

We can have preconditions on things like the distance(first, last) being at least the map.required_span_size()

But: How do we know that the constructed container has the right size

  • Sequence container requirements have some of semantics
  • BUT: we don't want to require sequence container with all its baggage.

Thus we are proposing (somewhat optimistically) a new named container requirement.

  • every requirement is optional: i.e. if the following expressions are well formed, they have the specified semantics
  • Postcondition for each expression that the size is right.
Size matching of containers and mappings.
  • We explicitly require that if you construct an mdarray from some existing set of elements (container, iterators, range, etc.), that the implied size of those arguments is larger or equal to the mappings required_span_size().

  • The larger or equal is intentional, because the mapping may already be not exhaustive.

    • I.e. the mdarray may not end up accessing all elements in its own container. But in that case it is not clear why having unused elements at the end should be different from having unused elements somewhere else in the container.
Conversion to mdspan

There are a number of possible approaches for getting an mdspan from and mdarray

  • operator mdspan: mdarray has all the information to create an mdspan so conversion operator is possible. We even can make a templated one to possibly avoid double construction in conversion cases.
  • deduction guide for mdspan(mdarray): works in conjunction with operator mdspan.
  • member function mdarray::view which returns an mdspan.

Generally there isn't much you can do with the explicit member function you can't do with the combination of operator mdspan and the deduction guide,
however this path is not available to user defined types, which are not allowed to define new deduction guides for classes in the standard library.
Thus we likely need a customization point anyway for creating mdspans and mdarray should likely implement that too.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No files, tests, or implementation entry points are named. Start by reviewing the mdarray design notes in this issue and identify the unresolved constructor, container-requirement, deduction-guide, and mdspan-conversion decisions; done would require an agreed design and a concrete implementation scope.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.