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