• 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(tibell): Get rid of Equals in favor of the operator. Same for Hash.
Equals(const StructPtr & other)85   bool Equals(const StructPtr& other) const {
86     if (is_null() || other.is_null())
87       return is_null() && other.is_null();
88     return ptr_->Equals(*other.ptr_);
89   }
90 
91   // Hashes based on the pointee (which might be null).
Hash(size_t seed)92   size_t Hash(size_t seed) const {
93     if (is_null())
94       return internal::HashCombine(seed, 0);
95     return ptr_->Hash(seed);
96   }
97 
98   explicit operator bool() const { return !is_null(); }
99 
100  private:
101   friend class internal::StructPtrWTFHelper<Struct>;
Take(StructPtr * other)102   void Take(StructPtr* other) {
103     reset();
104     Swap(other);
105   }
106 
107   std::unique_ptr<Struct> ptr_;
108 
109   DISALLOW_COPY_AND_ASSIGN(StructPtr);
110 };
111 
112 template <typename T>
113 bool operator==(const StructPtr<T>& lhs, const StructPtr<T>& rhs) {
114   return lhs.Equals(rhs);
115 }
116 template <typename T>
117 bool operator!=(const StructPtr<T>& lhs, const StructPtr<T>& rhs) {
118   return !(lhs == rhs);
119 }
120 
121 // Designed to be used when Struct is small and copyable.
122 template <typename S>
123 class InlinedStructPtr {
124  public:
125   using Struct = S;
126 
InlinedStructPtr()127   InlinedStructPtr() : state_(NIL) {}
InlinedStructPtr(decltype (nullptr))128   InlinedStructPtr(decltype(nullptr)) : state_(NIL) {}
129 
~InlinedStructPtr()130   ~InlinedStructPtr() {}
131 
decltype(nullptr)132   InlinedStructPtr& operator=(decltype(nullptr)) {
133     reset();
134     return *this;
135   }
136 
InlinedStructPtr(InlinedStructPtr && other)137   InlinedStructPtr(InlinedStructPtr&& other) : state_(NIL) { Take(&other); }
138   InlinedStructPtr& operator=(InlinedStructPtr&& other) {
139     Take(&other);
140     return *this;
141   }
142 
143   template <typename... Args>
InlinedStructPtr(base::in_place_t,Args &&...args)144   InlinedStructPtr(base::in_place_t, Args&&... args)
145       : value_(std::forward<Args>(args)...), state_(VALID) {}
146 
147   template <typename U>
To()148   U To() const {
149     return TypeConverter<U, InlinedStructPtr>::Convert(*this);
150   }
151 
reset()152   void reset() {
153     state_ = NIL;
154     value_. ~Struct();
155     new (&value_) Struct();
156   }
157 
is_null()158   bool is_null() const { return state_ == NIL; }
159 
160   Struct& operator*() const {
161     DCHECK(state_ == VALID);
162     return value_;
163   }
164   Struct* operator->() const {
165     DCHECK(state_ == VALID);
166     return &value_;
167   }
get()168   Struct* get() const { return &value_; }
169 
Swap(InlinedStructPtr * other)170   void Swap(InlinedStructPtr* other) {
171     std::swap(value_, other->value_);
172     std::swap(state_, other->state_);
173   }
174 
Clone()175   InlinedStructPtr Clone() const {
176     return is_null() ? InlinedStructPtr() : value_.Clone();
177   }
178 
179   // Compares the pointees (which might both be null).
Equals(const InlinedStructPtr & other)180   bool Equals(const InlinedStructPtr& other) const {
181     if (is_null() || other.is_null())
182       return is_null() && other.is_null();
183     return value_.Equals(other.value_);
184   }
185 
186   // Hashes based on the pointee (which might be null).
Hash(size_t seed)187   size_t Hash(size_t seed) const {
188     if (is_null())
189       return internal::HashCombine(seed, 0);
190     return value_.Hash(seed);
191   }
192 
193   explicit operator bool() const { return !is_null(); }
194 
195  private:
196   friend class internal::InlinedStructPtrWTFHelper<Struct>;
Take(InlinedStructPtr * other)197   void Take(InlinedStructPtr* other) {
198     reset();
199     Swap(other);
200   }
201 
202   enum State {
203     VALID,
204     NIL,
205     DELETED,  // For use in WTF::HashMap only
206   };
207 
208   mutable Struct value_;
209   State state_;
210 
211   DISALLOW_COPY_AND_ASSIGN(InlinedStructPtr);
212 };
213 
214 template <typename T>
215 bool operator==(const InlinedStructPtr<T>& lhs,
216                 const InlinedStructPtr<T>& rhs) {
217   return lhs.Equals(rhs);
218 }
219 template <typename T>
220 bool operator!=(const InlinedStructPtr<T>& lhs,
221                 const InlinedStructPtr<T>& rhs) {
222   return !(lhs == rhs);
223 }
224 
225 namespace internal {
226 
227 template <typename Struct>
228 class StructPtrWTFHelper {
229  public:
IsHashTableDeletedValue(const StructPtr<Struct> & value)230   static bool IsHashTableDeletedValue(const StructPtr<Struct>& value) {
231     return value.ptr_.get() == reinterpret_cast<Struct*>(1u);
232   }
233 
ConstructDeletedValue(mojo::StructPtr<Struct> & slot)234   static void ConstructDeletedValue(mojo::StructPtr<Struct>& slot) {
235     // |slot| refers to a previous, real value that got deleted and had its
236     // destructor run, so this is the first time the "deleted value" has its
237     // constructor called.
238     //
239     // Dirty trick: implant an invalid pointer in |ptr_|. Destructor isn't
240     // called for deleted buckets, so this is okay.
241     new (&slot) StructPtr<Struct>();
242     slot.ptr_.reset(reinterpret_cast<Struct*>(1u));
243   }
244 };
245 
246 template <typename Struct>
247 class InlinedStructPtrWTFHelper {
248  public:
IsHashTableDeletedValue(const InlinedStructPtr<Struct> & value)249   static bool IsHashTableDeletedValue(const InlinedStructPtr<Struct>& value) {
250     return value.state_ == InlinedStructPtr<Struct>::DELETED;
251   }
252 
ConstructDeletedValue(mojo::InlinedStructPtr<Struct> & slot)253   static void ConstructDeletedValue(mojo::InlinedStructPtr<Struct>& slot) {
254     // |slot| refers to a previous, real value that got deleted and had its
255     // destructor run, so this is the first time the "deleted value" has its
256     // constructor called.
257     new (&slot) InlinedStructPtr<Struct>();
258     slot.state_ = InlinedStructPtr<Struct>::DELETED;
259   }
260 };
261 
262 }  // namespace internal
263 }  // namespace mojo
264 
265 namespace std {
266 
267 template <typename T>
268 struct hash<mojo::StructPtr<T>> {
269   size_t operator()(const mojo::StructPtr<T>& value) const {
270     return value.Hash(mojo::internal::kHashSeed);
271   }
272 };
273 
274 template <typename T>
275 struct hash<mojo::InlinedStructPtr<T>> {
276   size_t operator()(const mojo::InlinedStructPtr<T>& value) const {
277     return value.Hash(mojo::internal::kHashSeed);
278   }
279 };
280 
281 }  // namespace std
282 
283 #endif  // MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_
284