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/macros.h" 12 #include "base/memory/weak_ptr.h" 13 #include "base/stl_util.h" 14 #include "mojo/public/cpp/bindings/associated_interface_ptr.h" 15 #include "mojo/public/cpp/bindings/interface_ptr.h" 16 17 namespace mojo { 18 19 using InterfacePtrSetElementId = size_t; 20 21 namespace internal { 22 23 // TODO(blundell): This class should be rewritten to be structured 24 // similarly to BindingSet if possible, with PtrSet owning its 25 // Elements and those Elements calling back into PtrSet on connection 26 // error. 27 template <typename Interface, template <typename> class Ptr> 28 class PtrSet { 29 public: PtrSet()30 PtrSet() {} ~PtrSet()31 ~PtrSet() { CloseAll(); } 32 AddPtr(Ptr<Interface> ptr)33 InterfacePtrSetElementId AddPtr(Ptr<Interface> ptr) { 34 InterfacePtrSetElementId id = next_ptr_id_++; 35 auto weak_interface_ptr = new Element(std::move(ptr)); 36 ptrs_.emplace(std::piecewise_construct, std::forward_as_tuple(id), 37 std::forward_as_tuple(weak_interface_ptr->GetWeakPtr())); 38 ClearNullPtrs(); 39 return id; 40 } 41 42 template <typename FunctionType> ForAllPtrs(FunctionType function)43 void ForAllPtrs(FunctionType function) { 44 for (const auto& it : ptrs_) { 45 if (it.second) 46 function(it.second->get()); 47 } 48 ClearNullPtrs(); 49 } 50 CloseAll()51 void CloseAll() { 52 for (const auto& it : ptrs_) { 53 if (it.second) 54 it.second->Close(); 55 } 56 ptrs_.clear(); 57 } 58 empty()59 bool empty() const { return ptrs_.empty(); } 60 61 // Calls FlushForTesting on all Ptrs sequentially. Since each call is a 62 // blocking operation, may be very slow as the number of pointers increases. FlushForTesting()63 void FlushForTesting() { 64 for (const auto& it : ptrs_) { 65 if (it.second) 66 it.second->FlushForTesting(); 67 } 68 ClearNullPtrs(); 69 } 70 HasPtr(InterfacePtrSetElementId id)71 bool HasPtr(InterfacePtrSetElementId id) { 72 return ptrs_.find(id) != ptrs_.end(); 73 } 74 RemovePtr(InterfacePtrSetElementId id)75 Ptr<Interface> RemovePtr(InterfacePtrSetElementId id) { 76 auto it = ptrs_.find(id); 77 if (it == ptrs_.end()) 78 return Ptr<Interface>(); 79 Ptr<Interface> ptr; 80 if (it->second) { 81 ptr = it->second->Take(); 82 delete it->second.get(); 83 } 84 ptrs_.erase(it); 85 return ptr; 86 } 87 88 private: 89 class Element { 90 public: Element(Ptr<Interface> ptr)91 explicit Element(Ptr<Interface> ptr) 92 : ptr_(std::move(ptr)), weak_ptr_factory_(this) { 93 ptr_.set_connection_error_handler(base::Bind(&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_; 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 template <typename Interface> 136 using InterfacePtrSet = internal::PtrSet<Interface, InterfacePtr>; 137 138 template <typename Interface> 139 using AssociatedInterfacePtrSet = 140 internal::PtrSet<Interface, AssociatedInterfacePtr>; 141 142 } // namespace mojo 143 144 #endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_SET_H_ 145