perf(util/list): use buffer of cells instead of buffer of T
T may be a big object. We minimize the ammount of copying using buffer of (pointers to) cells. Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
76252816ac
commit
64379a5a10
1 changed files with 44 additions and 30 deletions
|
@ -35,14 +35,25 @@ void to_buffer(list<T> const & l, buffer<typename list<T>::cell *> & r) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Auxiliary function for reverse function.
|
\brief Create a list using the values in the cells from \c begin to \c end.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
list<T> reverse_aux(list<T> const & l, list<T> const & r) {
|
list<T> cells_to_list(typename list<T>::cell * const * begin, typename list<T>::cell * const * end) {
|
||||||
if (is_nil(l))
|
list<T> r;
|
||||||
return r;
|
auto it = end;
|
||||||
else
|
while (it != begin) {
|
||||||
return reverse_aux(cdr(l), cons(car(l), r));
|
--it;
|
||||||
|
r = cons((*it)->head(), r);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Create a list using the values in the cells from \c b.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
list<T> buffer_to_list(buffer<typename list<T>::cell*> const & b) {
|
||||||
|
return cells_to_list<T>(b.begin(), b.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,7 +61,14 @@ list<T> reverse_aux(list<T> const & l, list<T> const & r) {
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
list<T> reverse(list<T> const & l) {
|
list<T> reverse(list<T> const & l) {
|
||||||
return reverse_aux(l, list<T>());
|
if (is_nil(l)) {
|
||||||
|
return l;
|
||||||
|
} else {
|
||||||
|
buffer<typename list<T>::cell *> tmp;
|
||||||
|
to_buffer(l, tmp);
|
||||||
|
std::reverse(tmp.begin(), tmp.end());
|
||||||
|
return buffer_to_list<T>(tmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,13 +82,13 @@ std::pair<list<T>, list<T>> split(list<T> const & l) {
|
||||||
} else if (is_nil(cdr(l))) {
|
} else if (is_nil(cdr(l))) {
|
||||||
return mk_pair(l, list<T>());
|
return mk_pair(l, list<T>());
|
||||||
} else {
|
} else {
|
||||||
buffer<T> tmp;
|
buffer<typename list<T>::cell*> tmp;
|
||||||
to_buffer(l, tmp);
|
to_buffer(l, tmp);
|
||||||
unsigned mid = tmp.size() / 2;
|
unsigned mid = tmp.size() / 2;
|
||||||
auto beg = tmp.begin();
|
auto beg = tmp.begin();
|
||||||
lean_assert(beg + mid <= tmp.end());
|
lean_assert(beg + mid <= tmp.end());
|
||||||
return mk_pair(to_list(beg, beg + mid),
|
return mk_pair(cells_to_list<T>(beg, beg + mid),
|
||||||
to_list(beg + mid, tmp.end()));
|
cells_to_list<T>(beg + mid, tmp.end()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,13 +122,13 @@ list<T> append(list<T> const & l1, list<T> const & l2) {
|
||||||
} else if (!l2) {
|
} else if (!l2) {
|
||||||
return l1;
|
return l1;
|
||||||
} else {
|
} else {
|
||||||
buffer<T> tmp;
|
buffer<typename list<T>::cell*> tmp;
|
||||||
list<T> r = l2;
|
list<T> r = l2;
|
||||||
to_buffer(l1, tmp);
|
to_buffer(l1, tmp);
|
||||||
unsigned i = tmp.size();
|
unsigned i = tmp.size();
|
||||||
while (i > 0) {
|
while (i > 0) {
|
||||||
--i;
|
--i;
|
||||||
r = cons(tmp[i], r);
|
r = cons(tmp[i]->head(), r);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -147,24 +165,20 @@ list<T> map_reuse(list<T> const & l, F f, Eq const & eq = Eq()) {
|
||||||
if (is_nil(l)) {
|
if (is_nil(l)) {
|
||||||
return l;
|
return l;
|
||||||
} else {
|
} else {
|
||||||
typedef typename list<T>::cell cell;
|
buffer<typename list<T>::cell*> tmp;
|
||||||
buffer<std::pair<T, cell*>> tmp;
|
to_buffer(l, tmp);
|
||||||
cell * it = l.raw();
|
auto it = tmp.end();
|
||||||
while (it) {
|
auto begin = tmp.begin();
|
||||||
tmp.emplace_back(f(it->head()), it);
|
while (it != begin) {
|
||||||
it = it->tail().raw();
|
--it;
|
||||||
}
|
auto curr = *it;
|
||||||
unsigned i = tmp.size();
|
auto new_v = f(curr->head());
|
||||||
lean_assert(i > 0);
|
if (!eq(new_v, curr->head())) {
|
||||||
while (i > 0) {
|
list<T> r(new_v, curr->tail());
|
||||||
--i;
|
while (it != begin) {
|
||||||
std::pair<T, cell*> const & p = tmp[i];
|
--it;
|
||||||
if (!eq(p.first, p.second->head())) {
|
auto curr = *it;
|
||||||
list<T> r(p.first, p.second->tail());
|
r = cons(f(curr->head()), r);
|
||||||
while (i > 0) {
|
|
||||||
--i;
|
|
||||||
std::pair<T, cell*> const & p = tmp[i];
|
|
||||||
r = cons(p.first, r);
|
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue