1 | //===-- StringList.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 "lldb/Utility/StringList.h" |
10 | |
11 | #include "lldb/Utility/Log.h" |
12 | #include "lldb/Utility/Stream.h" |
13 | #include "lldb/Utility/StreamString.h" |
14 | #include "llvm/ADT/ArrayRef.h" |
15 | |
16 | #include <algorithm> |
17 | #include <cstdint> |
18 | #include <cstring> |
19 | |
20 | using namespace lldb_private; |
21 | |
22 | StringList::StringList() : m_strings() {} |
23 | |
24 | StringList::StringList(const char *str) : m_strings() { |
25 | if (str) |
26 | m_strings.push_back(x: str); |
27 | } |
28 | |
29 | StringList::StringList(const char **strv, int strc) : m_strings() { |
30 | for (int i = 0; i < strc; ++i) { |
31 | if (strv[i]) |
32 | m_strings.push_back(x: strv[i]); |
33 | } |
34 | } |
35 | |
36 | StringList::~StringList() = default; |
37 | |
38 | void StringList::AppendString(const char *str) { |
39 | if (str) |
40 | m_strings.push_back(x: str); |
41 | } |
42 | |
43 | void StringList::AppendString(const std::string &s) { m_strings.push_back(x: s); } |
44 | |
45 | void StringList::AppendString(std::string &&s) { |
46 | m_strings.push_back(x: std::move(s)); |
47 | } |
48 | |
49 | void StringList::AppendString(const char *str, size_t str_len) { |
50 | if (str) |
51 | m_strings.push_back(x: std::string(str, str_len)); |
52 | } |
53 | |
54 | void StringList::AppendString(llvm::StringRef str) { |
55 | m_strings.push_back(x: str.str()); |
56 | } |
57 | |
58 | void StringList::AppendString(const llvm::Twine &str) { |
59 | m_strings.push_back(x: str.str()); |
60 | } |
61 | |
62 | void StringList::AppendList(const char **strv, int strc) { |
63 | for (int i = 0; i < strc; ++i) { |
64 | if (strv[i]) |
65 | m_strings.push_back(x: strv[i]); |
66 | } |
67 | } |
68 | |
69 | void StringList::AppendList(StringList strings) { |
70 | m_strings.reserve(n: m_strings.size() + strings.GetSize()); |
71 | m_strings.insert(position: m_strings.end(), first: strings.begin(), last: strings.end()); |
72 | } |
73 | |
74 | size_t StringList::GetSize() const { return m_strings.size(); } |
75 | |
76 | size_t StringList::GetMaxStringLength() const { |
77 | size_t max_length = 0; |
78 | for (const auto &s : m_strings) { |
79 | const size_t len = s.size(); |
80 | if (max_length < len) |
81 | max_length = len; |
82 | } |
83 | return max_length; |
84 | } |
85 | |
86 | const char *StringList::GetStringAtIndex(size_t idx) const { |
87 | if (idx < m_strings.size()) |
88 | return m_strings[idx].c_str(); |
89 | return nullptr; |
90 | } |
91 | |
92 | void StringList::Join(const char *separator, Stream &strm) { |
93 | size_t size = GetSize(); |
94 | |
95 | if (size == 0) |
96 | return; |
97 | |
98 | for (uint32_t i = 0; i < size; ++i) { |
99 | if (i > 0) |
100 | strm.PutCString(cstr: separator); |
101 | strm.PutCString(cstr: GetStringAtIndex(idx: i)); |
102 | } |
103 | } |
104 | |
105 | void StringList::Clear() { m_strings.clear(); } |
106 | |
107 | std::string StringList::LongestCommonPrefix() { |
108 | if (m_strings.empty()) |
109 | return {}; |
110 | |
111 | auto args = llvm::ArrayRef(m_strings); |
112 | llvm::StringRef prefix = args.front(); |
113 | for (auto arg : args.drop_front()) { |
114 | size_t count = 0; |
115 | for (count = 0; count < std::min(a: prefix.size(), b: arg.size()); ++count) { |
116 | if (prefix[count] != arg[count]) |
117 | break; |
118 | } |
119 | prefix = prefix.take_front(N: count); |
120 | } |
121 | return prefix.str(); |
122 | } |
123 | |
124 | void StringList::InsertStringAtIndex(size_t idx, const char *str) { |
125 | if (str) { |
126 | if (idx < m_strings.size()) |
127 | m_strings.insert(position: m_strings.begin() + idx, x: str); |
128 | else |
129 | m_strings.push_back(x: str); |
130 | } |
131 | } |
132 | |
133 | void StringList::InsertStringAtIndex(size_t idx, const std::string &str) { |
134 | if (idx < m_strings.size()) |
135 | m_strings.insert(position: m_strings.begin() + idx, x: str); |
136 | else |
137 | m_strings.push_back(x: str); |
138 | } |
139 | |
140 | void StringList::InsertStringAtIndex(size_t idx, std::string &&str) { |
141 | if (idx < m_strings.size()) |
142 | m_strings.insert(position: m_strings.begin() + idx, x: std::move(str)); |
143 | else |
144 | m_strings.push_back(x: std::move(str)); |
145 | } |
146 | |
147 | void StringList::DeleteStringAtIndex(size_t idx) { |
148 | if (idx < m_strings.size()) |
149 | m_strings.erase(position: m_strings.begin() + idx); |
150 | } |
151 | |
152 | size_t StringList::SplitIntoLines(const std::string &lines) { |
153 | return SplitIntoLines(lines: lines.c_str(), len: lines.size()); |
154 | } |
155 | |
156 | size_t StringList::SplitIntoLines(const char *lines, size_t len) { |
157 | const size_t orig_size = m_strings.size(); |
158 | |
159 | if (len == 0) |
160 | return 0; |
161 | |
162 | const char *k_newline_chars = "\r\n" ; |
163 | const char *p = lines; |
164 | const char *end = lines + len; |
165 | while (p < end) { |
166 | size_t count = strcspn(s: p, reject: k_newline_chars); |
167 | if (count == 0) { |
168 | if (p[count] == '\r' || p[count] == '\n') |
169 | m_strings.push_back(x: std::string()); |
170 | else |
171 | break; |
172 | } else { |
173 | if (p + count > end) |
174 | count = end - p; |
175 | m_strings.push_back(x: std::string(p, count)); |
176 | } |
177 | if (p[count] == '\r' && p[count + 1] == '\n') |
178 | count++; // Skip an extra newline char for the DOS newline |
179 | count++; // Skip the newline character |
180 | p += count; |
181 | } |
182 | return m_strings.size() - orig_size; |
183 | } |
184 | |
185 | void StringList::RemoveBlankLines() { |
186 | if (GetSize() == 0) |
187 | return; |
188 | |
189 | size_t idx = 0; |
190 | while (idx < m_strings.size()) { |
191 | if (m_strings[idx].empty()) |
192 | DeleteStringAtIndex(idx); |
193 | else |
194 | idx++; |
195 | } |
196 | } |
197 | |
198 | std::string StringList::CopyList(const char *item_preamble, |
199 | const char *items_sep) const { |
200 | StreamString strm; |
201 | for (size_t i = 0; i < GetSize(); i++) { |
202 | if (i && items_sep && items_sep[0]) |
203 | strm << items_sep; |
204 | if (item_preamble) |
205 | strm << item_preamble; |
206 | strm << GetStringAtIndex(idx: i); |
207 | } |
208 | return std::string(strm.GetString()); |
209 | } |
210 | |
211 | StringList &StringList::operator<<(const char *str) { |
212 | AppendString(str); |
213 | return *this; |
214 | } |
215 | |
216 | StringList &StringList::operator<<(const std::string &str) { |
217 | AppendString(s: str); |
218 | return *this; |
219 | } |
220 | |
221 | StringList &StringList::operator<<(const StringList &strings) { |
222 | AppendList(strings); |
223 | return *this; |
224 | } |
225 | |
226 | StringList &StringList::operator=(const std::vector<std::string> &rhs) { |
227 | m_strings.assign(first: rhs.begin(), last: rhs.end()); |
228 | |
229 | return *this; |
230 | } |
231 | |
232 | void StringList::LogDump(Log *log, const char *name) { |
233 | if (!log) |
234 | return; |
235 | |
236 | StreamString strm; |
237 | if (name) |
238 | strm.Printf(format: "Begin %s:\n" , name); |
239 | for (const auto &s : m_strings) { |
240 | strm.Indent(); |
241 | strm.Printf(format: "%s\n" , s.c_str()); |
242 | } |
243 | if (name) |
244 | strm.Printf(format: "End %s.\n" , name); |
245 | |
246 | LLDB_LOGV(log, "{0}" , strm.GetData()); |
247 | } |
248 | |