[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]]
+      __throw_bad_alloc();
+    if constexpr (is_trivially_copyable_v<_Tp>) {
+      clear();
+      __append_with_size(std::forward<_First>(__first), std::forward<_Sent>(__sent), __n);
+      return;
+    }
+    const size_t __initial_size   = size();
+    const size_t __assigned_elems = std::min(__initial_size, __n);
+    const size_t __remaining      = __n - __assigned_elems;
+    for (size_t __i = 0; __i < __assigned_elems; ++__i) {
+      data()[__i] = *__first;
+      _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__first != __sent, "Iterators modified during assignment or size was wrong");
+      _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(
+          size() == __initial_size, "Iterator or assignment modified container size during assign");
+      ++__first;
+    }
+    __append_with_size(std::forward<_First>(__first), std::forward<_Sent>(__sent), __remaining);
+  }
+
+  template <class _First, class _Sent>
+  constexpr _LIBCPP_HIDE_FROM_ABI void __assign_with_sentinel(_First&& __first, _Sent&& __sent) {
+    if constexpr (is_trivially_destructible_v<_Tp>) {
+      clear();
+      __append_with_sentinel(std::forward<_First>(__first), std::forward<_Sent>(__sent));
+      return;
+    }
+    size_t __existing = __sz_;
+    for (size_t __i = 0; __i < __existing; ++__i) {
+      if (__first == __sent)
+        return;
+      data()[__i] = *__first;
+      _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__first != __sent, "Iterators modified during assignment");
+      _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(
+          __existing + __i == __sz_, "Iterator or assignment modified container size during assign");
+      ++__first;
+    }
+    __append_with_sentinel(std::forward<_First>(__first), std::forward<_Sent>(__sent));
+  }
+
+public:
+  template <class _InputIterator>
+    requires(__has_input_iterator_category<_InputIterator>::value)
+  constexpr _LIBCPP_HIDE_FROM_ABI void assign(_InputIterator __first, _InputIterator __last) {
+    if constexpr (__has_forward_iterator_category<_InputIterator>::value) {
+      __assign_with_size(__first, __last, std::distance(__first, __last));
+      return;
+    }
+    __assign_with_sentinel(__first, __last);
+  }
+  template <_ContainerCompatibleRange<_Tp> _Range>
+  constexpr _LIBCPP_HIDE_FROM_ABI void assign_range(_Range&& __rg) {
+    if constexpr (ranges::sized_range<_Range&>) {
+      return __assign_with_size(ranges::begin(__rg), ranges::end(__rg), ranges::size(__rg));
+    } else if constexpr (ranges::forward_range<_Range&>) {
+      decltype(auto) __first(ranges::begin(__rg));
+      decltype(auto) __last(ranges::end(__rg));
+      return __assign_with_size(__first, __last, ranges::distance(__first, __last));
+    }
+    return __assign_with_sentinel(ranges::begin(__rg), ranges::end(__rg));
+  }
+  constexpr _LIBCPP_HIDE_FROM_ABI void assign(size_type __n, const _Tp& __u) {
+    if (__n > capacity()) [[unlikely]]
+      __throw_bad_alloc();
+    if constexpr (is_trivially_copyable_v<_Tp>) {
+      clear();
+    } else {
+      const size_t __initial_size   = size();
+      const size_t __assigned_elems = std::min(__initial_size, __n);
+      for (size_t __i = 0; __i < __assigned_elems; ++__i) {
+        data()[__i] = __u;
+        _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(
+            __sz_ == __initial_size, "inplace_vector element assignment modified container size during assign");
+      }
+    }
+    resize(__n, __u);
+  }
+  constexpr _LIBCPP_HIDE_FROM_ABI void assign(initializer_list<_Tp> __il) { assign(__il.begin(), __il.end()); }
+
+  // iterators
+  constexpr _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __make_iter(data()); }
+  constexpr _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __make_iter(data()); }
+  constexpr _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __make_iter(data() + size()); }
+  constexpr _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __make_iter(data() + size()); }
+  constexpr _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
+  constexpr _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const noexcept {
+    return const_reverse_iterator(end());
+  }
+  constexpr _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
+  constexpr _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const noexcept {
+    return const_reverse_iterator(begin());
+  }
+
+  constexpr _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const noexcept { return begin(); }
+  constexpr _LIBCPP_HIDE_FROM_ABI const_iterator cend() const noexcept { return end(); }
+  constexpr _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+  constexpr _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const noexcept { return rend(); }
----------------
philnik777 wrote:

These should probably all be `[[nodiscard]]`.

https://github.com/llvm/llvm-project/pull/105981


More information about the libcxx-commits mailing list