An open API service indexing awesome lists of open source software.

https://github.com/brevzin/span_ext

Comparison operators for std::span
https://github.com/brevzin/span_ext

cpp cpp20 span

Last synced: 7 months ago
JSON representation

Comparison operators for std::span

Awesome Lists containing this project

README

          

# span_ext

When `std::span` was added by [P0122](https://wg21.link/p0122), it had comparison
operators that performed a deep comparison. Those comparison operators were
removed as a result of [P1085](https://wg21.link/p1085).

I disagree with that removal - I do not consider it important that `span`
be Regular (and am not even sure that a deep-comparing fail fails to model
[`std::equality_comparable`](http://eel.is/c++draft/concept.equalitycomparable))
and I consider comparisons for `std::span` to be quite useful, and that as a
result we're missing functionality.

The goal of this repository is to provide that missing functionality, if you
choose to use it, and to gather feedback about the use of these operations.
If this repo proves broadly useful, then we should reconsider P1085. If this
repo reveals problems with `std::span` having deep comparison, then I will
reconsider my position.

Note that this repository does provide comparison operators in `namespace std`.
This is technically UB, as only the standard library is allowed to put things
in there (outside of specific exceptions, like providing specializations for
specific class templates in `std`), but these operators do not exist today so
there is nothing to conflict with.

# Design

Given the premise that `std::span` should have deep comparisons, the question
is what comparisons should be allowed? Should `std::span` be comparable
with:

1. `std::span`?
2. `std::vector`?
3. `std::list`?
4. `std::vector`?

My position is that `span`'s direct comparison operators should behave basically
like a `memcmp` - the easy-to-use syntax should only be there when you're
directly comparing blocks of memory. To that end, (1) and (2) should be allowed
(differing `const`ness is irrelevant and we don't care who owns the block of
memory) but comparing against (3) non-contiguous containers or (4) containers
of a different type are not supported. There is always `std::ranges::equal` for
that.

In other words, in this repo,
`span` is comparable with any `contiguous_range` with
`value_type` `U` such that `remove_cvref_t` and `remove_cvref_t` are the
same type.

Note that while with this design, you can compare a `span` to a `vector`,
it will still be the case that `std::equality_comparable_with, vector>`
fails while `std::equality_comparable_with, vector>` holds.
This is because `span` and `vector` do not share a common reference
(while `span` and `vector` do) - because `span` is not
constructible from a `vector` rvalue.

# Usage

Just include `` and it's as if `std::span` itself had
comparison operators already.

# Compiler requirements

These operators depend on the existence of `std::span`, the Concepts language
feature, some of the functionality introduced by Ranges, and `<=>`.

As a polyfill the standard library concepts and Ranges, this library will
fall back to using range-v3.

This library currently works with:

- gcc trunk
- clang-10 with range-v3

# Building and Testing

To test with clang-10, you need to also use range-v3. That can be done as follows:

```
$ mkdir build && cd build
$ CC=$(which clang) CXX=$(which clang-10) cmake -G Ninja -DCMAKE_CXX_FLAGS="-std=c++20 -Wall -Wextra" -DSPAN_EXT_LIBCXX=On -DSPAN_EXT_RANGE_V3_PATH=/path/to/range-v3 -DSPAN_EXT_TESTS=On ..
$ ninja
$ ninja test
```