xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_arena_scoped_ptr.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // unique_ptr-style pointer that stores values that may be from an arena. Takes
6 // up the same storage as the platform's native pointer type. Takes ownership
7 // of the value it's constructed with; if holding a value in an arena, and the
8 // type has a non-trivial destructor, the arena must outlive the
9 // QuicArenaScopedPtr. Does not support array overloads.
10 
11 #ifndef QUICHE_QUIC_CORE_QUIC_ARENA_SCOPED_PTR_H_
12 #define QUICHE_QUIC_CORE_QUIC_ARENA_SCOPED_PTR_H_
13 
14 #include <cstdint>  // for uintptr_t
15 
16 #include "quiche/quic/platform/api/quic_export.h"
17 #include "quiche/quic/platform/api/quic_logging.h"
18 
19 namespace quic {
20 
21 template <typename T>
22 class QUICHE_NO_EXPORT QuicArenaScopedPtr {
23   static_assert(alignof(T*) > 1,
24                 "QuicArenaScopedPtr can only store objects that are aligned to "
25                 "greater than 1 byte.");
26 
27  public:
28   // Constructs an empty QuicArenaScopedPtr.
29   QuicArenaScopedPtr();
30 
31   // Constructs a QuicArenaScopedPtr referencing the heap-allocated memory
32   // provided.
33   explicit QuicArenaScopedPtr(T* value);
34 
35   template <typename U>
36   QuicArenaScopedPtr(QuicArenaScopedPtr<U>&& other);  // NOLINT
37   template <typename U>
38   QuicArenaScopedPtr& operator=(QuicArenaScopedPtr<U>&& other);
39   ~QuicArenaScopedPtr();
40 
41   // Returns a pointer to the value.
42   T* get() const;
43 
44   // Returns a reference to the value.
45   T& operator*() const;
46 
47   // Returns a pointer to the value.
48   T* operator->() const;
49 
50   // Swaps the value of this pointer with |other|.
51   void swap(QuicArenaScopedPtr& other);
52 
53   // Resets the held value to |value|.
54   void reset(T* value = nullptr);
55 
56   // Returns true if |this| came from an arena. Primarily exposed for testing
57   // and assertions.
58   bool is_from_arena();
59 
60  private:
61   // Friends with other derived types of QuicArenaScopedPtr, to support the
62   // derived-types case.
63   template <typename U>
64   friend class QuicArenaScopedPtr;
65   // Also befriend all known arenas, only to prevent misuse.
66   template <uint32_t ArenaSize>
67   friend class QuicOneBlockArena;
68 
69   // Tag to denote that a QuicArenaScopedPtr is being explicitly created by an
70   // arena.
71   enum class ConstructFrom { kHeap, kArena };
72 
73   // Constructs a QuicArenaScopedPtr with the given representation.
74   QuicArenaScopedPtr(void* value, ConstructFrom from);
75   QuicArenaScopedPtr(const QuicArenaScopedPtr&) = delete;
76   QuicArenaScopedPtr& operator=(const QuicArenaScopedPtr&) = delete;
77 
78   // Low-order bits of value_ that determine if the pointer came from an arena.
79   static const uintptr_t kFromArenaMask = 0x1;
80 
81   // Every platform we care about has at least 4B aligned integers, so store the
82   // is_from_arena bit in the least significant bit.
83   void* value_;
84 };
85 
86 template <typename T>
87 bool operator==(const QuicArenaScopedPtr<T>& left,
88                 const QuicArenaScopedPtr<T>& right) {
89   return left.get() == right.get();
90 }
91 
92 template <typename T>
93 bool operator!=(const QuicArenaScopedPtr<T>& left,
94                 const QuicArenaScopedPtr<T>& right) {
95   return left.get() != right.get();
96 }
97 
98 template <typename T>
99 bool operator==(std::nullptr_t, const QuicArenaScopedPtr<T>& right) {
100   return nullptr == right.get();
101 }
102 
103 template <typename T>
104 bool operator!=(std::nullptr_t, const QuicArenaScopedPtr<T>& right) {
105   return nullptr != right.get();
106 }
107 
108 template <typename T>
109 bool operator==(const QuicArenaScopedPtr<T>& left, std::nullptr_t) {
110   return left.get() == nullptr;
111 }
112 
113 template <typename T>
114 bool operator!=(const QuicArenaScopedPtr<T>& left, std::nullptr_t) {
115   return left.get() != nullptr;
116 }
117 
118 template <typename T>
QuicArenaScopedPtr()119 QuicArenaScopedPtr<T>::QuicArenaScopedPtr() : value_(nullptr) {}
120 
121 template <typename T>
QuicArenaScopedPtr(T * value)122 QuicArenaScopedPtr<T>::QuicArenaScopedPtr(T* value)
123     : QuicArenaScopedPtr(value, ConstructFrom::kHeap) {}
124 
125 template <typename T>
126 template <typename U>
QuicArenaScopedPtr(QuicArenaScopedPtr<U> && other)127 QuicArenaScopedPtr<T>::QuicArenaScopedPtr(QuicArenaScopedPtr<U>&& other)
128     : value_(other.value_) {
129   static_assert(
130       std::is_base_of<T, U>::value || std::is_same<T, U>::value,
131       "Cannot construct QuicArenaScopedPtr; type is not derived or same.");
132   other.value_ = nullptr;
133 }
134 
135 template <typename T>
136 template <typename U>
137 QuicArenaScopedPtr<T>& QuicArenaScopedPtr<T>::operator=(
138     QuicArenaScopedPtr<U>&& other) {
139   static_assert(
140       std::is_base_of<T, U>::value || std::is_same<T, U>::value,
141       "Cannot assign QuicArenaScopedPtr; type is not derived or same.");
142   swap(other);
143   return *this;
144 }
145 
146 template <typename T>
~QuicArenaScopedPtr()147 QuicArenaScopedPtr<T>::~QuicArenaScopedPtr() {
148   reset();
149 }
150 
151 template <typename T>
get()152 T* QuicArenaScopedPtr<T>::get() const {
153   return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(value_) &
154                               ~kFromArenaMask);
155 }
156 
157 template <typename T>
158 T& QuicArenaScopedPtr<T>::operator*() const {
159   return *get();
160 }
161 
162 template <typename T>
163 T* QuicArenaScopedPtr<T>::operator->() const {
164   return get();
165 }
166 
167 template <typename T>
swap(QuicArenaScopedPtr & other)168 void QuicArenaScopedPtr<T>::swap(QuicArenaScopedPtr& other) {
169   using std::swap;
170   swap(value_, other.value_);
171 }
172 
173 template <typename T>
is_from_arena()174 bool QuicArenaScopedPtr<T>::is_from_arena() {
175   return (reinterpret_cast<uintptr_t>(value_) & kFromArenaMask) != 0;
176 }
177 
178 template <typename T>
reset(T * value)179 void QuicArenaScopedPtr<T>::reset(T* value) {
180   if (value_ != nullptr) {
181     if (is_from_arena()) {
182       // Manually invoke the destructor.
183       get()->~T();
184     } else {
185       delete get();
186     }
187   }
188   QUICHE_DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(value) & kFromArenaMask);
189   value_ = value;
190 }
191 
192 template <typename T>
QuicArenaScopedPtr(void * value,ConstructFrom from_arena)193 QuicArenaScopedPtr<T>::QuicArenaScopedPtr(void* value, ConstructFrom from_arena)
194     : value_(value) {
195   QUICHE_DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(value_) & kFromArenaMask);
196   switch (from_arena) {
197     case ConstructFrom::kHeap:
198       break;
199     case ConstructFrom::kArena:
200       value_ = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(value_) |
201                                        QuicArenaScopedPtr<T>::kFromArenaMask);
202       break;
203   }
204 }
205 
206 }  // namespace quic
207 
208 #endif  // QUICHE_QUIC_CORE_QUIC_ARENA_SCOPED_PTR_H_
209