From: Jonathan Wakely <jwakely@redhat.com>
To: Patrick Palka <ppalka@redhat.com>
Cc: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org
Subject: Re: [PATCH 2/2] libstdc++: P1739R4 Avoid template bloat for safe_ranges in combination with ...
Date: Thu, 20 Feb 2020 09:51:00 -0000 [thread overview]
Message-ID: <20200220095101.GT9441@redhat.com> (raw)
In-Reply-To: <20200220045332.1385014-2-ppalka@redhat.com>
On 19/02/20 23:53 -0500, Patrick Palka wrote:
>... 'subrange-y' view adaptors
>
>This implements an interpretation of P1739R4. It's only an "interpretation"
>becuase AFAICT there is an issue with the paper's wording as-is. So this patch
>deviates from paper when it comes to the problematic wording.
>
>The issue is that the paper's wording for views::take requires that the
>views::take of a specialization of subrange is not just another subrange, but
>specifically is the same specialization as the input subrange.
>But if, say, the input subrange does not model common_range, then the expression
>in section 6.1
>
> T{begin(E), begin(E) + min(size(E), F)}
>
>is ill-formed because T -- a specialization of subrange which does not model
>common_range -- must be constructed with an iterator-sentinel pair and not an
>iterator-iterator pair. A similar issue arises with the views::take of an
>iota_view whose value type differs from the type of its bound.
>
>So in light of this issue, this patch deviates from the paper's wording here by
>allowing the views::take of a subrange/iota_view input to be a different
>specialization than that of the input.
>
>Moreover, I found myself needing to define an extra constrained constructor
>iota_view(iterator_, iterator_) alongside the newly added
>iota_view(iterator_, sentinel_) constructor, so that the expression
>in views::take
>
> iota_view<ValueType,ValueType>{begin(E), begin(E) + min(size(E), F)}
>
>is well-formed in general. Despite these deviations, the intended end result
>remains the same AFAICT.
Please be sure to report these to the LWG chair address so issues can
be opened.
>@@ -1965,10 +1993,70 @@ namespace views
>
> namespace views
> {
>+ namespace __detail
>+ {
>+ template<typename _Tp>
>+ inline constexpr bool __is_empty_view = false;
>+
>+ template<typename _Tp>
>+ inline constexpr bool __is_empty_view<empty_view<_Tp>> = true;
>+
>+ template<typename _Tp>
>+ inline constexpr bool __is_dynamic_span = false;
>+
>+ template<typename _Tp>
>+ inline constexpr bool __is_dynamic_span<span<_Tp, dynamic_extent>>
>+ = true;
>+
>+ template<typename _Tp>
>+ inline constexpr bool __is_basic_string_view = false;
>+
>+ template<typename _CharT, typename _Traits>
>+ inline constexpr bool
>+ __is_basic_string_view<basic_string_view<_CharT, _Traits>> = true;
I think it should be possible to define these without including <span>
and <string_view>. Either by adding forward declarations of span and
basic_string_view, which is sufficient to define the variable template
specializations, or by defining something here and specializing it in
<span> and <string_view> e.g. in <ranges>:
template<typename _Tp>
inline constexpr bool __is_viewish = false;
And then in <span> add:
template<typename _Tp>
extern inline const bool __is_viewish;
template<typename _Tp>
inline constexpr bool __is_viewish<span<_Tp>> = true;
The first declaration is needed so that <span> works without including
<ranges>, and vice versa.
And in <string_view>:
#if __cplusplus > 201703L
template<typename _Tp>
extern inline const bool __is_viewish;
template<typename _Ch, typename _Tr>
inline constexpr bool __is_viewish<basic_string_view<_Ch, _Tr>>
= true;
#endif
That way we don't need to declare span and string_view in <ranges> at
all. We also don't need two separate variables, one will do. And
finally, doing it this way allows us to enable this feature for
experimental::basic_string_view too:
And in <experimental/string_view>:
#if __cplusplus > 201703L
template<typename _Tp>
extern inline const bool __is_viewish;
template<typename _Ch, typename _Tr>
inline constexpr bool
__is_viewish<experimental::basic_string_view<_Ch, _Tr>> = true;
#endif
This last specialization *must* be defined in
<experimental/string_view> not in <ranges>, because we don't want to
"leak" the non-reserved "experimental" name into <ranges> when the
user hasn't explicitly included a TS header.
A better name than "viewish" would be nice, but it does look like we
can use the same one for span and string_view, since you always treat
them the same.
>+
>+ template<typename _Tp>
>+ inline constexpr bool __is_iota_view = false;
>+
>+ template<weakly_incrementable _Winc, semiregular _Bound>
>+ inline constexpr bool __is_iota_view<iota_view<_Winc, _Bound>> = true;
>+
>+ template<typename _Tp>
>+ inline constexpr bool __is_subrange = false;
>+
>+ template<typename _It, typename _Sent, subrange_kind _Kind>
>+ inline constexpr bool
>+ __is_subrange<subrange<_It, _Sent, _Kind>> = true;
>+ }
>+
> inline constexpr __adaptor::_RangeAdaptor take
>- = [] <viewable_range _Range, typename _Tp> (_Range&& __r, _Tp&& __n)
>+ = [] <viewable_range _Range> (_Range&& __r, range_difference_t<_Range> __n)
> {
>- return take_view{std::forward<_Range>(__r), std::forward<_Tp>(__n)};
>+ using _Tp = remove_cvref_t<_Range>;
>+ if constexpr (__detail::__is_empty_view<_Tp>)
>+ return std::forward<_Range>(__r);
>+ else if constexpr (random_access_range<_Tp> && sized_range<_Tp>)
>+ {
>+ // XXX: we diverge from P1739R4 here in the way we fold iota_view
>+ // and subrange.
>+ auto __begin = ranges::begin(__r);
>+ auto __size = std::min<decltype(__n)>(ranges::size(__r), __n);
>+ if constexpr (__detail::__is_dynamic_span<_Tp>
>+ || __detail::__is_basic_string_view<_Tp>)
>+ return _Tp{__begin, __begin + __size};
>+ else if constexpr (__detail::__is_iota_view<_Tp>)
>+ {
>+ using _ValueType = range_value_t<_Tp>;
>+ return iota_view<_ValueType, _ValueType>{__begin,
>+ __begin + __size};
>+ }
>+ else if constexpr (__detail::__is_subrange<_Tp>)
>+ return subrange{__begin, __begin + __size};
>+ else
>+ return take_view{std::forward<_Range>(__r), __n};
>+ }
>+ else
>+ return take_view{std::forward<_Range>(__r), __n};
> };
> } // namespace views
>
>@@ -2135,9 +2223,24 @@ namespace views
> namespace views
> {
> inline constexpr __adaptor::_RangeAdaptor drop
>- = [] <viewable_range _Range, typename _Tp> (_Range&& __r, _Tp&& __n)
>+ = [] <viewable_range _Range> (_Range&& __r, range_difference_t<_Range> __n)
> {
>- return drop_view{std::forward<_Range>(__r), std::forward<_Tp>(__n)};
>+ using _Tp = remove_cvref_t<_Range>;
>+ if constexpr (__detail::__is_empty_view<_Tp>)
>+ return std::forward<_Range>(__r);
>+ else if constexpr (random_access_range<_Tp> && sized_range<_Tp>
>+ && (__detail::__is_dynamic_span<_Tp>
>+ || __detail::__is_basic_string_view<_Tp>
>+ || __detail::__is_iota_view<_Tp>
>+ || __detail::__is_subrange<_Tp>))
>+ {
>+ auto __begin = ranges::begin(__r);
>+ auto __size = std::min<decltype(__n)>(ranges::size(__r), __n);
>+ auto __end = ranges::end(__r);
>+ return _Tp{__begin + __size, __end};
>+ }
>+ else
>+ return drop_view{std::forward<_Range>(__r), __n};
> };
> } // namespace views
>
>@@ -2903,7 +3006,9 @@ namespace views
> constexpr auto
> operator()(_Iter __i, iter_difference_t<_Iter> __n) const
> {
>- if constexpr (random_access_iterator<_Iter>)
>+ if constexpr (contiguous_iterator<_Iter>)
>+ return span{to_address(std::move(__i)), __n};
Ah, this means we need to include <span> in <ranges> anyway. That's
OK, span isn't the biggest header. I'd still like to avoid including
<string_view> if possible though.
next prev parent reply other threads:[~2020-02-20 9:51 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-20 4:53 [PATCH 1/2] libstdc++: Forward second argument of views::iota using the correct type Patrick Palka
2020-02-20 4:53 ` [PATCH 2/2] libstdc++: P1739R4 Avoid template bloat for safe_ranges in combination with Patrick Palka
2020-02-20 9:51 ` Jonathan Wakely [this message]
2020-02-20 17:35 ` Patrick Palka
2020-02-20 9:24 ` [PATCH 1/2] libstdc++: Forward second argument of views::iota using the correct type Jonathan Wakely
2020-02-20 17:53 ` Patrick Palka
2020-02-20 18:40 ` Jonathan Wakely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200220095101.GT9441@redhat.com \
--to=jwakely@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=libstdc++@gcc.gnu.org \
--cc=ppalka@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).