[libcxx-commits] [PATCH] D107396: [libcxx][ranges] Add `ranges::iota_view`.
Louis Dionne via Phabricator via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Aug 10 12:23:50 PDT 2021
ldionne requested changes to this revision.
ldionne added inline comments.
This revision now requires changes to proceed.
================
Comment at: libcxx/include/__ranges/iota_view.h:1
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
----------------
Can you also add `views::iota` in this patch? It's just a CPO, so it doesn't require the range adaptor stuff (which is close to being done BTW).
================
Comment at: libcxx/include/__ranges/iota_view.h:27
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
----------------
Not necessary.
================
Comment at: libcxx/include/__ranges/iota_view.h:43-60
+ template<class _Int>
+ struct __get_wider_signed {
+ static_assert(sizeof(_Int) <= sizeof(long long),
+ "Found integer-like type that is bigger than largest integer like type.");
+ using type = long long;
+ };
+
----------------
================
Comment at: libcxx/include/__ranges/iota_view.h:63
+ template<class _Start>
+ using _IotaDiffT = _If<
+ (!integral<_Start> || sizeof(iter_difference_t<_Start>) > sizeof(_Start)),
----------------
Can you please add tests that checks the member typedefs of `iota_view::iterator` itself? In particular, I'd like to confirm that `iterator_difference_t` is deduced correctly when `W::difference_type` has sizes less than `short`, `int`, `long`, etc.
Note per our discussion: If it's not possible to have `W::difference_type` both be an integral type and be smaller than `short`, we should perhaps add a `static_assert` to keep us honest about it. But as we discussed, I think it is possible by having `W::difference_type` be `char`.
================
Comment at: libcxx/include/__ranges/iota_view.h:66
+ iter_difference_t<_Start>,
+ typename __get_wider_signed<_Start>::type
+ >;
----------------
This `_If` is too eager. It will fail if you pass a non-integer-like-type to it that is larger than `sizeof(long long)`, because you will eagerly instantiate `__get_wider_signed_integer` here and fail in the `static_assert`. This can be fixed by changing to this (not super pretty because we lack `iter_difference`, but oh-well):
```
template<class _Start>
using _IotaDiffT = typename _If<
(!integral<_Start> || sizeof(iter_difference_t<_Start>) > sizeof(_Start)),
type_identity<iter_difference_t<_Start>>,
__get_wider_signed<_Start>
>::type;
```
Can you add a test with a non-integer type with a size that's larger than `long long` and confirm that it fails? If it does not fail, we'll learn something interesting. If it does, we can fix it.
================
Comment at: libcxx/include/__ranges/iota_view.h:98
+ class iota_view : public view_interface<iota_view<_Start, _Bound>> {
+ // Not all compilers handle bool the same way. For consistency we just ban it.
+ static_assert(!std::same_as<_Start, bool>,
----------------
I think the correct location to fix this issue is in whatever concept currently accepts `bool` when it shouldn't, which is `weakly_incrementable` IIUC. So I would suggest fixing that in `weakly_incrementable` with a `&& !same_as<bool, T>`, along with a test that `bool` doesn't model `weakly_incrementable` (which we must be lacking right now), and also a TODO comment to remove the special case for `bool` once Clang has been fixed.
================
Comment at: libcxx/include/__ranges/iota_view.h:282
+ __sentinel() = default;
+ constexpr explicit __sentinel(_Bound __bound) : __bound_(_VSTD::move(__bound)) {}
+
----------------
Nit: make sure you test explicitness.
================
Comment at: libcxx/include/__ranges/iota_view.h:312
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr explicit iota_view(_Start __value) : __value_(_VSTD::move(__value)) { }
+
----------------
Do you test the explicitness by checking `!std::is_convertible`? If not, please do.
================
Comment at: libcxx/include/__ranges/iota_view.h:318-320
+ if constexpr ((integral<_Start> || is_pointer_v<_Start>) &&
+ (integral<_Bound> || is_pointer_v<_Bound>)) {
+ _LIBCPP_ASSERT(ranges::less_equal()(__value_, __bound_),
----------------
That would match the spec better.
================
Comment at: libcxx/include/__ranges/iota_view.h:331
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr iota_view(__iterator __first, unreachable_sentinel_t __last)
+ requires same_as<_Bound, unreachable_sentinel_t>
----------------
This is very nitpicky, but I would rather define this as `iota_view(__iterator __first, _Bound __last)` even though those are the same, simply because it matches the spec more closely and IMO it is easier to read that way (see http://eel.is/c++draft/range.iota#view-11.2).
================
Comment at: libcxx/include/__ranges/iota_view.h:362
+ {
+ if constexpr (__integer_like<_Start> && __integer_like<_Bound>) {
+ if (__value_ < 0) {
----------------
Can you please add tests at boundary conditions like `numeric_limits<T>::max()` & friends?
================
Comment at: libcxx/include/__ranges/iota_view.h:375-378
+ template<class _Start, class _Bound>
+ requires (!__integer_like<_Start> || !__integer_like<_Bound> ||
+ (__signed_integer_like<_Start> == __signed_integer_like<_Bound>))
+ iota_view(_Start, _Bound) -> iota_view<_Start, _Bound>;
----------------
Possible spec issue:
I'm kind of wondering why we don't define the constructor like this instead, and avoid defining a deduction guide altogether:
```
constexpr iota_view(W value, Bound bound)
requires (!is-integer-like<W> || !is-integer-like<Bound> ||
(is-signed-integer-like<W> == is-signed-integer-like<Bound>));
```
As specified in the Standard, we have the following situation, which seems to be weird and inconsistent:
```
iota_view<signed, unsigned> view(x, y); // works
iota_view view((signed)x, (unsigned)y); // doesn't work
```
I think both of them should not work.
@tcanens is that intentional?
================
Comment at: libcxx/test/std/ranges/range.factories/range.iota.view/begin.pass.cpp:11
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
----------------
Not necessary anymore, we don't support GCC 10.
I have a patch to remove them everywhere, but it would be nice if we stopped introducing those in new patches from now on.
================
Comment at: libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/minus.pass.cpp:48
+
+// TODO: it seems odd that this is the *only* place we are required to have an input_or_output_iterator.
+// Example: https://godbolt.org/z/WGc9xoqcb
----------------
Instead, can we add tests to confirm that this *doesn't* work? Can we file a LWG issue to relax this requirement? If this is indeed issue-worthy, our test is going to fail when we fix it, as it should.
================
Comment at: libcxx/test/std/ranges/range.factories/range.iota.view/types.h:1
+#ifndef TEST_STD_RANGES_RANGE_FACTORIES_RANGE_IOTA_VIEW_TYPES_H
+#define TEST_STD_RANGES_RANGE_FACTORIES_RANGE_IOTA_VIEW_TYPES_H
----------------
Missing license.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D107396/new/
https://reviews.llvm.org/D107396
More information about the libcxx-commits
mailing list