30template <StlType Stl>
class ListEntry {
32 ListEntry() =
default;
33 ListEntry(
ValueObjectSP entry_sp) : m_entry_sp(std::move(entry_sp)) {}
34 ListEntry(ValueObject *entry)
37 uint64_t value()
const {
40 return m_entry_sp->GetValueAsUnsigned(0);
46 bool null() {
return (value() == 0); }
48 explicit operator bool() {
return GetEntry() && !null(); }
54 bool operator==(
const ListEntry &rhs)
const {
return value() == rhs.value(); }
56 bool operator!=(
const ListEntry &rhs)
const {
return !(*
this == rhs); }
62template <> ListEntry<StlType::LibCxx> ListEntry<StlType::LibCxx>::next() {
65 return ListEntry(m_entry_sp->GetChildMemberWithName(
"__next_"));
68template <> ListEntry<StlType::LibCxx> ListEntry<StlType::LibCxx>::prev() {
71 return ListEntry(m_entry_sp->GetChildMemberWithName(
"__prev_"));
74template <> ListEntry<StlType::MsvcStl> ListEntry<StlType::MsvcStl>::next() {
77 return ListEntry(m_entry_sp->GetChildMemberWithName(
"_Next"));
80template <> ListEntry<StlType::MsvcStl> ListEntry<StlType::MsvcStl>::prev() {
83 return ListEntry(m_entry_sp->GetChildMemberWithName(
"_Prev"));
86template <StlType Stl>
class ListIterator {
88 ListIterator() =
default;
89 ListIterator(ListEntry<Stl> entry) : m_entry(std::move(entry)) {}
90 ListIterator(
ValueObjectSP entry) : m_entry(std::move(entry)) {}
91 ListIterator(ValueObject *entry) : m_entry(entry) {}
97 return m_entry.GetEntry();
100 return m_entry.GetEntry();
108 return m_entry.GetEntry();
111 bool operator==(
const ListIterator &rhs)
const {
112 return (rhs.m_entry == m_entry);
116 void next() { m_entry = m_entry.next(); }
118 void prev() { m_entry = m_entry.prev(); }
121 ListEntry<Stl> m_entry;
124template <StlType Stl>
130 AbstractListFrontEnd(ValueObject &valobj)
131 : SyntheticChildrenFrontEnd(valobj) {}
134 ValueObject *m_head =
nullptr;
136 static constexpr bool g_use_loop_detect =
true;
137 size_t m_loop_detected = 0;
139 ListEntry<Stl> m_slow_runner;
140 ListEntry<Stl> m_fast_runner;
142 size_t m_list_capping_size = 0;
143 CompilerType m_element_type;
144 std::map<size_t, ListIterator<Stl>> m_iterators;
146 bool HasLoop(
size_t count);
150class LibCxxForwardListFrontEnd :
public AbstractListFrontEnd<StlType::LibCxx> {
152 LibCxxForwardListFrontEnd(ValueObject &valobj);
159class LibCxxListFrontEnd :
public AbstractListFrontEnd<StlType::LibCxx> {
171 ValueObject *m_tail =
nullptr;
174class MsvcStlForwardListFrontEnd
175 :
public AbstractListFrontEnd<StlType::MsvcStl> {
177 MsvcStlForwardListFrontEnd(ValueObject &valobj);
184class MsvcStlListFrontEnd :
public AbstractListFrontEnd<StlType::MsvcStl> {
195 ValueObject *m_tail =
nullptr;
204 return val_sp->GetCompilerType();
210template <StlType Stl>
215 m_list_capping_size = 0;
216 m_slow_runner.SetEntry(
nullptr);
217 m_fast_runner.SetEntry(
nullptr);
220 if (m_backend.GetTargetSP())
221 m_list_capping_size =
222 m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
223 if (m_list_capping_size == 0)
224 m_list_capping_size = 255;
237template <StlType Stl>
bool AbstractListFrontEnd<Stl>::HasLoop(
size_t count) {
238 if (!g_use_loop_detect)
244 if (m_loop_detected == 0) {
247 m_slow_runner = ListEntry<Stl>(m_head).next();
248 m_fast_runner = m_slow_runner.next();
256 const size_t steps_to_run = std::min(count, m_count);
257 while (m_loop_detected < steps_to_run && m_slow_runner && m_fast_runner &&
258 m_slow_runner != m_fast_runner) {
260 m_slow_runner = m_slow_runner.next();
261 m_fast_runner = m_fast_runner.next().next();
264 if (count <= m_loop_detected)
266 if (!m_slow_runner || !m_fast_runner)
268 return m_slow_runner == m_fast_runner;
271template <StlType Stl>
272ValueObjectSP AbstractListFrontEnd<Stl>::GetItem(
size_t idx) {
274 ListIterator<Stl> current(m_head);
276 auto cached_iterator = m_iterators.find(idx - 1);
277 if (cached_iterator != m_iterators.end()) {
278 current = cached_iterator->second;
283 m_iterators[idx] = current;
287LibCxxForwardListFrontEnd::LibCxxForwardListFrontEnd(
ValueObject &valobj)
288 : AbstractListFrontEnd(valobj) {
292llvm::Expected<uint32_t> LibCxxForwardListFrontEnd::CalculateNumChildren() {
296 ListEntry<StlType::LibCxx> current(m_head);
298 while (current && m_count < m_list_capping_size) {
300 current = current.next();
305ValueObjectSP LibCxxForwardListFrontEnd::GetChildAtIndex(uint32_t idx) {
306 if (idx >= CalculateNumChildrenIgnoringErrors())
312 if (HasLoop(idx + 1))
319 current_sp = current_sp->GetChildAtIndex(1);
327 current_sp->GetData(data,
error);
331 return CreateValueObjectFromData(llvm::formatv(
"[{0}]", idx).str(), data,
332 m_backend.GetExecutionContextRef(),
337 AbstractListFrontEnd::Update();
341 if (err.
Fail() || !backend_addr)
344 auto list_base_sp = m_backend.GetChildAtIndex(0);
350 *list_base_sp,
"__before_begin_",
"__before_begin_");
352 return ChildCacheState::eRefetch;
354 if (is_compressed_pair)
358 return ChildCacheState::eRefetch;
360 m_head = impl_sp->GetChildMemberWithName(
"__next_").get();
362 return ChildCacheState::eRefetch;
366 : AbstractListFrontEnd(*valobj_sp) {
371llvm::Expected<uint32_t> LibCxxListFrontEnd::CalculateNumChildren() {
374 if (!m_head || !m_tail || m_node_address == 0)
377 auto [size_node_sp, is_compressed_pair] =
379 if (is_compressed_pair)
383 m_count = size_node_sp->GetValueAsUnsigned(
UINT32_MAX);
388 uint64_t next_val = m_head->GetValueAsUnsigned(0);
390 if (next_val == 0 || prev_val == 0)
392 if (next_val == m_node_address)
394 if (next_val == prev_val)
397 ListEntry<StlType::LibCxx> current(m_head);
398 while (current.next() && current.next().value() != m_node_address) {
400 current = current.next();
401 if (size > m_list_capping_size)
404 return m_count = (size - 1);
408 static ConstString g_value(
"__value_");
409 static ConstString g_next(
"__next_");
411 if (idx >= CalculateNumChildrenIgnoringErrors())
414 if (!m_head || !m_tail || m_node_address == 0)
417 if (HasLoop(idx + 1))
424 current_sp = current_sp->GetChildAtIndex(1);
428 if (current_sp->GetName() == g_next) {
429 ProcessSP process_sp(current_sp->GetProcessSP());
434 lldb::addr_t addr = current_sp->GetParent()->GetPointerValue().address;
435 addr = addr + 2 * process_sp->GetAddressByteSize();
436 ExecutionContext exe_ctx(process_sp);
438 CreateValueObjectFromAddress(
"__value_", addr, exe_ctx, m_element_type);
447 current_sp->GetData(data,
error);
452 name.
Printf(
"[%" PRIu64
"]", (uint64_t)idx);
453 return CreateValueObjectFromData(name.
GetString(), data,
454 m_backend.GetExecutionContextRef(),
459 AbstractListFrontEnd::Update();
465 if (err.
Fail() || !backend_addr)
467 m_node_address = backend_addr->GetValueAsUnsigned(0);
470 ValueObjectSP impl_sp(m_backend.GetChildMemberWithName(
"__end_"));
473 m_head = impl_sp->GetChildMemberWithName(
"__next_").get();
478MsvcStlForwardListFrontEnd::MsvcStlForwardListFrontEnd(ValueObject &valobj)
479 : AbstractListFrontEnd(valobj) {
483llvm::Expected<uint32_t> MsvcStlForwardListFrontEnd::CalculateNumChildren() {
487 ListEntry<StlType::MsvcStl> current(m_head);
489 while (current && m_count < m_list_capping_size) {
491 current = current.next();
496ValueObjectSP MsvcStlForwardListFrontEnd::GetChildAtIndex(uint32_t idx) {
497 if (idx >= CalculateNumChildrenIgnoringErrors())
503 if (HasLoop(idx + 1))
510 current_sp = current_sp->GetChildAtIndex(1);
518 current_sp->GetData(data,
error);
522 return CreateValueObjectFromData(llvm::formatv(
"[{0}]", idx).str(), data,
523 m_backend.GetExecutionContextRef(),
528 AbstractListFrontEnd::Update();
531 m_backend.GetChildAtNamePath({
"_Mypair",
"_Myval2",
"_Myhead"}))
532 m_head = head_sp.get();
535 if (!m_element_type && m_head)
536 m_element_type = GetMsvcStlElementTypeFromHead(*m_head);
538 return ChildCacheState::eRefetch;
542 : AbstractListFrontEnd(*valobj_sp) {
547llvm::Expected<uint32_t> MsvcStlListFrontEnd::CalculateNumChildren() {
550 if (!m_head || !m_tail)
554 m_backend.GetChildAtNamePath({
"_Mypair",
"_Myval2",
"_Mysize"});
556 return llvm::createStringError(
"Failed to resolve size.");
558 m_count = size_sp->GetValueAsUnsigned(
UINT32_MAX);
560 return llvm::createStringError(
"Failed to read size value.");
566 if (idx >= CalculateNumChildrenIgnoringErrors())
569 if (!m_head || !m_tail)
572 if (HasLoop(idx + 1))
579 current_sp = current_sp->GetChildAtIndex(2);
587 current_sp->GetData(data,
error);
592 name.
Printf(
"[%" PRIu64
"]", (uint64_t)idx);
593 return CreateValueObjectFromData(name.
GetString(), data,
594 m_backend.GetExecutionContextRef(),
599 AbstractListFrontEnd::Update();
611 m_head = first.get();
615 if (!m_element_type && m_head)
616 m_element_type = GetMsvcStlElementTypeFromHead(*m_head);
623 return (valobj_sp ?
new LibCxxListFrontEnd(valobj_sp) :
nullptr);
626SyntheticChildrenFrontEnd *
629 return valobj_sp ?
new LibCxxForwardListFrontEnd(*valobj_sp) : nullptr;
634 return valobj_sp->GetChildMemberWithName(
"_Mypair") !=
nullptr;
642 return (valobj_sp ?
new MsvcStlListFrontEnd(valobj_sp) :
nullptr);
648 return valobj_sp ?
new MsvcStlForwardListFrontEnd(*valobj_sp) : nullptr;
static llvm::raw_ostream & error(Stream &strm)
static void advance(TSLexer *lexer)
static std::optional< size_t > CalculateNumChildren(CompilerType container_elem_type, uint64_t num_elements, CompilerType element_type)
Calculates the number of elements stored in a container (with element type 'container_elem_type') as ...
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
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 uint64_t GetValueAsUnsigned(uint64_t fail_value, bool *success=nullptr)
virtual lldb::ValueObjectSP GetChildMemberWithName(llvm::StringRef name, bool can_create=true)
lldb::ValueObjectSP GetChildAtNamePath(llvm::ArrayRef< llvm::StringRef > names)
virtual lldb::ValueObjectSP GetNonSyntheticValue()
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
bool operator!=(const Address &lhs, const Address &rhs)
ChildCacheState
Specifies if children need to be re-computed after a call to SyntheticChildrenFrontEnd::Update.
@ eRefetch
Children need to be recomputed dynamically.
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
std::shared_ptr< lldb_private::Process > ProcessSP
bool LLDB_API operator==(const SBAddress &lhs, const SBAddress &rhs)