Fix broken corner cases in DualThreadStack::grow_ifn

We only grow when the ring buffer is full, which allows for a nice
simplification of the code.

Tell grow_ifn if we pushed in current or next so that we can
distinguish between filled by next or filled by current when
m_current == m_next_begin
This commit is contained in:
Maxime Coste 2023-02-14 17:13:31 +11:00
parent d708b77186
commit 85ceef29bd
2 changed files with 33 additions and 20 deletions

View File

@ -1578,6 +1578,11 @@ auto test_regex = UnitTest{[]{
kak_assert(vm.exec({str, str + sizeof(str)-1})); kak_assert(vm.exec({str, str + sizeof(str)-1}));
} }
{
TestVM<RegexMode::Forward | RegexMode::Search> vm{".{40}"};
kak_assert(vm.exec("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", RegexExecFlags::None));
}
{ {
auto eq = [](const CompiledRegex::NamedCapture& lhs, auto eq = [](const CompiledRegex::NamedCapture& lhs,
const CompiledRegex::NamedCapture& rhs) { const CompiledRegex::NamedCapture& rhs) {

View File

@ -492,6 +492,7 @@ private:
if (start_desc and m_threads.next_is_empty()) if (start_desc and m_threads.next_is_empty())
to_next_start(pos, config, *start_desc); to_next_start(pos, config, *start_desc);
m_threads.push_next({first_inst, -1}); m_threads.push_next({first_inst, -1});
m_threads.grow_ifn(false);
} }
m_threads.swap_next(); m_threads.swap_next();
} }
@ -609,10 +610,10 @@ private:
bool current_is_empty() const { return m_current == m_next_begin; } bool current_is_empty() const { return m_current == m_next_begin; }
bool next_is_empty() const { return m_next_end == m_next_begin; } bool next_is_empty() const { return m_next_end == m_next_begin; }
void push_current(Thread thread) { m_data[decrement(m_current)] = thread; grow_ifn(); } void push_current(Thread thread) { m_data[decrement(m_current)] = thread; grow_ifn(true); }
Thread pop_current() { auto res = m_data[m_current]; increment(m_current); return res; } Thread pop_current() { return m_data[post_increment(m_current)]; }
void push_next(Thread thread) { m_data[m_next_end] = thread; increment(m_next_end); } void push_next(Thread thread) { m_data[post_increment(m_next_end)] = thread; }
Thread pop_next() { return m_data[decrement(m_next_end)]; } Thread pop_next() { return m_data[decrement(m_next_end)]; }
void swap_next() void swap_next()
@ -621,27 +622,31 @@ private:
m_next_begin = m_next_end; m_next_begin = m_next_end;
} }
void ensure_initial_capacity() { void ensure_initial_capacity()
if (m_capacity == 0)
grow_ifn();
}
void grow_ifn()
{ {
if (m_current != m_next_end) if (m_capacity != 0)
return; return;
constexpr int32_t initial_capacity = 64 / sizeof(Thread); constexpr int32_t initial_capacity = 64 / sizeof(Thread);
static_assert(initial_capacity >= 4); static_assert(initial_capacity >= 4);
m_data.reset(new Thread[initial_capacity]);
m_capacity = initial_capacity;
const auto new_capacity = m_capacity ? m_capacity * 2 : initial_capacity; }
void grow_ifn(bool pushed_current)
{
if (m_current != m_next_end)
return;
const auto new_capacity = m_capacity * 2;
Thread* new_data = new Thread[new_capacity]; Thread* new_data = new Thread[new_capacity];
if (m_current < m_next_end) Thread* old_data = m_data.get();
m_next_end = std::copy(m_data.get() + m_current, m_data.get() + m_next_end, new_data) - new_data; std::rotate_copy(old_data, old_data + m_current, old_data + m_capacity, new_data);
else m_next_begin -= m_current;
m_next_end = std::copy(m_data.get(), m_data.get() + m_next_end, std::copy(m_data.get() + m_current, m_data.get() + m_capacity, new_data)) - new_data; if ((pushed_current and m_next_begin == 0) or m_next_begin < 0)
m_next_begin += m_capacity;
m_next_begin = m_next_begin >= m_current ? m_next_begin - m_current : m_capacity - (m_current - m_next_begin); m_next_end = m_capacity;
m_current = 0; m_current = 0;
m_data.reset(new_data); m_data.reset(new_data);
@ -649,16 +654,19 @@ private:
} }
private: private:
int32_t decrement(int32_t& index) { int32_t decrement(int32_t& index)
{
if (index == 0) if (index == 0)
index = m_capacity; index = m_capacity;
return --index; return --index;
} }
int32_t increment(int32_t& index) { int32_t post_increment(int32_t& index)
{
auto res = index;
if (++index == m_capacity) if (++index == m_capacity)
index = 0; index = 0;
return index; return res;
} }
std::unique_ptr<Thread[]> m_data; std::unique_ptr<Thread[]> m_data;