blob: 7c20fc7af4c3a86dde5b6819eac56d5d6726432a [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
QUICHE teama6ef0a62019-03-07 20:34:33 -050016#include "net/third_party/quiche/src/quic/platform/api/quic_aligned.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
18
19namespace quic {
20
21template <typename T>
22class QuicArenaScopedPtr {
23 static_assert(QUIC_ALIGN_OF(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
86template <typename T>
87bool operator==(const QuicArenaScopedPtr<T>& left,
88 const QuicArenaScopedPtr<T>& right) {
89 return left.get() == right.get();
90}
91
92template <typename T>
93bool operator!=(const QuicArenaScopedPtr<T>& left,
94 const QuicArenaScopedPtr<T>& right) {
95 return left.get() != right.get();
96}
97
98template <typename T>
99bool operator==(std::nullptr_t, const QuicArenaScopedPtr<T>& right) {
100 return nullptr == right.get();
101}
102
103template <typename T>
104bool operator!=(std::nullptr_t, const QuicArenaScopedPtr<T>& right) {
105 return nullptr != right.get();
106}
107
108template <typename T>
109bool operator==(const QuicArenaScopedPtr<T>& left, std::nullptr_t) {
110 return left.get() == nullptr;
111}
112
113template <typename T>
114bool operator!=(const QuicArenaScopedPtr<T>& left, std::nullptr_t) {
115 return left.get() != nullptr;
116}
117
118template <typename T>
119QuicArenaScopedPtr<T>::QuicArenaScopedPtr() : value_(nullptr) {}
120
121template <typename T>
122QuicArenaScopedPtr<T>::QuicArenaScopedPtr(T* value)
123 : QuicArenaScopedPtr(value, ConstructFrom::kHeap) {}
124
125template <typename T>
126template <typename U>
127QuicArenaScopedPtr<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
135template <typename T>
136template <typename U>
137QuicArenaScopedPtr<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
146template <typename T>
147QuicArenaScopedPtr<T>::~QuicArenaScopedPtr() {
148 reset();
149}
150
151template <typename T>
152T* QuicArenaScopedPtr<T>::get() const {
153 return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(value_) &
154 ~kFromArenaMask);
155}
156
157template <typename T>
158T& QuicArenaScopedPtr<T>::operator*() const {
159 return *get();
160}
161
162template <typename T>
163T* QuicArenaScopedPtr<T>::operator->() const {
164 return get();
165}
166
167template <typename T>
168void QuicArenaScopedPtr<T>::swap(QuicArenaScopedPtr& other) {
169 using std::swap;
170 swap(value_, other.value_);
171}
172
173template <typename T>
174bool QuicArenaScopedPtr<T>::is_from_arena() {
175 return (reinterpret_cast<uintptr_t>(value_) & kFromArenaMask) != 0;
176}
177
178template <typename T>
179void 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 DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(value) & kFromArenaMask);
189 value_ = value;
190}
191
192template <typename T>
193QuicArenaScopedPtr<T>::QuicArenaScopedPtr(void* value, ConstructFrom from_arena)
194 : value_(value) {
195 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_