include/SmallSortedSetAbstractDomain.h (142 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include <initializer_list> #include "AbstractDomain.h" #include "Exceptions.h" #include "FlatSet.h" namespace sparta { namespace sssad_impl { template <typename Element, std::size_t MaxCount> class SetValue final : public AbstractValue<SetValue<Element, MaxCount>> { public: SetValue() = default; SetValue(FlatSet<Element> set) : m_set(std::move(set)) {} void clear() override { m_set.clear(); } AbstractValueKind kind() const override { if (m_set.size() > MaxCount) { return AbstractValueKind::Top; } else { return AbstractValueKind::Value; } } bool empty() const { return m_set.empty(); } std::size_t size() const { return m_set.size(); } const FlatSet<Element>& elements() const { return m_set; } void add(const Element& e) { m_set.insert(e); } void remove(const Element& e) { m_set.remove(e); } bool contains(const Element& e) const { return m_set.contains(e); } bool leq(const SetValue& other) const override { return m_set.is_subset_of(other.m_set); } bool equals(const SetValue& other) const override { return m_set.equals(other.m_set); } AbstractValueKind join_with(const SetValue& other) override { m_set.union_with(other.m_set); return kind(); } AbstractValueKind widen_with(const SetValue& other) override { return join_with(other); } AbstractValueKind meet_with(const SetValue& other) override { m_set.intersection_with(other.m_set); return kind(); } AbstractValueKind narrow_with(const SetValue& other) override { return meet_with(other); } friend std::ostream& operator<<(std::ostream& out, const SetValue& value) { out << value.m_set; return out; } private: FlatSet<Element> m_set; }; } // namespace sssad_impl /** * An implementation of powerset abstract domains with a maximum number of * elements based on a sorted vector. This implementation is optimized for small * sets, e.g `MaxCount <= 20`. When a set goes beyond `MaxCount` elements, it is * collapsed to top. */ template <typename Element, std::size_t MaxCount> class SmallSortedSetAbstractDomain final : public AbstractDomainScaffolding< sssad_impl::SetValue<Element, MaxCount>, SmallSortedSetAbstractDomain<Element, MaxCount>> { public: using Value = sssad_impl::SetValue<Element, MaxCount>; /* Return the empty set. */ SmallSortedSetAbstractDomain() { this->set_to_value(Value()); } explicit SmallSortedSetAbstractDomain(AbstractValueKind kind) : AbstractDomainScaffolding< sssad_impl::SetValue<Element, MaxCount>, SmallSortedSetAbstractDomain<Element, MaxCount>>(kind) {} explicit SmallSortedSetAbstractDomain(const Element& e) { this->set_to_value(Value(FlatSet<Element>{e})); } explicit SmallSortedSetAbstractDomain(std::initializer_list<Element> l) { this->set_to_value(Value(FlatSet<Element>(l))); } explicit SmallSortedSetAbstractDomain(FlatSet<Element> set) { this->set_to_value(Value(std::move(set))); } static SmallSortedSetAbstractDomain bottom() { return SmallSortedSetAbstractDomain(AbstractValueKind::Bottom); } static SmallSortedSetAbstractDomain top() { return SmallSortedSetAbstractDomain(AbstractValueKind::Top); } bool empty() const { return this->is_value() && this->get_value()->empty(); } const FlatSet<Element>& elements() const { RUNTIME_CHECK(this->kind() == AbstractValueKind::Value, invalid_abstract_value() << expected_kind(AbstractValueKind::Value) << actual_kind(this->kind())); return this->get_value()->elements(); } std::size_t size() const { RUNTIME_CHECK(this->kind() == AbstractValueKind::Value, invalid_abstract_value() << expected_kind(AbstractValueKind::Value) << actual_kind(this->kind())); return this->get_value()->size(); } void add(const Element& e) { if (this->kind() == AbstractValueKind::Value) { this->get_value()->add(e); this->normalize(); } } void remove(const Element& e) { if (this->kind() == AbstractValueKind::Value) { this->get_value()->remove(e); this->normalize(); } } bool contains(const Element& e) const { switch (this->kind()) { case AbstractValueKind::Bottom: { return false; } case AbstractValueKind::Top: { return true; } case AbstractValueKind::Value: { return this->get_value()->contains(e); } } } friend std::ostream& operator<<(std::ostream& out, const SmallSortedSetAbstractDomain& x) { using namespace sparta; switch (x.kind()) { case AbstractValueKind::Bottom: { out << "_|_"; break; } case AbstractValueKind::Top: { out << "T"; break; } case AbstractValueKind::Value: { out << *x.get_value(); break; } } return out; } }; } // namespace sparta