/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 | 219k | SourcePosition SourceContentView::size() const { |
48 | 219k | return static_cast<SourcePosition>(absl::visit( |
49 | 219k | absl::Overload( |
50 | 219k | [](absl::Span<const char> view) { return view.size(); }, |
51 | 219k | [](absl::Span<const uint8_t> view) { return view.size(); }, |
52 | 219k | [](absl::Span<const char16_t> view) { return view.size(); }, |
53 | 219k | [](absl::Span<const char32_t> view) { return view.size(); }), |
54 | 219k | view_)); |
55 | 219k | } |
56 | | |
57 | 227k | bool SourceContentView::empty() const { |
58 | 227k | return absl::visit( |
59 | 227k | absl::Overload( |
60 | 227k | [](absl::Span<const char> view) { return view.empty(); }, |
61 | 227k | [](absl::Span<const uint8_t> view) { return view.empty(); }, |
62 | 227k | [](absl::Span<const char16_t> view) { return view.empty(); }, |
63 | 227k | [](absl::Span<const char32_t> view) { return view.empty(); }), |
64 | 227k | view_); |
65 | 227k | } |
66 | | |
67 | 192M | char32_t SourceContentView::at(SourcePosition position) const { |
68 | 192M | ABSL_DCHECK_GE(position, 0); |
69 | 192M | ABSL_DCHECK_LT(position, size()); |
70 | 192M | return absl::visit( |
71 | 192M | absl::Overload( |
72 | 192M | [position = |
73 | 192M | static_cast<size_t>(position)](absl::Span<const char> view) { |
74 | 97.0M | return static_cast<char32_t>(static_cast<uint8_t>(view[position])); |
75 | 97.0M | }, |
76 | 192M | [position = |
77 | 192M | static_cast<size_t>(position)](absl::Span<const uint8_t> view) { |
78 | 11.1M | return static_cast<char32_t>(view[position]); |
79 | 11.1M | }, |
80 | 192M | [position = |
81 | 192M | static_cast<size_t>(position)](absl::Span<const char16_t> view) { |
82 | 16.4M | return static_cast<char32_t>(view[position]); |
83 | 16.4M | }, |
84 | 192M | [position = |
85 | 192M | static_cast<size_t>(position)](absl::Span<const char32_t> view) { |
86 | 67.8M | return static_cast<char32_t>(view[position]); |
87 | 67.8M | }), |
88 | 192M | view_); |
89 | 192M | } |
90 | | |
91 | | std::string SourceContentView::ToString(SourcePosition begin, |
92 | 12.7M | SourcePosition end) const { |
93 | 12.7M | ABSL_DCHECK_GE(begin, 0); |
94 | 12.7M | ABSL_DCHECK_LE(end, size()); |
95 | 12.7M | ABSL_DCHECK_LE(begin, end); |
96 | 12.7M | return absl::visit( |
97 | 12.7M | absl::Overload( |
98 | 12.7M | [begin = static_cast<size_t>(begin), |
99 | 12.7M | end = static_cast<size_t>(end)](absl::Span<const char> view) { |
100 | 9.01M | view = view.subspan(begin, end - begin); |
101 | 9.01M | return std::string(view.data(), view.size()); |
102 | 9.01M | }, |
103 | 12.7M | [begin = static_cast<size_t>(begin), |
104 | 12.7M | end = static_cast<size_t>(end)](absl::Span<const uint8_t> view) { |
105 | 677k | view = view.subspan(begin, end - begin); |
106 | 677k | std::string result; |
107 | 677k | result.reserve(view.size() * 2); |
108 | 106M | for (const auto& code_point : view) { |
109 | 106M | internal::Utf8Encode(result, code_point); |
110 | 106M | } |
111 | 677k | result.shrink_to_fit(); |
112 | 677k | return result; |
113 | 677k | }, |
114 | 12.7M | [begin = static_cast<size_t>(begin), |
115 | 12.7M | end = static_cast<size_t>(end)](absl::Span<const char16_t> view) { |
116 | 1.52M | view = view.subspan(begin, end - begin); |
117 | 1.52M | std::string result; |
118 | 1.52M | result.reserve(view.size() * 3); |
119 | 266M | for (const auto& code_point : view) { |
120 | 266M | internal::Utf8Encode(result, code_point); |
121 | 266M | } |
122 | 1.52M | result.shrink_to_fit(); |
123 | 1.52M | return result; |
124 | 1.52M | }, |
125 | 12.7M | [begin = static_cast<size_t>(begin), |
126 | 12.7M | end = static_cast<size_t>(end)](absl::Span<const char32_t> view) { |
127 | 1.53M | view = view.subspan(begin, end - begin); |
128 | 1.53M | std::string result; |
129 | 1.53M | result.reserve(view.size() * 4); |
130 | 262M | for (const auto& code_point : view) { |
131 | 262M | internal::Utf8Encode(result, code_point); |
132 | 262M | } |
133 | 1.53M | result.shrink_to_fit(); |
134 | 1.53M | return result; |
135 | 1.53M | }), |
136 | 12.7M | view_); |
137 | 12.7M | } |
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 | 35.3k | : description_(std::move(description)), |
169 | 35.3k | line_offsets_(std::move(line_offsets)) {} |
170 | | |
171 | 290k | absl::string_view description() const final { return description_; } |
172 | | |
173 | 846k | absl::Span<const SourcePosition> line_offsets() const final { |
174 | 846k | return absl::MakeConstSpan(line_offsets_); |
175 | 846k | } |
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 | 32.2k | : SourceImpl(std::move(description), std::move(line_offsets)), |
190 | 32.2k | text_(std::move(text)) {} |
191 | | |
192 | 193k | ContentView content() const override { |
193 | 193k | return MakeContentView(absl::MakeConstSpan(text_)); |
194 | 193k | } |
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 | 442 | : SourceImpl(std::move(description), std::move(line_offsets)), |
206 | 442 | text_(std::move(text)) {} |
207 | | |
208 | 11.9k | ContentView content() const override { |
209 | 11.9k | return MakeContentView(absl::MakeConstSpan(text_)); |
210 | 11.9k | } |
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.40k | : SourceImpl(std::move(description), std::move(line_offsets)), |
222 | 1.40k | text_(std::move(text)) {} |
223 | | |
224 | 31.8k | ContentView content() const override { |
225 | 31.8k | return MakeContentView(absl::MakeConstSpan(text_)); |
226 | 31.8k | } |
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 | 1.19k | : SourceImpl(std::move(description), std::move(line_offsets)), |
238 | 1.19k | text_(std::move(text)) {} |
239 | | |
240 | 30.7k | ContentView content() const override { |
241 | 30.7k | return MakeContentView(absl::MakeConstSpan(text_)); |
242 | 30.7k | } |
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 | 35.5k | static iterator_type Begin(absl::string_view text) { return text; } |
256 | | |
257 | 46.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 | 737 | size_t n) { |
261 | 737 | const auto* in = reinterpret_cast<const uint8_t*>(text.data()); |
262 | 737 | out.insert(out.end(), in, in + n); |
263 | 737 | } |
264 | | |
265 | 32.2k | static std::vector<char> ToVector(absl::string_view in) { |
266 | 32.2k | std::vector<char> out; |
267 | 32.2k | out.reserve(in.size()); |
268 | 32.2k | out.insert(out.end(), in.begin(), in.end()); |
269 | 32.2k | return out; |
270 | 32.2k | } |
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 | 35.6k | const size_t max_codepoints) { |
312 | 35.6k | if (ABSL_PREDICT_FALSE( |
313 | 35.6k | text_size > |
314 | 35.6k | static_cast<size_t>(std::numeric_limits<int32_t>::max()))) { |
315 | 0 | return absl::InvalidArgumentError("expression larger than 2GiB limit"); |
316 | 0 | } |
317 | 35.6k | if ((text_size >> 2) > max_codepoints) { |
318 | | // If byte size is 4 times the codepoint limit, then definitely exceeded. |
319 | 29 | return absl::InvalidArgumentError(absl::StrCat( |
320 | 29 | "expression is larger than codepoint limit ", max_codepoints)); |
321 | 29 | } |
322 | 35.5k | using Traits = SourceTextTraits<T>; |
323 | 35.5k | size_t index = 0; |
324 | 35.5k | typename Traits::iterator_type it = Traits::Begin(text); |
325 | 35.5k | SourcePosition offset = 0; |
326 | 35.5k | char32_t code_point; |
327 | 35.5k | size_t code_units; |
328 | 35.5k | std::vector<uint8_t> data8; |
329 | 35.5k | std::vector<char16_t> data16; |
330 | 35.5k | std::vector<char32_t> data32; |
331 | 35.5k | absl::InlinedVector<SourcePosition, 1> line_offsets; |
332 | 30.9M | while (index < text_size) { |
333 | 30.9M | if (offset >= max_codepoints) { |
334 | 14 | return absl::InvalidArgumentError(absl::StrCat( |
335 | 14 | "expression is larger than codepoint limit ", max_codepoints)); |
336 | 14 | } |
337 | 30.9M | std::tie(code_point, code_units) = cel::internal::Utf8Decode(it); |
338 | 30.9M | if (ABSL_PREDICT_FALSE(code_point == |
339 | 30.9M | cel::internal::kUnicodeReplacementCharacter && |
340 | 30.9M | code_units == 1)) { |
341 | | // Thats an invalid UTF-8 encoding. |
342 | 73 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); |
343 | 73 | } |
344 | 30.9M | if (code_point == '\n') { |
345 | 6.17M | line_offsets.push_back(offset + 1); |
346 | 6.17M | } |
347 | 30.9M | if (code_point <= 0x7f) { |
348 | 30.9M | Traits::Advance(it, code_units); |
349 | 30.9M | index += code_units; |
350 | 30.9M | ++offset; |
351 | 30.9M | continue; |
352 | 30.9M | } |
353 | 3.20k | if (code_point <= 0xff) { |
354 | 737 | data8.reserve(text_size); |
355 | 737 | Traits::AppendTo(data8, text, index); |
356 | 737 | data8.push_back(static_cast<uint8_t>(code_point)); |
357 | 737 | Traits::Advance(it, code_units); |
358 | 737 | index += code_units; |
359 | 737 | ++offset; |
360 | 737 | goto latin1; |
361 | 737 | } |
362 | 2.46k | if (code_point <= 0xffff) { |
363 | 1.50k | data16.reserve(text_size); |
364 | 3.54M | for (size_t offset = 0; offset < index; offset++) { |
365 | 3.54M | data16.push_back(static_cast<uint8_t>(text[offset])); |
366 | 3.54M | } |
367 | 1.50k | data16.push_back(static_cast<char16_t>(code_point)); |
368 | 1.50k | Traits::Advance(it, code_units); |
369 | 1.50k | index += code_units; |
370 | 1.50k | ++offset; |
371 | 1.50k | goto basic; |
372 | 1.50k | } |
373 | 960 | data32.reserve(text_size); |
374 | 1.44M | for (size_t offset = 0; offset < index; offset++) { |
375 | 1.44M | data32.push_back(static_cast<char32_t>(text[offset])); |
376 | 1.44M | } |
377 | 960 | data32.push_back(code_point); |
378 | 960 | Traits::Advance(it, code_units); |
379 | 960 | index += code_units; |
380 | 960 | ++offset; |
381 | 960 | goto supplemental; |
382 | 2.46k | } |
383 | 32.2k | line_offsets.push_back(offset + 1); |
384 | 32.2k | return std::make_unique<AsciiSource>( |
385 | 32.2k | std::move(description), std::move(line_offsets), Traits::ToVector(text)); |
386 | 737 | latin1: |
387 | 4.16M | while (index < text_size) { |
388 | 4.15M | if (offset >= max_codepoints) { |
389 | 10 | return absl::InvalidArgumentError(absl::StrCat( |
390 | 10 | "expression is larger than codepoint limit ", max_codepoints)); |
391 | 10 | } |
392 | 4.15M | std::tie(code_point, code_units) = internal::Utf8Decode(it); |
393 | 4.15M | if (ABSL_PREDICT_FALSE(code_point == |
394 | 4.15M | internal::kUnicodeReplacementCharacter && |
395 | 4.15M | code_units == 1)) { |
396 | | // Thats an invalid UTF-8 encoding. |
397 | 30 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); |
398 | 30 | } |
399 | 4.15M | if (code_point == '\n') { |
400 | 291k | line_offsets.push_back(offset + 1); |
401 | 291k | } |
402 | 4.15M | if (code_point <= 0xff) { |
403 | 4.15M | data8.push_back(static_cast<uint8_t>(code_point)); |
404 | 4.15M | Traits::Advance(it, code_units); |
405 | 4.15M | index += code_units; |
406 | 4.15M | ++offset; |
407 | 4.15M | continue; |
408 | 4.15M | } |
409 | 255 | if (code_point <= 0xffff) { |
410 | 144 | data16.reserve(text_size); |
411 | 608k | for (const auto& value : data8) { |
412 | 608k | data16.push_back(value); |
413 | 608k | } |
414 | 144 | std::vector<uint8_t>().swap(data8); |
415 | 144 | data16.push_back(static_cast<char16_t>(code_point)); |
416 | 144 | Traits::Advance(it, code_units); |
417 | 144 | index += code_units; |
418 | 144 | ++offset; |
419 | 144 | goto basic; |
420 | 144 | } |
421 | 111 | data32.reserve(text_size); |
422 | 1.38M | for (const auto& value : data8) { |
423 | 1.38M | data32.push_back(value); |
424 | 1.38M | } |
425 | 111 | std::vector<uint8_t>().swap(data8); |
426 | 111 | data32.push_back(code_point); |
427 | 111 | Traits::Advance(it, code_units); |
428 | 111 | index += code_units; |
429 | 111 | ++offset; |
430 | 111 | goto supplemental; |
431 | 255 | } |
432 | 442 | line_offsets.push_back(offset + 1); |
433 | 442 | return std::make_unique<Latin1Source>( |
434 | 442 | std::move(description), std::move(line_offsets), std::move(data8)); |
435 | 1.64k | basic: |
436 | 5.90M | while (index < text_size) { |
437 | 5.90M | if (offset >= max_codepoints) { |
438 | 12 | return absl::InvalidArgumentError(absl::StrCat( |
439 | 12 | "expression is larger than codepoint limit ", max_codepoints)); |
440 | 12 | } |
441 | 5.90M | std::tie(code_point, code_units) = internal::Utf8Decode(it); |
442 | 5.90M | if (ABSL_PREDICT_FALSE(code_point == |
443 | 5.90M | internal::kUnicodeReplacementCharacter && |
444 | 5.90M | code_units == 1)) { |
445 | | // Thats an invalid UTF-8 encoding. |
446 | 38 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); |
447 | 38 | } |
448 | 5.90M | if (code_point == '\n') { |
449 | 1.57M | line_offsets.push_back(offset + 1); |
450 | 1.57M | } |
451 | 5.90M | if (code_point <= 0xffff) { |
452 | 5.90M | data16.push_back(static_cast<char16_t>(code_point)); |
453 | 5.90M | Traits::Advance(it, code_units); |
454 | 5.90M | index += code_units; |
455 | 5.90M | ++offset; |
456 | 5.90M | continue; |
457 | 5.90M | } |
458 | 190 | data32.reserve(text_size); |
459 | 1.77M | for (const auto& value : data16) { |
460 | 1.77M | data32.push_back(static_cast<char32_t>(value)); |
461 | 1.77M | } |
462 | 190 | std::vector<char16_t>().swap(data16); |
463 | 190 | data32.push_back(code_point); |
464 | 190 | Traits::Advance(it, code_units); |
465 | 190 | index += code_units; |
466 | 190 | ++offset; |
467 | 190 | goto supplemental; |
468 | 5.90M | } |
469 | 1.40k | line_offsets.push_back(offset + 1); |
470 | 1.40k | return std::make_unique<BasicPlaneSource>( |
471 | 1.40k | std::move(description), std::move(line_offsets), std::move(data16)); |
472 | 1.26k | supplemental: |
473 | 5.80M | while (index < text_size) { |
474 | 5.79M | if (offset >= max_codepoints) { |
475 | 16 | return absl::InvalidArgumentError(absl::StrCat( |
476 | 16 | "expression is larger than codepoint limit ", max_codepoints)); |
477 | 16 | } |
478 | 5.79M | std::tie(code_point, code_units) = internal::Utf8Decode(it); |
479 | 5.79M | if (ABSL_PREDICT_FALSE(code_point == |
480 | 5.79M | internal::kUnicodeReplacementCharacter && |
481 | 5.79M | code_units == 1)) { |
482 | | // Thats an invalid UTF-8 encoding. |
483 | 53 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); |
484 | 53 | } |
485 | 5.79M | if (code_point == '\n') { |
486 | 2.17M | line_offsets.push_back(offset + 1); |
487 | 2.17M | } |
488 | 5.79M | data32.push_back(code_point); |
489 | 5.79M | Traits::Advance(it, code_units); |
490 | 5.79M | index += code_units; |
491 | 5.79M | ++offset; |
492 | 5.79M | } |
493 | 1.19k | line_offsets.push_back(offset + 1); |
494 | 1.19k | return std::make_unique<SupplementalPlaneSource>( |
495 | 1.19k | std::move(description), std::move(line_offsets), std::move(data32)); |
496 | 1.26k | } 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 | 35.6k | const size_t max_codepoints) { | 312 | 35.6k | if (ABSL_PREDICT_FALSE( | 313 | 35.6k | text_size > | 314 | 35.6k | static_cast<size_t>(std::numeric_limits<int32_t>::max()))) { | 315 | 0 | return absl::InvalidArgumentError("expression larger than 2GiB limit"); | 316 | 0 | } | 317 | 35.6k | if ((text_size >> 2) > max_codepoints) { | 318 | | // If byte size is 4 times the codepoint limit, then definitely exceeded. | 319 | 29 | return absl::InvalidArgumentError(absl::StrCat( | 320 | 29 | "expression is larger than codepoint limit ", max_codepoints)); | 321 | 29 | } | 322 | 35.5k | using Traits = SourceTextTraits<T>; | 323 | 35.5k | size_t index = 0; | 324 | 35.5k | typename Traits::iterator_type it = Traits::Begin(text); | 325 | 35.5k | SourcePosition offset = 0; | 326 | 35.5k | char32_t code_point; | 327 | 35.5k | size_t code_units; | 328 | 35.5k | std::vector<uint8_t> data8; | 329 | 35.5k | std::vector<char16_t> data16; | 330 | 35.5k | std::vector<char32_t> data32; | 331 | 35.5k | absl::InlinedVector<SourcePosition, 1> line_offsets; | 332 | 30.9M | while (index < text_size) { | 333 | 30.9M | if (offset >= max_codepoints) { | 334 | 14 | return absl::InvalidArgumentError(absl::StrCat( | 335 | 14 | "expression is larger than codepoint limit ", max_codepoints)); | 336 | 14 | } | 337 | 30.9M | std::tie(code_point, code_units) = cel::internal::Utf8Decode(it); | 338 | 30.9M | if (ABSL_PREDICT_FALSE(code_point == | 339 | 30.9M | cel::internal::kUnicodeReplacementCharacter && | 340 | 30.9M | code_units == 1)) { | 341 | | // Thats an invalid UTF-8 encoding. | 342 | 73 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); | 343 | 73 | } | 344 | 30.9M | if (code_point == '\n') { | 345 | 6.17M | line_offsets.push_back(offset + 1); | 346 | 6.17M | } | 347 | 30.9M | if (code_point <= 0x7f) { | 348 | 30.9M | Traits::Advance(it, code_units); | 349 | 30.9M | index += code_units; | 350 | 30.9M | ++offset; | 351 | 30.9M | continue; | 352 | 30.9M | } | 353 | 3.20k | if (code_point <= 0xff) { | 354 | 737 | data8.reserve(text_size); | 355 | 737 | Traits::AppendTo(data8, text, index); | 356 | 737 | data8.push_back(static_cast<uint8_t>(code_point)); | 357 | 737 | Traits::Advance(it, code_units); | 358 | 737 | index += code_units; | 359 | 737 | ++offset; | 360 | 737 | goto latin1; | 361 | 737 | } | 362 | 2.46k | if (code_point <= 0xffff) { | 363 | 1.50k | data16.reserve(text_size); | 364 | 3.54M | for (size_t offset = 0; offset < index; offset++) { | 365 | 3.54M | data16.push_back(static_cast<uint8_t>(text[offset])); | 366 | 3.54M | } | 367 | 1.50k | data16.push_back(static_cast<char16_t>(code_point)); | 368 | 1.50k | Traits::Advance(it, code_units); | 369 | 1.50k | index += code_units; | 370 | 1.50k | ++offset; | 371 | 1.50k | goto basic; | 372 | 1.50k | } | 373 | 960 | data32.reserve(text_size); | 374 | 1.44M | for (size_t offset = 0; offset < index; offset++) { | 375 | 1.44M | data32.push_back(static_cast<char32_t>(text[offset])); | 376 | 1.44M | } | 377 | 960 | data32.push_back(code_point); | 378 | 960 | Traits::Advance(it, code_units); | 379 | 960 | index += code_units; | 380 | 960 | ++offset; | 381 | 960 | goto supplemental; | 382 | 2.46k | } | 383 | 32.2k | line_offsets.push_back(offset + 1); | 384 | 32.2k | return std::make_unique<AsciiSource>( | 385 | 32.2k | std::move(description), std::move(line_offsets), Traits::ToVector(text)); | 386 | 737 | latin1: | 387 | 4.16M | while (index < text_size) { | 388 | 4.15M | if (offset >= max_codepoints) { | 389 | 10 | return absl::InvalidArgumentError(absl::StrCat( | 390 | 10 | "expression is larger than codepoint limit ", max_codepoints)); | 391 | 10 | } | 392 | 4.15M | std::tie(code_point, code_units) = internal::Utf8Decode(it); | 393 | 4.15M | if (ABSL_PREDICT_FALSE(code_point == | 394 | 4.15M | internal::kUnicodeReplacementCharacter && | 395 | 4.15M | code_units == 1)) { | 396 | | // Thats an invalid UTF-8 encoding. | 397 | 30 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); | 398 | 30 | } | 399 | 4.15M | if (code_point == '\n') { | 400 | 291k | line_offsets.push_back(offset + 1); | 401 | 291k | } | 402 | 4.15M | if (code_point <= 0xff) { | 403 | 4.15M | data8.push_back(static_cast<uint8_t>(code_point)); | 404 | 4.15M | Traits::Advance(it, code_units); | 405 | 4.15M | index += code_units; | 406 | 4.15M | ++offset; | 407 | 4.15M | continue; | 408 | 4.15M | } | 409 | 255 | if (code_point <= 0xffff) { | 410 | 144 | data16.reserve(text_size); | 411 | 608k | for (const auto& value : data8) { | 412 | 608k | data16.push_back(value); | 413 | 608k | } | 414 | 144 | std::vector<uint8_t>().swap(data8); | 415 | 144 | data16.push_back(static_cast<char16_t>(code_point)); | 416 | 144 | Traits::Advance(it, code_units); | 417 | 144 | index += code_units; | 418 | 144 | ++offset; | 419 | 144 | goto basic; | 420 | 144 | } | 421 | 111 | data32.reserve(text_size); | 422 | 1.38M | for (const auto& value : data8) { | 423 | 1.38M | data32.push_back(value); | 424 | 1.38M | } | 425 | 111 | std::vector<uint8_t>().swap(data8); | 426 | 111 | data32.push_back(code_point); | 427 | 111 | Traits::Advance(it, code_units); | 428 | 111 | index += code_units; | 429 | 111 | ++offset; | 430 | 111 | goto supplemental; | 431 | 255 | } | 432 | 442 | line_offsets.push_back(offset + 1); | 433 | 442 | return std::make_unique<Latin1Source>( | 434 | 442 | std::move(description), std::move(line_offsets), std::move(data8)); | 435 | 1.64k | basic: | 436 | 5.90M | while (index < text_size) { | 437 | 5.90M | if (offset >= max_codepoints) { | 438 | 12 | return absl::InvalidArgumentError(absl::StrCat( | 439 | 12 | "expression is larger than codepoint limit ", max_codepoints)); | 440 | 12 | } | 441 | 5.90M | std::tie(code_point, code_units) = internal::Utf8Decode(it); | 442 | 5.90M | if (ABSL_PREDICT_FALSE(code_point == | 443 | 5.90M | internal::kUnicodeReplacementCharacter && | 444 | 5.90M | code_units == 1)) { | 445 | | // Thats an invalid UTF-8 encoding. | 446 | 38 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); | 447 | 38 | } | 448 | 5.90M | if (code_point == '\n') { | 449 | 1.57M | line_offsets.push_back(offset + 1); | 450 | 1.57M | } | 451 | 5.90M | if (code_point <= 0xffff) { | 452 | 5.90M | data16.push_back(static_cast<char16_t>(code_point)); | 453 | 5.90M | Traits::Advance(it, code_units); | 454 | 5.90M | index += code_units; | 455 | 5.90M | ++offset; | 456 | 5.90M | continue; | 457 | 5.90M | } | 458 | 190 | data32.reserve(text_size); | 459 | 1.77M | for (const auto& value : data16) { | 460 | 1.77M | data32.push_back(static_cast<char32_t>(value)); | 461 | 1.77M | } | 462 | 190 | std::vector<char16_t>().swap(data16); | 463 | 190 | data32.push_back(code_point); | 464 | 190 | Traits::Advance(it, code_units); | 465 | 190 | index += code_units; | 466 | 190 | ++offset; | 467 | 190 | goto supplemental; | 468 | 5.90M | } | 469 | 1.40k | line_offsets.push_back(offset + 1); | 470 | 1.40k | return std::make_unique<BasicPlaneSource>( | 471 | 1.40k | std::move(description), std::move(line_offsets), std::move(data16)); | 472 | 1.26k | supplemental: | 473 | 5.80M | while (index < text_size) { | 474 | 5.79M | if (offset >= max_codepoints) { | 475 | 16 | return absl::InvalidArgumentError(absl::StrCat( | 476 | 16 | "expression is larger than codepoint limit ", max_codepoints)); | 477 | 16 | } | 478 | 5.79M | std::tie(code_point, code_units) = internal::Utf8Decode(it); | 479 | 5.79M | if (ABSL_PREDICT_FALSE(code_point == | 480 | 5.79M | internal::kUnicodeReplacementCharacter && | 481 | 5.79M | code_units == 1)) { | 482 | | // Thats an invalid UTF-8 encoding. | 483 | 53 | return absl::InvalidArgumentError("cannot parse malformed UTF-8 input"); | 484 | 53 | } | 485 | 5.79M | if (code_point == '\n') { | 486 | 2.17M | line_offsets.push_back(offset + 1); | 487 | 2.17M | } | 488 | 5.79M | data32.push_back(code_point); | 489 | 5.79M | Traits::Advance(it, code_units); | 490 | 5.79M | index += code_units; | 491 | 5.79M | ++offset; | 492 | 5.79M | } | 493 | 1.19k | line_offsets.push_back(offset + 1); | 494 | 1.19k | return std::make_unique<SupplementalPlaneSource>( | 495 | 1.19k | std::move(description), std::move(line_offsets), std::move(data32)); | 496 | 1.26k | } |
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 | 232k | SourcePosition position) const { |
504 | 232k | if (auto line_and_offset = FindLine(position); |
505 | 232k | ABSL_PREDICT_TRUE(line_and_offset.has_value())) { |
506 | 227k | return SourceLocation{line_and_offset->first, |
507 | 227k | position - line_and_offset->second}; |
508 | 227k | } |
509 | 4.25k | return std::nullopt; |
510 | 232k | } |
511 | | |
512 | | absl::optional<SourcePosition> Source::GetPosition( |
513 | 1.74M | const SourceLocation& location) const { |
514 | 1.74M | if (ABSL_PREDICT_FALSE(location.line < 1 || location.column < 0)) { |
515 | 0 | return std::nullopt; |
516 | 0 | } |
517 | 1.74M | if (auto position = FindLinePosition(location.line); |
518 | 1.74M | ABSL_PREDICT_TRUE(position.has_value())) { |
519 | 1.74M | return *position + location.column; |
520 | 1.74M | } |
521 | 0 | return std::nullopt; |
522 | 1.74M | } |
523 | | |
524 | 233k | absl::optional<std::string> Source::Snippet(int32_t line) const { |
525 | 233k | auto content = this->content(); |
526 | 233k | auto start = FindLinePosition(line); |
527 | 233k | if (ABSL_PREDICT_FALSE(!start.has_value() || content.empty())) { |
528 | 5.18k | return std::nullopt; |
529 | 5.18k | } |
530 | 227k | auto end = FindLinePosition(line + 1); |
531 | 227k | if (end.has_value()) { |
532 | 44.2k | return content.ToString(*start, *end - 1); |
533 | 44.2k | } |
534 | 183k | return content.ToString(*start); |
535 | 227k | } |
536 | | |
537 | 233k | std::string Source::DisplayErrorLocation(SourceLocation location) const { |
538 | 233k | constexpr char32_t kDot = '.'; |
539 | 233k | constexpr char32_t kHat = '^'; |
540 | | |
541 | 233k | constexpr char32_t kWideDot = 0xff0e; |
542 | 233k | constexpr char32_t kWideHat = 0xff3e; |
543 | 233k | absl::optional<std::string> snippet = Snippet(location.line); |
544 | 233k | if (!snippet || snippet->empty()) { |
545 | 5.92k | return ""; |
546 | 5.92k | } |
547 | | |
548 | 227k | *snippet = absl::StrReplaceAll(*snippet, {{"\t", " "}}); |
549 | 227k | absl::string_view snippet_view(*snippet); |
550 | 227k | std::string result; |
551 | 227k | absl::StrAppend(&result, "\n | ", *snippet); |
552 | 227k | absl::StrAppend(&result, "\n | "); |
553 | | |
554 | 227k | std::string index_line; |
555 | 316M | for (int32_t i = 0; i < location.column && !snippet_view.empty(); ++i) { |
556 | 316M | size_t count; |
557 | 316M | std::tie(std::ignore, count) = internal::Utf8Decode(snippet_view); |
558 | 316M | snippet_view.remove_prefix(count); |
559 | 316M | if (count > 1) { |
560 | 5.68M | internal::Utf8Encode(index_line, kWideDot); |
561 | 310M | } else { |
562 | 310M | internal::Utf8Encode(index_line, kDot); |
563 | 310M | } |
564 | 316M | } |
565 | 227k | size_t count = 0; |
566 | 227k | if (!snippet_view.empty()) { |
567 | 217k | std::tie(std::ignore, count) = internal::Utf8Decode(snippet_view); |
568 | 217k | } |
569 | 227k | if (count > 1) { |
570 | 5.52k | internal::Utf8Encode(index_line, kWideHat); |
571 | 221k | } else { |
572 | 221k | internal::Utf8Encode(index_line, kHat); |
573 | 221k | } |
574 | 227k | absl::StrAppend(&result, index_line); |
575 | 227k | return result; |
576 | 233k | } |
577 | | |
578 | 2.20M | absl::optional<SourcePosition> Source::FindLinePosition(int32_t line) const { |
579 | 2.20M | if (ABSL_PREDICT_FALSE(line < 1)) { |
580 | 5.18k | return std::nullopt; |
581 | 5.18k | } |
582 | 2.19M | if (line == 1) { |
583 | 1.62M | return SourcePosition{0}; |
584 | 1.62M | } |
585 | 573k | const auto line_offsets = this->line_offsets(); |
586 | 573k | if (ABSL_PREDICT_TRUE(line <= static_cast<int32_t>(line_offsets.size()))) { |
587 | 390k | return line_offsets[static_cast<size_t>(line - 2)]; |
588 | 390k | } |
589 | 183k | return std::nullopt; |
590 | 573k | } |
591 | | |
592 | | absl::optional<std::pair<int32_t, SourcePosition>> Source::FindLine( |
593 | 232k | SourcePosition position) const { |
594 | 232k | if (ABSL_PREDICT_FALSE(position < 0)) { |
595 | 4.25k | return std::nullopt; |
596 | 4.25k | } |
597 | 227k | int32_t line = 1; |
598 | 227k | const auto line_offsets = this->line_offsets(); |
599 | 217M | for (const auto& line_offset : line_offsets) { |
600 | 217M | if (line_offset > position) { |
601 | 227k | break; |
602 | 227k | } |
603 | 217M | ++line; |
604 | 217M | } |
605 | 227k | if (line == 1) { |
606 | 188k | return std::make_pair(line, SourcePosition{0}); |
607 | 188k | } |
608 | 39.1k | return std::make_pair(line, line_offsets[static_cast<size_t>(line) - 2]); |
609 | 227k | } |
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 | 35.6k | static size_t ClampLimit(int value) { |
657 | 35.6k | if (value < 0) { |
658 | 0 | return std::numeric_limits<size_t>::max(); |
659 | 0 | } |
660 | 35.6k | return static_cast<size_t>(value); |
661 | 35.6k | } |
662 | | |
663 | | absl::StatusOr<absl_nonnull SourcePtr> NewSource(absl::string_view content, |
664 | | std::string description, |
665 | 35.6k | const SourceOptions& options) { |
666 | 35.6k | return common_internal::NewSourceImpl(std::move(description), content, |
667 | 35.6k | content.size(), |
668 | 35.6k | ClampLimit(options.max_codepoint_size)); |
669 | 35.6k | } |
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 |