/*++ Copyright (c) 2006 Microsoft Corporation Module Name: approx_set.h Abstract: Approximated sets. Author: Leonardo de Moura (leonardo) 2007-03-02. Revision History: --*/ #pragma once #include #include "util/debug.h" template class approx_set_traits; template <> class approx_set_traits { public: static const unsigned capacity = 64; static const unsigned long long zero = 0ull; static const unsigned long long one = 1ull; }; static_assert(sizeof(unsigned long long) == 8, ""); template <> class approx_set_traits { public: static const unsigned capacity = 32; static const unsigned zero = 0; static const unsigned one = 1; }; static_assert(sizeof(unsigned) == 4, "unsigned are 4 bytes"); template class approx_set_tpl : private T2U_Proc { protected: R m_set; unsigned e2u(T const & e) const { return T2U_Proc::operator()(e); } R u2s(unsigned u) const { return (approx_set_traits::one << (u & (approx_set_traits::capacity - 1))); } R e2s(T const & e) const { return u2s(e2u(e)); } static approx_set_tpl r2s(R const & s) { approx_set_tpl r; r.m_set = s; return r; } public: approx_set_tpl(): m_set(approx_set_traits::zero) { } explicit approx_set_tpl(T const & e): m_set(e2s(e)) { } approx_set_tpl(unsigned sz, T const * es): m_set(approx_set_traits::zero) { for (unsigned i = 0; i < sz; i++) insert(es[i]); } approx_set_tpl(approx_set_tpl const & s): m_set(s.m_set) { } void set(R s) { m_set = s; } R get() const { return m_set; } void insert(T const & e) { m_set |= e2s(e); } bool may_contain(T const & e) const { return (m_set & e2s(e)) != approx_set_traits::zero; } bool must_not_contain(T const & e) const { return !may_contain(e); } friend inline approx_set_tpl mk_union(approx_set_tpl const & s1, approx_set_tpl const & s2) { return r2s(s1.m_set | s2.m_set); } friend inline approx_set_tpl mk_intersection(approx_set_tpl const & s1, approx_set_tpl const & s2) { return r2s(s1.m_set & s2.m_set); } void operator|=(approx_set_tpl const & other) { m_set |= other.m_set; } void operator&=(approx_set_tpl const & other) { m_set &= other.m_set; } void operator-=(approx_set_tpl const & other) { m_set &= ~(other.m_set); } bool empty() const { return m_set == approx_set_traits::zero; } friend inline bool empty(approx_set_tpl const & s) { return s.empty(); } bool must_not_subset(approx_set_tpl const & s2) const { return (m_set & ~(s2.m_set)) != approx_set_traits::zero; } friend inline bool must_not_subset(approx_set_tpl const & s1, approx_set_tpl const & s2) { return s1.must_not_subset(s2); } bool must_not_subsume(approx_set_tpl const & s2) const { return must_not_subset(s2); } friend inline bool must_not_subsume(approx_set_tpl const & s1, approx_set_tpl const & s2) { return s1.must_not_subset(s2); } friend inline bool must_not_eq(approx_set_tpl const & s1, approx_set_tpl const & s2) { return s1.m_set != s2.m_set; } friend inline bool may_eq(approx_set_tpl const & s1, approx_set_tpl const & s2) { return s1.m_set == s2.m_set; } /** \brief Return if s1 and s2 are the same approximated set. */ bool equiv(approx_set_tpl const & s2) const { return m_set == s2.m_set; } friend inline bool equiv(approx_set_tpl const & s1, approx_set_tpl const & s2) { return s1.m_set == s2.m_set; } /** \brief Return true if the approximation of s1 is a subset of the approximation of s2. */ friend inline bool approx_subset(approx_set_tpl const & s1, approx_set_tpl const & s2) { return s2.equiv(mk_union(s1, s2)); } void reset() { m_set = approx_set_traits::zero; } bool empty_intersection(approx_set_tpl const & other) const { return mk_intersection(*this, other).empty(); } }; struct u2u { unsigned operator()(unsigned u) const { return u; } }; typedef approx_set_tpl u_approx_set; #define APPROX_SET_CAPACITY (approx_set_traits::capacity) class approx_set : public u_approx_set { public: approx_set() = default; approx_set(unsigned e):u_approx_set(e) {} class iterator { unsigned long long m_set; unsigned m_val; void move_to_next() { // TODO: this code can be optimized in platforms with special // instructions to count leading (trailing) zeros in a word. while (m_set > 0) { if ((m_set & 1ull) != 0) { return; } m_val ++; m_set = m_set >> 1; } } public: iterator(unsigned long long s): m_set(s), m_val(0) { move_to_next(); } unsigned operator*() const { return m_val; } iterator & operator++() { m_val++; m_set = m_set >> 1; move_to_next(); return *this; } iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; } bool operator==(iterator const & it) const { return m_set == it.m_set; } bool operator!=(iterator const & it) const { return m_set != it.m_set; } }; iterator begin() const { return iterator(m_set); } static iterator end() { return iterator(0); } void display(std::ostream & out) const; unsigned size() const; // for backward compatibility friend inline bool operator==(approx_set const & s1, approx_set const & s2) { return may_eq(s1, s2); } }; inline std::ostream & operator<<(std::ostream & out, approx_set const & s) { s.display(out); return out; }