[PATCH] libstdc++: Specialize ranges::__detail::__box for semiregular types

Jonathan Wakely jwakely@redhat.com
Thu Sep 24 14:59:04 GMT 2020


On 24/09/20 09:04 -0400, Patrick Palka via Libstdc++ wrote:
>The class template semiregular-box<T> defined in [range.semi.wrap] is
>used by a number of views to accomodate non-semiregular subobjects
>while ensuring that the overall view remains semiregular.  It provides
>a stand-in default constructor, copy assignment operator and move
>assignment operator whenever the underlying type lacks them.  The
>wrapper derives from std::optional<T> to support default construction
>when T is not default constructible.
>
>It would be nice for this wrapper to essentially be a no-op when the
>underlying type is already semiregular, but this is currently not the
>case due to its use of std::optional<T>, which incurs space overhead
>compared to storing just T.
>
>To that end, this patch specializes the semiregular wrapper for
>semiregular T.  Compared to the primary template, this specialization
>uses less space and it allows [[no_unique_address]] to optimize away
>wrapped data members whose underlying type is empty and semiregular
>(e.g. a non-capturing lambda).  This patch also applies
>[[no_unique_address]] to the five data members that currently use the
>wrapper.
>
>Tested on x86_64-pc-linux-gnu, does this look OK to commit?
>
>libstdc++-v3/ChangeLog:
>
>	* include/std/ranges (__detail::__boxable): Split out the
>	associated constraints of __box into here.
>	(__detail::__box): Use the __boxable concept.  Define a leaner
>	partial specialization for semiregular types.
>	(single_view::_M_value): Mark it [[no_unique_address]].
>	(filter_view::_M_pred): Likewise.
>	(transform_view::_M_fun): Likewise.
>	(take_while_view::_M_pred): Likewise.
>	(drop_while_view::_M_pred):: Likewise.
>	* testsuite/std/ranges/adaptors/detail/semiregular_box.cc: New
>	test.
>---
> libstdc++-v3/include/std/ranges               | 68 +++++++++++++++--
> .../ranges/adaptors/detail/semiregular_box.cc | 73 +++++++++++++++++++
> 2 files changed, 135 insertions(+), 6 deletions(-)
> create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/detail/semiregular_box.cc
>
>diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
>index e7fa4493612..8a302a7918f 100644
>--- a/libstdc++-v3/include/std/ranges
>+++ b/libstdc++-v3/include/std/ranges
>@@ -86,7 +86,10 @@ namespace ranges
>
>   namespace __detail
>   {
>-    template<copy_constructible _Tp> requires is_object_v<_Tp>
>+    template<typename _Tp>
>+      concept __boxable = copy_constructible<_Tp> && is_object_v<_Tp>;
>+
>+    template<__boxable _Tp>
>       struct __box : std::optional<_Tp>
>       {
> 	using std::optional<_Tp>::optional;
>@@ -130,6 +133,59 @@ namespace ranges
> 	}
>       };
>
>+    // For types which are already semiregular, this specialization of the
>+    // semiregular wrapper stores the object directly without going through
>+    // std::optional.  It provides the subset of the primary template's API
>+    // that we currently use.
>+    template<__boxable _Tp> requires semiregular<_Tp>
>+      struct __box<_Tp>
>+      {
>+      private:
>+	[[no_unique_address]] _Tp _M_value;
>+
>+      public:
>+	__box() = default;
>+
>+	constexpr
>+	__box(const _Tp& __t)
>+	noexcept(is_nothrow_copy_constructible_v<_Tp>)
>+	: _M_value{__t}
>+	{ }
>+
>+	constexpr
>+	__box(_Tp&& __t)

To be consistent with optional, these constructors should be
conditionally explicit (and since we're in C++20 code here, we can
actually use explicit(bool) rather than needing two overloads of each
constructor).

But I think we could just make them unconditionally explicit, since we
only ever construct them explicitly. No need to allow implicit
conversions if we never need them.

Otherwise this looks great, p[lease push. It's an ABI change for the
types using __box, so isn't appropriate for backporting to gcc-10
(unlike most changes to <ranges>).




More information about the Libstdc++ mailing list