cuda-kat
CUDA kernel author's tools
array.hpp
Go to the documentation of this file.
1 
10 // Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
11 // Copyright (C) 2017, 2019 Eyal Rozenberg <eyalroz@technion.ac.il>
12 //
13 // This file is based on <array> from the GNU ISO C++ Library. It is
14 // free software. Thus, you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the
16 // Free Software Foundation; either version 3, or (at your option)
17 // any later version.
18 //
19 // Under Section 7 of GPL version 3, you are granted additional
20 // permissions described in the GCC Runtime Library Exception, version
21 // 3.1, as published by the Free Software Foundation, i.e.:
22 //
23 // You may use this file as part of a free software library without
24 // restriction. Specifically, if other files instantiate templates or
25 // use macros or inline functions from this file, or you compile this file
26 // and link it with other files to produce an executable, this file does
27 // not by itself cause the resulting executable to be covered by the GNU
28 // General Public License. This exception does not however invalidate any
29 // other reasons why the executable file might be covered by the GNU
30 // General Public License.
31 //
32 // A copy of the GNU General Public License and a copy of the GCC Runtime
33 // Library Exception are available at <http://www.gnu.org/licenses/>.
34 
35 #pragma once
36 #ifndef CUDA_KAT_CONTAINERS_ARRAY_HPP_
37 #define CUDA_KAT_CONTAINERS_ARRAY_HPP_
38 
39 #include <kat/common.hpp>
40 #include <kat/detail/range_access.hpp>
41 
42 #include <cstddef>
43 #include <cstdlib>
44 #include <array>
45 #include <tuple>
46 #include <utility>
47 #include <algorithm>
48 #include <iterator>
49 #include <type_traits>
50 
51 namespace kat {
52 
54 template<typename T, size_t NumElements>
55 struct array_traits
56 {
57  typedef T type[NumElements];
58 
59  KAT_FHD static constexpr T& reference(const type& t, size_t n) noexcept { return const_cast<T&>(t[n]); }
60  KAT_FHD static constexpr T* pointer(const type& t) noexcept { return const_cast<T*>(t); }
61 };
62 
63 template<typename T>
64 struct array_traits<T, 0>
65 {
66  struct type { };
67 
68  KAT_FHD static constexpr T& reference(const type&, size_t) noexcept { return *static_cast<T*>(nullptr); }
69  KAT_FHD static constexpr T* pointer(const type&) noexcept { return nullptr; }
70 };
72 
80 template<typename T, size_t NumElements>
81 struct array
82 {
83  typedef T value_type;
84  typedef value_type* pointer;
85  typedef const value_type* const_pointer;
86  typedef value_type& reference;
87  typedef const value_type& const_reference;
88  typedef value_type* iterator;
89  typedef const value_type* const_iterator;
90  typedef size_t size_type;
91  typedef std::ptrdiff_t difference_type;
92  typedef std::reverse_iterator<iterator> reverse_iterator;
93  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
94 
95  // Support for zero-sized arrays mandatory.
96  typedef array_traits<T, NumElements> array_traits_type;
97 
98  typename array_traits_type::type elements;
99 
100  // No explicit construct/copy/destroy for aggregate type.
101 
102  // DR 776.
103  KAT_FHD CONSTEXPR_SINCE_CPP_14 void fill(const value_type& u)
104  {
105  //std::fill_n(begin(), size(), __u);
106  for(size_type i = 0; i < NumElements; i++) { elements[i] = u; }
107  }
108 
109  // Does the noexcept matter here?
110  KAT_FHD CONSTEXPR_SINCE_CPP_14 void swap(array& other) noexcept(noexcept(std::swap(std::declval<T&>(), std::declval<T&>())))
111  {
112  // std::swap_ranges(begin(), end(), other.begin());
113  for(size_type i = 0; i < NumElements; i++)
114  {
115  auto x = elements[i];
116  auto y = other.elements[i];
117  elements[i] = y;
118  other.elements[i] = x;
119  }
120  }
121 
122  // Iterators.
123 
124  KAT_FHD CONSTEXPR_SINCE_CPP_14 iterator begin() noexcept { return iterator(data()); }
125  KAT_FHD CONSTEXPR_SINCE_CPP_14 const_iterator begin() const noexcept { return const_iterator(data()); }
126  KAT_FHD CONSTEXPR_SINCE_CPP_14 iterator end() noexcept { return iterator(data() + NumElements); }
127  KAT_FHD CONSTEXPR_SINCE_CPP_14 const_iterator end() const noexcept { return const_iterator(data() + NumElements); }
128  KAT_FHD CONSTEXPR_SINCE_CPP_14 reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
129  KAT_FHD CONSTEXPR_SINCE_CPP_14 const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
130  KAT_FHD CONSTEXPR_SINCE_CPP_14 reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
131  KAT_FHD CONSTEXPR_SINCE_CPP_14 const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
132  KAT_FHD CONSTEXPR_SINCE_CPP_14 const_iterator cbegin() const noexcept { return const_iterator(data()); }
133  KAT_FHD CONSTEXPR_SINCE_CPP_14 const_iterator cend() const noexcept { return const_iterator(data() + NumElements); }
134  KAT_FHD CONSTEXPR_SINCE_CPP_14 const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
135  KAT_FHD CONSTEXPR_SINCE_CPP_14 const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
136 
137  // Capacity.
138 
139  KAT_FHD constexpr size_type size() const noexcept { return NumElements; }
140  KAT_FHD constexpr size_type max_size() const noexcept { return NumElements; }
141  KAT_FHD constexpr bool empty() const noexcept { return size() == 0; }
142 
143  // Element access.
144 
145  KAT_FHD CONSTEXPR_SINCE_CPP_14 reference operator[](size_type n) noexcept { return array_traits_type::reference(elements, n); }
146 
147  KAT_FHD constexpr const_reference operator[](size_type n) const noexcept { return array_traits_type::reference(elements, n); }
148 
149  // Note: The bounds checking here is more violent than usual: It will
150  // terminate the execution of the program / the kernel
151  KAT_FHD CONSTEXPR_SINCE_CPP_17 reference at(size_type n) noexcept {
152  if (n > NumElements) {
153 #if __CUDA_ARCH__
154  asm("trap;");
155 #else
156  throw std::out_of_range("kat::array::at: index n exceeds number of elements");
157 #endif
158  }
159  return array_traits_type::reference(elements, n);
160  }
161 
162  // Note: The bounds checking here is more violent than usual in a kernel
163  // terminate the execution of the program / the kernel
164  KAT_FHD CONSTEXPR_SINCE_CPP_17 const_reference at(size_type n) const
165  {
166  if (n > NumElements) {
167 #if __CUDA_ARCH__
168  asm("trap;");
169 #else
170  throw std::out_of_range("kat::array::at: index n exceeds number of elements");
171 #endif
172  }
173  return array_traits_type::reference(elements, n);
174  }
175 
176  KAT_FHD CONSTEXPR_SINCE_CPP_14 reference front() noexcept
177  { return *begin(); }
178 
179  KAT_FHD constexpr const_reference front() const noexcept
180  { return array_traits_type::reference(elements, 0); }
181 
182  KAT_FHD reference back() noexcept
183  { return NumElements ? *(end() - 1) : *end(); }
184 
185  KAT_FHD constexpr const_reference back() const noexcept
186  {
187  return NumElements ?
188  array_traits_type::reference(elements, NumElements - 1) :
189  array_traits_type::reference(elements, 0);
190  }
191 
192  KAT_FHD CONSTEXPR_SINCE_CPP_14 pointer data() noexcept { return array_traits_type::pointer(elements); }
193 
194  KAT_FHD constexpr const_pointer data() const noexcept { return array_traits_type::pointer(elements); }
195 };
196 
197 // Array comparisons.
198 template<typename T, size_t NumElements>
199 KAT_FHD CONSTEXPR_SINCE_CPP_17
200 bool operator==(const array<T, NumElements>& one, const array<T, NumElements>& two)
201 {
202 #if __cplusplus >= 202001L
203  // We can call it, since it's constexpr
204  return std::equal(one.begin(), one.end(), two.begin());
205 #else
206  auto first1 = one.cbegin();
207  const auto last1 = one.cend();
208  auto first2 = two.cbegin();
209  for (; first1 != last1; ++first1, ++first2) {
210  if (!(*first1 == *first2)) {
211  return false;
212  }
213  }
214  return true;
215 #endif
216 }
217 
218 template<typename T, size_t NumElements>
219 KAT_FHD CONSTEXPR_SINCE_CPP_17 bool
220 operator!=(const array<T, NumElements>& one, const array<T, NumElements>& two)
221 { return !(one == two); }
222 
223 template<typename T, size_t NumElements>
224 KAT_FHD bool CONSTEXPR_SINCE_CPP_17
225 operator<(const array<T, NumElements>& a, const array<T, NumElements>& b)
226 {
227 #if __cplusplus >= 202001L
228  // We can call it, since it's constexpr
229  return std::lexicographical_compare(a.cbegin(), a.cend(), b.cbegin(), b.cend());
230 #else
231  auto first1 = a.cbegin();
232  const auto last1 = a.cend();
233  auto first2 = b.cbegin();
234  const auto last2 = b.cend();
235  for ( ; (first1 != last1) && (first2 != last2); ++first1, (void) ++first2 ) {
236  if (*first1 < *first2) return true;
237  if (*first2 < *first1) return false;
238  }
239  return (first1 == last1) && (first2 != last2);
240 #endif
241 }
242 
243 template<typename T, size_t NumElements>
244 KAT_FHD bool CONSTEXPR_SINCE_CPP_17
245 operator>(const array<T, NumElements>& one, const array<T, NumElements>& two)
246 {
247  return two < one;
248 }
249 
250 template<typename T, size_t NumElements>
251 KAT_FHD bool CONSTEXPR_SINCE_CPP_17
252 operator<=(const array<T, NumElements>& one, const array<T, NumElements>& two)
253 {
254  return !(one > two);
255 }
256 
257 template<typename T, size_t NumElements>
258 KAT_FHD bool CONSTEXPR_SINCE_CPP_17
259 operator>=(const array<T, NumElements>& one, const array<T, NumElements>& two)
260 {
261  return !(one < two);
262 }
263 
264 // Specialized algorithms.
265 template<typename T, size_t NumElements>
266 KAT_FHD CONSTEXPR_SINCE_CPP_14 void swap(array<T, NumElements>& one, array<T, NumElements>& two)
267 noexcept(noexcept(one.swap(two)))
268 {
269  one.swap(two);
270 }
271 
272 template<size_t Integer, typename T, size_t NumElements>
273 KAT_FHD constexpr T& get(array<T, NumElements>& arr) noexcept
274 {
275  static_assert(Integer < NumElements, "index is out of bounds");
276  return array_traits<T, NumElements>::reference(arr.elements, Integer);
277 }
278 
279 template<size_t Integer, typename T, size_t NumElements>
280 KAT_FHD constexpr T&& get(array<T, NumElements>&& arr) noexcept
281 {
282  static_assert(Integer < NumElements, "index is out of bounds");
283  return std::move(get<Integer>(arr));
284 }
285 
286 template<size_t Integer, typename T, size_t NumElements>
287 KAT_FHD constexpr const T& get(const array<T, NumElements>& arr) noexcept
288 {
289  static_assert(Integer < NumElements, "index is out of bounds");
290  return array_traits<T, NumElements>::reference(arr.elements, Integer);
291 }
292 
293 } // namespace kat
294 
296 
297 namespace kat {
298 
299 // kat::tuple interface to class template array.
300 
301 template<typename T> class tuple_size;
302 
303 template<typename T, size_t NumElements>
304 struct tuple_size<array<T, NumElements>> : public std::integral_constant<size_t, NumElements> { };
305 
306 template<size_t Integer, typename T> class tuple_element;
307 
308 template<size_t Integer, typename T, size_t NumElements>
309 struct tuple_element<Integer, array<T, NumElements>>
310 {
311  static_assert(Integer < NumElements, "index is out of bounds");
312  using type = T;
313 };
314 
315 template<size_t Integer, typename T, size_t NumElements>
316 struct tuple_element<Integer, const array<T, NumElements>>
317 {
318  static_assert(Integer < NumElements, "index is out of bounds");
319  using type = const T;
320 };
321 
322 template<size_t Integer, typename T, size_t NumElements>
323 struct tuple_element<Integer, volatile array<T, NumElements>>
324 {
325  static_assert(Integer < NumElements, "index is out of bounds");
326  using type = volatile T;
327 };
328 
329 template<size_t Integer, typename T, size_t NumElements>
330 struct tuple_element<Integer, const volatile array<T, NumElements>>
331 {
332  static_assert(Integer < NumElements, "index is out of bounds");
333  using type = const volatile T;
334 };
335 
336 #if __cplusplus >= 201402L
337 #ifndef _KAT_TUPLE_ELEMENT_T
338 template <size_t I, class T>
339 using tuple_element_t = typename tuple_element<I, T>::type;
340 #define _KAT_TUPLE_ELEMENT_T
341 #endif
342 #endif
343 
345 
346 } // namespace kat
347 
348 namespace std {
349 
350 // std::tuple interface to class template kat::array.
351 
352 
353 template<typename T> class tuple_size;
354 
355 template<typename T, size_t NumElements>
356 struct tuple_size<kat::array<T, NumElements>> : public integral_constant<size_t, NumElements> { };
357 
358 template<size_t Integer, typename T> class tuple_element;
359 
360 template<size_t Integer, typename T, size_t NumElements>
361 struct tuple_element<Integer, kat::array<T, NumElements>>
362 {
363  static_assert(Integer < NumElements, "index is out of bounds");
364  typedef T type;
365 };
366 
367 template<size_t Integer, typename T, size_t NumElements>
368 struct tuple_element<Integer, const kat::array<T, NumElements>>
369 {
370  static_assert(Integer < NumElements, "index is out of bounds");
371  using type = const T;
372 };
373 
374 template<size_t Integer, typename T, size_t NumElements>
375 struct tuple_element<Integer, volatile kat::array<T, NumElements>>
376 {
377  static_assert(Integer < NumElements, "index is out of bounds");
378  using type = volatile T;
379 };
380 
381 template<size_t Integer, typename T, size_t NumElements>
382 struct tuple_element<Integer, const volatile kat::array<T, NumElements>>
383 {
384  static_assert(Integer < NumElements, "index is out of bounds");
385  using type = const volatile T;
386 };
387 
388 } // namespace std
389 
391 
392 #endif // CUDA_KAT_CONTAINERS_ARRAY_HPP_
Definition: tuple.hpp:60
Definition: array.hpp:353
STL namespace.
Definition: common.hpp:16
Basic type and macro definitions used throughout the KAT library.
Definition: tuple.hpp:63
Definition: array.hpp:358
A standard container for storing a fixed size sequence of elements, based on std::array - but fully G...
Definition: array.hpp:81