libstdc++
debug/array
Go to the documentation of this file.
1 // Debugging array implementation -*- C++ -*-
2 
3 // Copyright (C) 2012-2020 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 debug/array
26  * This is a Standard C++ Library header.
27  */
28 
29 #ifndef _GLIBCXX_DEBUG_ARRAY
30 #define _GLIBCXX_DEBUG_ARRAY 1
31 
32 #pragma GCC system_header
33 
34 #include <array>
35 
36 #include <debug/formatter.h>
37 #include <debug/macros.h>
38 
39 namespace std _GLIBCXX_VISIBILITY(default)
40 {
41 namespace __debug
42 {
43  template<typename _Tp, std::size_t _Nm>
44  struct array
45  {
46  typedef _Tp value_type;
47  typedef value_type* pointer;
48  typedef const value_type* const_pointer;
49  typedef value_type& reference;
50  typedef const value_type& const_reference;
51  typedef value_type* iterator;
52  typedef const value_type* const_iterator;
53  typedef std::size_t size_type;
54  typedef std::ptrdiff_t difference_type;
55  typedef std::reverse_iterator<iterator> reverse_iterator;
56  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
57 
58  // Support for zero-sized arrays mandatory.
59  typedef _GLIBCXX_STD_C::__array_traits<_Tp, _Nm> _AT_Type;
60  typename _AT_Type::_Type _M_elems;
61 
62  template<std::size_t _Size>
63  struct _Array_check_subscript
64  {
65  std::size_t size() { return _Size; }
66 
67  _Array_check_subscript(std::size_t __index)
68  { __glibcxx_check_subscript(__index); }
69  };
70 
71  template<std::size_t _Size>
72  struct _Array_check_nonempty
73  {
74  _GLIBCXX_NODISCARD bool empty() { return _Size == 0; }
75 
76  _Array_check_nonempty()
77  { __glibcxx_check_nonempty(); }
78  };
79 
80  // No explicit construct/copy/destroy for aggregate type.
81 
82  // DR 776.
83  _GLIBCXX20_CONSTEXPR void
84  fill(const value_type& __u)
85  { std::fill_n(begin(), size(), __u); }
86 
87  _GLIBCXX20_CONSTEXPR void
88  swap(array& __other)
89  noexcept(_AT_Type::_Is_nothrow_swappable::value)
90  { std::swap_ranges(begin(), end(), __other.begin()); }
91 
92  // Iterators.
93  _GLIBCXX17_CONSTEXPR iterator
94  begin() noexcept
95  { return iterator(data()); }
96 
97  _GLIBCXX17_CONSTEXPR const_iterator
98  begin() const noexcept
99  { return const_iterator(data()); }
100 
101  _GLIBCXX17_CONSTEXPR iterator
102  end() noexcept
103  { return iterator(data() + _Nm); }
104 
105  _GLIBCXX17_CONSTEXPR const_iterator
106  end() const noexcept
107  { return const_iterator(data() + _Nm); }
108 
109  _GLIBCXX17_CONSTEXPR reverse_iterator
110  rbegin() noexcept
111  { return reverse_iterator(end()); }
112 
113  _GLIBCXX17_CONSTEXPR const_reverse_iterator
114  rbegin() const noexcept
115  { return const_reverse_iterator(end()); }
116 
117  _GLIBCXX17_CONSTEXPR reverse_iterator
118  rend() noexcept
119  { return reverse_iterator(begin()); }
120 
121  _GLIBCXX17_CONSTEXPR const_reverse_iterator
122  rend() const noexcept
123  { return const_reverse_iterator(begin()); }
124 
125  _GLIBCXX17_CONSTEXPR const_iterator
126  cbegin() const noexcept
127  { return const_iterator(data()); }
128 
129  _GLIBCXX17_CONSTEXPR const_iterator
130  cend() const noexcept
131  { return const_iterator(data() + _Nm); }
132 
133  _GLIBCXX17_CONSTEXPR const_reverse_iterator
134  crbegin() const noexcept
135  { return const_reverse_iterator(end()); }
136 
137  _GLIBCXX17_CONSTEXPR const_reverse_iterator
138  crend() const noexcept
139  { return const_reverse_iterator(begin()); }
140 
141  // Capacity.
142  constexpr size_type
143  size() const noexcept { return _Nm; }
144 
145  constexpr size_type
146  max_size() const noexcept { return _Nm; }
147 
148  _GLIBCXX_NODISCARD constexpr bool
149  empty() const noexcept { return size() == 0; }
150 
151  // Element access.
152  _GLIBCXX17_CONSTEXPR reference
153  operator[](size_type __n) noexcept
154  {
155  __glibcxx_check_subscript(__n);
156  return _AT_Type::_S_ref(_M_elems, __n);
157  }
158 
159  constexpr const_reference
160  operator[](size_type __n) const noexcept
161  {
162  return __n < _Nm ? _AT_Type::_S_ref(_M_elems, __n)
163  : (_GLIBCXX_THROW_OR_ABORT(_Array_check_subscript<_Nm>(__n)),
164  _AT_Type::_S_ref(_M_elems, 0));
165  }
166 
167  _GLIBCXX17_CONSTEXPR reference
168  at(size_type __n)
169  {
170  if (__n >= _Nm)
171  std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) "
172  ">= _Nm (which is %zu)"),
173  __n, _Nm);
174  return _AT_Type::_S_ref(_M_elems, __n);
175  }
176 
177  constexpr const_reference
178  at(size_type __n) const
179  {
180  // Result of conditional expression must be an lvalue so use
181  // boolean ? lvalue : (throw-expr, lvalue)
182  return __n < _Nm ? _AT_Type::_S_ref(_M_elems, __n)
183  : (std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) "
184  ">= _Nm (which is %zu)"),
185  __n, _Nm),
186  _AT_Type::_S_ref(_M_elems, 0));
187  }
188 
189  _GLIBCXX17_CONSTEXPR reference
190  front() noexcept
191  {
192  __glibcxx_check_nonempty();
193  return *begin();
194  }
195 
196  constexpr const_reference
197  front() const noexcept
198  {
199  return _Nm ? _AT_Type::_S_ref(_M_elems, 0)
200  : (_GLIBCXX_THROW_OR_ABORT(_Array_check_nonempty<_Nm>()),
201  _AT_Type::_S_ref(_M_elems, 0));
202  }
203 
204  _GLIBCXX17_CONSTEXPR reference
205  back() noexcept
206  {
207  __glibcxx_check_nonempty();
208  return _Nm ? *(end() - 1) : *end();
209  }
210 
211  constexpr const_reference
212  back() const noexcept
213  {
214  return _Nm ? _AT_Type::_S_ref(_M_elems, _Nm - 1)
215  : (_GLIBCXX_THROW_OR_ABORT(_Array_check_nonempty<_Nm>()),
216  _AT_Type::_S_ref(_M_elems, 0));
217  }
218 
219  _GLIBCXX17_CONSTEXPR pointer
220  data() noexcept
221  { return _AT_Type::_S_ptr(_M_elems); }
222 
223  _GLIBCXX17_CONSTEXPR const_pointer
224  data() const noexcept
225  { return _AT_Type::_S_ptr(_M_elems); }
226  };
227 
228 #if __cpp_deduction_guides >= 201606
229  template<typename _Tp, typename... _Up>
230  array(_Tp, _Up...)
231  -> array<std::enable_if_t<(std::is_same_v<_Tp, _Up> && ...), _Tp>,
232  1 + sizeof...(_Up)>;
233 #endif
234 
235  // Array comparisons.
236  template<typename _Tp, std::size_t _Nm>
237  _GLIBCXX20_CONSTEXPR
238  inline bool
239  operator==(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two)
240  { return std::equal(__one.begin(), __one.end(), __two.begin()); }
241 
242 #if __cpp_lib_three_way_comparison && __cpp_lib_concepts
243  template<typename _Tp, size_t _Nm>
244  constexpr __detail::__synth3way_t<_Tp>
245  operator<=>(const array<_Tp, _Nm>& __a, const array<_Tp, _Nm>& __b)
246  {
247  if constexpr (_Nm && __is_byte<_Tp>::__value)
248  return __builtin_memcmp(__a.data(), __b.data(), _Nm) <=> 0;
249  else
250  {
251  for (size_t __i = 0; __i < _Nm; ++__i)
252  {
253  auto __c = __detail::__synth3way(__a[__i], __b[__i]);
254  if (__c != 0)
255  return __c;
256  }
257  }
258  return strong_ordering::equal;
259  }
260 #else
261  template<typename _Tp, std::size_t _Nm>
262  _GLIBCXX20_CONSTEXPR
263  inline bool
264  operator!=(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two)
265  { return !(__one == __two); }
266 
267  template<typename _Tp, std::size_t _Nm>
268  _GLIBCXX20_CONSTEXPR
269  inline bool
270  operator<(const array<_Tp, _Nm>& __a, const array<_Tp, _Nm>& __b)
271  {
272  return std::lexicographical_compare(__a.begin(), __a.end(),
273  __b.begin(), __b.end());
274  }
275 
276  template<typename _Tp, std::size_t _Nm>
277  _GLIBCXX20_CONSTEXPR
278  inline bool
279  operator>(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two)
280  { return __two < __one; }
281 
282  template<typename _Tp, std::size_t _Nm>
283  _GLIBCXX20_CONSTEXPR
284  inline bool
285  operator<=(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two)
286  { return !(__one > __two); }
287 
288  template<typename _Tp, std::size_t _Nm>
289  _GLIBCXX20_CONSTEXPR
290  inline bool
291  operator>=(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two)
292  { return !(__one < __two); }
293 #endif // three_way_comparison && concepts
294 
295  // Specialized algorithms.
296 
297 #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
298  template<typename _Tp, size_t _Nm>
299  typename enable_if<
300  !_GLIBCXX_STD_C::__array_traits<_Tp, _Nm>::_Is_swappable::value>::type
301  swap(array<_Tp, _Nm>&, array<_Tp, _Nm>&) = delete;
302 #endif
303 
304  template<typename _Tp, std::size_t _Nm>
305  _GLIBCXX20_CONSTEXPR
306  inline void
307  swap(array<_Tp, _Nm>& __one, array<_Tp, _Nm>& __two)
308  noexcept(noexcept(__one.swap(__two)))
309  { __one.swap(__two); }
310 
311  template<std::size_t _Int, typename _Tp, std::size_t _Nm>
312  constexpr _Tp&
313  get(array<_Tp, _Nm>& __arr) noexcept
314  {
315  static_assert(_Int < _Nm, "index is out of bounds");
316  return _GLIBCXX_STD_C::__array_traits<_Tp, _Nm>::
317  _S_ref(__arr._M_elems, _Int);
318  }
319 
320  template<std::size_t _Int, typename _Tp, std::size_t _Nm>
321  constexpr _Tp&&
322  get(array<_Tp, _Nm>&& __arr) noexcept
323  {
324  static_assert(_Int < _Nm, "index is out of bounds");
325  return std::move(__debug::get<_Int>(__arr));
326  }
327 
328  template<std::size_t _Int, typename _Tp, std::size_t _Nm>
329  constexpr const _Tp&
330  get(const array<_Tp, _Nm>& __arr) noexcept
331  {
332  static_assert(_Int < _Nm, "index is out of bounds");
333  return _GLIBCXX_STD_C::__array_traits<_Tp, _Nm>::
334  _S_ref(__arr._M_elems, _Int);
335  }
336 
337  template<std::size_t _Int, typename _Tp, std::size_t _Nm>
338  constexpr const _Tp&&
339  get(const array<_Tp, _Nm>&& __arr) noexcept
340  {
341  static_assert(_Int < _Nm, "index is out of bounds");
342  return std::move(__debug::get<_Int>(__arr));
343  }
344 
345 #if __cplusplus > 201703L
346 #define __cpp_lib_to_array 201907L
347 
348  template<bool _Move = false, typename _Tp, size_t... _Idx>
349  constexpr array<remove_cv_t<_Tp>, sizeof...(_Idx)>
350  __to_array(_Tp (&__a)[sizeof...(_Idx)], index_sequence<_Idx...>)
351  {
352  if constexpr (_Move)
353  return {{std::move(__a[_Idx])...}};
354  else
355  return {{__a[_Idx]...}};
356  }
357 
358  template<typename _Tp, size_t _Nm>
359  constexpr array<remove_cv_t<_Tp>, _Nm>
360  to_array(_Tp (&__a)[_Nm])
361  noexcept(is_nothrow_constructible_v<_Tp, _Tp&>)
362  {
363  static_assert(!is_array_v<_Tp>);
364  static_assert(is_constructible_v<_Tp, _Tp&>);
365  if constexpr (is_constructible_v<_Tp, _Tp&>)
366  return __debug::__to_array(__a, make_index_sequence<_Nm>{});
367  __builtin_unreachable(); // FIXME: see PR c++/91388
368  }
369 
370  template<typename _Tp, size_t _Nm>
371  constexpr array<remove_cv_t<_Tp>, _Nm>
372  to_array(_Tp (&&__a)[_Nm])
373  noexcept(is_nothrow_move_constructible_v<_Tp>)
374  {
375  static_assert(!is_array_v<_Tp>);
376  static_assert(is_move_constructible_v<_Tp>);
377  if constexpr (is_move_constructible_v<_Tp>)
378  return __debug::__to_array<1>(__a, make_index_sequence<_Nm>{});
379  __builtin_unreachable(); // FIXME: see PR c++/91388
380  }
381 #endif // C++20
382 
383 } // namespace __debug
384 
385 _GLIBCXX_BEGIN_NAMESPACE_VERSION
386  // Tuple interface to class template array.
387 
388  /// tuple_size
389  template<typename _Tp, std::size_t _Nm>
390  struct tuple_size<std::__debug::array<_Tp, _Nm>>
391  : public integral_constant<std::size_t, _Nm> { };
392 
393  /// tuple_element
394  template<std::size_t _Int, typename _Tp, std::size_t _Nm>
395  struct tuple_element<_Int, std::__debug::array<_Tp, _Nm>>
396  {
397  static_assert(_Int < _Nm, "index is out of bounds");
398  typedef _Tp type;
399  };
400 
401  template<typename _Tp, std::size_t _Nm>
402  struct __is_tuple_like_impl<std::__debug::array<_Tp, _Nm>> : true_type
403  { };
404 
405 _GLIBCXX_END_NAMESPACE_VERSION
406 } // namespace std
407 
408 #endif // _GLIBCXX_DEBUG_ARRAY