feat(kernel/expr): no overhead optional<expr> template specialization

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-12-08 10:17:29 -08:00
parent 3e1fd06903
commit 25b812f1c9
4 changed files with 57 additions and 15 deletions

View file

@ -38,7 +38,7 @@ expr_cell::expr_cell(expr_kind k, unsigned h, bool has_mv):
m_kind(static_cast<unsigned>(k)),
m_flags(has_mv ? 4 : 0),
m_hash(h),
m_rc(1) {
m_rc(0) {
// m_hash_alloc does not need to be a unique identifier.
// We want diverse hash codes such that given expr_cell * c1 and expr_cell * c2,
// if c1 != c2, then there is high probability c1->m_hash_alloc != c2->m_hash_alloc.

View file

@ -100,9 +100,10 @@ public:
class expr {
private:
expr_cell * m_ptr;
explicit expr(expr_cell * ptr):m_ptr(ptr) {}
explicit expr(expr_cell * ptr):m_ptr(ptr) { if (m_ptr) m_ptr->inc_ref(); }
friend class expr_cell;
expr_cell * steal_ptr() { expr_cell * r = m_ptr; m_ptr = nullptr; return r; }
friend class optional<expr>;
public:
expr();
expr(expr const & s):m_ptr(s.m_ptr) { if (m_ptr) m_ptr->inc_ref(); }
@ -135,10 +136,6 @@ public:
friend expr mk_metavar(name const & n, local_context const & ctx);
friend bool is_eqp(expr const & a, expr const & b) { return a.m_ptr == b.m_ptr; }
friend bool is_eqp(optional<expr> const & a, optional<expr> const & b) {
return static_cast<bool>(a) == static_cast<bool>(b) && (!a || is_eqp(*a, *b));
}
// Overloaded operator() can be used to create applications
expr operator()(expr const & a1) const;
expr operator()(expr const & a1, expr const & a2) const;
@ -150,6 +147,18 @@ public:
expr operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4, expr const & a5, expr const & a6, expr const & a7, expr const & a8) const;
};
// =======================================
// Structural equality
bool operator==(expr const & a, expr const & b);
inline bool operator!=(expr const & a, expr const & b) { return !operator==(a, b); }
// =======================================
SPECIALIZE_OPTIONAL_FOR_SMART_PTR(expr)
inline bool is_eqp(optional<expr> const & a, optional<expr> const & b) {
return static_cast<bool>(a) == static_cast<bool>(b) && (!a || is_eqp(*a, *b));
}
// =======================================
// Expr (internal) Representation
/** \brief Free variables. They are encoded using de Bruijn's indices. */
@ -513,12 +522,6 @@ inline bool has_metavar(expr const & e) { return e.has_metavar(); }
bool is_eq(expr const & e, expr & lhs, expr & rhs);
// =======================================
// =======================================
// Structural equality
bool operator==(expr const & a, expr const & b);
inline bool operator!=(expr const & a, expr const & b) { return !operator==(a, b); }
// =======================================
// =======================================
// Expression+Offset
typedef std::pair<expr, unsigned> expr_offset;

View file

@ -355,9 +355,7 @@ static void tst18() {
int main() {
save_stack_info();
std::cout << "sizeof(expr): " << sizeof(expr) << "\n";
std::cout << "sizeof(expr_app): " << sizeof(expr_app) << "\n";
std::cout << "sizeof(expr_cell): " << sizeof(expr_cell) << "\n";
lean_assert(sizeof(expr) == sizeof(optional<expr>));
tst1();
tst2();
tst3();
@ -376,6 +374,11 @@ int main() {
tst16();
tst17();
tst18();
std::cout << "sizeof(expr): " << sizeof(expr) << "\n";
std::cout << "sizeof(expr_app): " << sizeof(expr_app) << "\n";
std::cout << "sizeof(expr_cell): " << sizeof(expr_cell) << "\n";
std::cout << "sizeof(optional<expr>): " << sizeof(optional<expr>) << "\n";
std::cout << "sizeof(optional<sexpr>): " << sizeof(optional<sexpr>) << "\n";
std::cout << "done" << "\n";
return has_violations() ? 1 : 0;
}

View file

@ -110,4 +110,40 @@ public:
template<typename T> optional<T> some(T const & t) { return optional<T>(t); }
template<typename T> optional<T> some(T && t) { return optional<T>(std::forward<T>(t)); }
// The following macro creates a template specialization optional<P>, where P
// is an intrusive smart pointer that does not let "customers" point to nullptr.
// That is, if a customer have 'P x', then x is not a pointer to nullptr.
// Requirements:
// - P must declare optional<P> as a friend.
// - P must handle the nullptr case even if it does not let "customers" point to nullptr
// - P must have a field m_ptr a pointer to the actual value.
#define SPECIALIZE_OPTIONAL_FOR_SMART_PTR(P) \
template<> class optional<P> { \
P m_value; \
public: \
optional():m_value(nullptr) {} \
optional(optional const & other):m_value(other.m_value) {} \
optional(optional && other):m_value(std::forward<P>(other.m_value)) {} \
explicit optional(P const & v):m_value(v) {} \
explicit optional(P && v):m_value(std::forward<P>(v)) {} \
\
explicit operator bool() const { return m_value.m_ptr != nullptr; } \
P const * operator->() const { lean_assert(m_value.m_ptr); return &m_value; } \
P * operator->() { lean_assert(m_value.m_ptr); return &m_value; } \
P const & operator*() const { lean_assert(m_value.m_ptr); return m_value; } \
P & operator*() { lean_assert(m_value.m_ptr); return m_value; } \
P const & value() const { lean_assert(m_value.m_ptr); return m_value; } \
P & value() { lean_assert(m_value.m_ptr); return m_value; } \
optional & operator=(optional const & other) { m_value = other.m_value; return *this; } \
optional& operator=(optional && other) { m_value = std::forward<P>(other.m_value); return *this; } \
optional& operator=(P const & other) { m_value = other; return *this; } \
optional& operator=(P && other) { m_value = std::forward<P>(other); return *this; } \
friend bool operator==(optional const & o1, optional const & o2) { \
return static_cast<bool>(o1) == static_cast<bool>(o2) && (!o1 || o1.m_value == o2.m_value); \
} \
friend bool operator!=(optional const & o1, optional const & o2) { \
return !operator==(o1, o2); \
} \
};
}