1 //===-- LibCxxUnorderedMap.cpp ----------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
12 // Other libraries and framework includes
16 #include "lldb/Core/ValueObject.h"
17 #include "lldb/Core/ValueObjectConstResult.h"
18 #include "lldb/DataFormatters/FormattersHelpers.h"
19 #include "lldb/Symbol/ClangASTContext.h"
20 #include "lldb/Target/Target.h"
21 #include "lldb/Utility/DataBufferHeap.h"
22 #include "lldb/Utility/Endian.h"
23 #include "lldb/Utility/Status.h"
24 #include "lldb/Utility/Stream.h"
27 using namespace lldb_private;
28 using namespace lldb_private::formatters;
30 namespace lldb_private {
31 namespace formatters {
32 class LibcxxStdUnorderedMapSyntheticFrontEnd
33 : public SyntheticChildrenFrontEnd {
35 LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
37 ~LibcxxStdUnorderedMapSyntheticFrontEnd() override = default;
39 size_t CalculateNumChildren() override;
41 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
43 bool Update() override;
45 bool MightHaveChildren() override;
47 size_t GetIndexOfChildWithName(const ConstString &name) override;
50 CompilerType m_element_type;
51 CompilerType m_node_type;
53 size_t m_num_elements;
54 ValueObject *m_next_element;
55 std::vector<std::pair<ValueObject *, uint64_t>> m_elements_cache;
57 } // namespace formatters
58 } // namespace lldb_private
60 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
61 LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
62 : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type(), m_tree(nullptr),
63 m_num_elements(0), m_next_element(nullptr), m_elements_cache() {
68 size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
69 CalculateNumChildren() {
70 if (m_num_elements != UINT32_MAX)
71 return m_num_elements;
75 lldb::ValueObjectSP lldb_private::formatters::
76 LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
77 if (idx >= CalculateNumChildren())
78 return lldb::ValueObjectSP();
79 if (m_tree == nullptr)
80 return lldb::ValueObjectSP();
82 while (idx >= m_elements_cache.size()) {
83 if (m_next_element == nullptr)
84 return lldb::ValueObjectSP();
87 ValueObjectSP node_sp = m_next_element->Dereference(error);
88 if (!node_sp || error.Fail())
89 return lldb::ValueObjectSP();
91 ValueObjectSP value_sp =
92 node_sp->GetChildMemberWithName(ConstString("__value_"), true);
93 ValueObjectSP hash_sp =
94 node_sp->GetChildMemberWithName(ConstString("__hash_"), true);
95 if (!hash_sp || !value_sp) {
96 if (!m_element_type) {
97 auto p1_sp = m_backend.GetChildAtNamePath({ConstString("__table_"),
98 ConstString("__p1_")});
102 ValueObjectSP first_sp = nullptr;
103 switch (p1_sp->GetCompilerType().GetNumDirectBaseClasses()) {
105 // Assume a pre llvm r300140 __compressed_pair implementation:
106 first_sp = p1_sp->GetChildMemberWithName(ConstString("__first_"),
110 // Assume a post llvm r300140 __compressed_pair implementation:
111 ValueObjectSP first_elem_parent_sp =
112 p1_sp->GetChildAtIndex(0, true);
113 first_sp = p1_sp->GetChildMemberWithName(ConstString("__value_"),
123 m_element_type = first_sp->GetCompilerType();
124 m_element_type = m_element_type.GetTypeTemplateArgument(0);
125 m_element_type = m_element_type.GetPointeeType();
126 m_node_type = m_element_type;
127 m_element_type = m_element_type.GetTypeTemplateArgument(0);
130 m_element_type.GetFieldAtIndex(0, name, nullptr, nullptr, nullptr);
131 m_element_type = m_element_type.GetTypedefedType();
135 node_sp = node_sp->Cast(m_node_type);
136 value_sp = node_sp->GetChildMemberWithName(ConstString("__value_"), true);
137 hash_sp = node_sp->GetChildMemberWithName(ConstString("__hash_"), true);
138 if (!value_sp || !hash_sp)
141 m_elements_cache.push_back(
142 {value_sp.get(), hash_sp->GetValueAsUnsigned(0)});
144 node_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
145 if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0)
146 m_next_element = nullptr;
149 std::pair<ValueObject *, uint64_t> val_hash = m_elements_cache[idx];
151 return lldb::ValueObjectSP();
153 stream.Printf("[%" PRIu64 "]", (uint64_t)idx);
156 val_hash.first->GetData(data, error);
158 return lldb::ValueObjectSP();
159 const bool thread_and_frame_only_if_stopped = true;
160 ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock(
161 thread_and_frame_only_if_stopped);
162 return CreateValueObjectFromData(stream.GetString(), data, exe_ctx,
163 val_hash.first->GetCompilerType());
166 bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
168 m_num_elements = UINT32_MAX;
169 m_next_element = nullptr;
170 m_elements_cache.clear();
171 ValueObjectSP table_sp =
172 m_backend.GetChildMemberWithName(ConstString("__table_"), true);
176 ValueObjectSP p2_sp = table_sp->GetChildMemberWithName(
177 ConstString("__p2_"), true);
178 ValueObjectSP num_elements_sp = nullptr;
179 llvm::SmallVector<ConstString, 3> next_path;
180 switch (p2_sp->GetCompilerType().GetNumDirectBaseClasses()) {
182 // Assume a pre llvm r300140 __compressed_pair implementation:
183 num_elements_sp = p2_sp->GetChildMemberWithName(
184 ConstString("__first_"), true);
185 next_path.append({ConstString("__p1_"), ConstString("__first_"),
186 ConstString("__next_")});
189 // Assume a post llvm r300140 __compressed_pair implementation:
190 ValueObjectSP first_elem_parent = p2_sp->GetChildAtIndex(0, true);
191 num_elements_sp = first_elem_parent->GetChildMemberWithName(
192 ConstString("__value_"), true);
193 next_path.append({ConstString("__p1_"), ConstString("__value_"),
194 ConstString("__next_")});
201 if (!num_elements_sp)
203 m_num_elements = num_elements_sp->GetValueAsUnsigned(0);
204 m_tree = table_sp->GetChildAtNamePath(next_path).get();
205 if (m_num_elements > 0)
207 table_sp->GetChildAtNamePath(next_path).get();
211 bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
212 MightHaveChildren() {
216 size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
217 GetIndexOfChildWithName(const ConstString &name) {
218 return ExtractIndexFromString(name.GetCString());
221 SyntheticChildrenFrontEnd *
222 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator(
223 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
224 return (valobj_sp ? new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp)