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
= Status::FromErrorStringWithFormat(
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
= Status::FromErrorStringWithFormat(
138 "index %i is not valid for an empty array", idx
);
140 error
= Status::FromErrorStringWithFormat(
141 "index %i out of range, valid values are 0 through %" PRIu64
, idx
,
142 (uint64_t)(array_count
- 1));
145 Status::FromErrorStringWithFormat("negative index %i out of range, "
146 "valid values are -1 through "
148 idx
, (uint64_t)array_count
);
150 return OptionValueSP();
153 size_t OptionValueArray::GetArgs(Args
&args
) const {
155 const uint32_t size
= m_values
.size();
156 for (uint32_t i
= 0; i
< size
; ++i
) {
157 auto string_value
= m_values
[i
]->GetValueAs
<llvm::StringRef
>();
159 args
.AppendArgument(*string_value
);
162 return args
.GetArgumentCount();
165 Status
OptionValueArray::SetArgs(const Args
&args
, VarSetOperationType op
) {
167 const size_t argc
= args
.GetArgumentCount();
169 case eVarSetOperationInvalid
:
170 error
= Status::FromErrorString("unsupported operation");
173 case eVarSetOperationInsertBefore
:
174 case eVarSetOperationInsertAfter
:
177 const uint32_t count
= GetSize();
178 if (!llvm::to_integer(args
.GetArgumentAtIndex(0), idx
) || idx
> count
) {
179 error
= Status::FromErrorStringWithFormat(
180 "invalid insert array index %s, index must be 0 through %u",
181 args
.GetArgumentAtIndex(0), count
);
183 if (op
== eVarSetOperationInsertAfter
)
185 for (size_t i
= 1; i
< argc
; ++i
, ++idx
) {
186 lldb::OptionValueSP
value_sp(CreateValueFromCStringForTypeMask(
187 args
.GetArgumentAtIndex(i
), m_type_mask
, error
));
191 if (idx
>= m_values
.size())
192 m_values
.push_back(value_sp
);
194 m_values
.insert(m_values
.begin() + idx
, value_sp
);
196 error
= Status::FromErrorString(
197 "array of complex types must subclass OptionValueArray");
203 error
= Status::FromErrorString(
204 "insert operation takes an array index followed by "
205 "one or more values");
209 case eVarSetOperationRemove
:
211 const uint32_t size
= m_values
.size();
212 std::vector
<int> remove_indexes
;
213 bool all_indexes_valid
= true;
215 for (i
= 0; i
< argc
; ++i
) {
217 if (!llvm::to_integer(args
.GetArgumentAtIndex(i
), idx
) || idx
>= size
) {
218 all_indexes_valid
= false;
221 remove_indexes
.push_back(idx
);
224 if (all_indexes_valid
) {
225 size_t num_remove_indexes
= remove_indexes
.size();
226 if (num_remove_indexes
) {
227 // Sort and then erase in reverse so indexes are always valid
228 if (num_remove_indexes
> 1) {
229 llvm::sort(remove_indexes
);
230 for (std::vector
<int>::const_reverse_iterator
231 pos
= remove_indexes
.rbegin(),
232 end
= remove_indexes
.rend();
234 m_values
.erase(m_values
.begin() + *pos
);
238 m_values
.erase(m_values
.begin() + remove_indexes
.front());
242 error
= Status::FromErrorStringWithFormat(
243 "invalid array index '%s', aborting remove operation",
244 args
.GetArgumentAtIndex(i
));
247 error
= Status::FromErrorString(
248 "remove operation takes one or more array indices");
252 case eVarSetOperationClear
:
256 case eVarSetOperationReplace
:
259 const uint32_t count
= GetSize();
260 if (!llvm::to_integer(args
.GetArgumentAtIndex(0), idx
) || idx
> count
) {
261 error
= Status::FromErrorStringWithFormat(
262 "invalid replace array index %s, index must be 0 through %u",
263 args
.GetArgumentAtIndex(0), count
);
265 for (size_t i
= 1; i
< argc
; ++i
, ++idx
) {
266 lldb::OptionValueSP
value_sp(CreateValueFromCStringForTypeMask(
267 args
.GetArgumentAtIndex(i
), m_type_mask
, error
));
272 m_values
[idx
] = value_sp
;
274 m_values
.push_back(value_sp
);
276 error
= Status::FromErrorString(
277 "array of complex types must subclass OptionValueArray");
283 error
= Status::FromErrorString(
284 "replace operation takes an array index followed by "
285 "one or more values");
289 case eVarSetOperationAssign
:
291 // Fall through to append case
293 case eVarSetOperationAppend
:
294 for (size_t i
= 0; i
< argc
; ++i
) {
295 lldb::OptionValueSP
value_sp(CreateValueFromCStringForTypeMask(
296 args
.GetArgumentAtIndex(i
), m_type_mask
, error
));
300 m_value_was_set
= true;
301 AppendValue(value_sp
);
303 error
= Status::FromErrorString(
304 "array of complex types must subclass OptionValueArray");
313 OptionValueArray::DeepCopy(const OptionValueSP
&new_parent
) const {
314 auto copy_sp
= OptionValue::DeepCopy(new_parent
);
315 // copy_sp->GetAsArray cannot be used here as it doesn't work for derived
316 // types that override GetType returning a different value.
317 auto *array_value_ptr
= static_cast<OptionValueArray
*>(copy_sp
.get());
318 lldbassert(array_value_ptr
);
320 for (auto &value
: array_value_ptr
->m_values
)
321 value
= value
->DeepCopy(copy_sp
);