Line data Source code
1 : // Copyright 2017 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_TORQUE_UTILS_H_
6 : #define V8_TORQUE_UTILS_H_
7 :
8 : #include <ostream>
9 : #include <streambuf>
10 : #include <string>
11 : #include <unordered_set>
12 : #include <vector>
13 :
14 : #include "src/base/functional.h"
15 : #include "src/base/optional.h"
16 : #include "src/torque/contextual.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 : namespace torque {
21 :
22 : std::string StringLiteralUnquote(const std::string& s);
23 : std::string StringLiteralQuote(const std::string& s);
24 :
25 : // Decodes "file://" URIs into file paths which can then be used
26 : // with the standard stream API.
27 : V8_EXPORT_PRIVATE base::Optional<std::string> FileUriDecode(
28 : const std::string& s);
29 :
30 : class LintErrorStatus : public ContextualClass<LintErrorStatus> {
31 : public:
32 3 : LintErrorStatus() : has_lint_errors_(false) {}
33 :
34 3 : static bool HasLintErrors() { return Get().has_lint_errors_; }
35 0 : static void SetLintError() { Get().has_lint_errors_ = true; }
36 :
37 : private:
38 : bool has_lint_errors_;
39 : };
40 :
41 : void LintError(const std::string& error);
42 :
43 : // Prints a LintError with the format "{type} '{name}' doesn't follow
44 : // '{convention}' naming convention".
45 : void NamingConventionError(const std::string& type, const std::string& name,
46 : const std::string& convention);
47 :
48 : bool IsLowerCamelCase(const std::string& s);
49 : bool IsUpperCamelCase(const std::string& s);
50 : bool IsSnakeCase(const std::string& s);
51 : bool IsValidNamespaceConstName(const std::string& s);
52 : bool IsValidTypeName(const std::string& s);
53 :
54 : [[noreturn]] void ReportErrorString(const std::string& error,
55 : bool print_position);
56 : template <class... Args>
57 0 : [[noreturn]] void ReportError(Args&&... args) {
58 0 : std::stringstream s;
59 0 : USE((s << std::forward<Args>(args))...);
60 0 : ReportErrorString(s.str(), true);
61 : }
62 : template <class... Args>
63 0 : [[noreturn]] void ReportErrorWithoutPosition(Args&&... args) {
64 0 : std::stringstream s;
65 0 : USE((s << std::forward<Args>(args))...);
66 0 : ReportErrorString(s.str(), false);
67 : }
68 :
69 : std::string CapifyStringWithUnderscores(const std::string& camellified_string);
70 : std::string CamelifyString(const std::string& underscore_string);
71 : std::string DashifyString(const std::string& underscore_string);
72 :
73 : void ReplaceFileContentsIfDifferent(const std::string& file_path,
74 : const std::string& contents);
75 :
76 : std::string CurrentPositionAsString();
77 :
78 : template <class T>
79 6 : class Deduplicator {
80 : public:
81 : const T* Add(T x) { return &*(storage_.insert(std::move(x)).first); }
82 :
83 : private:
84 : std::unordered_set<T, base::hash<T>> storage_;
85 : };
86 :
87 : template <class C, class T>
88 7160 : void PrintCommaSeparatedList(std::ostream& os, const T& list, C transform) {
89 : bool first = true;
90 88628 : for (auto& e : list) {
91 40734 : if (first) {
92 : first = false;
93 : } else {
94 34023 : os << ", ";
95 : }
96 81468 : os << transform(e);
97 : }
98 7160 : }
99 :
100 : template <class T,
101 : typename std::enable_if<
102 : std::is_pointer<typename T::value_type>::value, int>::type = 0>
103 0 : void PrintCommaSeparatedList(std::ostream& os, const T& list) {
104 : bool first = true;
105 0 : for (auto& e : list) {
106 0 : if (first) {
107 : first = false;
108 : } else {
109 0 : os << ", ";
110 : }
111 0 : os << *e;
112 : }
113 0 : }
114 :
115 : template <class T,
116 : typename std::enable_if<
117 : !std::is_pointer<typename T::value_type>::value, int>::type = 0>
118 5742 : void PrintCommaSeparatedList(std::ostream& os, const T& list) {
119 : bool first = true;
120 16155 : for (auto& e : list) {
121 10413 : if (first) {
122 : first = false;
123 : } else {
124 4747 : os << ", ";
125 : }
126 302 : os << e;
127 : }
128 5742 : }
129 :
130 : struct BottomOffset {
131 : size_t offset;
132 : BottomOffset& operator++() {
133 13377 : ++offset;
134 : return *this;
135 : }
136 18442 : BottomOffset operator+(size_t x) const { return BottomOffset{offset + x}; }
137 : BottomOffset operator-(size_t x) const {
138 : DCHECK_LE(x, offset);
139 124383 : return BottomOffset{offset - x};
140 : }
141 : bool operator<(const BottomOffset& other) const {
142 : return offset < other.offset;
143 : }
144 : bool operator<=(const BottomOffset& other) const {
145 : return offset <= other.offset;
146 : }
147 : bool operator==(const BottomOffset& other) const {
148 202 : return offset == other.offset;
149 : }
150 : bool operator!=(const BottomOffset& other) const {
151 : return offset != other.offset;
152 : }
153 : };
154 :
155 : inline std::ostream& operator<<(std::ostream& out, BottomOffset from_bottom) {
156 : return out << "BottomOffset{" << from_bottom.offset << "}";
157 : }
158 :
159 : // An iterator-style range of stack slots.
160 : class StackRange {
161 : public:
162 55167 : StackRange(BottomOffset begin, BottomOffset end) : begin_(begin), end_(end) {
163 : DCHECK_LE(begin_, end_);
164 : }
165 :
166 : bool operator==(const StackRange& other) const {
167 202 : return begin_ == other.begin_ && end_ == other.end_;
168 : }
169 :
170 : void Extend(StackRange adjacent) {
171 : DCHECK_EQ(end_, adjacent.begin_);
172 7819 : end_ = adjacent.end_;
173 : }
174 :
175 132064 : size_t Size() const { return end_.offset - begin_.offset; }
176 : BottomOffset begin() const { return begin_; }
177 : BottomOffset end() const { return end_; }
178 :
179 : private:
180 : BottomOffset begin_;
181 : BottomOffset end_;
182 : };
183 :
184 : inline std::ostream& operator<<(std::ostream& out, StackRange range) {
185 : return out << "StackRange{" << range.begin() << ", " << range.end() << "}";
186 : }
187 :
188 : template <class T>
189 66194 : class Stack {
190 : public:
191 : using value_type = T;
192 : Stack() = default;
193 2 : Stack(std::initializer_list<T> initializer)
194 2 : : Stack(std::vector<T>(initializer)) {}
195 : explicit Stack(std::vector<T> v) : elements_(std::move(v)) {}
196 : size_t Size() const { return elements_.size(); }
197 : const T& Peek(BottomOffset from_bottom) const {
198 : return elements_.at(from_bottom.offset);
199 : }
200 1762 : void Poke(BottomOffset from_bottom, T x) {
201 2654 : elements_.at(from_bottom.offset) = std::move(x);
202 1762 : }
203 87660 : void Push(T x) { elements_.push_back(std::move(x)); }
204 : StackRange TopRange(size_t slot_count) const {
205 : DCHECK_GE(Size(), slot_count);
206 : return StackRange{AboveTop() - slot_count, AboveTop()};
207 : }
208 9858 : StackRange PushMany(const std::vector<T>& v) {
209 18664 : for (const T& x : v) {
210 8806 : Push(x);
211 : }
212 9858 : return TopRange(v.size());
213 : }
214 105372 : const T& Top() const { return Peek(AboveTop() - 1); }
215 2216 : T Pop() {
216 8774 : T result = std::move(elements_.back());
217 : elements_.pop_back();
218 2216 : return result;
219 : }
220 7448 : std::vector<T> PopMany(size_t count) {
221 : DCHECK_GE(elements_.size(), count);
222 : std::vector<T> result;
223 7448 : result.reserve(count);
224 16229 : for (auto it = elements_.end() - count; it != elements_.end(); ++it) {
225 : result.push_back(std::move(*it));
226 : }
227 7448 : elements_.resize(elements_.size() - count);
228 7448 : return result;
229 : }
230 : // The invalid offset above the top element. This is useful for StackRange.
231 : BottomOffset AboveTop() const { return BottomOffset{Size()}; }
232 : // Delete the slots in {range}, moving higher slots to fill the gap.
233 17528 : void DeleteRange(StackRange range) {
234 : DCHECK_LE(range.end(), AboveTop());
235 17528 : if (range.Size() == 0) return;
236 30594 : for (BottomOffset i = range.end(); i < AboveTop(); ++i) {
237 20241 : elements_[i.offset - range.Size()] = std::move(elements_[i.offset]);
238 : }
239 17217 : elements_.resize(elements_.size() - range.Size());
240 : }
241 :
242 : bool operator==(const Stack& other) const {
243 4453 : return elements_ == other.elements_;
244 : }
245 : bool operator!=(const Stack& other) const {
246 : return elements_ != other.elements_;
247 : }
248 :
249 : T* begin() { return elements_.data(); }
250 : T* end() { return begin() + elements_.size(); }
251 : const T* begin() const { return elements_.data(); }
252 : const T* end() const { return begin() + elements_.size(); }
253 :
254 : private:
255 : std::vector<T> elements_;
256 : };
257 :
258 : template <class T>
259 : T* CheckNotNull(T* x) {
260 : CHECK_NOT_NULL(x);
261 : return x;
262 : }
263 :
264 : template <class T>
265 : inline std::ostream& operator<<(std::ostream& os, Stack<T>& t) {
266 : os << "Stack{";
267 : PrintCommaSeparatedList(os, t);
268 : os << "}";
269 : return os;
270 : }
271 : class ToString {
272 : public:
273 : template <class T>
274 : ToString& operator<<(T&& x) {
275 : s_ << std::forward<T>(x);
276 : return *this;
277 : }
278 : operator std::string() { return s_.str(); }
279 :
280 : private:
281 : std::stringstream s_;
282 : };
283 :
284 : static const char* const kBaseNamespaceName = "base";
285 : static const char* const kTestNamespaceName = "test";
286 :
287 : // Erase elements of a container that has a constant-time erase function, like
288 : // std::set or std::list. Calling this on std::vector would have quadratic
289 : // complexity.
290 : template <class Container, class F>
291 115 : void EraseIf(Container* container, F f) {
292 287 : for (auto it = container->begin(); it != container->end();) {
293 344 : if (f(*it)) {
294 : it = container->erase(it);
295 : } else {
296 : ++it;
297 : }
298 : }
299 115 : }
300 :
301 9 : class NullStreambuf : public std::streambuf {
302 : public:
303 2615 : virtual int overflow(int c) {
304 2615 : setp(buffer_, buffer_ + sizeof(buffer_));
305 2615 : return (c == traits_type::eof()) ? '\0' : c;
306 : }
307 :
308 : private:
309 : char buffer_[64];
310 : };
311 :
312 6 : class NullOStream : public std::ostream {
313 : public:
314 12 : NullOStream() : std::ostream(&buffer_) {}
315 :
316 : private:
317 : NullStreambuf buffer_;
318 : };
319 :
320 : } // namespace torque
321 : } // namespace internal
322 : } // namespace v8
323 :
324 : #endif // V8_TORQUE_UTILS_H_
|