Home | History | Annotate | Download | only in bindings
      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:
     30   PtrSet() {}
     31   ~PtrSet() { CloseAll(); }
     32 
     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>
     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 
     51   void CloseAll() {
     52     for (const auto& it : ptrs_) {
     53       if (it.second)
     54         it.second->Close();
     55     }
     56     ptrs_.clear();
     57   }
     58 
     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.
     63   void FlushForTesting() {
     64     for (const auto& it : ptrs_) {
     65       if (it.second)
     66         it.second->FlushForTesting();
     67     }
     68     ClearNullPtrs();
     69   }
     70 
     71   bool HasPtr(InterfacePtrSetElementId id) {
     72     return ptrs_.find(id) != ptrs_.end();
     73   }
     74 
     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:
     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 
     96     ~Element() {}
     97 
     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 
    106     Interface* get() { return ptr_.get(); }
    107 
    108     Ptr<Interface> Take() { return std::move(ptr_); }
    109 
    110     base::WeakPtr<Element> GetWeakPtr() {
    111       return weak_ptr_factory_.GetWeakPtr();
    112     }
    113 
    114     void FlushForTesting() { ptr_.FlushForTesting(); }
    115 
    116    private:
    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 
    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