/proc/self/cwd/common/source.cc
Line | Count | Source |
1 | | // Copyright 2023 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include "common/source.h" |
16 | | |
17 | | #include <algorithm> |
18 | | #include <cstddef> |
19 | | #include <cstdint> |
20 | | #include <limits> |
21 | | #include <memory> |
22 | | #include <optional> |
23 | | #include <string> |
24 | | #include <tuple> |
25 | | #include <utility> |
26 | | #include <vector> |
27 | | |
28 | | #include "absl/base/nullability.h" |
29 | | #include "absl/base/optimization.h" |
30 | | #include "absl/container/inlined_vector.h" |
31 | | #include "absl/functional/overload.h" |
32 | | #include "absl/log/absl_check.h" |
33 | | #include "absl/status/status.h" |
34 | | #include "absl/status/statusor.h" |
35 | | #include "absl/strings/cord.h" |
36 | | #include "absl/strings/str_cat.h" |
37 | | #include "absl/strings/str_replace.h" |
38 | | #include "absl/strings/string_view.h" |
39 | | #include "absl/types/optional.h" |
40 | | #include "absl/types/span.h" |
41 | | #include "absl/types/variant.h" |
42 | | #include "internal/unicode.h" |
43 | | #include "internal/utf8.h" |
44 | | |
45 | | namespace cel { |
46 | | |
47 | 167k | SourcePosition SourceContentView::size() const { |
48 | 167k | return static_cast<SourcePosition>(absl::visit( |
49 | 167k | absl::Overload( |
50 | 167k | [](absl::Span<const char> view) { return view.size(); }, |
51 | 167k | [](absl::Span<const uint8_t> view) { return view.size(); }, |
52 | 167k | [](absl::Span<const char16_t> view) { return view.size(); }, |
53 | 167k | [](absl::Span<const char32_t> view) { return view.size(); }), |
54 | 167k | view_)); |
55 | 167k | } |
56 | | |
57 | 168k | bool SourceContentView::empty() const { |
58 | 168k | return absl::visit( |
59 | 168k | absl::Overload( |
60 | 168k | [](absl::Span<const char> view) { return view.empty(); }, |
61 | 168k | [](absl::Span<const uint8_t> view) { return view.empty(); }, |
62 | 168k | [](absl::Span<const char16_t> view) { return view.empty(); }, |
63 | 168k | [](absl::Span<const char32_t> view) { return view.empty(); }), |
64 | 168k | view_); |
65 | 168k | } |
66 | | |
67 | 140M | char32_t SourceContentView::at(SourcePosition position) const { |
68 | 140M | ABSL_DCHECK_GE(position, 0); |
69 | 140M | ABSL_DCHECK_LT(position, size()); |
70 | 140M | return absl::visit( |
71 | 140M | absl::Overload( |
72 | 140M | [position = |
73 | 140M | static_cast<size_t>(position)](absl::Span<const char> view) { |
74 | 79.7M | return static_cast<char32_t>(static_cast<uint8_t>(view[position])); |
75 | 79.7M | }, |
76 | 140M | [position = |
77 | 140M | static_cast<size_t>(position)](absl::Span<const uint8_t> view) { |
78 | 11.7M | return static_cast<char32_t>(view[position]); |
79 | 11.7M | }, |
80 | 140M | [position = |
81 | 140M | static_cast<size_t>(position)](absl::Span<const char16_t> view) { |
82 | 11.5M | return static_cast<char32_t>(view[position]); |
83 | 11.5M | }, |
84 | 140M | [position = |
85 | 140M | static_cast<size_t>(position)](absl::Span<const char32_t> view) { |
86 | 37.7M | return static_cast<char32_t>(view[position]); |
87 | 37.7M | }), |
88 | 140M | view_); |
89 | 140M | } |
90 | | |
91 | | std::string SourceContentView::ToString(SourcePosition begin, |
92 | 8.64M | SourcePosition end) const { |
93 | 8.64M | ABSL_DCHECK_GE(begin, 0); |
94 | 8.64M | ABSL_DCHECK_LE(end, size()); |
95 | 8.64M | ABSL_DCHECK_LE(begin, end); |
96 | 8.64M | return absl::visit( |
97 | 8.64M | absl::Overload( |
98 | 8.64M | [begin = static_cast<size_t>(begin), |
99 | 8.64M | end = static_cast<size_t>(end)](absl::Span<const char> view) { |
100 | 6.19M | view = view.subspan(begin, end - begin); |
101 | 6.19M | return std::string(view.data(), view.size()); |
102 | 6.19M | }, |
103 | 8.64M | [begin = static_cast<size_t>(begin), |
104 | 8.64M | end = static_cast<size_t>(end)](absl::Span<const uint8_t> view) { |
105 | 542k | view = view.subspan(begin, end - begin); |
106 | 542k | std::string result; |
107 | 542k | result.reserve(view.size() * 2); |
108 | 66.4M | for (const auto& code_point : view) { |
109 | 66.4M | internal::Utf8Encode(result, code_point); |
110 | 66.4M | } |
111 | 542k | result.shrink_to_fit(); |
112 | 542k | return result; |
113 | 542k | }, |
114 | 8.64M | [begin = static_cast<size_t>(begin), |
115 | 8.64M | end = static_cast<size_t>(end)](absl::Span<const char16_t> view) { |
116 | 920k | view = view.subspan(begin, end - begin); |
117 | 920k | std::string result; |
118 | 920k | result.reserve(view.size() * 3); |
119 | 198M | for (const auto& code_point : view) { |
120 | 198M | internal::Utf8Encode(result, code_point); |
121 | 198M | } |
122 | 920k | result.shrink_to_fit(); |
123 | 920k | return result; |
124 | 920k | }, |
125 | 8.64M | [begin = static_cast<size_t>(begin), |
126 | 8.64M | end = static_cast<size_t>(end)](absl::Span<const char32_t> view) { |
127 | 989k | view = view.subspan(begin, end - begin); |
128 | 989k | std::string result; |
129 | 989k | result.reserve(view.size() * 4); |
130 | 174M | for (const auto& code_point : view) { |
131 | 174M | internal::Utf8Encode(result, code_point); |
132 | 174M | } |
133 | 989k | result.shrink_to_fit(); |
134 | 989k | return result; |
135 | 989k | }), |
136 | 8.64M | view_); |
137 | 8.64M | } |
138 | | |
139 | 0 | void SourceContentView::AppendToString(std::string& dest) const { |
140 | 0 | absl::visit(absl::Overload( |
141 | 0 | [&dest](absl::Span<const char> view) { |
142 | 0 | dest.append(view.data(), view.size()); |
143 | 0 | }, |
144 | 0 | [&dest](absl::Span<const uint8_t> view) { |
145 | 0 | for (const auto& code_point : view) { |
146 | 0 | internal::Utf8Encode(dest, code_point); |
147 | 0 | } |
148 | 0 | }, |
149 | 0 | [&dest](absl::Span<const char16_t> view) { |
150 | 0 | for (const auto& code_point : view) { |
151 | 0 | internal::Utf8Encode(dest, code_point); |
152 | 0 | } |
153 | 0 | }, |
154 | 0 | [&dest](absl::Span<const char32_t> view) { |
155 | 0 | for (const auto& code_point : view) { |
156 | 0 | internal::Utf8Encode(dest, code_point); |
157 | 0 | } |
158 | 0 | }), |
159 | 0 | view_); |
160 | 0 | } |
161 | | |
162 | | namespace common_internal { |
163 | | |
164 | | class SourceImpl : public Source { |
165 | | public: |
166 | | SourceImpl(std::string description, |
167 | | absl::InlinedVector<SourcePosition, 1> line_offsets) |
168 | 28.8k | : description_(std::move(description)), |
169 | 28.8k | line_offsets_(std::move(line_offsets)) {} |
170 | | |
171 | 220k | absl::string_view description() const final { return description_; } |
172 | | |
173 | 630k | absl::Span<const SourcePosition> line_offsets() const final { |
174 | 630k | return absl::MakeConstSpan(line_offsets_); |
175 | 630k | } |
176 | | |
177 | | private: |
178 | | const std::string description_; |
179 | | const absl::InlinedVector<SourcePosition, 1> line_offsets_; |
180 | | }; |
181 | | |
182 | | namespace { |
183 | | |
184 | | class AsciiSource final : public SourceImpl { |
185 | | public: |
186 | | AsciiSource(std::string description, |
187 | | absl::InlinedVector<SourcePosition, 1> line_offsets, |
188 | | std::vector<char> text) |
189 | 26.4k | : SourceImpl(std::move(description), std::move(line_offsets)), |
190 | 26.4k | text_(std::move(text)) {} |
191 | | |
192 | 146k | ContentView content() const override { |
193 | 146k | return MakeContentView(absl::MakeConstSpan(text_)); |
194 | 146k | } |
195 | | |
196 | | private: |
197 | | const std::vector<char> text_; |
198 | | }; |
199 | | |
200 | | class Latin1Source final : public SourceImpl { |
201 | | public: |
202 | | Latin1Source(std::string description, |
203 | | absl::InlinedVector<SourcePosition, 1> line_offsets, |
204 | | std::vector<uint8_t> text) |
205 | 330 | : SourceImpl(std::move(description), std::move(line_offsets)), |
206 | 330 | text_(std::move(text)) {} |
207 | | |
208 | 8.25k | ContentView content() const override { |
209 | 8.25k | return MakeContentView(absl::MakeConstSpan(text_)); |
210 | 8.25k | } |
211 | | |
212 | | private: |
213 | | const std::vector<uint8_t> text_; |
214 | | }; |
215 | | |
216 | | class BasicPlaneSource final : public SourceImpl { |
217 | | public: |
218 | | BasicPlaneSource(std::string description, |
219 | | absl::InlinedVector<SourcePosition, 1> line_offsets, |
220 | | std::vector<char16_t> text) |
221 | 1.14k | : SourceImpl(std::move(description), std::move(line_offsets)), |
222 | 1.14k | text_(std::move(text)) {} |
223 | | |
224 | 24.5k | ContentView content() const override { |
225 | 24.5k | return MakeContentView(absl::MakeConstSpan(text_)); |
226 | 24.5k | } |
227 | | |
228 | | private: |
229 | | const std::vector<char16_t> text_; |
230 | | }; |
231 | | |
232 | | class SupplementalPlaneSource final : public SourceImpl { |
233 | | public: |
234 | | SupplementalPlaneSource(std::string description, |
235 | | absl::InlinedVector<SourcePosition, 1> line_offsets, |
236 | | std::vector<char32_t> text) |
237 | 894 | : SourceImpl(std::move(description), std::move(line_offsets)), |
238 | 894 | text_(std::move(text)) {} |
239 | | |
240 | 22.3k | ContentView content() const override { |
241 | 22.3k | return MakeContentView(absl::MakeConstSpan(text_)); |
242 | 22.3k | } |
243 | | |
244 | | private: |
245 | | const std::vector<char32_t> text_; |
246 | | }; |
247 | | |
248 | | template <typename T> |
249 | | struct SourceTextTraits; |
250 | | |
251 | | template <> |
252 | | struct SourceTextTraits<absl::string_view> { |
253 | | using iterator_type = absl::string_view; |
254 | | |
255 | 29.0k | static iterator_type Begin(absl::string_view text) { return text; } |
256 | | |
257 | 32.7M | static void Advance(iterator_type& it, size_t n) { it.remove_prefix(n); } |
258 | | |
259 | | static void AppendTo(std::vector<uint8_t>& out, absl::string_view text, |
260 | 572 | size_t n) { |
261 | 572 | const auto* in = reinterpret_cast<const uint8_t*>(text.data()); |
262 | 572 | out.insert(out.end(), in, in + n); |
263 | 572 | } |
264 | | |
265 | 26.4k | static std::vector<char> ToVector(absl::string_view in) { |
266 | 26.4k | std::vector<char> out; |
267 | 26.4k | out.reserve(in.size()); |
268 | 26.4k | out.insert(out.end(), in.begin(), in.end()); |
269 | 26.4k | return out; |
270 | 26.4k | } |
271 | | }; |
272 | | |
273 | | template <> |
274 | | struct SourceTextTraits<absl::Cord> { |
275 | | using iterator_type = absl::Cord::CharIterator; |
276 | | |
277 | 0 | static iterator_type Begin(const absl::Cord& text) { |
278 | 0 | return text.char_begin(); |
279 | 0 | } |
280 | | |
281 | 0 | static void Advance(iterator_type& it, size_t n) { |
282 | 0 | absl::Cord::Advance(&it, n); |
283 | 0 | } |
284 | | |
285 | | static void AppendTo(std::vector<uint8_t>& out, const absl::Cord& text, |
286 | 0 | size_t n) { |
287 | 0 | auto it = text.char_begin(); |
288 | 0 | while (n > 0) { |
289 | 0 | auto str = absl::Cord::ChunkRemaining(it); |
290 | 0 | size_t to_append = std::min(n, str.size()); |
291 | 0 | const auto* in = reinterpret_cast<const uint8_t*>(str.data()); |
292 | 0 | out.insert(out.end(), in, in + to_append); |
293 | 0 | n -= to_append; |
294 | 0 | absl::Cord::Advance(&it, to_append); |
295 | 0 | } |
296 | 0 | } |
297 | | |
298 | 0 | static std::vector<char> ToVector(const absl::Cord& in) { |
299 | 0 | std::vector<char> out; |
300 | 0 | out.reserve(in.size()); |
301 | 0 | for (const auto& chunk : in.Chunks()) { |
302 | 0 | out.insert(out.end(), chunk.begin(), chunk.end()); |
303 | 0 | } |
304 | 0 | return out; |
305 | 0 | } |
306 | | }; |
307 | | |
308 | | template <typename T> |
309 | | absl::StatusOr<SourcePtr> NewSourceImpl(std::string description, const T& text, |
310 | | const size_t text_size, |
311 | 29.0k | const size_t max_codepoints) { |
312 | 29.0k | if (ABSL_PREDICT_FALSE( |
313 | 29.0k | text_size > |
314 | 29.0k | static_cast<size_t>(std::numeric_limits<int32_t>::max()))) { |
315 | 0 | return absl::InvalidArgumentError("expression larger than 2GiB limit"); |
316 | 0 | } |
317 | 29.0k | if ((text_size >> 2) > max_codepoints) { |
318 | | // If byte size is 4 times the codepoint limit, then definitely exceeded. |
319 | 24 | return absl::InvalidArgumentError(absl::StrCat( |
320 | 24 | "expression is larger than codepoint limit ", max_codepoints)); |
321 | 24 | } |
322 | 29.0k | using Traits = SourceTextTraits<T>; |
323 | 29.0k | size_t index = 0; |
324 | 29.0k | typename Traits::iterator_type it = Traits::Begin(text); |
325 | 29.0k | SourcePosition offset = 0; |
326 | 29.0k | char32_t code_point; |
327 | 29.0k | size_t code_units; |
328 | 29.0k | std::vector<uint8_t> data8; |
329 | 29.0k | std::vector<char16_t> data16; |
330 | 29.0k | std::vector<char32_t> data32; |
331 | 29.0k | absl::InlinedVector<SourcePosition, 1> line_offsets; |
332 | 21.9M | while (index < text_size) { |
333 | 21.9M | if (offset >= max_codepoints) { |
334 | 7 | return absl::InvalidArgumentError(absl::StrCat( |
335 | 7 | "expression is larger than codepoint limit ", max_codepoints)); |
336 | 7 | } |
337 | 21.9M | std::tie(code_point, code_units) = cel::internal::Utf8Decode(it); |
338 | 21.9M | if (ABSL_PREDICT_FALSE(code_point == |
339 | 21.9M | cel::internal::kUnicodeReplacementCharacter && |
340 | 21.9M | code_units == 1)) { |
341 | | // Thats an invalid UTF-8 encoding. |
342 | 55 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); |
343 | 55 | } |
344 | 21.9M | if (code_point == '\n') { |
345 | 3.79M | line_offsets.push_back(offset + 1); |
346 | 3.79M | } |
347 | 21.9M | if (code_point <= 0x7f) { |
348 | 21.9M | Traits::Advance(it, code_units); |
349 | 21.9M | index += code_units; |
350 | 21.9M | ++offset; |
351 | 21.9M | continue; |
352 | 21.9M | } |
353 | 2.51k | if (code_point <= 0xff) { |
354 | 572 | data8.reserve(text_size); |
355 | 572 | Traits::AppendTo(data8, text, index); |
356 | 572 | data8.push_back(static_cast<uint8_t>(code_point)); |
357 | 572 | Traits::Advance(it, code_units); |
358 | 572 | index += code_units; |
359 | 572 | ++offset; |
360 | 572 | goto latin1; |
361 | 572 | } |
362 | 1.94k | if (code_point <= 0xffff) { |
363 | 1.21k | data16.reserve(text_size); |
364 | 2.42M | for (size_t offset = 0; offset < index; offset++) { |
365 | 2.42M | data16.push_back(static_cast<uint8_t>(text[offset])); |
366 | 2.42M | } |
367 | 1.21k | data16.push_back(static_cast<char16_t>(code_point)); |
368 | 1.21k | Traits::Advance(it, code_units); |
369 | 1.21k | index += code_units; |
370 | 1.21k | ++offset; |
371 | 1.21k | goto basic; |
372 | 1.21k | } |
373 | 734 | data32.reserve(text_size); |
374 | 1.04M | for (size_t offset = 0; offset < index; offset++) { |
375 | 1.04M | data32.push_back(static_cast<char32_t>(text[offset])); |
376 | 1.04M | } |
377 | 734 | data32.push_back(code_point); |
378 | 734 | Traits::Advance(it, code_units); |
379 | 734 | index += code_units; |
380 | 734 | ++offset; |
381 | 734 | goto supplemental; |
382 | 1.94k | } |
383 | 26.4k | line_offsets.push_back(offset + 1); |
384 | 26.4k | return std::make_unique<AsciiSource>( |
385 | 26.4k | std::move(description), std::move(line_offsets), Traits::ToVector(text)); |
386 | 572 | latin1: |
387 | 2.69M | while (index < text_size) { |
388 | 2.69M | if (offset >= max_codepoints) { |
389 | 7 | return absl::InvalidArgumentError(absl::StrCat( |
390 | 7 | "expression is larger than codepoint limit ", max_codepoints)); |
391 | 7 | } |
392 | 2.69M | std::tie(code_point, code_units) = internal::Utf8Decode(it); |
393 | 2.69M | if (ABSL_PREDICT_FALSE(code_point == |
394 | 2.69M | internal::kUnicodeReplacementCharacter && |
395 | 2.69M | code_units == 1)) { |
396 | | // Thats an invalid UTF-8 encoding. |
397 | 28 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); |
398 | 28 | } |
399 | 2.69M | if (code_point == '\n') { |
400 | 367k | line_offsets.push_back(offset + 1); |
401 | 367k | } |
402 | 2.69M | if (code_point <= 0xff) { |
403 | 2.69M | data8.push_back(static_cast<uint8_t>(code_point)); |
404 | 2.69M | Traits::Advance(it, code_units); |
405 | 2.69M | index += code_units; |
406 | 2.69M | ++offset; |
407 | 2.69M | continue; |
408 | 2.69M | } |
409 | 207 | if (code_point <= 0xffff) { |
410 | 122 | data16.reserve(text_size); |
411 | 576k | for (const auto& value : data8) { |
412 | 576k | data16.push_back(value); |
413 | 576k | } |
414 | 122 | std::vector<uint8_t>().swap(data8); |
415 | 122 | data16.push_back(static_cast<char16_t>(code_point)); |
416 | 122 | Traits::Advance(it, code_units); |
417 | 122 | index += code_units; |
418 | 122 | ++offset; |
419 | 122 | goto basic; |
420 | 122 | } |
421 | 85 | data32.reserve(text_size); |
422 | 850k | for (const auto& value : data8) { |
423 | 850k | data32.push_back(value); |
424 | 850k | } |
425 | 85 | std::vector<uint8_t>().swap(data8); |
426 | 85 | data32.push_back(code_point); |
427 | 85 | Traits::Advance(it, code_units); |
428 | 85 | index += code_units; |
429 | 85 | ++offset; |
430 | 85 | goto supplemental; |
431 | 207 | } |
432 | 330 | line_offsets.push_back(offset + 1); |
433 | 330 | return std::make_unique<Latin1Source>( |
434 | 330 | std::move(description), std::move(line_offsets), std::move(data8)); |
435 | 1.33k | basic: |
436 | 4.53M | while (index < text_size) { |
437 | 4.52M | if (offset >= max_codepoints) { |
438 | 9 | return absl::InvalidArgumentError(absl::StrCat( |
439 | 9 | "expression is larger than codepoint limit ", max_codepoints)); |
440 | 9 | } |
441 | 4.52M | std::tie(code_point, code_units) = internal::Utf8Decode(it); |
442 | 4.52M | if (ABSL_PREDICT_FALSE(code_point == |
443 | 4.52M | internal::kUnicodeReplacementCharacter && |
444 | 4.52M | code_units == 1)) { |
445 | | // Thats an invalid UTF-8 encoding. |
446 | 49 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); |
447 | 49 | } |
448 | 4.52M | if (code_point == '\n') { |
449 | 840k | line_offsets.push_back(offset + 1); |
450 | 840k | } |
451 | 4.52M | if (code_point <= 0xffff) { |
452 | 4.52M | data16.push_back(static_cast<char16_t>(code_point)); |
453 | 4.52M | Traits::Advance(it, code_units); |
454 | 4.52M | index += code_units; |
455 | 4.52M | ++offset; |
456 | 4.52M | continue; |
457 | 4.52M | } |
458 | 128 | data32.reserve(text_size); |
459 | 1.14M | for (const auto& value : data16) { |
460 | 1.14M | data32.push_back(static_cast<char32_t>(value)); |
461 | 1.14M | } |
462 | 128 | std::vector<char16_t>().swap(data16); |
463 | 128 | data32.push_back(code_point); |
464 | 128 | Traits::Advance(it, code_units); |
465 | 128 | index += code_units; |
466 | 128 | ++offset; |
467 | 128 | goto supplemental; |
468 | 4.52M | } |
469 | 1.14k | line_offsets.push_back(offset + 1); |
470 | 1.14k | return std::make_unique<BasicPlaneSource>( |
471 | 1.14k | std::move(description), std::move(line_offsets), std::move(data16)); |
472 | 947 | supplemental: |
473 | 3.56M | while (index < text_size) { |
474 | 3.56M | if (offset >= max_codepoints) { |
475 | 12 | return absl::InvalidArgumentError(absl::StrCat( |
476 | 12 | "expression is larger than codepoint limit ", max_codepoints)); |
477 | 12 | } |
478 | 3.56M | std::tie(code_point, code_units) = internal::Utf8Decode(it); |
479 | 3.56M | if (ABSL_PREDICT_FALSE(code_point == |
480 | 3.56M | internal::kUnicodeReplacementCharacter && |
481 | 3.56M | code_units == 1)) { |
482 | | // Thats an invalid UTF-8 encoding. |
483 | 41 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); |
484 | 41 | } |
485 | 3.56M | if (code_point == '\n') { |
486 | 1.31M | line_offsets.push_back(offset + 1); |
487 | 1.31M | } |
488 | 3.56M | data32.push_back(code_point); |
489 | 3.56M | Traits::Advance(it, code_units); |
490 | 3.56M | index += code_units; |
491 | 3.56M | ++offset; |
492 | 3.56M | } |
493 | 894 | line_offsets.push_back(offset + 1); |
494 | 894 | return std::make_unique<SupplementalPlaneSource>( |
495 | 894 | std::move(description), std::move(line_offsets), std::move(data32)); |
496 | 947 | } source.cc:absl::lts_20260526::StatusOr<std::__1::unique_ptr<cel::Source, std::__1::default_delete<cel::Source> > > cel::common_internal::(anonymous namespace)::NewSourceImpl<std::__1::basic_string_view<char, std::__1::char_traits<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> > const&, unsigned long, unsigned long) Line | Count | Source | 311 | 29.0k | const size_t max_codepoints) { | 312 | 29.0k | if (ABSL_PREDICT_FALSE( | 313 | 29.0k | text_size > | 314 | 29.0k | static_cast<size_t>(std::numeric_limits<int32_t>::max()))) { | 315 | 0 | return absl::InvalidArgumentError("expression larger than 2GiB limit"); | 316 | 0 | } | 317 | 29.0k | if ((text_size >> 2) > max_codepoints) { | 318 | | // If byte size is 4 times the codepoint limit, then definitely exceeded. | 319 | 24 | return absl::InvalidArgumentError(absl::StrCat( | 320 | 24 | "expression is larger than codepoint limit ", max_codepoints)); | 321 | 24 | } | 322 | 29.0k | using Traits = SourceTextTraits<T>; | 323 | 29.0k | size_t index = 0; | 324 | 29.0k | typename Traits::iterator_type it = Traits::Begin(text); | 325 | 29.0k | SourcePosition offset = 0; | 326 | 29.0k | char32_t code_point; | 327 | 29.0k | size_t code_units; | 328 | 29.0k | std::vector<uint8_t> data8; | 329 | 29.0k | std::vector<char16_t> data16; | 330 | 29.0k | std::vector<char32_t> data32; | 331 | 29.0k | absl::InlinedVector<SourcePosition, 1> line_offsets; | 332 | 21.9M | while (index < text_size) { | 333 | 21.9M | if (offset >= max_codepoints) { | 334 | 7 | return absl::InvalidArgumentError(absl::StrCat( | 335 | 7 | "expression is larger than codepoint limit ", max_codepoints)); | 336 | 7 | } | 337 | 21.9M | std::tie(code_point, code_units) = cel::internal::Utf8Decode(it); | 338 | 21.9M | if (ABSL_PREDICT_FALSE(code_point == | 339 | 21.9M | cel::internal::kUnicodeReplacementCharacter && | 340 | 21.9M | code_units == 1)) { | 341 | | // Thats an invalid UTF-8 encoding. | 342 | 55 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); | 343 | 55 | } | 344 | 21.9M | if (code_point == '\n') { | 345 | 3.79M | line_offsets.push_back(offset + 1); | 346 | 3.79M | } | 347 | 21.9M | if (code_point <= 0x7f) { | 348 | 21.9M | Traits::Advance(it, code_units); | 349 | 21.9M | index += code_units; | 350 | 21.9M | ++offset; | 351 | 21.9M | continue; | 352 | 21.9M | } | 353 | 2.51k | if (code_point <= 0xff) { | 354 | 572 | data8.reserve(text_size); | 355 | 572 | Traits::AppendTo(data8, text, index); | 356 | 572 | data8.push_back(static_cast<uint8_t>(code_point)); | 357 | 572 | Traits::Advance(it, code_units); | 358 | 572 | index += code_units; | 359 | 572 | ++offset; | 360 | 572 | goto latin1; | 361 | 572 | } | 362 | 1.94k | if (code_point <= 0xffff) { | 363 | 1.21k | data16.reserve(text_size); | 364 | 2.42M | for (size_t offset = 0; offset < index; offset++) { | 365 | 2.42M | data16.push_back(static_cast<uint8_t>(text[offset])); | 366 | 2.42M | } | 367 | 1.21k | data16.push_back(static_cast<char16_t>(code_point)); | 368 | 1.21k | Traits::Advance(it, code_units); | 369 | 1.21k | index += code_units; | 370 | 1.21k | ++offset; | 371 | 1.21k | goto basic; | 372 | 1.21k | } | 373 | 734 | data32.reserve(text_size); | 374 | 1.04M | for (size_t offset = 0; offset < index; offset++) { | 375 | 1.04M | data32.push_back(static_cast<char32_t>(text[offset])); | 376 | 1.04M | } | 377 | 734 | data32.push_back(code_point); | 378 | 734 | Traits::Advance(it, code_units); | 379 | 734 | index += code_units; | 380 | 734 | ++offset; | 381 | 734 | goto supplemental; | 382 | 1.94k | } | 383 | 26.4k | line_offsets.push_back(offset + 1); | 384 | 26.4k | return std::make_unique<AsciiSource>( | 385 | 26.4k | std::move(description), std::move(line_offsets), Traits::ToVector(text)); | 386 | 572 | latin1: | 387 | 2.69M | while (index < text_size) { | 388 | 2.69M | if (offset >= max_codepoints) { | 389 | 7 | return absl::InvalidArgumentError(absl::StrCat( | 390 | 7 | "expression is larger than codepoint limit ", max_codepoints)); | 391 | 7 | } | 392 | 2.69M | std::tie(code_point, code_units) = internal::Utf8Decode(it); | 393 | 2.69M | if (ABSL_PREDICT_FALSE(code_point == | 394 | 2.69M | internal::kUnicodeReplacementCharacter && | 395 | 2.69M | code_units == 1)) { | 396 | | // Thats an invalid UTF-8 encoding. | 397 | 28 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); | 398 | 28 | } | 399 | 2.69M | if (code_point == '\n') { | 400 | 367k | line_offsets.push_back(offset + 1); | 401 | 367k | } | 402 | 2.69M | if (code_point <= 0xff) { | 403 | 2.69M | data8.push_back(static_cast<uint8_t>(code_point)); | 404 | 2.69M | Traits::Advance(it, code_units); | 405 | 2.69M | index += code_units; | 406 | 2.69M | ++offset; | 407 | 2.69M | continue; | 408 | 2.69M | } | 409 | 207 | if (code_point <= 0xffff) { | 410 | 122 | data16.reserve(text_size); | 411 | 576k | for (const auto& value : data8) { | 412 | 576k | data16.push_back(value); | 413 | 576k | } | 414 | 122 | std::vector<uint8_t>().swap(data8); | 415 | 122 | data16.push_back(static_cast<char16_t>(code_point)); | 416 | 122 | Traits::Advance(it, code_units); | 417 | 122 | index += code_units; | 418 | 122 | ++offset; | 419 | 122 | goto basic; | 420 | 122 | } | 421 | 85 | data32.reserve(text_size); | 422 | 850k | for (const auto& value : data8) { | 423 | 850k | data32.push_back(value); | 424 | 850k | } | 425 | 85 | std::vector<uint8_t>().swap(data8); | 426 | 85 | data32.push_back(code_point); | 427 | 85 | Traits::Advance(it, code_units); | 428 | 85 | index += code_units; | 429 | 85 | ++offset; | 430 | 85 | goto supplemental; | 431 | 207 | } | 432 | 330 | line_offsets.push_back(offset + 1); | 433 | 330 | return std::make_unique<Latin1Source>( | 434 | 330 | std::move(description), std::move(line_offsets), std::move(data8)); | 435 | 1.33k | basic: | 436 | 4.53M | while (index < text_size) { | 437 | 4.52M | if (offset >= max_codepoints) { | 438 | 9 | return absl::InvalidArgumentError(absl::StrCat( | 439 | 9 | "expression is larger than codepoint limit ", max_codepoints)); | 440 | 9 | } | 441 | 4.52M | std::tie(code_point, code_units) = internal::Utf8Decode(it); | 442 | 4.52M | if (ABSL_PREDICT_FALSE(code_point == | 443 | 4.52M | internal::kUnicodeReplacementCharacter && | 444 | 4.52M | code_units == 1)) { | 445 | | // Thats an invalid UTF-8 encoding. | 446 | 49 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); | 447 | 49 | } | 448 | 4.52M | if (code_point == '\n') { | 449 | 840k | line_offsets.push_back(offset + 1); | 450 | 840k | } | 451 | 4.52M | if (code_point <= 0xffff) { | 452 | 4.52M | data16.push_back(static_cast<char16_t>(code_point)); | 453 | 4.52M | Traits::Advance(it, code_units); | 454 | 4.52M | index += code_units; | 455 | 4.52M | ++offset; | 456 | 4.52M | continue; | 457 | 4.52M | } | 458 | 128 | data32.reserve(text_size); | 459 | 1.14M | for (const auto& value : data16) { | 460 | 1.14M | data32.push_back(static_cast<char32_t>(value)); | 461 | 1.14M | } | 462 | 128 | std::vector<char16_t>().swap(data16); | 463 | 128 | data32.push_back(code_point); | 464 | 128 | Traits::Advance(it, code_units); | 465 | 128 | index += code_units; | 466 | 128 | ++offset; | 467 | 128 | goto supplemental; | 468 | 4.52M | } | 469 | 1.14k | line_offsets.push_back(offset + 1); | 470 | 1.14k | return std::make_unique<BasicPlaneSource>( | 471 | 1.14k | std::move(description), std::move(line_offsets), std::move(data16)); | 472 | 947 | supplemental: | 473 | 3.56M | while (index < text_size) { | 474 | 3.56M | if (offset >= max_codepoints) { | 475 | 12 | return absl::InvalidArgumentError(absl::StrCat( | 476 | 12 | "expression is larger than codepoint limit ", max_codepoints)); | 477 | 12 | } | 478 | 3.56M | std::tie(code_point, code_units) = internal::Utf8Decode(it); | 479 | 3.56M | if (ABSL_PREDICT_FALSE(code_point == | 480 | 3.56M | internal::kUnicodeReplacementCharacter && | 481 | 3.56M | code_units == 1)) { | 482 | | // Thats an invalid UTF-8 encoding. | 483 | 41 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); | 484 | 41 | } | 485 | 3.56M | if (code_point == '\n') { | 486 | 1.31M | line_offsets.push_back(offset + 1); | 487 | 1.31M | } | 488 | 3.56M | data32.push_back(code_point); | 489 | 3.56M | Traits::Advance(it, code_units); | 490 | 3.56M | index += code_units; | 491 | 3.56M | ++offset; | 492 | 3.56M | } | 493 | 894 | line_offsets.push_back(offset + 1); | 494 | 894 | return std::make_unique<SupplementalPlaneSource>( | 495 | 894 | std::move(description), std::move(line_offsets), std::move(data32)); | 496 | 947 | } |
Unexecuted instantiation: source.cc:absl::lts_20260526::StatusOr<std::__1::unique_ptr<cel::Source, std::__1::default_delete<cel::Source> > > cel::common_internal::(anonymous namespace)::NewSourceImpl<absl::lts_20260526::Cord>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, absl::lts_20260526::Cord const&, unsigned long, unsigned long) |
497 | | |
498 | | } // namespace |
499 | | |
500 | | } // namespace common_internal |
501 | | |
502 | | absl::optional<SourceLocation> Source::GetLocation( |
503 | 171k | SourcePosition position) const { |
504 | 171k | if (auto line_and_offset = FindLine(position); |
505 | 171k | ABSL_PREDICT_TRUE(line_and_offset.has_value())) { |
506 | 168k | return SourceLocation{line_and_offset->first, |
507 | 168k | position - line_and_offset->second}; |
508 | 168k | } |
509 | 3.28k | return std::nullopt; |
510 | 171k | } |
511 | | |
512 | | absl::optional<SourcePosition> Source::GetPosition( |
513 | 1.60M | const SourceLocation& location) const { |
514 | 1.60M | if (ABSL_PREDICT_FALSE(location.line < 1 || location.column < 0)) { |
515 | 0 | return std::nullopt; |
516 | 0 | } |
517 | 1.60M | if (auto position = FindLinePosition(location.line); |
518 | 1.60M | ABSL_PREDICT_TRUE(position.has_value())) { |
519 | 1.60M | return *position + location.column; |
520 | 1.60M | } |
521 | 0 | return std::nullopt; |
522 | 1.60M | } |
523 | | |
524 | 172k | absl::optional<std::string> Source::Snippet(int32_t line) const { |
525 | 172k | auto content = this->content(); |
526 | 172k | auto start = FindLinePosition(line); |
527 | 172k | if (ABSL_PREDICT_FALSE(!start.has_value() || content.empty())) { |
528 | 3.96k | return std::nullopt; |
529 | 3.96k | } |
530 | 168k | auto end = FindLinePosition(line + 1); |
531 | 168k | if (end.has_value()) { |
532 | 29.5k | return content.ToString(*start, *end - 1); |
533 | 29.5k | } |
534 | 138k | return content.ToString(*start); |
535 | 168k | } |
536 | | |
537 | 172k | std::string Source::DisplayErrorLocation(SourceLocation location) const { |
538 | 172k | constexpr char32_t kDot = '.'; |
539 | 172k | constexpr char32_t kHat = '^'; |
540 | | |
541 | 172k | constexpr char32_t kWideDot = 0xff0e; |
542 | 172k | constexpr char32_t kWideHat = 0xff3e; |
543 | 172k | absl::optional<std::string> snippet = Snippet(location.line); |
544 | 172k | if (!snippet || snippet->empty()) { |
545 | 4.55k | return ""; |
546 | 4.55k | } |
547 | | |
548 | 167k | *snippet = absl::StrReplaceAll(*snippet, {{"\t", " "}}); |
549 | 167k | absl::string_view snippet_view(*snippet); |
550 | 167k | std::string result; |
551 | 167k | absl::StrAppend(&result, "\n | ", *snippet); |
552 | 167k | absl::StrAppend(&result, "\n | "); |
553 | | |
554 | 167k | std::string index_line; |
555 | 248M | for (int32_t i = 0; i < location.column && !snippet_view.empty(); ++i) { |
556 | 248M | size_t count; |
557 | 248M | std::tie(std::ignore, count) = internal::Utf8Decode(snippet_view); |
558 | 248M | snippet_view.remove_prefix(count); |
559 | 248M | if (count > 1) { |
560 | 16.4M | internal::Utf8Encode(index_line, kWideDot); |
561 | 232M | } else { |
562 | 232M | internal::Utf8Encode(index_line, kDot); |
563 | 232M | } |
564 | 248M | } |
565 | 167k | size_t count = 0; |
566 | 167k | if (!snippet_view.empty()) { |
567 | 160k | std::tie(std::ignore, count) = internal::Utf8Decode(snippet_view); |
568 | 160k | } |
569 | 167k | if (count > 1) { |
570 | 4.62k | internal::Utf8Encode(index_line, kWideHat); |
571 | 163k | } else { |
572 | 163k | internal::Utf8Encode(index_line, kHat); |
573 | 163k | } |
574 | 167k | absl::StrAppend(&result, index_line); |
575 | 167k | return result; |
576 | 172k | } |
577 | | |
578 | 1.94M | absl::optional<SourcePosition> Source::FindLinePosition(int32_t line) const { |
579 | 1.94M | if (ABSL_PREDICT_FALSE(line < 1)) { |
580 | 3.96k | return std::nullopt; |
581 | 3.96k | } |
582 | 1.94M | if (line == 1) { |
583 | 1.51M | return SourcePosition{0}; |
584 | 1.51M | } |
585 | 423k | const auto line_offsets = this->line_offsets(); |
586 | 423k | if (ABSL_PREDICT_TRUE(line <= static_cast<int32_t>(line_offsets.size()))) { |
587 | 284k | return line_offsets[static_cast<size_t>(line - 2)]; |
588 | 284k | } |
589 | 138k | return std::nullopt; |
590 | 423k | } |
591 | | |
592 | | absl::optional<std::pair<int32_t, SourcePosition>> Source::FindLine( |
593 | 171k | SourcePosition position) const { |
594 | 171k | if (ABSL_PREDICT_FALSE(position < 0)) { |
595 | 3.28k | return std::nullopt; |
596 | 3.28k | } |
597 | 168k | int32_t line = 1; |
598 | 168k | const auto line_offsets = this->line_offsets(); |
599 | 136M | for (const auto& line_offset : line_offsets) { |
600 | 136M | if (line_offset > position) { |
601 | 168k | break; |
602 | 168k | } |
603 | 136M | ++line; |
604 | 136M | } |
605 | 168k | if (line == 1) { |
606 | 138k | return std::make_pair(line, SourcePosition{0}); |
607 | 138k | } |
608 | 30.0k | return std::make_pair(line, line_offsets[static_cast<size_t>(line) - 2]); |
609 | 168k | } |
610 | | |
611 | | SourceSubrange::SourceSubrange(const Source& source, SourceRange range) |
612 | 0 | : source_(source), range_(range) { |
613 | 0 | SourcePosition size = source_.content().size(); |
614 | 0 | ABSL_DCHECK(range_.begin >= 0); |
615 | 0 | ABSL_DCHECK(range_.begin <= size); |
616 | 0 | ABSL_DCHECK(range_.end >= range_.begin); |
617 | 0 | ABSL_DCHECK(range_.end <= size); |
618 | 0 | if (range_.begin < 0) { |
619 | 0 | range_.begin = 0; |
620 | 0 | } |
621 | 0 | if (range_.begin > size) { |
622 | 0 | range_.begin = size; |
623 | 0 | } |
624 | 0 | if (range_.end < range_.begin) { |
625 | 0 | range_.end = range_.begin; |
626 | 0 | } |
627 | 0 | if (range_.end > size) { |
628 | 0 | range_.end = size; |
629 | 0 | } |
630 | 0 | for (const auto& line_offset : source_.line_offsets()) { |
631 | 0 | if (line_offset > range_.begin && line_offset <= range_.end) { |
632 | 0 | line_offsets_.push_back(line_offset - range_.begin); |
633 | 0 | } |
634 | 0 | } |
635 | 0 | line_offsets_.push_back(range_.end - range_.begin + 1); |
636 | 0 | } |
637 | | |
638 | 0 | SourceContentView SourceSubrange::content() const { |
639 | 0 | auto parent_content = source_.content(); |
640 | 0 | if (parent_content.empty() || range_.begin >= range_.end) { |
641 | 0 | return EmptyContentView(); |
642 | 0 | } |
643 | 0 | return absl::visit( |
644 | 0 | [this](auto view) { |
645 | 0 | return SourceContentView( |
646 | 0 | view.subspan(static_cast<size_t>(range_.begin), |
647 | 0 | static_cast<size_t>(range_.end - range_.begin))); |
648 | 0 | }, Unexecuted instantiation: source.cc:auto cel::SourceSubrange::content() const::$_0::operator()<absl::lts_20260526::Span<char const> >(absl::lts_20260526::Span<char const>) const Unexecuted instantiation: source.cc:auto cel::SourceSubrange::content() const::$_0::operator()<absl::lts_20260526::Span<unsigned char const> >(absl::lts_20260526::Span<unsigned char const>) const Unexecuted instantiation: source.cc:auto cel::SourceSubrange::content() const::$_0::operator()<absl::lts_20260526::Span<char16_t const> >(absl::lts_20260526::Span<char16_t const>) const Unexecuted instantiation: source.cc:auto cel::SourceSubrange::content() const::$_0::operator()<absl::lts_20260526::Span<char32_t const> >(absl::lts_20260526::Span<char32_t const>) const |
649 | 0 | parent_content.view_); |
650 | 0 | } |
651 | | |
652 | 0 | absl::Span<const SourcePosition> SourceSubrange::line_offsets() const { |
653 | 0 | return absl::MakeConstSpan(line_offsets_); |
654 | 0 | } |
655 | | |
656 | 29.0k | static size_t ClampLimit(int value) { |
657 | 29.0k | if (value < 0) { |
658 | 0 | return std::numeric_limits<size_t>::max(); |
659 | 0 | } |
660 | 29.0k | return static_cast<size_t>(value); |
661 | 29.0k | } |
662 | | |
663 | | absl::StatusOr<absl_nonnull SourcePtr> NewSource(absl::string_view content, |
664 | | std::string description, |
665 | 29.0k | const SourceOptions& options) { |
666 | 29.0k | return common_internal::NewSourceImpl(std::move(description), content, |
667 | 29.0k | content.size(), |
668 | 29.0k | ClampLimit(options.max_codepoint_size)); |
669 | 29.0k | } |
670 | | |
671 | | absl::StatusOr<absl_nonnull SourcePtr> NewSource(const absl::Cord& content, |
672 | | std::string description, |
673 | 0 | const SourceOptions& options) { |
674 | 0 | return common_internal::NewSourceImpl(std::move(description), content, |
675 | 0 | content.size(), |
676 | 0 | ClampLimit(options.max_codepoint_size)); |
677 | 0 | } |
678 | | |
679 | | } // namespace cel |