Louis Dionne 427a5cf105
[libc++] Add support for bounded iterators in std::array (#110729)
This patch introduces a new kind of bounded iterator that knows the size
of its valid range at compile-time, as in std::array. This allows computing
the end of the range from the start of the range and the size, which requires
storing only the start of the range in the iterator instead of both the start
and the size (or start and end). The iterator wrapper is otherwise identical
in design to the existing __bounded_iter.

Since this requires changing the type of the iterators returned by
std::array, this new bounded iterator is controlled by an ABI flag.

As a drive-by, centralize the tests for std::array::operator[] and add
missing tests for OOB operator[] on non-empty arrays.

Fixes #70864
2024-11-07 09:23:21 -05:00

569 lines
23 KiB
C++

// -*- 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_ARRAY
#define _LIBCPP_ARRAY
/*
array synopsis
namespace std
{
template <class T, size_t N >
struct array
{
// types:
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using size_type = size_t;
using difference_type = ptrdiff_t;
using iterator = implementation-defined;
using const_iterator = implementation-defined;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
// No explicit construct/copy/destroy for aggregate type
void fill(const T& u); // constexpr in C++20
void swap(array& a) noexcept(is_nothrow_swappable_v<T>); // constexpr in C++20
// iterators:
iterator begin() noexcept; // constexpr in C++17
const_iterator begin() const noexcept; // constexpr in C++17
iterator end() noexcept; // constexpr in C++17
const_iterator end() const noexcept; // constexpr in C++17
reverse_iterator rbegin() noexcept; // constexpr in C++17
const_reverse_iterator rbegin() const noexcept; // constexpr in C++17
reverse_iterator rend() noexcept; // constexpr in C++17
const_reverse_iterator rend() const noexcept; // constexpr in C++17
const_iterator cbegin() const noexcept; // constexpr in C++17
const_iterator cend() const noexcept; // constexpr in C++17
const_reverse_iterator crbegin() const noexcept; // constexpr in C++17
const_reverse_iterator crend() const noexcept; // constexpr in C++17
// capacity:
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
constexpr bool empty() const noexcept;
// element access:
reference operator[](size_type n); // constexpr in C++17
const_reference operator[](size_type n) const; // constexpr in C++14
reference at(size_type n); // constexpr in C++17
const_reference at(size_type n) const; // constexpr in C++14
reference front(); // constexpr in C++17
const_reference front() const; // constexpr in C++14
reference back(); // constexpr in C++17
const_reference back() const; // constexpr in C++14
T* data() noexcept; // constexpr in C++17
const T* data() const noexcept; // constexpr in C++17
};
template <class T, class... U>
array(T, U...) -> array<T, 1 + sizeof...(U)>; // C++17
template <class T, size_t N>
bool operator==(const array<T,N>& x, const array<T,N>& y); // constexpr in C++20
template <class T, size_t N>
bool operator!=(const array<T,N>& x, const array<T,N>& y); // removed in C++20
template <class T, size_t N>
bool operator<(const array<T,N>& x, const array<T,N>& y); // removed in C++20
template <class T, size_t N>
bool operator>(const array<T,N>& x, const array<T,N>& y); // removed in C++20
template <class T, size_t N>
bool operator<=(const array<T,N>& x, const array<T,N>& y); // removed in C++20
template <class T, size_t N>
bool operator>=(const array<T,N>& x, const array<T,N>& y); // removed in C++20
template<class T, size_t N>
constexpr synth-three-way-result<T>
operator<=>(const array<T, N>& x, const array<T, N>& y); // since C++20
template <class T, size_t N >
void swap(array<T,N>& x, array<T,N>& y) noexcept(noexcept(x.swap(y))); // constexpr in C++20
template <class T, size_t N>
constexpr array<remove_cv_t<T>, N> to_array(T (&a)[N]); // C++20
template <class T, size_t N>
constexpr array<remove_cv_t<T>, N> to_array(T (&&a)[N]); // C++20
template <class T> struct tuple_size;
template <size_t I, class T> struct tuple_element;
template <class T, size_t N> struct tuple_size<array<T, N>>;
template <size_t I, class T, size_t N> struct tuple_element<I, array<T, N>>;
template <size_t I, class T, size_t N> T& get(array<T, N>&) noexcept; // constexpr in C++14
template <size_t I, class T, size_t N> const T& get(const array<T, N>&) noexcept; // constexpr in C++14
template <size_t I, class T, size_t N> T&& get(array<T, N>&&) noexcept; // constexpr in C++14
template <size_t I, class T, size_t N> const T&& get(const array<T, N>&&) noexcept; // constexpr in C++14
} // std
*/
#include <__algorithm/equal.h>
#include <__algorithm/fill_n.h>
#include <__algorithm/lexicographical_compare.h>
#include <__algorithm/lexicographical_compare_three_way.h>
#include <__algorithm/swap_ranges.h>
#include <__assert>
#include <__config>
#include <__cstddef/ptrdiff_t.h>
#include <__fwd/array.h>
#include <__iterator/reverse_iterator.h>
#include <__iterator/static_bounded_iter.h>
#include <__iterator/wrap_iter.h>
#include <__tuple/sfinae_helpers.h>
#include <__type_traits/conditional.h>
#include <__type_traits/conjunction.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_array.h>
#include <__type_traits/is_const.h>
#include <__type_traits/is_constructible.h>
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_swappable.h>
#include <__type_traits/is_trivially_relocatable.h>
#include <__type_traits/remove_cv.h>
#include <__utility/empty.h>
#include <__utility/integer_sequence.h>
#include <__utility/move.h>
#include <__utility/unreachable.h>
#include <stdexcept>
#include <version>
// standard-mandated includes
// [iterator.range]
#include <__iterator/access.h>
#include <__iterator/data.h>
#include <__iterator/empty.h>
#include <__iterator/reverse_access.h>
#include <__iterator/size.h>
// [array.syn]
#include <compare>
#include <initializer_list>
// [tuple.helper]
#include <__tuple/tuple_element.h>
#include <__tuple/tuple_size.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp, size_t _Size>
struct _LIBCPP_TEMPLATE_VIS array {
using __trivially_relocatable = __conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, array, void>;
// types:
using __self = array;
using value_type = _Tp;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY)
using iterator = __static_bounded_iter<pointer, _Size>;
using const_iterator = __static_bounded_iter<const_pointer, _Size>;
#elif defined(_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY)
using iterator = __wrap_iter<pointer>;
using const_iterator = __wrap_iter<const_pointer>;
#else
using iterator = pointer;
using const_iterator = const_pointer;
#endif
using size_type = size_t;
using difference_type = ptrdiff_t;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
_Tp __elems_[_Size];
// No explicit construct/copy/destroy for aggregate type
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void fill(const value_type& __u) {
std::fill_n(data(), _Size, __u);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(array& __a) _NOEXCEPT_(__is_nothrow_swappable_v<_Tp>) {
std::swap_ranges(data(), data() + _Size, __a.data());
}
// iterators:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 iterator begin() _NOEXCEPT {
#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY)
return std::__make_static_bounded_iter<_Size>(data(), data());
#else
return iterator(data());
#endif
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator begin() const _NOEXCEPT {
#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY)
return std::__make_static_bounded_iter<_Size>(data(), data());
#else
return const_iterator(data());
#endif
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 iterator end() _NOEXCEPT {
#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY)
return std::__make_static_bounded_iter<_Size>(data() + _Size, data());
#else
return iterator(data() + _Size);
#endif
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator end() const _NOEXCEPT {
#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY)
return std::__make_static_bounded_iter<_Size>(data() + _Size, data());
#else
return const_iterator(data() + _Size);
#endif
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator rbegin() _NOEXCEPT {
return reverse_iterator(end());
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator rbegin() const _NOEXCEPT {
return const_reverse_iterator(end());
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator rend() _NOEXCEPT {
return reverse_iterator(begin());
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator rend() const _NOEXCEPT {
return const_reverse_iterator(begin());
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator cbegin() const _NOEXCEPT { return begin(); }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator cend() const _NOEXCEPT { return end(); }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator crbegin() const _NOEXCEPT {
return rbegin();
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator crend() const _NOEXCEPT { return rend(); }
// capacity:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_type size() const _NOEXCEPT { return _Size; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_type max_size() const _NOEXCEPT { return _Size; }
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT { return _Size == 0; }
// element access:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference operator[](size_type __n) _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < _Size, "out-of-bounds access in std::array<T, N>");
return __elems_[__n];
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference operator[](size_type __n) const _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < _Size, "out-of-bounds access in std::array<T, N>");
return __elems_[__n];
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference at(size_type __n) {
if (__n >= _Size)
__throw_out_of_range("array::at");
return __elems_[__n];
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference at(size_type __n) const {
if (__n >= _Size)
__throw_out_of_range("array::at");
return __elems_[__n];
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference front() _NOEXCEPT { return (*this)[0]; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference front() const _NOEXCEPT { return (*this)[0]; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference back() _NOEXCEPT { return (*this)[_Size - 1]; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference back() const _NOEXCEPT {
return (*this)[_Size - 1];
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 value_type* data() _NOEXCEPT { return __elems_; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const value_type* data() const _NOEXCEPT { return __elems_; }
};
template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS array<_Tp, 0> {
// types:
using __self = array;
using value_type = _Tp;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY)
using iterator = __static_bounded_iter<pointer, 0>;
using const_iterator = __static_bounded_iter<const_pointer, 0>;
#elif defined(_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY)
using iterator = __wrap_iter<pointer>;
using const_iterator = __wrap_iter<const_pointer>;
#else
using iterator = pointer;
using const_iterator = const_pointer;
#endif
using size_type = size_t;
using difference_type = ptrdiff_t;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using _EmptyType = __conditional_t<is_const<_Tp>::value, const __empty, __empty>;
struct _ArrayInStructT {
_Tp __data_[1];
};
_ALIGNAS_TYPE(_ArrayInStructT) _EmptyType __elems_[sizeof(_ArrayInStructT)];
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 value_type* data() _NOEXCEPT { return nullptr; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const value_type* data() const _NOEXCEPT { return nullptr; }
// No explicit construct/copy/destroy for aggregate type
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void fill(const value_type&) {
static_assert(!is_const<_Tp>::value, "cannot fill zero-sized array of type 'const T'");
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(array&) _NOEXCEPT {
static_assert(!is_const<_Tp>::value, "cannot swap zero-sized array of type 'const T'");
}
// iterators:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 iterator begin() _NOEXCEPT {
#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY)
return std::__make_static_bounded_iter<0>(data(), data());
#else
return iterator(data());
#endif
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator begin() const _NOEXCEPT {
#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY)
return std::__make_static_bounded_iter<0>(data(), data());
#else
return const_iterator(data());
#endif
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 iterator end() _NOEXCEPT {
#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY)
return std::__make_static_bounded_iter<0>(data(), data());
#else
return iterator(data());
#endif
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator end() const _NOEXCEPT {
#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY)
return std::__make_static_bounded_iter<0>(data(), data());
#else
return const_iterator(data());
#endif
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator rbegin() _NOEXCEPT {
return reverse_iterator(end());
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator rbegin() const _NOEXCEPT {
return const_reverse_iterator(end());
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator rend() _NOEXCEPT {
return reverse_iterator(begin());
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator rend() const _NOEXCEPT {
return const_reverse_iterator(begin());
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator cbegin() const _NOEXCEPT { return begin(); }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator cend() const _NOEXCEPT { return end(); }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator crbegin() const _NOEXCEPT {
return rbegin();
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator crend() const _NOEXCEPT { return rend(); }
// capacity:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_type size() const _NOEXCEPT { return 0; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_type max_size() const _NOEXCEPT { return 0; }
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT { return true; }
// element access:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference operator[](size_type) _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::operator[] on a zero-sized array");
__libcpp_unreachable();
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference operator[](size_type) const _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::operator[] on a zero-sized array");
__libcpp_unreachable();
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference at(size_type) {
__throw_out_of_range("array<T, 0>::at");
__libcpp_unreachable();
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference at(size_type) const {
__throw_out_of_range("array<T, 0>::at");
__libcpp_unreachable();
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference front() _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::front() on a zero-sized array");
__libcpp_unreachable();
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference front() const _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::front() on a zero-sized array");
__libcpp_unreachable();
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference back() _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::back() on a zero-sized array");
__libcpp_unreachable();
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference back() const _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::back() on a zero-sized array");
__libcpp_unreachable();
}
};
#if _LIBCPP_STD_VER >= 17
template <class _Tp, class... _Args, class = enable_if_t<__all<_IsSame<_Tp, _Args>::value...>::value> >
array(_Tp, _Args...) -> array<_Tp, 1 + sizeof...(_Args)>;
#endif
template <class _Tp, size_t _Size>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
operator==(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) {
return std::equal(__x.begin(), __x.end(), __y.begin());
}
#if _LIBCPP_STD_VER <= 17
template <class _Tp, size_t _Size>
inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) {
return !(__x == __y);
}
template <class _Tp, size_t _Size>
inline _LIBCPP_HIDE_FROM_ABI bool operator<(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) {
return std::lexicographical_compare(__x.begin(), __x.end(), __y.begin(), __y.end());
}
template <class _Tp, size_t _Size>
inline _LIBCPP_HIDE_FROM_ABI bool operator>(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) {
return __y < __x;
}
template <class _Tp, size_t _Size>
inline _LIBCPP_HIDE_FROM_ABI bool operator<=(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) {
return !(__y < __x);
}
template <class _Tp, size_t _Size>
inline _LIBCPP_HIDE_FROM_ABI bool operator>=(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) {
return !(__x < __y);
}
#else // _LIBCPP_STD_VER <= 17
template <class _Tp, size_t _Size>
_LIBCPP_HIDE_FROM_ABI constexpr __synth_three_way_result<_Tp>
operator<=>(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) {
return std::lexicographical_compare_three_way(__x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way);
}
#endif // _LIBCPP_STD_VER <= 17
template <class _Tp, size_t _Size, __enable_if_t<_Size == 0 || __is_swappable_v<_Tp>, int> = 0>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(array<_Tp, _Size>& __x, array<_Tp, _Size>& __y)
_NOEXCEPT_(noexcept(__x.swap(__y))) {
__x.swap(__y);
}
template <class _Tp, size_t _Size>
struct _LIBCPP_TEMPLATE_VIS tuple_size<array<_Tp, _Size> > : public integral_constant<size_t, _Size> {};
template <size_t _Ip, class _Tp, size_t _Size>
struct _LIBCPP_TEMPLATE_VIS tuple_element<_Ip, array<_Tp, _Size> > {
static_assert(_Ip < _Size, "Index out of bounds in std::tuple_element<> (std::array)");
using type = _Tp;
};
template <size_t _Ip, class _Tp, size_t _Size>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp& get(array<_Tp, _Size>& __a) _NOEXCEPT {
static_assert(_Ip < _Size, "Index out of bounds in std::get<> (std::array)");
return __a.__elems_[_Ip];
}
template <size_t _Ip, class _Tp, size_t _Size>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp& get(const array<_Tp, _Size>& __a) _NOEXCEPT {
static_assert(_Ip < _Size, "Index out of bounds in std::get<> (const std::array)");
return __a.__elems_[_Ip];
}
template <size_t _Ip, class _Tp, size_t _Size>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp&& get(array<_Tp, _Size>&& __a) _NOEXCEPT {
static_assert(_Ip < _Size, "Index out of bounds in std::get<> (std::array &&)");
return std::move(__a.__elems_[_Ip]);
}
template <size_t _Ip, class _Tp, size_t _Size>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp&& get(const array<_Tp, _Size>&& __a) _NOEXCEPT {
static_assert(_Ip < _Size, "Index out of bounds in std::get<> (const std::array &&)");
return std::move(__a.__elems_[_Ip]);
}
#if _LIBCPP_STD_VER >= 20
template <typename _Tp, size_t _Size, size_t... _Index>
_LIBCPP_HIDE_FROM_ABI constexpr array<remove_cv_t<_Tp>, _Size>
__to_array_lvalue_impl(_Tp (&__arr)[_Size], index_sequence<_Index...>) {
return {{__arr[_Index]...}};
}
template <typename _Tp, size_t _Size, size_t... _Index>
_LIBCPP_HIDE_FROM_ABI constexpr array<remove_cv_t<_Tp>, _Size>
__to_array_rvalue_impl(_Tp (&&__arr)[_Size], index_sequence<_Index...>) {
return {{std::move(__arr[_Index])...}};
}
template <typename _Tp, size_t _Size>
_LIBCPP_HIDE_FROM_ABI constexpr array<remove_cv_t<_Tp>, _Size>
to_array(_Tp (&__arr)[_Size]) noexcept(is_nothrow_constructible_v<_Tp, _Tp&>) {
static_assert(!is_array_v<_Tp>, "[array.creation]/1: to_array does not accept multidimensional arrays.");
static_assert(is_constructible_v<_Tp, _Tp&>, "[array.creation]/1: to_array requires copy constructible elements.");
return std::__to_array_lvalue_impl(__arr, make_index_sequence<_Size>());
}
template <typename _Tp, size_t _Size>
_LIBCPP_HIDE_FROM_ABI constexpr array<remove_cv_t<_Tp>, _Size>
to_array(_Tp (&&__arr)[_Size]) noexcept(is_nothrow_move_constructible_v<_Tp>) {
static_assert(!is_array_v<_Tp>, "[array.creation]/4: to_array does not accept multidimensional arrays.");
static_assert(is_move_constructible_v<_Tp>, "[array.creation]/4: to_array requires move constructible elements.");
return std::__to_array_rvalue_impl(std::move(__arr), make_index_sequence<_Size>());
}
#endif // _LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
# include <algorithm>
# include <concepts>
# include <cstdlib>
# include <iterator>
# include <type_traits>
# include <utility>
#endif
#endif // _LIBCPP_ARRAY