@@ -889,6 +889,12 @@ void AddAsciiStringLength(FunctionRegistry* registry) {
889889 ty);
890890 DCHECK_OK (func->AddKernel ({ty}, int64 (), std::move (exec)));
891891 }
892+ // View element length is int32-sized, so both view types emit int32.
893+ for (const auto & ty : BinaryViewTypes ()) {
894+ auto exec = GenerateVarBinaryViewBase<applicator::ScalarUnaryNotNull, Int32Type,
895+ BinaryLength>(*ty);
896+ DCHECK_OK (func->AddKernel ({ty}, int32 (), std::move (exec)));
897+ }
892898 DCHECK_OK (func->AddKernel ({InputType (Type::FIXED_SIZE_BINARY )}, int32 (),
893899 BinaryLength::FixedSizeExec));
894900 DCHECK_OK (registry->AddFunction (std::move (func)));
@@ -1337,27 +1343,45 @@ struct RegexSubstringMatcher {
13371343
13381344template <typename Type, typename Matcher>
13391345struct MatchSubstringImpl {
1340- using offset_type = typename Type::offset_type;
1341-
13421346 static Status Exec (KernelContext* ctx, const ExecSpan& batch, ExecResult* out,
13431347 const Matcher* matcher) {
1344- StringBoolTransform<Type>(
1345- ctx, batch,
1346- [&matcher](const void * raw_offsets, const uint8_t * data, int64_t length,
1347- int64_t output_offset, uint8_t * output) {
1348- const offset_type* offsets = reinterpret_cast <const offset_type*>(raw_offsets);
1349- FirstTimeBitmapWriter bitmap_writer (output, output_offset, length);
1350- for (int64_t i = 0 ; i < length; ++i) {
1351- const char * current_data = reinterpret_cast <const char *>(data + offsets[i]);
1352- int64_t current_length = offsets[i + 1 ] - offsets[i];
1353- if (matcher->Match (std::string_view (current_data, current_length))) {
1354- bitmap_writer.Set ();
1348+ if constexpr (is_binary_view_like_type<Type>::value) {
1349+ // Views have no packed offset buffer, so iterate per element. Null slots
1350+ // are matched too (masked by output validity); reading their zero-filled
1351+ // view header is safe, as StringPredicateFunctor also assumes.
1352+ const ArraySpan& input = batch[0 ].array ;
1353+ ArraySpan* out_arr = out->array_span_mutable ();
1354+ ArrayIterator<Type> input_it (input);
1355+ FirstTimeBitmapWriter bitmap_writer (out_arr->buffers [1 ].data , out_arr->offset ,
1356+ input.length );
1357+ for (int64_t i = 0 ; i < input.length ; ++i) {
1358+ if (matcher->Match (input_it ())) {
1359+ bitmap_writer.Set ();
1360+ }
1361+ bitmap_writer.Next ();
1362+ }
1363+ bitmap_writer.Finish ();
1364+ } else {
1365+ using offset_type = typename Type::offset_type;
1366+ StringBoolTransform<Type>(
1367+ ctx, batch,
1368+ [&matcher](const void * raw_offsets, const uint8_t * data, int64_t length,
1369+ int64_t output_offset, uint8_t * output) {
1370+ const offset_type* offsets =
1371+ reinterpret_cast <const offset_type*>(raw_offsets);
1372+ FirstTimeBitmapWriter bitmap_writer (output, output_offset, length);
1373+ for (int64_t i = 0 ; i < length; ++i) {
1374+ const char * current_data = reinterpret_cast <const char *>(data + offsets[i]);
1375+ int64_t current_length = offsets[i + 1 ] - offsets[i];
1376+ if (matcher->Match (std::string_view (current_data, current_length))) {
1377+ bitmap_writer.Set ();
1378+ }
1379+ bitmap_writer.Next ();
13551380 }
1356- bitmap_writer.Next ();
1357- }
1358- bitmap_writer.Finish ();
1359- },
1360- out);
1381+ bitmap_writer.Finish ();
1382+ },
1383+ out);
1384+ }
13611385 return Status::OK ();
13621386 }
13631387};
@@ -1611,6 +1635,19 @@ const FunctionDoc match_like_doc(
16111635 {" strings" }, " MatchSubstringOptions" , /* options_required=*/ true );
16121636#endif
16131637
1638+ // Register the view kernels for a match-substring-style predicate. Registered per
1639+ // view type (not via GenerateVarBinaryViewBase) so utf8_view -> StringViewType keeps
1640+ // the is_utf8 distinction used by ignore_case/regex folding.
1641+ template <template <typename ...> class ExecTemplate , typename ... Matcher>
1642+ void AddMatchSubstringViewKernels (ScalarFunction* func) {
1643+ DCHECK_OK (func->AddKernel ({binary_view ()}, boolean (),
1644+ ExecTemplate<BinaryViewType, Matcher...>::Exec,
1645+ MatchSubstringState::Init));
1646+ DCHECK_OK (func->AddKernel ({utf8_view ()}, boolean (),
1647+ ExecTemplate<StringViewType, Matcher...>::Exec,
1648+ MatchSubstringState::Init));
1649+ }
1650+
16141651void AddAsciiStringMatchSubstring (FunctionRegistry* registry) {
16151652 {
16161653 auto func = std::make_shared<ScalarFunction>(" match_substring" , Arity::Unary (),
@@ -1620,6 +1657,7 @@ void AddAsciiStringMatchSubstring(FunctionRegistry* registry) {
16201657 DCHECK_OK (
16211658 func->AddKernel ({ty}, boolean (), std::move (exec), MatchSubstringState::Init));
16221659 }
1660+ AddMatchSubstringViewKernels<MatchSubstring, PlainSubstringMatcher>(func.get ());
16231661 DCHECK_OK (registry->AddFunction (std::move (func)));
16241662 }
16251663 {
@@ -1631,6 +1669,7 @@ void AddAsciiStringMatchSubstring(FunctionRegistry* registry) {
16311669 DCHECK_OK (
16321670 func->AddKernel ({ty}, boolean (), std::move (exec), MatchSubstringState::Init));
16331671 }
1672+ AddMatchSubstringViewKernels<MatchSubstring, PlainStartsWithMatcher>(func.get ());
16341673 DCHECK_OK (registry->AddFunction (std::move (func)));
16351674 }
16361675 {
@@ -1641,6 +1680,7 @@ void AddAsciiStringMatchSubstring(FunctionRegistry* registry) {
16411680 DCHECK_OK (
16421681 func->AddKernel ({ty}, boolean (), std::move (exec), MatchSubstringState::Init));
16431682 }
1683+ AddMatchSubstringViewKernels<MatchSubstring, PlainEndsWithMatcher>(func.get ());
16441684 DCHECK_OK (registry->AddFunction (std::move (func)));
16451685 }
16461686#ifdef ARROW_WITH_RE2
@@ -1652,6 +1692,7 @@ void AddAsciiStringMatchSubstring(FunctionRegistry* registry) {
16521692 DCHECK_OK (
16531693 func->AddKernel ({ty}, boolean (), std::move (exec), MatchSubstringState::Init));
16541694 }
1695+ AddMatchSubstringViewKernels<MatchSubstring, RegexSubstringMatcher>(func.get ());
16551696 DCHECK_OK (registry->AddFunction (std::move (func)));
16561697 }
16571698 {
@@ -1662,6 +1703,7 @@ void AddAsciiStringMatchSubstring(FunctionRegistry* registry) {
16621703 DCHECK_OK (
16631704 func->AddKernel ({ty}, boolean (), std::move (exec), MatchSubstringState::Init));
16641705 }
1706+ AddMatchSubstringViewKernels<MatchLike>(func.get ());
16651707 DCHECK_OK (registry->AddFunction (std::move (func)));
16661708 }
16671709#endif
@@ -1670,6 +1712,17 @@ void AddAsciiStringMatchSubstring(FunctionRegistry* registry) {
16701712// ----------------------------------------------------------------------
16711713// Substring find - lfind/index/etc.
16721714
1715+ // The output offset type for find/count kernels. Like TypeTraits<T>::OffsetType,
1716+ // but also defined for the view types, whose per-element length is int32-sized.
1717+ template <typename T, typename Enable = void >
1718+ struct StringOffsetType {
1719+ using type = typename TypeTraits<T>::OffsetType;
1720+ };
1721+ template <typename T>
1722+ struct StringOffsetType <T, enable_if_binary_view_like<T>> {
1723+ using type = Int32Type;
1724+ };
1725+
16731726struct FindSubstring {
16741727 const PlainSubstringMatcher matcher_;
16751728
@@ -1716,7 +1769,7 @@ struct FindSubstringRegex {
17161769
17171770template <typename InputType>
17181771struct FindSubstringExec {
1719- using OffsetType = typename TypeTraits <InputType>::OffsetType ;
1772+ using OffsetType = typename StringOffsetType <InputType>::type ;
17201773 static Status Exec (KernelContext* ctx, const ExecSpan& batch, ExecResult* out) {
17211774 const MatchSubstringOptions& options = MatchSubstringState::Get (ctx);
17221775 if (options.ignore_case ) {
@@ -1746,7 +1799,7 @@ const FunctionDoc find_substring_doc(
17461799#ifdef ARROW_WITH_RE2
17471800template <typename InputType>
17481801struct FindSubstringRegexExec {
1749- using OffsetType = typename TypeTraits <InputType>::OffsetType ;
1802+ using OffsetType = typename StringOffsetType <InputType>::type ;
17501803 static Status Exec (KernelContext* ctx, const ExecSpan& batch, ExecResult* out) {
17511804 const MatchSubstringOptions& options = MatchSubstringState::Get (ctx);
17521805 ARROW_ASSIGN_OR_RAISE (auto matcher, FindSubstringRegex::Make (options, false ));
@@ -1774,6 +1827,13 @@ void AddAsciiStringFindSubstring(FunctionRegistry* registry) {
17741827 GenerateVarBinaryToVarBinary<FindSubstringExec>(ty),
17751828 MatchSubstringState::Init));
17761829 }
1830+ // Per view type to keep the is_utf8 distinction; view length fits int32.
1831+ DCHECK_OK (func->AddKernel ({binary_view ()}, int32 (),
1832+ FindSubstringExec<BinaryViewType>::Exec,
1833+ MatchSubstringState::Init));
1834+ DCHECK_OK (func->AddKernel ({utf8_view ()}, int32 (),
1835+ FindSubstringExec<StringViewType>::Exec,
1836+ MatchSubstringState::Init));
17771837 DCHECK_OK (func->AddKernel ({InputType (Type::FIXED_SIZE_BINARY )}, int32 (),
17781838 FindSubstringExec<FixedSizeBinaryType>::Exec,
17791839 MatchSubstringState::Init));
@@ -1789,6 +1849,12 @@ void AddAsciiStringFindSubstring(FunctionRegistry* registry) {
17891849 GenerateVarBinaryToVarBinary<FindSubstringRegexExec>(ty),
17901850 MatchSubstringState::Init));
17911851 }
1852+ DCHECK_OK (func->AddKernel ({binary_view ()}, int32 (),
1853+ FindSubstringRegexExec<BinaryViewType>::Exec,
1854+ MatchSubstringState::Init));
1855+ DCHECK_OK (func->AddKernel ({utf8_view ()}, int32 (),
1856+ FindSubstringRegexExec<StringViewType>::Exec,
1857+ MatchSubstringState::Init));
17921858 DCHECK_OK (func->AddKernel ({InputType (Type::FIXED_SIZE_BINARY )}, int32 (),
17931859 FindSubstringRegexExec<FixedSizeBinaryType>::Exec,
17941860 MatchSubstringState::Init));
@@ -1862,7 +1928,7 @@ struct CountSubstringRegex {
18621928
18631929template <typename InputType>
18641930struct CountSubstringRegexExec {
1865- using OffsetType = typename TypeTraits <InputType>::OffsetType ;
1931+ using OffsetType = typename StringOffsetType <InputType>::type ;
18661932 static Status Exec (KernelContext* ctx, const ExecSpan& batch, ExecResult* out) {
18671933 const MatchSubstringOptions& options = MatchSubstringState::Get (ctx);
18681934 ARROW_ASSIGN_OR_RAISE (
@@ -1876,7 +1942,7 @@ struct CountSubstringRegexExec {
18761942
18771943template <typename InputType>
18781944struct CountSubstringExec {
1879- using OffsetType = typename TypeTraits <InputType>::OffsetType ;
1945+ using OffsetType = typename StringOffsetType <InputType>::type ;
18801946 static Status Exec (KernelContext* ctx, const ExecSpan& batch, ExecResult* out) {
18811947 const MatchSubstringOptions& options = MatchSubstringState::Get (ctx);
18821948 if (options.ignore_case ) {
@@ -1923,6 +1989,12 @@ void AddAsciiStringCountSubstring(FunctionRegistry* registry) {
19231989 GenerateVarBinaryToVarBinary<CountSubstringExec>(ty),
19241990 MatchSubstringState::Init));
19251991 }
1992+ DCHECK_OK (func->AddKernel ({binary_view ()}, int32 (),
1993+ CountSubstringExec<BinaryViewType>::Exec,
1994+ MatchSubstringState::Init));
1995+ DCHECK_OK (func->AddKernel ({utf8_view ()}, int32 (),
1996+ CountSubstringExec<StringViewType>::Exec,
1997+ MatchSubstringState::Init));
19261998 DCHECK_OK (func->AddKernel ({InputType (Type::FIXED_SIZE_BINARY )}, int32 (),
19271999 CountSubstringExec<FixedSizeBinaryType>::Exec,
19282000 MatchSubstringState::Init));
@@ -1938,6 +2010,12 @@ void AddAsciiStringCountSubstring(FunctionRegistry* registry) {
19382010 GenerateVarBinaryToVarBinary<CountSubstringRegexExec>(ty),
19392011 MatchSubstringState::Init));
19402012 }
2013+ DCHECK_OK (func->AddKernel ({binary_view ()}, int32 (),
2014+ CountSubstringRegexExec<BinaryViewType>::Exec,
2015+ MatchSubstringState::Init));
2016+ DCHECK_OK (func->AddKernel ({utf8_view ()}, int32 (),
2017+ CountSubstringRegexExec<StringViewType>::Exec,
2018+ MatchSubstringState::Init));
19412019 DCHECK_OK (func->AddKernel ({InputType (Type::FIXED_SIZE_BINARY )}, int32 (),
19422020 CountSubstringRegexExec<FixedSizeBinaryType>::Exec,
19432021 MatchSubstringState::Init));
0 commit comments