• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
7 
8 #include <functional>
9 #include <memory>
10 #include <new>
11 
12 #include "base/logging.h"
13 #include "base/macros.h"
14 #include "base/optional.h"
15 #include "mojo/public/cpp/bindings/lib/hash_util.h"
16 #include "mojo/public/cpp/bindings/type_converter.h"
17 
18 namespace mojo {
19 namespace internal {
20 
21 constexpr size_t kHashSeed = 31;
22 
23 template <typename Struct>
24 class StructPtrWTFHelper;
25 
26 template <typename Struct>
27 class InlinedStructPtrWTFHelper;
28 
29 }  // namespace internal
30 
31 // Smart pointer wrapping a mojom structure with move-only semantics.
32 template <typename S>
33 class StructPtr {
34  public:
35   using Struct = S;
36 
37   StructPtr() = default;
StructPtr(decltype (nullptr))38   StructPtr(decltype(nullptr)) {}
39 
40   ~StructPtr() = default;
41 
decltype(nullptr)42   StructPtr& operator=(decltype(nullptr)) {
43     reset();
44     return *this;
45   }
46 
StructPtr(StructPtr && other)47   StructPtr(StructPtr&& other) { Take(&other); }
48   StructPtr& operator=(StructPtr&& other) {
49     Take(&other);
50     return *this;
51   }
52 
53   template <typename... Args>
StructPtr(base::in_place_t,Args &&...args)54   StructPtr(base::in_place_t, Args&&... args)
55       : ptr_(new Struct(std::forward<Args>(args)...)) {}
56 
57   template <typename U>
To()58   U To() const {
59     return TypeConverter<U, StructPtr>::Convert(*this);
60   }
61 
reset()62   void reset() { ptr_.reset(); }
63 
is_null()64   bool is_null() const { return !ptr_; }
65 
66   Struct& operator*() const {
67     DCHECK(ptr_);
68     return *ptr_;
69   }
70   Struct* operator->() const {
71     DCHECK(ptr_);
72     return ptr_.get();
73   }
get()74   Struct* get() const { return ptr_.get(); }
75 
Swap(StructPtr * other)76   void Swap(StructPtr* other) { std::swap(ptr_, other->ptr_); }
77 
78   // Please note that calling this method will fail compilation if the value
79   // type |Struct| doesn't have a Clone() method defined (which usually means
80   // that it contains Mojo handles).
Clone()81   StructPtr Clone() const { return is_null() ? StructPtr() : ptr_->Clone(); }
82 
83   // Compares the pointees (which might both be null).
84   // TODO(crbug.com/735302): Get rid of Equals in favor of the operator. Same
85   // for Hash.
Equals(const StructPtr & other)86   bool Equals(const StructPtr& other) const {
87     if (is_null() || other.is_null())
88       return is_null() && other.is_null();
89     return ptr_->Equals(*other.ptr_);
90   }
91 
92   // Hashes based on the pointee (which might be null).
Hash(size_t seed)93   size_t Hash(size_t seed) const {
94     if (is_null())
95       return internal::HashCombine(seed, 0);
96     return ptr_->Hash(seed);
97   }
98 
99   explicit operator bool() const { return !is_null(); }
100 
101   bool operator<(const StructPtr& other) const {
102     return Hash(internal::kHashSeed) < other.Hash(internal::kHashSeed);
103   }
104 
105  private:
106   friend class internal::StructPtrWTFHelper<Struct>;
Take(StructPtr * other)107   void Take(StructPtr* other) {
108     reset();
109     Swap(other);
110   }
111 
112   std::unique_ptr<Struct> ptr_;
113 
114   DISALLOW_COPY_AND_ASSIGN(StructPtr);
115 };
116 
117 template <typename T>
118 bool operator==(const StructPtr<T>& lhs, const StructPtr<T>& rhs) {
119   return lhs.Equals(rhs);
120 }
121 template <typename T>
122 bool operator!=(const StructPtr<T>& lhs, const StructPtr<T>& rhs) {
123   return !(lhs == rhs);
124 }
125 
126 // Designed to be used when Struct is small and copyable.
127 template <typename S>
128 class InlinedStructPtr {
129  public:
130   using Struct = S;
131 
InlinedStructPtr()132   InlinedStructPtr() : state_(NIL) {}
InlinedStructPtr(decltype (nullptr))133   InlinedStructPtr(decltype(nullptr)) : state_(NIL) {}
134 
~InlinedStructPtr()135   ~InlinedStructPtr() {}
136 
decltype(nullptr)137   InlinedStructPtr& operator=(decltype(nullptr)) {
138     reset();
139     return *this;
140   }
141 
InlinedStructPtr(InlinedStructPtr && other)142   InlinedStructPtr(InlinedStructPtr&& other) : state_(NIL) { Take(&other); }
143   InlinedStructPtr& operator=(InlinedStructPtr&& other) {
144     Take(&other);
145     return *this;
146   }
147 
148   template <typename... Args>
InlinedStructPtr(base::in_place_t,Args &&...args)149   InlinedStructPtr(base::in_place_t, Args&&... args)
150       : value_(std::forward<Args>(args)...), state_(VALID) {}
151 
152   template <typename U>
To()153   U To() const {
154     return TypeConverter<U, InlinedStructPtr>::Convert(*this);
155   }
156 
reset()157   void reset() {
158     state_ = NIL;
159     value_. ~Struct();
160     new (&value_) Struct();
161   }
162 
is_null()163   bool is_null() const { return state_ == NIL; }
164 
165   Struct& operator*() const {
166     DCHECK(state_ == VALID);
167     return value_;
168   }
169   Struct* operator->() const {
170     DCHECK(state_ == VALID);
171     return &value_;
172   }
get()173   Struct* get() const { return &value_; }
174 
Swap(InlinedStructPtr * other)175   void Swap(InlinedStructPtr* other) {
176     std::swap(value_, other->value_);
177     std::swap(state_, other->state_);
178   }
179 
Clone()180   InlinedStructPtr Clone() const {
181     return is_null() ? InlinedStructPtr() : value_.Clone();
182   }
183 
184   // Compares the pointees (which might both be null).
Equals(const InlinedStructPtr & other)185   bool Equals(const InlinedStructPtr& other) const {
186     if (is_null() || other.is_null())
187       return is_null() && other.is_null();
188     return value_.Equals(other.value_);
189   }
190 
191   // Hashes based on the pointee (which might be null).
Hash(size_t seed)192   size_t Hash(size_t seed) const {
193     if (is_null())
194       return internal::HashCombine(seed, 0);
195     return value_.Hash(seed);
196   }
197 
198   explicit operator bool() const { return !is_null(); }
199 
200   bool operator<(const InlinedStructPtr& other) const {
201     return Hash(internal::kHashSeed) < other.Hash(internal::kHashSeed);
202   }
203 
204  private:
205   friend class internal::InlinedStructPtrWTFHelper<Struct>;
Take(InlinedStructPtr * other)206   void Take(InlinedStructPtr* other) {
207     reset();
208     Swap(other);
209   }
210 
211   enum State {
212     VALID,
213     NIL,
214     DELETED,  // For use in WTF::HashMap only
215   };
216 
217   mutable Struct value_;
218   State state_;
219 
220   DISALLOW_COPY_AND_ASSIGN(InlinedStructPtr);
221 };
222 
223 template <typename T>
224 bool operator==(const InlinedStructPtr<T>& lhs,
225                 const InlinedStructPtr<T>& rhs) {
226   return lhs.Equals(rhs);
227 }
228 template <typename T>
229 bool operator!=(const InlinedStructPtr<T>& lhs,
230                 const InlinedStructPtr<T>& rhs) {
231   return !(lhs == rhs);
232 }
233 
234 namespace internal {
235 
236 template <typename Struct>
237 class StructPtrWTFHelper {
238  public:
IsHashTableDeletedValue(const StructPtr<Struct> & value)239   static bool IsHashTableDeletedValue(const StructPtr<Struct>& value) {
240     return value.ptr_.get() == reinterpret_cast<Struct*>(1u);
241   }
242 
ConstructDeletedValue(mojo::StructPtr<Struct> & slot)243   static void ConstructDeletedValue(mojo::StructPtr<Struct>& slot) {
244     // |slot| refers to a previous, real value that got deleted and had its
245     // destructor run, so this is the first time the "deleted value" has its
246     // constructor called.
247     //
248     // Dirty trick: implant an invalid pointer in |ptr_|. Destructor isn't
249     // called for deleted buckets, so this is okay.
250     new (&slot) StructPtr<Struct>();
251     slot.ptr_.reset(reinterpret_cast<Struct*>(1u));
252   }
253 };
254 
255 template <typename Struct>
256 class InlinedStructPtrWTFHelper {
257  public:
IsHashTableDeletedValue(const InlinedStructPtr<Struct> & value)258   static bool IsHashTableDeletedValue(const InlinedStructPtr<Struct>& value) {
259     return value.state_ == InlinedStructPtr<Struct>::DELETED;
260   }
261 
ConstructDeletedValue(mojo::InlinedStructPtr<Struct> & slot)262   static void ConstructDeletedValue(mojo::InlinedStructPtr<Struct>& slot) {
263     // |slot| refers to a previous, real value that got deleted and had its
264     // destructor run, so this is the first time the "deleted value" has its
265     // constructor called.
266     new (&slot) InlinedStructPtr<Struct>();
267     slot.state_ = InlinedStructPtr<Struct>::DELETED;
268   }
269 };
270 
271 }  // namespace internal
272 }  // namespace mojo
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 
292 #endif  // MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
293