Cache the incremental iterators as you traverse the list, so that you don't have to keep recomputing them

If memory turns out to be a problem, which I don't think it will in practice because all these ValueObjects, we'd be keeping alive anyway, I can always resort to caching the farthest-most iterator only

This gains us an order of magnitude in my benchmark, cutting the time to traverse a 1500-elements list from 22 seconds down to 2

llvm-svn: 254762
This commit is contained in:
Enrico Granata 2015-12-04 20:12:46 +00:00
parent 4c8a5e37e2
commit 26935d9a09
1 changed files with 79 additions and 64 deletions

View File

@ -31,9 +31,6 @@ namespace {
class ListEntry
{
private:
static const std::initializer_list<size_t> __prev_idx;
static const std::initializer_list<size_t> __next_idx;
public:
ListEntry() = default;
ListEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
@ -102,6 +99,64 @@ namespace {
private:
ValueObjectSP m_entry_sp;
};
class ListIterator
{
public:
ListIterator() = default;
ListIterator (ListEntry entry) : m_entry(entry) {}
ListIterator (ValueObjectSP entry) : m_entry(entry) {}
ListIterator (const ListIterator& rhs) : m_entry(rhs.m_entry) {}
ListIterator (ValueObject* entry) : m_entry(entry) {}
ValueObjectSP
value ()
{
return m_entry.GetEntry();
}
ValueObjectSP
advance (size_t count)
{
if (count == 0)
return m_entry.GetEntry();
if (count == 1)
{
next ();
return m_entry.GetEntry();
}
while (count > 0)
{
next ();
count--;
if (m_entry.null())
return lldb::ValueObjectSP();
}
return m_entry.GetEntry();
}
bool
operator == (const ListIterator& rhs) const
{
return (rhs.m_entry == m_entry);
}
protected:
void
next ()
{
m_entry = m_entry.next();
}
void
prev ()
{
m_entry = m_entry.prev();
}
private:
ListEntry m_entry;
};
} // end anonymous namespace
@ -146,68 +201,11 @@ namespace lldb_private {
CompilerType m_element_type;
size_t m_count;
std::map<size_t,lldb::ValueObjectSP> m_children;
std::map<size_t, ListIterator> m_iterators;
};
} // namespace formatters
} // namespace lldb_private
class ListIterator
{
public:
ListIterator() = default;
ListIterator (ListEntry entry) : m_entry(entry) {}
ListIterator (ValueObjectSP entry) : m_entry(entry) {}
ListIterator (const ListIterator& rhs) : m_entry(rhs.m_entry) {}
ListIterator (ValueObject* entry) : m_entry(entry) {}
ValueObjectSP
value ()
{
return m_entry.GetEntry();
}
ValueObjectSP
advance (size_t count)
{
if (count == 0)
return m_entry.GetEntry();
if (count == 1)
{
next ();
return m_entry.GetEntry();
}
while (count > 0)
{
next ();
count--;
if (m_entry.null())
return lldb::ValueObjectSP();
}
return m_entry.GetEntry();
}
bool
operator == (const ListIterator& rhs) const
{
return (rhs.m_entry == m_entry);
}
protected:
void
next ()
{
m_entry = m_entry.next();
}
void
prev ()
{
m_entry = m_entry.prev();
}
private:
ListEntry m_entry;
};
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
SyntheticChildrenFrontEnd(*valobj_sp.get()),
m_list_capping_size(0),
@ -217,7 +215,8 @@ m_head(NULL),
m_tail(NULL),
m_element_type(),
m_count(UINT32_MAX),
m_children()
m_children(),
m_iterators()
{
if (valobj_sp)
Update();
@ -319,11 +318,26 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_
if (HasLoop(idx+1))
return lldb::ValueObjectSP();
size_t actual_advance = idx;
ListIterator current(m_head);
ValueObjectSP current_sp(current.advance(idx));
if (idx > 0)
{
auto cached_iterator = m_iterators.find(idx-1);
if (cached_iterator != m_iterators.end())
{
current = cached_iterator->second;
actual_advance = 1;
}
}
ValueObjectSP current_sp(current.advance(actual_advance));
if (!current_sp)
return lldb::ValueObjectSP();
m_iterators[idx] = current;
current_sp = current_sp->GetChildAtIndex(1, true); // get the __value_ child
if (!current_sp)
return lldb::ValueObjectSP();
@ -343,6 +357,7 @@ bool
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update()
{
m_children.clear();
m_iterators.clear();
m_head = m_tail = NULL;
m_node_address = 0;
m_count = UINT32_MAX;