Improvements with regex system.

This commit is contained in:
2026-07-29 16:40:08 +01:00
parent b10f1291a0
commit 89b24a7488
6 changed files with 117 additions and 132 deletions
+2
View File
@@ -5,3 +5,5 @@ compile_commands.json
bin/
build/
.cache/
sample.txt
+4 -6
View File
@@ -4,20 +4,18 @@
#include "vase/shard.h"
struct RegexGroup {
uint32_t start;
uint32_t end;
bool matched;
uint32_t start{UINT32_MAX};
uint32_t end{UINT32_MAX};
};
struct RegexMatch {
uint32_t start;
uint32_t end;
std::vector<RegexGroup> groups{};
RegexGroup groups[9]{};
};
const std::vector<RegexMatch> regex_search(
std::vector<RegexMatch> regex_search(
Shard *root, std::string_view pattern_str,
uint32_t start_offset, uint32_t end_offset,
std::string_view options
);
void print_regex(const std::vector<RegexMatch> &matches);
+4 -4
View File
@@ -4,20 +4,20 @@
#include "pch.h"
struct Shard {
enum struct ShardKind {
enum struct ShardKind : uint8_t {
Branch,
Petal
} kind;
uint8_t height;
uint32_t length;
uint32_t lines;
uint8_t height;
std::atomic_uint32_t refs;
Shard(ShardKind kind, uint32_t length, uint32_t lines, uint8_t height)
: kind(kind), length(length), lines(lines), height(height), refs(1) {};
: kind(kind), height(height), length(length), lines(lines), refs(1) {};
virtual ~Shard() = default;
+32 -11
View File
@@ -24,7 +24,15 @@ int main(int argc, char *argv[]) {
char *text;
read_file(path, &text, &len);
auto start = std::chrono::steady_clock::now();
Vase vase = Vase(text, len);
auto end = std::chrono::steady_clock::now();
std::cout << "Time to load: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< " ms\n";
std::cout << "Press Enter to continue...";
std::cin.get();
vase.insert(1, "bcgr\ntt", 5);
vase.insert(2, "cgr\ntt", 5);
@@ -40,28 +48,41 @@ int main(int argc, char *argv[]) {
vase.erase(offset_of(vase.root, 7, 3), -3);
// supports gisxUn and m as inverse (as multiline is default.)
std::vector<RegexMatch> matches = regex_search(vase.root, "a(.)c", 0, vase.length(), "s");
print_regex(matches); // debug
// print_regex(matches); // debug
start = std::chrono::steady_clock::now();
std::vector<RegexMatch> matches = regex_search(vase.root, "here", 0, vase.length(), "");
end = std::chrono::steady_clock::now();
std::cout << "Time search: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< " ms\n";
print_shard(vase.root); // debug
// print_shard(vase.root); // debug
LineIterator it(vase.root, 0);
/*LineIterator it(vase.root, 0);
std::string line;
while (it.next(line))
std::cout << line << "\n";
std::cout << line << "\n";*/
vase.regex_search_replace("a(.)c", 0, vase.length(), "|$1|", "g");
/*start = std::chrono::steady_clock::now();
vase.regex_search_replace("here", 0, vase.length(), "hello", "");
end = std::chrono::steady_clock::now();
std::cout << "Time replace: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< " ms\n";*/
std::cout << "\n\n";
std::cout << "\n\n"
<< (int)vase.root->height << " append:" << (int)vase.append.current_offset;
ChunkIterator it2(vase.root);
std::cout << "Press Enter to continue...";
std::cin.get();
/*ChunkIterator it2(vase.root);
const char *data;
uint32_t length;
while (it2.next(&data, &length))
std::cout << std::string(data, length);
std::cout << std::string(data, length);*/
std::cout << "\n\n"
<< vase.to_string();
// std::cout << vase.to_string();
return 0;
}
+7 -41
View File
@@ -1,7 +1,7 @@
#include "vase/search.h"
#include "vase/iterators/chunk.h"
const std::vector<RegexMatch> regex_search(
std::vector<RegexMatch> regex_search(
Shard *root, std::string_view pattern_str,
uint32_t start_offset, uint32_t end_offset,
std::string_view options
@@ -51,12 +51,8 @@ const std::vector<RegexMatch> regex_search(
NULL
);
if (re == NULL) {
PCRE2_UCHAR buffer[256];
pcre2_get_error_message(errornumber, buffer, sizeof(buffer));
printf("Compilation failed at offset %d: %s\n", (int)erroroffset, buffer);
if (re == NULL)
return results;
}
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re, NULL);
@@ -77,14 +73,13 @@ const std::vector<RegexMatch> regex_search(
.start = global_offset + (uint32_t)ovector[0],
.end = global_offset + (uint32_t)ovector[1]
};
match.groups.reserve(rc - 1);
for (int i = 1; i < rc; ++i) {
for (int i = 1; i < rc && i <= 9; ++i) {
PCRE2_SIZE s = ovector[2 * i];
PCRE2_SIZE e = ovector[2 * i + 1];
if (s == PCRE2_UNSET)
match.groups.push_back({0, 0, false});
else
match.groups.push_back({global_offset + (uint32_t)s, global_offset + (uint32_t)e, true});
if (s != PCRE2_UNSET) {
match.groups[i].start = global_offset + (uint32_t)s;
match.groups[i].end = global_offset + (uint32_t)e;
}
}
results.push_back(std::move(match));
};
@@ -186,7 +181,6 @@ const std::vector<RegexMatch> regex_search(
offset = 0;
break;
} else {
printf("A matching error occurred: %d\n", rc);
break;
}
}
@@ -237,7 +231,6 @@ const std::vector<RegexMatch> regex_search(
break;
} else {
offset = length;
printf("A matching error occurred: %d\n", rc);
break;
}
}
@@ -251,30 +244,3 @@ const std::vector<RegexMatch> regex_search(
return results;
}
void print_regex(const std::vector<RegexMatch> &matches) {
std::cout << "RegexMatches (" << matches.size() << "):\n";
for (size_t i = 0; i < matches.size(); ++i) {
const auto &match = matches[i];
std::cout << " [" << i << "] {\n";
std::cout << " start: " << match.start << '\n';
std::cout << " end: " << match.end << '\n';
std::cout << " groups (" << match.groups.size() << "):\n";
for (size_t j = 0; j < match.groups.size(); ++j) {
const auto &group = match.groups[j];
std::cout << " [" << j << "] { "
<< "matched: " << (group.matched ? "true" : "false")
<< ", start: " << group.start
<< ", end: " << group.end
<< " }\n";
}
std::cout << " }\n";
}
std::cout << "\n\n";
}
+68 -70
View File
@@ -98,18 +98,20 @@ struct ReplacePart {
Constant
} type;
std::variant<uint8_t, std::string> value;
std::variant<uint8_t, Shard *> value;
};
std::vector<ReplacePart> parse_replace(std::string_view s) {
std::vector<ReplacePart> parse_replace(AppendBuffer &buf, std::string_view s) {
std::vector<ReplacePart> parts;
std::string constant;
auto flush_constant = [&]() {
if (!constant.empty()) {
uint32_t lines = 0;
uint32_t pos = buf.append(constant.data(), (uint32_t)constant.size(), &lines);
parts.push_back(
ReplacePart{
.type = ReplacePart::PartType::Constant,
.value = std::move(constant)
.value = new Petal((uint32_t)constant.size(), lines, &buf, pos)
}
);
constant.clear();
@@ -153,28 +155,16 @@ std::vector<ReplacePart> parse_replace(std::string_view s) {
return parts;
}
static Shard *extract_range(Shard *tree, uint32_t start, uint32_t end) {
if (end <= start)
return nullptr;
auto [left, rest] = split_shard(tree, start);
auto [mid, right] = split_shard(rest, end - start);
Shard *build_balanced(Shard **pieces, size_t lo, size_t hi) {
if (hi - lo == 1)
return pieces[lo];
size_t mid = lo + (hi - lo) / 2;
Shard *left = build_balanced(pieces, lo, mid);
Shard *right = build_balanced(pieces, mid, hi);
Shard *node = new Branch(left, right);
Shard::release(left);
Shard::release(rest);
Shard::release(right);
return mid;
}
static void append_piece(Shard *&accum, Shard *piece) {
if (!piece)
return;
if (!accum) {
accum = piece;
return;
}
Shard *combined = concat_shard(accum, piece);
Shard::release(accum);
Shard::release(piece);
accum = combined;
return node;
}
void Vase::regex_search_replace(
@@ -182,73 +172,81 @@ void Vase::regex_search_replace(
uint32_t start_offset, uint32_t end_offset,
std::string_view replace, std::string_view options
) {
const std::vector<RegexMatch> matches = regex_search(root, pattern, start_offset, end_offset, options);
std::vector<RegexMatch> matches = regex_search(root, pattern, start_offset, end_offset, options);
if (matches.empty())
return;
std::vector<ReplacePart> replace_parts = parse_replace(replace);
std::vector<ReplacePart> replace_parts = parse_replace(append, replace);
struct ConstantRef {
uint32_t pos = 0;
uint32_t lines = 0;
};
std::vector<ConstantRef> constants(replace_parts.size());
for (size_t i = 0; i < replace_parts.size(); ++i) {
if (replace_parts[i].type != ReplacePart::PartType::Constant)
continue;
const std::string &text = std::get<std::string>(replace_parts[i].value);
uint32_t lines = 0;
uint32_t pos = append.append(text.data(), (uint32_t)text.size(), &lines);
constants[i] = {pos, lines};
}
std::vector<Shard *> pieces;
pieces.reserve(matches.size() * 2 + 1);
for (auto it = matches.rbegin(); it != matches.rend(); ++it) {
const RegexMatch &match = *it;
Shard *remaining = root;
Shard::retain(remaining);
uint32_t cursor = 0;
for (const RegexMatch &match : matches) {
uint32_t gap = match.start - cursor;
if (gap > 0) {
auto [keep, rest] = split_shard(remaining, gap);
Shard::release(remaining);
pieces.push_back(keep);
remaining = rest;
}
auto [dropped, rest2] = split_shard(remaining, match.end - match.start);
Shard::release(remaining);
remaining = rest2;
Shard *replacement = nullptr;
for (size_t i = 0; i < replace_parts.size(); ++i) {
const ReplacePart &part = replace_parts[i];
switch (part.type) {
case ReplacePart::PartType::Constant: {
const std::string &text = std::get<std::string>(part.value);
const ConstantRef &ref = constants[i];
Shard *piece = new Petal((uint32_t)text.size(), ref.lines, &append, ref.pos);
append_piece(replacement, piece);
case ReplacePart::PartType::Constant:
Shard::retain(std::get<Shard *>(part.value));
pieces.push_back(std::get<Shard *>(part.value));
break;
}
case ReplacePart::PartType::FullMatch:
append_piece(replacement, extract_range(root, match.start, match.end));
Shard::retain(dropped);
pieces.push_back(dropped);
break;
case ReplacePart::PartType::CaptureGroup: {
uint8_t idx = std::get<uint8_t>(part.value);
if (idx <= match.groups.size()) {
if (idx <= 9) {
const RegexGroup &group = match.groups[idx - 1];
if (group.matched)
append_piece(replacement, extract_range(root, group.start, group.end));
if (group.start != UINT32_MAX) {
uint32_t ls = group.start - match.start;
uint32_t le = group.end - match.start;
auto [a, b] = split_shard(dropped, ls);
auto [g, c] = split_shard(b, le - ls);
Shard::release(a);
Shard::release(b);
Shard::release(c);
pieces.push_back(g);
}
}
break;
}
}
}
auto [left, rest] = split_shard(root, match.start);
auto [dropped, right] = split_shard(rest, match.end - match.start);
Shard::release(dropped);
Shard::release(rest);
Shard *new_root;
if (replacement) {
Shard *left2 = concat_shard(left, replacement);
Shard::release(left);
Shard::release(replacement);
new_root = concat_shard(left2, right);
Shard::release(left2);
} else {
new_root = concat_shard(left, right);
Shard::release(left);
}
Shard::release(right);
Shard::release(root);
root = new_root;
cursor = match.end;
}
pieces.push_back(remaining);
for (auto &part : replace_parts)
if (part.type == ReplacePart::PartType::Constant)
Shard::release(std::get<Shard *>(part.value));
std::vector<Shard *> compact;
compact.reserve(pieces.size());
for (Shard *p : pieces) {
if (p && p->length > 0)
compact.push_back(p);
else if (p)
Shard::release(p);
}
Shard *new_root = compact.empty() ? nullptr : build_balanced(compact.data(), 0, compact.size());
Shard::release(root);
root = new_root;
}