-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement a generic set abstract domain on top of a given set
Summary: This implements a similar design as D50054646 but for sets. Users can provide set implementations by implementing `AbstractSet`. Then, a new class `SetAbstractDomain` can turn it into a powerset with a top and bottom element. For now, this is only used to implement `PatriciaTreeSetAbstractDomain`, but we will use it for hash set and sparse set in a follow-up. Reviewed By: arnaudvenet Differential Revision: D50054946 fbshipit-source-id: 756a5b5a3b66b7525e8e06b6d5b0046daab8d07a
- Loading branch information
1 parent
028d60b
commit afa37f8
Showing
2 changed files
with
146 additions
and
120 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
/* | ||
* 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 <sparta/AbstractSet.h> | ||
#include <sparta/PowersetAbstractDomain.h> | ||
|
||
namespace sparta { | ||
|
||
namespace set_impl { | ||
|
||
template <typename Set> | ||
class SetValue; | ||
|
||
} // namespace set_impl | ||
|
||
/* | ||
* An implementation of powerset abstract domains based on the given set. | ||
*/ | ||
template <typename Set> | ||
class SetAbstractDomain final | ||
: public PowersetAbstractDomain<typename Set::value_type, | ||
set_impl::SetValue<Set>, | ||
const Set&, | ||
SetAbstractDomain<Set>> { | ||
public: | ||
using Value = set_impl::SetValue<Set>; | ||
using Element = typename Set::value_type; | ||
|
||
~SetAbstractDomain() { | ||
static_assert(std::is_base_of<AbstractSet<Set>, Set>::value, | ||
"Set doesn't inherit from AbstractSet"); | ||
} | ||
|
||
SetAbstractDomain() | ||
: PowersetAbstractDomain<Element, | ||
Value, | ||
const Set&, | ||
SetAbstractDomain>() {} | ||
|
||
explicit SetAbstractDomain(AbstractValueKind kind) | ||
: PowersetAbstractDomain<Element, Value, const Set&, SetAbstractDomain>( | ||
kind) {} | ||
|
||
explicit SetAbstractDomain(Element e) { | ||
this->set_to_value(Value(std::move(e))); | ||
} | ||
|
||
explicit SetAbstractDomain(std::initializer_list<Element> l) { | ||
this->set_to_value(Value(l)); | ||
} | ||
|
||
explicit SetAbstractDomain(Set set) { | ||
this->set_to_value(Value(std::move(set))); | ||
} | ||
|
||
static SetAbstractDomain bottom() { | ||
return SetAbstractDomain(AbstractValueKind::Bottom); | ||
} | ||
|
||
static SetAbstractDomain top() { | ||
return SetAbstractDomain(AbstractValueKind::Top); | ||
} | ||
}; | ||
|
||
namespace set_impl { | ||
|
||
template <typename Set> | ||
class SetValue final : public PowersetImplementation<typename Set::value_type, | ||
const Set&, | ||
SetValue<Set>> { | ||
public: | ||
using Element = typename Set::value_type; | ||
|
||
SetValue() = default; | ||
|
||
explicit SetValue(Element e) : m_set(std::move(e)) {} | ||
|
||
explicit SetValue(std::initializer_list<Element> l) | ||
: m_set(l.begin(), l.end()) {} | ||
|
||
explicit SetValue(Set set) : m_set(std::move(set)) {} | ||
|
||
const Set& elements() const { return m_set; } | ||
|
||
size_t size() const { return m_set.size(); } | ||
|
||
bool contains(const Element& e) const { return m_set.contains(e); } | ||
|
||
void add(const Element& e) { m_set.insert(e); } | ||
|
||
void add(Element&& e) { m_set.insert(std::move(e)); } | ||
|
||
void remove(const Element& e) { m_set.remove(e); } | ||
|
||
void clear() { m_set.clear(); } | ||
|
||
AbstractValueKind kind() const { return AbstractValueKind::Value; } | ||
|
||
bool leq(const SetValue& other) const { | ||
return m_set.is_subset_of(other.m_set); | ||
} | ||
|
||
bool equals(const SetValue& other) const { return m_set.equals(other.m_set); } | ||
|
||
AbstractValueKind join_with(const SetValue& other) { | ||
m_set.union_with(other.m_set); | ||
return AbstractValueKind::Value; | ||
} | ||
|
||
AbstractValueKind meet_with(const SetValue& other) { | ||
m_set.intersection_with(other.m_set); | ||
return AbstractValueKind::Value; | ||
} | ||
|
||
AbstractValueKind difference_with(const SetValue& other) { | ||
m_set.difference_with(other.m_set); | ||
return AbstractValueKind::Value; | ||
} | ||
|
||
friend std::ostream& operator<<(std::ostream& o, const SetValue& value) { | ||
o << "[#" << value.size() << "]"; | ||
o << value.m_set; | ||
return o; | ||
} | ||
|
||
private: | ||
Set m_set; | ||
|
||
friend class sparta::SetAbstractDomain<Set>; | ||
}; | ||
|
||
} // namespace set_impl | ||
|
||
} // namespace sparta |