145 lines
3.8 KiB
C++
145 lines
3.8 KiB
C++
// Copyright 2014 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_SET_H_
|
|
#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_SET_H_
|
|
|
|
#include <map>
|
|
#include <utility>
|
|
|
|
#include "base/macros.h"
|
|
#include "base/memory/weak_ptr.h"
|
|
#include "base/stl_util.h"
|
|
#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
|
|
#include "mojo/public/cpp/bindings/interface_ptr.h"
|
|
|
|
namespace mojo {
|
|
|
|
using InterfacePtrSetElementId = size_t;
|
|
|
|
namespace internal {
|
|
|
|
// TODO(blundell): This class should be rewritten to be structured
|
|
// similarly to BindingSet if possible, with PtrSet owning its
|
|
// Elements and those Elements calling back into PtrSet on connection
|
|
// error.
|
|
template <typename Interface, template <typename> class Ptr>
|
|
class PtrSet {
|
|
public:
|
|
PtrSet() {}
|
|
~PtrSet() { CloseAll(); }
|
|
|
|
InterfacePtrSetElementId AddPtr(Ptr<Interface> ptr) {
|
|
InterfacePtrSetElementId id = next_ptr_id_++;
|
|
auto weak_interface_ptr = new Element(std::move(ptr));
|
|
ptrs_.emplace(std::piecewise_construct, std::forward_as_tuple(id),
|
|
std::forward_as_tuple(weak_interface_ptr->GetWeakPtr()));
|
|
ClearNullPtrs();
|
|
return id;
|
|
}
|
|
|
|
template <typename FunctionType>
|
|
void ForAllPtrs(FunctionType function) {
|
|
for (const auto& it : ptrs_) {
|
|
if (it.second)
|
|
function(it.second->get());
|
|
}
|
|
ClearNullPtrs();
|
|
}
|
|
|
|
void CloseAll() {
|
|
for (const auto& it : ptrs_) {
|
|
if (it.second)
|
|
it.second->Close();
|
|
}
|
|
ptrs_.clear();
|
|
}
|
|
|
|
bool empty() const { return ptrs_.empty(); }
|
|
|
|
// Calls FlushForTesting on all Ptrs sequentially. Since each call is a
|
|
// blocking operation, may be very slow as the number of pointers increases.
|
|
void FlushForTesting() {
|
|
for (const auto& it : ptrs_) {
|
|
if (it.second)
|
|
it.second->FlushForTesting();
|
|
}
|
|
ClearNullPtrs();
|
|
}
|
|
|
|
bool HasPtr(InterfacePtrSetElementId id) {
|
|
return ptrs_.find(id) != ptrs_.end();
|
|
}
|
|
|
|
Ptr<Interface> RemovePtr(InterfacePtrSetElementId id) {
|
|
auto it = ptrs_.find(id);
|
|
if (it == ptrs_.end())
|
|
return Ptr<Interface>();
|
|
Ptr<Interface> ptr;
|
|
if (it->second) {
|
|
ptr = it->second->Take();
|
|
delete it->second.get();
|
|
}
|
|
ptrs_.erase(it);
|
|
return ptr;
|
|
}
|
|
|
|
private:
|
|
class Element {
|
|
public:
|
|
explicit Element(Ptr<Interface> ptr)
|
|
: ptr_(std::move(ptr)), weak_ptr_factory_(this) {
|
|
ptr_.set_connection_error_handler(base::Bind(&DeleteElement, this));
|
|
}
|
|
|
|
~Element() {}
|
|
|
|
void Close() {
|
|
ptr_.reset();
|
|
|
|
// Resetting the interface ptr means that it won't call this object back
|
|
// on connection error anymore, so this object must delete itself now.
|
|
DeleteElement(this);
|
|
}
|
|
|
|
Interface* get() { return ptr_.get(); }
|
|
|
|
Ptr<Interface> Take() { return std::move(ptr_); }
|
|
|
|
base::WeakPtr<Element> GetWeakPtr() {
|
|
return weak_ptr_factory_.GetWeakPtr();
|
|
}
|
|
|
|
void FlushForTesting() { ptr_.FlushForTesting(); }
|
|
|
|
private:
|
|
static void DeleteElement(Element* element) { delete element; }
|
|
|
|
Ptr<Interface> ptr_;
|
|
base::WeakPtrFactory<Element> weak_ptr_factory_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(Element);
|
|
};
|
|
|
|
void ClearNullPtrs() {
|
|
base::EraseIf(ptrs_, [](const auto& pair) { return !(pair.second); });
|
|
}
|
|
|
|
InterfacePtrSetElementId next_ptr_id_ = 0;
|
|
std::map<InterfacePtrSetElementId, base::WeakPtr<Element>> ptrs_;
|
|
};
|
|
|
|
} // namespace internal
|
|
|
|
template <typename Interface>
|
|
using InterfacePtrSet = internal::PtrSet<Interface, InterfacePtr>;
|
|
|
|
template <typename Interface>
|
|
using AssociatedInterfacePtrSet =
|
|
internal::PtrSet<Interface, AssociatedInterfacePtr>;
|
|
|
|
} // namespace mojo
|
|
|
|
#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_SET_H_
|