Commit b976b465 by Maarten L. Hekkelman

Optimised erase III

parent eba04950
...@@ -57,6 +57,8 @@ namespace detail ...@@ -57,6 +57,8 @@ namespace detail
virtual bool test(row_handle) const = 0; virtual bool test(row_handle) const = 0;
virtual void str(std::ostream &) const = 0; virtual void str(std::ostream &) const = 0;
virtual std::optional<row_handle> single() const { return {}; }; virtual std::optional<row_handle> single() const { return {}; };
virtual bool equals(const condition_impl *rhs) const { return false; }
}; };
struct all_condition_impl : public condition_impl struct all_condition_impl : public condition_impl
...@@ -208,6 +210,19 @@ namespace detail ...@@ -208,6 +210,19 @@ namespace detail
return m_single_hit; return m_single_hit;
} }
virtual bool equals(const condition_impl *rhs) const override
{
if (typeid(*rhs) == typeid(key_equals_condition_impl))
{
auto ri = static_cast<const key_equals_condition_impl *>(rhs);
if (m_single_hit.has_value() or ri->m_single_hit.has_value())
return m_single_hit == ri->m_single_hit;
else
return m_item_ix == ri->m_item_ix and m_value == ri->m_value;
}
return this == rhs;
}
std::string m_item_tag; std::string m_item_tag;
uint16_t m_item_ix = 0; uint16_t m_item_ix = 0;
bool m_icase = false; bool m_icase = false;
...@@ -244,7 +259,7 @@ namespace detail ...@@ -244,7 +259,7 @@ namespace detail
void str(std::ostream &os) const override void str(std::ostream &os) const override
{ {
os << m_item_tag << (m_icase ? "^ " : " ") << " == " << m_value << " OR " << m_item_tag << " IS NULL"; os << '(' << m_item_tag << (m_icase ? "^ " : " ") << " == " << m_value << " OR " << m_item_tag << " IS NULL)";
} }
virtual std::optional<row_handle> single() const override virtual std::optional<row_handle> single() const override
...@@ -252,6 +267,19 @@ namespace detail ...@@ -252,6 +267,19 @@ namespace detail
return m_single_hit; return m_single_hit;
} }
virtual bool equals(const condition_impl *rhs) const override
{
if (typeid(*rhs) == typeid(key_equals_or_empty_condition_impl))
{
auto ri = static_cast<const key_equals_or_empty_condition_impl *>(rhs);
if (m_single_hit.has_value() or ri->m_single_hit.has_value())
return m_single_hit == ri->m_single_hit;
else
return m_item_ix == ri->m_item_ix and m_value == ri->m_value;
}
return this == rhs;
}
std::string m_item_tag; std::string m_item_tag;
uint16_t m_item_ix = 0; uint16_t m_item_ix = 0;
std::string m_value; std::string m_value;
...@@ -409,11 +437,30 @@ namespace detail ...@@ -409,11 +437,30 @@ namespace detail
// case they make up an indexed tuple. // case they make up an indexed tuple.
struct and_condition_impl : public condition_impl struct and_condition_impl : public condition_impl
{ {
and_condition_impl() = default;
and_condition_impl(condition &&a, condition &&b) and_condition_impl(condition &&a, condition &&b)
{ {
if (typeid(*a.m_impl) == typeid(*this))
{
and_condition_impl *ai = static_cast<and_condition_impl *>(a.m_impl);
std::swap(m_sub, ai->m_sub);
m_sub.emplace_back(std::exchange(b.m_impl, nullptr));
}
else if (typeid(*b.m_impl) == typeid(*this))
{
and_condition_impl *bi = static_cast<and_condition_impl *>(b.m_impl);
std::swap(m_sub, bi->m_sub);
m_sub.emplace_back(std::exchange(a.m_impl, nullptr));
}
else
{
m_sub.emplace_back(std::exchange(a.m_impl, nullptr)); m_sub.emplace_back(std::exchange(a.m_impl, nullptr));
m_sub.emplace_back(std::exchange(b.m_impl, nullptr)); m_sub.emplace_back(std::exchange(b.m_impl, nullptr));
} }
}
~and_condition_impl() ~and_condition_impl()
{ {
...@@ -421,7 +468,12 @@ namespace detail ...@@ -421,7 +468,12 @@ namespace detail
delete sub; delete sub;
} }
condition_impl *prepare(const category &c) override; condition_impl *prepare(const category &c) override
{
for (auto &sub : m_sub)
sub = sub->prepare(c);
return this;
}
bool test(row_handle r) const override bool test(row_handle r) const override
{ {
...@@ -481,6 +533,8 @@ namespace detail ...@@ -481,6 +533,8 @@ namespace detail
return result; return result;
} }
static condition_impl *combine_equal(std::vector<and_condition_impl *> &subs, or_condition_impl *oc);
std::vector<condition_impl *> m_sub; std::vector<condition_impl *> m_sub;
}; };
...@@ -535,16 +589,17 @@ namespace detail ...@@ -535,16 +589,17 @@ namespace detail
void str(std::ostream &os) const override void str(std::ostream &os) const override
{ {
bool first = true; bool first = true;
os << '(';
for (auto sub : m_sub) for (auto sub : m_sub)
{ {
if (first) if (first)
first = false; first = false;
else else
os << " OR "; os << " OR ";
os << '(';
sub->str(os); sub->str(os);
os << ')';
} }
os << ')';
} }
virtual std::optional<row_handle> single() const override virtual std::optional<row_handle> single() const override
...@@ -610,7 +665,7 @@ namespace detail ...@@ -610,7 +665,7 @@ namespace detail
} // namespace detail } // namespace detail
inline condition operator&&(condition &&a, condition &&b) inline condition operator and(condition &&a, condition &&b)
{ {
if (a.m_impl and b.m_impl) if (a.m_impl and b.m_impl)
return condition(new detail::and_condition_impl(std::move(a), std::move(b))); return condition(new detail::and_condition_impl(std::move(a), std::move(b)));
...@@ -619,12 +674,32 @@ inline condition operator&&(condition &&a, condition &&b) ...@@ -619,12 +674,32 @@ inline condition operator&&(condition &&a, condition &&b)
return condition(std::move(b)); return condition(std::move(b));
} }
inline condition operator||(condition &&a, condition &&b) inline condition operator or(condition &&a, condition &&b)
{ {
if (a.m_impl and b.m_impl) if (a.m_impl and b.m_impl)
{
if (typeid(*a.m_impl) == typeid(detail::key_equals_condition_impl) and
typeid(*b.m_impl) == typeid(detail::key_is_empty_condition_impl))
{
detail::key_equals_condition_impl *ci = static_cast<detail::key_equals_condition_impl *>(std::exchange(a.m_impl, nullptr));
delete std::exchange(b.m_impl, nullptr);
return condition(new detail::key_equals_or_empty_condition_impl(ci));
}
if (typeid(*b.m_impl) == typeid(detail::key_equals_condition_impl) and
typeid(*a.m_impl) == typeid(detail::key_is_empty_condition_impl))
{
detail::key_equals_condition_impl *ci = static_cast<detail::key_equals_condition_impl *>(std::exchange(b.m_impl, nullptr));
delete std::exchange(a.m_impl, nullptr);
return condition(new detail::key_equals_or_empty_condition_impl(ci));
}
return condition(new detail::or_condition_impl(std::move(a), std::move(b))); return condition(new detail::or_condition_impl(std::move(a), std::move(b)));
}
if (a.m_impl) if (a.m_impl)
return condition(std::move(a)); return condition(std::move(a));
return condition(std::move(b)); return condition(std::move(b));
} }
...@@ -747,7 +822,7 @@ inline condition operator==(const key &key, const empty_type &) ...@@ -747,7 +822,7 @@ inline condition operator==(const key &key, const empty_type &)
return condition(new detail::key_is_empty_condition_impl(key.m_item_tag)); return condition(new detail::key_is_empty_condition_impl(key.m_item_tag));
} }
inline condition operator !(condition &&rhs) inline condition operator not(condition &&rhs)
{ {
return condition(new detail::not_condition_impl(std::move(rhs))); return condition(new detail::not_condition_impl(std::move(rhs)));
} }
......
...@@ -1236,7 +1236,12 @@ size_t category::erase(condition &&cond, std::function<void(row_handle)> &&visit ...@@ -1236,7 +1236,12 @@ size_t category::erase(condition &&cond, std::function<void(row_handle)> &&visit
visit(*ri); visit(*ri);
for (auto &&[childCat, link] : m_child_links) for (auto &&[childCat, link] : m_child_links)
potential_orphans[childCat] = std::move(potential_orphans[childCat]) or get_children_condition(*ri, *childCat); {
auto cond = get_children_condition(*ri, *childCat);
if (not cond)
continue;
potential_orphans[childCat] = std::move(potential_orphans[childCat]) or std::move(cond);
}
save_value sv(m_validator); save_value sv(m_validator);
......
...@@ -76,59 +76,82 @@ namespace detail ...@@ -76,59 +76,82 @@ namespace detail
return this; return this;
} }
condition_impl *and_condition_impl::prepare(const category &c) bool found_in_range(condition_impl *c, std::vector<and_condition_impl *>::iterator b, std::vector<and_condition_impl *>::iterator e)
{ {
for (auto &sub : m_sub) bool result = true;
sub = sub->prepare(c);
for (;;) for (auto s = b; s != e; ++s)
{ {
auto si = find_if(m_sub.begin(), m_sub.end(), [](condition_impl *sub) { return dynamic_cast<and_condition_impl *>(sub) != nullptr; }); auto &cs = (*s)->m_sub;
if (si == m_sub.end())
break;
and_condition_impl *sub_and = static_cast<and_condition_impl *>(*si);
m_sub.erase(si); if (find_if(cs.begin(), cs.end(), [c](const condition_impl *i) { return i->equals(c); }) == cs.end())
{
m_sub.insert(m_sub.end(), sub_and->m_sub.begin(), sub_and->m_sub.end()); result = false;
sub_and->m_sub.clear(); break;
delete sub_and; }
} }
return this; return result;
} }
condition_impl *or_condition_impl::prepare(const category &c) condition_impl *and_condition_impl::combine_equal(std::vector<and_condition_impl *> &subs, or_condition_impl *oc)
{ {
condition_impl *result = this; and_condition_impl *and_result = nullptr;
for (auto &sub : m_sub) auto first = subs.front();
sub = sub->prepare(c); auto &fc = first->m_sub;
if (m_sub.size() == 2) for (auto c : fc)
{ {
auto a = m_sub.front(); if (not found_in_range(c, subs.begin() + 1, subs.end()))
auto b = m_sub.back(); continue;
if (and_result == nullptr)
and_result = new and_condition_impl();
key_equals_condition_impl *equals = dynamic_cast<key_equals_condition_impl*>(a); and_result->m_sub.push_back(c);
key_is_empty_condition_impl *empty = dynamic_cast<key_is_empty_condition_impl*>(b); fc.erase(remove(fc.begin(), fc.end(), c), fc.end());
for (auto sub : subs)
{
auto &ssub = sub->m_sub;
if (equals == nullptr and empty == nullptr) for (auto sc : ssub)
{ {
equals = dynamic_cast<key_equals_condition_impl*>(b); if (not sc->equals(c))
empty = dynamic_cast<key_is_empty_condition_impl*>(a); continue;
ssub.erase(remove(ssub.begin(), ssub.end(), sc), ssub.end());
delete sc;
break;
}
}
} }
if (equals != nullptr and empty != nullptr and equals->m_item_tag == empty->m_item_tag) if (and_result != nullptr)
{ {
result = new detail::key_equals_or_empty_condition_impl(equals); and_result->m_sub.push_back(oc);
result = result->prepare(c); return and_result;
delete this;
} }
return oc;
} }
return result; condition_impl *or_condition_impl::prepare(const category &c)
{
std::vector<and_condition_impl *> and_conditions;
for (auto &sub : m_sub)
{
sub = sub->prepare(c);
if (typeid(*sub) == typeid(and_condition_impl))
and_conditions.push_back(static_cast<and_condition_impl *>(sub));
}
if (and_conditions.size() == m_sub.size())
return and_condition_impl::combine_equal(and_conditions, this);
return this;
} }
} // namespace detail } // namespace detail
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment