| // Copyright 2016 The Fuchsia 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 PERIDOT_LIB_BOUND_SET_BOUND_SET_H_ |
| #define PERIDOT_LIB_BOUND_SET_BOUND_SET_H_ |
| |
| #include <vector> |
| |
| #include <lib/fidl/cpp/binding.h> |
| #include <lib/fidl/cpp/interface_ptr.h> |
| #include <src/lib/fxl/logging.h> |
| |
| namespace modular { |
| |
| // "Specialization" (overload) covering unique_ptr. |
| template <typename T> |
| T* GetFidlType(std::unique_ptr<T>* p) { |
| return p->get(); |
| } |
| |
| // General implementation intended to cover Binding and StrongBinding. |
| template <typename FidlType, typename UniqueType = FidlType*> |
| UniqueType Identify(FidlType* binding) { |
| return binding; |
| } |
| |
| // An extensible/derivable InterfacePtrSet/(Strong)BindingSet that contains a |
| // collection of objects of type T that contain FidlTypes (e.g. InterfacePtr, |
| // Binding, or StrongBinding). Elements are automatically removed from the |
| // collection and destroyed when their associated Channel experiences a |
| // connection error. When the set is destroyed all of the Channels will be |
| // closed. |
| // |
| // Unlike the Fidl library InterfacePtrSet and (Strong)BindingSet, this class |
| // does not prevent further mutations to the underlying Fidl type. For well- |
| // defined behavior, the Fidl types should not be modified after being added to |
| // the set. |
| // |
| // Template parameters: |
| // * FidlType - the Fidl type governing each element of the collection, e.g. |
| // InterfacePtr, Binding, or StrongBinding |
| // * T - the element type of the collection |
| // * GetFidlType - a function that extracts the FidlType from an element of the |
| // collection. Defaults to the identity function, which only works if T = |
| // FidlType. |
| // * UniqueType - a type that uniquely identifies a FidlType in the collection. |
| // For InterfacePtrs, this is a pointer to the interface. For bindings, this is |
| // the pointer to the binding. |
| // * Identify - a function that derives a UniqueType from a FidlType. Defaults |
| // behave as described at UniqueType. |
| template <typename FidlType, typename T = FidlType, |
| FidlType* GetFidlType(T*) = GetFidlType, typename UniqueType = void*, |
| UniqueType Identify(FidlType*) = Identify> |
| class BoundSet { |
| public: |
| typedef typename std::vector<T>::iterator iterator; |
| BoundSet() {} |
| virtual ~BoundSet() {} |
| |
| // |ptr| must be bound to a channel. |
| template <typename... _Args> |
| T* emplace(_Args&&... __args) { |
| elements_.emplace_back(std::forward<_Args>(__args)...); |
| T* const c = &elements_.back(); |
| FidlType* const m = GetFidlType(c); |
| FXL_CHECK(m->is_bound()); |
| UniqueType const id = Identify(m); |
| // Set the connection error handler for the newly added item to be a |
| // function that will erase it from the vector. |
| m->set_error_handler( |
| [this, id](zx_status_t status) { OnConnectionError(id); }); |
| return c; |
| } |
| |
| UniqueType GetId(T* object) { return Identify(GetFidlType(object)); } |
| |
| // Removes the element at the given iterator. This effectively closes the pipe |
| // there if open, but it does not call OnConnectionError. |
| iterator erase(iterator it) { return elements_.erase(it); } |
| iterator erase(UniqueType id) { |
| auto it = Find(id); |
| FXL_CHECK(it != elements_.end()); |
| return elements_.erase(it); |
| } |
| |
| // Closes the Channel associated with each of the items in this set and |
| // clears the set. This does not call OnConnectionError for every interface in |
| // the set. |
| void clear() { elements_.clear(); } |
| bool empty() const { return elements_.empty(); } |
| size_t size() const { return elements_.size(); } |
| |
| iterator begin() { return elements_.begin(); } |
| iterator end() { return elements_.end(); } |
| |
| protected: |
| virtual void OnConnectionError(UniqueType id) { erase(id); } |
| |
| private: |
| iterator Find(UniqueType id) { |
| return std::find_if(elements_.begin(), elements_.end(), |
| [id](T& e) { return Identify(GetFidlType(&e)) == id; }); |
| } |
| |
| std::vector<T> elements_; |
| }; |
| |
| // Convenience alias of BoundSet to handle non-movable FIDL types, like Bindings |
| // (and the mythical StrongBinding). |
| // |
| // Note that the default T here must be a unique_ptr rather than the FIDL type |
| // itself since these FIDL types are not movable. |
| template <typename FidlType, typename T = std::unique_ptr<FidlType>, |
| FidlType* GetFidlType(T*) = GetFidlType> |
| using BoundNonMovableSet = BoundSet<FidlType, T, GetFidlType, FidlType*>; |
| |
| template <typename Interface, |
| typename T = std::unique_ptr<fidl::InterfacePtr<Interface>>, |
| fidl::InterfacePtr<Interface>* GetFidlType(T*) = GetFidlType> |
| using BoundPtrSet = |
| BoundNonMovableSet<fidl::InterfacePtr<Interface>, T, GetFidlType>; |
| |
| // Convenience alias of BoundSet to handle Binding containers. |
| template <typename Interface, |
| typename T = std::unique_ptr<fidl::Binding<Interface>>, |
| fidl::Binding<Interface>* GetFidlType(T*) = GetFidlType> |
| using BindingSet = BoundNonMovableSet<fidl::Binding<Interface>, T, GetFidlType>; |
| |
| } // namespace modular |
| |
| #endif // PERIDOT_LIB_BOUND_SET_BOUND_SET_H_ |