include/HashedSetAbstractDomain.h (121 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 <cstddef> #include <initializer_list> #include <unordered_set> #include "PowersetAbstractDomain.h" namespace sparta { // Forward declaration. template <typename Element, typename Hash, typename Equal> class HashedSetAbstractDomain; namespace hsad_impl { /* * An abstract value from a powerset is implemented as a hash table. */ template <typename Element, typename Hash, typename Equal> class SetValue final : public PowersetImplementation< Element, const std::unordered_set<Element, Hash, Equal>&, SetValue<Element, Hash, Equal>> { public: SetValue() = default; SetValue(const Element& e) { m_set.insert(e); } SetValue(std::initializer_list<Element> l) : m_set(l.begin(), l.end()) {} const std::unordered_set<Element, Hash, Equal>& elements() const override { return m_set; } size_t size() const override { return m_set.size(); } bool contains(const Element& e) const override { return m_set.count(e) > 0; } void add(const Element& e) override { m_set.insert(e); } void remove(const Element& e) override { m_set.erase(e); } void clear() override { m_set.clear(); } AbstractValueKind kind() const override { return AbstractValueKind::Value; } bool leq(const SetValue& other) const override { if (m_set.size() > other.m_set.size()) { return false; } for (const Element& e : m_set) { if (other.m_set.count(e) == 0) { return false; } } return true; } bool equals(const SetValue& other) const override { return (m_set.size() == other.m_set.size()) && leq(other); } AbstractValueKind join_with(const SetValue& other) override { for (const Element& e : other.m_set) { m_set.insert(e); } return AbstractValueKind::Value; } AbstractValueKind meet_with(const SetValue& other) override { for (auto it = m_set.begin(); it != m_set.end();) { if (other.m_set.count(*it) == 0) { it = m_set.erase(it); } else { ++it; } } return AbstractValueKind::Value; } AbstractValueKind difference_with(const SetValue& other) override { for (auto it = m_set.begin(); it != m_set.end();) { if (other.m_set.count(*it) != 0) { it = m_set.erase(it); } else { ++it; } } return AbstractValueKind::Value; } friend std::ostream& operator<<(std::ostream& o, const SetValue& value) { o << "[#" << value.size() << "]"; const auto& elements = value.elements(); o << "{"; for (auto it = elements.begin(); it != elements.end();) { o << *it++; if (it != elements.end()) { o << ", "; } } o << "}"; return o; } private: std::unordered_set<Element, Hash, Equal> m_set; template <typename T1, typename T2, typename T3> friend class sparta::HashedSetAbstractDomain; }; } // namespace hsad_impl /* * An implementation of powerset abstract domains using hash tables. */ template <typename Element, typename Hash = std::hash<Element>, typename Equal = std::equal_to<Element>> class HashedSetAbstractDomain final : public PowersetAbstractDomain< Element, hsad_impl::SetValue<Element, Hash, Equal>, const std::unordered_set<Element, Hash, Equal>&, HashedSetAbstractDomain<Element, Hash, Equal>> { public: using Value = hsad_impl::SetValue<Element, Hash, Equal>; HashedSetAbstractDomain() : PowersetAbstractDomain<Element, Value, const std::unordered_set<Element, Hash, Equal>&, HashedSetAbstractDomain>() {} HashedSetAbstractDomain(AbstractValueKind kind) : PowersetAbstractDomain<Element, Value, const std::unordered_set<Element, Hash, Equal>&, HashedSetAbstractDomain>(kind) {} explicit HashedSetAbstractDomain(const Element& e) { this->set_to_value(Value(e)); } explicit HashedSetAbstractDomain(std::initializer_list<Element> l) { this->set_to_value(Value(l)); } static HashedSetAbstractDomain bottom() { return HashedSetAbstractDomain(AbstractValueKind::Bottom); } static HashedSetAbstractDomain top() { return HashedSetAbstractDomain(AbstractValueKind::Top); } }; } // namespace sparta