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_INTERFACE_PTR_SET_H_ 6 #define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_SET_H_ 7 8 #include <map> 9 #include <utility> 10 11 #include "base/bind.h" 12 #include "base/macros.h" 13 #include "base/memory/weak_ptr.h" 14 #include "base/stl_util.h" 15 #include "mojo/public/cpp/bindings/associated_interface_ptr.h" 16 #include "mojo/public/cpp/bindings/interface_ptr.h" 17 18 namespace mojo { 19 20 using InterfacePtrSetElementId = size_t; 21 22 namespace internal { 23 24 // TODO(https://crbug.com/965668): This class should be rewritten to be 25 // structured similarly to BindingSet if possible, with PtrSet owning its 26 // Elements and those Elements calling back into PtrSet on connection 27 // error. 28 template <typename Interface, template <typename> class Ptr> 29 class PtrSet { 30 public: PtrSet()31 PtrSet() {} ~PtrSet()32 ~PtrSet() { CloseAll(); } 33 AddPtr(Ptr<Interface> ptr)34 InterfacePtrSetElementId AddPtr(Ptr<Interface> ptr) { 35 InterfacePtrSetElementId id = next_ptr_id_++; 36 auto weak_interface_ptr = new Element(std::move(ptr)); 37 ptrs_.emplace(std::piecewise_construct, std::forward_as_tuple(id), 38 std::forward_as_tuple(weak_interface_ptr->GetWeakPtr())); 39 ClearNullPtrs(); 40 return id; 41 } 42 43 template <typename FunctionType> ForAllPtrs(FunctionType function)44 void ForAllPtrs(FunctionType function) { 45 for (const auto& it : ptrs_) { 46 if (it.second) 47 function(it.second->get()); 48 } 49 ClearNullPtrs(); 50 } 51 CloseAll()52 void CloseAll() { 53 for (const auto& it : ptrs_) { 54 if (it.second) 55 it.second->Close(); 56 } 57 ptrs_.clear(); 58 } 59 empty()60 bool empty() const { return ptrs_.empty(); } 61 62 // Calls FlushForTesting on all Ptrs sequentially. Since each call is a 63 // blocking operation, may be very slow as the number of pointers increases. FlushForTesting()64 void FlushForTesting() { 65 for (const auto& it : ptrs_) { 66 if (it.second) 67 it.second->FlushForTesting(); 68 } 69 ClearNullPtrs(); 70 } 71 HasPtr(InterfacePtrSetElementId id)72 bool HasPtr(InterfacePtrSetElementId id) { 73 return ptrs_.find(id) != ptrs_.end(); 74 } 75 RemovePtr(InterfacePtrSetElementId id)76 Ptr<Interface> RemovePtr(InterfacePtrSetElementId id) { 77 auto it = ptrs_.find(id); 78 if (it == ptrs_.end()) 79 return Ptr<Interface>(); 80 Ptr<Interface> ptr; 81 if (it->second) { 82 ptr = it->second->Take(); 83 delete it->second.get(); 84 } 85 ptrs_.erase(it); 86 return ptr; 87 } 88 89 private: 90 class Element { 91 public: Element(Ptr<Interface> ptr)92 explicit Element(Ptr<Interface> ptr) : ptr_(std::move(ptr)) { 93 ptr_.set_connection_error_handler(base::BindOnce(&DeleteElement, this)); 94 } 95 ~Element()96 ~Element() {} 97 Close()98 void Close() { 99 ptr_.reset(); 100 101 // Resetting the interface ptr means that it won't call this object back 102 // on connection error anymore, so this object must delete itself now. 103 DeleteElement(this); 104 } 105 get()106 Interface* get() { return ptr_.get(); } 107 Take()108 Ptr<Interface> Take() { return std::move(ptr_); } 109 GetWeakPtr()110 base::WeakPtr<Element> GetWeakPtr() { 111 return weak_ptr_factory_.GetWeakPtr(); 112 } 113 FlushForTesting()114 void FlushForTesting() { ptr_.FlushForTesting(); } 115 116 private: DeleteElement(Element * element)117 static void DeleteElement(Element* element) { delete element; } 118 119 Ptr<Interface> ptr_; 120 base::WeakPtrFactory<Element> weak_ptr_factory_{this}; 121 122 DISALLOW_COPY_AND_ASSIGN(Element); 123 }; 124 ClearNullPtrs()125 void ClearNullPtrs() { 126 base::EraseIf(ptrs_, [](const auto& pair) { return !(pair.second); }); 127 } 128 129 InterfacePtrSetElementId next_ptr_id_ = 0; 130 std::map<InterfacePtrSetElementId, base::WeakPtr<Element>> ptrs_; 131 }; 132 133 } // namespace internal 134 135 // DEPRECATED: Do not introduce new uses of this type. Instead use the 136 // RemoteSet type defined in remote_set.h. 137 template <typename Interface> 138 using InterfacePtrSet = internal::PtrSet<Interface, InterfacePtr>; 139 140 // DEPRECATED: Do not introduce new uses of this type. Instead use the 141 // AssociatedRemoteSet type defined in associated_remote_set.h. 142 template <typename Interface> 143 using AssociatedInterfacePtrSet = 144 internal::PtrSet<Interface, AssociatedInterfacePtr>; 145 146 } // namespace mojo 147 148 #endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_SET_H_ 149