[libcxx-commits] [PATCH] D107396: [libcxx][ranges] Add `ranges::iota_view`.
Christopher Di Bella via Phabricator via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Aug 3 14:03:50 PDT 2021
cjdb added a comment.
Mostly LGTM, but a few blockers before I'm happy to give it a green light. A few more comments below.
- Can you please implement `std::ranges::views::iota` as well? That one doesn't need a closure, so we can* get away with adding it in this patch.
- Don't forget the range concept conformance test.
- You've got a 2.5K log file at the end of this; I don't think that's supposed to be there.
================
Comment at: libcxx/include/__ranges/iota_view.h:64
+ using _IotaDiffT = _If<
+ (!is_integral_v<_Start> || sizeof(iter_difference_t<_Start>) > sizeof(_Start)),
+ iter_difference_t<_Start>,
----------------
Not that I super care, but why is this `is_integral_v` and not `integral`?
================
Comment at: libcxx/include/__ranges/iota_view.h:98
+ class iota_view : public view_interface<iota_view<_Start, _Bound>> {
+ struct __iterator : public __iota_iterator_category<_Start> {
+ friend class iota_view;
----------------
I really find it cluttering that the iterator is defined inside the range. Took me a whole two minutes to realise I was no longer reviewing `iota_view`, but rather `iota_view::__iterator`. (Two mins is probably a slight exaggeration, but it took me longer than I'd have liked.)
Can we please move the definition out-of-line to improve readability?
================
Comment at: libcxx/include/__ranges/iota_view.h:105-117
+ using iterator_concept = _If<
+ __advanceable<_Start>,
+ random_access_iterator_tag,
+ _If<
+ __decrementable<_Start>,
+ bidirectional_iterator_tag,
+ _If<
----------------
================
Comment at: libcxx/include/__ranges/iota_view.h:122
+ __iterator() requires default_initializable<_Start> = default;
+ constexpr explicit __iterator(_Start __value) : __value_(_VSTD::move(__value)) {}
+
----------------
Since this type is exposition-only, I think we can make this constructor private. That'll lead to fewer users attempting to declare an iterator outright.
================
Comment at: libcxx/include/__ranges/iota_view.h:131-133
+ }
+ constexpr void operator++(int) { ++*this; }
+ constexpr __iterator operator++(int) requires incrementable<_Start> {
----------------
================
Comment at: libcxx/include/__ranges/iota_view.h:186-190
+ friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
+ requires equality_comparable<_Start>
+ {
+ return __x.__value_ == __y.__value_;
+ }
----------------
I'm surprised this can't be just `= default;`
================
Comment at: libcxx/include/__ranges/iota_view.h:244-247
+ if (__y.__value_ > __x.__value_) {
+ return difference_type(-difference_type(__y.__value_ - __x.__value_));
+ }
+ return difference_type(__x.__value_ - __y.__value_);
----------------
I'd also like to see conditional operator use, but the salient feature of the suggested edit is the added else-clause.
================
Comment at: libcxx/include/__ranges/iota_view.h:249
+ }
+ return __x.__value_ - __y.__value_;
+ }
----------------
================
Comment at: libcxx/include/__ranges/iota_view.h:261
+ __sentinel() = default;
+ constexpr explicit __sentinel(_Bound __bound) : __bound_(_VSTD::move(__bound)) {}
+
----------------
Suggest making this private to limit user-touchability.
================
Comment at: libcxx/include/__ranges/iota_view.h:284
+ public:
+ iota_view() requires default_initializable<_Start> = default;
+
----------------
I know the standard has this, but I don't think it's strictly necessary?
================
Comment at: libcxx/include/__ranges/iota_view.h:289
+ constexpr iota_view(type_identity_t<_Start> __value, type_identity_t<_Bound> __bound)
+ : __value_(_VSTD::move(__value)), __bound_(_VSTD::move(__bound)) {}
+
----------------
I'd really like to see the precondition partially applied, particularly for integers, which are a very common use-case for `iota_view`. Same with the above constructor.
================
Comment at: libcxx/include/__ranges/iota_view.h:317-318
+ constexpr auto size() const
+ requires (same_as<_Start, _Bound> && __advanceable<_Start>) || (integral<_Start> && integral<_Bound>) ||
+ sized_sentinel_for<_Bound, _Start>
+ {
----------------
It took me editing this to realise that `sized_sentinel_for` doesn't have parens at all.
================
Comment at: libcxx/include/__ranges/iota_view.h:320-327
+ if constexpr (__integer_like<_Start> && __integer_like<_Bound>) {
+ if (__value_ < 0) {
+ if (__bound_ < 0) {
+ return __to_unsigned_like(-__value_) - __to_unsigned_like(-__bound_);
+ }
+ return __to_unsigned_like(__bound_) + __to_unsigned_like(-__value_);
+ }
----------------
I'd honestly prefer a conditional expression here.
================
Comment at: libcxx/include/__ranges/iota_view.h:329
+ }
+ return __to_unsigned_like(__bound_ - __value_);
+ }
----------------
Please put this in an else-clause to account for constexpr instantiation..
================
Comment at: libcxx/test/std/ranges/range.factories/range.iota.view/iterator/compare.pass.cpp:1
+//===----------------------------------------------------------------------===//
+//
----------------
Please add commented-out tests for `<=>`, or a FIXME, or both. We also still need to test `!=` is `not (x == y)`.
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