From a1b9ae0e673a2c457e1886dcd7bf7a536d0a3188 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 23 May 2018 15:05:08 -0700 Subject: [PATCH] feat(util/obj_list): add `map_reuse` and cleanup code --- src/util/obj_list.h | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/util/obj_list.h b/src/util/obj_list.h index 741a17b571..586c9a237e 100644 --- a/src/util/obj_list.h +++ b/src/util/obj_list.h @@ -8,6 +8,8 @@ Author: Leonardo de Moura #include "util/object_ref.h" namespace lean { +template T const & head(object * o) { return static_cast(cnstr_obj_ref(o, 0)); } + /* Wrapper for manipulating Lean lists in C++ */ template class obj_list : public object_ref { @@ -51,8 +53,8 @@ public: while (!is_scalar(it1) && !is_scalar(it2)) { if (it1 == it2) return true; - T const & h1 = static_cast(cnstr_obj_ref(it1, 0)); - T const & h2 = static_cast(cnstr_obj_ref(it2, 0)); + T const & h1 = ::lean::head(it1); + T const & h2 = ::lean::head(it2); if (h1 != h2) return false; it1 = cnstr_obj(it1, 1); @@ -77,7 +79,7 @@ public: iterator operator++(int) { iterator tmp(*this); operator++(); return tmp; } bool operator==(iterator const & s) const { return m_it == s.m_it; } bool operator!=(iterator const & s) const { return !operator==(s); } - T const & operator*() { return static_cast(cnstr_obj_ref(m_it, 0)); } + T const & operator*() { return ::lean::head(m_it); } }; iterator begin() const { return iterator(raw()); } @@ -92,6 +94,8 @@ public: } }; +template obj_list const & tail(object * o) { return static_cast const &>(cnstr_obj_ref(o, 1)); } + template size_t length(obj_list const & l) { size_t r = 0; object * it = l.raw(); @@ -126,8 +130,30 @@ obj_list map(obj_list const & l, F && f) { template obj_list map_reuse(obj_list const & l, F && f) { - // TODO(Leo): - return map(l, std::move(f)); + if (is_nil(l)) + return l; + buffer tmp; + l.get_cons_cells(tmp); + auto it = tmp.end(); + auto begin = tmp.begin(); + while (it != begin) { + --it; + object * curr = *it; + T const & h = head(curr); + T new_h = f(h); + if (new_h.raw() != h.raw()) { + obj_list const & t = tail(curr); + obj_list r(new_h, t); + while (it != begin) { + --it; + object * curr = *it; + T const & h = head(curr); + r = cons(f(h), r); + } + return r; + } + } + return l; } /** \brief Compare two lists using the binary predicate p. */ @@ -160,18 +186,18 @@ obj_list filter(obj_list const & l, P && p) { size_t i = tmp.size(); while (i > 0) { --i; - if (!p(static_cast(cnstr_obj_ref(tmp[i], 0)))) { + if (!p(head(tmp[i]))) { obj_list r; - r = static_cast const &>(cnstr_obj_ref(tmp[i], 1)); + r = tail(tmp[i]); while (i > 0) { --i; - T const & h = static_cast(cnstr_obj_ref(tmp[i], 0)); + T const & h = head(tmp[i]); if (p(h)) r = cons(h, r); } return r; } } - return l; // not element was removed + return l; // no element was removed } }