1 //===-- OptionValueArray.cpp ----------------------------------------------===//
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 //===----------------------------------------------------------------------===//
9 #include "lldb/Interpreter/OptionValueArray.h"
11 #include "lldb/Utility/Args.h"
12 #include "lldb/Utility/Stream.h"
15 using namespace lldb_private
;
17 void OptionValueArray::DumpValue(const ExecutionContext
*exe_ctx
, Stream
&strm
,
19 const Type array_element_type
= ConvertTypeMaskToType(m_type_mask
);
20 if (dump_mask
& eDumpOptionType
) {
21 if ((GetType() == eTypeArray
) && (m_type_mask
!= eTypeInvalid
))
22 strm
.Printf("(%s of %ss)", GetTypeAsCString(),
23 GetBuiltinTypeAsCString(array_element_type
));
25 strm
.Printf("(%s)", GetTypeAsCString());
27 if (dump_mask
& eDumpOptionValue
) {
28 const bool one_line
= dump_mask
& eDumpOptionCommand
;
29 const uint32_t size
= m_values
.size();
30 if (dump_mask
& eDumpOptionType
)
31 strm
.Printf(" =%s", (m_values
.size() > 0 && !one_line
) ? "\n" : "");
34 for (uint32_t i
= 0; i
< size
; ++i
) {
37 strm
.Printf("[%u]: ", i
);
39 const uint32_t extra_dump_options
= m_raw_value_dump
? eDumpOptionRaw
: 0;
40 switch (array_element_type
) {
45 case eTypeFileSpecList
:
47 m_values
[i
]->DumpValue(exe_ctx
, strm
, dump_mask
| extra_dump_options
);
54 case eTypeFileLineColumn
:
60 // No need to show the type for dictionaries of simple items
61 m_values
[i
]->DumpValue(exe_ctx
, strm
, (dump_mask
& (~eDumpOptionType
)) |
78 llvm::json::Value
OptionValueArray::ToJSON(const ExecutionContext
*exe_ctx
) {
79 llvm::json::Array json_array
;
80 const uint32_t size
= m_values
.size();
81 for (uint32_t i
= 0; i
< size
; ++i
)
82 json_array
.emplace_back(m_values
[i
]->ToJSON(exe_ctx
));
86 Status
OptionValueArray::SetValueFromString(llvm::StringRef value
,
87 VarSetOperationType op
) {
88 Args
args(value
.str());
89 Status error
= SetArgs(args
, op
);
96 OptionValueArray::GetSubValue(const ExecutionContext
*exe_ctx
,
97 llvm::StringRef name
, Status
&error
) const {
98 if (name
.empty() || name
.front() != '[') {
99 error
.SetErrorStringWithFormat(
100 "invalid value path '%s', %s values only support '[<index>]' subvalues "
101 "where <index> is a positive or negative array index",
102 name
.str().c_str(), GetTypeAsCString());
106 name
= name
.drop_front();
107 llvm::StringRef index
, sub_value
;
108 std::tie(index
, sub_value
) = name
.split(']');
109 if (index
.size() == name
.size()) {
110 // Couldn't find a closing bracket
114 const size_t array_count
= m_values
.size();
116 if (index
.getAsInteger(0, idx
))
119 uint32_t new_idx
= UINT32_MAX
;
121 // Access from the end of the array if the index is negative
122 new_idx
= array_count
- idx
;
124 // Just a standard index
128 if (new_idx
< array_count
) {
129 if (m_values
[new_idx
]) {
130 if (!sub_value
.empty())
131 return m_values
[new_idx
]->GetSubValue(exe_ctx
, sub_value
, error
);
133 return m_values
[new_idx
];
136 if (array_count
== 0)
137 error
.SetErrorStringWithFormat(
138 "index %i is not valid for an empty array", idx
);
140 error
.SetErrorStringWithFormat(
141 "index %i out of range, valid values are 0 through %" PRIu64
,
142 idx
, (uint64_t)(array_count
- 1));
144 error
.SetErrorStringWithFormat("negative index %i out of range, "
145 "valid values are -1 through "
147 idx
, (uint64_t)array_count
);
149 return OptionValueSP();
152 size_t OptionValueArray::GetArgs(Args
&args
) const {
154 const uint32_t size
= m_values
.size();
155 for (uint32_t i
= 0; i
< size
; ++i
) {
156 auto string_value
= m_values
[i
]->GetValueAs
<llvm::StringRef
>();
158 args
.AppendArgument(*string_value
);
161 return args
.GetArgumentCount();
164 Status
OptionValueArray::SetArgs(const Args
&args
, VarSetOperationType op
) {
166 const size_t argc
= args
.GetArgumentCount();
168 case eVarSetOperationInvalid
:
169 error
.SetErrorString("unsupported operation");
172 case eVarSetOperationInsertBefore
:
173 case eVarSetOperationInsertAfter
:
176 const uint32_t count
= GetSize();
177 if (!llvm::to_integer(args
.GetArgumentAtIndex(0), idx
) || idx
> count
) {
178 error
.SetErrorStringWithFormat(
179 "invalid insert array index %s, index must be 0 through %u",
180 args
.GetArgumentAtIndex(0), count
);
182 if (op
== eVarSetOperationInsertAfter
)
184 for (size_t i
= 1; i
< argc
; ++i
, ++idx
) {
185 lldb::OptionValueSP
value_sp(CreateValueFromCStringForTypeMask(
186 args
.GetArgumentAtIndex(i
), m_type_mask
, error
));
190 if (idx
>= m_values
.size())
191 m_values
.push_back(value_sp
);
193 m_values
.insert(m_values
.begin() + idx
, value_sp
);
195 error
.SetErrorString(
196 "array of complex types must subclass OptionValueArray");
202 error
.SetErrorString("insert operation takes an array index followed by "
203 "one or more values");
207 case eVarSetOperationRemove
:
209 const uint32_t size
= m_values
.size();
210 std::vector
<int> remove_indexes
;
211 bool all_indexes_valid
= true;
213 for (i
= 0; i
< argc
; ++i
) {
215 if (!llvm::to_integer(args
.GetArgumentAtIndex(i
), idx
) || idx
>= size
) {
216 all_indexes_valid
= false;
219 remove_indexes
.push_back(idx
);
222 if (all_indexes_valid
) {
223 size_t num_remove_indexes
= remove_indexes
.size();
224 if (num_remove_indexes
) {
225 // Sort and then erase in reverse so indexes are always valid
226 if (num_remove_indexes
> 1) {
227 llvm::sort(remove_indexes
);
228 for (std::vector
<int>::const_reverse_iterator
229 pos
= remove_indexes
.rbegin(),
230 end
= remove_indexes
.rend();
232 m_values
.erase(m_values
.begin() + *pos
);
236 m_values
.erase(m_values
.begin() + remove_indexes
.front());
240 error
.SetErrorStringWithFormat(
241 "invalid array index '%s', aborting remove operation",
242 args
.GetArgumentAtIndex(i
));
245 error
.SetErrorString("remove operation takes one or more array indices");
249 case eVarSetOperationClear
:
253 case eVarSetOperationReplace
:
256 const uint32_t count
= GetSize();
257 if (!llvm::to_integer(args
.GetArgumentAtIndex(0), idx
) || idx
> count
) {
258 error
.SetErrorStringWithFormat(
259 "invalid replace array index %s, index must be 0 through %u",
260 args
.GetArgumentAtIndex(0), count
);
262 for (size_t i
= 1; i
< argc
; ++i
, ++idx
) {
263 lldb::OptionValueSP
value_sp(CreateValueFromCStringForTypeMask(
264 args
.GetArgumentAtIndex(i
), m_type_mask
, error
));
269 m_values
[idx
] = value_sp
;
271 m_values
.push_back(value_sp
);
273 error
.SetErrorString(
274 "array of complex types must subclass OptionValueArray");
280 error
.SetErrorString("replace operation takes an array index followed by "
281 "one or more values");
285 case eVarSetOperationAssign
:
287 // Fall through to append case
289 case eVarSetOperationAppend
:
290 for (size_t i
= 0; i
< argc
; ++i
) {
291 lldb::OptionValueSP
value_sp(CreateValueFromCStringForTypeMask(
292 args
.GetArgumentAtIndex(i
), m_type_mask
, error
));
296 m_value_was_set
= true;
297 AppendValue(value_sp
);
299 error
.SetErrorString(
300 "array of complex types must subclass OptionValueArray");
309 OptionValueArray::DeepCopy(const OptionValueSP
&new_parent
) const {
310 auto copy_sp
= OptionValue::DeepCopy(new_parent
);
311 // copy_sp->GetAsArray cannot be used here as it doesn't work for derived
312 // types that override GetType returning a different value.
313 auto *array_value_ptr
= static_cast<OptionValueArray
*>(copy_sp
.get());
314 lldbassert(array_value_ptr
);
316 for (auto &value
: array_value_ptr
->m_values
)
317 value
= value
->DeepCopy(copy_sp
);