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/detail/utilities/host_vector.hpp>
20 #include <cudf/types.hpp>
21 #include <cudf/utilities/export.hpp>
22 
23 #include <rmm/device_buffer.hpp>
24 #include <rmm/device_uvector.hpp>
25 #include <rmm/device_vector.hpp>
26 
27 #include <thrust/detail/raw_pointer_cast.h>
28 #include <thrust/device_vector.h>
29 #include <thrust/host_vector.h>
30 #include <thrust/memory.h>
31 
32 #include <cstddef>
33 #include <limits>
34 #include <type_traits>
35 #include <utility>
36 
37 namespace CUDF_EXPORT cudf {
46 constexpr std::size_t dynamic_extent = std::numeric_limits<std::size_t>::max();
47  // end of group
49 namespace detail {
50 
55 template <typename T, std::size_t Extent, typename Derived>
56 class span_base {
57  static_assert(Extent == dynamic_extent, "Only dynamic extent is supported");
58 
59  public:
60  using element_type = T;
61  using value_type = std::remove_cv<T>;
62  using size_type = std::size_t;
63  using difference_type = std::ptrdiff_t;
64  using pointer = T*;
65  using iterator = T*;
66  using const_pointer = T const*;
67  using reference = T&;
69  T const&;
70 
71  static constexpr std::size_t extent = Extent;
72 
73  CUDF_HOST_DEVICE constexpr span_base() noexcept {}
80  CUDF_HOST_DEVICE constexpr span_base(pointer data, size_type size) : _data(data), _size(size) {}
81  // constexpr span_base(pointer begin, pointer end) : _data(begin), _size(end - begin) {}
82  CUDF_HOST_DEVICE constexpr span_base(span_base const&) noexcept = default;
88  CUDF_HOST_DEVICE constexpr span_base& operator=(span_base const&) noexcept = default;
89 
97  [[nodiscard]] CUDF_HOST_DEVICE constexpr iterator begin() const noexcept { return _data; }
105  [[nodiscard]] CUDF_HOST_DEVICE constexpr iterator end() const noexcept { return _data + _size; }
111  [[nodiscard]] CUDF_HOST_DEVICE constexpr pointer data() const noexcept { return _data; }
112 
118  [[nodiscard]] CUDF_HOST_DEVICE constexpr size_type size() const noexcept { return _size; }
124  [[nodiscard]] CUDF_HOST_DEVICE constexpr size_type size_bytes() const noexcept
125  {
126  return sizeof(T) * _size;
127  }
128 
134  [[nodiscard]] CUDF_HOST_DEVICE constexpr bool empty() const noexcept { return _size == 0; }
135 
142  [[nodiscard]] constexpr Derived first(size_type count) const noexcept
143  {
144  return Derived(_data, count);
145  }
146 
153  [[nodiscard]] constexpr Derived last(size_type count) const noexcept
154  {
155  return Derived(_data + _size - count, count);
156  }
157 
158  protected:
159  pointer _data{nullptr};
160  size_type _size{0};
161 };
162 
163 } // namespace detail
164 
172 // ===== host_span =================================================================================
173 
174 template <typename T>
175 struct is_host_span_supported_container : std::false_type {};
176 
177 template <typename T, typename Alloc>
179  std::vector<T, Alloc>> : std::true_type {};
180 
181 template <typename T, typename Alloc>
183  thrust::host_vector<T, Alloc>> : std::true_type {};
184 
185 template <typename T, typename Alloc>
187  std::basic_string<T, std::char_traits<T>, Alloc>> : std::true_type {};
188 
193 template <typename T, std::size_t Extent = cudf::dynamic_extent>
194 struct host_span : public cudf::detail::span_base<T, Extent, host_span<T, Extent>> {
196  using base::base;
197 
198  constexpr host_span() noexcept : base() {} // required to compile on centos
199 
209  CUDF_HOST_DEVICE constexpr host_span(T* data, std::size_t size, bool is_device_accessible)
210  : base(data, size), _is_device_accessible{is_device_accessible}
211  {
212  }
213 
216  template <typename C,
217  // Only supported containers of types convertible to T
218  std::enable_if_t<is_host_span_supported_container<C>::value &&
219  std::is_convertible_v<
220  std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
221  std::declval<C&>().data()))> (*)[],
222  T (*)[]>>* = nullptr> // NOLINT
223  constexpr host_span(C& in) : base(thrust::raw_pointer_cast(in.data()), in.size())
224  {
225  }
226 
229  template <typename C,
230  // Only supported containers of types convertible to T
231  std::enable_if_t<is_host_span_supported_container<C>::value &&
232  std::is_convertible_v<
233  std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
234  std::declval<C&>().data()))> (*)[],
235  T (*)[]>>* = nullptr> // NOLINT
236  constexpr host_span(C const& in) : base(thrust::raw_pointer_cast(in.data()), in.size())
237  {
238  }
239 
242  template <typename OtherT,
243  // Only supported containers of types convertible to T
244  std::enable_if_t<std::is_convertible_v<OtherT (*)[], T (*)[]>>* = nullptr> // NOLINT
245  constexpr host_span(cudf::detail::host_vector<OtherT>& in)
246  : base(in.data(), in.size()), _is_device_accessible{in.get_allocator().is_device_accessible()}
247  {
248  }
249 
252  template <typename OtherT,
253  // Only supported containers of types convertible to T
254  std::enable_if_t<std::is_convertible_v<OtherT (*)[], T (*)[]>>* = nullptr> // NOLINT
255  constexpr host_span(cudf::detail::host_vector<OtherT> const& in)
256  : base(in.data(), in.size()), _is_device_accessible{in.get_allocator().is_device_accessible()}
257  {
258  }
259 
260  // Copy construction to support const conversion
262  template <typename OtherT,
263  std::size_t OtherExtent,
264  std::enable_if_t<(Extent == OtherExtent || Extent == dynamic_extent) &&
265  std::is_convertible_v<OtherT (*)[], T (*)[]>, // NOLINT
266  void>* = nullptr>
267  constexpr host_span(host_span<OtherT, OtherExtent> const& other) noexcept
268  : base(other.data(), other.size()), _is_device_accessible{other.is_device_accessible()}
269  {
270  }
271  // not noexcept due to undefined behavior when idx < 0 || idx >= size
281  constexpr typename base::reference operator[](typename base::size_type idx) const
282  {
283  static_assert(sizeof(idx) >= sizeof(size_t), "index type must not be smaller than size_t");
284  return this->_data[idx];
285  }
286 
287  // not noexcept due to undefined behavior when size = 0
295  [[nodiscard]] constexpr typename base::reference front() const { return this->_data[0]; }
296  // not noexcept due to undefined behavior when size = 0
304  [[nodiscard]] constexpr typename base::reference back() const
305  {
306  return this->_data[this->_size - 1];
307  }
308 
314  [[nodiscard]] bool is_device_accessible() const { return _is_device_accessible; }
315 
323  [[nodiscard]] CUDF_HOST_DEVICE constexpr host_span subspan(
324  typename base::size_type offset, typename base::size_type count) const noexcept
325  {
326  return host_span{this->data() + offset, count, _is_device_accessible};
327  }
328 
329  private:
330  bool _is_device_accessible{false};
331 };
332 
333 // ===== device_span ===============================================================================
334 
335 template <typename T>
336 struct is_device_span_supported_container : std::false_type {};
337 
338 template <typename T, typename Alloc>
340  thrust::device_vector<T, Alloc>> : std::true_type {};
341 
342 template <typename T>
344  rmm::device_vector<T>> : std::true_type {};
345 
346 template <typename T>
348  rmm::device_uvector<T>> : std::true_type {};
349 
354 template <typename T, std::size_t Extent = cudf::dynamic_extent>
355 struct device_span : public cudf::detail::span_base<T, Extent, device_span<T, Extent>> {
357  using base::base;
358 
359  CUDF_HOST_DEVICE constexpr device_span() noexcept : base() {} // required to compile on centos
360 
363  template <typename C,
364  // Only supported containers of types convertible to T
365  std::enable_if_t<is_device_span_supported_container<C>::value &&
366  std::is_convertible_v<
367  std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
368  std::declval<C&>().data()))> (*)[],
369  T (*)[]>>* = nullptr> // NOLINT
370  constexpr device_span(C& in) : base(thrust::raw_pointer_cast(in.data()), in.size())
371  {
372  }
373 
376  template <typename C,
377  // Only supported containers of types convertible to T
378  std::enable_if_t<is_device_span_supported_container<C>::value &&
379  std::is_convertible_v<
380  std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
381  std::declval<C&>().data()))> (*)[],
382  T (*)[]>>* = nullptr> // NOLINT
383  constexpr device_span(C const& in) : base(thrust::raw_pointer_cast(in.data()), in.size())
384  {
385  }
386 
387  // Copy construction to support const conversion
389  template <typename OtherT,
390  std::size_t OtherExtent,
391  std::enable_if_t<(Extent == OtherExtent || Extent == dynamic_extent) &&
392  std::is_convertible_v<OtherT (*)[], T (*)[]>, // NOLINT
393  void>* = nullptr>
395  : base(other.data(), other.size())
396  {
397  }
398 
399  // not noexcept due to undefined behavior when idx < 0 || idx >= size
409  __device__ constexpr typename base::reference operator[](typename base::size_type idx) const
410  {
411  static_assert(sizeof(idx) >= sizeof(size_t), "index type must not be smaller than size_t");
412  return this->_data[idx];
413  }
414 
415  // not noexcept due to undefined behavior when size = 0
423  [[nodiscard]] __device__ constexpr typename base::reference front() const
424  {
425  return this->_data[0];
426  }
427  // not noexcept due to undefined behavior when size = 0
435  [[nodiscard]] __device__ constexpr typename base::reference back() const
436  {
437  return this->_data[this->_size - 1];
438  }
439 
447  [[nodiscard]] CUDF_HOST_DEVICE constexpr device_span subspan(
448  typename base::size_type offset, typename base::size_type count) const noexcept
449  {
450  return device_span{this->data() + offset, count};
451  }
452 }; // end of group
454 
455 namespace detail {
456 
462 template <typename T, template <typename, std::size_t> typename RowType>
463 class base_2dspan {
464  public:
465  using size_type =
466  std::pair<size_t, size_t>;
467 
468  constexpr base_2dspan() noexcept = default;
475  constexpr base_2dspan(RowType<T, dynamic_extent> flat_view, size_t columns)
476  : _flat{flat_view}, _size{columns == 0 ? 0 : flat_view.size() / columns, columns}
477  {
478 #ifndef __CUDA_ARCH__
479  CUDF_EXPECTS(_size.first * _size.second == flat_view.size(), "Invalid 2D span size");
480 #endif
481  }
482 
488  [[nodiscard]] CUDF_HOST_DEVICE constexpr auto data() const noexcept { return _flat.data(); }
489 
495  [[nodiscard]] CUDF_HOST_DEVICE constexpr auto size() const noexcept { return _size; }
496 
502  [[nodiscard]] CUDF_HOST_DEVICE constexpr auto count() const noexcept { return _flat.size(); }
503 
509  [[nodiscard]] CUDF_HOST_DEVICE constexpr bool is_empty() const noexcept { return count() == 0; }
510 
520  CUDF_HOST_DEVICE constexpr RowType<T, dynamic_extent> operator[](std::size_t row) const
521  {
522  return _flat.subspan(row * _size.second, _size.second);
523  }
524 
530  [[nodiscard]] CUDF_HOST_DEVICE constexpr RowType<T, dynamic_extent> flat_view() const
531  {
532  return _flat;
533  }
534 
542  template <typename OtherT,
543  template <typename, size_t>
544  typename OtherRowType,
545  std::enable_if_t<std::is_convertible_v<OtherRowType<OtherT, dynamic_extent>,
546  RowType<T, dynamic_extent>>,
547  void>* = nullptr>
548  constexpr base_2dspan(base_2dspan<OtherT, OtherRowType> const& other) noexcept
549  : _flat{other.flat_view()}, _size{other.size()}
550  {
551  }
552 
553  protected:
554  RowType<T, dynamic_extent> _flat;
555  size_type _size{0, 0};
556 };
557 
563 template <class T>
565 
571 template <class T>
573 
574 } // namespace detail
575 } // namespace CUDF_EXPORT cudf
Generic class for row-major 2D spans. Not compliant with STL container semantics/syntax.
Definition: span.hpp:463
std::pair< size_t, size_t > size_type
Type used to represent the dimension of the span.
Definition: span.hpp:466
constexpr CUDF_HOST_DEVICE bool is_empty() const noexcept
Checks if the span is empty.
Definition: span.hpp:509
constexpr CUDF_HOST_DEVICE auto size() const noexcept
Returns the size in the span as pair.
Definition: span.hpp:495
constexpr CUDF_HOST_DEVICE auto count() const noexcept
Returns the number of elements in the span.
Definition: span.hpp:502
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:520
constexpr CUDF_HOST_DEVICE auto data() const noexcept
Returns a pointer to the beginning of the sequence.
Definition: span.hpp:488
constexpr CUDF_HOST_DEVICE RowType< T, dynamic_extent > flat_view() const
Returns a flattened span of the 2D span.
Definition: span.hpp:530
RowType< T, dynamic_extent > _flat
flattened 2D span
Definition: span.hpp:554
constexpr base_2dspan(base_2dspan< OtherT, OtherRowType > const &other) noexcept
Construct a 2D span from another 2D span of convertible type.
Definition: span.hpp:548
C++20 std::span with reduced feature set.
Definition: span.hpp:56
std::size_t size_type
The type used for the size of the span.
Definition: span.hpp:62
constexpr CUDF_HOST_DEVICE iterator end() const noexcept
Returns an iterator to the element following the last element of the span.
Definition: span.hpp:105
constexpr Derived first(size_type count) const noexcept
Obtains a subspan consisting of the first N elements of the sequence.
Definition: span.hpp:142
T * iterator
The type of the iterator returned by begin()
Definition: span.hpp:65
constexpr CUDF_HOST_DEVICE pointer data() const noexcept
Returns a pointer to the beginning of the sequence.
Definition: span.hpp:111
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:118
constexpr Derived last(size_type count) const noexcept
Obtains a subspan consisting of the last N elements of the sequence.
Definition: span.hpp:153
std::remove_cv< T > value_type
Stored value type.
Definition: span.hpp:61
std::ptrdiff_t difference_type
std::ptrdiff_t
Definition: span.hpp:63
T * pointer
The type of the pointer returned by data()
Definition: span.hpp:64
T const * const_pointer
The type of the pointer returned by data() const.
Definition: span.hpp:66
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:80
T & reference
The type of the reference returned by operator[](size_type)
Definition: span.hpp:67
constexpr CUDF_HOST_DEVICE bool empty() const noexcept
Checks if the span is empty.
Definition: span.hpp:134
constexpr CUDF_HOST_DEVICE iterator begin() const noexcept
Returns an iterator to the first element of the span.
Definition: span.hpp:97
constexpr CUDF_HOST_DEVICE size_type size_bytes() const noexcept
Returns the size of the sequence in bytes.
Definition: span.hpp:124
T const & const_reference
The type of the reference returned by operator[](size_type) const.
Definition: span.hpp:69
T element_type
The type of the elements in the span.
Definition: span.hpp:60
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:178
constexpr std::size_t dynamic_extent
A constant used to differentiate std::span of static and dynamic extent.
Definition: span.hpp:46
cuDF interfaces
Definition: host_udf.hpp:37
Device version of C++20 std::span with reduced feature set.
Definition: span.hpp:355
constexpr base::reference back() const
Returns a reference to the last element in the span.
Definition: span.hpp:435
constexpr CUDF_HOST_DEVICE device_span(device_span< OtherT, OtherExtent > const &other) noexcept
Definition: span.hpp:394
constexpr base::reference front() const
Returns a reference to the first element in the span.
Definition: span.hpp:423
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:447
constexpr device_span(C &in)
Definition: span.hpp:370
constexpr device_span(C const &in)
Definition: span.hpp:383
constexpr base::reference operator[](typename base::size_type idx) const
Returns a reference to the idx-th element of the sequence.
Definition: span.hpp:409
C++20 std::span with reduced feature set.
Definition: span.hpp:194
constexpr base::reference front() const
Returns a reference to the first element in the span.
Definition: span.hpp:295
constexpr host_span(cudf::detail::host_vector< OtherT > &in)
Definition: span.hpp:245
constexpr base::reference operator[](typename base::size_type idx) const
Returns a reference to the idx-th element of the sequence.
Definition: span.hpp:281
constexpr host_span(C const &in)
Definition: span.hpp:236
constexpr host_span(cudf::detail::host_vector< OtherT > const &in)
Definition: span.hpp:255
bool is_device_accessible() const
Returns whether the data is device accessible (e.g. pinned memory)
Definition: span.hpp:314
constexpr host_span(host_span< OtherT, OtherExtent > const &other) noexcept
Definition: span.hpp:267
constexpr CUDF_HOST_DEVICE host_span(T *data, std::size_t size, bool is_device_accessible)
Constructor from pointer and size.
Definition: span.hpp:209
constexpr base::reference back() const
Returns a reference to the last element in the span.
Definition: span.hpp:304
constexpr host_span(C &in)
Definition: span.hpp:223
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:323
Type declarations for libcudf.
#define CUDF_HOST_DEVICE
Indicates that the function or method is usable on host and device.
Definition: types.hpp:32