// -*- C++ -*- // Copyright (C) 2007-2023 Free Software Foundation, Inc. // // 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 // . /** @file include/array * This is a Standard C++ Library header. */ #ifndef _GLIBCXX_ARRAY #define _GLIBCXX_ARRAY 1 #pragma GCC system_header #if __cplusplus < 201103L # include #else #include #include #include #include #include #include // std::begin, std::end etc. #include // std::index_sequence, std::tuple_size #include namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __array_traits { using _Type = _Tp[_Nm]; using _Is_swappable = __is_swappable<_Tp>; using _Is_nothrow_swappable = __is_nothrow_swappable<_Tp>; }; template struct __array_traits<_Tp, 0> { // Empty type used instead of _Tp[0] for std::array<_Tp, 0>. struct _Type { // Indexing is undefined. __attribute__((__always_inline__,__noreturn__)) _Tp& operator[](size_t) const noexcept { __builtin_trap(); } // Conversion to a pointer produces a null pointer. __attribute__((__always_inline__)) constexpr explicit operator _Tp*() const noexcept { return nullptr; } }; using _Is_swappable = true_type; using _Is_nothrow_swappable = true_type; }; /** * @brief A standard container for storing a fixed size sequence of elements. * * @ingroup sequences * * Meets the requirements of a container, a * reversible container, and a * sequence. * * Sets support random access iterators. * * @tparam Tp Type of element. Required to be a complete type. * @tparam Nm Number of elements. */ template struct array { typedef _Tp value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; typedef value_type* iterator; typedef const value_type* const_iterator; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; // Support for zero-sized arrays mandatory. typename __array_traits<_Tp, _Nm>::_Type _M_elems; // No explicit construct/copy/destroy for aggregate type. // DR 776. _GLIBCXX20_CONSTEXPR void fill(const value_type& __u) { std::fill_n(begin(), size(), __u); } _GLIBCXX20_CONSTEXPR void swap(array& __other) noexcept(__array_traits<_Tp, _Nm>::_Is_nothrow_swappable::value) { std::swap_ranges(begin(), end(), __other.begin()); } // Iterators. [[__gnu__::__const__, __nodiscard__]] _GLIBCXX17_CONSTEXPR iterator begin() noexcept { return iterator(data()); } [[__nodiscard__]] _GLIBCXX17_CONSTEXPR const_iterator begin() const noexcept { return const_iterator(data()); } [[__gnu__::__const__, __nodiscard__]] _GLIBCXX17_CONSTEXPR iterator end() noexcept { return iterator(data() + _Nm); } [[__nodiscard__]] _GLIBCXX17_CONSTEXPR const_iterator end() const noexcept { return const_iterator(data() + _Nm); } [[__gnu__::__const__, __nodiscard__]] _GLIBCXX17_CONSTEXPR reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } [[__nodiscard__]] _GLIBCXX17_CONSTEXPR const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } [[__gnu__::__const__, __nodiscard__]] _GLIBCXX17_CONSTEXPR reverse_iterator rend() noexcept { return reverse_iterator(begin()); } [[__nodiscard__]] _GLIBCXX17_CONSTEXPR const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } [[__nodiscard__]] _GLIBCXX17_CONSTEXPR const_iterator cbegin() const noexcept { return const_iterator(data()); } [[__nodiscard__]] _GLIBCXX17_CONSTEXPR const_iterator cend() const noexcept { return const_iterator(data() + _Nm); } [[__nodiscard__]] _GLIBCXX17_CONSTEXPR const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } [[__nodiscard__]] _GLIBCXX17_CONSTEXPR const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } // Capacity. [[__nodiscard__, __gnu__::__const__, __gnu__::__always_inline__]] constexpr size_type size() const noexcept { return _Nm; } [[__nodiscard__, __gnu__::__const__, __gnu__::__always_inline__]] constexpr size_type max_size() const noexcept { return _Nm; } [[__nodiscard__, __gnu__::__const__, __gnu__::__always_inline__]] constexpr bool empty() const noexcept { return size() == 0; } // Element access. [[__nodiscard__]] _GLIBCXX17_CONSTEXPR reference operator[](size_type __n) noexcept { __glibcxx_requires_subscript(__n); return _M_elems[__n]; } [[__nodiscard__]] constexpr const_reference operator[](size_type __n) const noexcept { #if __cplusplus >= 201402L __glibcxx_requires_subscript(__n); #endif return _M_elems[__n]; } _GLIBCXX17_CONSTEXPR reference at(size_type __n) { if (__n >= _Nm) std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) " ">= _Nm (which is %zu)"), __n, _Nm); return _M_elems[__n]; } constexpr const_reference at(size_type __n) const { // Result of conditional expression must be an lvalue so use // boolean ? lvalue : (throw-expr, lvalue) return __n < _Nm ? _M_elems[__n] : (std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) " ">= _Nm (which is %zu)"), __n, _Nm), _M_elems[__n]); } [[__nodiscard__]] _GLIBCXX17_CONSTEXPR reference front() noexcept { __glibcxx_requires_nonempty(); return _M_elems[(size_type)0]; } [[__nodiscard__]] constexpr const_reference front() const noexcept { #if __cplusplus >= 201402L __glibcxx_requires_nonempty(); #endif return _M_elems[(size_type)0]; } [[__nodiscard__]] _GLIBCXX17_CONSTEXPR reference back() noexcept { __glibcxx_requires_nonempty(); return _M_elems[_Nm - 1]; } [[__nodiscard__]] constexpr const_reference back() const noexcept { #if __cplusplus >= 201402L __glibcxx_requires_nonempty(); #endif return _M_elems[_Nm - 1]; } [[__nodiscard__, __gnu__::__const__, __gnu__::__always_inline__]] _GLIBCXX17_CONSTEXPR pointer data() noexcept { return static_cast(_M_elems); } [[__nodiscard__]] _GLIBCXX17_CONSTEXPR const_pointer data() const noexcept { return static_cast(_M_elems); } }; #if __cpp_deduction_guides >= 201606 template array(_Tp, _Up...) -> array && ...), _Tp>, 1 + sizeof...(_Up)>; #endif // Array comparisons. template [[__nodiscard__]] _GLIBCXX20_CONSTEXPR inline bool operator==(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two) { return std::equal(__one.begin(), __one.end(), __two.begin()); } #if __cpp_lib_three_way_comparison && __cpp_lib_concepts template [[nodiscard]] constexpr __detail::__synth3way_t<_Tp> operator<=>(const array<_Tp, _Nm>& __a, const array<_Tp, _Nm>& __b) { if constexpr (_Nm && __is_memcmp_ordered<_Tp>::__value) if (!std::__is_constant_evaluated()) { constexpr size_t __n = _Nm * sizeof(_Tp); return __builtin_memcmp(__a.data(), __b.data(), __n) <=> 0; } for (size_t __i = 0; __i < _Nm; ++__i) { auto __c = __detail::__synth3way(__a[__i], __b[__i]); if (__c != 0) return __c; } return strong_ordering::equal; } #else template [[__nodiscard__]] _GLIBCXX20_CONSTEXPR inline bool operator!=(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two) { return !(__one == __two); } template [[__nodiscard__]] _GLIBCXX20_CONSTEXPR inline bool operator<(const array<_Tp, _Nm>& __a, const array<_Tp, _Nm>& __b) { return std::lexicographical_compare(__a.begin(), __a.end(), __b.begin(), __b.end()); } template [[__nodiscard__]] _GLIBCXX20_CONSTEXPR inline bool operator>(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two) { return __two < __one; } template [[__nodiscard__]] _GLIBCXX20_CONSTEXPR inline bool operator<=(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two) { return !(__one > __two); } template [[__nodiscard__]] _GLIBCXX20_CONSTEXPR inline bool operator>=(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two) { return !(__one < __two); } #endif // three_way_comparison && concepts // Specialized algorithms. template _GLIBCXX20_CONSTEXPR inline #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 // Constrained free swap overload, see p0185r1 __enable_if_t<__array_traits<_Tp, _Nm>::_Is_swappable::value> #else void #endif swap(array<_Tp, _Nm>& __one, array<_Tp, _Nm>& __two) noexcept(noexcept(__one.swap(__two))) { __one.swap(__two); } #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 template __enable_if_t::_Is_swappable::value> swap(array<_Tp, _Nm>&, array<_Tp, _Nm>&) = delete; #endif template [[__nodiscard__]] constexpr _Tp& get(array<_Tp, _Nm>& __arr) noexcept { static_assert(_Int < _Nm, "array index is within bounds"); return __arr._M_elems[_Int]; } template [[__nodiscard__]] constexpr _Tp&& get(array<_Tp, _Nm>&& __arr) noexcept { static_assert(_Int < _Nm, "array index is within bounds"); return std::move(std::get<_Int>(__arr)); } template [[__nodiscard__]] constexpr const _Tp& get(const array<_Tp, _Nm>& __arr) noexcept { static_assert(_Int < _Nm, "array index is within bounds"); return __arr._M_elems[_Int]; } template [[__nodiscard__]] constexpr const _Tp&& get(const array<_Tp, _Nm>&& __arr) noexcept { static_assert(_Int < _Nm, "array index is within bounds"); return std::move(std::get<_Int>(__arr)); } #if __cplusplus >= 202002L && __cpp_generic_lambdas >= 201707L #define __cpp_lib_to_array 201907L template [[nodiscard]] constexpr array, _Nm> to_array(_Tp (&__a)[_Nm]) noexcept(is_nothrow_constructible_v<_Tp, _Tp&>) { static_assert(!is_array_v<_Tp>); static_assert(is_constructible_v<_Tp, _Tp&>); if constexpr (is_constructible_v<_Tp, _Tp&>) { if constexpr (is_trivial_v<_Tp>) { array, _Nm> __arr; if (!__is_constant_evaluated() && _Nm != 0) __builtin_memcpy((void*)__arr.data(), (void*)__a, sizeof(__a)); else for (size_t __i = 0; __i < _Nm; ++__i) __arr._M_elems[__i] = __a[__i]; return __arr; } else return [&__a](index_sequence<_Idx...>) { return array, _Nm>{{ __a[_Idx]... }}; }(make_index_sequence<_Nm>{}); } else __builtin_unreachable(); // FIXME: see PR c++/91388 } template [[nodiscard]] constexpr array, _Nm> to_array(_Tp (&&__a)[_Nm]) noexcept(is_nothrow_move_constructible_v<_Tp>) { static_assert(!is_array_v<_Tp>); static_assert(is_move_constructible_v<_Tp>); if constexpr (is_move_constructible_v<_Tp>) { if constexpr (is_trivial_v<_Tp>) { array, _Nm> __arr; if (!__is_constant_evaluated() && _Nm != 0) __builtin_memcpy((void*)__arr.data(), (void*)__a, sizeof(__a)); else for (size_t __i = 0; __i < _Nm; ++__i) __arr._M_elems[__i] = __a[__i]; return __arr; } else return [&__a](index_sequence<_Idx...>) { return array, _Nm>{{ std::move(__a[_Idx])... }}; }(make_index_sequence<_Nm>{}); } else __builtin_unreachable(); // FIXME: see PR c++/91388 } #endif // C++20 // Tuple interface to class template array. /// Partial specialization for std::array template struct tuple_size> : public integral_constant { }; /// Partial specialization for std::array template struct tuple_element<_Ind, array<_Tp, _Nm>> { static_assert(_Ind < _Nm, "array index is in range"); using type = _Tp; }; #if __cplusplus >= 201703L template inline constexpr size_t tuple_size_v> = _Nm; template inline constexpr size_t tuple_size_v> = _Nm; #endif template struct __is_tuple_like_impl> : true_type { }; _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++11 #endif // _GLIBCXX_ARRAY