Since the standard range adaptors are specified to derive from the empty
class view_base, making their first data member store the underlying
view is suboptimal, for if the underlying view also derives from
view_base then the two view_base subobjects will be adjacent, thus
preventing the compiler from applying the empty base optimization to
elide away the storage for these two empty bases.

This patch improves the situation by declaring the _M_base data member
last instead of first in each range adaptor that has more than one data
member, so that the empty base optimization can apply more often.

Tested on x86_64-pc-linux-gnu with and wihout -m32.

libstdc++-v3/ChangeLog:

        * include/std/ranges (filter_view::_M_base): Declare this data
        member last.
        (transform_view::_M_base): Likewise.
        (take_view::_M_base): Likewise.
        (take_while_view::_M_base): Likewise.
        (drop_view::_M_base): Likewise.
        (drop_while_view::_M_base): Likewise.
        (join_view::_M_base): Likewise.
        (split_view::_M_base): Likewise.
        * testsuite/std/ranges/adaptors/sizeof.cc: Adjust expected
        sizes.
---
 libstdc++-v3/include/std/ranges                | 17 ++++++++---------
 .../testsuite/std/ranges/adaptors/sizeof.cc    | 18 +++++++++---------
 2 files changed, 17 insertions(+), 18 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 964a2b616a6..6fd8a85c2bf 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -1250,9 +1250,9 @@ namespace views
        { return __y.__equal(__x); }
       };
 
-      _Vp _M_base = _Vp();
       [[no_unique_address]] __detail::__box<_Pred> _M_pred;
       [[no_unique_address]] __detail::_CachedPosition<_Vp> _M_cached_begin;
+      _Vp _M_base = _Vp();
 
     public:
       filter_view() = default;
@@ -1588,8 +1588,8 @@ namespace views
          friend _Sentinel<!_Const>;
        };
 
-      _Vp _M_base = _Vp();
       [[no_unique_address]] __detail::__box<_Fp> _M_fun;
+      _Vp _M_base = _Vp();
 
     public:
       transform_view() = default;
@@ -1695,8 +1695,8 @@ namespace views
          friend _Sentinel<!_Const>;
        };
 
-      _Vp _M_base = _Vp();
       range_difference_t<_Vp> _M_count = 0;
+      _Vp _M_base = _Vp();
 
     public:
       take_view() = default;
@@ -1842,8 +1842,8 @@ namespace views
          friend _Sentinel<!_Const>;
        };
 
-      _Vp _M_base = _Vp();
       [[no_unique_address]] __detail::__box<_Pred> _M_pred;
+      _Vp _M_base = _Vp();
 
     public:
       take_while_view() = default;
@@ -1902,8 +1902,8 @@ namespace views
     class drop_view : public view_interface<drop_view<_Vp>>
     {
     private:
-      _Vp _M_base = _Vp();
       range_difference_t<_Vp> _M_count = 0;
+      _Vp _M_base = _Vp();
 
       // ranges::next(begin(base), count, end(base)) is O(1) if _Vp satisfies
       // both random_access_range and sized_range. Otherwise, cache its result.
@@ -2002,9 +2002,9 @@ namespace views
     class drop_while_view : public view_interface<drop_while_view<_Vp, _Pred>>
     {
     private:
-      _Vp _M_base = _Vp();
       [[no_unique_address]] __detail::__box<_Pred> _M_pred;
       [[no_unique_address]] __detail::_CachedPosition<_Vp> _M_cached_begin;
+      _Vp _M_base = _Vp();
 
     public:
       drop_while_view() = default;
@@ -2300,12 +2300,11 @@ namespace views
          friend _Sentinel<!_Const>;
        };
 
-      _Vp _M_base = _Vp();
-
       // XXX: _M_inner is "present only when !is_reference_v<_InnerRange>"
       [[no_unique_address]]
        __detail::__maybe_present_t<!is_reference_v<_InnerRange>,
                                    views::all_t<_InnerRange>> _M_inner;
+      _Vp _M_base = _Vp();
 
     public:
       join_view() = default;
@@ -2680,8 +2679,8 @@ namespace views
          { ranges::iter_swap(__x._M_i_current(), __y._M_i_current()); }
        };
 
-      _Vp _M_base = _Vp();
       _Pattern _M_pattern = _Pattern();
+      _Vp _M_base = _Vp();
 
       // XXX: _M_current is "present only if !forward_range<V>"
       [[no_unique_address]]
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc
index 5fb1ab7e4da..a7f622bb725 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc
@@ -33,17 +33,17 @@ using V = ranges::subrange<int*, int*>;
 constexpr auto ptr = sizeof(int*);
 static_assert(sizeof(V) == 2*ptr);
 
-static_assert(sizeof(ranges::take_view<V>) == 4*ptr);
-static_assert(sizeof(ranges::drop_view<V>) == 4*ptr);
+static_assert(sizeof(ranges::take_view<V>) == 3*ptr);
+static_assert(sizeof(ranges::drop_view<V>) == 3*ptr);
 
-static_assert(sizeof(ranges::filter_view<V, decltype(&pred_f)>) == 5*ptr);
-static_assert(sizeof(ranges::take_while_view<V, decltype(&pred_f)>) == 4*ptr);
-static_assert(sizeof(ranges::drop_while_view<V, decltype(&pred_f)>) == 5*ptr);
-static_assert(sizeof(ranges::transform_view<V, decltype(&func_f)>) == 4*ptr);
+static_assert(sizeof(ranges::filter_view<V, decltype(&pred_f)>) == 4*ptr);
+static_assert(sizeof(ranges::take_while_view<V, decltype(&pred_f)>) == 3*ptr);
+static_assert(sizeof(ranges::drop_while_view<V, decltype(&pred_f)>) == 4*ptr);
+static_assert(sizeof(ranges::transform_view<V, decltype(&func_f)>) == 3*ptr);
 
-static_assert(sizeof(ranges::filter_view<V, decltype(pred_l)>) == 4*ptr);
+static_assert(sizeof(ranges::filter_view<V, decltype(pred_l)>) == 3*ptr);
 static_assert(sizeof(ranges::take_while_view<V, decltype(pred_l)>) == 3*ptr);
-static_assert(sizeof(ranges::drop_while_view<V, decltype(pred_l)>) == 4*ptr);
+static_assert(sizeof(ranges::drop_while_view<V, decltype(pred_l)>) == 3*ptr);
 static_assert(sizeof(ranges::transform_view<V, decltype(func_l)>) == 3*ptr);
 
-static_assert(sizeof(ranges::split_view<V, std::string_view>) == 5*ptr);
+static_assert(sizeof(ranges::split_view<V, std::string_view>) == 4*ptr);
-- 
2.28.0.618.g9bc233ae1c

Reply via email to