29 ListEntry() =
default;
30 ListEntry(ValueObjectSP entry_sp) : m_entry_sp(std::move(entry_sp)) {}
32 : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
39 return ListEntry(m_entry_sp->GetChildMemberWithName(g_next,
true));
47 return ListEntry(m_entry_sp->GetChildMemberWithName(g_prev,
true));
50 uint64_t value()
const {
53 return m_entry_sp->GetValueAsUnsigned(0);
56 bool null() {
return (value() == 0); }
58 explicit operator bool() {
return GetEntry() && !null(); }
60 ValueObjectSP GetEntry() {
return m_entry_sp; }
62 void SetEntry(ValueObjectSP entry) { m_entry_sp = entry; }
64 bool operator==(
const ListEntry &rhs)
const {
return value() == rhs.value(); }
66 bool operator!=(
const ListEntry &rhs)
const {
return !(*
this == rhs); }
69 ValueObjectSP m_entry_sp;
74 ListIterator() =
default;
75 ListIterator(ListEntry entry) : m_entry(std::move(entry)) {}
76 ListIterator(ValueObjectSP entry) : m_entry(std::move(entry)) {}
77 ListIterator(
ValueObject *entry) : m_entry(entry) {}
79 ValueObjectSP value() {
return m_entry.GetEntry(); }
81 ValueObjectSP advance(
size_t count) {
83 return m_entry.GetEntry();
86 return m_entry.GetEntry();
92 return lldb::ValueObjectSP();
94 return m_entry.GetEntry();
97 bool operator==(
const ListIterator &rhs)
const {
98 return (rhs.m_entry == m_entry);
102 void next() { m_entry = m_entry.next(); }
104 void prev() { m_entry = m_entry.prev(); }
125 static constexpr bool g_use_loop_detect =
true;
126 size_t m_loop_detected = 0;
128 ListEntry m_slow_runner;
129 ListEntry m_fast_runner;
131 size_t m_list_capping_size = 0;
133 std::map<size_t, ListIterator> m_iterators;
135 bool HasLoop(
size_t count);
136 ValueObjectSP GetItem(
size_t idx);
139class ForwardListFrontEnd :
public AbstractListFrontEnd {
144 ValueObjectSP GetChildAtIndex(
size_t idx)
override;
145 bool Update()
override;
148class ListFrontEnd :
public AbstractListFrontEnd {
150 ListFrontEnd(lldb::ValueObjectSP valobj_sp);
152 ~ListFrontEnd()
override =
default;
156 lldb::ValueObjectSP GetChildAtIndex(
size_t idx)
override;
158 bool Update()
override;
167bool AbstractListFrontEnd::Update() {
171 m_list_capping_size = 0;
172 m_slow_runner.SetEntry(
nullptr);
173 m_fast_runner.SetEntry(
nullptr);
176 if (m_backend.GetTargetSP())
177 m_list_capping_size =
178 m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
179 if (m_list_capping_size == 0)
180 m_list_capping_size = 255;
193bool AbstractListFrontEnd::HasLoop(
size_t count) {
194 if (!g_use_loop_detect)
200 if (m_loop_detected == 0) {
203 m_slow_runner = ListEntry(m_head).next();
204 m_fast_runner = m_slow_runner.next();
212 const size_t steps_to_run = std::min(count, m_count);
213 while (m_loop_detected < steps_to_run && m_slow_runner && m_fast_runner &&
214 m_slow_runner != m_fast_runner) {
216 m_slow_runner = m_slow_runner.next();
217 m_fast_runner = m_fast_runner.next().next();
220 if (count <= m_loop_detected)
222 if (!m_slow_runner || !m_fast_runner)
224 return m_slow_runner == m_fast_runner;
227ValueObjectSP AbstractListFrontEnd::GetItem(
size_t idx) {
228 size_t advance = idx;
229 ListIterator current(m_head);
231 auto cached_iterator = m_iterators.find(idx - 1);
232 if (cached_iterator != m_iterators.end()) {
233 current = cached_iterator->second;
237 ValueObjectSP value_sp = current.advance(advance);
238 m_iterators[idx] = current;
242ForwardListFrontEnd::ForwardListFrontEnd(
ValueObject &valobj)
243 : AbstractListFrontEnd(valobj) {
247size_t ForwardListFrontEnd::CalculateNumChildren() {
251 ListEntry current(m_head);
253 while (current && m_count < m_list_capping_size) {
255 current = current.next();
260ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(
size_t idx) {
267 if (HasLoop(idx + 1))
270 ValueObjectSP current_sp = GetItem(idx);
274 current_sp = current_sp->GetChildAtIndex(1,
true);
282 current_sp->GetData(data,
error);
286 return CreateValueObjectFromData(llvm::formatv(
"[{0}]", idx).str(), data,
287 m_backend.GetExecutionContextRef(),
291bool ForwardListFrontEnd::Update() {
292 AbstractListFrontEnd::Update();
295 ValueObjectSP backend_addr(m_backend.AddressOf(err));
296 if (err.
Fail() || !backend_addr)
299 ValueObjectSP impl_sp(
300 m_backend.GetChildMemberWithName(
ConstString(
"__before_begin_"),
true));
306 m_head = impl_sp->GetChildMemberWithName(
ConstString(
"__next_"),
true).get();
310ListFrontEnd::ListFrontEnd(lldb::ValueObjectSP valobj_sp)
311 : AbstractListFrontEnd(*valobj_sp) {
316size_t ListFrontEnd::CalculateNumChildren() {
319 if (!m_head || !m_tail || m_node_address == 0)
321 ValueObjectSP size_alloc(
322 m_backend.GetChildMemberWithName(
ConstString(
"__size_alloc_"),
true));
326 m_count = value->GetValueAsUnsigned(
UINT32_MAX);
332 uint64_t next_val = m_head->GetValueAsUnsigned(0);
333 uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
334 if (next_val == 0 || prev_val == 0)
336 if (next_val == m_node_address)
338 if (next_val == prev_val)
341 ListEntry current(m_head);
342 while (current.next() && current.next().value() != m_node_address) {
344 current = current.next();
345 if (size > m_list_capping_size)
348 return m_count = (size - 1);
352lldb::ValueObjectSP ListFrontEnd::GetChildAtIndex(
size_t idx) {
357 return lldb::ValueObjectSP();
359 if (!m_head || !m_tail || m_node_address == 0)
360 return lldb::ValueObjectSP();
362 if (HasLoop(idx + 1))
363 return lldb::ValueObjectSP();
365 ValueObjectSP current_sp = GetItem(idx);
367 return lldb::ValueObjectSP();
369 current_sp = current_sp->GetChildAtIndex(1,
true);
371 return lldb::ValueObjectSP();
373 if (current_sp->GetName() == g_next) {
374 ProcessSP process_sp(current_sp->GetProcessSP());
376 return lldb::ValueObjectSP();
379 lldb::addr_t addr = current_sp->GetParent()->GetPointerValue();
380 addr = addr + 2 * process_sp->GetAddressByteSize();
383 CreateValueObjectFromAddress(
"__value_", addr, exe_ctx, m_element_type);
385 return lldb::ValueObjectSP();
392 current_sp->GetData(data,
error);
394 return lldb::ValueObjectSP();
397 name.
Printf(
"[%" PRIu64
"]", (uint64_t)idx);
398 return CreateValueObjectFromData(name.
GetString(), data,
399 m_backend.GetExecutionContextRef(),
403bool ListFrontEnd::Update() {
404 AbstractListFrontEnd::Update();
409 ValueObjectSP backend_addr(m_backend.AddressOf(err));
410 if (err.
Fail() || !backend_addr)
412 m_node_address = backend_addr->GetValueAsUnsigned(0);
415 ValueObjectSP impl_sp(
416 m_backend.GetChildMemberWithName(
ConstString(
"__end_"),
true));
419 m_head = impl_sp->GetChildMemberWithName(
ConstString(
"__next_"),
true).get();
420 m_tail = impl_sp->GetChildMemberWithName(
ConstString(
"__prev_"),
true).get();
426 return (valobj_sp ?
new ListFrontEnd(valobj_sp) :
nullptr);
432 return valobj_sp ?
new ForwardListFrontEnd(*valobj_sp) :
nullptr;
static llvm::raw_ostream & error(Stream &strm)
static size_t CalculateNumChildren(CompilerType container_type, CompilerType element_type, lldb_private::ExecutionContextScope *exe_scope=nullptr)
Generic representation of a type in a programming language.
CompilerType GetTypeTemplateArgument(size_t idx, bool expand_pack=false) const
size_t GetNumTemplateArguments(bool expand_pack=false) const
Return the number of template arguments the type has.
CompilerType GetNonReferenceType() const
If this type is a reference to a type (L value or R value reference), return a new type with the refe...
bool IsReferenceType(CompilerType *pointee_type=nullptr, bool *is_rvalue=nullptr) const
A uniqued constant string class.
const char * GetCString() const
Get the string value as a C string.
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
bool Fail() const
Test for error condition.
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
virtual bool MightHaveChildren()=0
virtual size_t GetIndexOfChildWithName(ConstString name)=0
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
bool operator!=(const Address &lhs, const Address &rhs)
bool LLDB_API operator==(const SBAddress &lhs, const SBAddress &rhs)