Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
b39a18e
feature: implement Glushkov's NFA
lingyany-nv Mar 21, 2026
d90a5e6
implement shared memory version of Glushkov's NFA
lingyany-nv Mar 23, 2026
7644ff4
refactor and simplify the code
lingyany-nv Mar 23, 2026
b3d7ab9
add python regex tests from spark-rapids regex tests
lingyany-nv Mar 25, 2026
cca1cba
add more complex regexes to the benchmarks
lingyany-nv Apr 1, 2026
8cacf16
fix the correctness (leftmost-longest vs leftmost-first) issue; chang…
lingyany-nv Apr 8, 2026
76fb67f
add compile-time-check to disalbe Glushkov when it cannot produce lef…
lingyany-nv Apr 9, 2026
cca35f9
add nullable regexes unit tests
lingyany-nv Apr 9, 2026
9edbab7
for affected benchmarks, keep unsupported patterns in the benchmark, …
lingyany-nv Apr 10, 2026
f2240da
fix minor issues
lingyany-nv Apr 10, 2026
98646b4
delete some dead code, update stale comments
lingyany-nv Apr 10, 2026
2eaec3c
remove stalbe comments
lingyany-nv Apr 10, 2026
30fa2eb
applied the formatter
lingyany-nv Apr 13, 2026
b114480
fix python format
lingyany-nv Apr 13, 2026
8acb318
fix clang-format again
lingyany-nv Apr 13, 2026
c4e1cb8
add replace_re tests, fixed minior issues
lingyany-nv Apr 15, 2026
7c4fc14
clang-format
lingyany-nv Apr 15, 2026
c18abd8
deleted unuseful comments
lingyany-nv Apr 28, 2026
604b216
remove multi-pattern replace
davidwendt May 26, 2026
2e3a089
remove multi_re.cu from cmake file
davidwendt May 26, 2026
6328c9e
remove nullable, lazy-quantifier; add tests
davidwendt May 26, 2026
68bd0f4
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt May 26, 2026
324b304
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt May 29, 2026
e642ea1
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt May 29, 2026
d635a72
use non-capture on findall tests
davidwendt May 29, 2026
93fcf31
fix merge conflicts
davidwendt Jun 2, 2026
5f7bab7
use reinst for positions
davidwendt Jun 2, 2026
2c119e5
remove glushkov.inl
davidwendt Jun 2, 2026
b1ebcd7
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jun 3, 2026
cf49828
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jun 4, 2026
e3ae0a0
remove unused glushkov_global_source
davidwendt Jun 4, 2026
24163c5
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jun 5, 2026
c2b29aa
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jun 8, 2026
2ca6b3b
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jun 10, 2026
1a6341b
fix merge conflicts
davidwendt Jun 12, 2026
08736b4
factor out useful tests appropriately
davidwendt Jun 12, 2026
3a17319
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jun 12, 2026
d415848
merge changes for findall_tests.cpp
davidwendt Jun 12, 2026
5a2228b
templatize prog_device in utilities.cuh functions
davidwendt Jun 12, 2026
e06ca9d
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jun 22, 2026
22e7b81
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jun 23, 2026
1ab8b6e
removed more code; change g_state to glushkov_state
davidwendt Jun 23, 2026
f59edb4
separated gkprog_device from reprog_device
davidwendt Jun 23, 2026
c29f286
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jun 24, 2026
6a11a35
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jun 25, 2026
d9ba38d
some cleanup of comments and member variable names
davidwendt Jun 25, 2026
03ad2da
rework gkprog_device::create
davidwendt Jun 25, 2026
7a3b5c2
fix merge conflict
davidwendt Jun 30, 2026
4a0df6a
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jun 30, 2026
53bb5cc
remove the GLUSHKOV regex-flag
davidwendt Jun 30, 2026
4dd07ed
add glushkov fast-path to appropriate regex functions
davidwendt Jun 30, 2026
b7f1b50
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jun 30, 2026
7d8e573
remove glushkov_tests.cpp
davidwendt Jun 30, 2026
6f7d705
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jun 30, 2026
73a179e
replace __builtins with STL calls
davidwendt Jun 30, 2026
e177089
reset regecomp.cpp
davidwendt Jun 30, 2026
3d3e50e
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jun 30, 2026
0999669
linter fix: auto cast
davidwendt Jul 1, 2026
b6aebfb
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 1, 2026
84af963
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 1, 2026
5810765
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 2, 2026
5ab9b4f
cleanup and rename reclass.hpp to common.cuh
davidwendt Jul 2, 2026
ef1376f
add env variable
davidwendt Jul 2, 2026
5535e37
undo unneeded benchmark changes
davidwendt Jul 2, 2026
bcbf166
add sync calls
davidwendt Jul 2, 2026
28d11f5
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 2, 2026
bdf6185
remove unneeded variable
davidwendt Jul 2, 2026
11f77ad
prevent double creating the reprog-device objects
davidwendt Jul 2, 2026
5189fe1
fix builtins space check
davidwendt Jul 2, 2026
d9ff906
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 2, 2026
38f856b
fix new linter error
davidwendt Jul 3, 2026
92cd568
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 3, 2026
e1d7ec5
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 6, 2026
5d18241
remove nullable words
davidwendt Jul 6, 2026
7efb37f
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 7, 2026
7ae1f3c
use stack intead of recursion for eps_closure and ordered_eps_frontier
lingyany-nv Jul 7, 2026
9d6a4ca
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 7, 2026
2891dcc
remove new; rework reclass
davidwendt Jul 7, 2026
9046fdf
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 7, 2026
92e93d5
undo comment change
davidwendt Jul 7, 2026
35290f6
undo more unneeded changes to regexec.cpp
davidwendt Jul 7, 2026
7047521
remove unneeded include
davidwendt Jul 7, 2026
01e844e
added some consts
davidwendt Jul 7, 2026
c848b9d
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 7, 2026
9d2570e
use tuple as return type, use array instead of map
lingyany-nv Jul 8, 2026
293d238
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 8, 2026
251211d
Merge branch 'lingyany/glushkov-nfa' of github.com:lingyany-nv/cudf i…
davidwendt Jul 8, 2026
8a46843
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 8, 2026
ae3bdbc
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 8, 2026
7179ad7
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 9, 2026
41caa42
replace some literals with named constant
davidwendt Jul 9, 2026
cc0e60a
remove include cuda_runtime.h
davidwendt Jul 9, 2026
54af99b
add/update some comments
davidwendt Jul 9, 2026
8eaf307
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 9, 2026
ed12956
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 13, 2026
0e54aa9
Merge branch 'main' into lingyany/glushkov-nfa
davidwendt Jul 14, 2026
faf578d
fix merge conflicts
davidwendt Jul 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,7 @@ add_library(
src/strings/merge/merge.cu
src/strings/padding.cu
src/strings/positions.cu
src/strings/regex/glushkov_regcomp.cpp
src/strings/regex/regcomp.cpp
src/strings/regex/regexec.cpp
src/strings/regex/regex_program.cpp
Expand Down
39 changes: 34 additions & 5 deletions cpp/benchmarks/string/contains.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2021-2025, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2021-2026, NVIDIA CORPORATION.
* SPDX-License-Identifier: Apache-2.0
*/

Expand All @@ -12,21 +12,49 @@

#include <nvbench/nvbench.cuh>

#include <utility>
#include <vector>

// create_string_column generates data from 10 hardcoded strings where only row 0
// ("123 abc 4567890 DEFGHI 0987 5W43") is scattered at exactly hit_rate%.
// All patterns below match ONLY row 0 (via the unique "5W" substring), so
// the hit_rate parameter correctly controls the match frequency for every pattern.
// longer pattern lengths demand more working memory per string
std::string patterns[] = {"^\\d+ [a-z]+", "[A-Z ]+\\d+ +\\d+[A-Z]+\\d+$", "5W43"};
// patterns 0 and 1 contain anchors (^ $) so Glushkov falls back to Thompson for those
static std::vector<std::string> const patterns = {
"^\\d+ [a-z]+", // 0: anchor pattern (anchors ^ $)
"[A-Z ]+\\d+ +\\d+[A-Z]+\\d+$", // 1: anchor pattern (anchors ^ $)
"5W43", // 2: simple literal (baseline)
"5[A-Z]\\d+", // 3: char class + quantifier (3 positions)
"5W43|X9Z8", // 4: alternation (8 positions; only "5W43" branch matches)
"5W4{1,3}", // 5: bounded repetition (5 positions)
"(?:5W){1,2}", // 6: non-capturing group + bounded rep (4 positions)
"5.4.", // 7: dot wildcard (4 positions)
".+5W", // 8: late-failure stress (dot prefix):
// '.' matches everything → phase 1 state never dies until "5W" found;
// only row 0 has "5W" → hit_rate controls match frequency correctly
};

static void bench_contains(nvbench::state& state)
{
auto const num_rows = static_cast<cudf::size_type>(state.get_int64("num_rows"));
auto const row_width = static_cast<cudf::size_type>(state.get_int64("row_width"));
auto const pattern_index = static_cast<cudf::size_type>(state.get_int64("pattern"));
auto const hit_rate = static_cast<cudf::size_type>(state.get_int64("hit_rate"));
auto const engine = state.get_string("engine");

// Patterns 0-1 contain anchors (^ $) which Glushkov doesn't support
if (engine == "glushkov" && pattern_index <= 1) {
state.skip("anchor pattern — Glushkov falls back to Thompson");
return;
}

auto col = create_string_column(num_rows, row_width, hit_rate);
auto input = cudf::strings_column_view(col->view());

auto pattern = patterns[pattern_index];
auto program = cudf::strings::regex_program::create(pattern);
auto flags = (engine == "glushkov") ? cudf::strings::regex_flags::GLUSHKOV
: cudf::strings::regex_flags::DEFAULT;
auto program = cudf::strings::regex_program::create(patterns[pattern_index], flags);

state.add_global_memory_reads<nvbench::int8_t>(col->alloc_size());
state.add_global_memory_writes<nvbench::int32_t>(input.size());
Expand All @@ -40,4 +68,5 @@ NVBENCH_BENCH(bench_contains)
.add_int64_axis("row_width", {32, 64, 128, 256})
.add_int64_axis("num_rows", {32768, 262144, 2097152})
.add_int64_axis("hit_rate", {50, 100}) // percentage
.add_int64_axis("pattern", {0, 1, 2});
.add_int64_axis("pattern", {0, 1, 2, 3, 4, 5, 6, 7, 8})
.add_string_axis("engine", {"thompson", "glushkov"});
34 changes: 29 additions & 5 deletions cpp/benchmarks/string/count.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2021-2025, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2021-2026, NVIDIA CORPORATION.
* SPDX-License-Identifier: Apache-2.0
*/

Expand All @@ -14,14 +14,36 @@

#include <nvbench/nvbench.cuh>

static std::string patterns[] = {"\\d+", "a"};
#include <utility>
#include <vector>

// All patterns are Glushkov-compatible (no anchors ^ $ \b \B, all < 64 NFA positions).
// Match-rate estimates for 32-char random ASCII strings (chars 32-126, ~90% ASCII):
// \d+ : ~97% of strings contain ≥1 digit run (~3 matches/string)
// [a-z]+[A-Z]+ : ~92% of strings contain ≥1 lower→upper transition (~2 matches)
// [a-f]+|[0-5]+ : similar density to \d+ (~2 matches/string) -- exercises alternation
// [a-z][0-9]{0,3}[A-Z]: ~92% via the zero-digit case alone -- exercises gap transitions
static std::vector<std::string> const patterns = {
"\\d+", // 0: char class + quantifier (baseline)
"a", // 1: simple literal
"[a-z]+[A-Z]+", // 2: multi char-class sequence
"[a-f]+|[0-5]+", // 3: alternation (comparable density to \d+)
"[a-z][0-9]{0,3}[A-Z]", // 4: bounded repetition / gap transitions (7 positions)
".+[0-9]", // 5: late-failure stress (~97% hit rate, ~1 match/string):
// '.' matches all ASCII → phase 1 state never dies until digit
// found; O(n) two-phase search for both engines
"[a-z]+Z", // 6: late-failure + low hit rate (~23% on 32-char strings,
// ~79% on 256-char strings); Glushkov skips ~73% of start
// positions via reach filter
};

static void bench_count(nvbench::state& state)
{
auto const num_rows = static_cast<cudf::size_type>(state.get_int64("num_rows"));
auto const min_width = static_cast<cudf::size_type>(state.get_int64("min_width"));
auto const max_width = static_cast<cudf::size_type>(state.get_int64("max_width"));
auto const pattern_index = static_cast<cudf::size_type>(state.get_int64("pattern"));
auto const engine = state.get_string("engine");

data_profile const table_profile = data_profile_builder().distribution(
cudf::type_id::STRING, distribution_id::NORMAL, min_width, max_width);
Expand All @@ -30,8 +52,9 @@ static void bench_count(nvbench::state& state)
cudf::strings_column_view input(table->view().column(0));

auto const pattern = patterns[pattern_index];

auto prog = cudf::strings::regex_program::create(pattern);
auto const flags = (engine == "glushkov") ? cudf::strings::regex_flags::GLUSHKOV
: cudf::strings::regex_flags::DEFAULT;
auto prog = cudf::strings::regex_program::create(pattern, flags);

state.set_cuda_stream(nvbench::make_cuda_stream_view(cudf::get_default_stream().value()));
// gather some throughput statistics as well
Expand All @@ -48,4 +71,5 @@ NVBENCH_BENCH(bench_count)
.add_int64_axis("min_width", {0})
.add_int64_axis("max_width", {32, 64, 128, 256})
.add_int64_axis("num_rows", {32768, 262144, 2097152})
.add_int64_axis("pattern", {0, 1});
.add_int64_axis("pattern", {0, 1, 2, 3, 4, 5, 6})
.add_string_axis("engine", {"thompson", "glushkov"});
50 changes: 43 additions & 7 deletions cpp/benchmarks/string/replace_re.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2021-2025, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2021-2026, NVIDIA CORPORATION.
* SPDX-License-Identifier: Apache-2.0
*/

Expand All @@ -12,19 +12,53 @@

#include <nvbench/nvbench.cuh>

#include <utility>
#include <vector>

// All patterns are Glushkov-compatible (no anchors ^ $ \b \B, all < 64 NFA positions).
// No capture groups in the patterns — for replace_with_backrefs the benchmark wraps
// each pattern in a capture group at runtime so \1 references the whole match.
// Match-rate estimates for 32-char random ASCII strings (chars 32-126, ~90% ASCII):
// \d+ : ~97% of strings contain ≥1 digit run (~3 matches/string)
// [a-z]+[A-Z]+ : ~92% of strings contain ≥1 lower→upper transition (~2 matches)
// [a-f]+|[0-5]+ : similar density to \d+ (~2 matches/string) -- exercises alternation
// [a-z][0-9]{0,3}[A-Z]: ~92% via the zero-digit case alone -- exercises gap transitions
static std::vector<std::string> const patterns = {
"\\d+", // 0: char class + quantifier (baseline)
"[a-z]+[A-Z]+", // 1: multi char-class sequence
"[a-f]+|[0-5]+", // 2: alternation (comparable density to \d+)
"[a-z][0-9]{0,3}[A-Z]", // 3: bounded repetition / gap transitions (7 positions)
".+[0-9]", // 4: late-failure stress (~97% hit rate — quadratic for Glushkov):
// '.' matches all ASCII → inner loop runs full string from every start
"[a-z]+Z", // 5: late-failure + low hit rate (~23% on 32-char, ~79% on 256-char)
};

static void bench_replace(nvbench::state& state)
{
auto const num_rows = static_cast<cudf::size_type>(state.get_int64("num_rows"));
auto const min_width = static_cast<cudf::size_type>(state.get_int64("min_width"));
auto const max_width = static_cast<cudf::size_type>(state.get_int64("max_width"));
auto const rtype = state.get_string("type");
auto const num_rows = static_cast<cudf::size_type>(state.get_int64("num_rows"));
auto const min_width = static_cast<cudf::size_type>(state.get_int64("min_width"));
auto const max_width = static_cast<cudf::size_type>(state.get_int64("max_width"));
auto const pattern_index = static_cast<cudf::size_type>(state.get_int64("pattern"));
auto const rtype = state.get_string("type");
auto const engine = state.get_string("engine");

// replace_with_backrefs requires capture groups; Glushkov doesn't support extract/backrefs
if (engine == "glushkov" && rtype == "backref") {
state.skip("backref replace — Glushkov doesn't support capture groups");
return;
}

data_profile const profile = data_profile_builder().distribution(
cudf::type_id::STRING, distribution_id::NORMAL, min_width, max_width);
auto const column = create_random_column(cudf::type_id::STRING, row_count{num_rows}, profile);
cudf::strings_column_view input(column->view());

auto program = cudf::strings::regex_program::create("(\\d+)");
auto flags = (engine == "glushkov") ? cudf::strings::regex_flags::GLUSHKOV
: cudf::strings::regex_flags::DEFAULT;
// Wrap in a capture group for backref replace so \1 references the whole match
auto const pat =
(rtype == "backref") ? "(" + patterns[pattern_index] + ")" : patterns[pattern_index];
auto program = cudf::strings::regex_program::create(pat, flags);

auto const data_size = column->alloc_size();
state.add_global_memory_reads<nvbench::int8_t>(data_size);
Expand All @@ -48,4 +82,6 @@ NVBENCH_BENCH(bench_replace)
.add_int64_axis("min_width", {0})
.add_int64_axis("max_width", {32, 64, 128, 256})
.add_int64_axis("num_rows", {32768, 262144, 2097152})
.add_string_axis("type", {"replace", "backref"});
.add_int64_axis("pattern", {0, 1, 2, 3, 4, 5})
.add_string_axis("type", {"replace", "backref"})
.add_string_axis("engine", {"thompson", "glushkov"});
37 changes: 31 additions & 6 deletions cpp/benchmarks/string/split_re.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2023-2025, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2023-2026, NVIDIA CORPORATION.
* SPDX-License-Identifier: Apache-2.0
*/

Expand All @@ -14,13 +14,36 @@

#include <nvbench/nvbench.cuh>

#include <utility>
#include <vector>

// All patterns are Glushkov-compatible (no anchors ^ $ \b \B, all < 64 NFA positions).
// Match-rate estimates for 32-char random ASCII strings (chars 32-126, ~90% ASCII):
// \d+ : ~97% of strings contain ≥1 digit run (~3 matches/string)
// [a-z]+[A-Z]+ : ~92% of strings contain ≥1 lower→upper transition (~2 matches)
// [a-f]+|[0-5]+ : similar density to \d+ (~2 matches/string) -- exercises alternation
// [a-z][0-9]{0,3}[A-Z]: ~92% via the zero-digit case alone -- exercises gap transitions
static std::vector<std::string> const patterns = {
"\\d+", // 0: char class + quantifier (baseline)
"[a-z]+[A-Z]+", // 1: multi char-class sequence
"[a-f]+|[0-5]+", // 2: alternation (comparable density to \d+)
"[a-z][0-9]{0,3}[A-Z]", // 3: bounded repetition / gap transitions (7 positions)
".+[0-9]", // 4: late-failure stress (~97% hit rate — quadratic for Glushkov):
// '.' matches all ASCII → inner loop runs full string from every start
"[a-z]+Z", // 5: late-failure + low hit rate (~23% on 32-char, ~79% on 256-char)
};

static void bench_split(nvbench::state& state)
{
auto const num_rows = static_cast<cudf::size_type>(state.get_int64("num_rows"));
auto const min_width = static_cast<cudf::size_type>(state.get_int64("min_width"));
auto const max_width = static_cast<cudf::size_type>(state.get_int64("max_width"));
auto const num_rows = static_cast<cudf::size_type>(state.get_int64("num_rows"));
auto const min_width = static_cast<cudf::size_type>(state.get_int64("min_width"));
auto const max_width = static_cast<cudf::size_type>(state.get_int64("max_width"));
auto const pattern_index = static_cast<cudf::size_type>(state.get_int64("pattern"));
auto const engine = state.get_string("engine");

auto prog = cudf::strings::regex_program::create("\\d+");
auto flags = (engine == "glushkov") ? cudf::strings::regex_flags::GLUSHKOV
: cudf::strings::regex_flags::DEFAULT;
auto prog = cudf::strings::regex_program::create(patterns[pattern_index], flags);

data_profile const profile = data_profile_builder().distribution(
cudf::type_id::STRING, distribution_id::NORMAL, min_width, max_width);
Expand All @@ -42,4 +65,6 @@ NVBENCH_BENCH(bench_split)
.set_name("split_re")
.add_int64_axis("min_width", {0})
.add_int64_axis("max_width", {32, 64, 128, 256})
.add_int64_axis("num_rows", {32768, 262144, 2097152});
.add_int64_axis("num_rows", {32768, 262144, 2097152})
.add_int64_axis("pattern", {0, 1, 2, 3, 4, 5})
.add_string_axis("engine", {"thompson", "glushkov"});
26 changes: 20 additions & 6 deletions cpp/include/cudf/strings/regex/flags.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@ namespace strings {
* and to match the Python flag values.
*/
enum regex_flags : uint32_t {
DEFAULT = 0, ///< default
IGNORECASE = 2, ///< ignore case on matching all literal characters
MULTILINE = 8, ///< the '^' and '$' honor new-line characters
DOTALL = 16, ///< the '.' matching includes new-line characters
ASCII = 256, ///< use only ASCII when matching built-in character classes
EXT_NEWLINE = 512 ///< new-line matches extended characters
DEFAULT = 0, ///< default
IGNORECASE = 2, ///< ignore case on matching all literal characters
MULTILINE = 8, ///< the '^' and '$' honor new-line characters
DOTALL = 16, ///< the '.' matching includes new-line characters
ASCII = 256, ///< use only ASCII when matching built-in character classes
EXT_NEWLINE = 512, ///< new-line matches extended characters
GLUSHKOV = 1024, ///< prefer Glushkov NFA (bit-parallel, no working memory);
///< automatically falls back to Thompson NFA when the pattern
///< contains assertions (^ $ \\b \\B) or has >64 positions
};

/**
Expand Down Expand Up @@ -87,6 +90,17 @@ constexpr bool is_ext_newline(regex_flags const f)
return (f & regex_flags::EXT_NEWLINE) == regex_flags::EXT_NEWLINE;
}

/**
* @brief Returns true if the given flags request the Glushkov NFA engine.
*
* @param f Regex flags to check
* @return true if `f` includes GLUSHKOV
*/
constexpr bool is_glushkov(regex_flags const f)
{
return (f & regex_flags::GLUSHKOV) == regex_flags::GLUSHKOV;
}

/**
* @brief Capture groups setting
*
Expand Down
8 changes: 4 additions & 4 deletions cpp/src/strings/extract/extract.cu
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ std::unique_ptr<table> extract(strings_column_view const& input,
rmm::cuda_stream_view stream,
rmm::device_async_resource_ref mr)
{
// create device object from regex_program
auto d_prog = regex_device_builder::create_prog_device(prog, stream);
// create device object from regex_program — extract() needs Thompson (Glushkov has no groups)
auto d_prog = regex_device_builder::create_prog_device(prog, stream, /*use_glushkov=*/false);

auto const groups = d_prog->group_counts();
CUDF_EXPECTS(groups > 0, "Group indicators not found in regex pattern");
Expand Down Expand Up @@ -151,8 +151,8 @@ std::unique_ptr<column> extract_single(strings_column_view const& input,
{
if (input.is_empty()) { return make_empty_column(type_id::STRING); }

// create device object from regex_program
auto d_prog = regex_device_builder::create_prog_device(prog, stream);
// create device object from regex_program — extract() needs Thompson (Glushkov has no groups)
auto d_prog = regex_device_builder::create_prog_device(prog, stream, /*use_glushkov=*/false);

auto const groups = d_prog->group_counts();
CUDF_EXPECTS(groups > 0, "capture groups not found in regex pattern", std::invalid_argument);
Expand Down
4 changes: 2 additions & 2 deletions cpp/src/strings/extract/extract_all.cu
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ std::unique_ptr<column> extract_all_record(strings_column_view const& input,
auto const strings_count = input.size();
auto const d_strings = column_device_view::create(input.parent(), stream);

// create device object from regex_program
auto d_prog = regex_device_builder::create_prog_device(prog, stream);
// create device object from regex_program — extract() needs Thompson (Glushkov has no groups)
auto d_prog = regex_device_builder::create_prog_device(prog, stream, /*use_glushkov=*/false);

// The extract pattern should always include groups.
auto const groups = d_prog->group_counts();
Expand Down
Loading
Loading