span.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020-2024, 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 
204  constexpr host_span(T* data, std::size_t size, bool is_device_accessible)
205  : base(data, size), _is_device_accessible{is_device_accessible}
206  {
207  }
208 
211  template <typename C,
212  // Only supported containers of types convertible to T
213  std::enable_if_t<is_host_span_supported_container<C>::value &&
214  std::is_convertible_v<
215  std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
216  std::declval<C&>().data()))> (*)[],
217  T (*)[]>>* = nullptr> // NOLINT
218  constexpr host_span(C& in) : base(thrust::raw_pointer_cast(in.data()), in.size())
219  {
220  }
221 
224  template <typename C,
225  // Only supported containers of types convertible to T
226  std::enable_if_t<is_host_span_supported_container<C>::value &&
227  std::is_convertible_v<
228  std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
229  std::declval<C&>().data()))> (*)[],
230  T (*)[]>>* = nullptr> // NOLINT
231  constexpr host_span(C const& in) : base(thrust::raw_pointer_cast(in.data()), in.size())
232  {
233  }
234 
237  template <typename OtherT,
238  // Only supported containers of types convertible to T
239  std::enable_if_t<std::is_convertible_v<OtherT (*)[], T (*)[]>>* = nullptr> // NOLINT
240  constexpr host_span(cudf::detail::host_vector<OtherT>& in)
241  : base(in.data(), in.size()), _is_device_accessible{in.get_allocator().is_device_accessible()}
242  {
243  }
244 
247  template <typename OtherT,
248  // Only supported containers of types convertible to T
249  std::enable_if_t<std::is_convertible_v<OtherT (*)[], T (*)[]>>* = nullptr> // NOLINT
250  constexpr host_span(cudf::detail::host_vector<OtherT> const& in)
251  : base(in.data(), in.size()), _is_device_accessible{in.get_allocator().is_device_accessible()}
252  {
253  }
254 
255  // Copy construction to support const conversion
257  template <typename OtherT,
258  std::size_t OtherExtent,
259  std::enable_if_t<(Extent == OtherExtent || Extent == dynamic_extent) &&
260  std::is_convertible_v<OtherT (*)[], T (*)[]>, // NOLINT
261  void>* = nullptr>
262  constexpr host_span(host_span<OtherT, OtherExtent> const& other) noexcept
263  : base(other.data(), other.size()), _is_device_accessible{other.is_device_accessible()}
264  {
265  }
266  // not noexcept due to undefined behavior when idx < 0 || idx >= size
276  constexpr typename base::reference operator[](size_type idx) const { return this->_data[idx]; }
277 
278  // not noexcept due to undefined behavior when size = 0
286  [[nodiscard]] constexpr typename base::reference front() const { return this->_data[0]; }
287  // not noexcept due to undefined behavior when size = 0
295  [[nodiscard]] constexpr typename base::reference back() const
296  {
297  return this->_data[this->_size - 1];
298  }
299 
305  [[nodiscard]] bool is_device_accessible() const { return _is_device_accessible; }
306 
314  [[nodiscard]] constexpr host_span subspan(typename base::size_type offset,
315  typename base::size_type count) const noexcept
316  {
317  return host_span{this->data() + offset, count, _is_device_accessible};
318  }
319 
320  private:
321  bool _is_device_accessible{false};
322 };
323 
324 // ===== device_span ===============================================================================
325 
326 template <typename T>
327 struct is_device_span_supported_container : std::false_type {};
328 
329 template <typename T, typename Alloc>
331  thrust::device_vector<T, Alloc>> : std::true_type {};
332 
333 template <typename T>
335  rmm::device_vector<T>> : std::true_type {};
336 
337 template <typename T>
339  rmm::device_uvector<T>> : std::true_type {};
340 
345 template <typename T, std::size_t Extent = cudf::dynamic_extent>
346 struct device_span : public cudf::detail::span_base<T, Extent, device_span<T, Extent>> {
348  using base::base;
349 
350  CUDF_HOST_DEVICE constexpr device_span() noexcept : base() {} // required to compile on centos
351 
354  template <typename C,
355  // Only supported containers of types convertible to T
356  std::enable_if_t<is_device_span_supported_container<C>::value &&
357  std::is_convertible_v<
358  std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
359  std::declval<C&>().data()))> (*)[],
360  T (*)[]>>* = nullptr> // NOLINT
361  constexpr device_span(C& in) : base(thrust::raw_pointer_cast(in.data()), in.size())
362  {
363  }
364 
367  template <typename C,
368  // Only supported containers of types convertible to T
369  std::enable_if_t<is_device_span_supported_container<C>::value &&
370  std::is_convertible_v<
371  std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
372  std::declval<C&>().data()))> (*)[],
373  T (*)[]>>* = nullptr> // NOLINT
374  constexpr device_span(C const& in) : base(thrust::raw_pointer_cast(in.data()), in.size())
375  {
376  }
377 
378  // Copy construction to support const conversion
380  template <typename OtherT,
381  std::size_t OtherExtent,
382  std::enable_if_t<(Extent == OtherExtent || Extent == dynamic_extent) &&
383  std::is_convertible_v<OtherT (*)[], T (*)[]>, // NOLINT
384  void>* = nullptr>
386  : base(other.data(), other.size())
387  {
388  }
389 
390  // not noexcept due to undefined behavior when idx < 0 || idx >= size
400  __device__ constexpr typename base::reference operator[](size_type idx) const
401  {
402  return this->_data[idx];
403  }
404 
405  // not noexcept due to undefined behavior when size = 0
413  [[nodiscard]] __device__ constexpr typename base::reference front() const
414  {
415  return this->_data[0];
416  }
417  // not noexcept due to undefined behavior when size = 0
425  [[nodiscard]] __device__ constexpr typename base::reference back() const
426  {
427  return this->_data[this->_size - 1];
428  }
429 
437  [[nodiscard]] constexpr device_span subspan(typename base::size_type offset,
438  typename base::size_type count) const noexcept
439  {
440  return device_span{this->data() + offset, count};
441  }
442 }; // end of group
444 
445 namespace detail {
446 
452 template <typename T, template <typename, std::size_t> typename RowType>
453 class base_2dspan {
454  public:
455  using size_type =
456  std::pair<size_t, size_t>;
457 
458  constexpr base_2dspan() noexcept = default;
465  constexpr base_2dspan(RowType<T, dynamic_extent> flat_view, size_t columns)
466  : _flat{flat_view}, _size{columns == 0 ? 0 : flat_view.size() / columns, columns}
467  {
468 #ifndef __CUDA_ARCH__
469  CUDF_EXPECTS(_size.first * _size.second == flat_view.size(), "Invalid 2D span size");
470 #endif
471  }
472 
478  [[nodiscard]] constexpr auto data() const noexcept { return _flat.data(); }
479 
485  [[nodiscard]] constexpr auto size() const noexcept { return _size; }
486 
492  [[nodiscard]] constexpr auto count() const noexcept { return _flat.size(); }
493 
499  [[nodiscard]] constexpr bool is_empty() const noexcept { return count() == 0; }
500 
510  constexpr RowType<T, dynamic_extent> operator[](size_t row) const
511  {
512  return _flat.subspan(row * _size.second, _size.second);
513  }
514 
520  [[nodiscard]] constexpr RowType<T, dynamic_extent> flat_view() const { return _flat; }
521 
529  template <typename OtherT,
530  template <typename, size_t>
531  typename OtherRowType,
532  std::enable_if_t<std::is_convertible_v<OtherRowType<OtherT, dynamic_extent>,
533  RowType<T, dynamic_extent>>,
534  void>* = nullptr>
535  constexpr base_2dspan(base_2dspan<OtherT, OtherRowType> const& other) noexcept
536  : _flat{other.flat_view()}, _size{other.size()}
537  {
538  }
539 
540  protected:
541  RowType<T, dynamic_extent> _flat;
542  size_type _size{0, 0};
543 };
544 
550 template <class T>
552 
558 template <class T>
560 
561 } // namespace detail
562 } // namespace CUDF_EXPORT cudf
Generic class for row-major 2D spans. Not compliant with STL container semantics/syntax.
Definition: span.hpp:453
std::pair< size_t, size_t > size_type
Type used to represent the dimension of the span.
Definition: span.hpp:456
constexpr auto count() const noexcept
Returns the number of elements in the span.
Definition: span.hpp:492
constexpr RowType< T, dynamic_extent > flat_view() const
Returns a flattened span of the 2D span.
Definition: span.hpp:520
constexpr bool is_empty() const noexcept
Checks if the span is empty.
Definition: span.hpp:499
constexpr auto data() const noexcept
Returns a pointer to the beginning of the sequence.
Definition: span.hpp:478
constexpr RowType< T, dynamic_extent > operator[](size_t row) const
Returns a reference to the row-th element of the sequence.
Definition: span.hpp:510
constexpr auto size() const noexcept
Returns the size in the span as pair.
Definition: span.hpp:485
RowType< T, dynamic_extent > _flat
flattened 2D span
Definition: span.hpp:541
constexpr base_2dspan(base_2dspan< OtherT, OtherRowType > const &other) noexcept
Construct a 2D span from another 2D span of convertible type.
Definition: span.hpp:535
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:39
Device version of C++20 std::span with reduced feature set.
Definition: span.hpp:346
constexpr base::reference operator[](size_type idx) const
Returns a reference to the idx-th element of the sequence.
Definition: span.hpp:400
constexpr base::reference back() const
Returns a reference to the last element in the span.
Definition: span.hpp:425
constexpr CUDF_HOST_DEVICE device_span(device_span< OtherT, OtherExtent > const &other) noexcept
Definition: span.hpp:385
constexpr base::reference front() const
Returns a reference to the first element in the span.
Definition: span.hpp:413
constexpr device_span(C &in)
Definition: span.hpp:361
constexpr 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:437
constexpr device_span(C const &in)
Definition: span.hpp:374
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:286
constexpr host_span(cudf::detail::host_vector< OtherT > &in)
Definition: span.hpp:240
constexpr host_span(C const &in)
Definition: span.hpp:231
constexpr base::reference operator[](size_type idx) const
Returns a reference to the idx-th element of the sequence.
Definition: span.hpp:276
constexpr host_span(cudf::detail::host_vector< OtherT > const &in)
Definition: span.hpp:250
bool is_device_accessible() const
Returns whether the data is device accessible (e.g. pinned memory)
Definition: span.hpp:305
constexpr host_span(host_span< OtherT, OtherExtent > const &other) noexcept
Definition: span.hpp:262
constexpr base::reference back() const
Returns a reference to the last element in the span.
Definition: span.hpp:295
constexpr host_span(C &in)
Definition: span.hpp:218
constexpr 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:314
constexpr host_span(T *data, std::size_t size, bool is_device_accessible)
Definition: span.hpp:204
Type declarations for libcudf.
#define CUDF_HOST_DEVICE
Indicates that the function or method is usable on host and device.
Definition: types.hpp:32