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