On 17/07/25 11:26 -0400, Patrick Palka wrote:
On Thu, 17 Jul 2025, Tomasz Kamiński wrote:

From: Jonathan Wakely <jwak...@redhat.com>

Implement std::inplace_vector as specified in P0843R14, without follow
up papers, in particular P3074R7 (trivial unions). In consequence
inplace_vector<T, N> can be used inside constant evaluations only
if T is trivial of N is equal to zero.

... or N is ...


We provide a separate specialization for inplace_vector<T, 0> to meet
the requirements of N5008 [inplace.vector.overview] p5. In particular
objects of such types needs to be empty.

Can't we just make the _M_elems data member conditionally present in the
primary template and add N != 0 constraints where appropriate etc, or
would that be too ugly?


To allow contexpr variable of inplace_vector v, where v.size() < v.capacity(),

constexpr

we need to guaranteed that all elements of the storage array are initialized,
even ones in range [v.data() + v.size(), v.data() + v.capacity()). This is
perfomed by _M_init function, that is alled by each constructored. By storing
the array in animous union, we can perform this intialization in constant

anonymous, initialization

evaluation, avoiding the impact on runtime path.

The size() function conveys the information that _M_size <= _Nm to compiler,
by calling __builtin_unreachable(). In particular this allows us to eliminate
FP warnings by using _Nm - size() instead of _Nm - _M_size, when computing
available elements.

However, we still have one -Waggressive-loop-optimizations (to best of our
knowledge false-positive warning produced in cons/from_range.cc and
cons/throws.cc. Currently it is pruned using dg-prune-output and tracked by
PR121143.

The included test cover almost all code paths at runtime, however some
compile time evaluation test are not yet implemented:
* operations on range, they depenend on making testsuite_iterators constexpr
* negative test for invoking operations with preconditions at compile time,
  especially for zero size specialization.

        PR libstdc++/119137

libstdc++-v3/ChangeLog:

        * doc/doxygen/user.cfg.in (INPUT): Add new header.
        * include/Makefile.am: Add new header.
        * include/Makefile.in: Regenerate.
        * include/bits/version.def (inplace_vector): Define.
        * include/bits/version.h: Regenerate.
        * include/precompiled/stdc++.h: Include new header.
        * src/c++23/std.cc.in: Export contents if new header.
        * include/std/inplace_vector: New file.
        * testsuite/23_containers/inplace_vector/access/capacity.cc: New file.
        * testsuite/23_containers/inplace_vector/access/elem.cc: New file.
        * testsuite/23_containers/inplace_vector/access/elem_neg.cc: New file.
        * testsuite/23_containers/inplace_vector/cons/1.cc: New file.
        * testsuite/23_containers/inplace_vector/cons/from_range.cc: New file.
        * testsuite/23_containers/inplace_vector/cons/throws.cc: New file.
        * testsuite/23_containers/inplace_vector/copy.cc: New file.
        * testsuite/23_containers/inplace_vector/erasure.cc: New file.
        * testsuite/23_containers/inplace_vector/modifiers/assign.cc: New file.
        * testsuite/23_containers/inplace_vector/modifiers/erase.cc: New file.
        * testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc:
        New file.
        * testsuite/23_containers/inplace_vector/modifiers/single_insert.cc:
        New file.
        * testsuite/23_containers/inplace_vector/move.cc: New file.
        * testsuite/23_containers/inplace_vector/relops.cc: New file.
        * testsuite/23_containers/inplace_vector/version.cc: New file.
        * testsuite/util/testsuite_iterators.h (input_iterator_wrapper::base):
        Define.

Co-authored-by: Tomasz Kamiński <tkami...@redhat.com>
Signed-off-by: Tomasz Kamiński <tkami...@redhat.com>
---
Jonathan have provided initial implementation, that I (Tomasz) have
later finished and extended the test coverate. Details can be found at:
https://forge.sourceware.org/gcc/gcc-TEST/pulls/58

Tested on x86_64-linux. OK for trunk?

 libstdc++-v3/doc/doxygen/user.cfg.in          |    1 +
 libstdc++-v3/include/Makefile.am              |    1 +
 libstdc++-v3/include/Makefile.in              |    1 +
 libstdc++-v3/include/bits/version.def         |    8 +
 libstdc++-v3/include/bits/version.h           |   10 +
 libstdc++-v3/include/precompiled/stdc++.h     |    1 +
 libstdc++-v3/include/std/inplace_vector       | 1397 +++++++++++++++++
 libstdc++-v3/src/c++23/std.cc.in              |   10 +-
 .../inplace_vector/access/capacity.cc         |   51 +
 .../inplace_vector/access/elem.cc             |  103 ++
 .../inplace_vector/access/elem_neg.cc         |   29 +
 .../23_containers/inplace_vector/cons/1.cc    |  385 +++++
 .../inplace_vector/cons/from_range.cc         |  186 +++
 .../inplace_vector/cons/throws.cc             |  131 ++
 .../23_containers/inplace_vector/copy.cc      |  247 +++
 .../23_containers/inplace_vector/erasure.cc   |   49 +
 .../inplace_vector/modifiers/assign.cc        |  386 +++++
 .../inplace_vector/modifiers/erase.cc         |  117 ++
 .../inplace_vector/modifiers/multi_insert.cc  |  611 +++++++
 .../inplace_vector/modifiers/single_insert.cc |  215 +++
 .../23_containers/inplace_vector/move.cc      |  358 +++++
 .../23_containers/inplace_vector/relops.cc    |   60 +
 .../23_containers/inplace_vector/version.cc   |   20 +
 .../testsuite/util/testsuite_iterators.h      |    6 +
 24 files changed, 4382 insertions(+), 1 deletion(-)
 create mode 100644 libstdc++-v3/include/std/inplace_vector
 create mode 100644 
libstdc++-v3/testsuite/23_containers/inplace_vector/access/capacity.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/inplace_vector/cons/throws.cc
 create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/inplace_vector/erasure.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc
 create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/inplace_vector/relops.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc

diff --git a/libstdc++-v3/doc/doxygen/user.cfg.in 
b/libstdc++-v3/doc/doxygen/user.cfg.in
index 536e035b023..8969bb8b948 100644
--- a/libstdc++-v3/doc/doxygen/user.cfg.in
+++ b/libstdc++-v3/doc/doxygen/user.cfg.in
@@ -869,6 +869,7 @@ INPUT                  = @srcdir@/doc/doxygen/doxygroups.cc 
\
                          include/functional \
                          include/future \
                          include/generator \
+                         include/inplace_vector \
                          include/iomanip \
                          include/ios \
                          include/iosfwd \
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index cc402f0648f..6f248fe48cb 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -77,6 +77,7 @@ std_headers = \
        ${std_srcdir}/forward_list \
        ${std_srcdir}/fstream \
        ${std_srcdir}/future \
+       ${std_srcdir}/inplace_vector \
        ${std_srcdir}/iomanip \
        ${std_srcdir}/ios \
        ${std_srcdir}/iosfwd \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 0ef8564f238..014466fc40b 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -433,6 +433,7 @@ std_freestanding = \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/forward_list \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/fstream \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/future \
+@GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/inplace_vector \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/iomanip \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/ios \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/iosfwd \
diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 2f70a529927..dbe2cb8f175 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1988,6 +1988,14 @@ ftms = {
   };
 };

