span.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020-2025, NVIDIA CORPORATION.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <cudf/types.hpp>
20 #include <cudf/utilities/export.hpp>
21 
22 #include <rmm/device_buffer.hpp>
23 #include <rmm/device_uvector.hpp>
24 #include <rmm/device_vector.hpp>
25 
26 #include <thrust/detail/raw_pointer_cast.h>
27 #include <thrust/device_vector.h>
28 #include <thrust/host_vector.h>
29 #include <thrust/memory.h>
30 
31 #include <cstddef>
32 #include <limits>
33 #include <type_traits>
34 #include <utility>
35 
36 namespace CUDF_EXPORT cudf {
45 constexpr std::size_t dynamic_extent = std::numeric_limits<std::size_t>::max();
46  // end of group
48 namespace detail {
49 
54 template <typename T, std::size_t Extent, typename Derived>
55 class span_base {
56  static_assert(Extent == dynamic_extent, "Only dynamic extent is supported");
57 
58  public:
59  using element_type = T;
60  using value_type = std::remove_cv<T>;
61  using size_type = std::size_t;
62  using difference_type = std::ptrdiff_t;
63  using pointer = T*;
64  using iterator = T*;
65  using const_pointer = T const*;
66  using reference = T&;
68  T const&;
69 
70  static constexpr std::size_t extent = Extent;
71 
72  CUDF_HOST_DEVICE constexpr span_base() noexcept {}
79  CUDF_HOST_DEVICE constexpr span_base(pointer data, size_type size) : _data(data), _size(size) {}
80  // constexpr span_base(pointer begin, pointer end) : _data(begin), _size(end - begin) {}
81  CUDF_HOST_DEVICE constexpr span_base(span_base const&) noexcept = default;
87  CUDF_HOST_DEVICE constexpr span_base& operator=(span_base const&) noexcept = default;
88 
96  [[nodiscard]] CUDF_HOST_DEVICE constexpr iterator begin() const noexcept { return _data; }
104  [[nodiscard]] CUDF_HOST_DEVICE constexpr iterator end() const noexcept { return _data + _size; }
110  [[nodiscard]] CUDF_HOST_DEVICE constexpr pointer data() const noexcept { return _data; }
111 
117  [[nodiscard]] CUDF_HOST_DEVICE constexpr size_type size() const noexcept { return _size; }
123  [[nodiscard]] CUDF_HOST_DEVICE constexpr size_type size_bytes() const noexcept
124  {
125  return sizeof(T) * _size;
126  }
127 
133  [[nodiscard]] CUDF_HOST_DEVICE constexpr bool empty() const noexcept { return _size == 0; }
134 
141  [[nodiscard]] constexpr Derived first(size_type count) const noexcept
142  {
143  return Derived(_data, count);
144  }
145 
152  [[nodiscard]] constexpr Derived last(size_type count) const noexcept
153  {
154  return Derived(_data + _size - count, count);
155  }
156 
157  protected:
158  pointer _data{nullptr};
159  size_type _size{0};
160 };
161 
162 } // namespace detail
163 
171 // ===== host_span =================================================================================
172 
173 template <typename T>
174 struct is_host_span_supported_container : std::false_type {};
175 
176 template <typename T, typename Alloc>
178  std::vector<T, Alloc>> : std::true_type {};
179 
180 template <typename T, typename Alloc>
182  thrust::host_vector<T, Alloc>> : std::true_type {};
183 
184 template <typename T, typename Alloc>
186  std::basic_string<T, std::char_traits<T>, Alloc>> : std::true_type {};
187 
192 template <typename T, std::size_t Extent = cudf::dynamic_extent>
193 struct host_span : public cudf::detail::span_base<T, Extent, host_span<T, Extent>> {
195  using base::base;
196 
197  constexpr host_span() noexcept : base() {} // required to compile on centos
198 
208  CUDF_HOST_DEVICE constexpr host_span(T* data, std::size_t size, bool is_device_accessible)
209  : base(data, size), _is_device_accessible{is_device_accessible}
210  {
211  }
212 
215  template <typename C,
216  // Only supported containers of types convertible to T
217  std::enable_if_t<is_host_span_supported_container<C>::value &&
218  std::is_convertible_v<
219  std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
220  std::declval<C&>().data()))> (*)[],
221  T (*)[]>>* = nullptr> // NOLINT
222  constexpr host_span(C& in) : base(thrust::raw_pointer_cast(in.data()), in.size())
223  {
224  }
225 
228  template <typename C,
229  // Only supported containers of types convertible to T
230  std::enable_if_t<is_host_span_supported_container<C>::value &&
231  std::is_convertible_v<
232  std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
233  std::declval<C&>().data()))> (*)[],
234  T (*)[]>>* = nullptr> // NOLINT
235  constexpr host_span(C const& in) : base(thrust::raw_pointer_cast(in.data()), in.size())
236  {
237  }
238 
239  // Copy construction to support const conversion
241  template <typename OtherT,
242  std::size_t OtherExtent,
243  std::enable_if_t<(Extent == OtherExtent || Extent == dynamic_extent) &&
244  std::is_convertible_v<OtherT (*)[], T (*)[]>, // NOLINT
245  void>* = nullptr>
246  constexpr host_span(host_span<OtherT, OtherExtent> const& other) noexcept
247  : base(other.data(), other.size()), _is_device_accessible{other.is_device_accessible()}
248  {
249  }
250  // not noexcept due to undefined behavior when idx < 0 || idx >= size
260  constexpr typename base::reference operator[](typename base::size_type idx) const
261  {
262  static_assert(sizeof(idx) >= sizeof(size_t), "index type must not be smaller than size_t");
263  return this->_data[idx];
264  }
265 
266  // not noexcept due to undefined behavior when size = 0
274  [[nodiscard]] constexpr typename base::reference front() const { return this->_data[0]; }
275  // not noexcept due to undefined behavior when size = 0
283  [[nodiscard]] constexpr typename base::reference back() const
284  {
285  return this->_data[this->_size - 1];
286  }
287 
293  [[nodiscard]] bool is_device_accessible() const { return _is_device_accessible; }
294 
302  [[nodiscard]] CUDF_HOST_DEVICE constexpr host_span subspan(
303  typename base::size_type offset, typename base::size_type count) const noexcept
304  {
305  return host_span{this->data() + offset, count, _is_device_accessible};
306  }
307 
308  private:
309  bool _is_device_accessible{false};
310 };
311 
312 // ===== device_span ===============================================================================
313 
314 template <typename T>
315 struct is_device_span_supported_container : std::false_type {};
316 
317 template <typename T, typename Alloc>
319  thrust::device_vector<T, Alloc>> : std::true_type {};
320 
321 template <typename T>
323  rmm::device_vector<T>> : std::true_type {};
324 
325 template <typename T>
327  rmm::device_uvector<T>> : std::true_type {};
328 
333 template <typename T, std::size_t Extent = cudf::dynamic_extent>
334 struct device_span : public cudf::detail::span_base<T, Extent, device_span<T, Extent>> {
336  using base::base;
337 
338  CUDF_HOST_DEVICE constexpr device_span() noexcept : base() {} // required to compile on centos
339 
342  template <typename C,
343  // Only supported containers of types convertible to T
344  std::enable_if_t<is_device_span_supported_container<C>::value &&
345  std::is_convertible_v<
346  std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
347  std::declval<C&>().data()))> (*)[],
348  T (*)[]>>* = nullptr> // NOLINT
349  constexpr device_span(C& in) : base(thrust::raw_pointer_cast(in.data()), in.size())
350  {
351  }
352 
355  template <typename C,
356  // Only supported containers of types convertible to T
357  std::enable_if_t<is_device_span_supported_container<C>::value &&
358  std::is_convertible_v<
359  std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
360  std::declval<C&>().data()))> (*)[],
361  T (*)[]>>* = nullptr> // NOLINT
362  constexpr device_span(C const& in) : base(thrust::raw_pointer_cast(in.data()), in.size())
363  {
364  }
365 
366  // Copy construction to support const conversion
368  template <typename OtherT,
369  std::size_t OtherExtent,
370  std::enable_if_t<(Extent == OtherExtent || Extent == dynamic_extent) &&
371  std::is_convertible_v<OtherT (*)[], T (*)[]>, // NOLINT
372  void>* = nullptr>
374  : base(other.data(), other.size())
375  {
376  }
377 
378  // not noexcept due to undefined behavior when idx < 0 || idx >= size
388  __device__ constexpr typename base::reference operator[](typename base::size_type idx) const
389  {
390  static_assert(sizeof(idx) >= sizeof(size_t), "index type must not be smaller than size_t");
391  return this->_data[idx];
392  }
393 
394  // not noexcept due to undefined behavior when size = 0
402  [[nodiscard]] __device__ constexpr typename base::reference front() const
403  {
404  return this->_data[0];
405  }
406  // not noexcept due to undefined behavior when size = 0
414  [[nodiscard]] __device__ constexpr typename base::reference back() const
415  {
416  return this->_data[this->_size - 1];
417  }
418 
426  [[nodiscard]] CUDF_HOST_DEVICE constexpr device_span subspan(
427  typename base::size_type offset, typename base::size_type count) const noexcept
428  {
429  return device_span{this->data() + offset, count};
430  }
431 }; // end of group
433 
434 namespace detail {
435 
441 template <typename T, template <typename, std::size_t> typename RowType>
442 class base_2dspan {
443  public:
444  using size_type =
445  std::pair<size_t, size_t>;
446 
447  constexpr base_2dspan() noexcept = default;
454  constexpr base_2dspan(RowType<T, dynamic_extent> flat_view, size_t columns)
455  : _flat{flat_view}, _size{columns == 0 ? 0 : flat_view.size() / columns, columns}
456  {
457 #ifndef __CUDA_ARCH__
458  CUDF_EXPECTS(_size.first * _size.second == flat_view.size(), "Invalid 2D span size");
459 #endif
460  }
461 
467  [[nodiscard]] CUDF_HOST_DEVICE constexpr auto data() const noexcept { return _flat.data(); }
468 
474  [[nodiscard]] CUDF_HOST_DEVICE constexpr auto size() const noexcept { return _size; }
475 
481  [[nodiscard]] CUDF_HOST_DEVICE constexpr auto count() const noexcept { return _flat.size(); }
482 
488  [[nodiscard]] CUDF_HOST_DEVICE constexpr bool is_empty() const noexcept { return count() == 0; }
489 
499  CUDF_HOST_DEVICE constexpr RowType<T, dynamic_extent> operator[](std::size_t row) const
500  {
501  return _flat.subspan(row * _size.second, _size.second);
502  }
503 
509  [[nodiscard]] CUDF_HOST_DEVICE constexpr RowType<T, dynamic_extent> flat_view() const
510  {
511  return _flat;
512  }
513 
521  template <typename OtherT,
522  template <typename, size_t> typename OtherRowType,
523  std::enable_if_t<std::is_convertible_v<OtherRowType<OtherT, dynamic_extent>,
524  RowType<T, dynamic_extent>>,
525  void>* = nullptr>
526  constexpr base_2dspan(base_2dspan<OtherT, OtherRowType> const& other) noexcept
527  : _flat{other.flat_view()}, _size{other.size()}
528  {
529  }
530 
531  protected:
532  RowType<T, dynamic_extent> _flat;
533  size_type _size{0, 0};
534 };
535 
541 template <class T>
543 
549 template <class T>
551 
552 } // namespace detail
553 } // namespace CUDF_EXPORT cudf
Generic class for row-major 2D spans. Not compliant with STL container semantics/syntax.
Definition: span.hpp:442
std::pair< size_t, size_t > size_type
Type used to represent the dimension of the span.
Definition: span.hpp:445
constexpr CUDF_HOST_DEVICE bool is_empty() const noexcept
Checks if the span is empty.
Definition: span.hpp:488
constexpr CUDF_HOST_DEVICE auto size() const noexcept
Returns the size in the span as pair.
Definition: span.hpp:474
constexpr CUDF_HOST_DEVICE auto count() const noexcept
Returns the number of elements in the span.
Definition: span.hpp:481
constexpr CUDF_HOST_DEVICE RowType< T, dynamic_extent > operator[](std::size_t row) const
Returns a reference to the row-th element of the sequence.
Definition: span.hpp:499
constexpr CUDF_HOST_DEVICE auto data() const noexcept
Returns a pointer to the beginning of the sequence.
Definition: span.hpp:467
constexpr CUDF_HOST_DEVICE RowType< T, dynamic_extent > flat_view() const
Returns a flattened span of the 2D span.
Definition: span.hpp:509
RowType< T, dynamic_extent > _flat
flattened 2D span
Definition: span.hpp:532
constexpr base_2dspan(base_2dspan< OtherT, OtherRowType > const &other) noexcept
Construct a 2D span from another 2D span of convertible type.
Definition: span.hpp:526
C++20 std::span with reduced feature set.
Definition: span.hpp:55
std::size_t size_type
The type used for the size of the span.
Definition: span.hpp:61
constexpr CUDF_HOST_DEVICE iterator end() const noexcept
Returns an iterator to the element following the last element of the span.
Definition: span.hpp:104
constexpr Derived first(size_type count) const noexcept
Obtains a subspan consisting of the first N elements of the sequence.
Definition: span.hpp:141
T * iterator
The type of the iterator returned by begin()
Definition: span.hpp:64
constexpr CUDF_HOST_DEVICE pointer data() const noexcept
Returns a pointer to the beginning of the sequence.
Definition: span.hpp:110
constexpr CUDF_HOST_DEVICE span_base(span_base const &) noexcept=default
Copy constructor.
constexpr CUDF_HOST_DEVICE size_type size() const noexcept
Returns the number of elements in the span.
Definition: span.hpp:117
constexpr Derived last(size_type count) const noexcept
Obtains a subspan consisting of the last N elements of the sequence.
Definition: span.hpp:152
std::remove_cv< T > value_type
Stored value type.
Definition: span.hpp:60
std::ptrdiff_t difference_type
std::ptrdiff_t
Definition: span.hpp:62
T * pointer
The type of the pointer returned by data()
Definition: span.hpp:63
T const * const_pointer
The type of the pointer returned by data() const.
Definition: span.hpp:65
constexpr CUDF_HOST_DEVICE span_base & operator=(span_base const &) noexcept=default
Copy assignment operator.
constexpr CUDF_HOST_DEVICE span_base(pointer data, size_type size)
Constructs a span from a pointer and a size.
Definition: span.hpp:79
T & reference
The type of the reference returned by operator[](size_type)
Definition: span.hpp:66
constexpr CUDF_HOST_DEVICE bool empty() const noexcept
Checks if the span is empty.
Definition: span.hpp:133
constexpr CUDF_HOST_DEVICE iterator begin() const noexcept
Returns an iterator to the first element of the span.
Definition: span.hpp:96
constexpr CUDF_HOST_DEVICE size_type size_bytes() const noexcept
Returns the size of the sequence in bytes.
Definition: span.hpp:123
T const & const_reference
The type of the reference returned by operator[](size_type) const.
Definition: span.hpp:68
T element_type
The type of the elements in the span.
Definition: span.hpp:59
thrust::device_vector< T, rmm::mr::thrust_allocator< T > > device_vector
#define CUDF_EXPECTS(...)
Macro for checking (pre-)conditions that throws an exception when a condition is violated.
Definition: error.hpp:154
constexpr std::size_t dynamic_extent
A constant used to differentiate std::span of static and dynamic extent.
Definition: span.hpp:45
cuDF interfaces
Definition: host_udf.hpp:37
Device version of C++20 std::span with reduced feature set.
Definition: span.hpp:334
constexpr base::reference back() const
Returns a reference to the last element in the span.
Definition: span.hpp:414
constexpr CUDF_HOST_DEVICE device_span(device_span< OtherT, OtherExtent > const &other) noexcept
Definition: span.hpp:373
constexpr base::reference front() const
Returns a reference to the first element in the span.
Definition: span.hpp:402
constexpr CUDF_HOST_DEVICE device_span subspan(typename base::size_type offset, typename base::size_type count) const noexcept
Obtains a span that is a view over the count elements of this span starting at offset.
Definition: span.hpp:426
constexpr device_span(C &in)
Definition: span.hpp:349
constexpr device_span(C const &in)
Definition: span.hpp:362
constexpr base::reference operator[](typename base::size_type idx) const
Returns a reference to the idx-th element of the sequence.
Definition: span.hpp:388
C++20 std::span with reduced feature set.
Definition: span.hpp:193
constexpr base::reference front() const
Returns a reference to the first element in the span.
Definition: span.hpp:274
constexpr base::reference operator[](typename base::size_type idx) const
Returns a reference to the idx-th element of the sequence.
Definition: span.hpp:260
constexpr host_span(C const &in)
Definition: span.hpp:235
bool is_device_accessible() const
Returns whether the data is device accessible (e.g. pinned memory)
Definition: span.hpp:293
constexpr host_span(host_span< OtherT, OtherExtent > const &other) noexcept
Definition: span.hpp:246
constexpr CUDF_HOST_DEVICE host_span(T *data, std::size_t size, bool is_device_accessible)
Constructor from pointer and size.
Definition: span.hpp:208
constexpr base::reference back() const
Returns a reference to the last element in the span.
Definition: span.hpp:283
constexpr host_span(C &in)
Definition: span.hpp:222
constexpr CUDF_HOST_DEVICE host_span subspan(typename base::size_type offset, typename base::size_type count) const noexcept
Obtains a span that is a view over the count elements of this span starting at offset.
Definition: span.hpp:302
Type declarations for libcudf.
#define CUDF_HOST_DEVICE
Indicates that the function or method is usable on host and device.
Definition: types.hpp:32