1//===-- LibCxxSpan.cpp ----------------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "LibCxx.h"
10
11#include "lldb/DataFormatters/FormattersHelpers.h"
12#include "lldb/Utility/ConstString.h"
13#include "lldb/ValueObject/ValueObject.h"
14#include "llvm/ADT/APSInt.h"
15#include <optional>
16
17using namespace lldb;
18using namespace lldb_private;
19using namespace lldb_private::formatters;
20
21namespace lldb_private {
22namespace formatters {
23
24class LibcxxStdSpanSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
25public:
26 LibcxxStdSpanSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
27
28 ~LibcxxStdSpanSyntheticFrontEnd() override = default;
29
30 llvm::Expected<uint32_t> CalculateNumChildren() override;
31
32 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
33
34 /// Determines properties of the std::span<> associated with this object
35 //
36 // std::span can either be instantiated with a compile-time known
37 // extent or a std::dynamic_extent (this is the default if only the
38 // type template argument is provided). The layout of std::span
39 // depends on whether the extent is dynamic or not. For static
40 // extents (e.g., std::span<int, 9>):
41 //
42 // (std::__1::span<const int, 9>) s = {
43 // __data = 0x000000016fdff494
44 // }
45 //
46 // For dynamic extents, e.g., std::span<int>, the layout is:
47 //
48 // (std::__1::span<const int, 18446744073709551615>) s = {
49 // __data = 0x000000016fdff494
50 // __size = 6
51 // }
52 //
53 // This function checks for a '__size' member to determine the number
54 // of elements in the span. If no such member exists, we get the size
55 // from the only other place it can be: the template argument.
56 lldb::ChildCacheState Update() override;
57
58 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
59
60private:
61 ValueObject *m_start = nullptr; ///< First element of span. Held, not owned.
62 CompilerType m_element_type{}; ///< Type of span elements.
63 size_t m_num_elements = 0; ///< Number of elements in span.
64 uint32_t m_element_size = 0; ///< Size in bytes of each span element.
65};
66
67lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::
68 LibcxxStdSpanSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
69 : SyntheticChildrenFrontEnd(*valobj_sp) {
70 if (valobj_sp)
71 Update();
72}
73
74llvm::Expected<uint32_t> lldb_private::formatters::
75 LibcxxStdSpanSyntheticFrontEnd::CalculateNumChildren() {
76 return m_num_elements;
77}
78
79lldb::ValueObjectSP
80lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::GetChildAtIndex(
81 uint32_t idx) {
82 if (!m_start)
83 return {};
84
85 uint64_t offset = idx * m_element_size;
86 offset = offset + m_start->GetValueAsUnsigned(fail_value: 0);
87 StreamString name;
88 name.Printf(format: "[%" PRIu64 "]", (uint64_t)idx);
89 return CreateValueObjectFromAddress(name: name.GetString(), address: offset,
90 exe_ctx: m_backend.GetExecutionContextRef(),
91 type: m_element_type);
92}
93
94lldb::ChildCacheState
95lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::Update() {
96 // Get element type.
97 ValueObjectSP data_type_finder_sp = GetChildMemberWithName(
98 obj&: m_backend, alternative_names: {ConstString("__data_"), ConstString("__data")});
99 if (!data_type_finder_sp)
100 return lldb::ChildCacheState::eRefetch;
101
102 m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType();
103
104 // Get element size.
105 llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(exe_scope: nullptr);
106 if (!size_or_err)
107 LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
108 "{0}");
109 else {
110 m_element_size = *size_or_err;
111
112 // Get data.
113 if (m_element_size > 0) {
114 m_start = data_type_finder_sp.get();
115 }
116
117 // Get number of elements.
118 if (auto size_sp = GetChildMemberWithName(
119 obj&: m_backend, alternative_names: {ConstString("__size_"), ConstString("__size")})) {
120 m_num_elements = size_sp->GetValueAsUnsigned(fail_value: 0);
121 } else if (auto arg =
122 m_backend.GetCompilerType().GetIntegralTemplateArgument(idx: 1)) {
123
124 m_num_elements = arg->value.GetAPSInt().getLimitedValue();
125 }
126 }
127
128 return lldb::ChildCacheState::eReuse;
129}
130
131llvm::Expected<size_t> lldb_private::formatters::
132 LibcxxStdSpanSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
133 if (!m_start)
134 return llvm::createStringError(Fmt: "Type has no child named '%s'",
135 Vals: name.AsCString());
136 auto optional_idx = formatters::ExtractIndexFromString(item_name: name.GetCString());
137 if (!optional_idx) {
138 return llvm::createStringError(Fmt: "Type has no child named '%s'",
139 Vals: name.AsCString());
140 }
141 return *optional_idx;
142}
143
144lldb_private::SyntheticChildrenFrontEnd *
145LibcxxStdSpanSyntheticFrontEndCreator(CXXSyntheticChildren *,
146 lldb::ValueObjectSP valobj_sp) {
147 if (!valobj_sp)
148 return nullptr;
149 CompilerType type = valobj_sp->GetCompilerType();
150 if (!type.IsValid() || type.GetNumTemplateArguments() != 2)
151 return nullptr;
152 return new LibcxxStdSpanSyntheticFrontEnd(valobj_sp);
153}
154
155} // namespace formatters
156} // namespace lldb_private
157

source code of lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp