Coverage Report

Created: 2026-07-11 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/common/memory.h
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
#ifndef THIRD_PARTY_CEL_CPP_COMMON_MEMORY_H_
16
#define THIRD_PARTY_CEL_CPP_COMMON_MEMORY_H_
17
18
#include <cstddef>
19
#include <cstdint>
20
#include <memory>
21
#include <ostream>
22
#include <type_traits>
23
#include <utility>
24
25
#include "absl/base/attributes.h"
26
#include "absl/base/macros.h"
27
#include "absl/base/nullability.h"
28
#include "absl/base/optimization.h"
29
#include "absl/log/absl_check.h"
30
#include "absl/numeric/bits.h"
31
#include "common/allocator.h"
32
#include "common/arena.h"
33
#include "common/data.h"
34
#include "common/internal/metadata.h"
35
#include "common/internal/reference_count.h"
36
#include "common/reference_count.h"
37
#include "internal/exceptions.h"
38
#include "internal/to_address.h"  // IWYU pragma: keep
39
#include "google/protobuf/arena.h"
40
41
namespace cel {
42
43
// Obtain the address of the underlying element from a raw pointer or "fancy"
44
// pointer.
45
using internal::to_address;
46
47
// MemoryManagement is an enumeration of supported memory management forms
48
// underlying `cel::MemoryManager`.
49
enum class MemoryManagement {
50
  // Region-based (a.k.a. arena). Memory is allocated in fixed size blocks and
51
  // deallocated all at once upon destruction of the `cel::MemoryManager`.
52
  kPooling = 1,
53
  // Reference counting. Memory is allocated with an associated reference
54
  // counter. When the reference counter hits 0, it is deallocated.
55
  kReferenceCounting,
56
};
57
58
std::ostream& operator<<(std::ostream& out, MemoryManagement memory_management);
59
60
class ABSL_ATTRIBUTE_TRIVIAL_ABI [[nodiscard]] Owner;
61
class Borrower;
62
template <typename T>
63
class ABSL_ATTRIBUTE_TRIVIAL_ABI [[nodiscard]] Unique;
64
template <typename T>
65
class ABSL_ATTRIBUTE_TRIVIAL_ABI [[nodiscard]] Owned;
66
template <typename T>
67
class Borrowed;
68
template <typename T>
69
struct Ownable;
70
template <typename T>
71
struct Borrowable;
72
73
class MemoryManager;
74
class ReferenceCountingMemoryManager;
75
class PoolingMemoryManager;
76
77
namespace common_internal {
78
template <typename T>
79
inline constexpr bool kNotMessageLiteAndNotData =
80
    std::conjunction_v<std::negation<std::is_base_of<google::protobuf::MessageLite, T>>,
81
                       std::negation<std::is_base_of<Data, T>>>;
82
template <typename To, typename From>
83
inline constexpr bool kIsPointerConvertible = std::is_convertible_v<From*, To*>;
84
template <typename To, typename From>
85
inline constexpr bool kNotSameAndIsPointerConvertible =
86
    std::conjunction_v<std::negation<std::is_same<To, From>>,
87
                       std::bool_constant<kIsPointerConvertible<To, From>>>;
88
89
// Clears the contents of `owner`, and returns the reference count if in use.
90
const ReferenceCount* absl_nullable OwnerRelease(Owner owner) noexcept;
91
const ReferenceCount* absl_nullable BorrowerRelease(Borrower borrower) noexcept;
92
template <typename T>
93
Owned<const T> WrapEternal(const T* value);
94
95
// Pointer tag used by `cel::Unique` to indicate that the destructor needs to be
96
// registered with the arena, but it has not been done yet. Must be done when
97
// releasing.
98
inline constexpr uintptr_t kUniqueArenaUnownedBit = uintptr_t{1} << 0;
99
inline constexpr uintptr_t kUniqueArenaBits = kUniqueArenaUnownedBit;
100
inline constexpr uintptr_t kUniqueArenaPointerMask = ~kUniqueArenaBits;
101
}  // namespace common_internal
102
103
template <typename T, typename... Args>
104
Owned<T> AllocateShared(Allocator<> allocator, Args&&... args);
105
106
template <typename T>
107
Owned<T> WrapShared(T* object, Allocator<> allocator);
108
109
// `Owner` represents a reference to some co-owned data, of which this owner is
110
// one of the co-owners. When using reference counting, `Owner` performs
111
// increment/decrement where appropriate similar to `std::shared_ptr`.
112
// `Borrower` is similar to `Owner`, except that it is always trivially
113
// copyable/destructible. In that sense, `Borrower` is similar to
114
// `std::reference_wrapper<const Owner>`.
115
class ABSL_ATTRIBUTE_TRIVIAL_ABI [[nodiscard]] Owner final {
116
 private:
117
  static constexpr uintptr_t kNone = common_internal::kMetadataOwnerNone;
118
  static constexpr uintptr_t kReferenceCountBit =
119
      common_internal::kMetadataOwnerReferenceCountBit;
120
  static constexpr uintptr_t kArenaBit =
121
      common_internal::kMetadataOwnerArenaBit;
122
  static constexpr uintptr_t kBits = common_internal::kMetadataOwnerBits;
123
  static constexpr uintptr_t kPointerMask =
124
      common_internal::kMetadataOwnerPointerMask;
125
126
 public:
127
0
  static Owner None() noexcept { return Owner(); }
128
129
0
  static Owner Allocator(Allocator<> allocator) noexcept {
130
0
    auto* arena = allocator.arena();
131
0
    return arena != nullptr ? Arena(arena) : None();
132
0
  }
133
134
  static Owner Arena(google::protobuf::Arena* absl_nonnull arena
135
0
                         ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept {
136
0
    ABSL_DCHECK(arena != nullptr);
137
0
    return Owner(reinterpret_cast<uintptr_t>(arena) | kArenaBit);
138
0
  }
139
140
  static Owner Arena(std::nullptr_t) = delete;
141
142
  static Owner ReferenceCount(const ReferenceCount* absl_nonnull reference_count
143
0
                                  ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept {
144
0
    ABSL_DCHECK(reference_count != nullptr);
145
0
    common_internal::StrongRef(*reference_count);
146
0
    return Owner(reinterpret_cast<uintptr_t>(reference_count) |
147
0
                 kReferenceCountBit);
148
0
  }
149
150
  static Owner ReferenceCount(std::nullptr_t) = delete;
151
152
  Owner() = default;
153
154
0
  Owner(const Owner& other) noexcept : Owner(CopyFrom(other.ptr_)) {}
155
156
0
  Owner(Owner&& other) noexcept : Owner(MoveFrom(other.ptr_)) {}
157
158
  template <typename T>
159
  // NOLINTNEXTLINE(google-explicit-constructor)
160
  Owner(const Owned<T>& owned) noexcept;
161
162
  template <typename T>
163
  // NOLINTNEXTLINE(google-explicit-constructor)
164
  Owner(Owned<T>&& owned) noexcept;
165
166
  explicit Owner(Borrower borrower) noexcept;
167
168
  template <typename T>
169
  explicit Owner(Borrowed<T> borrowed) noexcept;
170
171
0
  ~Owner() { Destroy(ptr_); }
172
173
0
  Owner& operator=(const Owner& other) noexcept {
174
0
    if (ptr_ != other.ptr_) {
175
0
      Destroy(ptr_);
176
0
      ptr_ = CopyFrom(other.ptr_);
177
0
    }
178
0
    return *this;
179
0
  }
180
181
0
  Owner& operator=(Owner&& other) noexcept {
182
0
    if (ABSL_PREDICT_TRUE(this != &other)) {
183
0
      Destroy(ptr_);
184
0
      ptr_ = MoveFrom(other.ptr_);
185
0
    }
186
0
    return *this;
187
0
  }
188
189
  template <typename T>
190
  // NOLINTNEXTLINE(google-explicit-constructor)
191
  Owner& operator=(const Owned<T>& owned) noexcept;
192
193
  template <typename T>
194
  // NOLINTNEXTLINE(google-explicit-constructor)
195
  Owner& operator=(Owned<T>&& owned) noexcept;
196
197
0
  explicit operator bool() const noexcept { return !IsNone(ptr_); }
198
199
0
  google::protobuf::Arena* absl_nullable arena() const noexcept {
200
0
    return (ptr_ & Owner::kBits) == Owner::kArenaBit
201
0
               ? reinterpret_cast<google::protobuf::Arena*>(ptr_ & Owner::kPointerMask)
202
0
               : nullptr;
203
0
  }
204
205
0
  void reset() noexcept {
206
0
    Destroy(ptr_);
207
0
    ptr_ = 0;
208
0
  }
209
210
  // Tests whether two owners have ownership over the same data, that is they
211
  // are co-owners.
212
0
  friend bool operator==(const Owner& lhs, const Owner& rhs) noexcept {
213
0
    // A reference count and arena can never occupy the same memory address, so
214
0
    // we can compare for equality without masking off the bits.
215
0
    return lhs.ptr_ == rhs.ptr_;
216
0
  }
217
218
 private:
219
  template <typename T>
220
  friend class Unique;
221
  friend class Borrower;
222
  template <typename T, typename... Args>
223
  friend Owned<T> AllocateShared(cel::Allocator<> allocator, Args&&... args);
224
  template <typename T>
225
  friend Owned<T> WrapShared(T* object, cel::Allocator<> allocator);
226
  template <typename U>
227
  friend struct Ownable;
228
  friend const common_internal::ReferenceCount* absl_nullable
229
  common_internal::OwnerRelease(Owner owner) noexcept;
230
  friend const common_internal::ReferenceCount* absl_nullable
231
  common_internal::BorrowerRelease(Borrower borrower) noexcept;
232
  friend struct ArenaTraits<Owner>;
233
234
0
  constexpr explicit Owner(uintptr_t ptr) noexcept : ptr_(ptr) {}
235
236
0
  static constexpr bool IsNone(uintptr_t ptr) noexcept { return ptr == kNone; }
237
238
0
  static constexpr bool IsArena(uintptr_t ptr) noexcept {
239
0
    return (ptr & kArenaBit) != kNone;
240
0
  }
241
242
0
  static constexpr bool IsReferenceCount(uintptr_t ptr) noexcept {
243
0
    return (ptr & kReferenceCountBit) != kNone;
244
0
  }
245
246
  ABSL_ATTRIBUTE_RETURNS_NONNULL
247
0
  static google::protobuf::Arena* absl_nonnull AsArena(uintptr_t ptr) noexcept {
248
0
    ABSL_ASSERT(IsArena(ptr));
249
0
    return reinterpret_cast<google::protobuf::Arena*>(ptr & kPointerMask);
250
0
  }
251
252
  ABSL_ATTRIBUTE_RETURNS_NONNULL
253
  static const common_internal::ReferenceCount* absl_nonnull AsReferenceCount(
254
0
      uintptr_t ptr) noexcept {
255
0
    ABSL_ASSERT(IsReferenceCount(ptr));
256
0
    return reinterpret_cast<const common_internal::ReferenceCount*>(
257
0
        ptr & kPointerMask);
258
0
  }
259
260
0
  static uintptr_t CopyFrom(uintptr_t other) noexcept { return Own(other); }
261
262
0
  static uintptr_t MoveFrom(uintptr_t& other) noexcept {
263
0
    return std::exchange(other, kNone);
264
0
  }
265
266
0
  static void Destroy(uintptr_t ptr) noexcept { Unown(ptr); }
267
268
0
  static uintptr_t Own(uintptr_t ptr) noexcept {
269
0
    if (IsReferenceCount(ptr)) {
270
0
      const auto* refcount = Owner::AsReferenceCount(ptr);
271
0
      ABSL_ASSUME(refcount != nullptr);
272
0
      common_internal::StrongRef(refcount);
273
0
    }
274
0
    return ptr;
275
0
  }
276
277
0
  static void Unown(uintptr_t ptr) noexcept {
278
0
    if (IsReferenceCount(ptr)) {
279
0
      const auto* reference_count = AsReferenceCount(ptr);
280
0
      ABSL_ASSUME(reference_count != nullptr);
281
0
      common_internal::StrongUnref(reference_count);
282
0
    }
283
0
  }
284
285
  uintptr_t ptr_ = kNone;
286
};
287
288
0
inline bool operator!=(const Owner& lhs, const Owner& rhs) noexcept {
289
0
  return !operator==(lhs, rhs);
290
0
}
291
292
namespace common_internal {
293
294
0
inline const ReferenceCount* absl_nullable OwnerRelease(Owner owner) noexcept {
295
0
  uintptr_t ptr = std::exchange(owner.ptr_, kMetadataOwnerNone);
296
0
  if (Owner::IsReferenceCount(ptr)) {
297
0
    return Owner::AsReferenceCount(ptr);
298
0
  }
299
0
  return nullptr;
300
0
}
301
302
}  // namespace common_internal
303
304
template <>
305
struct ArenaTraits<Owner> {
306
0
  static bool trivially_destructible(const Owner& owner) {
307
0
    return !Owner::IsReferenceCount(owner.ptr_);
308
0
  }
309
};
310
311
// `Borrower` represents a reference to some borrowed data, where the data has
312
// at least one owner. When using reference counting, `Borrower` does not
313
// participate in incrementing/decrementing the reference count. Thus `Borrower`
314
// will not keep the underlying data alive.
315
class Borrower final {
316
 public:
317
0
  static Borrower None() noexcept { return Borrower(); }
318
319
0
  static Borrower Allocator(Allocator<> allocator) noexcept {
320
0
    auto* arena = allocator.arena();
321
0
    return arena != nullptr ? Arena(arena) : None();
322
0
  }
323
324
  static Borrower Arena(google::protobuf::Arena* absl_nonnull arena
325
12.5k
                            ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept {
326
12.5k
    ABSL_DCHECK(arena != nullptr);
327
12.5k
    return Borrower(reinterpret_cast<uintptr_t>(arena) | Owner::kArenaBit);
328
12.5k
  }
329
330
  static Borrower Arena(std::nullptr_t) = delete;
331
332
  static Borrower ReferenceCount(
333
      const ReferenceCount* absl_nonnull reference_count
334
0
          ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept {
335
0
    ABSL_DCHECK(reference_count != nullptr);
336
0
    return Borrower(reinterpret_cast<uintptr_t>(reference_count) |
337
0
                    Owner::kReferenceCountBit);
338
0
  }
339
340
  static Borrower ReferenceCount(std::nullptr_t) = delete;
341
342
  Borrower() = default;
343
  Borrower(const Borrower&) = default;
344
  Borrower(Borrower&&) = default;
345
  Borrower& operator=(const Borrower&) = default;
346
  Borrower& operator=(Borrower&&) = default;
347
348
  template <typename T>
349
  // NOLINTNEXTLINE(google-explicit-constructor)
350
  Borrower(const Owned<T>& owned ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept;
351
352
  template <typename T>
353
  // NOLINTNEXTLINE(google-explicit-constructor)
354
  Borrower(Borrowed<T> borrowed) noexcept;
355
356
  // NOLINTNEXTLINE(google-explicit-constructor)
357
  Borrower(const Owner& owner ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
358
0
      : ptr_(owner.ptr_) {}
359
360
  // NOLINTNEXTLINE(google-explicit-constructor)
361
  Borrower& operator=(
362
0
      const Owner& owner ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept {
363
0
    ptr_ = owner.ptr_;
364
0
    return *this;
365
0
  }
366
367
  Borrower& operator=(Owner&&) = delete;
368
369
  template <typename T>
370
  Borrower& operator=(
371
      const Owned<T>& owned ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept;
372
373
  template <typename T>
374
  Borrower& operator=(Owned<T>&&) = delete;
375
376
  template <typename T>
377
  // NOLINTNEXTLINE(google-explicit-constructor)
378
  Borrower& operator=(Borrowed<T> borrowed) noexcept;
379
380
0
  explicit operator bool() const noexcept { return !Owner::IsNone(ptr_); }
381
382
12.5k
  google::protobuf::Arena* absl_nullable arena() const noexcept {
383
12.5k
    return (ptr_ & Owner::kBits) == Owner::kArenaBit
384
12.5k
               ? reinterpret_cast<google::protobuf::Arena*>(ptr_ & Owner::kPointerMask)
385
12.5k
               : nullptr;
386
12.5k
  }
387
388
0
  void reset() noexcept { ptr_ = 0; }
389
390
  // Tests whether two borrowers are borrowing the same data.
391
0
  friend bool operator==(Borrower lhs, Borrower rhs) noexcept {
392
0
    // A reference count and arena can never occupy the same memory address, so
393
0
    // we can compare for equality without masking off the bits.
394
0
    return lhs.ptr_ == rhs.ptr_;
395
0
  }
396
397
 private:
398
  friend class Owner;
399
  template <typename U>
400
  friend struct Borrowable;
401
  friend const common_internal::ReferenceCount* absl_nullable
402
  common_internal::BorrowerRelease(Borrower borrower) noexcept;
403
404
12.5k
  constexpr explicit Borrower(uintptr_t ptr) noexcept : ptr_(ptr) {}
405
406
  uintptr_t ptr_ = Owner::kNone;
407
};
408
409
0
inline bool operator!=(Borrower lhs, Borrower rhs) noexcept {
410
0
  return !operator==(lhs, rhs);
411
0
}
412
413
0
inline bool operator==(Borrower lhs, const Owner& rhs) noexcept {
414
0
  return operator==(lhs, Borrower(rhs));
415
0
}
416
417
0
inline bool operator==(const Owner& lhs, Borrower rhs) noexcept {
418
0
  return operator==(Borrower(lhs), rhs);
419
0
}
420
421
0
inline bool operator!=(Borrower lhs, const Owner& rhs) noexcept {
422
0
  return !operator==(lhs, rhs);
423
0
}
424
425
0
inline bool operator!=(const Owner& lhs, Borrower rhs) noexcept {
426
0
  return !operator==(lhs, rhs);
427
0
}
428
429
inline Owner::Owner(Borrower borrower) noexcept
430
    : ptr_(Owner::Own(borrower.ptr_)) {}
431
432
namespace common_internal {
433
434
inline const ReferenceCount* absl_nullable BorrowerRelease(
435
0
    Borrower borrower) noexcept {
436
0
  uintptr_t ptr = borrower.ptr_;
437
0
  if (Owner::IsReferenceCount(ptr)) {
438
0
    return Owner::AsReferenceCount(ptr);
439
0
  }
440
0
  return nullptr;
441
0
}
442
443
}  // namespace common_internal
444
445
template <typename T, typename... Args>
446
Unique<T> AllocateUnique(Allocator<> allocator, Args&&... args);
447
448
// Wrap an already created `T` in `Unique`. Requires that `T` is not const,
449
// otherwise `GetArena()` may return slightly unexpected results depending on if
450
// it is the default value.
451
template <typename T>
452
std::enable_if_t<!std::is_const_v<T>, Unique<T>> WrapUnique(T* object);
453
454
template <typename T>
455
Unique<T> WrapUnique(T* object, Allocator<> allocator);
456
457
// `Unique<T>` points to an object which was allocated using `Allocator<>` or
458
// `Allocator<T>`. It has ownership over the object, and will perform any
459
// destruction and deallocation required. `Unique` must not outlive the
460
// underlying arena, if any. Unlike `Owned` and `Borrowed`, `Unique` supports
461
// arena incompatible objects. It is very similar to `std::unique_ptr` when
462
// using a custom deleter.
463
//
464
// IMPLEMENTATION NOTES:
465
// When utilizing arenas, we optionally perform a risky optimization via
466
// `AllocateUnique`. We do not use `Arena::Create`, instead we directly allocate
467
// the bytes and construct it in place ourselves. This avoids registering the
468
// destructor when required. Instead we register the destructor ourselves, if
469
// required, during `Unique::release`. This allows us to avoid deferring
470
// destruction of the object until the arena is destroyed, avoiding the cost
471
// involved in doing so.
472
template <typename T>
473
class ABSL_ATTRIBUTE_TRIVIAL_ABI [[nodiscard]] Unique final {
474
 public:
475
  using element_type = T;
476
477
  static_assert(!std::is_array_v<T>, "T must not be an array");
478
  static_assert(!std::is_reference_v<T>, "T must not be a reference");
479
  static_assert(!std::is_volatile_v<T>, "T must not be volatile qualified");
480
481
0
  Unique() = default;
482
  Unique(const Unique&) = delete;
483
  Unique& operator=(const Unique&) = delete;
484
485
  explicit Unique(T* ptr) noexcept
486
      : Unique(ptr, common_internal::GetArena(ptr)) {}
487
488
  // NOLINTNEXTLINE(google-explicit-constructor)
489
  Unique(std::nullptr_t) noexcept : Unique() {}
490
491
0
  Unique(Unique&& other) noexcept : Unique(other.ptr_, other.arena_) {
492
0
    other.ptr_ = nullptr;
493
0
  }
494
495
  template <typename U,
496
            typename = std::enable_if_t<
497
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
498
  // NOLINTNEXTLINE(google-explicit-constructor)
499
  Unique(Unique<U>&& other) noexcept : Unique(other.ptr_, other.arena_) {
500
    other.ptr_ = nullptr;
501
  }
502
503
0
  ~Unique() { Delete(); }
504
505
0
  Unique& operator=(Unique&& other) noexcept {
506
0
    if (ABSL_PREDICT_TRUE(this != &other)) {
507
0
      Delete();
508
0
      ptr_ = other.ptr_;
509
0
      arena_ = other.arena_;
510
0
      other.ptr_ = nullptr;
511
0
    }
512
0
    return *this;
513
0
  }
514
515
  template <typename U,
516
            typename = std::enable_if_t<
517
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
518
  // NOLINTNEXTLINE(google-explicit-constructor)
519
  Unique& operator=(U* other) noexcept {
520
    reset(other);
521
    return *this;
522
  }
523
524
  template <typename U,
525
            typename = std::enable_if_t<
526
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
527
  // NOLINTNEXTLINE(google-explicit-constructor)
528
  Unique& operator=(Unique<U>&& other) noexcept {
529
    Delete();
530
    ptr_ = other.ptr_;
531
    arena_ = other.arena_;
532
    other.ptr_ = nullptr;
533
    return *this;
534
  }
535
536
  // NOLINTNEXTLINE(google-explicit-constructor)
537
  Unique& operator=(std::nullptr_t) noexcept {
538
    reset();
539
    return *this;
540
  }
541
542
0
  T& operator*() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
543
0
    ABSL_DCHECK(static_cast<bool>(*this));
544
0
    return *get();
545
0
  }
546
547
0
  T* absl_nonnull operator->() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
548
0
    ABSL_DCHECK(static_cast<bool>(*this));
549
0
    return get();
550
0
  }
551
552
  // Relinquishes ownership of `T*`, returning it. If `T` was allocated and
553
  // constructed using an arena, no further action is required. If `T` was
554
  // allocated and constructed without an arena, the caller must eventually call
555
  // `delete`.
556
0
  ABSL_MUST_USE_RESULT T* release() noexcept {
557
0
    PreRelease();
558
0
    return std::exchange(ptr_, nullptr);
559
0
  }
560
561
  void reset() noexcept { reset(nullptr); }
562
563
  void reset(T* ptr) noexcept {
564
    Delete();
565
    ptr_ = ptr;
566
    arena_ = reinterpret_cast<uintptr_t>(common_internal::GetArena(ptr));
567
  }
568
569
  void reset(std::nullptr_t) noexcept {
570
    Delete();
571
    ptr_ = nullptr;
572
    arena_ = 0;
573
  }
574
575
0
  explicit operator bool() const noexcept { return get() != nullptr; }
576
577
0
  google::protobuf::Arena* absl_nullable arena() const noexcept {
578
0
    return reinterpret_cast<google::protobuf::Arena*>(
579
0
        arena_ & common_internal::kUniqueArenaPointerMask);
580
0
  }
581
582
  friend void swap(Unique& lhs, Unique& rhs) noexcept {
583
    using std::swap;
584
    swap(lhs.ptr_, rhs.ptr_);
585
    swap(lhs.arena_, rhs.arena_);
586
  }
587
588
 private:
589
  template <typename U>
590
  friend class Unique;
591
  template <typename U>
592
  friend class Owned;
593
  template <typename U, typename... Args>
594
  friend Unique<U> AllocateUnique(Allocator<> allocator, Args&&... args);
595
  template <typename U>
596
  friend Unique<U> WrapUnique(U* object, Allocator<> allocator);
597
  friend class ReferenceCountingMemoryManager;
598
  friend class PoolingMemoryManager;
599
  friend struct std::pointer_traits<Unique<T>>;
600
  friend struct ArenaTraits<Unique<T>>;
601
602
  static constexpr bool kNeedsArenaDestructor =
603
      !std::is_trivially_destructible_v<T> &&
604
      !google::protobuf::Arena::is_destructor_skippable<T>::value &&
605
      !std::is_base_of_v<google::protobuf::MessageLite, T>;
606
607
0
  Unique(T* ptr, uintptr_t arena) noexcept : ptr_(ptr), arena_(arena) {}
608
609
  Unique(T* ptr, google::protobuf::Arena* arena, bool unowned = false) noexcept
610
0
      : Unique(ptr,
611
0
               reinterpret_cast<uintptr_t>(arena) |
612
0
                   (unowned ? common_internal::kUniqueArenaUnownedBit : 0)) {
613
0
    ABSL_ASSERT(!unowned || (unowned && arena != nullptr));
614
0
  }
615
616
  Unique(google::protobuf::Arena* arena, T* ptr, bool unowned = false) noexcept
617
      : Unique(ptr, arena, unowned) {}
618
619
0
  T* get() const noexcept { return ptr_; }
620
621
0
  void Delete() const noexcept {
622
0
    if (static_cast<bool>(*this)) {
623
0
      if (arena_ != 0) {
624
0
        if ((arena_ & common_internal::kUniqueArenaBits) ==
625
0
            common_internal::kUniqueArenaUnownedBit) {
626
          // We never registered the destructor, call it if necessary.
627
          if constexpr (kNeedsArenaDestructor) {
628
            std::destroy_at(ptr_);
629
          }
630
0
        }
631
0
      } else {
632
0
        delete ptr_;
633
0
      }
634
0
    }
635
0
  }
636
637
0
  void PreRelease() noexcept {
638
    if constexpr (kNeedsArenaDestructor) {
639
      if (static_cast<bool>(*this) &&
640
          (arena_ & common_internal::kUniqueArenaBits) ==
641
              common_internal::kUniqueArenaUnownedBit) {
642
        // We never registered the destructor, call it if necessary.
643
        arena()->OwnDestructor(const_cast<std::remove_const_t<T>*>(ptr_));
644
        arena_ &= common_internal::kUniqueArenaPointerMask;
645
      }
646
    }
647
0
  }
648
649
  void Release(T** ptr, Owner* owner) noexcept {
650
    if (ptr_ == nullptr) {
651
      *ptr = nullptr;
652
      return;
653
    }
654
    PreRelease();
655
    *ptr = std::exchange(ptr_, nullptr);
656
    if (arena_ == 0) {
657
      owner->ptr_ = reinterpret_cast<uintptr_t>(
658
                        common_internal::MakeDeletingReferenceCount(*ptr)) |
659
                    common_internal::kMetadataOwnerReferenceCountBit;
660
    } else {
661
      owner->ptr_ = reinterpret_cast<uintptr_t>(arena()) |
662
                    common_internal::kMetadataOwnerArenaBit;
663
    }
664
  }
665
666
  T* ptr_ = nullptr;
667
  // Potentially tagged pointer to `google::protobuf::Arena`. The tag is used to determine
668
  // whether we still need to register the destructor with the `google::protobuf::Arena`.
669
  uintptr_t arena_ = 0;
670
};
671
672
template <typename T>
673
Unique(T*) -> Unique<T>;
674
675
template <typename T, typename... Args>
676
Unique<T> AllocateUnique(Allocator<> allocator, Args&&... args) {
677
  using U = std::remove_cv_t<T>;
678
  static_assert(!std::is_reference_v<U>, "T must not be a reference");
679
  static_assert(!std::is_array_v<U>, "T must not be an array");
680
681
  U* object;
682
  google::protobuf::Arena* absl_nullable arena = allocator.arena();
683
  bool unowned;
684
  if constexpr (google::protobuf::Arena::is_arena_constructable<U>::value) {
685
    object = google::protobuf::Arena::Create<U>(arena, std::forward<Args>(args)...);
686
    // For arena-compatible proto types, let the Arena::Create handle
687
    // registering the destructor call.
688
    // Otherwise, Unique<T> retains a pointer to the owning arena so it may
689
    // conditionally register T::~T depending on usage.
690
    unowned = false;
691
  } else {
692
    void* p = allocator.allocate_bytes(sizeof(U), alignof(U));
693
    CEL_INTERNAL_TRY {
694
      if constexpr (ArenaTraits<>::constructible<U>()) {
695
        object = ::new (p) U(arena, std::forward<Args>(args)...);
696
      } else {
697
        object = ::new (p) U(std::forward<Args>(args)...);
698
      }
699
    }
700
    CEL_INTERNAL_CATCH_ANY {
701
      allocator.deallocate_bytes(p, sizeof(U), alignof(U));
702
      CEL_INTERNAL_RETHROW;
703
    }
704
    unowned =
705
        arena != nullptr && !ArenaTraits<>::trivially_destructible(*object);
706
  }
707
  return Unique<T>(object, arena, unowned);
708
}
709
710
template <typename T>
711
std::enable_if_t<!std::is_const_v<T>, Unique<T>> WrapUnique(T* object) {
712
  return Unique<T>(object);
713
}
714
715
template <typename T>
716
0
Unique<T> WrapUnique(T* object, Allocator<> allocator) {
717
0
  return Unique<T>(object, allocator.arena());
718
0
}
719
720
template <typename T>
721
inline bool operator==(const Unique<T>& lhs, std::nullptr_t) {
722
  return !static_cast<bool>(lhs);
723
}
724
725
template <typename T>
726
inline bool operator==(std::nullptr_t, const Unique<T>& rhs) {
727
  return !static_cast<bool>(rhs);
728
}
729
730
template <typename T>
731
0
inline bool operator!=(const Unique<T>& lhs, std::nullptr_t) {
732
0
  return static_cast<bool>(lhs);
733
0
}
734
735
template <typename T>
736
inline bool operator!=(std::nullptr_t, const Unique<T>& rhs) {
737
  return static_cast<bool>(rhs);
738
}
739
740
}  // namespace cel
741
742
namespace std {
743
744
template <typename T>
745
struct pointer_traits<cel::Unique<T>> {
746
  using pointer = cel::Unique<T>;
747
  using element_type = typename cel::Unique<T>::element_type;
748
  using difference_type = ptrdiff_t;
749
750
  template <typename U>
751
  using rebind = cel::Unique<U>;
752
753
0
  static element_type* to_address(const pointer& p) noexcept { return p.ptr_; }
754
};
755
756
}  // namespace std
757
758
namespace cel {
759
760
template <typename T>
761
struct ArenaTraits<Unique<T>> {
762
  static bool trivially_destructible(const Unique<T>& unique) {
763
    return unique.arena_ != 0 &&
764
           (unique.arena_ & common_internal::kUniqueArenaBits) == 0;
765
  }
766
};
767
768
// `Owned<T>` points to an object which was allocated using `Allocator<>` or
769
// `Allocator<T>`. It has co-ownership over the object. `T` must meet the named
770
// requirement `ArenaConstructable`.
771
template <typename T>
772
class ABSL_ATTRIBUTE_TRIVIAL_ABI [[nodiscard]] Owned final {
773
 public:
774
  using element_type = T;
775
776
  static_assert(!std::is_array_v<T>, "T must not be an array");
777
  static_assert(!std::is_reference_v<T>, "T must not be a reference");
778
  static_assert(!std::is_volatile_v<T>, "T must not be volatile qualified");
779
  static_assert(!std::is_void_v<T>, "T must not be void");
780
781
  Owned() = default;
782
  Owned(const Owned&) = default;
783
  Owned& operator=(const Owned&) = default;
784
785
  Owned(Owned&& other) noexcept
786
      : Owned(std::exchange(other.value_, nullptr), std::move(other.owner_)) {}
787
788
  template <typename U,
789
            typename = std::enable_if_t<
790
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
791
  // NOLINTNEXTLINE(google-explicit-constructor)
792
  Owned(const Owned<U>& other) noexcept : Owned(other.value_, other.owner_) {}
793
794
  template <typename U,
795
            typename = std::enable_if_t<
796
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
797
  // NOLINTNEXTLINE(google-explicit-constructor)
798
  Owned(Owned<U>&& other) noexcept
799
      : Owned(std::exchange(other.value_, nullptr), std::move(other.owner_)) {}
800
801
  template <typename U, typename = std::enable_if_t<
802
                            common_internal::kIsPointerConvertible<T, U>>>
803
  explicit Owned(Borrowed<U> other) noexcept;
804
805
  template <typename U, typename = std::enable_if_t<
806
                            common_internal::kIsPointerConvertible<T, U>>>
807
  // NOLINTNEXTLINE(google-explicit-constructor)
808
  Owned(Unique<U>&& other) : Owned() {
809
    other.Release(&value_, &owner_);
810
  }
811
812
  Owned(Owner owner, T* value ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
813
      : Owned(value, std::move(owner)) {}
814
815
  // NOLINTNEXTLINE(google-explicit-constructor)
816
  Owned(std::nullptr_t) noexcept : Owned() {}
817
818
  Owned& operator=(Owned&& other) noexcept {
819
    if (ABSL_PREDICT_TRUE(this != &other)) {
820
      value_ = std::exchange(other.value_, nullptr);
821
      owner_ = std::move(other.owner_);
822
    }
823
    return *this;
824
  }
825
826
  template <typename U,
827
            typename = std::enable_if_t<
828
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
829
  // NOLINTNEXTLINE(google-explicit-constructor)
830
  Owned& operator=(const Owned<U>& other) noexcept {
831
    value_ = other.value_;
832
    owner_ = other.owner_;
833
    return *this;
834
  }
835
836
  template <typename U,
837
            typename = std::enable_if_t<
838
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
839
  // NOLINTNEXTLINE(google-explicit-constructor)
840
  Owned& operator=(Owned<U>&& other) noexcept {
841
    value_ = std::exchange(other.value_, nullptr);
842
    owner_ = std::move(other.owner_);
843
    return *this;
844
  }
845
846
  template <typename U, typename = std::enable_if_t<
847
                            common_internal::kIsPointerConvertible<T, U>>>
848
  // NOLINTNEXTLINE(google-explicit-constructor)
849
  Owned& operator=(Borrowed<U> other) noexcept;
850
851
  template <typename U, typename = std::enable_if_t<
852
                            common_internal::kIsPointerConvertible<T, U>>>
853
  // NOLINTNEXTLINE(google-explicit-constructor)
854
  Owned& operator=(Unique<U>&& other) {
855
    owner_.reset();
856
    other.Release(&value_, &owner_);
857
    return *this;
858
  }
859
860
  // NOLINTNEXTLINE(google-explicit-constructor)
861
  Owned& operator=(std::nullptr_t) noexcept {
862
    reset();
863
    return *this;
864
  }
865
866
  T& operator*() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
867
    ABSL_DCHECK(static_cast<bool>(*this));
868
    return *get();
869
  }
870
871
  T* absl_nonnull operator->() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
872
    ABSL_DCHECK(static_cast<bool>(*this));
873
    return get();
874
  }
875
876
  void reset() noexcept {
877
    value_ = nullptr;
878
    owner_.reset();
879
  }
880
881
  google::protobuf::Arena* absl_nullable arena() const noexcept { return owner_.arena(); }
882
883
  explicit operator bool() const noexcept { return get() != nullptr; }
884
885
  friend void swap(Owned& lhs, Owned& rhs) noexcept {
886
    using std::swap;
887
    swap(lhs.value_, rhs.value_);
888
    swap(lhs.owner_, rhs.owner_);
889
  }
890
891
 private:
892
  friend class Owner;
893
  friend class Borrower;
894
  template <typename U>
895
  friend class Owned;
896
  template <typename U>
897
  friend class Borrowed;
898
  template <typename U>
899
  friend struct Ownable;
900
  template <typename U, typename... Args>
901
  friend Owned<U> AllocateShared(Allocator<> allocator, Args&&... args);
902
  template <typename U>
903
  friend Owned<U> WrapShared(U* object, Allocator<> allocator);
904
  template <typename U>
905
  friend Owned<const U> common_internal::WrapEternal(const U* value);
906
  friend struct std::pointer_traits<Owned<T>>;
907
  friend struct ArenaTraits<Owned<T>>;
908
909
  Owned(T* value, Owner owner) noexcept
910
      : value_(value), owner_(std::move(owner)) {}
911
912
  T* get() const noexcept { return value_; }
913
914
  T* value_ = nullptr;
915
  Owner owner_;
916
};
917
918
template <typename T>
919
Owned(T*) -> Owned<T>;
920
template <typename T>
921
Owned(Unique<T>) -> Owned<T>;
922
template <typename T>
923
Owned(Owner, T*) -> Owned<T>;
924
template <typename T>
925
Owned(Borrowed<T>) -> Owned<T>;
926
927
}  // namespace cel
928
929
namespace std {
930
931
template <typename T>
932
struct pointer_traits<cel::Owned<T>> {
933
  using pointer = cel::Owned<T>;
934
  using element_type = typename cel::Owned<T>::element_type;
935
  using difference_type = ptrdiff_t;
936
937
  template <typename U>
938
  using rebind = cel::Owned<U>;
939
940
  static element_type* to_address(const pointer& p) noexcept {
941
    return p.value_;
942
  }
943
};
944
945
}  // namespace std
946
947
namespace cel {
948
949
template <typename T>
950
struct ArenaTraits<Owned<T>> {
951
  static bool trivially_destructible(const Owned<T>& owned) {
952
    return ArenaTraits<>::trivially_destructible(owned.owner_);
953
  }
954
};
955
956
template <typename T>
957
Owner::Owner(const Owned<T>& owned) noexcept : Owner(owned.owner_) {}
958
959
template <typename T>
960
Owner::Owner(Owned<T>&& owned) noexcept : Owner(std::move(owned.owner_)) {
961
  owned.value_ = nullptr;
962
}
963
964
template <typename T>
965
Owner& Owner::operator=(const Owned<T>& owned) noexcept {
966
  *this = owned.owner_;
967
  return *this;
968
}
969
970
template <typename T>
971
Owner& Owner::operator=(Owned<T>&& owned) noexcept {
972
  *this = std::move(owned.owner_);
973
  owned.value_ = nullptr;
974
  return *this;
975
}
976
977
template <typename T>
978
bool operator==(const Owned<T>& lhs, std::nullptr_t) noexcept {
979
  return !static_cast<bool>(lhs);
980
}
981
982
template <typename T>
983
bool operator==(std::nullptr_t, const Owned<T>& rhs) noexcept {
984
  return rhs == nullptr;
985
}
986
987
template <typename T>
988
bool operator!=(const Owned<T>& lhs, std::nullptr_t) noexcept {
989
  return !operator==(lhs, nullptr);
990
}
991
992
template <typename T>
993
bool operator!=(std::nullptr_t, const Owned<T>& rhs) noexcept {
994
  return !operator==(nullptr, rhs);
995
}
996
997
template <typename T, typename... Args>
998
Owned<T> AllocateShared(Allocator<> allocator, Args&&... args) {
999
  using U = std::remove_cv_t<T>;
1000
  static_assert(!std::is_reference_v<U>, "T must not be a reference");
1001
  static_assert(!std::is_array_v<U>, "T must not be an array");
1002
1003
  U* object;
1004
  Owner owner;
1005
  if (google::protobuf::Arena* absl_nullable arena = allocator.arena();
1006
      arena != nullptr) {
1007
    object = ArenaAllocator(arena).template new_object<U>(
1008
        std::forward<Args>(args)...);
1009
    owner.ptr_ = reinterpret_cast<uintptr_t>(arena) |
1010
                 common_internal::kMetadataOwnerArenaBit;
1011
  } else {
1012
    const common_internal::ReferenceCount* refcount;
1013
    std::tie(object, refcount) = common_internal::MakeEmplacedReferenceCount<U>(
1014
        std::forward<Args>(args)...);
1015
    owner.ptr_ = reinterpret_cast<uintptr_t>(refcount) |
1016
                 common_internal::kMetadataOwnerReferenceCountBit;
1017
  }
1018
  return Owned<U>(object, std::move(owner));
1019
}
1020
1021
template <typename T>
1022
Owned<T> WrapShared(T* object, Allocator<> allocator) {
1023
  Owner owner;
1024
  if (object == nullptr) {
1025
  } else if (allocator.arena() != nullptr) {
1026
    owner.ptr_ = reinterpret_cast<uintptr_t>(
1027
                     static_cast<google::protobuf::Arena*>(allocator.arena())) |
1028
                 common_internal::kMetadataOwnerArenaBit;
1029
  } else {
1030
    owner.ptr_ = reinterpret_cast<uintptr_t>(
1031
                     common_internal::MakeDeletingReferenceCount(object)) |
1032
                 common_internal::kMetadataOwnerReferenceCountBit;
1033
  }
1034
  return Owned<T>(object, std::move(owner));
1035
}
1036
1037
template <typename T>
1038
std::enable_if_t<!std::is_const_v<T>, Owned<T>> WrapShared(T* object) {
1039
  return WrapShared(object, object->GetArena());
1040
}
1041
1042
namespace common_internal {
1043
1044
template <typename T>
1045
Owned<const T> WrapEternal(const T* value) {
1046
  return Owned<const T>(value, Owner::None());
1047
}
1048
1049
}  // namespace common_internal
1050
1051
// `Borrowed<T>` points to an object which was allocated using `Allocator<>` or
1052
// `Allocator<T>`. It has no ownership over the object, and is only valid so
1053
// long as one or more owners of the object exist. `T` must meet the named
1054
// requirement `ArenaConstructable`.
1055
template <typename T>
1056
class Borrowed final {
1057
 public:
1058
  using element_type = T;
1059
1060
  static_assert(!std::is_array_v<T>, "T must not be an array");
1061
  static_assert(!std::is_reference_v<T>, "T must not be a reference");
1062
  static_assert(!std::is_volatile_v<T>, "T must not be volatile qualified");
1063
  static_assert(!std::is_void_v<T>, "T must not be void");
1064
1065
  Borrowed() = default;
1066
  Borrowed(const Borrowed&) = default;
1067
  Borrowed(Borrowed&&) = default;
1068
  Borrowed& operator=(const Borrowed&) = default;
1069
  Borrowed& operator=(Borrowed&&) = default;
1070
1071
  template <typename U,
1072
            typename = std::enable_if_t<
1073
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
1074
  // NOLINTNEXTLINE(google-explicit-constructor)
1075
  Borrowed(const Borrowed<U>& other) noexcept
1076
      : Borrowed(other.value_, other.borrower_) {}
1077
1078
  template <typename U,
1079
            typename = std::enable_if_t<
1080
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
1081
  // NOLINTNEXTLINE(google-explicit-constructor)
1082
  Borrowed(Borrowed<U>&& other) noexcept
1083
      : Borrowed(other.value_, other.borrower_) {}
1084
1085
  template <typename U, typename = std::enable_if_t<
1086
                            common_internal::kIsPointerConvertible<T, U>>>
1087
  // NOLINTNEXTLINE(google-explicit-constructor)
1088
  Borrowed(const Owned<U>& other ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
1089
      : Borrowed(other.value_, other.owner_) {}
1090
1091
  Borrowed(Borrower borrower, T* ptr) noexcept : Borrowed(ptr, borrower) {}
1092
1093
  // NOLINTNEXTLINE(google-explicit-constructor)
1094
  Borrowed(std::nullptr_t) noexcept : Borrowed() {}
1095
1096
  template <typename U,
1097
            typename = std::enable_if_t<
1098
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
1099
  // NOLINTNEXTLINE(google-explicit-constructor)
1100
  Borrowed& operator=(const Borrowed<U>& other) noexcept {
1101
    value_ = other.value_;
1102
    borrower_ = other.borrower_;
1103
    return *this;
1104
  }
1105
1106
  template <typename U,
1107
            typename = std::enable_if_t<
1108
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
1109
  // NOLINTNEXTLINE(google-explicit-constructor)
1110
  Borrowed& operator=(Borrowed<U>&& other) noexcept {
1111
    value_ = other.value_;
1112
    borrower_ = other.borrower_;
1113
    return *this;
1114
  }
1115
1116
  template <typename U, typename = std::enable_if_t<
1117
                            common_internal::kIsPointerConvertible<T, U>>>
1118
  // NOLINTNEXTLINE(google-explicit-constructor)
1119
  Borrowed& operator=(
1120
      const Owned<U>& other ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept {
1121
    value_ = other.value_;
1122
    borrower_ = other.borrower_;
1123
    return *this;
1124
  }
1125
1126
  template <typename U, typename = std::enable_if_t<
1127
                            common_internal::kIsPointerConvertible<T, U>>>
1128
  // NOLINTNEXTLINE(google-explicit-constructor)
1129
  Borrowed& operator=(Owned<U>&&) = delete;
1130
1131
  // NOLINTNEXTLINE(google-explicit-constructor)
1132
  Borrowed& operator=(std::nullptr_t) noexcept {
1133
    reset();
1134
    return *this;
1135
  }
1136
1137
  T& operator*() const noexcept {
1138
    ABSL_DCHECK(static_cast<bool>(*this));
1139
    return *get();
1140
  }
1141
1142
  T* absl_nonnull operator->() const noexcept {
1143
    ABSL_DCHECK(static_cast<bool>(*this));
1144
    return get();
1145
  }
1146
1147
  void reset() noexcept {
1148
    value_ = nullptr;
1149
    borrower_.reset();
1150
  }
1151
1152
  google::protobuf::Arena* absl_nullable arena() const noexcept {
1153
    return borrower_.arena();
1154
  }
1155
1156
  explicit operator bool() const noexcept { return get() != nullptr; }
1157
1158
 private:
1159
  friend class Owner;
1160
  friend class Borrower;
1161
  template <typename U>
1162
  friend class Owned;
1163
  template <typename U>
1164
  friend class Borrowed;
1165
  template <typename U>
1166
  friend struct Borrowable;
1167
  friend struct std::pointer_traits<Borrowed<T>>;
1168
1169
  constexpr Borrowed(T* value, Borrower borrower) noexcept
1170
      : value_(value), borrower_(borrower) {}
1171
1172
  T* get() const noexcept { return value_; }
1173
1174
  T* value_ = nullptr;
1175
  Borrower borrower_;
1176
};
1177
1178
template <typename T>
1179
Borrowed(T*) -> Borrowed<T>;
1180
template <typename T>
1181
Borrowed(Borrower, T*) -> Borrowed<T>;
1182
template <typename T>
1183
Borrowed(Owned<T>) -> Borrowed<T>;
1184
1185
}  // namespace cel
1186
1187
namespace std {
1188
1189
template <typename T>
1190
struct pointer_traits<cel::Borrowed<T>> {
1191
  using pointer = cel::Borrowed<T>;
1192
  using element_type = typename cel::Borrowed<T>::element_type;
1193
  using difference_type = ptrdiff_t;
1194
1195
  template <typename U>
1196
  using rebind = cel::Borrowed<U>;
1197
1198
  static element_type* to_address(pointer p) noexcept { return p.value_; }
1199
};
1200
1201
}  // namespace std
1202
1203
namespace cel {
1204
1205
template <typename T>
1206
Owner::Owner(Borrowed<T> borrowed) noexcept : Owner(borrowed.borrower_) {}
1207
1208
template <typename T>
1209
Borrower::Borrower(const Owned<T>& owned ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
1210
    : Borrower(owned.owner_) {}
1211
1212
template <typename T>
1213
Borrower::Borrower(Borrowed<T> borrowed) noexcept
1214
    : Borrower(borrowed.borrower_) {}
1215
1216
template <typename T>
1217
Borrower& Borrower::operator=(
1218
    const Owned<T>& owned ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept {
1219
  *this = owned.owner_;
1220
  return *this;
1221
}
1222
1223
template <typename T>
1224
Borrower& Borrower::operator=(Borrowed<T> borrowed) noexcept {
1225
  *this = borrowed.borrower_;
1226
  return *this;
1227
}
1228
1229
template <typename T>
1230
bool operator==(Borrowed<T> lhs, std::nullptr_t) noexcept {
1231
  return !static_cast<bool>(lhs);
1232
}
1233
1234
template <typename T>
1235
bool operator==(std::nullptr_t, Borrowed<T> rhs) noexcept {
1236
  return rhs == nullptr;
1237
}
1238
1239
template <typename T>
1240
bool operator!=(Borrowed<T> lhs, std::nullptr_t) noexcept {
1241
  return !operator==(lhs, nullptr);
1242
}
1243
1244
template <typename T>
1245
bool operator!=(std::nullptr_t, Borrowed<T> rhs) noexcept {
1246
  return !operator==(nullptr, rhs);
1247
}
1248
1249
template <typename T>
1250
template <typename U, typename>
1251
Owned<T>::Owned(Borrowed<U> other) noexcept
1252
    : Owned(other.value_, Owner(other.borrower_)) {}
1253
1254
template <typename T>
1255
template <typename U, typename>
1256
Owned<T>& Owned<T>::operator=(Borrowed<U> other) noexcept {
1257
  value_ = other.value_;
1258
  owner_ = Owner(other.borrower_);
1259
  return *this;
1260
}
1261
1262
// `Ownable<T>` is a mixin for enabling the ability to get `Owned` that refer to
1263
// this.
1264
template <typename T>
1265
struct Ownable {
1266
 protected:
1267
  Owned<const T> Own() const noexcept {
1268
    static_assert(std::is_base_of_v<Data, T>, "T must be derived from Data");
1269
    const T* const that = static_cast<const T*>(this);
1270
    return Owned<const T>(
1271
        Owner(Owner::Own(static_cast<const Data*>(that)->owner_)), that);
1272
  }
1273
1274
  Owned<T> Own() noexcept {
1275
    static_assert(std::is_base_of_v<Data, T>, "T must be derived from Data");
1276
    T* const that = static_cast<T*>(this);
1277
    return Owned<T>(Owner(Owner::Own(static_cast<Data*>(that)->owner_)), that);
1278
  }
1279
1280
  ABSL_DEPRECATED("Use Own")
1281
  Owned<const T> shared_from_this() const noexcept { return Own(); }
1282
1283
  ABSL_DEPRECATED("Use Own")
1284
  Owned<T> shared_from_this() noexcept { return Own(); }
1285
};
1286
1287
// `Borrowable<T>` is a mixin for enabling the ability to get `Borrowed` that
1288
// refer to this.
1289
template <typename T>
1290
struct Borrowable {
1291
 protected:
1292
  Borrowed<const T> Borrow() const noexcept {
1293
    static_assert(std::is_base_of_v<Data, T>, "T must be derived from Data");
1294
    const T* const that = static_cast<const T*>(this);
1295
    return Borrowed<const T>(Borrower(static_cast<const Data*>(that)->owner_),
1296
                             that);
1297
  }
1298
1299
  Borrowed<T> Borrow() noexcept {
1300
    static_assert(std::is_base_of_v<Data, T>, "T must be derived from Data");
1301
    T* const that = static_cast<T*>(this);
1302
    return Borrowed<T>(Borrower(static_cast<Data*>(that)->owner_), that);
1303
  }
1304
};
1305
1306
// `ReferenceCountingMemoryManager` is a `MemoryManager` which employs automatic
1307
// memory management through reference counting.
1308
class ReferenceCountingMemoryManager final {
1309
 public:
1310
  ReferenceCountingMemoryManager(const ReferenceCountingMemoryManager&) =
1311
      delete;
1312
  ReferenceCountingMemoryManager(ReferenceCountingMemoryManager&&) = delete;
1313
  ReferenceCountingMemoryManager& operator=(
1314
      const ReferenceCountingMemoryManager&) = delete;
1315
  ReferenceCountingMemoryManager& operator=(ReferenceCountingMemoryManager&&) =
1316
      delete;
1317
1318
 private:
1319
  static void* Allocate(size_t size, size_t alignment);
1320
1321
  static bool Deallocate(void* ptr, size_t size, size_t alignment) noexcept;
1322
1323
  explicit ReferenceCountingMemoryManager() = default;
1324
1325
  friend class MemoryManager;
1326
};
1327
1328
// `PoolingMemoryManager` is a `MemoryManager` which employs automatic
1329
// memory management through memory pooling.
1330
class PoolingMemoryManager final {
1331
 public:
1332
  PoolingMemoryManager(const PoolingMemoryManager&) = delete;
1333
  PoolingMemoryManager(PoolingMemoryManager&&) = delete;
1334
  PoolingMemoryManager& operator=(const PoolingMemoryManager&) = delete;
1335
  PoolingMemoryManager& operator=(PoolingMemoryManager&&) = delete;
1336
1337
 private:
1338
  // Allocates memory directly from the allocator used by this memory manager.
1339
  // If `memory_management()` returns `MemoryManagement::kReferenceCounting`,
1340
  // this allocation *must* be explicitly deallocated at some point via
1341
  // `Deallocate`. Otherwise deallocation is optional.
1342
  ABSL_MUST_USE_RESULT static void* Allocate(google::protobuf::Arena* absl_nonnull arena,
1343
0
                                             size_t size, size_t alignment) {
1344
0
    ABSL_DCHECK(absl::has_single_bit(alignment))
1345
0
        << "alignment must be a power of 2";
1346
0
    if (size == 0) {
1347
0
      return nullptr;
1348
0
    }
1349
0
    return arena->AllocateAligned(size, alignment);
1350
0
  }
1351
1352
  // Attempts to deallocate memory previously allocated via `Allocate`, `size`
1353
  // and `alignment` must match the values from the previous call to `Allocate`.
1354
  // Returns `true` if the deallocation was successful and additional calls to
1355
  // `Allocate` may re-use the memory, `false` otherwise. Returns `false` if
1356
  // given `nullptr`.
1357
  static bool Deallocate(google::protobuf::Arena* absl_nonnull, void*, size_t,
1358
0
                         size_t alignment) noexcept {
1359
0
    ABSL_DCHECK(absl::has_single_bit(alignment))
1360
0
        << "alignment must be a power of 2";
1361
0
    return false;
1362
0
  }
1363
1364
  // Registers a custom destructor to be run upon destruction of the memory
1365
  // management implementation. Return value is always `true`, indicating that
1366
  // the destructor may be called at some point in the future.
1367
  static bool OwnCustomDestructor(google::protobuf::Arena* absl_nonnull arena,
1368
                                  void* object,
1369
0
                                  void (*absl_nonnull destruct)(void*)) {
1370
0
    ABSL_DCHECK(destruct != nullptr);
1371
0
    arena->OwnCustomDestructor(object, destruct);
1372
0
    return true;
1373
0
  }
1374
1375
  template <typename T>
1376
  static void DefaultDestructor(void* ptr) {
1377
    static_assert(!std::is_trivially_destructible_v<T>);
1378
    static_cast<T*>(ptr)->~T();
1379
  }
1380
1381
  explicit PoolingMemoryManager() = default;
1382
1383
  friend class MemoryManager;
1384
};
1385
1386
// `MemoryManager` is an abstraction for supporting automatic memory management.
1387
// All objects created by the `MemoryManager` have a lifetime governed by the
1388
// underlying memory management strategy. Currently `MemoryManager` is a
1389
// composed type that holds either a reference to
1390
// `ReferenceCountingMemoryManager` or owns a `PoolingMemoryManager`.
1391
//
1392
// ============================ Reference Counting ============================
1393
// `Unique`: The object is valid until destruction of the `Unique`.
1394
//
1395
// `Shared`: The object is valid so long as one or more `Shared` managing the
1396
// object exist.
1397
//
1398
// ================================= Pooling ==================================
1399
// `Unique`: The object is valid until destruction of the underlying memory
1400
// resources or of the `Unique`.
1401
//
1402
// `Shared`: The object is valid until destruction of the underlying memory
1403
// resources.
1404
class MemoryManager final {
1405
 public:
1406
  // Returns a `MemoryManager` which utilizes an arena but never frees its
1407
  // memory. It is effectively a memory leak and should only be used for limited
1408
  // use cases, such as initializing singletons which live for the life of the
1409
  // program.
1410
  static MemoryManager Unmanaged();
1411
1412
  // Returns a `MemoryManager` which utilizes reference counting.
1413
0
  ABSL_MUST_USE_RESULT static MemoryManager ReferenceCounting() {
1414
0
    return MemoryManager(nullptr);
1415
0
  }
1416
1417
  // Returns a `MemoryManager` which utilizes an arena.
1418
  ABSL_MUST_USE_RESULT static MemoryManager Pooling(
1419
528k
      google::protobuf::Arena* absl_nonnull arena) {
1420
528k
    return MemoryManager(arena);
1421
528k
  }
1422
1423
0
  explicit MemoryManager(Allocator<> allocator) : arena_(allocator.arena()) {}
1424
1425
  MemoryManager() = delete;
1426
  MemoryManager(const MemoryManager&) = default;
1427
  MemoryManager& operator=(const MemoryManager&) = default;
1428
1429
0
  MemoryManagement memory_management() const noexcept {
1430
0
    return arena_ == nullptr ? MemoryManagement::kReferenceCounting
1431
0
                             : MemoryManagement::kPooling;
1432
0
  }
1433
1434
  // Allocates memory directly from the allocator used by this memory manager.
1435
  // If `memory_management()` returns `MemoryManagement::kReferenceCounting`,
1436
  // this allocation *must* be explicitly deallocated at some point via
1437
  // `Deallocate`. Otherwise deallocation is optional.
1438
0
  ABSL_MUST_USE_RESULT void* Allocate(size_t size, size_t alignment) {
1439
0
    if (arena_ == nullptr) {
1440
0
      return ReferenceCountingMemoryManager::Allocate(size, alignment);
1441
0
    } else {
1442
0
      return PoolingMemoryManager::Allocate(arena_, size, alignment);
1443
0
    }
1444
0
  }
1445
1446
  // Attempts to deallocate memory previously allocated via `Allocate`, `size`
1447
  // and `alignment` must match the values from the previous call to `Allocate`.
1448
  // Returns `true` if the deallocation was successful and additional calls to
1449
  // `Allocate` may re-use the memory, `false` otherwise. Returns `false` if
1450
  // given `nullptr`.
1451
0
  bool Deallocate(void* ptr, size_t size, size_t alignment) noexcept {
1452
0
    if (arena_ == nullptr) {
1453
0
      return ReferenceCountingMemoryManager::Deallocate(ptr, size, alignment);
1454
0
    } else {
1455
0
      return PoolingMemoryManager::Deallocate(arena_, ptr, size, alignment);
1456
0
    }
1457
0
  }
1458
1459
  // Registers a custom destructor to be run upon destruction of the memory
1460
  // management implementation. A return of `true` indicates the destructor may
1461
  // be called at some point in the future, `false` if will definitely not be
1462
  // called. All pooling memory managers return `true` while the reference
1463
  // counting memory manager returns `false`.
1464
0
  bool OwnCustomDestructor(void* object, void (*absl_nonnull destruct)(void*)) {
1465
0
    ABSL_DCHECK(destruct != nullptr);
1466
0
    if (arena_ == nullptr) {
1467
0
      return false;
1468
0
    } else {
1469
0
      return PoolingMemoryManager::OwnCustomDestructor(arena_, object,
1470
0
                                                       destruct);
1471
0
    }
1472
0
  }
1473
1474
779k
  google::protobuf::Arena* absl_nullable arena() const noexcept { return arena_; }
1475
1476
  template <typename T>
1477
  // NOLINTNEXTLINE(google-explicit-constructor)
1478
  operator Allocator<T>() const {
1479
    return arena();
1480
  }
1481
1482
0
  friend void swap(MemoryManager& lhs, MemoryManager& rhs) noexcept {
1483
0
    using std::swap;
1484
0
    swap(lhs.arena_, rhs.arena_);
1485
0
  }
1486
1487
 private:
1488
  friend class PoolingMemoryManager;
1489
1490
0
  explicit MemoryManager(std::nullptr_t) : arena_(nullptr) {}
1491
1492
528k
  explicit MemoryManager(google::protobuf::Arena* absl_nonnull arena) : arena_(arena) {}
1493
1494
  // If `nullptr`, we are using reference counting. Otherwise we are using
1495
  // Pooling. We use `UnreachablePooling()` as a sentinel to detect use after
1496
  // move otherwise the moved-from `MemoryManager` would be in a valid state and
1497
  // utilize reference counting.
1498
  google::protobuf::Arena* absl_nullable arena_;
1499
};
1500
1501
using MemoryManagerRef = MemoryManager;
1502
1503
}  // namespace cel
1504
1505
#endif  // THIRD_PARTY_CEL_CPP_COMMON_MEMORY_H_