libstdc++
array
Go to the documentation of this file.
1 // <array> -*- C++ -*-
2 
3 // Copyright (C) 2007-2025 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 /** @file include/array
26  * This is a Standard C++ Library header.
27  */
28 
29 #ifndef _GLIBCXX_ARRAY
30 #define _GLIBCXX_ARRAY 1
31 
32 #ifdef _GLIBCXX_SYSHDR
33 #pragma GCC system_header
34 #endif
35 
36 #if __cplusplus < 201103L
37 # include <bits/c++0x_warning.h>
38 #else
39 
40 #include <compare>
41 #include <initializer_list>
42 
43 #include <type_traits>
44 #include <bits/functexcept.h>
45 #include <bits/stl_algobase.h>
46 #include <bits/range_access.h> // std::begin, std::end etc.
47 #include <bits/utility.h> // std::index_sequence, std::tuple_size
48 #include <debug/assertions.h>
49 
50 #define __glibcxx_want_array_constexpr
51 #define __glibcxx_want_freestanding_array
52 #define __glibcxx_want_nonmember_container_access
53 #define __glibcxx_want_to_array
54 #include <bits/version.h>
55 
56 namespace std _GLIBCXX_VISIBILITY(default)
57 {
58 _GLIBCXX_BEGIN_NAMESPACE_VERSION
59 
60  template<typename _Tp, size_t _Nm>
61  struct __array_traits
62  {
63  using _Type = _Tp[_Nm];
64  using _Is_swappable = __is_swappable<_Tp>;
65  using _Is_nothrow_swappable = __is_nothrow_swappable<_Tp>;
66  };
67 
68  template<typename _Tp>
69  struct __array_traits<_Tp, 0>
70  {
71  // Empty type used instead of _Tp[0] for std::array<_Tp, 0>.
72  struct _Type
73  {
74  // Indexing is undefined.
75  __attribute__((__always_inline__,__noreturn__))
76  _Tp& operator[](size_t) const noexcept { __builtin_trap(); }
77 
78  // Conversion to a pointer produces a null pointer.
79  __attribute__((__always_inline__))
80  constexpr explicit operator _Tp*() const noexcept { return nullptr; }
81  };
82 
83  using _Is_swappable = true_type;
84  using _Is_nothrow_swappable = true_type;
85  };
86 
87  /**
88  * @brief A standard container for storing a fixed size sequence of elements.
89  *
90  * @ingroup sequences
91  *
92  * Meets the requirements of a <a href="tables.html#65">container</a>, a
93  * <a href="tables.html#66">reversible container</a>, and a
94  * <a href="tables.html#67">sequence</a>.
95  *
96  * Sets support random access iterators.
97  *
98  * @tparam Tp Type of element. Required to be a complete type.
99  * @tparam Nm Number of elements.
100  */
101  template<typename _Tp, std::size_t _Nm>
102  struct array
103  {
104  typedef _Tp value_type;
105  typedef value_type* pointer;
106  typedef const value_type* const_pointer;
107  typedef value_type& reference;
108  typedef const value_type& const_reference;
109  typedef value_type* iterator;
110  typedef const value_type* const_iterator;
111  typedef std::size_t size_type;
112  typedef std::ptrdiff_t difference_type;
113  typedef std::reverse_iterator<iterator> reverse_iterator;
114  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
115 
116  // Support for zero-sized arrays mandatory.
117  typename __array_traits<_Tp, _Nm>::_Type _M_elems;
118 
119  // No explicit construct/copy/destroy for aggregate type.
120 
121  // DR 776.
122  _GLIBCXX20_CONSTEXPR void
123  fill(const value_type& __u)
124  { std::fill_n(begin(), size(), __u); }
125 
126  _GLIBCXX20_CONSTEXPR void
127  swap(array& __other)
128  noexcept(__array_traits<_Tp, _Nm>::_Is_nothrow_swappable::value)
129  { std::swap_ranges(begin(), end(), __other.begin()); }
130 
131  // Iterators.
132  [[__gnu__::__const__, __nodiscard__]]
133  _GLIBCXX17_CONSTEXPR iterator
134  begin() noexcept
135  { return iterator(data()); }
136 
137  [[__nodiscard__]]
138  _GLIBCXX17_CONSTEXPR const_iterator
139  begin() const noexcept
140  { return const_iterator(data()); }
141 
142  [[__gnu__::__const__, __nodiscard__]]
143  _GLIBCXX17_CONSTEXPR iterator
144  end() noexcept
145  { return iterator(data() + _Nm); }
146 
147  [[__nodiscard__]]
148  _GLIBCXX17_CONSTEXPR const_iterator
149  end() const noexcept
150  { return const_iterator(data() + _Nm); }
151 
152  [[__gnu__::__const__, __nodiscard__]]
153  _GLIBCXX17_CONSTEXPR reverse_iterator
154  rbegin() noexcept
155  { return reverse_iterator(end()); }
156 
157  [[__nodiscard__]]
158  _GLIBCXX17_CONSTEXPR const_reverse_iterator
159  rbegin() const noexcept
160  { return const_reverse_iterator(end()); }
161 
162  [[__gnu__::__const__, __nodiscard__]]
163  _GLIBCXX17_CONSTEXPR reverse_iterator
164  rend() noexcept
165  { return reverse_iterator(begin()); }
166 
167  [[__nodiscard__]]
168  _GLIBCXX17_CONSTEXPR const_reverse_iterator
169  rend() const noexcept
170  { return const_reverse_iterator(begin()); }
171 
172  [[__nodiscard__]]
173  _GLIBCXX17_CONSTEXPR const_iterator
174  cbegin() const noexcept
175  { return const_iterator(data()); }
176 
177  [[__nodiscard__]]
178  _GLIBCXX17_CONSTEXPR const_iterator
179  cend() const noexcept
180  { return const_iterator(data() + _Nm); }
181 
182  [[__nodiscard__]]
183  _GLIBCXX17_CONSTEXPR const_reverse_iterator
184  crbegin() const noexcept
185  { return const_reverse_iterator(end()); }
186 
187  [[__nodiscard__]]
188  _GLIBCXX17_CONSTEXPR const_reverse_iterator
189  crend() const noexcept
190  { return const_reverse_iterator(begin()); }
191 
192  // Capacity.
193  [[__nodiscard__, __gnu__::__const__, __gnu__::__always_inline__]]
194  constexpr size_type
195  size() const noexcept { return _Nm; }
196 
197  [[__nodiscard__, __gnu__::__const__, __gnu__::__always_inline__]]
198  constexpr size_type
199  max_size() const noexcept { return _Nm; }
200 
201  [[__nodiscard__, __gnu__::__const__, __gnu__::__always_inline__]]
202  constexpr bool
203  empty() const noexcept { return size() == 0; }
204 
205  // Element access.
206  [[__nodiscard__]]
207  _GLIBCXX17_CONSTEXPR reference
208  operator[](size_type __n) noexcept
209  {
210  __glibcxx_requires_subscript(__n);
211  return _M_elems[__n];
212  }
213 
214  [[__nodiscard__]]
215  constexpr const_reference
216  operator[](size_type __n) const noexcept
217  {
218 #if __cplusplus >= 201402L
219  __glibcxx_requires_subscript(__n);
220 #endif
221  return _M_elems[__n];
222  }
223 
224  _GLIBCXX17_CONSTEXPR reference
225  at(size_type __n)
226  {
227  if (__n >= _Nm)
228  std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) "
229  ">= _Nm (which is %zu)"),
230  __n, _Nm);
231  return _M_elems[__n];
232  }
233 
234  constexpr const_reference
235  at(size_type __n) const
236  {
237  // Result of conditional expression must be an lvalue so use
238  // boolean ? lvalue : (throw-expr, lvalue)
239  return __n < _Nm ? _M_elems[__n]
240  : (std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) "
241  ">= _Nm (which is %zu)"),
242  __n, _Nm),
243  _M_elems[__n]);
244  }
245 
246  [[__nodiscard__]]
247  _GLIBCXX17_CONSTEXPR reference
248  front() noexcept
249  {
250  __glibcxx_requires_nonempty();
251  return _M_elems[(size_type)0];
252  }
253 
254  [[__nodiscard__]]
255  constexpr const_reference
256  front() const noexcept
257  {
258 #if __cplusplus >= 201402L
259  __glibcxx_requires_nonempty();
260 #endif
261  return _M_elems[(size_type)0];
262  }
263 
264  [[__nodiscard__]]
265  _GLIBCXX17_CONSTEXPR reference
266  back() noexcept
267  {
268  __glibcxx_requires_nonempty();
269  return _M_elems[_Nm - 1];
270  }
271 
272  [[__nodiscard__]]
273  constexpr const_reference
274  back() const noexcept
275  {
276 #if __cplusplus >= 201402L
277  __glibcxx_requires_nonempty();
278 #endif
279  return _M_elems[_Nm - 1];
280  }
281 
282  [[__nodiscard__, __gnu__::__const__, __gnu__::__always_inline__]]
283  _GLIBCXX17_CONSTEXPR pointer
284  data() noexcept
285  { return static_cast<pointer>(_M_elems); }
286 
287  [[__nodiscard__]]
288  _GLIBCXX17_CONSTEXPR const_pointer
289  data() const noexcept
290  { return static_cast<const_pointer>(_M_elems); }
291  };
292 
293 #if __cpp_deduction_guides >= 201606
294  template<typename _Tp, typename... _Up>
295  array(_Tp, _Up...)
296  -> array<enable_if_t<(is_same_v<_Tp, _Up> && ...), _Tp>,
297  1 + sizeof...(_Up)>;
298 #endif
299 
300  // Array comparisons.
301  template<typename _Tp, std::size_t _Nm>
302  [[__nodiscard__]]
303  _GLIBCXX20_CONSTEXPR
304  inline bool
305  operator==(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two)
306  { return std::__equal_aux1(__one.begin(), __one.end(), __two.begin()); }
307 
308 #if __cpp_lib_three_way_comparison // C++ >= 20 && lib_concepts
309  template<typename _Tp, size_t _Nm>
310  [[nodiscard]]
311  constexpr __detail::__synth3way_t<_Tp>
312  operator<=>(const array<_Tp, _Nm>& __a, const array<_Tp, _Nm>& __b)
313  {
314  if constexpr (_Nm && __is_memcmp_ordered<_Tp>::__value)
315  if (!std::__is_constant_evaluated())
316  {
317  constexpr size_t __n = _Nm * sizeof(_Tp);
318  return __builtin_memcmp(__a.data(), __b.data(), __n) <=> 0;
319  }
320 
321  for (size_t __i = 0; __i < _Nm; ++__i)
322  {
323  auto __c = __detail::__synth3way(__a[__i], __b[__i]);
324  if (__c != 0)
325  return __c;
326  }
327  return strong_ordering::equal;
328  }
329 #else
330  template<typename _Tp, std::size_t _Nm>
331  [[__nodiscard__]]
332  _GLIBCXX20_CONSTEXPR
333  inline bool
334  operator!=(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two)
335  { return !(__one == __two); }
336 
337  template<typename _Tp, std::size_t _Nm>
338  [[__nodiscard__]]
339  _GLIBCXX20_CONSTEXPR
340  inline bool
341  operator<(const array<_Tp, _Nm>& __a, const array<_Tp, _Nm>& __b)
342  {
343  return std::lexicographical_compare(__a.begin(), __a.end(),
344  __b.begin(), __b.end());
345  }
346 
347  template<typename _Tp, std::size_t _Nm>
348  [[__nodiscard__]]
349  _GLIBCXX20_CONSTEXPR
350  inline bool
351  operator>(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two)
352  { return __two < __one; }
353 
354  template<typename _Tp, std::size_t _Nm>
355  [[__nodiscard__]]
356  _GLIBCXX20_CONSTEXPR
357  inline bool
358  operator<=(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two)
359  { return !(__one > __two); }
360 
361  template<typename _Tp, std::size_t _Nm>
362  [[__nodiscard__]]
363  _GLIBCXX20_CONSTEXPR
364  inline bool
365  operator>=(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two)
366  { return !(__one < __two); }
367 #endif // three_way_comparison && concepts
368 
369  // Specialized algorithms.
370  template<typename _Tp, std::size_t _Nm>
371  _GLIBCXX20_CONSTEXPR
372  inline
373 #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
374  // Constrained free swap overload, see p0185r1
375  __enable_if_t<__array_traits<_Tp, _Nm>::_Is_swappable::value>
376 #else
377  void
378 #endif
379  swap(array<_Tp, _Nm>& __one, array<_Tp, _Nm>& __two)
380  noexcept(noexcept(__one.swap(__two)))
381  { __one.swap(__two); }
382 
383 #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
384  template<typename _Tp, std::size_t _Nm>
385  __enable_if_t<!__array_traits<_Tp, _Nm>::_Is_swappable::value>
386  swap(array<_Tp, _Nm>&, array<_Tp, _Nm>&) = delete;
387 #endif
388 
389  template<std::size_t _Int, typename _Tp, std::size_t _Nm>
390  [[__nodiscard__]]
391  constexpr _Tp&
392  get(array<_Tp, _Nm>& __arr) noexcept
393  {
394  static_assert(_Int < _Nm, "array index is within bounds");
395  return __arr._M_elems[_Int];
396  }
397 
398  template<std::size_t _Int, typename _Tp, std::size_t _Nm>
399  [[__nodiscard__]]
400  constexpr _Tp&&
401  get(array<_Tp, _Nm>&& __arr) noexcept
402  {
403  static_assert(_Int < _Nm, "array index is within bounds");
404  return std::move(std::get<_Int>(__arr));
405  }
406 
407  template<std::size_t _Int, typename _Tp, std::size_t _Nm>
408  [[__nodiscard__]]
409  constexpr const _Tp&
410  get(const array<_Tp, _Nm>& __arr) noexcept
411  {
412  static_assert(_Int < _Nm, "array index is within bounds");
413  return __arr._M_elems[_Int];
414  }
415 
416  template<std::size_t _Int, typename _Tp, std::size_t _Nm>
417  [[__nodiscard__]]
418  constexpr const _Tp&&
419  get(const array<_Tp, _Nm>&& __arr) noexcept
420  {
421  static_assert(_Int < _Nm, "array index is within bounds");
422  return std::move(std::get<_Int>(__arr));
423  }
424 
425 #ifdef __cpp_lib_to_array // C++ >= 20 && __cpp_generic_lambdas >= 201707L
426  template<typename _Tp, size_t _Nm>
427  [[nodiscard]]
428  constexpr array<remove_cv_t<_Tp>, _Nm>
429  to_array(_Tp (&__a)[_Nm])
430  noexcept(is_nothrow_constructible_v<_Tp, _Tp&>)
431  {
432  static_assert(!is_array_v<_Tp>);
433  static_assert(is_constructible_v<_Tp, _Tp&>);
434  if constexpr (is_constructible_v<_Tp, _Tp&>)
435  {
436  if constexpr (is_trivially_copyable_v<_Tp>
437  && is_trivially_default_constructible_v<_Tp>
438  && is_copy_assignable_v<_Tp>)
439  {
440  array<remove_cv_t<_Tp>, _Nm> __arr;
441  if (!__is_constant_evaluated() && _Nm != 0)
442  __builtin_memcpy((void*)__arr.data(), (void*)__a, sizeof(__a));
443  else
444  for (size_t __i = 0; __i < _Nm; ++__i)
445  __arr._M_elems[__i] = __a[__i];
446  return __arr;
447  }
448  else
449  return [&__a]<size_t... _Idx>(index_sequence<_Idx...>) {
450  return array<remove_cv_t<_Tp>, _Nm>{{ __a[_Idx]... }};
451  }(make_index_sequence<_Nm>{});
452  }
453  else
454  __builtin_unreachable(); // FIXME: see PR c++/91388
455  }
456 
457  template<typename _Tp, size_t _Nm>
458  [[nodiscard]]
459  constexpr array<remove_cv_t<_Tp>, _Nm>
460  to_array(_Tp (&&__a)[_Nm])
461  noexcept(is_nothrow_move_constructible_v<_Tp>)
462  {
463  static_assert(!is_array_v<_Tp>);
464  static_assert(is_move_constructible_v<_Tp>);
465  if constexpr (is_move_constructible_v<_Tp>)
466  {
467  if constexpr (is_trivially_copyable_v<_Tp>
468  && is_trivially_default_constructible_v<_Tp>
469  && is_copy_assignable_v<_Tp>)
470  {
471  array<remove_cv_t<_Tp>, _Nm> __arr;
472  if (!__is_constant_evaluated() && _Nm != 0)
473  __builtin_memcpy((void*)__arr.data(), (void*)__a, sizeof(__a));
474  else
475  for (size_t __i = 0; __i < _Nm; ++__i)
476  __arr._M_elems[__i] = __a[__i];
477  return __arr;
478  }
479  else
480  return [&__a]<size_t... _Idx>(index_sequence<_Idx...>) {
481  return array<remove_cv_t<_Tp>, _Nm>{{ std::move(__a[_Idx])... }};
482  }(make_index_sequence<_Nm>{});
483  }
484  else
485  __builtin_unreachable(); // FIXME: see PR c++/91388
486  }
487 #endif // __cpp_lib_to_array
488 
489  // Tuple interface to class template array.
490 
491  /// Partial specialization for std::array
492  template<typename _Tp, size_t _Nm>
493  struct tuple_size<array<_Tp, _Nm>>
494  : public integral_constant<size_t, _Nm> { };
495 
496  /// Partial specialization for std::array
497  template<size_t _Ind, typename _Tp, size_t _Nm>
498  struct tuple_element<_Ind, array<_Tp, _Nm>>
499  {
500  static_assert(_Ind < _Nm, "array index is in range");
501  using type = _Tp;
502  };
503 
504 #if __cplusplus >= 201703L
505  template<typename _Tp, size_t _Nm>
506  inline constexpr size_t tuple_size_v<array<_Tp, _Nm>> = _Nm;
507 
508  template<typename _Tp, size_t _Nm>
509  inline constexpr size_t tuple_size_v<const array<_Tp, _Nm>> = _Nm;
510 #endif
511 
512  template<typename _Tp, size_t _Nm>
513  struct __is_tuple_like_impl<array<_Tp, _Nm>> : true_type
514  { };
515 
516 _GLIBCXX_END_NAMESPACE_VERSION
517 } // namespace std
518 
519 #endif // C++11
520 
521 #endif // _GLIBCXX_ARRAY