David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 1 | // Copyright (c) 2012 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 | // This file contains utility functions and classes that help the |
| 6 | // implementation, and management of the Callback objects. |
| 7 | |
| 8 | #ifndef BASE_CALLBACK_INTERNAL_H_ |
| 9 | #define BASE_CALLBACK_INTERNAL_H_ |
| 10 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 11 | #include "base/base_export.h" |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 12 | #include "base/callback_forward.h" |
| 13 | #include "base/macros.h" |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 14 | #include "base/memory/ref_counted.h" |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 15 | |
| 16 | namespace base { |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 17 | |
| 18 | struct FakeBindState; |
| 19 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 20 | namespace internal { |
| 21 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 22 | class CallbackBase; |
| 23 | class CallbackBaseCopyable; |
| 24 | |
| 25 | class BindStateBase; |
| 26 | |
| 27 | template <typename Functor, typename... BoundArgs> |
| 28 | struct BindState; |
| 29 | |
| 30 | struct BindStateBaseRefCountTraits { |
| 31 | static void Destruct(const BindStateBase*); |
| 32 | }; |
| 33 | |
| 34 | template <typename T> |
| 35 | #if defined(STARBOARD) && defined(SB_IS_COMPILER_MSVC) |
| 36 | // On MSVC, std::conditional_t does not return true with some equal types. |
| 37 | using PassingType = T&&; |
| 38 | #else |
| 39 | using PassingType = std::conditional_t<std::is_scalar<T>::value, T, T&&>; |
| 40 | #endif |
| 41 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 42 | // BindStateBase is used to provide an opaque handle that the Callback |
| 43 | // class can use to represent a function object with bound arguments. It |
| 44 | // behaves as an existential type that is used by a corresponding |
| 45 | // DoInvoke function to perform the function execution. This allows |
| 46 | // us to shield the Callback class from the types of the bound argument via |
| 47 | // "type erasure." |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 48 | // At the base level, the only task is to add reference counting data. Don't use |
| 49 | // RefCountedThreadSafe since it requires the destructor to be a virtual method. |
| 50 | // Creating a vtable for every BindState template instantiation results in a lot |
| 51 | // of bloat. Its only task is to call the destructor which can be done with a |
| 52 | // function pointer. |
| 53 | class BASE_EXPORT BindStateBase |
| 54 | : public RefCountedThreadSafe<BindStateBase, BindStateBaseRefCountTraits> { |
| 55 | public: |
| 56 | REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE(); |
| 57 | |
| 58 | enum CancellationQueryMode { |
| 59 | IS_CANCELLED, |
| 60 | MAYBE_VALID, |
| 61 | }; |
| 62 | |
| 63 | using InvokeFuncStorage = void(*)(); |
| 64 | |
| 65 | private: |
| 66 | BindStateBase(InvokeFuncStorage polymorphic_invoke, |
| 67 | void (*destructor)(const BindStateBase*)); |
| 68 | BindStateBase(InvokeFuncStorage polymorphic_invoke, |
| 69 | void (*destructor)(const BindStateBase*), |
| 70 | bool (*query_cancellation_traits)(const BindStateBase*, |
| 71 | CancellationQueryMode mode)); |
| 72 | |
| 73 | ~BindStateBase() = default; |
| 74 | |
| 75 | friend struct BindStateBaseRefCountTraits; |
| 76 | friend class RefCountedThreadSafe<BindStateBase, BindStateBaseRefCountTraits>; |
| 77 | |
| 78 | friend class CallbackBase; |
| 79 | friend class CallbackBaseCopyable; |
| 80 | |
| 81 | // Whitelist subclasses that access the destructor of BindStateBase. |
| 82 | template <typename Functor, typename... BoundArgs> |
| 83 | friend struct BindState; |
| 84 | friend struct ::base::FakeBindState; |
| 85 | |
| 86 | bool IsCancelled() const { |
| 87 | return query_cancellation_traits_(this, IS_CANCELLED); |
| 88 | } |
| 89 | |
| 90 | bool MaybeValid() const { |
| 91 | return query_cancellation_traits_(this, MAYBE_VALID); |
| 92 | } |
| 93 | |
| 94 | // In C++, it is safe to cast function pointers to function pointers of |
| 95 | // another type. It is not okay to use void*. We create a InvokeFuncStorage |
| 96 | // that that can store our function pointer, and then cast it back to |
| 97 | // the original type on usage. |
| 98 | InvokeFuncStorage polymorphic_invoke_; |
| 99 | |
| 100 | // Pointer to a function that will properly destroy |this|. |
| 101 | void (*destructor_)(const BindStateBase*); |
| 102 | bool (*query_cancellation_traits_)(const BindStateBase*, |
| 103 | CancellationQueryMode mode); |
| 104 | |
| 105 | DISALLOW_COPY_AND_ASSIGN(BindStateBase); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 106 | }; |
| 107 | |
| 108 | // Holds the Callback methods that don't require specialization to reduce |
| 109 | // template bloat. |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 110 | // CallbackBase<MoveOnly> is a direct base class of MoveOnly callbacks, and |
| 111 | // CallbackBase<Copyable> uses CallbackBase<MoveOnly> for its implementation. |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 112 | class BASE_EXPORT CallbackBase { |
| 113 | public: |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 114 | inline CallbackBase(CallbackBase&& c) noexcept; |
| 115 | CallbackBase& operator=(CallbackBase&& c) noexcept; |
| 116 | |
| 117 | explicit CallbackBase(const CallbackBaseCopyable& c); |
| 118 | CallbackBase& operator=(const CallbackBaseCopyable& c); |
| 119 | |
| 120 | explicit CallbackBase(CallbackBaseCopyable&& c) noexcept; |
| 121 | CallbackBase& operator=(CallbackBaseCopyable&& c) noexcept; |
| 122 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 123 | // Returns true if Callback is null (doesn't refer to anything). |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 124 | bool is_null() const { return !bind_state_; } |
| 125 | explicit operator bool() const { return !is_null(); } |
| 126 | |
| 127 | // Returns true if the callback invocation will be nop due to an cancellation. |
| 128 | // It's invalid to call this on uninitialized callback. |
| 129 | // |
| 130 | // Must be called on the Callback's destination sequence. |
| 131 | bool IsCancelled() const; |
| 132 | |
| 133 | // If this returns false, the callback invocation will be a nop due to a |
| 134 | // cancellation. This may(!) still return true, even on a cancelled callback. |
| 135 | // |
| 136 | // This function is thread-safe. |
| 137 | bool MaybeValid() const; |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 138 | |
| 139 | // Returns the Callback into an uninitialized state. |
| 140 | void Reset(); |
| 141 | |
| 142 | protected: |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 143 | using InvokeFuncStorage = BindStateBase::InvokeFuncStorage; |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 144 | |
| 145 | // Returns true if this callback equals |other|. |other| may be null. |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 146 | bool EqualsInternal(const CallbackBase& other) const; |
| 147 | |
| 148 | constexpr inline CallbackBase(); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 149 | |
| 150 | // Allow initializing of |bind_state_| via the constructor to avoid default |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 151 | // initialization of the scoped_refptr. |
| 152 | explicit inline CallbackBase(BindStateBase* bind_state); |
| 153 | |
| 154 | InvokeFuncStorage polymorphic_invoke() const { |
| 155 | return bind_state_->polymorphic_invoke_; |
| 156 | } |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 157 | |
| 158 | // Force the destructor to be instantiated inside this translation unit so |
| 159 | // that our subclasses will not get inlined versions. Avoids more template |
| 160 | // bloat. |
| 161 | ~CallbackBase(); |
| 162 | |
| 163 | scoped_refptr<BindStateBase> bind_state_; |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 164 | }; |
| 165 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 166 | constexpr CallbackBase::CallbackBase() = default; |
| 167 | CallbackBase::CallbackBase(CallbackBase&&) noexcept = default; |
| 168 | CallbackBase::CallbackBase(BindStateBase* bind_state) |
| 169 | : bind_state_(AdoptRef(bind_state)) {} |
| 170 | |
| 171 | // CallbackBase<Copyable> is a direct base class of Copyable Callbacks. |
| 172 | class BASE_EXPORT CallbackBaseCopyable : public CallbackBase { |
| 173 | public: |
| 174 | CallbackBaseCopyable(const CallbackBaseCopyable& c); |
| 175 | CallbackBaseCopyable(CallbackBaseCopyable&& c) noexcept = default; |
| 176 | CallbackBaseCopyable& operator=(const CallbackBaseCopyable& c); |
| 177 | CallbackBaseCopyable& operator=(CallbackBaseCopyable&& c) noexcept; |
| 178 | |
| 179 | protected: |
| 180 | constexpr CallbackBaseCopyable() = default; |
| 181 | explicit CallbackBaseCopyable(BindStateBase* bind_state) |
| 182 | : CallbackBase(bind_state) {} |
| 183 | ~CallbackBaseCopyable() = default; |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 184 | }; |
| 185 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 186 | } // namespace internal |
| 187 | } // namespace base |
| 188 | |
| 189 | #endif // BASE_CALLBACK_INTERNAL_H_ |