/proc/self/cwd/common/internal/byte_string.cc
Line | Count | Source |
1 | | // Copyright 2024 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/internal/byte_string.h" |
16 | | |
17 | | #include <algorithm> |
18 | | #include <cstddef> |
19 | | #include <cstring> |
20 | | #include <string> |
21 | | #include <utility> |
22 | | |
23 | | #include "absl/base/nullability.h" |
24 | | #include "absl/base/optimization.h" |
25 | | #include "absl/functional/overload.h" |
26 | | #include "absl/log/absl_check.h" |
27 | | #include "absl/strings/cord.h" |
28 | | #include "absl/strings/resize_and_overwrite.h" |
29 | | #include "absl/strings/string_view.h" |
30 | | #include "absl/types/optional.h" |
31 | | #include "google/protobuf/arena.h" |
32 | | |
33 | | namespace cel::common_internal { |
34 | | |
35 | | ByteString ByteString::From(absl::string_view value, |
36 | 12.6k | google::protobuf::Arena* absl_nonnull arena) { |
37 | 12.6k | ABSL_DCHECK(arena != nullptr); |
38 | 12.6k | ByteString result(UninitializedTag{}); |
39 | 12.6k | if (value.size() <= kSmallByteStringCapacity) { |
40 | 11.1k | result.SetSmall(value); |
41 | 11.1k | } else { |
42 | 1.49k | char* arena_value = |
43 | 1.49k | reinterpret_cast<char*>(arena->AllocateAligned(value.size())); |
44 | 1.49k | std::memcpy(arena_value, value.data(), value.size()); |
45 | 1.49k | result.SetMedium(arena, absl::string_view(arena_value, value.size())); |
46 | 1.49k | } |
47 | 12.6k | return result; |
48 | 12.6k | } |
49 | | |
50 | | ByteString ByteString::From(absl::Cord value, |
51 | 0 | google::protobuf::Arena* absl_nonnull arena) { |
52 | 0 | ABSL_DCHECK(arena != nullptr); |
53 | 0 | ByteString result(UninitializedTag{}); |
54 | 0 | if (value.size() <= kSmallByteStringCapacity) { |
55 | 0 | result.SetSmall(value); |
56 | 0 | } else { |
57 | 0 | result.SetLarge(arena, |
58 | 0 | google::protobuf::Arena::Create<absl::Cord>(arena, std::move(value))); |
59 | 0 | } |
60 | 0 | return result; |
61 | 0 | } |
62 | | |
63 | | ByteString ByteString::From(std::string&& value, |
64 | 1.32k | google::protobuf::Arena* absl_nonnull arena) { |
65 | 1.32k | ABSL_DCHECK(arena != nullptr); |
66 | 1.32k | ByteString result(UninitializedTag{}); |
67 | 1.32k | if (value.size() <= kSmallByteStringCapacity) { |
68 | 1.32k | result.SetSmall(value); |
69 | 1.32k | } else if (value.size() > sizeof(std::string)) { |
70 | 0 | value.shrink_to_fit(); |
71 | 0 | result.SetMedium( |
72 | 0 | arena, google::protobuf::Arena::Create<std::string>(arena, std::move(value))); |
73 | 0 | } else { |
74 | 0 | char* arena_value = |
75 | 0 | reinterpret_cast<char*>(arena->AllocateAligned(value.size())); |
76 | 0 | std::memcpy(arena_value, value.data(), value.size()); |
77 | 0 | result.SetMedium(arena, absl::string_view(arena_value, value.size())); |
78 | 0 | } |
79 | 1.32k | return result; |
80 | 1.32k | } |
81 | | |
82 | | ByteString ByteString::Concat(const ByteString& lhs, const ByteString& rhs, |
83 | 4.81k | google::protobuf::Arena* absl_nonnull arena) { |
84 | 4.81k | ABSL_DCHECK(arena != nullptr); |
85 | | |
86 | 4.81k | if (lhs.empty()) { |
87 | 800 | return rhs; |
88 | 800 | } |
89 | 4.01k | if (rhs.empty()) { |
90 | 857 | return lhs; |
91 | 857 | } |
92 | | |
93 | 3.15k | if (lhs.GetKind() == ByteStringKind::kLarge || |
94 | 3.15k | rhs.GetKind() == ByteStringKind::kLarge) { |
95 | | // If either the left or right are absl::Cord, use absl::Cord. |
96 | 0 | absl::Cord result; |
97 | 0 | lhs.AppendToCord(&result); |
98 | 0 | rhs.AppendToCord(&result); |
99 | 0 | return From(result, arena); |
100 | 0 | } |
101 | | |
102 | 3.15k | const size_t lhs_size = lhs.size(); |
103 | 3.15k | const size_t rhs_size = rhs.size(); |
104 | 3.15k | const size_t result_size = lhs_size + rhs_size; |
105 | 3.15k | ByteString result(UninitializedTag{}); |
106 | 3.15k | if (result_size <= kSmallByteStringCapacity) { |
107 | | // If the resulting string fits in inline storage, do it. |
108 | 2.81k | result.rep_.header.kind = ByteStringKind::kSmall; |
109 | 2.81k | result.rep_.small.size = result_size; |
110 | 2.81k | lhs.CopyToArray(result.rep_.small.data); |
111 | 2.81k | rhs.CopyToArray(result.rep_.small.data + lhs_size); |
112 | 2.81k | } else { |
113 | | // Otherwise allocate on the arena. |
114 | 349 | char* result_data = |
115 | 349 | reinterpret_cast<char*>(arena->AllocateAligned(result_size)); |
116 | 349 | lhs.CopyToArray(result_data); |
117 | 349 | rhs.CopyToArray(result_data + lhs_size); |
118 | 349 | result.rep_.header.kind = ByteStringKind::kMedium; |
119 | 349 | result.rep_.medium.data = result_data; |
120 | 349 | result.rep_.medium.size = result_size; |
121 | 349 | result.rep_.medium.arena = arena; |
122 | 349 | } |
123 | 3.15k | return result; |
124 | 3.15k | } |
125 | | |
126 | 0 | absl::optional<absl::string_view> ByteString::TryFlat() const { |
127 | 0 | switch (GetKind()) { |
128 | 0 | case ByteStringKind::kSmall: |
129 | 0 | return GetSmall(); |
130 | 0 | case ByteStringKind::kMedium: |
131 | 0 | return GetMedium(); |
132 | 0 | case ByteStringKind::kLarge: { |
133 | 0 | if (auto flat = rep_.large.data->TryFlat(); flat.has_value()) { |
134 | 0 | return flat->substr(rep_.large.offset, rep_.large.size); |
135 | 0 | } |
136 | 0 | return absl::nullopt; |
137 | 0 | } |
138 | 0 | } |
139 | 0 | } |
140 | | |
141 | | absl::optional<size_t> ByteString::Find(absl::string_view needle, |
142 | 0 | size_t pos) const { |
143 | 0 | ABSL_DCHECK_LE(pos, size()); |
144 | |
|
145 | 0 | return Visit(absl::Overload( |
146 | 0 | [&needle, pos](absl::string_view lhs) -> absl::optional<size_t> { |
147 | 0 | absl::string_view::size_type i = lhs.find(needle, pos); |
148 | 0 | if (i == absl::string_view::npos) { |
149 | 0 | return std::nullopt; |
150 | 0 | } |
151 | 0 | return i; |
152 | 0 | }, |
153 | 0 | [&needle, pos](const absl::Cord& lhs) -> absl::optional<size_t> { |
154 | 0 | absl::Cord cord = lhs.Subcord(pos, lhs.size() - pos); |
155 | 0 | absl::Cord::CharIterator it = cord.Find(needle); |
156 | 0 | if (it == cord.char_end()) { |
157 | 0 | return std::nullopt; |
158 | 0 | } |
159 | 0 | return pos + |
160 | 0 | static_cast<size_t>(absl::Cord::Distance(cord.char_begin(), it)); |
161 | 0 | })); |
162 | 0 | } |
163 | | |
164 | | absl::optional<size_t> ByteString::Find(const absl::Cord& needle, |
165 | 0 | size_t pos) const { |
166 | 0 | ABSL_DCHECK_LE(pos, size()); |
167 | |
|
168 | 0 | return Visit(absl::Overload( |
169 | 0 | [&needle, pos](absl::string_view lhs) -> absl::optional<size_t> { |
170 | 0 | if (auto flat_needle = needle.TryFlat(); flat_needle) { |
171 | 0 | absl::string_view::size_type i = lhs.find(*flat_needle, pos); |
172 | 0 | if (i == absl::string_view::npos) { |
173 | 0 | return std::nullopt; |
174 | 0 | } |
175 | 0 | return i; |
176 | 0 | } |
177 | | // Needle is fragmented, we have to do a linear scan. |
178 | 0 | const size_t needle_size = needle.size(); |
179 | 0 | if (pos + needle_size > lhs.size()) { |
180 | 0 | return std::nullopt; |
181 | 0 | } |
182 | 0 | if (ABSL_PREDICT_FALSE(needle_size == 0)) { |
183 | 0 | return pos; |
184 | 0 | } |
185 | | // Optimization: find the first chunk of the needle, then compare the |
186 | | // rest. If the first chunk is empty, `lhs.find` will return |
187 | | // `current_pos`, which correctly degrades to a linear scan. |
188 | 0 | absl::string_view first_chunk = *needle.Chunks().begin(); |
189 | 0 | absl::Cord rest_of_needle = needle.Subcord( |
190 | 0 | first_chunk.size(), needle_size - first_chunk.size()); |
191 | 0 | size_t current_pos = pos; |
192 | 0 | while (true) { |
193 | 0 | size_t found_pos = lhs.find(first_chunk, current_pos); |
194 | 0 | if (found_pos == absl::string_view::npos || |
195 | 0 | found_pos > lhs.size() - needle_size) { |
196 | 0 | return std::nullopt; |
197 | 0 | } |
198 | 0 | if (lhs.substr(found_pos + first_chunk.size(), |
199 | 0 | rest_of_needle.size()) == rest_of_needle) { |
200 | 0 | return found_pos; |
201 | 0 | } |
202 | 0 | current_pos = found_pos + 1; |
203 | 0 | } |
204 | 0 | }, |
205 | 0 | [&needle, pos](const absl::Cord& lhs) -> absl::optional<size_t> { |
206 | 0 | absl::Cord cord = lhs.Subcord(pos, lhs.size() - pos); |
207 | 0 | absl::Cord::CharIterator it = cord.Find(needle); |
208 | 0 | if (it == cord.char_end()) { |
209 | 0 | return std::nullopt; |
210 | 0 | } |
211 | 0 | return pos + |
212 | 0 | static_cast<size_t>(absl::Cord::Distance(cord.char_begin(), it)); |
213 | 0 | })); |
214 | 0 | } |
215 | | |
216 | 0 | ByteString ByteString::Substring(size_t pos, size_t npos) const { |
217 | 0 | ABSL_DCHECK_LE(npos, size()); |
218 | 0 | ABSL_DCHECK_LE(pos, npos); |
219 | |
|
220 | 0 | switch (GetKind()) { |
221 | 0 | case ByteStringKind::kSmall: { |
222 | 0 | ByteString result(UninitializedTag{}); |
223 | 0 | result.SetSmall(GetSmall().substr(pos, npos - pos)); |
224 | 0 | return result; |
225 | 0 | } |
226 | 0 | case ByteStringKind::kMedium: { |
227 | 0 | ByteString result(UninitializedTag{}); |
228 | 0 | result.SetMedium(GetMediumArena(), GetMedium().substr(pos, npos - pos)); |
229 | 0 | return result; |
230 | 0 | } |
231 | 0 | case ByteStringKind::kLarge: |
232 | 0 | ByteString result(UninitializedTag{}); |
233 | 0 | result.SetLarge(GetLargeArena(), rep_.large.data, rep_.large.offset + pos, |
234 | 0 | npos - pos); |
235 | 0 | return result; |
236 | 0 | } |
237 | 0 | } |
238 | | |
239 | 0 | void ByteString::RemovePrefix(size_t n) { |
240 | 0 | ABSL_DCHECK_LE(n, size()); |
241 | 0 | if (n == 0) { |
242 | 0 | return; |
243 | 0 | } |
244 | 0 | switch (GetKind()) { |
245 | 0 | case ByteStringKind::kSmall: |
246 | 0 | std::memmove(rep_.small.data, rep_.small.data + n, rep_.small.size - n); |
247 | 0 | rep_.small.size = rep_.small.size - n; |
248 | 0 | break; |
249 | 0 | case ByteStringKind::kMedium: |
250 | 0 | rep_.medium.data = rep_.medium.data + n; |
251 | 0 | rep_.medium.size = rep_.medium.size - n; |
252 | 0 | break; |
253 | 0 | case ByteStringKind::kLarge: |
254 | 0 | rep_.large.offset = rep_.large.offset + n; |
255 | 0 | rep_.large.size = rep_.large.size - n; |
256 | 0 | break; |
257 | 0 | } |
258 | 0 | } |
259 | | |
260 | 0 | void ByteString::RemoveSuffix(size_t n) { |
261 | 0 | ABSL_DCHECK_LE(n, size()); |
262 | 0 | if (n == 0) { |
263 | 0 | return; |
264 | 0 | } |
265 | 0 | switch (GetKind()) { |
266 | 0 | case ByteStringKind::kSmall: |
267 | 0 | rep_.small.size = rep_.small.size - n; |
268 | 0 | break; |
269 | 0 | case ByteStringKind::kMedium: |
270 | 0 | rep_.medium.size = rep_.medium.size - n; |
271 | 0 | break; |
272 | 0 | case ByteStringKind::kLarge: |
273 | 0 | rep_.large.size = rep_.large.size - n; |
274 | 0 | break; |
275 | 0 | } |
276 | 0 | } |
277 | | |
278 | 6.31k | void ByteString::CopyToArray(char* absl_nonnull out) const { |
279 | 6.31k | ABSL_DCHECK(out != nullptr); |
280 | 6.31k | switch (GetKind()) { |
281 | 6.22k | case ByteStringKind::kSmall: { |
282 | 6.22k | absl::string_view small = GetSmall(); |
283 | 6.22k | std::memcpy(out, small.data(), small.size()); |
284 | 6.22k | } break; |
285 | 97 | case ByteStringKind::kMedium: { |
286 | 97 | absl::string_view medium = GetMedium(); |
287 | 97 | std::memcpy(out, medium.data(), medium.size()); |
288 | 97 | } break; |
289 | 0 | case ByteStringKind::kLarge: { |
290 | 0 | (CopyCordToArray)(*rep_.large.data, rep_.large.offset, rep_.large.size, |
291 | 0 | out); |
292 | 0 | } break; |
293 | 6.31k | } |
294 | 6.31k | } |
295 | | |
296 | 228k | std::string ByteString::ToString() const { |
297 | 228k | switch (GetKind()) { |
298 | 167k | case ByteStringKind::kSmall: |
299 | 167k | return std::string(GetSmall()); |
300 | 61.4k | case ByteStringKind::kMedium: |
301 | 61.4k | return std::string(GetMedium()); |
302 | 0 | case ByteStringKind::kLarge: { |
303 | 0 | std::string result; |
304 | 0 | absl::StringResizeAndOverwrite( |
305 | 0 | result, rep_.large.size, |
306 | 0 | [this](char* buffer, size_t buffer_size) -> size_t { |
307 | 0 | (CopyCordToArray)(*rep_.large.data, rep_.large.offset, |
308 | 0 | rep_.large.size, buffer); |
309 | 0 | return rep_.large.size; |
310 | 0 | }); |
311 | 0 | return result; |
312 | 0 | } |
313 | 228k | } |
314 | 228k | } |
315 | | |
316 | 0 | void ByteString::CopyToString(std::string* absl_nonnull out) const { |
317 | 0 | ABSL_DCHECK(out != nullptr); |
318 | 0 | switch (GetKind()) { |
319 | 0 | case ByteStringKind::kSmall: |
320 | 0 | out->assign(GetSmall()); |
321 | 0 | break; |
322 | 0 | case ByteStringKind::kMedium: |
323 | 0 | out->assign(GetMedium()); |
324 | 0 | break; |
325 | 0 | case ByteStringKind::kLarge: |
326 | 0 | absl::StringResizeAndOverwrite( |
327 | 0 | *out, rep_.large.size, |
328 | 0 | [this](char* buffer, size_t buffer_size) -> size_t { |
329 | 0 | CopyCordToArray(*rep_.large.data, rep_.large.offset, |
330 | 0 | rep_.large.size, buffer); |
331 | 0 | return rep_.large.size; |
332 | 0 | }); |
333 | 0 | break; |
334 | 0 | } |
335 | 0 | } |
336 | | |
337 | 0 | void ByteString::AppendToString(std::string* absl_nonnull out) const { |
338 | 0 | ABSL_DCHECK(out != nullptr); |
339 | 0 | switch (GetKind()) { |
340 | 0 | case ByteStringKind::kSmall: |
341 | 0 | out->append(GetSmall()); |
342 | 0 | break; |
343 | 0 | case ByteStringKind::kMedium: |
344 | 0 | out->append(GetMedium()); |
345 | 0 | break; |
346 | 0 | case ByteStringKind::kLarge: |
347 | 0 | AppendCordToString(*rep_.large.data, rep_.large.offset, rep_.large.size, |
348 | 0 | *out); |
349 | 0 | break; |
350 | 0 | } |
351 | 0 | } |
352 | | |
353 | 0 | absl::Cord ByteString::ToCord() const { |
354 | 0 | switch (GetKind()) { |
355 | 0 | case ByteStringKind::kSmall: |
356 | 0 | return absl::Cord(GetSmall()); |
357 | 0 | case ByteStringKind::kMedium: |
358 | 0 | return absl::Cord(GetMedium()); |
359 | 0 | case ByteStringKind::kLarge: |
360 | 0 | return GetLarge(); |
361 | 0 | } |
362 | 0 | } |
363 | | |
364 | 0 | void ByteString::CopyToCord(absl::Cord* absl_nonnull out) const { |
365 | 0 | ABSL_DCHECK(out != nullptr); |
366 | 0 | switch (GetKind()) { |
367 | 0 | case ByteStringKind::kSmall: |
368 | 0 | *out = absl::Cord(GetSmall()); |
369 | 0 | break; |
370 | 0 | case ByteStringKind::kMedium: |
371 | 0 | *out = absl::Cord(GetMedium()); |
372 | 0 | break; |
373 | 0 | case ByteStringKind::kLarge: |
374 | 0 | *out = GetLarge(); |
375 | 0 | break; |
376 | 0 | } |
377 | 0 | } |
378 | | |
379 | 0 | void ByteString::AppendToCord(absl::Cord* absl_nonnull out) const { |
380 | 0 | ABSL_DCHECK(out != nullptr); |
381 | 0 | switch (GetKind()) { |
382 | 0 | case ByteStringKind::kSmall: |
383 | 0 | out->Append(GetSmall()); |
384 | 0 | break; |
385 | 0 | case ByteStringKind::kMedium: |
386 | 0 | out->Append(GetMedium()); |
387 | 0 | break; |
388 | 0 | case ByteStringKind::kLarge: |
389 | 0 | out->Append(GetLarge()); |
390 | 0 | break; |
391 | 0 | } |
392 | 0 | } |
393 | | |
394 | | absl::string_view ByteString::ToStringView( |
395 | 1.75k | std::string* absl_nonnull scratch) const { |
396 | 1.75k | ABSL_DCHECK(scratch != nullptr); |
397 | 1.75k | switch (GetKind()) { |
398 | 280 | case ByteStringKind::kSmall: |
399 | 280 | return GetSmall(); |
400 | 1.47k | case ByteStringKind::kMedium: |
401 | 1.47k | return GetMedium(); |
402 | 0 | case ByteStringKind::kLarge: |
403 | 0 | if (auto flat = rep_.large.data->TryFlat(); flat.has_value()) { |
404 | 0 | return flat->substr(rep_.large.offset, rep_.large.size); |
405 | 0 | } |
406 | 0 | absl::StringResizeAndOverwrite( |
407 | 0 | *scratch, rep_.large.size, |
408 | 0 | [this](char* buffer, size_t buffer_size) -> size_t { |
409 | 0 | CopyCordToArray(*rep_.large.data, rep_.large.offset, |
410 | 0 | rep_.large.size, buffer); |
411 | 0 | return rep_.large.size; |
412 | 0 | }); |
413 | 0 | return absl::string_view(*scratch); |
414 | 1.75k | } |
415 | 1.75k | } |
416 | | |
417 | 0 | ByteString ByteString::Clone(google::protobuf::Arena* absl_nonnull arena) const { |
418 | 0 | ABSL_DCHECK(arena != nullptr); |
419 | 0 | switch (GetKind()) { |
420 | 0 | case ByteStringKind::kSmall: { |
421 | 0 | ByteString result(UninitializedTag{}); |
422 | 0 | result.SetSmall(GetSmall()); |
423 | 0 | return result; |
424 | 0 | } |
425 | 0 | case ByteStringKind::kMedium: { |
426 | 0 | google::protobuf::Arena* absl_nullable other_arena = GetMediumArena(); |
427 | 0 | if (other_arena != arena) { |
428 | 0 | return From(GetMedium(), arena); |
429 | 0 | } |
430 | 0 | return *this; |
431 | 0 | } |
432 | 0 | case ByteStringKind::kLarge: { |
433 | 0 | google::protobuf::Arena* absl_nullable other_arena = GetLargeArena(); |
434 | 0 | if (other_arena != arena) { |
435 | 0 | return From(GetLarge(), arena); |
436 | 0 | } |
437 | 0 | return *this; |
438 | 0 | } |
439 | 0 | } |
440 | 0 | } |
441 | | |
442 | | void ByteString::CopyCordToArray(const absl::Cord& cord, size_t offset, |
443 | 0 | size_t size, char* data) { |
444 | 0 | for (auto chunk : cord.Chunks()) { |
445 | 0 | if (size == 0) { |
446 | 0 | break; |
447 | 0 | } |
448 | 0 | if (offset > 0) { |
449 | 0 | size_t min_offset = std::min(chunk.size(), offset); |
450 | 0 | offset -= min_offset; |
451 | 0 | if (offset > 0) { |
452 | 0 | continue; |
453 | 0 | } |
454 | 0 | chunk.remove_prefix(min_offset); |
455 | 0 | } |
456 | 0 | size_t min_size = std::min(size, chunk.size()); |
457 | 0 | std::memcpy(data, chunk.data(), min_size); |
458 | 0 | data += min_size; |
459 | 0 | size -= min_size; |
460 | 0 | } |
461 | 0 | } |
462 | | |
463 | | void ByteString::AppendCordToString(const absl::Cord& cord, size_t offset, |
464 | 0 | size_t size, std::string& data) { |
465 | 0 | size_t original_size = data.size(); |
466 | 0 | size_t target_size = original_size + size; |
467 | 0 | absl::StringResizeAndOverwrite( |
468 | 0 | data, original_size + size, |
469 | 0 | [&cord, offset, size, original_size, target_size]( |
470 | 0 | char* buf, size_t buf_size) -> size_t { |
471 | 0 | CopyCordToArray(cord, offset, size, buf + original_size); |
472 | 0 | return target_size; |
473 | 0 | }); |
474 | 0 | } |
475 | | |
476 | | absl::string_view LegacyByteString(const ByteString& string, bool stable, |
477 | 502 | google::protobuf::Arena* absl_nonnull arena) { |
478 | 502 | ABSL_DCHECK(arena != nullptr); |
479 | 502 | if (string.empty()) { |
480 | 38 | return absl::string_view(); |
481 | 38 | } |
482 | 464 | const ByteStringKind kind = string.GetKind(); |
483 | 464 | if (kind == ByteStringKind::kMedium && string.GetMediumArena() == arena) { |
484 | 7 | google::protobuf::Arena* absl_nullable other_arena = string.GetMediumArena(); |
485 | 7 | if (other_arena == arena || other_arena == nullptr) { |
486 | | // Legacy values do not preserve arena. For speed, we assume the arena is |
487 | | // compatible. |
488 | 7 | return string.GetMedium(); |
489 | 7 | } |
490 | 7 | } |
491 | 457 | if (stable && kind == ByteStringKind::kSmall) { |
492 | 0 | return string.GetSmall(); |
493 | 0 | } |
494 | 457 | std::string* absl_nonnull result = google::protobuf::Arena::Create<std::string>(arena); |
495 | 457 | switch (kind) { |
496 | 401 | case ByteStringKind::kSmall: |
497 | 401 | result->assign(string.GetSmall()); |
498 | 401 | break; |
499 | 56 | case ByteStringKind::kMedium: |
500 | 56 | result->assign(string.GetMedium()); |
501 | 56 | break; |
502 | 0 | case ByteStringKind::kLarge: |
503 | 0 | absl::CopyCordToString(string.GetLarge(), result); |
504 | 0 | break; |
505 | 457 | } |
506 | 457 | return absl::string_view(*result); |
507 | 457 | } |
508 | | |
509 | | } // namespace cel::common_internal |