Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(888)

Side by Side Diff: mojo/public/cpp/bindings/struct_ptr.h

Issue 2339413004: Allow Mojo structs as map keys (Closed)
Patch Set: Address sammc's comments and improve Blink tests Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_ 5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_ 6 #define MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
7 7
8 #include <functional>
8 #include <new> 9 #include <new>
9 10
10 #include "base/logging.h" 11 #include "base/logging.h"
11 #include "base/macros.h" 12 #include "base/macros.h"
13 #include "mojo/public/cpp/bindings/lib/hash_util.h"
12 #include "mojo/public/cpp/bindings/type_converter.h" 14 #include "mojo/public/cpp/bindings/type_converter.h"
13 15
14 namespace mojo { 16 namespace mojo {
15 namespace internal { 17 namespace internal {
16 18
19 constexpr size_t kHashSeed = 31;
20
17 template <typename Struct> 21 template <typename Struct>
18 class StructHelper { 22 class StructHelper {
19 public: 23 public:
20 template <typename Ptr> 24 template <typename Ptr>
21 static void Initialize(Ptr* ptr) { 25 static void Initialize(Ptr* ptr) {
22 ptr->Initialize(); 26 ptr->Initialize();
23 } 27 }
24 }; 28 };
25 29
30 template <typename Struct>
31 class StructPtrWTFHelper;
32
33 template <typename Struct>
34 class InlinedStructPtrWTFHelper;
35
26 } // namespace internal 36 } // namespace internal
27 37
28 // Smart pointer wrapping a mojom structure with move-only semantics. 38 // Smart pointer wrapping a mojom structure with move-only semantics.
29 template <typename S> 39 template <typename S>
30 class StructPtr { 40 class StructPtr {
31 public: 41 public:
32 using Struct = S; 42 using Struct = S;
33 43
34 StructPtr() : ptr_(nullptr) {} 44 StructPtr() : ptr_(nullptr) {}
35 StructPtr(decltype(nullptr)) : ptr_(nullptr) {} 45 StructPtr(decltype(nullptr)) : ptr_(nullptr) {}
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 } 81 }
72 Struct* get() const { return ptr_; } 82 Struct* get() const { return ptr_; }
73 83
74 void Swap(StructPtr* other) { std::swap(ptr_, other->ptr_); } 84 void Swap(StructPtr* other) { std::swap(ptr_, other->ptr_); }
75 85
76 // Please note that calling this method will fail compilation if the value 86 // Please note that calling this method will fail compilation if the value
77 // type |Struct| doesn't have a Clone() method defined (which usually means 87 // type |Struct| doesn't have a Clone() method defined (which usually means
78 // that it contains Mojo handles). 88 // that it contains Mojo handles).
79 StructPtr Clone() const { return is_null() ? StructPtr() : ptr_->Clone(); } 89 StructPtr Clone() const { return is_null() ? StructPtr() : ptr_->Clone(); }
80 90
91 // Compares the pointees (which might both be null).
92 // TODO(tibell): Get rid of Equals in favor of the operator. Same for Hash.
81 bool Equals(const StructPtr& other) const { 93 bool Equals(const StructPtr& other) const {
82 if (is_null() || other.is_null()) 94 if (is_null() || other.is_null())
83 return is_null() && other.is_null(); 95 return is_null() && other.is_null();
84 return ptr_->Equals(*other.ptr_); 96 return ptr_->Equals(*other.ptr_);
85 } 97 }
86 98
87 private: 99 // Hashes based on the pointee (which might be null).
88 // TODO(dcheng): Use an explicit conversion operator. 100 size_t Hash(size_t seed) const {
89 typedef Struct* StructPtr::*Testable; 101 if (is_null())
102 return internal::HashCombine(seed, 0);
103 return ptr_->Hash(seed);
104 }
90 105
91 public: 106 explicit operator bool() const { return !is_null(); }
92 operator Testable() const { return ptr_ ? &StructPtr::ptr_ : 0; }
93 107
94 private: 108 private:
95 friend class internal::StructHelper<Struct>; 109 friend class internal::StructHelper<Struct>;
96 110 friend class internal::StructPtrWTFHelper<Struct>;
97 // Forbid the == and != operators explicitly, otherwise StructPtr will be
98 // converted to Testable to do == or != comparison.
99 template <typename T>
100 bool operator==(const StructPtr<T>& other) const = delete;
101 template <typename T>
102 bool operator!=(const StructPtr<T>& other) const = delete;
103 111
104 void Initialize() { 112 void Initialize() {
105 DCHECK(!ptr_); 113 DCHECK(!ptr_);
106 ptr_ = new Struct(); 114 ptr_ = new Struct();
107 } 115 }
108 116
109 void Take(StructPtr* other) { 117 void Take(StructPtr* other) {
110 reset(); 118 reset();
111 Swap(other); 119 Swap(other);
112 } 120 }
113 121
114 Struct* ptr_; 122 Struct* ptr_;
115 123
116 DISALLOW_COPY_AND_ASSIGN(StructPtr); 124 DISALLOW_COPY_AND_ASSIGN(StructPtr);
117 }; 125 };
118 126
127 template <typename T>
128 bool operator==(const StructPtr<T>& lhs, const StructPtr<T>& rhs) {
129 return lhs.Equals(rhs);
130 }
131 template <typename T>
132 bool operator!=(const StructPtr<T>& lhs, const StructPtr<T>& rhs) {
133 return !(lhs == rhs);
134 }
135
119 // Designed to be used when Struct is small and copyable. 136 // Designed to be used when Struct is small and copyable.
120 template <typename S> 137 template <typename S>
121 class InlinedStructPtr { 138 class InlinedStructPtr {
122 public: 139 public:
123 using Struct = S; 140 using Struct = S;
124 141
125 InlinedStructPtr() : is_null_(true) {} 142 InlinedStructPtr() : state_(NIL) {}
126 InlinedStructPtr(decltype(nullptr)) : is_null_(true) {} 143 InlinedStructPtr(decltype(nullptr)) : state_(NIL) {}
127 144
128 ~InlinedStructPtr() {} 145 ~InlinedStructPtr() {}
129 146
130 InlinedStructPtr& operator=(decltype(nullptr)) { 147 InlinedStructPtr& operator=(decltype(nullptr)) {
131 reset(); 148 reset();
132 return *this; 149 return *this;
133 } 150 }
134 151
135 InlinedStructPtr(InlinedStructPtr&& other) : is_null_(true) { Take(&other); } 152 InlinedStructPtr(InlinedStructPtr&& other) : state_(NIL) { Take(&other); }
136 InlinedStructPtr& operator=(InlinedStructPtr&& other) { 153 InlinedStructPtr& operator=(InlinedStructPtr&& other) {
137 Take(&other); 154 Take(&other);
138 return *this; 155 return *this;
139 } 156 }
140 157
141 template <typename U> 158 template <typename U>
142 U To() const { 159 U To() const {
143 return TypeConverter<U, InlinedStructPtr>::Convert(*this); 160 return TypeConverter<U, InlinedStructPtr>::Convert(*this);
144 } 161 }
145 162
146 void reset() { 163 void reset() {
147 is_null_ = true; 164 state_ = NIL;
148 value_. ~Struct(); 165 value_. ~Struct();
149 new (&value_) Struct(); 166 new (&value_) Struct();
150 } 167 }
151 168
152 bool is_null() const { return is_null_; } 169 bool is_null() const { return state_ == NIL; }
153 170
154 Struct& operator*() const { 171 Struct& operator*() const {
155 DCHECK(!is_null_); 172 DCHECK(state_ == VALID);
156 return value_; 173 return value_;
157 } 174 }
158 Struct* operator->() const { 175 Struct* operator->() const {
159 DCHECK(!is_null_); 176 DCHECK(state_ == VALID);
160 return &value_; 177 return &value_;
161 } 178 }
162 Struct* get() const { return &value_; } 179 Struct* get() const { return &value_; }
163 180
164 void Swap(InlinedStructPtr* other) { 181 void Swap(InlinedStructPtr* other) {
165 std::swap(value_, other->value_); 182 std::swap(value_, other->value_);
166 std::swap(is_null_, other->is_null_); 183 std::swap(state_, other->state_);
167 } 184 }
168 185
169 InlinedStructPtr Clone() const { 186 InlinedStructPtr Clone() const {
170 return is_null() ? InlinedStructPtr() : value_.Clone(); 187 return is_null() ? InlinedStructPtr() : value_.Clone();
171 } 188 }
189
190 // Compares the pointees (which might both be null).
172 bool Equals(const InlinedStructPtr& other) const { 191 bool Equals(const InlinedStructPtr& other) const {
173 if (is_null() || other.is_null()) 192 if (is_null() || other.is_null())
174 return is_null() && other.is_null(); 193 return is_null() && other.is_null();
175 return value_.Equals(other.value_); 194 return value_.Equals(other.value_);
176 } 195 }
177 196
178 private: 197 // Hashes based on the pointee (which might be null).
179 // TODO(dcheng): Use an explicit conversion operator. 198 size_t Hash(size_t seed) const {
180 typedef Struct InlinedStructPtr::*Testable; 199 if (is_null())
200 return internal::HashCombine(seed, 0);
201 return value_.Hash(seed);
202 }
181 203
182 public: 204 explicit operator bool() const { return !is_null(); }
183 operator Testable() const { return is_null_ ? 0 : &InlinedStructPtr::value_; }
184 205
185 private: 206 private:
186 friend class internal::StructHelper<Struct>; 207 friend class internal::StructHelper<Struct>;
208 friend class internal::InlinedStructPtrWTFHelper<Struct>;
187 209
188 // Forbid the == and != operators explicitly, otherwise InlinedStructPtr will 210 void Initialize() { state_ = VALID; }
189 // be converted to Testable to do == or != comparison.
190 template <typename T>
191 bool operator==(const InlinedStructPtr<T>& other) const = delete;
192 template <typename T>
193 bool operator!=(const InlinedStructPtr<T>& other) const = delete;
194
195 void Initialize() { is_null_ = false; }
196 211
197 void Take(InlinedStructPtr* other) { 212 void Take(InlinedStructPtr* other) {
198 reset(); 213 reset();
199 Swap(other); 214 Swap(other);
200 } 215 }
201 216
217 enum State {
218 VALID,
219 NIL,
220 DELETED, // For use in WTF::HashMap only
221 };
222
202 mutable Struct value_; 223 mutable Struct value_;
203 bool is_null_; 224 State state_;
204 225
205 DISALLOW_COPY_AND_ASSIGN(InlinedStructPtr); 226 DISALLOW_COPY_AND_ASSIGN(InlinedStructPtr);
206 }; 227 };
207 228
229 template <typename T>
230 bool operator==(const InlinedStructPtr<T>& lhs,
231 const InlinedStructPtr<T>& rhs) {
232 return lhs.Equals(rhs);
233 }
234 template <typename T>
235 bool operator!=(const InlinedStructPtr<T>& lhs,
236 const InlinedStructPtr<T>& rhs) {
237 return !(lhs == rhs);
238 }
239
240 namespace internal {
241
242 template <typename Struct>
243 class StructPtrWTFHelper {
244 public:
245 static bool IsHashTableDeletedValue(const StructPtr<Struct>& value) {
246 return value.ptr_ == reinterpret_cast<Struct*>(1u);
247 }
248
249 static void ConstructDeletedValue(mojo::StructPtr<Struct>& slot) {
250 // Dirty trick: implant an invalid pointer in |ptr_|. Destructor isn't
251 // called for deleted buckets, so this is okay.
252 new (&slot) StructPtr<Struct>();
253 slot.ptr_ = reinterpret_cast<Struct*>(1u);
254 }
255 };
256
257 template <typename Struct>
258 class InlinedStructPtrWTFHelper {
259 public:
260 static bool IsHashTableDeletedValue(const InlinedStructPtr<Struct>& value) {
261 return value.state_ == InlinedStructPtr<Struct>::DELETED;
262 }
263
264 static void ConstructDeletedValue(mojo::InlinedStructPtr<Struct>& slot) {
265 new (&slot) InlinedStructPtr<Struct>();
266 slot.state_ = InlinedStructPtr<Struct>::DELETED;
267 }
268 };
269
270 } // namespace internal
271
208 } // namespace mojo 272 } // namespace mojo
209 273
274 namespace std {
275
276 template <typename T>
277 struct hash<mojo::StructPtr<T>> {
278 size_t operator()(const mojo::StructPtr<T>& value) const {
279 return value.Hash(mojo::internal::kHashSeed);
280 }
281 };
282
283 template <typename T>
284 struct hash<mojo::InlinedStructPtr<T>> {
285 size_t operator()(const mojo::InlinedStructPtr<T>& value) const {
286 return value.Hash(mojo::internal::kHashSeed);
287 }
288 };
289
290 } // namespace std
291
210 #endif // MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_ 292 #endif // MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698