1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-29 14:05:11 +00:00

LibRegex: Use a copy-on-write vector for fork state

This commit is contained in:
Ali Mohammad Pur 2022-11-03 02:36:25 +03:30 committed by Ali Mohammad Pur
parent 48a4c9c1ad
commit f1851346d3
3 changed files with 140 additions and 8 deletions

View file

@ -1060,9 +1060,11 @@ ALWAYS_INLINE ExecutionResult OpCode_Checkpoint::execute(MatchInput const& input
ALWAYS_INLINE ExecutionResult OpCode_JumpNonEmpty::execute(MatchInput const& input, MatchState& state) const
{
auto current_position = state.string_position;
u64 current_position = state.string_position;
auto checkpoint_ip = state.instruction_position + size() + checkpoint();
if (input.checkpoints.get(checkpoint_ip).value_or(current_position) != current_position) {
auto checkpoint_position = input.checkpoints.find(checkpoint_ip);
if (checkpoint_position != input.checkpoints.end() && checkpoint_position->value != current_position) {
auto form = this->form();
if (form == OpCodeId::Jump) {

View file

@ -12,6 +12,7 @@
#include <AK/FlyString.h>
#include <AK/HashMap.h>
#include <AK/MemMem.h>
#include <AK/RedBlackTree.h>
#include <AK/String.h>
#include <AK/StringBuilder.h>
#include <AK/StringView.h>
@ -23,6 +24,135 @@
namespace regex {
template<typename T>
class COWVector {
struct Detail : RefCounted<Detail> {
Vector<T> m_members;
};
public:
COWVector()
: m_detail(make_ref_counted<Detail>())
{
}
COWVector(COWVector const&) = default;
COWVector(COWVector&&) = default;
COWVector& operator=(COWVector const&) = default;
COWVector& operator=(COWVector&&) = default;
Vector<T> release() &&
{
if (m_detail->ref_count() == 1)
return exchange(m_detail->m_members, Vector<T>());
return m_detail->m_members;
}
void append(T const& value)
{
return append(T { value });
}
void append(T&& value)
{
copy();
m_detail->m_members.append(move(value));
}
void resize(size_t size)
{
copy();
m_detail->m_members.resize(size);
}
void ensure_capacity(size_t capacity)
{
if (m_detail->m_members.capacity() >= capacity)
return;
copy();
m_detail->m_members.ensure_capacity(capacity);
}
template<typename... Args>
void empend(Args&&... args)
{
copy();
m_detail->m_members.empend(forward<Args>(args)...);
}
void clear()
{
if (m_detail->ref_count() > 1)
m_detail = make_ref_counted<Detail>();
else
m_detail->m_members.clear();
}
T& at(size_t index)
{
// We're handing out a mutable reference, so make sure we own the data exclusively.
copy();
return m_detail->m_members.at(index);
}
T const& at(size_t index) const
{
return m_detail->m_members.at(index);
}
T& operator[](size_t index)
{
// We're handing out a mutable reference, so make sure we own the data exclusively.
copy();
return m_detail->m_members[index];
}
T const& operator[](size_t index) const
{
return m_detail->m_members[index];
}
size_t capacity() const
{
return m_detail->m_members.capacity();
}
size_t size() const
{
return m_detail->m_members.size();
}
bool is_empty() const
{
return m_detail->m_members.is_empty();
}
T const& first() const
{
return m_detail->m_members.first();
}
T const& last() const
{
return m_detail->m_members.last();
}
private:
void copy()
{
if (m_detail->ref_count() <= 1)
return;
auto new_detail = make_ref_counted<Detail>();
new_detail->m_members = m_detail->m_members;
m_detail = new_detail;
}
NonnullRefPtr<Detail> m_detail;
};
class RegexStringView {
public:
RegexStringView() = default;
@ -510,9 +640,9 @@ struct MatchState {
size_t fork_at_position { 0 };
size_t forks_since_last_save { 0 };
Optional<size_t> initiating_fork;
Vector<Match> matches;
Vector<Vector<Match>> capture_group_matches;
Vector<u64> repetition_marks;
COWVector<Match> matches;
COWVector<Vector<Match>> capture_group_matches;
COWVector<u64> repetition_marks;
};
}

View file

@ -156,7 +156,7 @@ RegexResult Matcher<Parser>::match(Vector<RegexStringView> const& views, Optiona
for (size_t j = 0; j < c_match_preallocation_count; ++j) {
state.matches.empend();
state.capture_group_matches.unchecked_append({});
state.capture_group_matches.empend();
state.capture_group_matches.at(j).ensure_capacity(capture_groups_count);
for (size_t k = 0; k < capture_groups_count; ++k)
state.capture_group_matches.at(j).unchecked_append({});
@ -306,8 +306,8 @@ RegexResult Matcher<Parser>::match(Vector<RegexStringView> const& views, Optiona
RegexResult result {
match_count != 0,
match_count,
move(state.matches),
move(state.capture_group_matches),
move(state.matches).release(),
move(state.capture_group_matches).release(),
operations,
m_pattern->parser_result.capture_groups_count,
m_pattern->parser_result.named_capture_groups_count,