• 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_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