[PATCH] libstdc++: Add std::inplace_vector for C++26 (P0843R14) [PR119137]
Jonathan Wakely
jwakely@redhat.com
Thu Jul 17 16:05:23 GMT 2025
On 17/07/25 11:26 -0400, Patrick Palka wrote:
>On Thu, 17 Jul 2025, Tomasz Kamiński wrote:
>
>> From: Jonathan Wakely <jwakely@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 <tkaminsk@redhat.com>
>> Signed-off-by: Tomasz Kamiński <tkaminsk@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).
More information about the Libstdc++
mailing list