Coverage Report

Created: 2026-05-27 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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 <cstddef>
18
#include <cstdint>
19
#include <cstring>
20
#include <string>
21
#include <tuple>
22
#include <utility>
23
24
#include "absl/base/nullability.h"
25
#include "absl/base/optimization.h"
26
#include "absl/functional/overload.h"
27
#include "absl/hash/hash.h"
28
#include "absl/log/absl_check.h"
29
#include "absl/strings/cord.h"
30
#include "absl/strings/match.h"
31
#include "absl/strings/string_view.h"
32
#include "absl/types/optional.h"
33
#include "common/allocator.h"
34
#include "common/internal/metadata.h"
35
#include "common/internal/reference_count.h"
36
#include "common/memory.h"
37
#include "google/protobuf/arena.h"
38
39
namespace cel::common_internal {
40
41
namespace {
42
43
0
char* CopyCordToArray(const absl::Cord& cord, char* data) {
44
0
  for (auto chunk : cord.Chunks()) {
45
0
    std::memcpy(data, chunk.data(), chunk.size());
46
0
    data += chunk.size();
47
0
  }
48
0
  return data;
49
0
}
50
51
template <typename T>
52
T ConsumeAndDestroy(T& object) {
53
  T consumed = std::move(object);
54
  object.~T();  // NOLINT(bugprone-use-after-move)
55
  return consumed;
56
}
57
58
}  // namespace
59
60
ByteString ByteString::Concat(const ByteString& lhs, const ByteString& rhs,
61
2.72k
                              google::protobuf::Arena* absl_nonnull arena) {
62
2.72k
  ABSL_DCHECK(arena != nullptr);
63
64
2.72k
  if (lhs.empty()) {
65
308
    return rhs;
66
308
  }
67
2.42k
  if (rhs.empty()) {
68
1.39k
    return lhs;
69
1.39k
  }
70
71
1.02k
  if (lhs.GetKind() == ByteStringKind::kLarge ||
72
1.02k
      rhs.GetKind() == ByteStringKind::kLarge) {
73
    // If either the left or right are absl::Cord, use absl::Cord.
74
0
    absl::Cord result;
75
0
    result.Append(lhs.ToCord());
76
0
    result.Append(rhs.ToCord());
77
0
    return ByteString(std::move(result));
78
0
  }
79
80
1.02k
  const size_t lhs_size = lhs.size();
81
1.02k
  const size_t rhs_size = rhs.size();
82
1.02k
  const size_t result_size = lhs_size + rhs_size;
83
1.02k
  ByteString result;
84
1.02k
  if (result_size <= kSmallByteStringCapacity) {
85
    // If the resulting string fits in inline storage, do it.
86
225
    result.rep_.small.size = result_size;
87
225
    result.rep_.small.arena = arena;
88
225
    lhs.CopyToArray(result.rep_.small.data);
89
225
    rhs.CopyToArray(result.rep_.small.data + lhs_size);
90
802
  } else {
91
    // Otherwise allocate on the arena.
92
802
    char* result_data =
93
802
        reinterpret_cast<char*>(arena->AllocateAligned(result_size));
94
802
    lhs.CopyToArray(result_data);
95
802
    rhs.CopyToArray(result_data + lhs_size);
96
802
    result.rep_.medium.data = result_data;
97
802
    result.rep_.medium.size = result_size;
98
802
    result.rep_.medium.owner =
99
802
        reinterpret_cast<uintptr_t>(arena) | kMetadataOwnerArenaBit;
100
802
    result.rep_.header.kind = ByteStringKind::kMedium;
101
802
  }
102
1.02k
  return result;
103
1.02k
}
104
105
30.3k
ByteString::ByteString(Allocator<> allocator, absl::string_view string) {
106
30.3k
  ABSL_DCHECK_LE(string.size(), max_size());
107
30.3k
  auto* arena = allocator.arena();
108
30.3k
  if (string.size() <= kSmallByteStringCapacity) {
109
24.8k
    SetSmall(arena, string);
110
24.8k
  } else {
111
5.46k
    SetMedium(arena, string);
112
5.46k
  }
113
30.3k
}
114
115
0
ByteString::ByteString(Allocator<> allocator, const std::string& string) {
116
0
  ABSL_DCHECK_LE(string.size(), max_size());
117
0
  auto* arena = allocator.arena();
118
0
  if (string.size() <= kSmallByteStringCapacity) {
119
0
    SetSmall(arena, string);
120
0
  } else {
121
0
    SetMedium(arena, string);
122
0
  }
123
0
}
124
125
6
ByteString::ByteString(Allocator<> allocator, std::string&& string) {
126
6
  ABSL_DCHECK_LE(string.size(), max_size());
127
6
  auto* arena = allocator.arena();
128
6
  if (string.size() <= kSmallByteStringCapacity) {
129
4
    SetSmall(arena, string);
130
4
  } else {
131
2
    SetMedium(arena, std::move(string));
132
2
  }
133
6
}
134
135
0
ByteString::ByteString(Allocator<> allocator, const absl::Cord& cord) {
136
0
  ABSL_DCHECK_LE(cord.size(), max_size());
137
0
  auto* arena = allocator.arena();
138
0
  if (cord.size() <= kSmallByteStringCapacity) {
139
0
    SetSmall(arena, cord);
140
0
  } else if (arena != nullptr) {
141
0
    SetMedium(arena, cord);
142
0
  } else {
143
0
    SetLarge(cord);
144
0
  }
145
0
}
146
147
128
ByteString ByteString::Borrowed(Borrower borrower, absl::string_view string) {
148
256
  ABSL_DCHECK(borrower != Borrower::None()) << "Borrowing from Owner::None()";
149
128
  auto* arena = borrower.arena();
150
128
  if (string.size() <= kSmallByteStringCapacity || arena != nullptr) {
151
128
    return ByteString(arena, string);
152
128
  }
153
0
  const auto* refcount = BorrowerRelease(borrower);
154
  // A nullptr refcount indicates somebody called us to borrow something that
155
  // has no owner. If this is the case, we fallback to assuming operator
156
  // new/delete and convert it to a reference count.
157
0
  if (refcount == nullptr) {
158
0
    std::tie(refcount, string) = MakeReferenceCountedString(string);
159
0
  } else {
160
0
    StrongRef(*refcount);
161
0
  }
162
0
  return ByteString(refcount, string);
163
128
}
164
165
0
ByteString ByteString::Borrowed(Borrower borrower, const absl::Cord& cord) {
166
0
  ABSL_DCHECK(borrower != Borrower::None()) << "Borrowing from Owner::None()";
167
0
  return ByteString(borrower.arena(), cord);
168
0
}
169
170
ByteString::ByteString(const ReferenceCount* absl_nonnull refcount,
171
0
                       absl::string_view string) {
172
0
  ABSL_DCHECK_LE(string.size(), max_size());
173
0
  SetMedium(string, reinterpret_cast<uintptr_t>(refcount) |
174
0
                        kMetadataOwnerReferenceCountBit);
175
0
}
176
177
ByteString::ByteString(ByteString::ExternalStringTag,
178
0
                       absl::string_view string) {
179
0
  if (string.size() <= kSmallByteStringCapacity) {
180
0
    SetSmall(nullptr, string);
181
0
  } else {
182
0
    SetExternalMedium(string);
183
0
  }
184
0
}
185
186
0
ByteString ByteString::FromExternal(absl::string_view string) {
187
0
  return ByteString(ExternalStringTag{}, string);
188
0
}
189
190
0
google::protobuf::Arena* absl_nullable ByteString::GetArena() const {
191
0
  switch (GetKind()) {
192
0
    case ByteStringKind::kSmall:
193
0
      return GetSmallArena();
194
0
    case ByteStringKind::kMedium:
195
0
      return GetMediumArena();
196
0
    case ByteStringKind::kLarge:
197
0
      return nullptr;
198
0
  }
199
0
}
200
201
5.86k
bool ByteString::empty() const {
202
5.86k
  switch (GetKind()) {
203
3.52k
    case ByteStringKind::kSmall:
204
3.52k
      return rep_.small.size == 0;
205
2.34k
    case ByteStringKind::kMedium:
206
2.34k
      return rep_.medium.size == 0;
207
0
    case ByteStringKind::kLarge:
208
0
      return GetLarge().empty();
209
5.86k
  }
210
5.86k
}
211
212
2.05k
size_t ByteString::size() const {
213
2.05k
  switch (GetKind()) {
214
1.11k
    case ByteStringKind::kSmall:
215
1.11k
      return rep_.small.size;
216
937
    case ByteStringKind::kMedium:
217
937
      return rep_.medium.size;
218
0
    case ByteStringKind::kLarge:
219
0
      return GetLarge().size();
220
2.05k
  }
221
2.05k
}
222
223
0
absl::string_view ByteString::Flatten() {
224
0
  switch (GetKind()) {
225
0
    case ByteStringKind::kSmall:
226
0
      return GetSmall();
227
0
    case ByteStringKind::kMedium:
228
0
      return GetMedium();
229
0
    case ByteStringKind::kLarge:
230
0
      return GetLarge().Flatten();
231
0
  }
232
0
}
233
234
0
absl::optional<absl::string_view> ByteString::TryFlat() const {
235
0
  switch (GetKind()) {
236
0
    case ByteStringKind::kSmall:
237
0
      return GetSmall();
238
0
    case ByteStringKind::kMedium:
239
0
      return GetMedium();
240
0
    case ByteStringKind::kLarge:
241
0
      return GetLarge().TryFlat();
242
0
  }
243
0
}
244
245
3.27k
bool ByteString::Equals(absl::string_view rhs) const {
246
3.27k
  return Visit(absl::Overload(
247
3.27k
      [&rhs](absl::string_view lhs) -> bool { return lhs == rhs; },
248
3.27k
      [&rhs](const absl::Cord& lhs) -> bool { return lhs == rhs; }));
249
3.27k
}
250
251
0
bool ByteString::Equals(const absl::Cord& rhs) const {
252
0
  return Visit(absl::Overload(
253
0
      [&rhs](absl::string_view lhs) -> bool { return lhs == rhs; },
254
0
      [&rhs](const absl::Cord& lhs) -> bool { return lhs == rhs; }));
255
0
}
256
257
775
int ByteString::Compare(absl::string_view rhs) const {
258
775
  return Visit(absl::Overload(
259
775
      [&rhs](absl::string_view lhs) -> int { return lhs.compare(rhs); },
260
775
      [&rhs](const absl::Cord& lhs) -> int { return lhs.Compare(rhs); }));
261
775
}
262
263
0
int ByteString::Compare(const absl::Cord& rhs) const {
264
0
  return Visit(absl::Overload(
265
0
      [&rhs](absl::string_view lhs) -> int { return -rhs.Compare(lhs); },
266
0
      [&rhs](const absl::Cord& lhs) -> int { return lhs.Compare(rhs); }));
267
0
}
268
269
0
bool ByteString::StartsWith(absl::string_view rhs) const {
270
0
  return Visit(absl::Overload(
271
0
      [&rhs](absl::string_view lhs) -> bool {
272
0
        return absl::StartsWith(lhs, rhs);
273
0
      },
274
0
      [&rhs](const absl::Cord& lhs) -> bool { return lhs.StartsWith(rhs); }));
275
0
}
276
277
0
bool ByteString::StartsWith(const absl::Cord& rhs) const {
278
0
  return Visit(absl::Overload(
279
0
      [&rhs](absl::string_view lhs) -> bool {
280
0
        return lhs.size() >= rhs.size() && lhs.substr(0, rhs.size()) == rhs;
281
0
      },
282
0
      [&rhs](const absl::Cord& lhs) -> bool { return lhs.StartsWith(rhs); }));
283
0
}
284
285
0
bool ByteString::EndsWith(absl::string_view rhs) const {
286
0
  return Visit(absl::Overload(
287
0
      [&rhs](absl::string_view lhs) -> bool {
288
0
        return absl::EndsWith(lhs, rhs);
289
0
      },
290
0
      [&rhs](const absl::Cord& lhs) -> bool { return lhs.EndsWith(rhs); }));
291
0
}
292
293
0
bool ByteString::EndsWith(const absl::Cord& rhs) const {
294
0
  return Visit(absl::Overload(
295
0
      [&rhs](absl::string_view lhs) -> bool {
296
0
        return lhs.size() >= rhs.size() &&
297
0
               lhs.substr(lhs.size() - rhs.size()) == rhs;
298
0
      },
299
0
      [&rhs](const absl::Cord& lhs) -> bool { return lhs.EndsWith(rhs); }));
300
0
}
301
302
absl::optional<size_t> ByteString::Find(absl::string_view needle,
303
0
                                        size_t pos) const {
304
0
  ABSL_DCHECK_LE(pos, size());
305
306
0
  return Visit(absl::Overload(
307
0
      [&needle, pos](absl::string_view lhs) -> absl::optional<size_t> {
308
0
        absl::string_view::size_type i = lhs.find(needle, pos);
309
0
        if (i == absl::string_view::npos) {
310
0
          return absl::nullopt;
311
0
        }
312
0
        return i;
313
0
      },
314
0
      [&needle, pos](const absl::Cord& lhs) -> absl::optional<size_t> {
315
0
        absl::Cord cord = lhs.Subcord(pos, lhs.size() - pos);
316
0
        absl::Cord::CharIterator it = cord.Find(needle);
317
0
        if (it == cord.char_end()) {
318
0
          return absl::nullopt;
319
0
        }
320
0
        return pos +
321
0
               static_cast<size_t>(absl::Cord::Distance(cord.char_begin(), it));
322
0
      }));
323
0
}
324
325
absl::optional<size_t> ByteString::Find(const absl::Cord& needle,
326
0
                                        size_t pos) const {
327
0
  ABSL_DCHECK_LE(pos, size());
328
329
0
  return Visit(absl::Overload(
330
0
      [&needle, pos](absl::string_view lhs) -> absl::optional<size_t> {
331
0
        if (auto flat_needle = needle.TryFlat(); flat_needle) {
332
0
          absl::string_view::size_type i = lhs.find(*flat_needle, pos);
333
0
          if (i == absl::string_view::npos) {
334
0
            return absl::nullopt;
335
0
          }
336
0
          return i;
337
0
        }
338
        // Needle is fragmented, we have to do a linear scan.
339
0
        const size_t needle_size = needle.size();
340
0
        if (pos + needle_size > lhs.size()) {
341
0
          return absl::nullopt;
342
0
        }
343
0
        if (ABSL_PREDICT_FALSE(needle_size == 0)) {
344
0
          return pos;
345
0
        }
346
        // Optimization: find the first chunk of the needle, then compare the
347
        // rest. If the first chunk is empty, `lhs.find` will return
348
        // `current_pos`, which correctly degrades to a linear scan.
349
0
        absl::string_view first_chunk = *needle.Chunks().begin();
350
0
        absl::Cord rest_of_needle = needle.Subcord(
351
0
            first_chunk.size(), needle_size - first_chunk.size());
352
0
        size_t current_pos = pos;
353
0
        while (true) {
354
0
          size_t found_pos = lhs.find(first_chunk, current_pos);
355
0
          if (found_pos == absl::string_view::npos ||
356
0
              found_pos > lhs.size() - needle_size) {
357
0
            return absl::nullopt;
358
0
          }
359
0
          if (lhs.substr(found_pos + first_chunk.size(),
360
0
                         rest_of_needle.size()) == rest_of_needle) {
361
0
            return found_pos;
362
0
          }
363
0
          current_pos = found_pos + 1;
364
0
        }
365
0
      },
366
0
      [&needle, pos](const absl::Cord& lhs) -> absl::optional<size_t> {
367
0
        absl::Cord cord = lhs.Subcord(pos, lhs.size() - pos);
368
0
        absl::Cord::CharIterator it = cord.Find(needle);
369
0
        if (it == cord.char_end()) {
370
0
          return absl::nullopt;
371
0
        }
372
0
        return pos +
373
0
               static_cast<size_t>(absl::Cord::Distance(cord.char_begin(), it));
374
0
      }));
375
0
}
376
377
0
ByteString ByteString::Substring(size_t pos, size_t npos) const {
378
0
  ABSL_DCHECK_LE(npos, size());
379
0
  ABSL_DCHECK_LE(pos, npos);
380
381
0
  switch (GetKind()) {
382
0
    case ByteStringKind::kSmall: {
383
0
      ByteString result;
384
0
      result.rep_.header.kind = ByteStringKind::kSmall;
385
0
      result.rep_.small.size = npos - pos;
386
0
      std::memcpy(result.rep_.small.data, rep_.small.data + pos,
387
0
                  result.rep_.small.size);
388
0
      result.rep_.small.arena = GetSmallArena();
389
0
      return result;
390
0
    }
391
0
    case ByteStringKind::kMedium: {
392
0
      ByteString result(*this);
393
0
      result.rep_.medium.data += pos;
394
0
      result.rep_.medium.size = npos - pos;
395
0
      return result;
396
0
    }
397
0
    case ByteStringKind::kLarge:
398
0
      return ByteString(GetLarge().Subcord(pos, npos - pos));
399
0
  }
400
0
}
401
402
0
void ByteString::RemovePrefix(size_t n) {
403
0
  ABSL_DCHECK_LE(n, size());
404
0
  if (n == 0) {
405
0
    return;
406
0
  }
407
0
  switch (GetKind()) {
408
0
    case ByteStringKind::kSmall:
409
0
      std::memmove(rep_.small.data, rep_.small.data + n, rep_.small.size - n);
410
0
      rep_.small.size -= n;
411
0
      break;
412
0
    case ByteStringKind::kMedium:
413
0
      rep_.medium.data += n;
414
0
      rep_.medium.size -= n;
415
0
      if (rep_.medium.size <= kSmallByteStringCapacity) {
416
0
        const auto* refcount = GetMediumReferenceCount();
417
0
        SetSmall(GetMediumArena(), GetMedium());
418
0
        StrongUnref(refcount);
419
0
      }
420
0
      break;
421
0
    case ByteStringKind::kLarge: {
422
0
      auto& large = GetLarge();
423
0
      const auto large_size = large.size();
424
0
      const auto new_large_pos = n;
425
0
      const auto new_large_size = large_size - n;
426
0
      large = large.Subcord(new_large_pos, new_large_size);
427
0
      if (new_large_size <= kSmallByteStringCapacity) {
428
0
        auto large_copy = std::move(large);
429
0
        DestroyLarge();
430
0
        SetSmall(nullptr, large_copy);
431
0
      }
432
0
    } break;
433
0
  }
434
0
}
435
436
0
void ByteString::RemoveSuffix(size_t n) {
437
0
  ABSL_DCHECK_LE(n, size());
438
0
  if (n == 0) {
439
0
    return;
440
0
  }
441
0
  switch (GetKind()) {
442
0
    case ByteStringKind::kSmall:
443
0
      rep_.small.size -= n;
444
0
      break;
445
0
    case ByteStringKind::kMedium:
446
0
      rep_.medium.size -= n;
447
0
      if (rep_.medium.size <= kSmallByteStringCapacity) {
448
0
        const auto* refcount = GetMediumReferenceCount();
449
0
        SetSmall(GetMediumArena(), GetMedium());
450
0
        StrongUnref(refcount);
451
0
      }
452
0
      break;
453
0
    case ByteStringKind::kLarge: {
454
0
      auto& large = GetLarge();
455
0
      const auto large_size = large.size();
456
0
      const auto new_large_pos = 0;
457
0
      const auto new_large_size = large_size - n;
458
0
      large = large.Subcord(new_large_pos, new_large_size);
459
0
      if (new_large_size <= kSmallByteStringCapacity) {
460
0
        auto large_copy = std::move(large);
461
0
        DestroyLarge();
462
0
        SetSmall(nullptr, large_copy);
463
0
      }
464
0
    } break;
465
0
  }
466
0
}
467
468
2.05k
void ByteString::CopyToArray(char* absl_nonnull out) const {
469
2.05k
  ABSL_DCHECK(out != nullptr);
470
471
2.05k
  switch (GetKind()) {
472
1.11k
    case ByteStringKind::kSmall: {
473
1.11k
      absl::string_view small = GetSmall();
474
1.11k
      std::memcpy(out, small.data(), small.size());
475
1.11k
    } break;
476
937
    case ByteStringKind::kMedium: {
477
937
      absl::string_view medium = GetMedium();
478
937
      std::memcpy(out, medium.data(), medium.size());
479
937
    } break;
480
0
    case ByteStringKind::kLarge: {
481
0
      const absl::Cord& large = GetLarge();
482
0
      (CopyCordToArray)(large, out);
483
0
    } break;
484
2.05k
  }
485
2.05k
}
486
487
19.4k
std::string ByteString::ToString() const {
488
19.4k
  switch (GetKind()) {
489
17.0k
    case ByteStringKind::kSmall:
490
17.0k
      return std::string(GetSmall());
491
2.44k
    case ByteStringKind::kMedium:
492
2.44k
      return std::string(GetMedium());
493
0
    case ByteStringKind::kLarge:
494
0
      return static_cast<std::string>(GetLarge());
495
19.4k
  }
496
19.4k
}
497
498
0
void ByteString::CopyToString(std::string* absl_nonnull out) const {
499
0
  ABSL_DCHECK(out != nullptr);
500
501
0
  switch (GetKind()) {
502
0
    case ByteStringKind::kSmall:
503
0
      out->assign(GetSmall());
504
0
      break;
505
0
    case ByteStringKind::kMedium:
506
0
      out->assign(GetMedium());
507
0
      break;
508
0
    case ByteStringKind::kLarge:
509
0
      absl::CopyCordToString(GetLarge(), out);
510
0
      break;
511
0
  }
512
0
}
513
514
0
void ByteString::AppendToString(std::string* absl_nonnull out) const {
515
0
  ABSL_DCHECK(out != nullptr);
516
517
0
  switch (GetKind()) {
518
0
    case ByteStringKind::kSmall:
519
0
      out->append(GetSmall());
520
0
      break;
521
0
    case ByteStringKind::kMedium:
522
0
      out->append(GetMedium());
523
0
      break;
524
0
    case ByteStringKind::kLarge:
525
0
      absl::AppendCordToString(GetLarge(), out);
526
0
      break;
527
0
  }
528
0
}
529
530
namespace {
531
532
struct ReferenceCountReleaser {
533
  const ReferenceCount* absl_nonnull refcount;
534
535
0
  void operator()() const { StrongUnref(*refcount); }
536
};
537
538
}  // namespace
539
540
0
absl::Cord ByteString::ToCord() const& {
541
0
  switch (GetKind()) {
542
0
    case ByteStringKind::kSmall:
543
0
      return absl::Cord(GetSmall());
544
0
    case ByteStringKind::kMedium: {
545
0
      const auto* refcount = GetMediumReferenceCount();
546
0
      if (refcount != nullptr) {
547
0
        StrongRef(*refcount);
548
0
        return absl::MakeCordFromExternal(GetMedium(),
549
0
                                          ReferenceCountReleaser{refcount});
550
0
      }
551
0
      return absl::Cord(GetMedium());
552
0
    }
553
0
    case ByteStringKind::kLarge:
554
0
      return GetLarge();
555
0
  }
556
0
}
557
558
0
absl::Cord ByteString::ToCord() && {
559
0
  switch (GetKind()) {
560
0
    case ByteStringKind::kSmall:
561
0
      return absl::Cord(GetSmall());
562
0
    case ByteStringKind::kMedium: {
563
0
      const auto* refcount = GetMediumReferenceCount();
564
0
      if (refcount != nullptr) {
565
0
        auto medium = GetMedium();
566
0
        SetSmallEmpty(nullptr);
567
0
        return absl::MakeCordFromExternal(medium,
568
0
                                          ReferenceCountReleaser{refcount});
569
0
      }
570
0
      return absl::Cord(GetMedium());
571
0
    }
572
0
    case ByteStringKind::kLarge:
573
0
      return GetLarge();
574
0
  }
575
0
}
576
577
0
void ByteString::CopyToCord(absl::Cord* absl_nonnull out) const {
578
0
  ABSL_DCHECK(out != nullptr);
579
580
0
  switch (GetKind()) {
581
0
    case ByteStringKind::kSmall:
582
0
      *out = absl::Cord(GetSmall());
583
0
      break;
584
0
    case ByteStringKind::kMedium: {
585
0
      const auto* refcount = GetMediumReferenceCount();
586
0
      if (refcount != nullptr) {
587
0
        StrongRef(*refcount);
588
0
        *out = absl::MakeCordFromExternal(GetMedium(),
589
0
                                          ReferenceCountReleaser{refcount});
590
0
      } else {
591
0
        *out = absl::Cord(GetMedium());
592
0
      }
593
0
    } break;
594
0
    case ByteStringKind::kLarge:
595
0
      *out = GetLarge();
596
0
      break;
597
0
  }
598
0
}
599
600
0
void ByteString::AppendToCord(absl::Cord* absl_nonnull out) const {
601
0
  ABSL_DCHECK(out != nullptr);
602
603
0
  switch (GetKind()) {
604
0
    case ByteStringKind::kSmall:
605
0
      out->Append(GetSmall());
606
0
      break;
607
0
    case ByteStringKind::kMedium: {
608
0
      const auto* refcount = GetMediumReferenceCount();
609
0
      if (refcount != nullptr) {
610
0
        StrongRef(*refcount);
611
0
        out->Append(absl::MakeCordFromExternal(
612
0
            GetMedium(), ReferenceCountReleaser{refcount}));
613
0
      } else {
614
0
        out->Append(GetMedium());
615
0
      }
616
0
    } break;
617
0
    case ByteStringKind::kLarge:
618
0
      out->Append(GetLarge());
619
0
      break;
620
0
  }
621
0
}
622
623
absl::string_view ByteString::ToStringView(
624
0
    std::string* absl_nonnull scratch) const {
625
0
  ABSL_DCHECK(scratch != nullptr);
626
627
0
  switch (GetKind()) {
628
0
    case ByteStringKind::kSmall:
629
0
      return GetSmall();
630
0
    case ByteStringKind::kMedium:
631
0
      return GetMedium();
632
0
    case ByteStringKind::kLarge:
633
0
      if (auto flat = GetLarge().TryFlat(); flat) {
634
0
        return *flat;
635
0
      }
636
0
      absl::CopyCordToString(GetLarge(), scratch);
637
0
      return absl::string_view(*scratch);
638
0
  }
639
0
}
640
641
0
absl::string_view ByteString::AsStringView() const {
642
0
  const ByteStringKind kind = GetKind();
643
0
  ABSL_CHECK(kind == ByteStringKind::kSmall ||  // Crash OK
644
0
             kind == ByteStringKind::kMedium);
645
0
  switch (kind) {
646
0
    case ByteStringKind::kSmall:
647
0
      return GetSmall();
648
0
    case ByteStringKind::kMedium:
649
0
      return GetMedium();
650
0
    case ByteStringKind::kLarge:
651
0
      ABSL_UNREACHABLE();
652
0
  }
653
0
}
654
655
google::protobuf::Arena* absl_nullable ByteString::GetMediumArena(
656
284
    const MediumByteStringRep& rep) {
657
284
  if ((rep.owner & kMetadataOwnerBits) == kMetadataOwnerArenaBit) {
658
56
    return reinterpret_cast<google::protobuf::Arena*>(rep.owner &
659
56
                                            kMetadataOwnerPointerMask);
660
56
  }
661
228
  return nullptr;
662
284
}
663
664
const ReferenceCount* absl_nullable ByteString::GetMediumReferenceCount(
665
97.7k
    const MediumByteStringRep& rep) {
666
97.7k
  if ((rep.owner & kMetadataOwnerBits) == kMetadataOwnerReferenceCountBit) {
667
35.9k
    return reinterpret_cast<const ReferenceCount*>(rep.owner &
668
35.9k
                                                   kMetadataOwnerPointerMask);
669
35.9k
  }
670
61.8k
  return nullptr;
671
97.7k
}
672
673
void ByteString::Construct(const ByteString& other,
674
14.5k
                           absl::optional<Allocator<>> allocator) {
675
14.5k
  switch (other.GetKind()) {
676
2.38k
    case ByteStringKind::kSmall:
677
2.38k
      rep_.small = other.rep_.small;
678
2.38k
      if (allocator.has_value()) {
679
0
        rep_.small.arena = allocator->arena();
680
0
      }
681
2.38k
      break;
682
12.1k
    case ByteStringKind::kMedium:
683
12.1k
      if (allocator.has_value() &&
684
0
          allocator->arena() != other.GetMediumArena()) {
685
0
        SetMedium(allocator->arena(), other.GetMedium());
686
12.1k
      } else {
687
12.1k
        rep_.medium = other.rep_.medium;
688
12.1k
        StrongRef(GetMediumReferenceCount());
689
12.1k
      }
690
12.1k
      break;
691
0
    case ByteStringKind::kLarge:
692
0
      if (allocator.has_value() && allocator->arena() != nullptr) {
693
0
        SetMedium(allocator->arena(), other.GetLarge());
694
0
      } else {
695
0
        SetLarge(other.GetLarge());
696
0
      }
697
0
      break;
698
14.5k
  }
699
14.5k
}
700
701
void ByteString::Construct(ByteString& other,
702
103k
                           absl::optional<Allocator<>> allocator) {
703
103k
  switch (other.GetKind()) {
704
44.5k
    case ByteStringKind::kSmall:
705
44.5k
      rep_.small = other.rep_.small;
706
44.5k
      if (allocator.has_value()) {
707
0
        rep_.small.arena = allocator->arena();
708
0
      }
709
44.5k
      break;
710
59.0k
    case ByteStringKind::kMedium:
711
59.0k
      if (allocator.has_value() &&
712
0
          allocator->arena() != other.GetMediumArena()) {
713
0
        SetMedium(allocator->arena(), other.GetMedium());
714
59.0k
      } else {
715
59.0k
        rep_.medium = other.rep_.medium;
716
59.0k
        other.rep_.medium.owner = 0;
717
59.0k
      }
718
59.0k
      break;
719
0
    case ByteStringKind::kLarge:
720
0
      if (allocator.has_value() && allocator->arena() != nullptr) {
721
0
        SetMedium(allocator->arena(), other.GetLarge());
722
0
      } else {
723
0
        SetLarge(std::move(other.GetLarge()));
724
0
      }
725
0
      break;
726
103k
  }
727
103k
}
728
729
324
void ByteString::CopyFrom(const ByteString& other) {
730
324
  ABSL_DCHECK_NE(&other, this);
731
732
324
  switch (other.GetKind()) {
733
239
    case ByteStringKind::kSmall:
734
239
      switch (GetKind()) {
735
239
        case ByteStringKind::kSmall:
736
239
          break;
737
0
        case ByteStringKind::kMedium:
738
0
          DestroyMedium();
739
0
          break;
740
0
        case ByteStringKind::kLarge:
741
0
          DestroyLarge();
742
0
          break;
743
239
      }
744
239
      rep_.small = other.rep_.small;
745
239
      break;
746
85
    case ByteStringKind::kMedium:
747
85
      switch (GetKind()) {
748
85
        case ByteStringKind::kSmall:
749
85
          rep_.medium = other.rep_.medium;
750
85
          StrongRef(GetMediumReferenceCount());
751
85
          break;
752
0
        case ByteStringKind::kMedium:
753
0
          StrongRef(other.GetMediumReferenceCount());
754
0
          DestroyMedium();
755
0
          rep_.medium = other.rep_.medium;
756
0
          break;
757
0
        case ByteStringKind::kLarge:
758
0
          DestroyLarge();
759
0
          rep_.medium = other.rep_.medium;
760
0
          StrongRef(GetMediumReferenceCount());
761
0
          break;
762
85
      }
763
85
      break;
764
85
    case ByteStringKind::kLarge:
765
0
      switch (GetKind()) {
766
0
        case ByteStringKind::kSmall:
767
0
          SetLarge(other.GetLarge());
768
0
          break;
769
0
        case ByteStringKind::kMedium:
770
0
          DestroyMedium();
771
0
          SetLarge(other.GetLarge());
772
0
          break;
773
0
        case ByteStringKind::kLarge:
774
0
          GetLarge() = other.GetLarge();
775
0
          break;
776
0
      }
777
0
      break;
778
324
  }
779
324
}
780
781
430
void ByteString::MoveFrom(ByteString& other) {
782
430
  ABSL_DCHECK_NE(&other, this);
783
784
430
  switch (other.GetKind()) {
785
0
    case ByteStringKind::kSmall:
786
0
      switch (GetKind()) {
787
0
        case ByteStringKind::kSmall:
788
0
          break;
789
0
        case ByteStringKind::kMedium:
790
0
          DestroyMedium();
791
0
          break;
792
0
        case ByteStringKind::kLarge:
793
0
          DestroyLarge();
794
0
          break;
795
0
      }
796
0
      rep_.small = other.rep_.small;
797
0
      break;
798
430
    case ByteStringKind::kMedium:
799
430
      switch (GetKind()) {
800
0
        case ByteStringKind::kSmall:
801
0
          rep_.medium = other.rep_.medium;
802
0
          break;
803
430
        case ByteStringKind::kMedium:
804
430
          DestroyMedium();
805
430
          rep_.medium = other.rep_.medium;
806
430
          break;
807
0
        case ByteStringKind::kLarge:
808
0
          DestroyLarge();
809
0
          rep_.medium = other.rep_.medium;
810
0
          break;
811
430
      }
812
430
      other.rep_.medium.owner = 0;
813
430
      break;
814
0
    case ByteStringKind::kLarge:
815
0
      switch (GetKind()) {
816
0
        case ByteStringKind::kSmall:
817
0
          SetLarge(std::move(other.GetLarge()));
818
0
          break;
819
0
        case ByteStringKind::kMedium:
820
0
          DestroyMedium();
821
0
          SetLarge(std::move(other.GetLarge()));
822
0
          break;
823
0
        case ByteStringKind::kLarge:
824
0
          GetLarge() = std::move(other.GetLarge());
825
0
          break;
826
0
      }
827
0
      break;
828
430
  }
829
430
}
830
831
0
ByteString ByteString::Clone(google::protobuf::Arena* absl_nonnull arena) const {
832
0
  ABSL_DCHECK(arena != nullptr);
833
834
0
  switch (GetKind()) {
835
0
    case ByteStringKind::kSmall:
836
0
      return ByteString(arena, GetSmall());
837
0
    case ByteStringKind::kMedium: {
838
0
      google::protobuf::Arena* absl_nullable other_arena = GetMediumArena();
839
0
      if (arena != nullptr) {
840
0
        if (arena == other_arena) {
841
0
          return *this;
842
0
        }
843
0
        return ByteString(arena, GetMedium());
844
0
      }
845
0
      if (other_arena != nullptr) {
846
0
        return ByteString(arena, GetMedium());
847
0
      }
848
0
      return *this;
849
0
    }
850
0
    case ByteStringKind::kLarge:
851
0
      return ByteString(arena, GetLarge());
852
0
  }
853
0
}
854
855
1.54k
void ByteString::HashValue(absl::HashState state) const {
856
1.54k
  switch (GetKind()) {
857
1.06k
    case ByteStringKind::kSmall:
858
1.06k
      absl::HashState::combine(std::move(state), GetSmall());
859
1.06k
      break;
860
479
    case ByteStringKind::kMedium:
861
479
      absl::HashState::combine(std::move(state), GetMedium());
862
479
      break;
863
0
    case ByteStringKind::kLarge:
864
0
      absl::HashState::combine(std::move(state), GetLarge());
865
0
      break;
866
1.54k
  }
867
1.54k
}
868
869
0
void ByteString::Swap(ByteString& other) {
870
0
  ABSL_DCHECK_NE(&other, this);
871
0
  using std::swap;
872
873
0
  switch (other.GetKind()) {
874
0
    case ByteStringKind::kSmall:
875
0
      switch (GetKind()) {
876
0
        case ByteStringKind::kSmall:
877
          // small <=> small
878
0
          swap(rep_.small, other.rep_.small);
879
0
          break;
880
0
        case ByteStringKind::kMedium:
881
          // medium <=> small
882
0
          swap(rep_, other.rep_);
883
0
          break;
884
0
        case ByteStringKind::kLarge: {
885
0
          absl::Cord cord = std::move(GetLarge());
886
0
          DestroyLarge();
887
0
          rep_ = other.rep_;
888
0
          other.SetLarge(std::move(cord));
889
0
        } break;
890
0
      }
891
0
      break;
892
0
    case ByteStringKind::kMedium:
893
0
      switch (GetKind()) {
894
0
        case ByteStringKind::kSmall:
895
0
          swap(rep_, other.rep_);
896
0
          break;
897
0
        case ByteStringKind::kMedium:
898
0
          swap(rep_.medium, other.rep_.medium);
899
0
          break;
900
0
        case ByteStringKind::kLarge: {
901
0
          absl::Cord cord = std::move(GetLarge());
902
0
          DestroyLarge();
903
0
          rep_ = other.rep_;
904
0
          other.SetLarge(std::move(cord));
905
0
        } break;
906
0
      }
907
0
      break;
908
0
    case ByteStringKind::kLarge:
909
0
      switch (GetKind()) {
910
0
        case ByteStringKind::kSmall: {
911
0
          absl::Cord cord = std::move(other.GetLarge());
912
0
          other.DestroyLarge();
913
0
          other.rep_.small = rep_.small;
914
0
          SetLarge(std::move(cord));
915
0
        } break;
916
0
        case ByteStringKind::kMedium: {
917
0
          absl::Cord cord = std::move(other.GetLarge());
918
0
          other.DestroyLarge();
919
0
          other.rep_.medium = rep_.medium;
920
0
          SetLarge(std::move(cord));
921
0
        } break;
922
0
        case ByteStringKind::kLarge:
923
0
          swap(GetLarge(), other.GetLarge());
924
0
          break;
925
0
      }
926
0
      break;
927
0
  }
928
0
}
929
930
136k
void ByteString::Destroy() {
931
136k
  switch (GetKind()) {
932
60.8k
    case ByteStringKind::kSmall:
933
60.8k
      break;
934
75.9k
    case ByteStringKind::kMedium:
935
75.9k
      DestroyMedium();
936
75.9k
      break;
937
0
    case ByteStringKind::kLarge:
938
0
      DestroyLarge();
939
0
      break;
940
136k
  }
941
136k
}
942
943
void ByteString::SetSmall(google::protobuf::Arena* absl_nullable arena,
944
24.8k
                          absl::string_view string) {
945
24.8k
  ABSL_DCHECK_LE(string.size(), kSmallByteStringCapacity);
946
24.8k
  rep_.header.kind = ByteStringKind::kSmall;
947
24.8k
  rep_.small.size = string.size();
948
24.8k
  rep_.small.arena = arena;
949
24.8k
  std::memcpy(rep_.small.data, string.data(), rep_.small.size);
950
24.8k
}
951
952
void ByteString::SetSmall(google::protobuf::Arena* absl_nullable arena,
953
0
                          const absl::Cord& cord) {
954
0
  ABSL_DCHECK_LE(cord.size(), kSmallByteStringCapacity);
955
0
  rep_.header.kind = ByteStringKind::kSmall;
956
0
  rep_.small.size = cord.size();
957
0
  rep_.small.arena = arena;
958
0
  (CopyCordToArray)(cord, rep_.small.data);
959
0
}
960
961
void ByteString::SetMedium(google::protobuf::Arena* absl_nullable arena,
962
5.46k
                           absl::string_view string) {
963
5.46k
  ABSL_DCHECK_GT(string.size(), kSmallByteStringCapacity);
964
5.46k
  rep_.header.kind = ByteStringKind::kMedium;
965
5.46k
  rep_.medium.size = string.size();
966
5.46k
  if (arena != nullptr) {
967
0
    char* data = static_cast<char*>(
968
0
        arena->AllocateAligned(rep_.medium.size, alignof(char)));
969
0
    std::memcpy(data, string.data(), rep_.medium.size);
970
0
    rep_.medium.data = data;
971
0
    rep_.medium.owner =
972
0
        reinterpret_cast<uintptr_t>(arena) | kMetadataOwnerArenaBit;
973
5.46k
  } else {
974
5.46k
    auto pair = MakeReferenceCountedString(string);
975
5.46k
    rep_.medium.data = pair.second.data();
976
5.46k
    rep_.medium.owner = reinterpret_cast<uintptr_t>(pair.first) |
977
5.46k
                        kMetadataOwnerReferenceCountBit;
978
5.46k
  }
979
5.46k
}
980
981
0
void ByteString::SetExternalMedium(absl::string_view string) {
982
0
  ABSL_DCHECK_GT(string.size(), kSmallByteStringCapacity);
983
0
  rep_.header.kind = ByteStringKind::kMedium;
984
0
  rep_.medium.size = string.size();
985
0
  rep_.medium.data = string.data();
986
0
  rep_.medium.owner = 0;
987
0
}
988
989
void ByteString::SetMedium(google::protobuf::Arena* absl_nullable arena,
990
2
                           std::string&& string) {
991
2
  ABSL_DCHECK_GT(string.size(), kSmallByteStringCapacity);
992
2
  rep_.header.kind = ByteStringKind::kMedium;
993
2
  rep_.medium.size = string.size();
994
2
  if (arena != nullptr) {
995
0
    auto* data = google::protobuf::Arena::Create<std::string>(arena, std::move(string));
996
0
    rep_.medium.data = data->data();
997
0
    rep_.medium.owner =
998
0
        reinterpret_cast<uintptr_t>(arena) | kMetadataOwnerArenaBit;
999
2
  } else {
1000
2
    auto pair = MakeReferenceCountedString(std::move(string));
1001
2
    rep_.medium.data = pair.second.data();
1002
2
    rep_.medium.owner = reinterpret_cast<uintptr_t>(pair.first) |
1003
2
                        kMetadataOwnerReferenceCountBit;
1004
2
  }
1005
2
}
1006
1007
void ByteString::SetMedium(google::protobuf::Arena* absl_nonnull arena,
1008
0
                           const absl::Cord& cord) {
1009
0
  ABSL_DCHECK_GT(cord.size(), kSmallByteStringCapacity);
1010
0
  rep_.header.kind = ByteStringKind::kMedium;
1011
0
  rep_.medium.size = cord.size();
1012
0
  char* data = static_cast<char*>(
1013
0
      arena->AllocateAligned(rep_.medium.size, alignof(char)));
1014
0
  (CopyCordToArray)(cord, data);
1015
0
  rep_.medium.data = data;
1016
0
  rep_.medium.owner =
1017
0
      reinterpret_cast<uintptr_t>(arena) | kMetadataOwnerArenaBit;
1018
0
}
1019
1020
void ByteString::SetMedium(absl::string_view string, uintptr_t owner) {
1021
  ABSL_DCHECK_GT(string.size(), kSmallByteStringCapacity);
1022
  ABSL_DCHECK_NE(owner, 0);
1023
  rep_.header.kind = ByteStringKind::kMedium;
1024
  rep_.medium.size = string.size();
1025
  rep_.medium.data = string.data();
1026
  rep_.medium.owner = owner;
1027
}
1028
1029
0
void ByteString::SetLarge(const absl::Cord& cord) {
1030
0
  ABSL_DCHECK_GT(cord.size(), kSmallByteStringCapacity);
1031
0
  rep_.header.kind = ByteStringKind::kLarge;
1032
0
  ::new (static_cast<void*>(&rep_.large.data[0])) absl::Cord(cord);
1033
0
}
1034
1035
0
void ByteString::SetLarge(absl::Cord&& cord) {
1036
0
  ABSL_DCHECK_GT(cord.size(), kSmallByteStringCapacity);
1037
0
  rep_.header.kind = ByteStringKind::kLarge;
1038
0
  ::new (static_cast<void*>(&rep_.large.data[0])) absl::Cord(std::move(cord));
1039
0
}
1040
1041
absl::string_view LegacyByteString(const ByteString& string, bool stable,
1042
718
                                   google::protobuf::Arena* absl_nonnull arena) {
1043
718
  ABSL_DCHECK(arena != nullptr);
1044
718
  if (string.empty()) {
1045
37
    return absl::string_view();
1046
37
  }
1047
681
  const ByteStringKind kind = string.GetKind();
1048
681
  if (kind == ByteStringKind::kMedium && string.GetMediumArena() == arena) {
1049
28
    google::protobuf::Arena* absl_nullable other_arena = string.GetMediumArena();
1050
28
    if (other_arena == arena || other_arena == nullptr) {
1051
      // Legacy values do not preserve arena. For speed, we assume the arena is
1052
      // compatible.
1053
28
      return string.GetMedium();
1054
28
    }
1055
28
  }
1056
653
  if (stable && kind == ByteStringKind::kSmall) {
1057
0
    return string.GetSmall();
1058
0
  }
1059
653
  std::string* absl_nonnull result = google::protobuf::Arena::Create<std::string>(arena);
1060
653
  switch (kind) {
1061
425
    case ByteStringKind::kSmall:
1062
425
      result->assign(string.GetSmall());
1063
425
      break;
1064
228
    case ByteStringKind::kMedium:
1065
228
      result->assign(string.GetMedium());
1066
228
      break;
1067
0
    case ByteStringKind::kLarge:
1068
0
      absl::CopyCordToString(string.GetLarge(), result);
1069
0
      break;
1070
653
  }
1071
653
  return absl::string_view(*result);
1072
653
}
1073
1074
}  // namespace cel::common_internal