[libcxx-commits] [PATCH] D103056: [libcxx][ranges] Add `ranges::transform_view`.
Arthur O'Dwyer via Phabricator via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Jun 25 07:32:09 PDT 2021
Quuxplusone added inline comments.
================
Comment at: libcxx/include/__ranges/concepts.h:108
+ template<bool _Const, class _Tp>
+ using __maybe_const = conditional_t<_Const, const _Tp, _Tp>;
} // namespace ranges
----------------
zoecarver wrote:
> Quuxplusone wrote:
> > zoecarver wrote:
> > > ldionne wrote:
> > > > Is this used anywhere else other than in `transform_view`? If not, let's put it in `transform_view.h` only.
> > > Yes, it's used in many views.
> > FWIW, I think the libc++ style here would be to name it either `__maybe_const_t` or `_MaybeConst`, and then stick it in `<type_traits>`.
> >
> > (The otherwise-badly-named `_Parent` and `_Base` typedefs repeated below are merely mirroring the Standard exposition-only wording; see `Parent` and `Base` in https://en.cppreference.com/w/cpp/ranges/transform_view/sentinel . So even though they're awfully ugly, I think `_Parent` and `_Base` are probably following the right course of action.)
> If you'd rather me put it in type traits that fine with me. But I want to keep the name the same. All of these exposition only concepts and type traits we do a mechanical transformation of `concept-or-trait` -> `__concept_or_trait`. Makes it easy to keep track of things, verify correctness, and reduce duplication.
Ah, I see https://eel.is/c++draft/ranges.syn has the exposition-only //`maybe-const`//. Weird that cppreference avoids //`maybe-const`// and just does the English description e.g. "`const V` if `Const` is true, otherwise `V`." Anyway, LGTM.
================
Comment at: libcxx/include/__ranges/transform_view.h:18
+#include <__ranges/empty.h>
+#include <__ranges/copyable_box.h>
+#include <__ranges/view_interface.h>
----------------
alphabetize plz
================
Comment at: libcxx/include/__ranges/transform_view.h:73-74
+
+ constexpr __iterator<false> begin()
+ noexcept(noexcept(ranges::begin(__base_)))
+ {
----------------
Teeechnically... it's impossible for humans to write noexcept-clauses. ;) Could you test locally with an iterator type like this, and report back if it prints `OK!`?
https://godbolt.org/z/fvxTo4n1v
================
Comment at: libcxx/include/__ranges/transform_view.h:98
+ constexpr __sentinel<true> end()
+ const noexcept(noexcept(ranges::end(__base_)))
+ requires range<const _View> &&
----------------
This `const` is on the wrong line; ditto on line 79 above; and then please rearrange these getters into any reasonable order (e.g. `begin`, `begin const`, `end`, `end const`). Right now they're in the order `begin const, begin, end, end const`, which combined with the lack of trailing `const` keyword, confused the heck out of me.
================
Comment at: libcxx/include/__ranges/transform_view.h:338
+ requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
+ friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel __y) {
+ return __x.__current_ == __y.__end_;
----------------
Either a missing `&` in `const __sentinel`, or a superfluous `const` — please decide which.
(On line 345 you went with the missing-`&` interpretation.)
[Grep your codebase today!](https://quuxplusone.github.io/blog/2019/01/03/const-is-a-contract/#grep-your-codebase-today)
================
Comment at: libcxx/include/optional:936
const value_type&&
- operator*() const&&
+ operator*() const&& noexcept
{
----------------
These noexcepts look great to me, but perhaps we should add a simple ~five-line test for them in `libcxx/test/libcxx/`.
================
Comment at: libcxx/test/std/ranges/range.adaptors/range.transform/general.pass.cpp:39
+auto withRandom(R range, Fn func = Fn()) {
+ return std::ranges::transform_view(range, std::bind_front(func, std::rand()));
+}
----------------
I don't understand what's going on here with `std::bind_front`, nor the defaulted function argument `func = Fn()`, but surely our unit tests should not depend on the behavior of `rand()`.
Please switch to e.g. `[](int x) { return x + 1; }` and remove the `bind` and default-function-argument stuff.
================
Comment at: libcxx/test/std/ranges/range.adaptors/range.transform/general.pass.cpp:45
+ return std::ranges::transform_view(a, [&a, &b, join](auto& x) {
+ auto idx = (&x) - a;
+ return join(x, b[idx]);
----------------
Is the point of this test to verify that `x` is in fact a reference into the original viewed range, and not a copy? If so, this could be more explicit. If not, then again this seems overly confusing and complicated.
================
Comment at: libcxx/test/std/ranges/range.adaptors/range.transform/general.pass.cpp:50-54
+template<>
+constexpr bool std::ranges::enable_view<std::vector<int>> = true;
+
+template<>
+constexpr bool std::ranges::enable_view<std::string_view> = true;
----------------
I assume lines 50-54 were here for polyfill purposes; they can be removed now that `enable_view` is in master, right?
================
Comment at: libcxx/test/support/test_iterators.h:234
- TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;}
+ TEST_CONSTEXPR_CXX14 reference operator*() const noexcept {return *it_;}
TEST_CONSTEXPR_CXX14 pointer operator->() const {return it_;}
----------------
This shouldn't be necessary. Not necessarily a //bad// idea, but unnecessary.
If we're going to `noexcept`-qualify our test iterators' `operator*`, `operator->`, and `operator[]`, that should be done consistently across //all// of the test iterator types, and it should be done in a separate PR so we can see what effect it has (if any) on the existing test suite.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D103056/new/
https://reviews.llvm.org/D103056
More information about the libcxx-commits
mailing list