1 //===-- LibCxxUnorderedMap.cpp ----------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
11 #include "lldb/Core/ValueObject.h"
12 #include "lldb/Core/ValueObjectConstResult.h"
13 #include "lldb/DataFormatters/FormattersHelpers.h"
14 #include "lldb/Symbol/ClangASTContext.h"
15 #include "lldb/Target/Target.h"
16 #include "lldb/Utility/DataBufferHeap.h"
17 #include "lldb/Utility/Endian.h"
18 #include "lldb/Utility/Status.h"
19 #include "lldb/Utility/Stream.h"
22 using namespace lldb_private;
23 using namespace lldb_private::formatters;
25 namespace lldb_private {
26 namespace formatters {
27 class LibcxxStdUnorderedMapSyntheticFrontEnd
28 : public SyntheticChildrenFrontEnd {
30 LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
32 ~LibcxxStdUnorderedMapSyntheticFrontEnd() override = default;
34 size_t CalculateNumChildren() override;
36 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
38 bool Update() override;
40 bool MightHaveChildren() override;
42 size_t GetIndexOfChildWithName(ConstString name) override;
45 CompilerType m_element_type;
46 CompilerType m_node_type;
48 size_t m_num_elements;
49 ValueObject *m_next_element;
50 std::vector<std::pair<ValueObject *, uint64_t>> m_elements_cache;
52 } // namespace formatters
53 } // namespace lldb_private
55 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
56 LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
57 : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type(), m_tree(nullptr),
58 m_num_elements(0), m_next_element(nullptr), m_elements_cache() {
63 size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
64 CalculateNumChildren() {
65 if (m_num_elements != UINT32_MAX)
66 return m_num_elements;
70 lldb::ValueObjectSP lldb_private::formatters::
71 LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
72 if (idx >= CalculateNumChildren())
73 return lldb::ValueObjectSP();
74 if (m_tree == nullptr)
75 return lldb::ValueObjectSP();
77 while (idx >= m_elements_cache.size()) {
78 if (m_next_element == nullptr)
79 return lldb::ValueObjectSP();
82 ValueObjectSP node_sp = m_next_element->Dereference(error);
83 if (!node_sp || error.Fail())
84 return lldb::ValueObjectSP();
86 ValueObjectSP value_sp =
87 node_sp->GetChildMemberWithName(ConstString("__value_"), true);
88 ValueObjectSP hash_sp =
89 node_sp->GetChildMemberWithName(ConstString("__hash_"), true);
90 if (!hash_sp || !value_sp) {
91 if (!m_element_type) {
92 auto p1_sp = m_backend.GetChildAtNamePath({ConstString("__table_"),
93 ConstString("__p1_")});
97 ValueObjectSP first_sp = nullptr;
98 switch (p1_sp->GetCompilerType().GetNumDirectBaseClasses()) {
100 // Assume a pre llvm r300140 __compressed_pair implementation:
101 first_sp = p1_sp->GetChildMemberWithName(ConstString("__first_"),
105 // Assume a post llvm r300140 __compressed_pair implementation:
106 ValueObjectSP first_elem_parent_sp =
107 p1_sp->GetChildAtIndex(0, true);
108 first_sp = p1_sp->GetChildMemberWithName(ConstString("__value_"),
118 m_element_type = first_sp->GetCompilerType();
119 m_element_type = m_element_type.GetTypeTemplateArgument(0);
120 m_element_type = m_element_type.GetPointeeType();
121 m_node_type = m_element_type;
122 m_element_type = m_element_type.GetTypeTemplateArgument(0);
125 m_element_type.GetFieldAtIndex(0, name, nullptr, nullptr, nullptr);
126 m_element_type = m_element_type.GetTypedefedType();
130 node_sp = node_sp->Cast(m_node_type);
131 value_sp = node_sp->GetChildMemberWithName(ConstString("__value_"), true);
132 hash_sp = node_sp->GetChildMemberWithName(ConstString("__hash_"), true);
133 if (!value_sp || !hash_sp)
136 m_elements_cache.push_back(
137 {value_sp.get(), hash_sp->GetValueAsUnsigned(0)});
139 node_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
140 if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0)
141 m_next_element = nullptr;
144 std::pair<ValueObject *, uint64_t> val_hash = m_elements_cache[idx];
146 return lldb::ValueObjectSP();
148 stream.Printf("[%" PRIu64 "]", (uint64_t)idx);
151 val_hash.first->GetData(data, error);
153 return lldb::ValueObjectSP();
154 const bool thread_and_frame_only_if_stopped = true;
155 ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock(
156 thread_and_frame_only_if_stopped);
157 return CreateValueObjectFromData(stream.GetString(), data, exe_ctx,
158 val_hash.first->GetCompilerType());
161 bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
163 m_num_elements = UINT32_MAX;
164 m_next_element = nullptr;
165 m_elements_cache.clear();
166 ValueObjectSP table_sp =
167 m_backend.GetChildMemberWithName(ConstString("__table_"), true);
171 ValueObjectSP p2_sp = table_sp->GetChildMemberWithName(
172 ConstString("__p2_"), true);
173 ValueObjectSP num_elements_sp = nullptr;
174 llvm::SmallVector<ConstString, 3> next_path;
175 switch (p2_sp->GetCompilerType().GetNumDirectBaseClasses()) {
177 // Assume a pre llvm r300140 __compressed_pair implementation:
178 num_elements_sp = p2_sp->GetChildMemberWithName(
179 ConstString("__first_"), true);
180 next_path.append({ConstString("__p1_"), ConstString("__first_"),
181 ConstString("__next_")});
184 // Assume a post llvm r300140 __compressed_pair implementation:
185 ValueObjectSP first_elem_parent = p2_sp->GetChildAtIndex(0, true);
186 num_elements_sp = first_elem_parent->GetChildMemberWithName(
187 ConstString("__value_"), true);
188 next_path.append({ConstString("__p1_"), ConstString("__value_"),
189 ConstString("__next_")});
196 if (!num_elements_sp)
198 m_num_elements = num_elements_sp->GetValueAsUnsigned(0);
199 m_tree = table_sp->GetChildAtNamePath(next_path).get();
200 if (m_num_elements > 0)
202 table_sp->GetChildAtNamePath(next_path).get();
206 bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
207 MightHaveChildren() {
211 size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
212 GetIndexOfChildWithName(ConstString name) {
213 return ExtractIndexFromString(name.GetCString());
216 SyntheticChildrenFrontEnd *
217 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator(
218 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
219 return (valobj_sp ? new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp)