Coverage Report

Created: 2026-05-27 07:00

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
128
                            ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept {
326
128
    ABSL_DCHECK(arena != nullptr);
327
128
    return Borrower(reinterpret_cast<uintptr_t>(arena) | Owner::kArenaBit);
328
128
  }
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
128
  google::protobuf::Arena* absl_nullable arena() const noexcept {
383
128
    return (ptr_ & Owner::kBits) == Owner::kArenaBit
384
128
               ? reinterpret_cast<google::protobuf::Arena*>(ptr_ & Owner::kPointerMask)
385
128
               : nullptr;
386
128
  }
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
128
  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
0
  Unique(T* ptr, uintptr_t arena) noexcept : ptr_(ptr), arena_(arena) {}
603
604
  Unique(T* ptr, google::protobuf::Arena* arena, bool unowned = false) noexcept
605
0
      : Unique(ptr,
606
0
               reinterpret_cast<uintptr_t>(arena) |
607
0
                   (unowned ? common_internal::kUniqueArenaUnownedBit : 0)) {
608
0
    ABSL_ASSERT(!unowned || (unowned && arena != nullptr));
609
0
  }
610
611
  Unique(google::protobuf::Arena* arena, T* ptr, bool unowned = false) noexcept
612
      : Unique(ptr, arena, unowned) {}
613
614
0
  T* get() const noexcept { return ptr_; }
615
616
0
  void Delete() const noexcept {
617
0
    if (static_cast<bool>(*this)) {
618
0
      if (arena_ != 0) {
619
0
        if ((arena_ & common_internal::kUniqueArenaBits) ==
620
0
            common_internal::kUniqueArenaUnownedBit) {
621
          // We never registered the destructor, call it if necessary.
622
          if constexpr (!std::is_trivially_destructible_v<T> &&
623
0
                        !google::protobuf::Arena::is_destructor_skippable<T>::value) {
624
0
            std::destroy_at(ptr_);
625
0
          }
626
0
        }
627
0
      } else {
628
0
        delete ptr_;
629
0
      }
630
0
    }
631
0
  }
632
633
0
  void PreRelease() noexcept {
634
    if constexpr (!std::is_trivially_destructible_v<T> &&
635
0
                  !google::protobuf::Arena::is_destructor_skippable<T>::value) {
636
0
      if (static_cast<bool>(*this) &&
637
0
          (arena_ & common_internal::kUniqueArenaBits) ==
638
0
              common_internal::kUniqueArenaUnownedBit) {
639
        // We never registered the destructor, call it if necessary.
640
0
        arena()->OwnDestructor(const_cast<std::remove_const_t<T>*>(ptr_));
641
0
        arena_ &= common_internal::kUniqueArenaPointerMask;
642
0
      }
643
0
    }
644
0
  }
645
646
  void Release(T** ptr, Owner* owner) noexcept {
647
    if (ptr_ == nullptr) {
648
      *ptr = nullptr;
649
      return;
650
    }
651
    PreRelease();
652
    *ptr = std::exchange(ptr_, nullptr);
653
    if (arena_ == 0) {
654
      owner->ptr_ = reinterpret_cast<uintptr_t>(
655
                        common_internal::MakeDeletingReferenceCount(*ptr)) |
656
                    common_internal::kMetadataOwnerReferenceCountBit;
657
    } else {
658
      owner->ptr_ = reinterpret_cast<uintptr_t>(arena()) |
659
                    common_internal::kMetadataOwnerArenaBit;
660
    }
661
  }
662
663
  T* ptr_ = nullptr;
664
  // Potentially tagged pointer to `google::protobuf::Arena`. The tag is used to determine
665
  // whether we still need to register the destructor with the `google::protobuf::Arena`.
666
  uintptr_t arena_ = 0;
667
};
668
669
template <typename T>
670
Unique(T*) -> Unique<T>;
671
672
template <typename T, typename... Args>
673
Unique<T> AllocateUnique(Allocator<> allocator, Args&&... args) {
674
  using U = std::remove_cv_t<T>;
675
  static_assert(!std::is_reference_v<U>, "T must not be a reference");
676
  static_assert(!std::is_array_v<U>, "T must not be an array");
677
678
  U* object;
679
  google::protobuf::Arena* absl_nullable arena = allocator.arena();
680
  bool unowned;
681
  if constexpr (google::protobuf::Arena::is_arena_constructable<U>::value) {
682
    object = google::protobuf::Arena::Create<U>(arena, std::forward<Args>(args)...);
683
    // For arena-compatible proto types, let the Arena::Create handle
684
    // registering the destructor call.
685
    // Otherwise, Unique<T> retains a pointer to the owning arena so it may
686
    // conditionally register T::~T depending on usage.
687
    unowned = false;
688
  } else {
689
    void* p = allocator.allocate_bytes(sizeof(U), alignof(U));
690
    CEL_INTERNAL_TRY {
691
      if constexpr (ArenaTraits<>::constructible<U>()) {
692
        object = ::new (p) U(arena, std::forward<Args>(args)...);
693
      } else {
694
        object = ::new (p) U(std::forward<Args>(args)...);
695
      }
696
    }
697
    CEL_INTERNAL_CATCH_ANY {
698
      allocator.deallocate_bytes(p, sizeof(U), alignof(U));
699
      CEL_INTERNAL_RETHROW;
700
    }
701
    unowned =
702
        arena != nullptr && !ArenaTraits<>::trivially_destructible(*object);
703
  }
704
  return Unique<T>(object, arena, unowned);
705
}
706
707
template <typename T>
708
std::enable_if_t<!std::is_const_v<T>, Unique<T>> WrapUnique(T* object) {
709
  return Unique<T>(object);
710
}
711
712
template <typename T>
713
0
Unique<T> WrapUnique(T* object, Allocator<> allocator) {
714
0
  return Unique<T>(object, allocator.arena());
715
0
}
716
717
template <typename T>
718
inline bool operator==(const Unique<T>& lhs, std::nullptr_t) {
719
  return !static_cast<bool>(lhs);
720
}
721
722
template <typename T>
723
inline bool operator==(std::nullptr_t, const Unique<T>& rhs) {
724
  return !static_cast<bool>(rhs);
725
}
726
727
template <typename T>
728
0
inline bool operator!=(const Unique<T>& lhs, std::nullptr_t) {
729
0
  return static_cast<bool>(lhs);
730
0
}
731
732
template <typename T>
733
inline bool operator!=(std::nullptr_t, const Unique<T>& rhs) {
734
  return static_cast<bool>(rhs);
735
}
736
737
}  // namespace cel
738
739
namespace std {
740
741
template <typename T>
742
struct pointer_traits<cel::Unique<T>> {
743
  using pointer = cel::Unique<T>;
744
  using element_type = typename cel::Unique<T>::element_type;
745
  using difference_type = ptrdiff_t;
746
747
  template <typename U>
748
  using rebind = cel::Unique<U>;
749
750
0
  static element_type* to_address(const pointer& p) noexcept { return p.ptr_; }
751
};
752
753
}  // namespace std
754
755
namespace cel {
756
757
template <typename T>
758
struct ArenaTraits<Unique<T>> {
759
  static bool trivially_destructible(const Unique<T>& unique) {
760
    return unique.arena_ != 0 &&
761
           (unique.arena_ & common_internal::kUniqueArenaBits) == 0;
762
  }
763
};
764
765
// `Owned<T>` points to an object which was allocated using `Allocator<>` or
766
// `Allocator<T>`. It has co-ownership over the object. `T` must meet the named
767
// requirement `ArenaConstructable`.
768
template <typename T>
769
class ABSL_ATTRIBUTE_TRIVIAL_ABI [[nodiscard]] Owned final {
770
 public:
771
  using element_type = T;
772
773
  static_assert(!std::is_array_v<T>, "T must not be an array");
774
  static_assert(!std::is_reference_v<T>, "T must not be a reference");
775
  static_assert(!std::is_volatile_v<T>, "T must not be volatile qualified");
776
  static_assert(!std::is_void_v<T>, "T must not be void");
777
778
  Owned() = default;
779
  Owned(const Owned&) = default;
780
  Owned& operator=(const Owned&) = default;
781
782
  Owned(Owned&& other) noexcept
783
      : Owned(std::exchange(other.value_, nullptr), std::move(other.owner_)) {}
784
785
  template <typename U,
786
            typename = std::enable_if_t<
787
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
788
  // NOLINTNEXTLINE(google-explicit-constructor)
789
  Owned(const Owned<U>& other) noexcept : Owned(other.value_, other.owner_) {}
790
791
  template <typename U,
792
            typename = std::enable_if_t<
793
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
794
  // NOLINTNEXTLINE(google-explicit-constructor)
795
  Owned(Owned<U>&& other) noexcept
796
      : Owned(std::exchange(other.value_, nullptr), std::move(other.owner_)) {}
797
798
  template <typename U, typename = std::enable_if_t<
799
                            common_internal::kIsPointerConvertible<T, U>>>
800
  explicit Owned(Borrowed<U> other) noexcept;
801
802
  template <typename U, typename = std::enable_if_t<
803
                            common_internal::kIsPointerConvertible<T, U>>>
804
  // NOLINTNEXTLINE(google-explicit-constructor)
805
  Owned(Unique<U>&& other) : Owned() {
806
    other.Release(&value_, &owner_);
807
  }
808
809
  Owned(Owner owner, T* value ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
810
      : Owned(value, std::move(owner)) {}
811
812
  // NOLINTNEXTLINE(google-explicit-constructor)
813
  Owned(std::nullptr_t) noexcept : Owned() {}
814
815
  Owned& operator=(Owned&& other) noexcept {
816
    if (ABSL_PREDICT_TRUE(this != &other)) {
817
      value_ = std::exchange(other.value_, nullptr);
818
      owner_ = std::move(other.owner_);
819
    }
820
    return *this;
821
  }
822
823
  template <typename U,
824
            typename = std::enable_if_t<
825
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
826
  // NOLINTNEXTLINE(google-explicit-constructor)
827
  Owned& operator=(const Owned<U>& other) noexcept {
828
    value_ = other.value_;
829
    owner_ = other.owner_;
830
    return *this;
831
  }
832
833
  template <typename U,
834
            typename = std::enable_if_t<
835
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
836
  // NOLINTNEXTLINE(google-explicit-constructor)
837
  Owned& operator=(Owned<U>&& other) noexcept {
838
    value_ = std::exchange(other.value_, nullptr);
839
    owner_ = std::move(other.owner_);
840
    return *this;
841
  }
842
843
  template <typename U, typename = std::enable_if_t<
844
                            common_internal::kIsPointerConvertible<T, U>>>
845
  // NOLINTNEXTLINE(google-explicit-constructor)
846
  Owned& operator=(Borrowed<U> other) noexcept;
847
848
  template <typename U, typename = std::enable_if_t<
849
                            common_internal::kIsPointerConvertible<T, U>>>
850
  // NOLINTNEXTLINE(google-explicit-constructor)
851
  Owned& operator=(Unique<U>&& other) {
852
    owner_.reset();
853
    other.Release(&value_, &owner_);
854
    return *this;
855
  }
856
857
  // NOLINTNEXTLINE(google-explicit-constructor)
858
  Owned& operator=(std::nullptr_t) noexcept {
859
    reset();
860
    return *this;
861
  }
862
863
  T& operator*() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
864
    ABSL_DCHECK(static_cast<bool>(*this));
865
    return *get();
866
  }
867
868
  T* absl_nonnull operator->() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
869
    ABSL_DCHECK(static_cast<bool>(*this));
870
    return get();
871
  }
872
873
  void reset() noexcept {
874
    value_ = nullptr;
875
    owner_.reset();
876
  }
877
878
  google::protobuf::Arena* absl_nullable arena() const noexcept { return owner_.arena(); }
879
880
  explicit operator bool() const noexcept { return get() != nullptr; }
881
882
  friend void swap(Owned& lhs, Owned& rhs) noexcept {
883
    using std::swap;
884
    swap(lhs.value_, rhs.value_);
885
    swap(lhs.owner_, rhs.owner_);
886
  }
887
888
 private:
889
  friend class Owner;
890
  friend class Borrower;
891
  template <typename U>
892
  friend class Owned;
893
  template <typename U>
894
  friend class Borrowed;
895
  template <typename U>
896
  friend struct Ownable;
897
  template <typename U, typename... Args>
898
  friend Owned<U> AllocateShared(Allocator<> allocator, Args&&... args);
899
  template <typename U>
900
  friend Owned<U> WrapShared(U* object, Allocator<> allocator);
901
  template <typename U>
902
  friend Owned<const U> common_internal::WrapEternal(const U* value);
903
  friend struct std::pointer_traits<Owned<T>>;
904
  friend struct ArenaTraits<Owned<T>>;
905
906
  Owned(T* value, Owner owner) noexcept
907
      : value_(value), owner_(std::move(owner)) {}
908
909
  T* get() const noexcept { return value_; }
910
911
  T* value_ = nullptr;
912
  Owner owner_;
913
};
914
915
template <typename T>
916
Owned(T*) -> Owned<T>;
917
template <typename T>
918
Owned(Unique<T>) -> Owned<T>;
919
template <typename T>
920
Owned(Owner, T*) -> Owned<T>;
921
template <typename T>
922
Owned(Borrowed<T>) -> Owned<T>;
923
924
}  // namespace cel
925
926
namespace std {
927
928
template <typename T>
929
struct pointer_traits<cel::Owned<T>> {
930
  using pointer = cel::Owned<T>;
931
  using element_type = typename cel::Owned<T>::element_type;
932
  using difference_type = ptrdiff_t;
933
934
  template <typename U>
935
  using rebind = cel::Owned<U>;
936
937
  static element_type* to_address(const pointer& p) noexcept {
938
    return p.value_;
939
  }
940
};
941
942
}  // namespace std
943
944
namespace cel {
945
946
template <typename T>
947
struct ArenaTraits<Owned<T>> {
948
  static bool trivially_destructible(const Owned<T>& owned) {
949
    return ArenaTraits<>::trivially_destructible(owned.owner_);
950
  }
951
};
952
953
template <typename T>
954
Owner::Owner(const Owned<T>& owned) noexcept : Owner(owned.owner_) {}
955
956
template <typename T>
957
Owner::Owner(Owned<T>&& owned) noexcept : Owner(std::move(owned.owner_)) {
958
  owned.value_ = nullptr;
959
}
960
961
template <typename T>
962
Owner& Owner::operator=(const Owned<T>& owned) noexcept {
963
  *this = owned.owner_;
964
  return *this;
965
}
966
967
template <typename T>
968
Owner& Owner::operator=(Owned<T>&& owned) noexcept {
969
  *this = std::move(owned.owner_);
970
  owned.value_ = nullptr;
971
  return *this;
972
}
973
974
template <typename T>
975
bool operator==(const Owned<T>& lhs, std::nullptr_t) noexcept {
976
  return !static_cast<bool>(lhs);
977
}
978
979
template <typename T>
980
bool operator==(std::nullptr_t, const Owned<T>& rhs) noexcept {
981
  return rhs == nullptr;
982
}
983
984
template <typename T>
985
bool operator!=(const Owned<T>& lhs, std::nullptr_t) noexcept {
986
  return !operator==(lhs, nullptr);
987
}
988
989
template <typename T>
990
bool operator!=(std::nullptr_t, const Owned<T>& rhs) noexcept {
991
  return !operator==(nullptr, rhs);
992
}
993
994
template <typename T, typename... Args>
995
Owned<T> AllocateShared(Allocator<> allocator, Args&&... args) {
996
  using U = std::remove_cv_t<T>;
997
  static_assert(!std::is_reference_v<U>, "T must not be a reference");
998
  static_assert(!std::is_array_v<U>, "T must not be an array");
999
1000
  U* object;
1001
  Owner owner;
1002
  if (google::protobuf::Arena* absl_nullable arena = allocator.arena();
1003
      arena != nullptr) {
1004
    object = ArenaAllocator(arena).template new_object<U>(
1005
        std::forward<Args>(args)...);
1006
    owner.ptr_ = reinterpret_cast<uintptr_t>(arena) |
1007
                 common_internal::kMetadataOwnerArenaBit;
1008
  } else {
1009
    const common_internal::ReferenceCount* refcount;
1010
    std::tie(object, refcount) = common_internal::MakeEmplacedReferenceCount<U>(
1011
        std::forward<Args>(args)...);
1012
    owner.ptr_ = reinterpret_cast<uintptr_t>(refcount) |
1013
                 common_internal::kMetadataOwnerReferenceCountBit;
1014
  }
1015
  return Owned<U>(object, std::move(owner));
1016
}
1017
1018
template <typename T>
1019
Owned<T> WrapShared(T* object, Allocator<> allocator) {
1020
  Owner owner;
1021
  if (object == nullptr) {
1022
  } else if (allocator.arena() != nullptr) {
1023
    owner.ptr_ = reinterpret_cast<uintptr_t>(
1024
                     static_cast<google::protobuf::Arena*>(allocator.arena())) |
1025
                 common_internal::kMetadataOwnerArenaBit;
1026
  } else {
1027
    owner.ptr_ = reinterpret_cast<uintptr_t>(
1028
                     common_internal::MakeDeletingReferenceCount(object)) |
1029
                 common_internal::kMetadataOwnerReferenceCountBit;
1030
  }
1031
  return Owned<T>(object, std::move(owner));
1032
}
1033
1034
template <typename T>
1035
std::enable_if_t<!std::is_const_v<T>, Owned<T>> WrapShared(T* object) {
1036
  return WrapShared(object, object->GetArena());
1037
}
1038
1039
namespace common_internal {
1040
1041
template <typename T>
1042
Owned<const T> WrapEternal(const T* value) {
1043
  return Owned<const T>(value, Owner::None());
1044
}
1045
1046
}  // namespace common_internal
1047
1048
// `Borrowed<T>` points to an object which was allocated using `Allocator<>` or
1049
// `Allocator<T>`. It has no ownership over the object, and is only valid so
1050
// long as one or more owners of the object exist. `T` must meet the named
1051
// requirement `ArenaConstructable`.
1052
template <typename T>
1053
class Borrowed final {
1054
 public:
1055
  using element_type = T;
1056
1057
  static_assert(!std::is_array_v<T>, "T must not be an array");
1058
  static_assert(!std::is_reference_v<T>, "T must not be a reference");
1059
  static_assert(!std::is_volatile_v<T>, "T must not be volatile qualified");
1060
  static_assert(!std::is_void_v<T>, "T must not be void");
1061
1062
  Borrowed() = default;
1063
  Borrowed(const Borrowed&) = default;
1064
  Borrowed(Borrowed&&) = default;
1065
  Borrowed& operator=(const Borrowed&) = default;
1066
  Borrowed& operator=(Borrowed&&) = default;
1067
1068
  template <typename U,
1069
            typename = std::enable_if_t<
1070
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
1071
  // NOLINTNEXTLINE(google-explicit-constructor)
1072
  Borrowed(const Borrowed<U>& other) noexcept
1073
      : Borrowed(other.value_, other.borrower_) {}
1074
1075
  template <typename U,
1076
            typename = std::enable_if_t<
1077
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
1078
  // NOLINTNEXTLINE(google-explicit-constructor)
1079
  Borrowed(Borrowed<U>&& other) noexcept
1080
      : Borrowed(other.value_, other.borrower_) {}
1081
1082
  template <typename U, typename = std::enable_if_t<
1083
                            common_internal::kIsPointerConvertible<T, U>>>
1084
  // NOLINTNEXTLINE(google-explicit-constructor)
1085
  Borrowed(const Owned<U>& other ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
1086
      : Borrowed(other.value_, other.owner_) {}
1087
1088
  Borrowed(Borrower borrower, T* ptr) noexcept : Borrowed(ptr, borrower) {}
1089
1090
  // NOLINTNEXTLINE(google-explicit-constructor)
1091
  Borrowed(std::nullptr_t) noexcept : Borrowed() {}
1092
1093
  template <typename U,
1094
            typename = std::enable_if_t<
1095
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
1096
  // NOLINTNEXTLINE(google-explicit-constructor)
1097
  Borrowed& operator=(const Borrowed<U>& other) noexcept {
1098
    value_ = other.value_;
1099
    borrower_ = other.borrower_;
1100
    return *this;
1101
  }
1102
1103
  template <typename U,
1104
            typename = std::enable_if_t<
1105
                common_internal::kNotSameAndIsPointerConvertible<T, U>>>
1106
  // NOLINTNEXTLINE(google-explicit-constructor)
1107
  Borrowed& operator=(Borrowed<U>&& other) noexcept {
1108
    value_ = other.value_;
1109
    borrower_ = other.borrower_;
1110
    return *this;
1111
  }
1112
1113
  template <typename U, typename = std::enable_if_t<
1114
                            common_internal::kIsPointerConvertible<T, U>>>
1115
  // NOLINTNEXTLINE(google-explicit-constructor)
1116
  Borrowed& operator=(
1117
      const Owned<U>& other ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept {
1118
    value_ = other.value_;
1119
    borrower_ = other.borrower_;
1120
    return *this;
1121
  }
1122
1123
  template <typename U, typename = std::enable_if_t<
1124
                            common_internal::kIsPointerConvertible<T, U>>>
1125
  // NOLINTNEXTLINE(google-explicit-constructor)
1126
  Borrowed& operator=(Owned<U>&&) = delete;
1127
1128
  // NOLINTNEXTLINE(google-explicit-constructor)
1129
  Borrowed& operator=(std::nullptr_t) noexcept {
1130
    reset();
1131
    return *this;
1132
  }
1133
1134
  T& operator*() const noexcept {
1135
    ABSL_DCHECK(static_cast<bool>(*this));
1136
    return *get();
1137
  }
1138
1139
  T* absl_nonnull operator->() const noexcept {
1140
    ABSL_DCHECK(static_cast<bool>(*this));
1141
    return get();
1142
  }
1143
1144
  void reset() noexcept {
1145
    value_ = nullptr;
1146
    borrower_.reset();
1147
  }
1148
1149
  google::protobuf::Arena* absl_nullable arena() const noexcept {
1150
    return borrower_.arena();
1151
  }
1152
1153
  explicit operator bool() const noexcept { return get() != nullptr; }
1154
1155
 private:
1156
  friend class Owner;
1157
  friend class Borrower;
1158
  template <typename U>
1159
  friend class Owned;
1160
  template <typename U>
1161
  friend class Borrowed;
1162
  template <typename U>
1163
  friend struct Borrowable;
1164
  friend struct std::pointer_traits<Borrowed<T>>;
1165
1166
  constexpr Borrowed(T* value, Borrower borrower) noexcept
1167
      : value_(value), borrower_(borrower) {}
1168
1169
  T* get() const noexcept { return value_; }
1170
1171
  T* value_ = nullptr;
1172
  Borrower borrower_;
1173
};
1174
1175
template <typename T>
1176
Borrowed(T*) -> Borrowed<T>;
1177
template <typename T>
1178
Borrowed(Borrower, T*) -> Borrowed<T>;
1179
template <typename T>
1180
Borrowed(Owned<T>) -> Borrowed<T>;
1181
1182
}  // namespace cel
1183
1184
namespace std {
1185
1186
template <typename T>
1187
struct pointer_traits<cel::Borrowed<T>> {
1188
  using pointer = cel::Borrowed<T>;
1189
  using element_type = typename cel::Borrowed<T>::element_type;
1190
  using difference_type = ptrdiff_t;
1191
1192
  template <typename U>
1193
  using rebind = cel::Borrowed<U>;
1194
1195
  static element_type* to_address(pointer p) noexcept { return p.value_; }
1196
};
1197
1198
}  // namespace std
1199
1200
namespace cel {
1201
1202
template <typename T>
1203
Owner::Owner(Borrowed<T> borrowed) noexcept : Owner(borrowed.borrower_) {}
1204
1205
template <typename T>
1206
Borrower::Borrower(const Owned<T>& owned ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
1207
    : Borrower(owned.owner_) {}
1208
1209
template <typename T>
1210
Borrower::Borrower(Borrowed<T> borrowed) noexcept
1211
    : Borrower(borrowed.borrower_) {}
1212
1213
template <typename T>
1214
Borrower& Borrower::operator=(
1215
    const Owned<T>& owned ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept {
1216
  *this = owned.owner_;
1217
  return *this;
1218
}
1219
1220
template <typename T>
1221
Borrower& Borrower::operator=(Borrowed<T> borrowed) noexcept {
1222
  *this = borrowed.borrower_;
1223
  return *this;
1224
}
1225
1226
template <typename T>
1227
bool operator==(Borrowed<T> lhs, std::nullptr_t) noexcept {
1228
  return !static_cast<bool>(lhs);
1229
}
1230
1231
template <typename T>
1232
bool operator==(std::nullptr_t, Borrowed<T> rhs) noexcept {
1233
  return rhs == nullptr;
1234
}
1235
1236
template <typename T>
1237
bool operator!=(Borrowed<T> lhs, std::nullptr_t) noexcept {
1238
  return !operator==(lhs, nullptr);
1239
}
1240
1241
template <typename T>
1242
bool operator!=(std::nullptr_t, Borrowed<T> rhs) noexcept {
1243
  return !operator==(nullptr, rhs);
1244
}
1245
1246
template <typename T>
1247
template <typename U, typename>
1248
Owned<T>::Owned(Borrowed<U> other) noexcept
1249
    : Owned(other.value_, Owner(other.borrower_)) {}
1250
1251
template <typename T>
1252
template <typename U, typename>
1253
Owned<T>& Owned<T>::operator=(Borrowed<U> other) noexcept {
1254
  value_ = other.value_;
1255
  owner_ = Owner(other.borrower_);
1256
  return *this;
1257
}
1258
1259
// `Ownable<T>` is a mixin for enabling the ability to get `Owned` that refer to
1260
// this.
1261
template <typename T>
1262
struct Ownable {
1263
 protected:
1264
  Owned<const T> Own() const noexcept {
1265
    static_assert(std::is_base_of_v<Data, T>, "T must be derived from Data");
1266
    const T* const that = static_cast<const T*>(this);
1267
    return Owned<const T>(
1268
        Owner(Owner::Own(static_cast<const Data*>(that)->owner_)), that);
1269
  }
1270
1271
  Owned<T> Own() noexcept {
1272
    static_assert(std::is_base_of_v<Data, T>, "T must be derived from Data");
1273
    T* const that = static_cast<T*>(this);
1274
    return Owned<T>(Owner(Owner::Own(static_cast<Data*>(that)->owner_)), that);
1275
  }
1276
1277
  ABSL_DEPRECATED("Use Own")
1278
  Owned<const T> shared_from_this() const noexcept { return Own(); }
1279
1280
  ABSL_DEPRECATED("Use Own")
1281
  Owned<T> shared_from_this() noexcept { return Own(); }
1282
};
1283
1284
// `Borrowable<T>` is a mixin for enabling the ability to get `Borrowed` that
1285
// refer to this.
1286
template <typename T>
1287
struct Borrowable {
1288
 protected:
1289
  Borrowed<const T> Borrow() const noexcept {
1290
    static_assert(std::is_base_of_v<Data, T>, "T must be derived from Data");
1291
    const T* const that = static_cast<const T*>(this);
1292
    return Borrowed<const T>(Borrower(static_cast<const Data*>(that)->owner_),
1293
                             that);
1294
  }
1295
1296
  Borrowed<T> Borrow() noexcept {
1297
    static_assert(std::is_base_of_v<Data, T>, "T must be derived from Data");
1298
    T* const that = static_cast<T*>(this);
1299
    return Borrowed<T>(Borrower(static_cast<Data*>(that)->owner_), that);
1300
  }
1301
};
1302
1303
// `ReferenceCountingMemoryManager` is a `MemoryManager` which employs automatic
1304
// memory management through reference counting.
1305
class ReferenceCountingMemoryManager final {
1306
 public:
1307
  ReferenceCountingMemoryManager(const ReferenceCountingMemoryManager&) =
1308
      delete;
1309
  ReferenceCountingMemoryManager(ReferenceCountingMemoryManager&&) = delete;
1310
  ReferenceCountingMemoryManager& operator=(
1311
      const ReferenceCountingMemoryManager&) = delete;
1312
  ReferenceCountingMemoryManager& operator=(ReferenceCountingMemoryManager&&) =
1313
      delete;
1314
1315
 private:
1316
  static void* Allocate(size_t size, size_t alignment);
1317
1318
  static bool Deallocate(void* ptr, size_t size, size_t alignment) noexcept;
1319
1320
  explicit ReferenceCountingMemoryManager() = default;
1321
1322
  friend class MemoryManager;
1323
};
1324
1325
// `PoolingMemoryManager` is a `MemoryManager` which employs automatic
1326
// memory management through memory pooling.
1327
class PoolingMemoryManager final {
1328
 public:
1329
  PoolingMemoryManager(const PoolingMemoryManager&) = delete;
1330
  PoolingMemoryManager(PoolingMemoryManager&&) = delete;
1331
  PoolingMemoryManager& operator=(const PoolingMemoryManager&) = delete;
1332
  PoolingMemoryManager& operator=(PoolingMemoryManager&&) = delete;
1333
1334
 private:
1335
  // Allocates memory directly from the allocator used by this memory manager.
1336
  // If `memory_management()` returns `MemoryManagement::kReferenceCounting`,
1337
  // this allocation *must* be explicitly deallocated at some point via
1338
  // `Deallocate`. Otherwise deallocation is optional.
1339
  ABSL_MUST_USE_RESULT static void* Allocate(google::protobuf::Arena* absl_nonnull arena,
1340
0
                                             size_t size, size_t alignment) {
1341
0
    ABSL_DCHECK(absl::has_single_bit(alignment))
1342
0
        << "alignment must be a power of 2";
1343
0
    if (size == 0) {
1344
0
      return nullptr;
1345
0
    }
1346
0
    return arena->AllocateAligned(size, alignment);
1347
0
  }
1348
1349
  // Attempts to deallocate memory previously allocated via `Allocate`, `size`
1350
  // and `alignment` must match the values from the previous call to `Allocate`.
1351
  // Returns `true` if the deallocation was successful and additional calls to
1352
  // `Allocate` may re-use the memory, `false` otherwise. Returns `false` if
1353
  // given `nullptr`.
1354
  static bool Deallocate(google::protobuf::Arena* absl_nonnull, void*, size_t,
1355
0
                         size_t alignment) noexcept {
1356
0
    ABSL_DCHECK(absl::has_single_bit(alignment))
1357
0
        << "alignment must be a power of 2";
1358
0
    return false;
1359
0
  }
1360
1361
  // Registers a custom destructor to be run upon destruction of the memory
1362
  // management implementation. Return value is always `true`, indicating that
1363
  // the destructor may be called at some point in the future.
1364
  static bool OwnCustomDestructor(google::protobuf::Arena* absl_nonnull arena,
1365
                                  void* object,
1366
0
                                  void (*absl_nonnull destruct)(void*)) {
1367
0
    ABSL_DCHECK(destruct != nullptr);
1368
0
    arena->OwnCustomDestructor(object, destruct);
1369
0
    return true;
1370
0
  }
1371
1372
  template <typename T>
1373
  static void DefaultDestructor(void* ptr) {
1374
    static_assert(!std::is_trivially_destructible_v<T>);
1375
    static_cast<T*>(ptr)->~T();
1376
  }
1377
1378
  explicit PoolingMemoryManager() = default;
1379
1380
  friend class MemoryManager;
1381
};
1382
1383
// `MemoryManager` is an abstraction for supporting automatic memory management.
1384
// All objects created by the `MemoryManager` have a lifetime governed by the
1385
// underlying memory management strategy. Currently `MemoryManager` is a
1386
// composed type that holds either a reference to
1387
// `ReferenceCountingMemoryManager` or owns a `PoolingMemoryManager`.
1388
//
1389
// ============================ Reference Counting ============================
1390
// `Unique`: The object is valid until destruction of the `Unique`.
1391
//
1392
// `Shared`: The object is valid so long as one or more `Shared` managing the
1393
// object exist.
1394
//
1395
// ================================= Pooling ==================================
1396
// `Unique`: The object is valid until destruction of the underlying memory
1397
// resources or of the `Unique`.
1398
//
1399
// `Shared`: The object is valid until destruction of the underlying memory
1400
// resources.
1401
class MemoryManager final {
1402
 public:
1403
  // Returns a `MemoryManager` which utilizes an arena but never frees its
1404
  // memory. It is effectively a memory leak and should only be used for limited
1405
  // use cases, such as initializing singletons which live for the life of the
1406
  // program.
1407
  static MemoryManager Unmanaged();
1408
1409
  // Returns a `MemoryManager` which utilizes reference counting.
1410
0
  ABSL_MUST_USE_RESULT static MemoryManager ReferenceCounting() {
1411
0
    return MemoryManager(nullptr);
1412
0
  }
1413
1414
  // Returns a `MemoryManager` which utilizes an arena.
1415
  ABSL_MUST_USE_RESULT static MemoryManager Pooling(
1416
3.59k
      google::protobuf::Arena* absl_nonnull arena) {
1417
3.59k
    return MemoryManager(arena);
1418
3.59k
  }
1419
1420
0
  explicit MemoryManager(Allocator<> allocator) : arena_(allocator.arena()) {}
1421
1422
  MemoryManager() = delete;
1423
  MemoryManager(const MemoryManager&) = default;
1424
  MemoryManager& operator=(const MemoryManager&) = default;
1425
1426
0
  MemoryManagement memory_management() const noexcept {
1427
0
    return arena_ == nullptr ? MemoryManagement::kReferenceCounting
1428
0
                             : MemoryManagement::kPooling;
1429
0
  }
1430
1431
  // Allocates memory directly from the allocator used by this memory manager.
1432
  // If `memory_management()` returns `MemoryManagement::kReferenceCounting`,
1433
  // this allocation *must* be explicitly deallocated at some point via
1434
  // `Deallocate`. Otherwise deallocation is optional.
1435
0
  ABSL_MUST_USE_RESULT void* Allocate(size_t size, size_t alignment) {
1436
0
    if (arena_ == nullptr) {
1437
0
      return ReferenceCountingMemoryManager::Allocate(size, alignment);
1438
0
    } else {
1439
0
      return PoolingMemoryManager::Allocate(arena_, size, alignment);
1440
0
    }
1441
0
  }
1442
1443
  // Attempts to deallocate memory previously allocated via `Allocate`, `size`
1444
  // and `alignment` must match the values from the previous call to `Allocate`.
1445
  // Returns `true` if the deallocation was successful and additional calls to
1446
  // `Allocate` may re-use the memory, `false` otherwise. Returns `false` if
1447
  // given `nullptr`.
1448
0
  bool Deallocate(void* ptr, size_t size, size_t alignment) noexcept {
1449
0
    if (arena_ == nullptr) {
1450
0
      return ReferenceCountingMemoryManager::Deallocate(ptr, size, alignment);
1451
0
    } else {
1452
0
      return PoolingMemoryManager::Deallocate(arena_, ptr, size, alignment);
1453
0
    }
1454
0
  }
1455
1456
  // Registers a custom destructor to be run upon destruction of the memory
1457
  // management implementation. A return of `true` indicates the destructor may
1458
  // be called at some point in the future, `false` if will definitely not be
1459
  // called. All pooling memory managers return `true` while the reference
1460
  // counting memory manager returns `false`.
1461
0
  bool OwnCustomDestructor(void* object, void (*absl_nonnull destruct)(void*)) {
1462
0
    ABSL_DCHECK(destruct != nullptr);
1463
0
    if (arena_ == nullptr) {
1464
0
      return false;
1465
0
    } else {
1466
0
      return PoolingMemoryManager::OwnCustomDestructor(arena_, object,
1467
0
                                                       destruct);
1468
0
    }
1469
0
  }
1470
1471
5.24k
  google::protobuf::Arena* absl_nullable arena() const noexcept { return arena_; }
1472
1473
  template <typename T>
1474
  // NOLINTNEXTLINE(google-explicit-constructor)
1475
  operator Allocator<T>() const {
1476
    return arena();
1477
  }
1478
1479
0
  friend void swap(MemoryManager& lhs, MemoryManager& rhs) noexcept {
1480
0
    using std::swap;
1481
0
    swap(lhs.arena_, rhs.arena_);
1482
0
  }
1483
1484
 private:
1485
  friend class PoolingMemoryManager;
1486
1487
0
  explicit MemoryManager(std::nullptr_t) : arena_(nullptr) {}
1488
1489
3.59k
  explicit MemoryManager(google::protobuf::Arena* absl_nonnull arena) : arena_(arena) {}
1490
1491
  // If `nullptr`, we are using reference counting. Otherwise we are using
1492
  // Pooling. We use `UnreachablePooling()` as a sentinel to detect use after
1493
  // move otherwise the moved-from `MemoryManager` would be in a valid state and
1494
  // utilize reference counting.
1495
  google::protobuf::Arena* absl_nullable arena_;
1496
};
1497
1498
using MemoryManagerRef = MemoryManager;
1499
1500
}  // namespace cel
1501
1502
#endif  // THIRD_PARTY_CEL_CPP_COMMON_MEMORY_H_