mdarray: Add container_to_accessor customization point(s)
Nobody has claimed this yet.
- Dominant language
- HTML
- Stars
- 29
- Forks
- 26
- PR merge metrics
- No merged PRs in 30d
Description
Problem: Conversion to mdspan assumes default_accessor
As of P1684R3, mdarray has two conversions to mdspan.
operator mdspan()to_mdspan(const OtherAccessor&)
Both of these assume that default_accessor applies to the container, and that default_accessor is convertible to the returned mdspan type's accessor type. This is acceptable for the use case of viewing a contiguous container's memory. Users can view the mdarray in a particular context with a special accessor (that e.g., uses atomic_ref or restrict) by calling to_mdspan with an accessor of the desired type. However, this design has the following issues.
- It strips away any compile-time access restrictions that the container's
operator[]might have. - It only works if the result of the container's
data()method is convertible toElementType*, and represents an array of at leastrequired_span_size()elements.
Regarding (1): An example is that the container might contain a GPU device allocation that is not accessible from normal host code. The container's operator[] might have annotations that make calling it from host code a compile-time error. Even if we have an mdspan "device_only_accessor" with the analogous feature, it's still possible with the current mdarray design to convert an mdarray to an mdspan with default_accessor. This would strip away the protection that the container offers.
Regarding (2): This is not the same syntactically as a "contiguous container," but is semantically close. It prevents use of containers to express things like remote memory allocations (in the PGAS sense: e.g., NVSHMEM or MPI 1-sided). We can express access to remote memory allocations and other non-raw-pointer-things with mdspan, but we can't with mdarray.
Solution: Container-to-accessor customization point(s)
Add to P1684 a container_to_accessor customization point that defines a custom mapping from container to accessor. mdarray's default mapping would use default_accessor, but users could override this for custom container types (i.e., container types not in the Standard Library). Any conversion of mdarray to mdspan would use this container-to-accessor mapping. operator mdspan() would use it to determine the container's accessor type, to see if it can be converted to the left-hand-side's accessor type. to_mdspan(const OtherAccessor& other) member function would use this in the same way (asking whether the container's accessor can be converted to other).
Container-to-accessor mapping is one to one
This design relies on a one-to-one container-to-accessor mapping. In particular, users would need a custom container to express "you can't access this memory on host"; they could not just use a custom allocator with std::vector. We think this is correct. For instance, users cannot change the compile-time behavior of std::vector::operator[] with a custom allocator.
Overloads for const and nonconst container reference
This is actually two customization points:
container_to_accessor(container_type&)for use when the mdarray is called in a nonconst context, andcontainer_to_accessor(const container_type&)for use when the mdarray is called in a const context.
The difference could matter for performance. For example, read-only access to remote memory could be cached without coherence. mdarray would use the appropriate overload based on context, so users would only need to define container_to_accessor(const container_type&) to cover both cases.
Customization point syntax
Here is our intent.
- Users may not override the container-to-accessor mapping for existing container types in the Standard Library.
- If users override the container-to-accessor mapping for a custom container type, then mdarray will use this overridden mapping. In that case, it is a compile-time error (Mandates) if the mapping is needed for nonconst mdarray, but the user only provides the mapping for
const container_type&. - Otherwise, if the container's
.data()method is convertible toElementType*(orconst ElementType*if called in a const context), then the default container-to-accessor mapping isdefault_accessor<ElementType>(resp.default_accessor<const ElementType>).
This behaves like ranges::swap: a single function-ish thing for mdarray to call, that can dispatch either to user-defined behavior or default behavior. The question, then, is what syntax to use to express this. The phrase "customization point" strongly suggests [customization.point.object] (CPO), or at least the intent to inhibit argument-dependent lookup. WG21 hasn't given clear guidance yet on whether CPOs, tag_invoke, or some not-yet-ratified syntax is the approved way to implement customization points. It's not so important to us what syntax to use, as long as users can do something simple, like define functions container_to_accessor(container_type&) and container_to_accessor(const container_type&) for us to ADL-find.
Earlier versions of P1684 had contemplated a "ContainerPolicy" template parameter that would define both the container type, and its associated accessor type. This would prevent the need for a customization point. However, this design has several issues.
- It would complicate common use cases, for which the default container-to-accessor mapping suffices.
- It would make the name of the mdarray (with its template arguments) less transparent.
- It could give the incorrect impression that mdarray uses the accessor policy to access the container. mdarray always uses the container's
operator[]directly; it does not access the container indirectly through an accessor.
An advantage of the customization point design is that if users never convert an mdarray to mdspan, then a container-to-accessor mapping need not even exist.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the P1684R3 mdarray-to-mdspan conversions described in the issue, then compare the proposed const and nonconst container_to_accessor customization points with the existing default_accessor behavior. Done means the proposal specifies a workable customization syntax and defines how both mdarray conversion paths select or reject the resulting accessor.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100