column_device_view.cuh
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-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 #pragma once
17 
20 #include <cudf/detail/utilities/alignment.hpp>
21 #include <cudf/lists/list_view.hpp>
25 #include <cudf/utilities/span.hpp>
27 
28 #include <rmm/cuda_stream_view.hpp>
29 
30 #include <thrust/iterator/counting_iterator.h>
31 #include <thrust/iterator/transform_iterator.h>
32 #include <thrust/pair.h>
33 
34 #include <functional>
35 
41 namespace CUDF_EXPORT cudf {
42 
49 class alignas(16) column_device_view : public column_device_view_core {
50  public:
52 
53  column_device_view() = delete;
54  ~column_device_view() = default;
69 
79  column_device_view(column_view column, void* h_ptr, void* d_ptr);
80 
98  size_type size) const noexcept
99  {
100  return column_device_view{this->type(),
101  size,
102  this->head(),
103  this->null_mask(),
104  this->offset() + offset,
105  static_cast<column_device_view*>(d_children),
106  this->num_child_columns()};
107  }
108 
126  template <typename T, CUDF_ENABLE_IF(is_rep_layout_compatible<T>())>
127  [[nodiscard]] __device__ T element(size_type element_index) const noexcept
128  {
129  return base::element<T>(element_index);
130  }
131 
143  template <typename T, CUDF_ENABLE_IF(cuda::std::is_same_v<T, string_view>)>
144  [[nodiscard]] __device__ T element(size_type element_index) const noexcept
145  {
146  return base::element<T>(element_index);
147  }
148 
159  template <typename T, CUDF_ENABLE_IF(cudf::is_fixed_point<T>())>
160  [[nodiscard]] __device__ T element(size_type element_index) const noexcept
161  {
162  return base::element<T>(element_index);
163  }
164 
165  private:
171  struct index_element_fn {
172  template <typename IndexType,
173  CUDF_ENABLE_IF(is_index_type<IndexType>() and cuda::std::is_signed_v<IndexType>)>
174  __device__ size_type operator()(column_device_view const& indices, size_type index)
175  {
176  return static_cast<size_type>(indices.element<IndexType>(index));
177  }
178 
179  template <typename IndexType,
180  typename... Args,
181  CUDF_ENABLE_IF(not(is_index_type<IndexType>() and cuda::std::is_signed_v<IndexType>))>
182  __device__ size_type operator()(Args&&... args)
183  {
184  CUDF_UNREACHABLE("dictionary indices must be a signed integral type");
185  }
186  };
187 
188  public:
213  template <typename T, CUDF_ENABLE_IF(cuda::std::is_same_v<T, dictionary32>)>
214  [[nodiscard]] __device__ T element(size_type element_index) const noexcept
215  {
216  size_type index = element_index + offset(); // account for this view's _offset
217  auto const indices = child(0);
218  return dictionary32{type_dispatcher(indices.type(), index_element_fn{}, indices, index)};
219  }
220 
227  template <typename T>
228  CUDF_HOST_DEVICE static constexpr bool has_element_accessor()
229  {
230  return has_element_accessor_impl<column_device_view, T>::value;
231  }
232 
234  using count_it = thrust::counting_iterator<size_type>;
238  template <typename T>
239  using const_iterator = thrust::transform_iterator<detail::value_accessor<T>, count_it>;
240 
256  template <typename T, CUDF_ENABLE_IF(column_device_view::has_element_accessor<T>())>
257  [[nodiscard]] const_iterator<T> begin() const
258  {
260  }
261 
276  template <typename T, CUDF_ENABLE_IF(column_device_view::has_element_accessor<T>())>
277  [[nodiscard]] const_iterator<T> end() const
278  {
279  return const_iterator<T>{count_it{size()}, detail::value_accessor<T>{*this}};
280  }
281 
285  template <typename T, typename Nullate>
287  thrust::transform_iterator<detail::optional_accessor<T, Nullate>, count_it>;
288 
292  template <typename T, bool has_nulls>
294  thrust::transform_iterator<detail::pair_accessor<T, has_nulls>, count_it>;
295 
301  template <typename T, bool has_nulls>
303  thrust::transform_iterator<detail::pair_rep_accessor<T, has_nulls>, count_it>;
304 
359  template <typename T,
360  typename Nullate,
361  CUDF_ENABLE_IF(column_device_view::has_element_accessor<T>())>
362  auto optional_begin(Nullate has_nulls) const
363  {
366  }
367 
389  template <typename T,
390  bool has_nulls,
391  CUDF_ENABLE_IF(column_device_view::has_element_accessor<T>())>
393  {
396  }
397 
421  template <typename T,
422  bool has_nulls,
423  CUDF_ENABLE_IF(column_device_view::has_element_accessor<T>())>
425  {
428  }
429 
446  template <typename T,
447  typename Nullate,
448  CUDF_ENABLE_IF(column_device_view::has_element_accessor<T>())>
449  auto optional_end(Nullate has_nulls) const
450  {
453  }
454 
466  template <typename T,
467  bool has_nulls,
468  CUDF_ENABLE_IF(column_device_view::has_element_accessor<T>())>
470  {
473  }
474 
487  template <typename T,
488  bool has_nulls,
489  CUDF_ENABLE_IF(column_device_view::has_element_accessor<T>())>
491  {
494  }
495 
514  static std::unique_ptr<column_device_view, std::function<void(column_device_view*)>> create(
516 
523  void destroy();
524 
532  static std::size_t extent(column_view const& source_view);
533 
540  [[nodiscard]] __device__ column_device_view child(size_type child_index) const noexcept
541  {
542  return static_cast<column_device_view*>(d_children)[child_index];
543  }
544 
550  [[nodiscard]] __device__ device_span<column_device_view const> children() const noexcept
551  {
552  return {static_cast<column_device_view*>(d_children), static_cast<std::size_t>(_num_children)};
553  }
554 
560  [[nodiscard]] CUDF_HOST_DEVICE size_type num_child_columns() const noexcept
561  {
562  return _num_children;
563  }
564 
565  private:
579  size_type size,
580  void const* data,
581  bitmask_type const* null_mask,
582  size_type offset,
583  column_device_view* children,
584  size_type num_children)
585  : column_device_view_core{type, size, data, null_mask, offset, children, num_children}
586  {
587  }
588 
599  column_device_view(column_view source);
600 };
601 
609  public:
611 
612  mutable_column_device_view() = delete;
613  ~mutable_column_device_view() = default;
628 
639 
658  static std::unique_ptr<mutable_column_device_view,
659  std::function<void(mutable_column_device_view*)>>
662 
680  template <typename T, CUDF_ENABLE_IF(is_rep_layout_compatible<T>())>
681  [[nodiscard]] __device__ T& element(size_type element_index) const noexcept
682  {
683  return base::element<T>(element_index);
684  }
685 
692  template <typename T>
693  CUDF_HOST_DEVICE static constexpr bool has_element_accessor()
694  {
695  return has_element_accessor_impl<mutable_column_device_view, T>::value;
696  }
697 
699  using count_it = thrust::counting_iterator<size_type>;
703  template <typename T>
704  using iterator = thrust::transform_iterator<detail::mutable_value_accessor<T>, count_it>;
705 
716  template <typename T, CUDF_ENABLE_IF(mutable_column_device_view::has_element_accessor<T>())>
718  {
720  }
721 
732  template <typename T, CUDF_ENABLE_IF(mutable_column_device_view::has_element_accessor<T>())>
734  {
736  }
737 
744  [[nodiscard]] __device__ mutable_column_device_view child(size_type child_index) const noexcept
745  {
746  return static_cast<mutable_column_device_view*>(d_children)[child_index];
747  }
748 
757  static std::size_t extent(mutable_column_view source_view);
758 
765  void destroy();
766 
767  private:
777 };
778 
779 static_assert(sizeof(column_device_view) == sizeof(column_device_view_core),
780  "column_device_view and raw_column_device_view must be bitwise-compatible");
781 
782 static_assert(
784  "mutable_column_device_view and raw_mutable_column_device_view must be bitwise-compatible");
785 
786 namespace detail {
787 
802 template <typename T>
805 
811  value_accessor(column_device_view const& _col) : col{_col}
812  {
813  CUDF_EXPECTS(type_id_matches_device_storage_type<T>(col.type().id()), "the data type mismatch");
814  }
815 
821  __device__ T operator()(cudf::size_type i) const { return col.element<T>(i); }
822 };
823 
850 template <typename T, typename Nullate>
853 
860  optional_accessor(column_device_view const& _col, Nullate with_nulls)
861  : col{_col}, has_nulls{with_nulls}
862  {
863  CUDF_EXPECTS(type_id_matches_device_storage_type<T>(col.type().id()), "the data type mismatch");
864  if (with_nulls) { CUDF_EXPECTS(_col.nullable(), "Unexpected non-nullable column."); }
865  }
866 
874  __device__ inline cuda::std::optional<T> operator()(cudf::size_type i) const
875  {
876  if (has_nulls) {
877  return (col.is_valid_nocheck(i)) ? cuda::std::optional<T>{col.element<T>(i)}
878  : cuda::std::optional<T>{cuda::std::nullopt};
879  }
880  return cuda::std::optional<T>{col.element<T>(i)};
881  }
882 
883  Nullate has_nulls{};
884 };
885 
905 template <typename T, bool has_nulls = false>
908 
914  pair_accessor(column_device_view const& _col) : col{_col}
915  {
916  CUDF_EXPECTS(type_id_matches_device_storage_type<T>(col.type().id()), "the data type mismatch");
917  if (has_nulls) { CUDF_EXPECTS(_col.nullable(), "Unexpected non-nullable column."); }
918  }
919 
926  __device__ inline thrust::pair<T, bool> operator()(cudf::size_type i) const
927  {
928  return {col.element<T>(i), (has_nulls ? col.is_valid_nocheck(i) : true)};
929  }
930 };
931 
951 template <typename T, bool has_nulls = false>
954 
956 
962  pair_rep_accessor(column_device_view const& _col) : col{_col}
963  {
964  CUDF_EXPECTS(type_id_matches_device_storage_type<T>(col.type().id()), "the data type mismatch");
965  if (has_nulls) { CUDF_EXPECTS(_col.nullable(), "Unexpected non-nullable column."); }
966  }
967 
974  __device__ inline thrust::pair<rep_type, bool> operator()(cudf::size_type i) const
975  {
976  return {get_rep<T>(i), (has_nulls ? col.is_valid_nocheck(i) : true)};
977  }
978 
979  private:
980  template <typename R, std::enable_if_t<std::is_same_v<R, rep_type>, void>* = nullptr>
981  [[nodiscard]] __device__ inline auto get_rep(cudf::size_type i) const
982  {
983  return col.element<R>(i);
984  }
985 
986  template <typename R, std::enable_if_t<not std::is_same_v<R, rep_type>, void>* = nullptr>
987  [[nodiscard]] __device__ inline auto get_rep(cudf::size_type i) const
988  {
989  return col.element<R>(i).value();
990  }
991 };
992 
1004 template <typename T>
1007 
1014  {
1015  CUDF_EXPECTS(type_id_matches_device_storage_type<T>(col.type().id()), "the data type mismatch");
1016  }
1017 
1024  __device__ T& operator()(cudf::size_type i) { return col.element<T>(i); }
1025 };
1026 
1052 template <typename ColumnDeviceView, typename ColumnViewIterator>
1053 ColumnDeviceView* child_columns_to_device_array(ColumnViewIterator child_begin,
1054  ColumnViewIterator child_end,
1055  void* h_ptr,
1056  void* d_ptr)
1057 {
1058  ColumnDeviceView* d_children = detail::align_ptr_for_type<ColumnDeviceView>(d_ptr);
1059  auto num_children = std::distance(child_begin, child_end);
1060  if (num_children > 0) {
1061  // The beginning of the memory must be the fixed-sized ColumnDeviceView
1062  // struct objects in order for d_children to be used as an array.
1063  auto h_column = detail::align_ptr_for_type<ColumnDeviceView>(h_ptr);
1064  auto d_column = d_children;
1065 
1066  // Any child data is assigned past the end of this array: h_end and d_end.
1067  auto h_end = reinterpret_cast<int8_t*>(h_column + num_children);
1068  auto d_end = reinterpret_cast<int8_t*>(d_column + num_children);
1069  std::for_each(child_begin, child_end, [&](auto const& col) {
1070  // inplace-new each child into host memory
1071  new (h_column) ColumnDeviceView(col, h_end, d_end);
1072  h_column++; // advance to next child
1073  // update the pointers for holding this child column's child data
1074  auto col_child_data_size = ColumnDeviceView::extent(col) - sizeof(ColumnDeviceView);
1075  h_end += col_child_data_size;
1076  d_end += col_child_data_size;
1077  });
1078  }
1079  return d_children;
1080 }
1081 
1082 } // namespace detail
1083 } // namespace CUDF_EXPORT cudf
An immutable, non-owning view of device data as a column of elements that is trivially copyable and u...
An immutable, non-owning view of device data as a column of elements that is trivially copyable and u...
static std::unique_ptr< column_device_view, std::function< void(column_device_view *)> > create(column_view source_view, rmm::cuda_stream_view stream=cudf::get_default_stream())
Factory to construct a column view that is usable in device memory.
column_device_view child(size_type child_index) const noexcept
Returns the specified child.
void destroy()
Destroy the column_device_view object.
column_device_view & operator=(column_device_view &&)=default
Move assignment operator.
thrust::counting_iterator< size_type > count_it
Counting iterator.
static constexpr CUDF_HOST_DEVICE bool has_element_accessor()
For a given T, indicates if column_device_view::element<T>() has a valid overload.
const_pair_iterator< T, has_nulls > pair_end() const
Return a pair iterator to the element following the last element of the column.
const_pair_rep_iterator< T, has_nulls > pair_rep_end() const
Return a pair iterator to the element following the last element of the column.
const_pair_iterator< T, has_nulls > pair_begin() const
Return a pair iterator to the first element of the column.
T element(size_type element_index) const noexcept
Returns reference to element at the specified index.
column_device_view & operator=(column_device_view const &)=default
Copy assignment operator.
CUDF_HOST_DEVICE column_device_view slice(size_type offset, size_type size) const noexcept
Get a new column_device_view which is a slice of this column.
thrust::transform_iterator< detail::value_accessor< T >, count_it > const_iterator
Iterator for navigating this column.
auto optional_end(Nullate has_nulls) const
Return an optional iterator to the element following the last element of the column.
thrust::transform_iterator< detail::pair_accessor< T, has_nulls >, count_it > const_pair_iterator
Pair iterator for navigating this column.
const_pair_rep_iterator< T, has_nulls > pair_rep_begin() const
Return a pair iterator to the first element of the column.
thrust::transform_iterator< detail::optional_accessor< T, Nullate >, count_it > const_optional_iterator
Optional iterator for navigating this column.
CUDF_HOST_DEVICE size_type num_child_columns() const noexcept
Returns the number of child columns.
auto optional_begin(Nullate has_nulls) const
Return an optional iterator to the first element of the column.
column_device_view(column_device_view const &)=default
Copy constructor.
column_device_view(column_device_view &&)=default
Move constructor.
const_iterator< T > begin() const
Return an iterator to the first element of the column.
thrust::transform_iterator< detail::pair_rep_accessor< T, has_nulls >, count_it > const_pair_rep_iterator
Pair rep iterator for navigating this column.
static std::size_t extent(column_view const &source_view)
Return the size in bytes of the amount of memory needed to hold a device view of the specified column...
column_device_view(column_view column, void *h_ptr, void *d_ptr)
Creates an instance of this class using the specified host memory pointer (h_ptr) to store child obje...
const_iterator< T > end() const
Returns an iterator to the element following the last element of the column.
device_span< column_device_view const > children() const noexcept
Returns a span containing the children of this column.
A non-owning, immutable view of device data as a column of elements, some of which may be null as ind...
A container of nullable device data as a column of elements.
Definition: column.hpp:47
Indicator for the logical data type of an element in a column.
Definition: types.hpp:243
constexpr CUDF_HOST_DEVICE type_id id() const noexcept
Returns the type identifier.
Definition: types.hpp:287
CUDF_HOST_DEVICE data_type type() const noexcept
Returns the element type.
bool is_valid_nocheck(size_type element_index) const noexcept
Returns whether the specified element holds a valid value (i.e., not null)
CUDF_HOST_DEVICE bool nullable() const noexcept
Indicates whether the column can contain null elements, i.e., if it has an allocated bitmask.
A mutable, non-owning view of device data as a column of elements that is trivially copyable and usab...
A mutable, non-owning view of device data as a column of elements that is trivially copyable and usab...
static constexpr CUDF_HOST_DEVICE bool has_element_accessor()
For a given T, indicates if mutable_column_device_view::element<T>() has a valid overload.
void destroy()
Destroy the mutable_column_device_view object.
mutable_column_device_view(mutable_column_view column, void *h_ptr, void *d_ptr)
Creates an instance of this class using the specified host memory pointer (h_ptr) to store child obje...
static std::size_t extent(mutable_column_view source_view)
Return the size in bytes of the amount of memory needed to hold a device view of the specified column...
thrust::counting_iterator< size_type > count_it
Counting iterator.
mutable_column_device_view child(size_type child_index) const noexcept
Returns the specified child.
mutable_column_device_view(mutable_column_device_view const &)=default
Copy constructor.
T & element(size_type element_index) const noexcept
Returns reference to element at the specified index.
iterator< T > end()
Return one past the last element after underlying data is casted to the specified type.
mutable_column_device_view & operator=(mutable_column_device_view &&)=default
Move assignment operator.
mutable_column_device_view(mutable_column_device_view &&)=default
Move constructor.
mutable_column_device_view & operator=(mutable_column_device_view const &)=default
Copy assignment operator.
static std::unique_ptr< mutable_column_device_view, std::function< void(mutable_column_device_view *)> > create(mutable_column_view source_view, rmm::cuda_stream_view stream=cudf::get_default_stream())
Factory to construct a column view that is usable in device memory.
thrust::transform_iterator< detail::mutable_value_accessor< T >, count_it > iterator
Iterator for navigating this column.
iterator< T > begin()
Return first element (accounting for offset) after underlying data is casted to the specified type.
A non-owning, mutable view of device data as a column of elements, some of which may be null as indic...
ColumnDeviceView * child_columns_to_device_array(ColumnViewIterator child_begin, ColumnViewIterator child_end, void *h_ptr, void *d_ptr)
Helper function for use by column_device_view and mutable_column_device_view constructors to build de...
Column device view class definitions.
column view class definitions
rmm::cuda_stream_view const get_default_stream()
Get the current default stream.
CUDF_HOST_DEVICE constexpr decltype(auto) __forceinline__ type_dispatcher(cudf::data_type dtype, Functor f, Ts &&... args)
Invokes an operator() template with the type instantiation based on the specified cudf::data_type's i...
std::conditional_t< std::is_same_v< numeric::decimal32, T >, int32_t, std::conditional_t< std::is_same_v< numeric::decimal64, T >, int64_t, std::conditional_t< std::is_same_v< numeric::decimal128, T >, __int128_t, T > >> device_storage_type_t
"Returns" the corresponding type that is stored on the device when using cudf::column
#define CUDF_EXPECTS(...)
Macro for checking (pre-)conditions that throws an exception when a condition is violated.
Definition: error.hpp:178
int32_t size_type
Row index type for columns and tables.
Definition: types.hpp:95
uint32_t bitmask_type
Bitmask type stored as 32-bit unsigned integer.
Definition: types.hpp:96
size_type distance(T f, T l)
Similar to std::distance but returns cudf::size_type and performs static_cast
Definition: types.hpp:110
#define CUDF_ENABLE_IF(...)
Convenience macro for SFINAE as an unnamed template parameter.
Definition: traits.hpp:50
Class definition for cudf::list_view.
cuDF interfaces
Definition: host_udf.hpp:37
bool has_nulls(table_view const &view)
Returns True if the table has nulls in any of its columns.
APIs for spans.
Class definition for cudf::strings_column_view.
Class definition for cudf::struct_view.
Mutable value accessor of column without null bitmask.
T & operator()(cudf::size_type i)
Accessor.
mutable_value_accessor(mutable_column_device_view &_col)
Constructor.
mutable_column_device_view col
mutable column view of column in device
optional accessor of a column
cuda::std::optional< T > operator()(cudf::size_type i) const
Returns a cuda::std::optional of column[i].
column_device_view const col
column view of column in device
optional_accessor(column_device_view const &_col, Nullate with_nulls)
Constructor.
pair accessor of column with/without null bitmask
column_device_view const col
column view of column in device
thrust::pair< T, bool > operator()(cudf::size_type i) const
Pair accessor.
pair_accessor(column_device_view const &_col)
constructor
pair accessor of column with/without null bitmask
thrust::pair< rep_type, bool > operator()(cudf::size_type i) const
Pair accessor.
column_device_view const col
column view of column in device
device_storage_type_t< T > rep_type
representation type
pair_rep_accessor(column_device_view const &_col)
constructor
value accessor of column without null bitmask
column_device_view const col
column view of column in device
value_accessor(column_device_view const &_col)
constructor
T operator()(cudf::size_type i) const
Returns the value of element at index i
Device version of C++20 std::span with reduced feature set.
Definition: span.hpp:355
A strongly typed wrapper for indices in a DICTIONARY type column.
Definition: dictionary.hpp:49
Defines the mapping between cudf::type_id runtime type information and concrete C++ types.
#define CUDF_HOST_DEVICE
Indicates that the function or method is usable on host and device.
Definition: types.hpp:32