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>
127 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name)
override {
130 return llvm::createStringError(
"Type has no child named '%s'",
133 return *optional_idx;
138 AbstractListFrontEnd(ValueObject &valobj)
139 : SyntheticChildrenFrontEnd(valobj) {}
142 ValueObject *m_head =
nullptr;
144 static constexpr bool g_use_loop_detect =
true;
145 size_t m_loop_detected = 0;
147 ListEntry<Stl> m_slow_runner;
148 ListEntry<Stl> m_fast_runner;
150 size_t m_list_capping_size = 0;
151 CompilerType m_element_type;
152 std::map<size_t, ListIterator<Stl>> m_iterators;
154 bool HasLoop(
size_t count);
158class LibCxxForwardListFrontEnd :
public AbstractListFrontEnd<StlType::LibCxx> {
160 LibCxxForwardListFrontEnd(ValueObject &valobj);
167class LibCxxListFrontEnd :
public AbstractListFrontEnd<StlType::LibCxx> {
179 ValueObject *m_tail =
nullptr;
182class MsvcStlForwardListFrontEnd
183 :
public AbstractListFrontEnd<StlType::MsvcStl> {
185 MsvcStlForwardListFrontEnd(ValueObject &valobj);
192class MsvcStlListFrontEnd :
public AbstractListFrontEnd<StlType::MsvcStl> {
203 ValueObject *m_tail =
nullptr;
212 return val_sp->GetCompilerType();
218template <StlType Stl>
223 m_list_capping_size = 0;
224 m_slow_runner.SetEntry(
nullptr);
225 m_fast_runner.SetEntry(
nullptr);
228 if (m_backend.GetTargetSP())
229 m_list_capping_size =
230 m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
231 if (m_list_capping_size == 0)
232 m_list_capping_size = 255;
245template <StlType Stl>
bool AbstractListFrontEnd<Stl>::HasLoop(
size_t count) {
246 if (!g_use_loop_detect)
252 if (m_loop_detected == 0) {
255 m_slow_runner = ListEntry<Stl>(m_head).next();
256 m_fast_runner = m_slow_runner.next();
264 const size_t steps_to_run = std::min(count, m_count);
265 while (m_loop_detected < steps_to_run && m_slow_runner && m_fast_runner &&
266 m_slow_runner != m_fast_runner) {
268 m_slow_runner = m_slow_runner.next();
269 m_fast_runner = m_fast_runner.next().next();
272 if (count <= m_loop_detected)
274 if (!m_slow_runner || !m_fast_runner)
276 return m_slow_runner == m_fast_runner;
279template <StlType Stl>
280ValueObjectSP AbstractListFrontEnd<Stl>::GetItem(
size_t idx) {
281 size_t advance = idx;
282 ListIterator<Stl> current(m_head);
284 auto cached_iterator = m_iterators.find(idx - 1);
285 if (cached_iterator != m_iterators.end()) {
286 current = cached_iterator->second;
291 m_iterators[idx] = current;
295LibCxxForwardListFrontEnd::LibCxxForwardListFrontEnd(
ValueObject &valobj)
296 : AbstractListFrontEnd(valobj) {
300llvm::Expected<uint32_t> LibCxxForwardListFrontEnd::CalculateNumChildren() {
304 ListEntry<StlType::LibCxx> current(m_head);
306 while (current && m_count < m_list_capping_size) {
308 current = current.next();
313ValueObjectSP LibCxxForwardListFrontEnd::GetChildAtIndex(uint32_t idx) {
314 if (idx >= CalculateNumChildrenIgnoringErrors())
320 if (HasLoop(idx + 1))
327 current_sp = current_sp->GetChildAtIndex(1);
335 current_sp->GetData(data,
error);
339 return CreateValueObjectFromData(llvm::formatv(
"[{0}]", idx).str(), data,
340 m_backend.GetExecutionContextRef(),
345 AbstractListFrontEnd::Update();
349 if (err.
Fail() || !backend_addr)
352 auto list_base_sp = m_backend.GetChildAtIndex(0);
357 auto [impl_sp, is_compressed_pair] =
359 "__before_begin_",
"__before_begin_");
361 return ChildCacheState::eRefetch;
363 if (is_compressed_pair)
367 return ChildCacheState::eRefetch;
369 m_head = impl_sp->GetChildMemberWithName(
"__next_").get();
371 return ChildCacheState::eRefetch;
375 : AbstractListFrontEnd(*valobj_sp) {
380llvm::Expected<uint32_t> LibCxxListFrontEnd::CalculateNumChildren() {
383 if (!m_head || !m_tail || m_node_address == 0)
387 m_backend, 1,
"__size_",
"__size_alloc_");
388 if (is_compressed_pair)
392 m_count = size_node_sp->GetValueAsUnsigned(
UINT32_MAX);
397 uint64_t next_val = m_head->GetValueAsUnsigned(0);
399 if (next_val == 0 || prev_val == 0)
401 if (next_val == m_node_address)
403 if (next_val == prev_val)
406 ListEntry<StlType::LibCxx> current(m_head);
407 while (current.next() && current.next().value() != m_node_address) {
409 current = current.next();
410 if (size > m_list_capping_size)
413 return m_count = (size - 1);
417 static ConstString g_value(
"__value_");
418 static ConstString g_next(
"__next_");
420 if (idx >= CalculateNumChildrenIgnoringErrors())
423 if (!m_head || !m_tail || m_node_address == 0)
426 if (HasLoop(idx + 1))
433 current_sp = current_sp->GetChildAtIndex(1);
437 if (current_sp->GetName() == g_next) {
438 ProcessSP process_sp(current_sp->GetProcessSP());
443 lldb::addr_t addr = current_sp->GetParent()->GetPointerValue().address;
444 addr = addr + 2 * process_sp->GetAddressByteSize();
445 ExecutionContext exe_ctx(process_sp);
447 CreateValueObjectFromAddress(
"__value_", addr, exe_ctx, m_element_type);
456 current_sp->GetData(data,
error);
461 name.
Printf(
"[%" PRIu64
"]", (uint64_t)idx);
462 return CreateValueObjectFromData(name.
GetString(), data,
463 m_backend.GetExecutionContextRef(),
468 AbstractListFrontEnd::Update();
474 if (err.
Fail() || !backend_addr)
476 m_node_address = backend_addr->GetValueAsUnsigned(0);
479 ValueObjectSP impl_sp(m_backend.GetChildMemberWithName(
"__end_"));
482 m_head = impl_sp->GetChildMemberWithName(
"__next_").get();
487MsvcStlForwardListFrontEnd::MsvcStlForwardListFrontEnd(ValueObject &valobj)
488 : AbstractListFrontEnd(valobj) {
492llvm::Expected<uint32_t> MsvcStlForwardListFrontEnd::CalculateNumChildren() {
496 ListEntry<StlType::MsvcStl> current(m_head);
498 while (current && m_count < m_list_capping_size) {
500 current = current.next();
505ValueObjectSP MsvcStlForwardListFrontEnd::GetChildAtIndex(uint32_t idx) {
506 if (idx >= CalculateNumChildrenIgnoringErrors())
512 if (HasLoop(idx + 1))
519 current_sp = current_sp->GetChildAtIndex(1);
527 current_sp->GetData(data,
error);
531 return CreateValueObjectFromData(llvm::formatv(
"[{0}]", idx).str(), data,
532 m_backend.GetExecutionContextRef(),
537 AbstractListFrontEnd::Update();
540 m_backend.GetChildAtNamePath({
"_Mypair",
"_Myval2",
"_Myhead"}))
541 m_head = head_sp.get();
544 if (!m_element_type && m_head)
545 m_element_type = GetMsvcStlElementTypeFromHead(*m_head);
547 return ChildCacheState::eRefetch;
551 : AbstractListFrontEnd(*valobj_sp) {
556llvm::Expected<uint32_t> MsvcStlListFrontEnd::CalculateNumChildren() {
559 if (!m_head || !m_tail)
563 m_backend.GetChildAtNamePath({
"_Mypair",
"_Myval2",
"_Mysize"});
565 return llvm::createStringError(
"Failed to resolve size.");
567 m_count = size_sp->GetValueAsUnsigned(
UINT32_MAX);
569 return llvm::createStringError(
"Failed to read size value.");
575 if (idx >= CalculateNumChildrenIgnoringErrors())
578 if (!m_head || !m_tail)
581 if (HasLoop(idx + 1))
588 current_sp = current_sp->GetChildAtIndex(2);
596 current_sp->GetData(data,
error);
601 name.
Printf(
"[%" PRIu64
"]", (uint64_t)idx);
602 return CreateValueObjectFromData(name.
GetString(), data,
603 m_backend.GetExecutionContextRef(),
608 AbstractListFrontEnd::Update();
620 m_head = first.get();
624 if (!m_element_type && m_head)
625 m_element_type = GetMsvcStlElementTypeFromHead(*m_head);
632 return (valobj_sp ?
new LibCxxListFrontEnd(valobj_sp) :
nullptr);
635SyntheticChildrenFrontEnd *
638 return valobj_sp ?
new LibCxxForwardListFrontEnd(*valobj_sp) : nullptr;
643 return valobj_sp->GetChildMemberWithName(
"_Mypair") !=
nullptr;
651 return (valobj_sp ?
new MsvcStlListFrontEnd(valobj_sp) :
nullptr);
657 return valobj_sp ?
new MsvcStlForwardListFrontEnd(*valobj_sp) : nullptr;
static llvm::raw_ostream & error(Stream &strm)
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
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
const char * GetCString() const
Get the string value as a C string.
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)