diff --git a/docs/cudf/source/developer_guide/pylibcudf.md b/docs/cudf/source/developer_guide/pylibcudf.md index 1b321dbb1fe..0120cbb286e 100644 --- a/docs/cudf/source/developer_guide/pylibcudf.md +++ b/docs/cudf/source/developer_guide/pylibcudf.md @@ -153,3 +153,26 @@ from cudf._lib.cpp.copying cimport out_of_bounds_policy from cudf._lib.cpp.copying import \ out_of_bounds_policy as OutOfBoundsPolicy # no-cython-lint ``` + +### Handling overloaded functions in libcudf +As a C++ library, libcudf makes extensive use of function overloading. +For example, both of the following functions exist in libcudf: +```cpp +std::unique_ptr empty_like(table_view const& input_table); +std::unique_ptr empty_like(column_view const& input); +``` + +However, Cython does not directly support overloading in this way, instead following Pythonic semantics where every function name must uniquely identify the function. +Therefore, Cython's [fused types](https://cython.readthedocs.io/en/latest/src/userguide/fusedtypes.html) should be used when implementing pylibcudf wrappers of overloaded functions like the above. +Fused types are Cython's version of generic programming and in this case amount to writing templated functions that compile into separate copies corresponding to the different C++ overloads. +For the above functions, the equivalent Cython function is +```cython +ctypedef fused ColumnOrTable: + Table + Column + +cpdef ColumnOrTable empty_like(ColumnOrTable input) +``` + +[Cython supports specializing the contents of fused-type functions based on the argument types](https://cython.readthedocs.io/en/latest/src/userguide/fusedtypes.html#type-checking-specializations), so any type-specific logic may be encoded using the appropriate conditionals. +See the pylibcudf source for examples of how to implement such functions. diff --git a/python/cudf/cudf/_lib/copying.pyx b/python/cudf/cudf/_lib/copying.pyx index 8eb0500617f..6a52af520f0 100644 --- a/python/cudf/cudf/_lib/copying.pyx +++ b/python/cudf/cudf/_lib/copying.pyx @@ -1,4 +1,4 @@ -# Copyright (c) 2020-2023, NVIDIA CORPORATION. +# Copyright (c) 2020-2024, NVIDIA CORPORATION. import pickle @@ -184,18 +184,13 @@ def scatter(list sources, Column scatter_map, list target_columns, f"index out of bounds for column of size {n_rows}" ) - if isinstance(sources[0], Column): - tbl = pylibcudf.copying.scatter_table( - pylibcudf.Table([col.to_pylibcudf(mode="read") for col in sources]), - scatter_map.to_pylibcudf(mode="read"), - pylibcudf.Table([col.to_pylibcudf(mode="read") for col in target_columns]), - ) - else: - tbl = pylibcudf.copying.scatter_scalars( - [( as_device_scalar(slr)).c_value for slr in sources], - scatter_map.to_pylibcudf(mode="read"), - pylibcudf.Table([col.to_pylibcudf(mode="read") for col in target_columns]), - ) + tbl = pylibcudf.copying.scatter( + pylibcudf.Table([col.to_pylibcudf(mode="read") for col in sources]) + if isinstance(sources[0], Column) + else [( as_device_scalar(slr)).c_value for slr in sources], + scatter_map.to_pylibcudf(mode="read"), + pylibcudf.Table([col.to_pylibcudf(mode="read") for col in target_columns]), + ) return columns_from_pylibcudf_table(tbl) @@ -203,7 +198,7 @@ def scatter(list sources, Column scatter_map, list target_columns, @acquire_spill_lock() def column_empty_like(Column input_column): return Column.from_pylibcudf( - pylibcudf.copying.empty_column_like( + pylibcudf.copying.empty_like( input_column.to_pylibcudf(mode="read") ) ) @@ -222,7 +217,7 @@ def column_allocate_like(Column input_column, size=None): @acquire_spill_lock() def columns_empty_like(list input_columns): return columns_from_pylibcudf_table( - pylibcudf.copying.empty_table_like( + pylibcudf.copying.empty_like( pylibcudf.Table([col.to_pylibcudf(mode="read") for col in input_columns]) ) ) @@ -232,7 +227,7 @@ def columns_empty_like(list input_columns): def column_slice(Column input_column, object indices): return [ Column.from_pylibcudf(c) - for c in pylibcudf.copying.column_slice( + for c in pylibcudf.copying.slice( input_column.to_pylibcudf(mode="read"), list(indices), ) @@ -243,7 +238,7 @@ def column_slice(Column input_column, object indices): def columns_slice(list input_columns, object indices): return [ columns_from_pylibcudf_table(tbl) - for tbl in pylibcudf.copying.table_slice( + for tbl in pylibcudf.copying.slice( pylibcudf.Table([col.to_pylibcudf(mode="read") for col in input_columns]), list(indices), ) @@ -254,7 +249,7 @@ def columns_slice(list input_columns, object indices): def column_split(Column input_column, object splits): return [ Column.from_pylibcudf(c) - for c in pylibcudf.copying.column_split( + for c in pylibcudf.copying.split( input_column.to_pylibcudf(mode="read"), list(splits), ) @@ -265,7 +260,7 @@ def column_split(Column input_column, object splits): def columns_split(list input_columns, object splits): return [ columns_from_pylibcudf_table(tbl) - for tbl in pylibcudf.copying.table_split( + for tbl in pylibcudf.copying.split( pylibcudf.Table([col.to_pylibcudf(mode="read") for col in input_columns]), list(splits), ) @@ -303,18 +298,13 @@ def boolean_mask_scatter(list input_, list target_columns, if len(input_) == 0: return [] - if isinstance(input_[0], Column): - tbl = pylibcudf.copying.boolean_mask_table_scatter( - pylibcudf.Table([col.to_pylibcudf(mode="read") for col in input_]), - pylibcudf.Table([col.to_pylibcudf(mode="read") for col in target_columns]), - boolean_mask.to_pylibcudf(mode="read"), - ) - else: - tbl = pylibcudf.copying.boolean_mask_scalars_scatter( - [( as_device_scalar(i)).c_value for i in input_], - pylibcudf.Table([col.to_pylibcudf(mode="read") for col in target_columns]), - boolean_mask.to_pylibcudf(mode="read"), - ) + tbl = pylibcudf.copying.boolean_mask_scatter( + pylibcudf.Table([col.to_pylibcudf(mode="read") for col in input_]) + if isinstance(input_[0], Column) + else [( as_device_scalar(i)).c_value for i in input_], + pylibcudf.Table([col.to_pylibcudf(mode="read") for col in target_columns]), + boolean_mask.to_pylibcudf(mode="read"), + ) return columns_from_pylibcudf_table(tbl) diff --git a/python/cudf/cudf/_lib/pylibcudf/binaryop.pxd b/python/cudf/cudf/_lib/pylibcudf/binaryop.pxd index 56b98333757..a0bcbfd00b2 100644 --- a/python/cudf/cudf/_lib/pylibcudf/binaryop.pxd +++ b/python/cudf/cudf/_lib/pylibcudf/binaryop.pxd @@ -3,12 +3,22 @@ from cudf._lib.cpp.binaryop cimport binary_operator from .column cimport Column +from .scalar cimport Scalar from .types cimport DataType +# Need two separate fused types to generate the cartesian product of signatures. +ctypedef fused LeftBinaryOperand: + Column + Scalar + +ctypedef fused RightBinaryOperand: + Column + Scalar + cpdef Column binary_operation( - object lhs, - object rhs, + LeftBinaryOperand lhs, + RightBinaryOperand rhs, binary_operator op, DataType data_type ) diff --git a/python/cudf/cudf/_lib/pylibcudf/binaryop.pyx b/python/cudf/cudf/_lib/pylibcudf/binaryop.pyx index af248ba2071..4675fae90b0 100644 --- a/python/cudf/cudf/_lib/pylibcudf/binaryop.pyx +++ b/python/cudf/cudf/_lib/pylibcudf/binaryop.pyx @@ -18,25 +18,25 @@ from .types cimport DataType cpdef Column binary_operation( - object lhs, - object rhs, + LeftBinaryOperand lhs, + RightBinaryOperand rhs, binary_operator op, DataType data_type ): """Perform a binary operation between a column and another column or scalar. - Either ``lhs`` or ``rhs`` must be a - :py:class:`~cudf._lib.pylibcudf.column.Column`. The other may be a + ``lhs`` and ``rhs`` may be a :py:class:`~cudf._lib.pylibcudf.column.Column` or a - :py:class:`~cudf._lib.pylibcudf.scalar.Scalar`. + :py:class:`~cudf._lib.pylibcudf.scalar.Scalar`, but at least one must be a + :py:class:`~cudf._lib.pylibcudf.column.Column`. For details, see :cpp:func:`binary_operation`. Parameters ---------- - lhs : Column or Scalar + lhs : Union[Column, Scalar] The left hand side argument. - rhs : Column or Scalar + rhs : Union[Column, Scalar] The right hand side argument. op : BinaryOperator The operation to perform. @@ -50,32 +50,32 @@ cpdef Column binary_operation( """ cdef unique_ptr[column] result - if isinstance(lhs, Column) and isinstance(rhs, Column): + if LeftBinaryOperand is Column and RightBinaryOperand is Column: with nogil: result = move( cpp_binaryop.binary_operation( - ( lhs).view(), - ( rhs).view(), + lhs.view(), + rhs.view(), op, data_type.c_obj ) ) - elif isinstance(lhs, Column) and isinstance(rhs, Scalar): + elif LeftBinaryOperand is Column and RightBinaryOperand is Scalar: with nogil: result = move( cpp_binaryop.binary_operation( - ( lhs).view(), - dereference(( rhs).c_obj), + lhs.view(), + dereference(rhs.c_obj), op, data_type.c_obj ) ) - elif isinstance(lhs, Scalar) and isinstance(rhs, Column): + elif LeftBinaryOperand is Scalar and RightBinaryOperand is Column: with nogil: result = move( cpp_binaryop.binary_operation( - dereference(( lhs).c_obj), - ( rhs).view(), + dereference(lhs.c_obj), + rhs.view(), op, data_type.c_obj ) diff --git a/python/cudf/cudf/_lib/pylibcudf/copying.pxd b/python/cudf/cudf/_lib/pylibcudf/copying.pxd index 3567df9ac9c..7b5f1e70ea3 100644 --- a/python/cudf/cudf/_lib/pylibcudf/copying.pxd +++ b/python/cudf/cudf/_lib/pylibcudf/copying.pxd @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. from libcpp cimport bool as cbool @@ -9,6 +9,26 @@ from .column cimport Column from .scalar cimport Scalar from .table cimport Table +ctypedef fused ColumnOrTable: + Table + Column + + +ctypedef fused TableOrListOfScalars: + Table + # The contents of the list must be validated as Scalars at runtime. + list + + +# Need two separate fused types to generate the cartesian product of signatures. +ctypedef fused LeftCopyIfElseOperand: + Column + Scalar + +ctypedef fused RightCopyIfElseOperand: + Column + Scalar + cpdef Table gather( Table source_table, @@ -16,13 +36,9 @@ cpdef Table gather( out_of_bounds_policy bounds_policy ) -cpdef Table scatter_table(Table source, Column scatter_map, Table target_table) - -cpdef Table scatter_scalars(list source, Column scatter_map, Table target_table) +cpdef Table scatter(TableOrListOfScalars source, Column scatter_map, Table target_table) -cpdef object empty_column_like(Column input) - -cpdef object empty_table_like(Table input) +cpdef ColumnOrTable empty_like(ColumnOrTable input) cpdef Column allocate_like(Column input_column, mask_allocation_policy policy, size=*) @@ -44,18 +60,20 @@ cpdef Column copy_range( cpdef Column shift(Column input, size_type offset, Scalar fill_values) -cpdef list column_split(Column input_column, list splits) - -cpdef list table_split(Table input_table, list splits) - -cpdef list column_slice(Column input_column, list indices) +cpdef list split(ColumnOrTable input, list splits) -cpdef list table_slice(Table input_table, list indices) +cpdef list slice(ColumnOrTable input, list indices) -cpdef Column copy_if_else(object lhs, object rhs, Column boolean_mask) - -cpdef Table boolean_mask_table_scatter(Table input, Table target, Column boolean_mask) +cpdef Column copy_if_else( + LeftCopyIfElseOperand lhs, + RightCopyIfElseOperand rhs, + Column boolean_mask +) -cpdef Table boolean_mask_scalars_scatter(list input, Table target, Column boolean_mask) +cpdef Table boolean_mask_scatter( + TableOrListOfScalars input, + Table target, + Column boolean_mask +) cpdef Scalar get_element(Column input_column, size_type index) diff --git a/python/cudf/cudf/_lib/pylibcudf/copying.pyx b/python/cudf/cudf/_lib/pylibcudf/copying.pyx index 12e592f3a92..d78955dc325 100644 --- a/python/cudf/cudf/_lib/pylibcudf/copying.pyx +++ b/python/cudf/cudf/_lib/pylibcudf/copying.pyx @@ -67,49 +67,22 @@ cpdef Table gather( return Table.from_libcudf(move(c_result)) -cpdef Table scatter_table(Table source, Column scatter_map, Table target_table): - """Scatter rows from source into target_table according to scatter_map. - - For details, see :cpp:func:`scatter`. - - Parameters - ---------- - source : Table - The table object from which to pull data. - scatter_map : Column - A mapping from rows in source to rows in target_table. - target_table : Table - The table object into which to scatter data. - - Returns - ------- - pylibcudf.Table - The result of the scatter - """ - cdef unique_ptr[table] c_result - - with nogil: - c_result = move( - cpp_copying.scatter( - source.view(), - scatter_map.view(), - target_table.view(), - ) - ) - - return Table.from_libcudf(move(c_result)) - +cpdef Table scatter( + TableOrListOfScalars source, + Column scatter_map, + Table target_table +): + """Scatter from source into target_table according to scatter_map. -# TODO: Could generalize list to sequence -cpdef Table scatter_scalars(list source, Column scatter_map, Table target_table): - """Scatter scalars from source into target_table according to scatter_map. + If source is a table, it specifies rows to scatter. If source is a list, + each scalar is scattered into the corresponding column in the ``target_table``. For details, see :cpp:func:`scatter`. Parameters ---------- - source : List[Scalar] - A list of scalars to scatter into target_table. + source : Union[Table, List[Scalar]] + The table object or list of scalars from which to pull data. scatter_map : Column A mapping from rows in source to rows in target_table. target_table : Table @@ -117,73 +90,58 @@ cpdef Table scatter_scalars(list source, Column scatter_map, Table target_table) Returns ------- - pylibcudf.Table + Table The result of the scatter """ - cdef vector[reference_wrapper[const scalar]] source_scalars = \ - _as_vector(source) - cdef unique_ptr[table] c_result - with nogil: - c_result = move( - cpp_copying.scatter( - source_scalars, - scatter_map.view(), - target_table.view(), + cdef vector[reference_wrapper[const scalar]] source_scalars + if TableOrListOfScalars is Table: + with nogil: + c_result = move( + cpp_copying.scatter( + source.view(), + scatter_map.view(), + target_table.view(), + ) ) - ) - - return Table.from_libcudf(move(c_result)) - - -cpdef object empty_column_like(Column input): - """Create an empty column with the same type as input. - - For details, see :cpp:func:`empty_like`. - - Parameters - ---------- - input : Column - The column to use as a template for the output. - - Returns - ------- - pylibcudf.Column - An empty column with the same type as input. - """ - cdef unique_ptr[column] c_column_result - with nogil: - c_column_result = move( - cpp_copying.empty_like( - ( input).view(), + else: + source_scalars = _as_vector(source) + with nogil: + c_result = move( + cpp_copying.scatter( + source_scalars, + scatter_map.view(), + target_table.view(), + ) ) - ) - return Column.from_libcudf(move(c_column_result)) + return Table.from_libcudf(move(c_result)) -cpdef object empty_table_like(Table input): - """Create an empty table with the same type as input. +cpdef ColumnOrTable empty_like(ColumnOrTable input): + """Create an empty column or table with the same type as ``input``. For details, see :cpp:func:`empty_like`. Parameters ---------- - input : Table - The table to use as a template for the output. + input : Union[Column, Table] + The column or table to use as a template for the output. Returns ------- - pylibcudf.Table - An empty table with the same type as input. + Union[Column, Table] + An empty column or table with the same type(s) as ``input``. """ - cdef unique_ptr[table] c_table_result - with nogil: - c_table_result = move( - cpp_copying.empty_like( - (
input).view(), - ) - ) - return Table.from_libcudf(move(c_table_result)) + cdef unique_ptr[table] c_tbl_result + cdef unique_ptr[column] c_col_result + if ColumnOrTable is Column: + with nogil: + c_col_result = move(cpp_copying.empty_like(input.view())) + return Column.from_libcudf(move(c_col_result)) + else: + with nogil: + c_tbl_result = move(cpp_copying.empty_like(input.view())) + return Table.from_libcudf(move(c_tbl_result)) cpdef Column allocate_like( @@ -340,157 +298,100 @@ cpdef Column shift(Column input, size_type offset, Scalar fill_values): return Column.from_libcudf(move(c_result)) -cpdef list column_split(Column input_column, list splits): - """Split input_column into multiple columns. +cpdef list split(ColumnOrTable input, list splits): + """Split input into multiple. For details on the implementation, see :cpp:func:`split`. Parameters ---------- - input_column : Column + input : Union[Column, Table] The column to split. splits : List[int] The indices at which to split the column. Returns ------- - List[pylibcudf.Column] - The result of splitting input_column. + List[Union[Column, Table]] + The result of splitting input. """ - cdef vector[size_type] c_splits - cdef int split - for split in splits: - c_splits.push_back(split) - - cdef vector[column_view] c_result - with nogil: - c_result = move( - cpp_copying.split( - input_column.view(), - c_splits - ) - ) - + cdef vector[size_type] c_splits = splits + cdef vector[column_view] c_col_result + cdef vector[table_view] c_tbl_result cdef int i - return [ - Column.from_column_view(c_result[i], input_column) - for i in range(c_result.size()) - ] + if ColumnOrTable is Column: + with nogil: + c_col_result = move(cpp_copying.split(input.view(), c_splits)) -cpdef list table_split(Table input_table, list splits): - """Split input_table into multiple tables. - - For details on the implementation, see :cpp:func:`split`. - - Parameters - ---------- - input_table : Table - The table to split. - splits : List[int] - The indices at which to split the table. - - Returns - ------- - List[pylibcudf.Table] - The result of splitting input_table. - """ - cdef vector[size_type] c_splits = splits - cdef vector[table_view] c_result - with nogil: - c_result = move( - cpp_copying.split( - input_table.view(), - c_splits - ) - ) + return [ + Column.from_column_view(c_col_result[i], input) + for i in range(c_col_result.size()) + ] + else: + with nogil: + c_tbl_result = move(cpp_copying.split(input.view(), c_splits)) - cdef int i - return [ - Table.from_table_view(c_result[i], input_table) - for i in range(c_result.size()) - ] + return [ + Table.from_table_view(c_tbl_result[i], input) + for i in range(c_tbl_result.size()) + ] -cpdef list column_slice(Column input_column, list indices): - """Slice input_column according to indices. +cpdef list slice(ColumnOrTable input, list indices): + """Slice input according to indices. For details on the implementation, see :cpp:func:`slice`. Parameters ---------- - input_column : Column - The column to slice. + input_column : Union[Column, Table] + The column or table to slice. indices : List[int] - The indices to select from input_column. + The indices to select from input. Returns ------- - List[pylibcudf.Column] - The result of slicing input_column. + List[Union[Column, Table]] + The result of slicing ``input``. """ cdef vector[size_type] c_indices = indices - cdef vector[column_view] c_result - with nogil: - c_result = move( - cpp_copying.slice( - input_column.view(), - c_indices - ) - ) - + cdef vector[column_view] c_col_result + cdef vector[table_view] c_tbl_result cdef int i - return [ - Column.from_column_view(c_result[i], input_column) - for i in range(c_result.size()) - ] - - -cpdef list table_slice(Table input_table, list indices): - """Slice input_table according to indices. - - For details on the implementation, see :cpp:func:`slice`. - - Parameters - ---------- - input_table : Table - The table to slice. - indices : List[int] - The indices to select from input_table. + if ColumnOrTable is Column: + with nogil: + c_col_result = move(cpp_copying.slice(input.view(), c_indices)) - Returns - ------- - List[pylibcudf.Table] - The result of slicing input_table. - """ - cdef vector[size_type] c_indices = indices - cdef vector[table_view] c_result - with nogil: - c_result = move( - cpp_copying.slice( - input_table.view(), - c_indices - ) - ) + return [ + Column.from_column_view(c_col_result[i], input) + for i in range(c_col_result.size()) + ] + else: + with nogil: + c_tbl_result = move(cpp_copying.slice(input.view(), c_indices)) - cdef int i - return [ - Table.from_table_view(c_result[i], input_table) - for i in range(c_result.size()) - ] + return [ + Table.from_table_view(c_tbl_result[i], input) + for i in range(c_tbl_result.size()) + ] -cpdef Column copy_if_else(object lhs, object rhs, Column boolean_mask): +cpdef Column copy_if_else( + LeftCopyIfElseOperand lhs, + RightCopyIfElseOperand rhs, + Column boolean_mask +): """Copy elements from lhs or rhs into a new column according to boolean_mask. For details on the implementation, see :cpp:func:`copy_if_else`. Parameters ---------- - lhs : Column or Scalar + lhs : Union[Column, Scalar] The column or scalar to copy from if the corresponding element in boolean_mask is True. - rhs : Column or Scalar + rhs : Union[Column, Scalar] The column or scalar to copy from if the corresponding element in boolean_mask is False. boolean_mask : Column @@ -503,56 +404,51 @@ cpdef Column copy_if_else(object lhs, object rhs, Column boolean_mask): """ cdef unique_ptr[column] result - if isinstance(lhs, Column) and isinstance(rhs, Column): + if LeftCopyIfElseOperand is Column and RightCopyIfElseOperand is Column: with nogil: result = move( - cpp_copying.copy_if_else( - ( lhs).view(), - ( rhs).view(), - boolean_mask.view() - ) + cpp_copying.copy_if_else(lhs.view(), rhs.view(), boolean_mask.view()) ) - elif isinstance(lhs, Column) and isinstance(rhs, Scalar): + elif LeftCopyIfElseOperand is Column and RightCopyIfElseOperand is Scalar: with nogil: result = move( cpp_copying.copy_if_else( - ( lhs).view(), - dereference(( rhs).c_obj), - boolean_mask.view() + lhs.view(), dereference(rhs.c_obj), boolean_mask.view() ) ) - elif isinstance(lhs, Scalar) and isinstance(rhs, Column): + elif LeftCopyIfElseOperand is Scalar and RightCopyIfElseOperand is Column: with nogil: result = move( cpp_copying.copy_if_else( - dereference(( lhs).c_obj), - ( rhs).view(), - boolean_mask.view() + dereference(lhs.c_obj), rhs.view(), boolean_mask.view() ) ) - elif isinstance(lhs, Scalar) and isinstance(rhs, Scalar): + else: with nogil: result = move( cpp_copying.copy_if_else( - dereference(( lhs).c_obj), - dereference(( rhs).c_obj), - boolean_mask.view() + dereference(lhs.c_obj), dereference(rhs.c_obj), boolean_mask.view() ) ) - else: - raise ValueError(f"Invalid arguments {lhs} and {rhs}") return Column.from_libcudf(move(result)) -cpdef Table boolean_mask_table_scatter(Table input, Table target, Column boolean_mask): +cpdef Table boolean_mask_scatter( + TableOrListOfScalars input, + Table target, + Column boolean_mask +): """Scatter rows from input into target according to boolean_mask. + If source is a table, it specifies rows to scatter. If source is a list, + each scalar is scattered into the corresponding column in the ``target_table``. + For details on the implementation, see :cpp:func:`boolean_mask_scatter`. Parameters ---------- - input : Table + input : Union[Table, List[Scalar]] The table object from which to pull data. target : Table The table object into which to scatter data. @@ -561,54 +457,31 @@ cpdef Table boolean_mask_table_scatter(Table input, Table target, Column boolean Returns ------- - pylibcudf.Table + Table The result of the scatter """ cdef unique_ptr[table] result + cdef vector[reference_wrapper[const scalar]] source_scalars - with nogil: - result = move( - cpp_copying.boolean_mask_scatter( - (
input).view(), - target.view(), - boolean_mask.view() + if TableOrListOfScalars is Table: + with nogil: + result = move( + cpp_copying.boolean_mask_scatter( + input.view(), + target.view(), + boolean_mask.view() + ) ) - ) - - return Table.from_libcudf(move(result)) - - -# TODO: Could generalize list to sequence -cpdef Table boolean_mask_scalars_scatter(list input, Table target, Column boolean_mask): - """Scatter scalars from input into target according to boolean_mask. - - For details on the implementation, see :cpp:func:`boolean_mask_scatter`. - - Parameters - ---------- - input : List[Scalar] - A list of scalars to scatter into target. - target : Table - The table object into which to scatter data. - boolean_mask : Column - A mapping from rows in input to rows in target. - - Returns - ------- - pylibcudf.Table - The result of the scatter - """ - cdef vector[reference_wrapper[const scalar]] source_scalars = _as_vector(input) - - cdef unique_ptr[table] result - with nogil: - result = move( - cpp_copying.boolean_mask_scatter( - source_scalars, - target.view(), - boolean_mask.view(), + else: + source_scalars = _as_vector(input) + with nogil: + result = move( + cpp_copying.boolean_mask_scatter( + source_scalars, + target.view(), + boolean_mask.view(), + ) ) - ) return Table.from_libcudf(move(result))