| // Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2013 |
| // Google Inc. All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the name Chromium Embedded |
| // Framework nor the names of its contributors may be used to endorse |
| // or promote products derived from this software without specific prior |
| // written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #ifndef CEF_INCLUDE_BASE_CEF_CALLBACK_LIST_H_ |
| #define CEF_INCLUDE_BASE_CEF_CALLBACK_LIST_H_ |
| #pragma once |
| |
| #if defined(BASE_CALLBACK_LIST_H_) |
| // Do nothing if the Chromium header has already been included. |
| // This can happen in cases where Chromium code is used directly by the |
| // client application. When using Chromium code directly always include |
| // the Chromium header first to avoid type conflicts. |
| #elif defined(USING_CHROMIUM_INCLUDES) |
| // When building CEF include the Chromium header directly. |
| #include "base/callback_list.h" |
| #else // !USING_CHROMIUM_INCLUDES |
| // The following is substantially similar to the Chromium implementation. |
| // If the Chromium implementation diverges the below implementation should be |
| // updated to match. |
| |
| #include <list> |
| |
| #include "include/base/cef_basictypes.h" |
| #include "include/base/cef_build.h" |
| #include "include/base/cef_callback.h" |
| #include "include/base/cef_logging.h" |
| #include "include/base/cef_macros.h" |
| #include "include/base/cef_scoped_ptr.h" |
| #include "include/base/internal/cef_callback_internal.h" |
| |
| // OVERVIEW: |
| // |
| // A container for a list of callbacks. Unlike a normal STL vector or list, |
| // this container can be modified during iteration without invalidating the |
| // iterator. It safely handles the case of a callback removing itself |
| // or another callback from the list while callbacks are being run. |
| // |
| // TYPICAL USAGE: |
| // |
| // class MyWidget { |
| // public: |
| // ... |
| // |
| // typedef base::Callback<void(const Foo&)> OnFooCallback; |
| // |
| // scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription> |
| // RegisterCallback(const OnFooCallback& cb) { |
| // return callback_list_.Add(cb); |
| // } |
| // |
| // private: |
| // void NotifyFoo(const Foo& foo) { |
| // callback_list_.Notify(foo); |
| // } |
| // |
| // base::CallbackList<void(const Foo&)> callback_list_; |
| // |
| // DISALLOW_COPY_AND_ASSIGN(MyWidget); |
| // }; |
| // |
| // |
| // class MyWidgetListener { |
| // public: |
| // MyWidgetListener::MyWidgetListener() { |
| // foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback( |
| // base::Bind(&MyWidgetListener::OnFoo, this))); |
| // } |
| // |
| // MyWidgetListener::~MyWidgetListener() { |
| // // Subscription gets deleted automatically and will deregister |
| // // the callback in the process. |
| // } |
| // |
| // private: |
| // void OnFoo(const Foo& foo) { |
| // // Do something. |
| // } |
| // |
| // scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription> |
| // foo_subscription_; |
| // |
| // DISALLOW_COPY_AND_ASSIGN(MyWidgetListener); |
| // }; |
| |
| namespace base { |
| |
| namespace cef_internal { |
| |
| template <typename CallbackType> |
| class CallbackListBase { |
| public: |
| class Subscription { |
| public: |
| Subscription(CallbackListBase<CallbackType>* list, |
| typename std::list<CallbackType>::iterator iter) |
| : list_(list), iter_(iter) {} |
| |
| ~Subscription() { |
| if (list_->active_iterator_count_) { |
| iter_->Reset(); |
| } else { |
| list_->callbacks_.erase(iter_); |
| if (!list_->removal_callback_.is_null()) |
| list_->removal_callback_.Run(); |
| } |
| } |
| |
| private: |
| CallbackListBase<CallbackType>* list_; |
| typename std::list<CallbackType>::iterator iter_; |
| |
| DISALLOW_COPY_AND_ASSIGN(Subscription); |
| }; |
| |
| // Add a callback to the list. The callback will remain registered until the |
| // returned Subscription is destroyed, which must occur before the |
| // CallbackList is destroyed. |
| scoped_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT { |
| DCHECK(!cb.is_null()); |
| return scoped_ptr<Subscription>( |
| new Subscription(this, callbacks_.insert(callbacks_.end(), cb))); |
| } |
| |
| // Sets a callback which will be run when a subscription list is changed. |
| void set_removal_callback(const Closure& callback) { |
| removal_callback_ = callback; |
| } |
| |
| // Returns true if there are no subscriptions. This is only valid to call when |
| // not looping through the list. |
| bool empty() { |
| DCHECK_EQ(0, active_iterator_count_); |
| return callbacks_.empty(); |
| } |
| |
| protected: |
| // An iterator class that can be used to access the list of callbacks. |
| class Iterator { |
| public: |
| explicit Iterator(CallbackListBase<CallbackType>* list) |
| : list_(list), list_iter_(list_->callbacks_.begin()) { |
| ++list_->active_iterator_count_; |
| } |
| |
| Iterator(const Iterator& iter) |
| : list_(iter.list_), list_iter_(iter.list_iter_) { |
| ++list_->active_iterator_count_; |
| } |
| |
| ~Iterator() { |
| if (list_ && --list_->active_iterator_count_ == 0) { |
| list_->Compact(); |
| } |
| } |
| |
| CallbackType* GetNext() { |
| while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null()) |
| ++list_iter_; |
| |
| CallbackType* cb = NULL; |
| if (list_iter_ != list_->callbacks_.end()) { |
| cb = &(*list_iter_); |
| ++list_iter_; |
| } |
| return cb; |
| } |
| |
| private: |
| CallbackListBase<CallbackType>* list_; |
| typename std::list<CallbackType>::iterator list_iter_; |
| }; |
| |
| CallbackListBase() : active_iterator_count_(0) {} |
| |
| ~CallbackListBase() { |
| DCHECK_EQ(0, active_iterator_count_); |
| DCHECK_EQ(0U, callbacks_.size()); |
| } |
| |
| // Returns an instance of a CallbackListBase::Iterator which can be used |
| // to run callbacks. |
| Iterator GetIterator() { return Iterator(this); } |
| |
| // Compact the list: remove any entries which were NULLed out during |
| // iteration. |
| void Compact() { |
| typename std::list<CallbackType>::iterator it = callbacks_.begin(); |
| bool updated = false; |
| while (it != callbacks_.end()) { |
| if ((*it).is_null()) { |
| updated = true; |
| it = callbacks_.erase(it); |
| } else { |
| ++it; |
| } |
| |
| if (updated && !removal_callback_.is_null()) |
| removal_callback_.Run(); |
| } |
| } |
| |
| private: |
| std::list<CallbackType> callbacks_; |
| int active_iterator_count_; |
| Closure removal_callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CallbackListBase); |
| }; |
| |
| } // namespace cef_internal |
| |
| template <typename Sig> |
| class CallbackList; |
| |
| template <> |
| class CallbackList<void(void)> |
| : public cef_internal::CallbackListBase<Callback<void(void)>> { |
| public: |
| typedef Callback<void(void)> CallbackType; |
| |
| CallbackList() {} |
| |
| void Notify() { |
| cef_internal::CallbackListBase<CallbackType>::Iterator it = |
| this->GetIterator(); |
| CallbackType* cb; |
| while ((cb = it.GetNext()) != NULL) { |
| cb->Run(); |
| } |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(CallbackList); |
| }; |
| |
| template <typename A1> |
| class CallbackList<void(A1)> |
| : public cef_internal::CallbackListBase<Callback<void(A1)>> { |
| public: |
| typedef Callback<void(A1)> CallbackType; |
| |
| CallbackList() {} |
| |
| void Notify(typename cef_internal::CallbackParamTraits<A1>::ForwardType a1) { |
| typename cef_internal::CallbackListBase<CallbackType>::Iterator it = |
| this->GetIterator(); |
| CallbackType* cb; |
| while ((cb = it.GetNext()) != NULL) { |
| cb->Run(a1); |
| } |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(CallbackList); |
| }; |
| |
| template <typename A1, typename A2> |
| class CallbackList<void(A1, A2)> |
| : public cef_internal::CallbackListBase<Callback<void(A1, A2)>> { |
| public: |
| typedef Callback<void(A1, A2)> CallbackType; |
| |
| CallbackList() {} |
| |
| void Notify(typename cef_internal::CallbackParamTraits<A1>::ForwardType a1, |
| typename cef_internal::CallbackParamTraits<A2>::ForwardType a2) { |
| typename cef_internal::CallbackListBase<CallbackType>::Iterator it = |
| this->GetIterator(); |
| CallbackType* cb; |
| while ((cb = it.GetNext()) != NULL) { |
| cb->Run(a1, a2); |
| } |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(CallbackList); |
| }; |
| |
| template <typename A1, typename A2, typename A3> |
| class CallbackList<void(A1, A2, A3)> |
| : public cef_internal::CallbackListBase<Callback<void(A1, A2, A3)>> { |
| public: |
| typedef Callback<void(A1, A2, A3)> CallbackType; |
| |
| CallbackList() {} |
| |
| void Notify(typename cef_internal::CallbackParamTraits<A1>::ForwardType a1, |
| typename cef_internal::CallbackParamTraits<A2>::ForwardType a2, |
| typename cef_internal::CallbackParamTraits<A3>::ForwardType a3) { |
| typename cef_internal::CallbackListBase<CallbackType>::Iterator it = |
| this->GetIterator(); |
| CallbackType* cb; |
| while ((cb = it.GetNext()) != NULL) { |
| cb->Run(a1, a2, a3); |
| } |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(CallbackList); |
| }; |
| |
| template <typename A1, typename A2, typename A3, typename A4> |
| class CallbackList<void(A1, A2, A3, A4)> |
| : public cef_internal::CallbackListBase<Callback<void(A1, A2, A3, A4)>> { |
| public: |
| typedef Callback<void(A1, A2, A3, A4)> CallbackType; |
| |
| CallbackList() {} |
| |
| void Notify(typename cef_internal::CallbackParamTraits<A1>::ForwardType a1, |
| typename cef_internal::CallbackParamTraits<A2>::ForwardType a2, |
| typename cef_internal::CallbackParamTraits<A3>::ForwardType a3, |
| typename cef_internal::CallbackParamTraits<A4>::ForwardType a4) { |
| typename cef_internal::CallbackListBase<CallbackType>::Iterator it = |
| this->GetIterator(); |
| CallbackType* cb; |
| while ((cb = it.GetNext()) != NULL) { |
| cb->Run(a1, a2, a3, a4); |
| } |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(CallbackList); |
| }; |
| |
| template <typename A1, typename A2, typename A3, typename A4, typename A5> |
| class CallbackList<void(A1, A2, A3, A4, A5)> |
| : public cef_internal::CallbackListBase< |
| Callback<void(A1, A2, A3, A4, A5)>> { |
| public: |
| typedef Callback<void(A1, A2, A3, A4, A5)> CallbackType; |
| |
| CallbackList() {} |
| |
| void Notify(typename cef_internal::CallbackParamTraits<A1>::ForwardType a1, |
| typename cef_internal::CallbackParamTraits<A2>::ForwardType a2, |
| typename cef_internal::CallbackParamTraits<A3>::ForwardType a3, |
| typename cef_internal::CallbackParamTraits<A4>::ForwardType a4, |
| typename cef_internal::CallbackParamTraits<A5>::ForwardType a5) { |
| typename cef_internal::CallbackListBase<CallbackType>::Iterator it = |
| this->GetIterator(); |
| CallbackType* cb; |
| while ((cb = it.GetNext()) != NULL) { |
| cb->Run(a1, a2, a3, a4, a5); |
| } |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(CallbackList); |
| }; |
| |
| template <typename A1, |
| typename A2, |
| typename A3, |
| typename A4, |
| typename A5, |
| typename A6> |
| class CallbackList<void(A1, A2, A3, A4, A5, A6)> |
| : public cef_internal::CallbackListBase< |
| Callback<void(A1, A2, A3, A4, A5, A6)>> { |
| public: |
| typedef Callback<void(A1, A2, A3, A4, A5, A6)> CallbackType; |
| |
| CallbackList() {} |
| |
| void Notify(typename cef_internal::CallbackParamTraits<A1>::ForwardType a1, |
| typename cef_internal::CallbackParamTraits<A2>::ForwardType a2, |
| typename cef_internal::CallbackParamTraits<A3>::ForwardType a3, |
| typename cef_internal::CallbackParamTraits<A4>::ForwardType a4, |
| typename cef_internal::CallbackParamTraits<A5>::ForwardType a5, |
| typename cef_internal::CallbackParamTraits<A6>::ForwardType a6) { |
| typename cef_internal::CallbackListBase<CallbackType>::Iterator it = |
| this->GetIterator(); |
| CallbackType* cb; |
| while ((cb = it.GetNext()) != NULL) { |
| cb->Run(a1, a2, a3, a4, a5, a6); |
| } |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(CallbackList); |
| }; |
| |
| template <typename A1, |
| typename A2, |
| typename A3, |
| typename A4, |
| typename A5, |
| typename A6, |
| typename A7> |
| class CallbackList<void(A1, A2, A3, A4, A5, A6, A7)> |
| : public cef_internal::CallbackListBase< |
| Callback<void(A1, A2, A3, A4, A5, A6, A7)>> { |
| public: |
| typedef Callback<void(A1, A2, A3, A4, A5, A6, A7)> CallbackType; |
| |
| CallbackList() {} |
| |
| void Notify(typename cef_internal::CallbackParamTraits<A1>::ForwardType a1, |
| typename cef_internal::CallbackParamTraits<A2>::ForwardType a2, |
| typename cef_internal::CallbackParamTraits<A3>::ForwardType a3, |
| typename cef_internal::CallbackParamTraits<A4>::ForwardType a4, |
| typename cef_internal::CallbackParamTraits<A5>::ForwardType a5, |
| typename cef_internal::CallbackParamTraits<A6>::ForwardType a6, |
| typename cef_internal::CallbackParamTraits<A7>::ForwardType a7) { |
| typename cef_internal::CallbackListBase<CallbackType>::Iterator it = |
| this->GetIterator(); |
| CallbackType* cb; |
| while ((cb = it.GetNext()) != NULL) { |
| cb->Run(a1, a2, a3, a4, a5, a6, a7); |
| } |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(CallbackList); |
| }; |
| |
| } // namespace base |
| |
| #endif // !USING_CHROMIUM_INCLUDES |
| |
| #endif // CEF_INCLUDE_BASE_CEF_CALLBACK_LIST_H_ |