[libcxx-commits] [libcxx] [libc++] Implement `std::inplace_vector<T, N>` (PR #105981)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Nov 8 04:25:01 PST 2024
================
@@ -0,0 +1,1091 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_INPLACE_VECTOR
+#define _LIBCPP_INPLACE_VECTOR
+
+/*
+ inplace_vector synopsis
+
+// mostly freestanding
+#include <compare> // see [compare.syn]
+#include <initializer_list> // see [initializer.list.syn]
+
+namespace std {
+ // [inplace.vector], class template inplace_vector
+ template<class T, size_t N>
+ class inplace_vector { // partially freestanding
+ public:
+ // types:
+ using value_type = T;
+ using pointer = T*;
+ using const_pointer = const T*;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ using iterator = implementation-defined; // see [container.requirements]
+ using const_iterator = implementation-defined; // see [container.requirements]
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ // [inplace.vector.cons], construct/copy/destroy
+ constexpr inplace_vector() noexcept;
+ constexpr explicit inplace_vector(size_type n); // freestanding-deleted
+ constexpr inplace_vector(size_type n, const T& value); // freestanding-deleted
+ template<class InputIterator>
+ constexpr inplace_vector(InputIterator first, InputIterator last); // freestanding-deleted
+ template<container-compatible-range<T> R>
+ constexpr inplace_vector(from_range_t, R&& rg); // freestanding-deleted
+ constexpr inplace_vector(const inplace_vector&);
+ constexpr inplace_vector(inplace_vector&&)
+ noexcept(N == 0 || is_nothrow_move_constructible_v<T>);
+ constexpr inplace_vector(initializer_list<T> il); // freestanding-deleted
+ constexpr ~inplace_vector();
+ constexpr inplace_vector& operator=(const inplace_vector& other);
+ constexpr inplace_vector& operator=(inplace_vector&& other)
+ noexcept(N == 0 || (is_nothrow_move_assignable_v<T> &&
+ is_nothrow_move_constructible_v<T>));
+ constexpr inplace_vector& operator=(initializer_list<T>); // freestanding-deleted
+ template<class InputIterator>
+ constexpr void assign(InputIterator first, InputIterator last); // freestanding-deleted
+ template<container-compatible-range<T> R>
+ constexpr void assign_range(R&& rg); // freestanding-deleted
+ constexpr void assign(size_type n, const T& u); // freestanding-deleted
+ constexpr void assign(initializer_list<T> il); // freestanding-deleted
+
+ // iterators
+ constexpr iterator begin() noexcept;
+ constexpr const_iterator begin() const noexcept;
+ constexpr iterator end() noexcept;
+ constexpr const_iterator end() const noexcept;
+ constexpr reverse_iterator rbegin() noexcept;
+ constexpr const_reverse_iterator rbegin() const noexcept;
+ constexpr reverse_iterator rend() noexcept;
+ constexpr const_reverse_iterator rend() const noexcept;
+
+ constexpr const_iterator cbegin() const noexcept;
+ constexpr const_iterator cend() const noexcept;
+ constexpr const_reverse_iterator crbegin() const noexcept;
+ constexpr const_reverse_iterator crend() const noexcept;
+
+ // [inplace.vector.capacity] size/capacity
+ constexpr bool empty() const noexcept;
+ constexpr size_type size() const noexcept;
+ static constexpr size_type max_size() noexcept;
+ static constexpr size_type capacity() noexcept;
+ constexpr void resize(size_type sz); // freestanding-deleted
+ constexpr void resize(size_type sz, const T& c); // freestanding-deleted
+ static constexpr void reserve(size_type n); // freestanding-deleted
+ static constexpr void shrink_to_fit() noexcept;
+
+ // element access
+ constexpr reference operator[](size_type n);
+ constexpr const_reference operator[](size_type n) const;
+ constexpr reference at(size_type n); // freestanding-deleted
+ constexpr const_reference at(size_type n) const; // freestanding-deleted
+ constexpr reference front();
+ constexpr const_reference front() const;
+ constexpr reference back();
+ constexpr const_reference back() const;
+
+ // [inplace.vector.data], data access
+ constexpr T* data() noexcept;
+ constexpr const T* data() const noexcept;
+
+ // [inplace.vector.modifiers], modifiers
+ template<class... Args>
+ constexpr reference emplace_back(Args&&... args); // freestanding-deleted
+ constexpr reference push_back(const T& x); // freestanding-deleted
+ constexpr reference push_back(T&& x); // freestanding-deleted
+ template<container-compatible-range<T> R>
+ constexpr void append_range(R&& rg); // freestanding-deleted
+ constexpr void pop_back();
+
+ template<class... Args>
+ constexpr pointer try_emplace_back(Args&&... args);
+ constexpr pointer try_push_back(const T& x);
+ constexpr pointer try_push_back(T&& x);
+ template<container-compatible-range<T> R>
+ constexpr ranges::borrowed_iterator_t<R> try_append_range(R&& rg);
+
+ template<class... Args>
+ constexpr reference unchecked_emplace_back(Args&&... args);
+ constexpr reference unchecked_push_back(const T& x);
+ constexpr reference unchecked_push_back(T&& x);
+
+ template<class... Args>
+ constexpr iterator emplace(const_iterator position, Args&&... args); // freestanding-deleted
+ constexpr iterator insert(const_iterator position, const T& x); // freestanding-deleted
+ constexpr iterator insert(const_iterator position, T&& x); // freestanding-deleted
+ constexpr iterator insert(const_iterator position, size_type n, // freestanding-deleted
+ const T& x);
+ template<class InputIterator>
+ constexpr iterator insert(const_iterator position, // freestanding-deleted
+ InputIterator first, InputIterator last);
+ template<container-compatible-range<T> R>
+ constexpr iterator insert_range(const_iterator position, R&& rg); // freestanding-deleted
+ constexpr iterator insert(const_iterator position, // freestanding-deleted
+ initializer_list<T> il);
+ constexpr iterator erase(const_iterator position);
+ constexpr iterator erase(const_iterator first, const_iterator last);
+ constexpr void swap(inplace_vector& x)
+ noexcept(N == 0 || (is_nothrow_swappable_v<T> &&
+ is_nothrow_move_constructible_v<T>));
+ constexpr void clear() noexcept;
+
+ constexpr friend bool operator==(const inplace_vector& x,
+ const inplace_vector& y);
+ constexpr friend synth-three-way-result<T>
+ operator<=>(const inplace_vector& x, const inplace_vector& y);
+ constexpr friend void swap(inplace_vector& x, inplace_vector& y)
+ noexcept(N == 0 || (is_nothrow_swappable_v<T> &&
+ is_nothrow_move_constructible_v<T>))
+ { x.swap(y); }
+ };
+
+ // [inplace.vector.erasure], erasure
+ template<class T, size_t N, class U = T>
+ constexpr typename inplace_vector<T, N>::size_type
+ erase(inplace_vector<T, N>& c, const U& value);
+ template<class T, size_t N, class Predicate>
+ constexpr typename inplace_vector<T, N>::size_type
+ erase_if(inplace_vector<T, N>& c, Predicate pred);
+} // namespace std
+*/
+
+#include <__algorithm/copy.h>
+#include <__algorithm/equal.h>
+#include <__algorithm/lexicographical_compare_three_way.h>
+#include <__algorithm/min.h>
+#include <__algorithm/move.h>
+#include <__algorithm/move_backward.h>
+#include <__algorithm/remove.h>
+#include <__algorithm/remove_if.h>
+#include <__algorithm/rotate.h>
+#include <__algorithm/swap_ranges.h>
+#include <__compare/synth_three_way.h>
+#include <__config>
+#include <__cstddef/size_t.h>
+#include <__iterator/distance.h>
+#include <__iterator/iterator_traits.h>
+#include <__iterator/move_iterator.h>
+#include <__iterator/reverse_iterator.h>
+#include <__iterator/size.h>
+#include <__iterator/wrap_iter.h>
+#include <__memory/addressof.h>
+#include <__memory/construct_at.h>
+#include <__memory/pointer_traits.h>
+#include <__memory/voidify.h>
+#include <__ranges/access.h>
+#include <__ranges/concepts.h>
+#include <__ranges/container_compatible_range.h>
+#include <__ranges/dangling.h>
+#include <__ranges/from_range.h>
+#include <__type_traits/conditional.h>
+#include <__type_traits/is_nothrow_assignable.h>
+#include <__type_traits/is_nothrow_constructible.h>
+#include <__type_traits/is_swappable.h>
+#include <__type_traits/is_trivially_assignable.h>
+#include <__type_traits/is_trivially_constructible.h>
+#include <__type_traits/is_trivially_destructible.h>
+#include <__type_traits/is_trivially_relocatable.h>
+#include <__utility/cmp.h>
+#include <__utility/forward.h>
+#include <__utility/unreachable.h>
+#include <new>
+#include <stdexcept>
+
+// standard-mandated includes
+
+// [inplace.vector.syn]
+#include <compare>
+#include <initializer_list>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 26
+
+template <class _Tp, size_t _Capacity>
+class _LIBCPP_TEMPLATE_VIS inplace_vector;
+
+template <size_t _MaximumPadding, size_t _Capacity>
+_LIBCPP_HIDE_FROM_ABI auto __inplace_vector_size_type() {
+ if constexpr (_MaximumPadding >= sizeof(size_t)) {
+ // Unconditionally use size_t in this case. Using a smaller size
+ // will not change the size of the inplace_vector because it will
+ // only introduce more padding bits
+ return static_cast<size_t>(0);
+ } else if constexpr (_Capacity <= static_cast<unsigned char>(-1) && (sizeof(unsigned char) < sizeof(size_t))) {
+ return static_cast<unsigned char>(0);
+ } else if constexpr (_Capacity <= static_cast<unsigned short>(-1) && (sizeof(unsigned short) < sizeof(size_t))) {
+ return static_cast<unsigned short>(0);
+ } else if constexpr (_Capacity <= static_cast<unsigned int>(-1) && (sizeof(unsigned int) < sizeof(size_t))) {
+ return static_cast<unsigned int>(0);
+ } else if constexpr (_Capacity <= static_cast<unsigned long>(-1) && (sizeof(unsigned long) < sizeof(size_t))) {
+ return static_cast<unsigned long>(0);
+ } else {
+ return static_cast<size_t>(0);
+ }
+}
+
+[[__noreturn__]] _LIBCPP_HIDE_FROM_ABI inline void __inplace_vector_throw_out_of_range() {
+ __throw_out_of_range("inplace_vector");
+ unreachable();
+}
+
+template <class _Tp, size_t _Capacity>
+class _LIBCPP_TEMPLATE_VIS __inplace_vector_array {
+ friend inplace_vector<_Tp, _Capacity>;
+ using __small_size_type = decltype(__inplace_vector_size_type<alignof(_Tp), _Capacity>());
+
+ union {
+ _Tp __elems_[_Capacity];
+ };
+ __small_size_type __sz_;
+
+ // When __constexpr is true, do not actually destroy any elements
+ // so that this can be used as a constexpr variable (otherwise it
+ // would be rejected for being uninitialized)
+ static constexpr bool __constexpr = is_trivially_default_constructible_v<_Tp> && is_trivially_destructible_v<_Tp>;
+ static constexpr bool __trivial_copy_construct = is_trivially_copy_constructible_v<_Tp>;
+ static constexpr bool __trivial_move_construct = is_trivially_move_constructible_v<_Tp>;
+ static constexpr bool __trivial_copy_assign =
+ is_trivially_destructible_v<_Tp> && is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_assignable_v<_Tp>;
+ static constexpr bool __trivial_move_assign =
+ is_trivially_destructible_v<_Tp> && is_trivially_move_constructible_v<_Tp> && is_trivially_move_assignable_v<_Tp>;
+
+ constexpr _LIBCPP_HIDE_FROM_ABI __inplace_vector_array() noexcept : __sz_(0) {
+ if consteval {
+ extern _LIBCPP_HIDE_FROM_ABI void
+ __this_inplace_vector_cannot_be_used_in_a_constant_expression_because_the_type_is_not_trivial();
+ __this_inplace_vector_cannot_be_used_in_a_constant_expression_because_the_type_is_not_trivial();
+ }
+
+ // Start the lifetime of the array without starting the lifetime
+ // of any of its elements
+ // TODO: When start_lifetime_as is implemented on all compilers, remove
+ // this conditional
+# ifdef __cpp_lib_start_lifetime_as
+ std::start_lifetime_as<_Tp[_Capacity]>(__elems_);
+# else
+ ::new (std::__voidify(__elems_)) unsigned char[sizeof(_Tp[_Capacity])];
+# endif
+ }
+ constexpr _LIBCPP_HIDE_FROM_ABI __inplace_vector_array() noexcept
+ requires(__constexpr)
+ : __elems_(), __sz_(0) {
+ if !consteval {
+ std::destroy(__elems_, __elems_ + _Capacity);
+ }
+ }
+ constexpr _LIBCPP_HIDE_FROM_ABI __inplace_vector_array(const __inplace_vector_array&) noexcept
+ /* strengthened */
+ requires(__trivial_copy_construct)
+ = default;
+ constexpr _LIBCPP_HIDE_FROM_ABI __inplace_vector_array(__inplace_vector_array&&) noexcept
+ /* strengthened */
+ requires(__trivial_move_construct)
+ = default;
+
+ constexpr _LIBCPP_HIDE_FROM_ABI ~__inplace_vector_array() {
+ __small_size_type __size = __sz_;
+ __sz_ = 0;
+ std::destroy(__elems_, __elems_ + __size);
+ }
+ constexpr _LIBCPP_HIDE_FROM_ABI ~__inplace_vector_array()
+ requires(is_trivially_destructible_v<_Tp>)
+ = default;
+
+ constexpr _LIBCPP_HIDE_FROM_ABI __inplace_vector_array& operator=(const __inplace_vector_array&) noexcept
+ requires(__trivial_copy_assign)
+ = default;
+ constexpr _LIBCPP_HIDE_FROM_ABI __inplace_vector_array& operator=(__inplace_vector_array&&) noexcept
+ requires(__trivial_move_assign)
+ = default;
+
+ using __trivially_relocatable =
+ __conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, inplace_vector<_Tp, _Capacity>, void>;
+};
+
+template <class _Tp>
+class _LIBCPP_TEMPLATE_VIS __inplace_vector_array<_Tp, 0> {
+private:
+ friend inplace_vector<_Tp, 0>;
+ using __small_size_type = size_t;
+
+ static constexpr bool __constexpr = true;
+ static constexpr bool __trivial_copy_construct = true;
+ static constexpr bool __trivial_move_construct = true;
+ static constexpr bool __trivial_copy_assign = true;
+ static constexpr bool __trivial_move_assign = true;
+
+ static_assert((static_cast<_Tp (*)[1]>(nullptr) == nullptr), "inplace_vector<T, 0> must still have a valid T");
+ static constexpr _Tp* __elems_ = nullptr;
+ static constexpr __small_size_type __sz_ = 0;
+
+ constexpr _LIBCPP_HIDE_FROM_ABI __inplace_vector_array() noexcept = default;
+ constexpr _LIBCPP_HIDE_FROM_ABI __inplace_vector_array(const __inplace_vector_array&) noexcept /* strengthened */ =
+ default;
+ constexpr _LIBCPP_HIDE_FROM_ABI __inplace_vector_array(__inplace_vector_array&&) noexcept = default;
+ constexpr _LIBCPP_HIDE_FROM_ABI ~__inplace_vector_array() = default;
+
+ constexpr _LIBCPP_HIDE_FROM_ABI __inplace_vector_array& operator=(const __inplace_vector_array&) noexcept = default;
+ constexpr _LIBCPP_HIDE_FROM_ABI __inplace_vector_array& operator=(__inplace_vector_array&&) noexcept = default;
+
+ using __trivially_relocatable = inplace_vector<_Tp, 0>;
+};
+
+template <class _Tp, size_t _Capacity>
+class _LIBCPP_TEMPLATE_VIS inplace_vector : private __inplace_vector_array<_Tp, _Capacity> {
+ using __base = __inplace_vector_array<_Tp, _Capacity>;
+ using __base::__elems_, __base::__sz_;
+ using __small_size_type = __base::__small_size_type;
+
+ static constexpr _LIBCPP_HIDE_FROM_ABI bool __do_destroy() noexcept {
+ if consteval {
+ // Do not destroy elements of the array in a constant expression
+ return !__base::__constexpr;
+ }
+ return true;
+ }
+
+public:
+ // types
+ using value_type = _Tp;
+ using pointer = _Tp*;
+ using const_pointer = const _Tp*;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS
+ using iterator = __bounded_iter<__wrap_iter<pointer>>;
+ using const_iterator = __bounded_iter<__wrap_iter<const_pointer>>;
+# else
+ using iterator = __wrap_iter<pointer>;
+ using const_iterator = __wrap_iter<const_pointer>;
+# endif
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ using __trivially_relocatable = __base::__trivially_relocatable;
+
+ // [inplace.vector.cons], construct/copy/destroy
+ constexpr _LIBCPP_HIDE_FROM_ABI inplace_vector() noexcept = default;
+ constexpr _LIBCPP_HIDE_FROM_ABI explicit inplace_vector(size_type __n) : inplace_vector() {
+ if (__n > capacity())
+ __throw_bad_alloc();
+ // TODO: investigate optimization for trivially constructible _Tp that,
+ // for small _Capacity, unconditionally value_construct all the elements to turn
+ // "memset(data(), 0, sizeof(_Tp) * __n)" into
+ // "memset(data(), 0, sizeof(_Tp[_Capacity]))" which might optimize better
+ for (size_type __i = 0; __i < __n; ++__i) {
+ unchecked_emplace_back();
+ _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__i + 1zu == __sz_, "inplace_vector modified before its lifetime began");
+ }
+ }
+ constexpr _LIBCPP_HIDE_FROM_ABI inplace_vector(size_type __n, const _Tp& __value) : inplace_vector() {
+ if (__n > capacity())
+ __throw_bad_alloc();
+ for (size_type __i = 0; __i < __n; ++__i) {
+ unchecked_emplace_back(__value);
+ _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__i + 1zu == __sz_, "inplace_vector modified before its lifetime began");
+ }
+ }
+
+ // NOTE: [sequence.reqmts]p(67.1) does not apply to this constructor but apply
+ // it anyways so the (size_type, const T&) constructor can never be ambiguous
+ template <class _InputIterator>
+ requires(__has_input_iterator_category<_InputIterator>::value)
+ constexpr _LIBCPP_HIDE_FROM_ABI inplace_vector(_InputIterator __first, _InputIterator __last) : inplace_vector() {
+ if constexpr (__has_forward_iterator_category<_InputIterator>::value) {
+ __append_with_size(__first, __last, std::distance(__first, __last));
+ return;
+ }
+ __append_with_sentinel(__first, __last);
+ }
+ template <_ContainerCompatibleRange<_Tp> _Range>
+ constexpr _LIBCPP_HIDE_FROM_ABI inplace_vector(from_range_t, _Range&& __rg) : inplace_vector() {
+ append_range<true>(__rg);
+ }
+ constexpr _LIBCPP_HIDE_FROM_ABI
+ inplace_vector(const inplace_vector& __other) noexcept(is_nothrow_copy_constructible_v<_Tp>) /* strengthened */
+ : inplace_vector() {
+ _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(this != std::addressof(__other), "inplace_vector self-assign");
+ __small_size_type __expected_size = __other.__sz_;
+ for (__small_size_type __i = 0; __i < __expected_size; ++__i) {
+ unchecked_push_back(__other.data()[__i]);
+ _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__i + 1zu == __sz_, "inplace_vector modified before it's lifetime began");
+ _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(
+ __other.__sz_ == __expected_size, "inplace_vector modified while it's being copied from");
+ }
+ }
+ constexpr _LIBCPP_HIDE_FROM_ABI inplace_vector(const inplace_vector&) noexcept
+ /* strengthened */
+ requires(__base::__trivial_copy_construct)
+ = default;
+ constexpr _LIBCPP_HIDE_FROM_ABI
+ inplace_vector(inplace_vector&& __other) noexcept(is_nothrow_move_constructible_v<_Tp>) /* strengthened */
+ : inplace_vector() {
+ _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(this != std::addressof(__other), "inplace_vector self-assign");
+ __small_size_type __expected_size = __other.__sz_;
+ for (__small_size_type __i = 0; __i < __expected_size; ++__i) {
+ unchecked_push_back(std::move(__other.data()[__i]));
+ _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__i + 1zu == __sz_, "inplace_vector modified before it's lifetime began");
+ _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(
+ __other.__sz_ == __expected_size, "inplace_vector modified while it's being copied from");
+ }
+ }
+ constexpr _LIBCPP_HIDE_FROM_ABI inplace_vector(inplace_vector&&) noexcept
+ /* strengthened */
+ requires(__base::__trivial_move_construct)
+ = default;
+ constexpr _LIBCPP_HIDE_FROM_ABI inplace_vector(initializer_list<_Tp> __il)
+ : inplace_vector(__il.begin(), __il.end()) {}
+
+ constexpr _LIBCPP_HIDE_FROM_ABI inplace_vector& operator=(const inplace_vector& __other) noexcept(
+ is_nothrow_copy_assignable_v<_Tp> && is_nothrow_copy_constructible_v<_Tp>) /* strengthened */ {
+ static_assert(_Capacity != 0, "Should have picked the trivial operator");
+ if (this != std::addressof(__other)) [[likely]] {
+ __small_size_type __assign = std::min(size(), __other.size());
+ std::copy(__other.data(), __other.data() + __assign, data());
+ if (__other.size() > size()) {
+ __append_with_size(__other.data() + __assign, __other.data() + __other.size(), __other.size() - __assign);
+ } else {
+ __resize_down(__other.size());
+ }
+ }
+ return *this;
+ }
+ constexpr _LIBCPP_HIDE_FROM_ABI inplace_vector& operator=(const inplace_vector&) noexcept
+ /* strengthened */
+ requires(__base::__trivial_copy_assign)
+ = default;
+ constexpr _LIBCPP_HIDE_FROM_ABI inplace_vector& operator=(inplace_vector&& __other) noexcept(
+ is_nothrow_move_assignable_v<_Tp> && is_nothrow_move_constructible_v<_Tp>) {
+ static_assert(_Capacity != 0, "Should have picked the trivial operator");
+ if (this != std::addressof(__other)) [[likely]] {
+ __small_size_type __assign = std::min(size(), __other.size());
+ std::move(__other.data(), __other.data() + __assign, data());
+ if (__other.size() > size()) {
+ __append_with_size(std::make_move_iterator(__other.data() + __assign),
+ std::make_move_iterator(__other.data() + __other.size()),
+ __other.size() - __assign);
+ } else {
+ __resize_down(__other.size());
+ }
+ }
+ return *this;
+ }
+ constexpr _LIBCPP_HIDE_FROM_ABI inplace_vector& operator=(inplace_vector&&) noexcept
+ /* strengthened */
+ requires(__base::__trivial_move_assign)
+ = default;
+
+ constexpr _LIBCPP_HIDE_FROM_ABI ~inplace_vector() = default;
+
+private:
+ constexpr _LIBCPP_HIDE_FROM_ABI iterator __make_iter(pointer __p) const noexcept {
+# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS
+ return std::__make_bounded_iter(__p, __wrap_iter<pointer>(__elems_ + 0), __wrap_iter<pointer>(__elems_ + __sz_));
+# else
+ return iterator(__p);
+# endif
+ }
+
+ constexpr _LIBCPP_HIDE_FROM_ABI const_iterator __make_iter(const_pointer __p) const noexcept {
+ return __make_iter(const_cast<pointer>(__p));
+ }
+
+ template <class _First, class _Sent>
+ constexpr _LIBCPP_HIDE_FROM_ABI void __assign_with_size(_First&& __first, _Sent&& __sent, size_t __n) {
+ if (__n > capacity()) [[unlikely]]
----------------
philnik777 wrote:
```suggestion
if (__n > capacity())
```
You call a `[[noreturn]]` function in this branch. The compiler already marks that us unlikely. No need to do it explicitly.
https://github.com/llvm/llvm-project/pull/105981
More information about the libcxx-commits
mailing list