/* Copyright (c) 2013 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author: Leonardo de Moura */ #pragma once #include #include #include "util/list.h" #include "util/buffer.h" #include "util/pair.h" namespace lean { /** \brief Copy the values in the list \c l to the buffer \c r. */ template void to_buffer(list const & l, buffer & r) { for (T const & v : l) { r.push_back(v); } } /** \brief Copy the cells in the list \c l to the buffer \c r. */ template void to_buffer(list const & l, buffer::cell *> & r) { typename list::cell * it = l.raw(); while (it) { r.push_back(it); it = it->tail().raw(); } } /** \brief Auxiliary function for reverse function. */ template list reverse_aux(list const & l, list const & r) { if (is_nil(l)) return r; else return reverse_aux(cdr(l), cons(car(l), r)); } /** \brief Return the reverse list. */ template list reverse(list const & l) { return reverse_aux(l, list()); } /** \brief Return two lists \c l1 and \c l2 of approximately the same size s.t. append(l1, l2) == l */ template std::pair, list> split(list const & l) { if (is_nil(l)) { return mk_pair(l, l); } else if (is_nil(cdr(l))) { return mk_pair(l, list()); } else { buffer tmp; to_buffer(l, tmp); unsigned mid = tmp.size() / 2; auto beg = tmp.begin(); lean_assert(beg + mid <= tmp.end()); return mk_pair(to_list(beg, beg + mid), to_list(beg + mid, tmp.end())); } } /** \brief Return two lists \c l1 and \c l2 of approximately the same size s.t. append(l1, reverse(l2)) == l */ template std::pair, list> split_reverse_second(list const & l) { if (is_nil(l)) { return mk_pair(l, l); } else if (is_nil(cdr(l))) { return mk_pair(l, list()); } else { buffer tmp; to_buffer(l, tmp); unsigned mid = tmp.size() / 2; auto beg = tmp.begin(); lean_assert(beg + mid <= tmp.end()); return mk_pair(to_list(beg, beg + mid), reverse_to_list(beg+mid, tmp.end())); } } /** \brief Append two lists */ template list append(list const & l1, list const & l2) { if (!l1) { return l2; } else if (!l2) { return l1; } else { buffer tmp; list r = l2; to_buffer(l1, tmp); unsigned i = tmp.size(); while (i > 0) { --i; r = cons(tmp[i], r); } return r; } } /** \brief Given list (a_0, ..., a_k), return list (f(a_0), ..., f(a_k)). */ template list map(list const & l, F f) { static_assert(std::is_same::type, T>::value, "map: return type of f is not sxpr"); if (is_nil(l)) { return l; } else { buffer::cell*> tmp; to_buffer(l, tmp); unsigned i = tmp.size(); list r; while (i > 0) { --i; r = cons(f(tmp[i]->head()), r); } return l; } } /** \brief Semantically equivalent to \c map, but it tries to reuse list cells. The elements are compared using the predicate \c eq. */ template> list map_reuse(list const & l, F f, Eq const & eq = Eq()) { if (is_nil(l)) { return l; } else { typedef typename list::cell cell; buffer> tmp; cell * it = l.raw(); while (it) { tmp.emplace_back(f(it->head()), it); it = it->tail().raw(); } unsigned i = tmp.size(); lean_assert(i > 0); while (i > 0) { --i; std::pair const & p = tmp[i]; if (!eq(p.first, p.second->head())) { list r(p.first, p.second->tail()); while (i > 0) { --i; std::pair const & p = tmp[i]; r = cons(p.first, r); } return r; } } return l; } } /** \brief Given list (a_0, ..., a_k), exec f(a_0); f(a_1); ... f(a_k). */ template void for_each(list const & l, F f) { static_assert(std::is_same::type, void>::value, "for_each: return type of f is not void"); typedef typename list::cell cell; cell * it = l.raw(); while (it) { f(it->head()); it = it->tail().raw(); } } /** \brief Compare two lists using the binary predicate p. */ template bool compare(list const & l1, list const & l2, P p) { static_assert(std::is_same::type, bool>::value, "compare: return type of f is not bool"); auto it1 = l1.begin(); auto it2 = l2.begin(); auto end1 = l1.end(); auto end2 = l2.end(); for (; it1 != end1 && it2 != end2; ++it1, ++it2) { if (!p(*it1, *it2)) return false; } return it1 == end1 && it2 == end2; } }