+ftms = {
+  name = inplace_vector;
+  values = {
+    v = 202406;
+    cxxmin = 26;
+  };
+};
+
 ftms = {
   name = indirect;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 8e0ae682251..7bb6016df68 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2229,6 +2229,16 @@
 #endif /* !defined(__cpp_lib_modules) && defined(__glibcxx_want_modules) */
 #undef __glibcxx_want_modules

+#if !defined(__cpp_lib_inplace_vector)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_inplace_vector 202406L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_inplace_vector)
+#   define __cpp_lib_inplace_vector 202406L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_inplace_vector) && 
defined(__glibcxx_want_inplace_vector) */
+#undef __glibcxx_want_inplace_vector
+
 #if !defined(__cpp_lib_indirect)
 # if (__cplusplus >  202302L) && _GLIBCXX_HOSTED
 #  define __glibcxx_indirect 202502L
diff --git a/libstdc++-v3/include/precompiled/stdc++.h 
b/libstdc++-v3/include/precompiled/stdc++.h
index e7d89c92704..733a5e5fb0b 100644
--- a/libstdc++-v3/include/precompiled/stdc++.h
+++ b/libstdc++-v3/include/precompiled/stdc++.h
@@ -237,6 +237,7 @@
 #endif

 #if __cplusplus > 202302L
+#include <inplace_vector>
 #include <text_encoding>
 #include <stdbit.h>
 #include <stdckdint.h>
diff --git a/libstdc++-v3/include/std/inplace_vector 
b/libstdc++-v3/include/std/inplace_vector
new file mode 100644
index 00000000000..780d84821ee
--- /dev/null
+++ b/libstdc++-v3/include/std/inplace_vector
@@ -0,0 +1,1397 @@
+// Sequence container with fixed capacity -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/inplace_vector
+ *  This is a Standard C++ Library header.
+ *  @ingroup sequences
+ */
+
+#ifndef _GLIBCXX_INPLACE_VECTOR
+#define _GLIBCXX_INPLACE_VECTOR 1
+
+#pragma GCC system_header
+
+#define __glibcxx_want_inplace_vector
+#include <bits/version.h>
+
+#ifdef __cpp_lib_inplace_vector

Maybe add a

// C++ >= 26

comment to this preprocessor condition

+#include <compare>
+#include <initializer_list>
+#include <bits/range_access.h>
+#include <bits/ranges_base.h> // borrowed_iterator_t, 
__detail::__container_compatible_range
+#include <bits/ranges_util.h> // subrange
+#include <bits/ranges_uninitialized.h>
+#include <bits/refwrap.h>
+#include <bits/stl_construct.h>
+#include <bits/stl_uninitialized.h>
+#include <bits/stl_algo.h> // rotate
+#include <ranges> // for views::as_rvalue TODO: move to another header?

Looks like as_rvalue is no longer needed can we get of this include?

+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+namespace __detail
+{
+  // Is a Cpp17InputIterator or satisfies std::input_iterator.
+  template<typename _InputIterator>
+    concept __input_iterator
+      = input_iterator<_InputIterator>
+         || derived_from<__iter_category_t<_InputIterator>,
+                         input_iterator_tag>;

There's __has_input_iter_cat which we can use here.
I wonder why does inplace_vector specifically need to check
for both C++20 and legacy InputIterators?  I don't think other
containers do this currently.

They don't, but maybe they should (PR 100070, and the work I've been
doing for std::distance and std::prev for PR 102181).

Reply via email to