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 <new> 9 10 #include "base/logging.h" 11 #include "base/macros.h" 12 #include "mojo/public/cpp/bindings/type_converter.h" 13 14 namespace mojo { 15 namespace internal { 16 17 template <typename Struct> 18 class StructHelper { 19 public: 20 template <typename Ptr> Initialize(Ptr * ptr)21 static void Initialize(Ptr* ptr) { 22 ptr->Initialize(); 23 } 24 }; 25 26 } // namespace internal 27 28 // Smart pointer wrapping a mojom structure with move-only semantics. 29 template <typename S> 30 class StructPtr { 31 public: 32 using Struct = S; 33 StructPtr()34 StructPtr() : ptr_(nullptr) {} StructPtr(decltype (nullptr))35 StructPtr(decltype(nullptr)) : ptr_(nullptr) {} 36 ~StructPtr()37 ~StructPtr() { delete ptr_; } 38 decltype(nullptr)39 StructPtr& operator=(decltype(nullptr)) { 40 reset(); 41 return *this; 42 } 43 StructPtr(StructPtr && other)44 StructPtr(StructPtr&& other) : ptr_(nullptr) { Take(&other); } 45 StructPtr& operator=(StructPtr&& other) { 46 Take(&other); 47 return *this; 48 } 49 50 template <typename U> To()51 U To() const { 52 return TypeConverter<U, StructPtr>::Convert(*this); 53 } 54 reset()55 void reset() { 56 if (ptr_) { 57 delete ptr_; 58 ptr_ = nullptr; 59 } 60 } 61 is_null()62 bool is_null() const { return ptr_ == nullptr; } 63 64 Struct& operator*() const { 65 DCHECK(ptr_); 66 return *ptr_; 67 } 68 Struct* operator->() const { 69 DCHECK(ptr_); 70 return ptr_; 71 } get()72 Struct* get() const { return ptr_; } 73 Swap(StructPtr * other)74 void Swap(StructPtr* other) { std::swap(ptr_, other->ptr_); } 75 76 // 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 78 // that it contains Mojo handles). Clone()79 StructPtr Clone() const { return is_null() ? StructPtr() : ptr_->Clone(); } 80 Equals(const StructPtr & other)81 bool Equals(const StructPtr& other) const { 82 if (is_null() || other.is_null()) 83 return is_null() && other.is_null(); 84 return ptr_->Equals(*other.ptr_); 85 } 86 87 private: 88 // TODO(dcheng): Use an explicit conversion operator. 89 typedef Struct* StructPtr::*Testable; 90 91 public: Testable()92 operator Testable() const { return ptr_ ? &StructPtr::ptr_ : 0; } 93 94 private: 95 friend class internal::StructHelper<Struct>; 96 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 Initialize()104 void Initialize() { 105 DCHECK(!ptr_); 106 ptr_ = new Struct(); 107 } 108 Take(StructPtr * other)109 void Take(StructPtr* other) { 110 reset(); 111 Swap(other); 112 } 113 114 Struct* ptr_; 115 116 DISALLOW_COPY_AND_ASSIGN(StructPtr); 117 }; 118 119 // Designed to be used when Struct is small and copyable. 120 template <typename S> 121 class InlinedStructPtr { 122 public: 123 using Struct = S; 124 InlinedStructPtr()125 InlinedStructPtr() : is_null_(true) {} InlinedStructPtr(decltype (nullptr))126 InlinedStructPtr(decltype(nullptr)) : is_null_(true) {} 127 ~InlinedStructPtr()128 ~InlinedStructPtr() {} 129 decltype(nullptr)130 InlinedStructPtr& operator=(decltype(nullptr)) { 131 reset(); 132 return *this; 133 } 134 InlinedStructPtr(InlinedStructPtr && other)135 InlinedStructPtr(InlinedStructPtr&& other) : is_null_(true) { Take(&other); } 136 InlinedStructPtr& operator=(InlinedStructPtr&& other) { 137 Take(&other); 138 return *this; 139 } 140 141 template <typename U> To()142 U To() const { 143 return TypeConverter<U, InlinedStructPtr>::Convert(*this); 144 } 145 reset()146 void reset() { 147 is_null_ = true; 148 value_. ~Struct(); 149 new (&value_) Struct(); 150 } 151 is_null()152 bool is_null() const { return is_null_; } 153 154 Struct& operator*() const { 155 DCHECK(!is_null_); 156 return value_; 157 } 158 Struct* operator->() const { 159 DCHECK(!is_null_); 160 return &value_; 161 } get()162 Struct* get() const { return &value_; } 163 Swap(InlinedStructPtr * other)164 void Swap(InlinedStructPtr* other) { 165 std::swap(value_, other->value_); 166 std::swap(is_null_, other->is_null_); 167 } 168 Clone()169 InlinedStructPtr Clone() const { 170 return is_null() ? InlinedStructPtr() : value_.Clone(); 171 } Equals(const InlinedStructPtr & other)172 bool Equals(const InlinedStructPtr& other) const { 173 if (is_null() || other.is_null()) 174 return is_null() && other.is_null(); 175 return value_.Equals(other.value_); 176 } 177 178 private: 179 // TODO(dcheng): Use an explicit conversion operator. 180 typedef Struct InlinedStructPtr::*Testable; 181 182 public: Testable()183 operator Testable() const { return is_null_ ? 0 : &InlinedStructPtr::value_; } 184 185 private: 186 friend class internal::StructHelper<Struct>; 187 188 // Forbid the == and != operators explicitly, otherwise InlinedStructPtr will 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 Initialize()195 void Initialize() { is_null_ = false; } 196 Take(InlinedStructPtr * other)197 void Take(InlinedStructPtr* other) { 198 reset(); 199 Swap(other); 200 } 201 202 mutable Struct value_; 203 bool is_null_; 204 205 DISALLOW_COPY_AND_ASSIGN(InlinedStructPtr); 206 }; 207 208 } // namespace mojo 209 210 #endif // MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_ 211