Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -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 | |
| 11 | #include <stddef.h> |
| 12 | #include <map> |
| 13 | #include <memory> |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 14 | #include <type_traits> |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 15 | #include <vector> |
| 16 | |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 17 | #include "base/base_export.h" |
Alex Vakulenko | bf79a9e | 2016-03-28 15:11:43 -0700 | [diff] [blame] | 18 | #include "base/callback_forward.h" |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 19 | #include "base/macros.h" |
| 20 | #include "base/memory/ref_counted.h" |
| 21 | #include "base/memory/scoped_ptr.h" |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 22 | |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 23 | namespace base { |
| 24 | namespace internal { |
Alex Vakulenko | bf79a9e | 2016-03-28 15:11:43 -0700 | [diff] [blame] | 25 | template <CopyMode copy_mode> |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 26 | class CallbackBase; |
| 27 | |
| 28 | // BindStateBase is used to provide an opaque handle that the Callback |
| 29 | // class can use to represent a function object with bound arguments. It |
| 30 | // behaves as an existential type that is used by a corresponding |
| 31 | // DoInvoke function to perform the function execution. This allows |
| 32 | // us to shield the Callback class from the types of the bound argument via |
| 33 | // "type erasure." |
| 34 | // At the base level, the only task is to add reference counting data. Don't use |
| 35 | // RefCountedThreadSafe since it requires the destructor to be a virtual method. |
| 36 | // Creating a vtable for every BindState template instantiation results in a lot |
| 37 | // of bloat. Its only task is to call the destructor which can be done with a |
| 38 | // function pointer. |
| 39 | class BindStateBase { |
| 40 | protected: |
| 41 | explicit BindStateBase(void (*destructor)(BindStateBase*)) |
| 42 | : ref_count_(0), destructor_(destructor) {} |
| 43 | ~BindStateBase() = default; |
| 44 | |
| 45 | private: |
| 46 | friend class scoped_refptr<BindStateBase>; |
Alex Vakulenko | bf79a9e | 2016-03-28 15:11:43 -0700 | [diff] [blame] | 47 | template <CopyMode copy_mode> |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 48 | friend class CallbackBase; |
| 49 | |
| 50 | void AddRef(); |
| 51 | void Release(); |
| 52 | |
Vitaly Buka | b1fcfc0 | 2015-09-14 10:24:39 -0700 | [diff] [blame] | 53 | std::atomic<int32_t> ref_count_; |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 54 | |
| 55 | // Pointer to a function that will properly destroy |this|. |
| 56 | void (*destructor_)(BindStateBase*); |
| 57 | |
| 58 | DISALLOW_COPY_AND_ASSIGN(BindStateBase); |
| 59 | }; |
| 60 | |
| 61 | // Holds the Callback methods that don't require specialization to reduce |
| 62 | // template bloat. |
Alex Vakulenko | bf79a9e | 2016-03-28 15:11:43 -0700 | [diff] [blame] | 63 | // CallbackBase<MoveOnly> is a direct base class of MoveOnly callbacks, and |
| 64 | // CallbackBase<Copyable> uses CallbackBase<MoveOnly> for its implementation. |
| 65 | template <> |
| 66 | class BASE_EXPORT CallbackBase<CopyMode::MoveOnly> { |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 67 | public: |
Alex Vakulenko | bf79a9e | 2016-03-28 15:11:43 -0700 | [diff] [blame] | 68 | CallbackBase(CallbackBase&& c); |
| 69 | CallbackBase& operator=(CallbackBase&& c); |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 70 | |
| 71 | // Returns true if Callback is null (doesn't refer to anything). |
| 72 | bool is_null() const { return bind_state_.get() == NULL; } |
| 73 | |
| 74 | // Returns the Callback into an uninitialized state. |
| 75 | void Reset(); |
| 76 | |
| 77 | protected: |
| 78 | // In C++, it is safe to cast function pointers to function pointers of |
| 79 | // another type. It is not okay to use void*. We create a InvokeFuncStorage |
| 80 | // that that can store our function pointer, and then cast it back to |
| 81 | // the original type on usage. |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 82 | using InvokeFuncStorage = void(*)(); |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 83 | |
| 84 | // Returns true if this callback equals |other|. |other| may be null. |
Alex Vakulenko | bf79a9e | 2016-03-28 15:11:43 -0700 | [diff] [blame] | 85 | bool EqualsInternal(const CallbackBase& other) const; |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 86 | |
| 87 | // Allow initializing of |bind_state_| via the constructor to avoid default |
| 88 | // initialization of the scoped_refptr. We do not also initialize |
| 89 | // |polymorphic_invoke_| here because doing a normal assignment in the |
| 90 | // derived Callback templates makes for much nicer compiler errors. |
| 91 | explicit CallbackBase(BindStateBase* bind_state); |
| 92 | |
| 93 | // Force the destructor to be instantiated inside this translation unit so |
| 94 | // that our subclasses will not get inlined versions. Avoids more template |
| 95 | // bloat. |
| 96 | ~CallbackBase(); |
| 97 | |
| 98 | scoped_refptr<BindStateBase> bind_state_; |
Alex Vakulenko | bf79a9e | 2016-03-28 15:11:43 -0700 | [diff] [blame] | 99 | InvokeFuncStorage polymorphic_invoke_ = nullptr; |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 100 | }; |
| 101 | |
Alex Vakulenko | bf79a9e | 2016-03-28 15:11:43 -0700 | [diff] [blame] | 102 | // CallbackBase<Copyable> is a direct base class of Copyable Callbacks. |
| 103 | template <> |
| 104 | class BASE_EXPORT CallbackBase<CopyMode::Copyable> |
| 105 | : public CallbackBase<CopyMode::MoveOnly> { |
| 106 | public: |
| 107 | CallbackBase(const CallbackBase& c); |
| 108 | CallbackBase(CallbackBase&& c); |
| 109 | CallbackBase& operator=(const CallbackBase& c); |
| 110 | CallbackBase& operator=(CallbackBase&& c); |
| 111 | protected: |
| 112 | explicit CallbackBase(BindStateBase* bind_state) |
| 113 | : CallbackBase<CopyMode::MoveOnly>(bind_state) {} |
| 114 | ~CallbackBase() {} |
| 115 | }; |
| 116 | |
| 117 | extern template class CallbackBase<CopyMode::MoveOnly>; |
| 118 | extern template class CallbackBase<CopyMode::Copyable>; |
| 119 | |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 120 | // A helper template to determine if given type is non-const move-only-type, |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 121 | // i.e. if a value of the given type should be passed via std::move() in a |
| 122 | // destructive way. Types are considered to be move-only if they have a |
| 123 | // sentinel MoveOnlyTypeForCPP03 member: a class typically gets this from using |
| 124 | // the DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND macro. |
| 125 | // It would be easy to generalize this trait to all move-only types... but this |
| 126 | // confuses template deduction in VS2013 with certain types such as |
| 127 | // std::unique_ptr. |
| 128 | // TODO(dcheng): Revisit this when Windows switches to VS2015 by default. |
Alex Vakulenko | bf79a9e | 2016-03-28 15:11:43 -0700 | [diff] [blame] | 129 | |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 130 | template <typename T> struct IsMoveOnlyType { |
Alex Vakulenko | bf79a9e | 2016-03-28 15:11:43 -0700 | [diff] [blame] | 131 | // Types YesType and NoType are guaranteed such that sizeof(YesType) < |
| 132 | // sizeof(NoType). |
| 133 | using YesType = char; |
| 134 | struct NoType { YesType dummy[2]; }; |
| 135 | |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 136 | template <typename U> |
| 137 | static YesType Test(const typename U::MoveOnlyTypeForCPP03*); |
| 138 | |
| 139 | template <typename U> |
| 140 | static NoType Test(...); |
| 141 | |
| 142 | static const bool value = sizeof((Test<T>(0))) == sizeof(YesType) && |
Vitaly Buka | 8750b27 | 2015-08-18 18:39:08 -0700 | [diff] [blame] | 143 | !std::is_const<T>::value; |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 144 | }; |
| 145 | |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 146 | // Specialization of IsMoveOnlyType so that std::unique_ptr is still considered |
| 147 | // move-only, even without the sentinel member. |
Alex Vakulenko | bf79a9e | 2016-03-28 15:11:43 -0700 | [diff] [blame] | 148 | template <typename T, typename D> |
| 149 | struct IsMoveOnlyType<std::unique_ptr<T, D>> : std::true_type {}; |
| 150 | |
| 151 | // Specialization of std::vector, so that it's considered move-only if the |
| 152 | // element type is move-only. Allocator is explicitly ignored when determining |
| 153 | // move-only status of the std::vector. |
| 154 | template <typename T, typename Allocator> |
| 155 | struct IsMoveOnlyType<std::vector<T, Allocator>> : IsMoveOnlyType<T> {}; |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 156 | |
| 157 | template <typename> |
| 158 | struct CallbackParamTraitsForMoveOnlyType; |
| 159 | |
| 160 | template <typename> |
| 161 | struct CallbackParamTraitsForNonMoveOnlyType; |
| 162 | |
| 163 | // TODO(tzik): Use a default parameter once MSVS supports variadic templates |
| 164 | // with default values. |
| 165 | // http://connect.microsoft.com/VisualStudio/feedbackdetail/view/957801/compilation-error-with-variadic-templates |
| 166 | // |
| 167 | // This is a typetraits object that's used to take an argument type, and |
Alex Vakulenko | bf79a9e | 2016-03-28 15:11:43 -0700 | [diff] [blame] | 168 | // extract a suitable type for forwarding arguments. |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 169 | template <typename T> |
| 170 | struct CallbackParamTraits |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 171 | : std::conditional<IsMoveOnlyType<T>::value, |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 172 | CallbackParamTraitsForMoveOnlyType<T>, |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 173 | CallbackParamTraitsForNonMoveOnlyType<T>>::type { |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 174 | }; |
| 175 | |
| 176 | template <typename T> |
| 177 | struct CallbackParamTraitsForNonMoveOnlyType { |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 178 | using ForwardType = const T&; |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 179 | }; |
| 180 | |
| 181 | // Note that for array types, we implicitly add a const in the conversion. This |
| 182 | // means that it is not possible to bind array arguments to functions that take |
| 183 | // a non-const pointer. Trying to specialize the template based on a "const |
| 184 | // T[n]" does not seem to match correctly, so we are stuck with this |
| 185 | // restriction. |
| 186 | template <typename T, size_t n> |
| 187 | struct CallbackParamTraitsForNonMoveOnlyType<T[n]> { |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 188 | using ForwardType = const T*; |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 189 | }; |
| 190 | |
| 191 | // See comment for CallbackParamTraits<T[n]>. |
| 192 | template <typename T> |
| 193 | struct CallbackParamTraitsForNonMoveOnlyType<T[]> { |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 194 | using ForwardType = const T*; |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 195 | }; |
| 196 | |
| 197 | // Parameter traits for movable-but-not-copyable scopers. |
| 198 | // |
| 199 | // Callback<>/Bind() understands movable-but-not-copyable semantics where |
| 200 | // the type cannot be copied but can still have its state destructively |
| 201 | // transferred (aka. moved) to another instance of the same type by calling a |
| 202 | // helper function. When used with Bind(), this signifies transferal of the |
| 203 | // object's state to the target function. |
| 204 | // |
| 205 | // For these types, the ForwardType must not be a const reference, or a |
| 206 | // reference. A const reference is inappropriate, and would break const |
| 207 | // correctness, because we are implementing a destructive move. A non-const |
| 208 | // reference cannot be used with temporaries which means the result of a |
| 209 | // function or a cast would not be usable with Callback<> or Bind(). |
| 210 | template <typename T> |
| 211 | struct CallbackParamTraitsForMoveOnlyType { |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 212 | using ForwardType = T; |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 213 | }; |
| 214 | |
| 215 | // CallbackForward() is a very limited simulation of C++11's std::forward() |
| 216 | // used by the Callback/Bind system for a set of movable-but-not-copyable |
| 217 | // types. It is needed because forwarding a movable-but-not-copyable |
| 218 | // argument to another function requires us to invoke the proper move |
| 219 | // operator to create a rvalue version of the type. The supported types are |
| 220 | // whitelisted below as overloads of the CallbackForward() function. The |
| 221 | // default template compiles out to be a no-op. |
| 222 | // |
| 223 | // In C++11, std::forward would replace all uses of this function. However, it |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 224 | // is impossible to implement a general std::forward without C++11 due to a lack |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 225 | // of rvalue references. |
| 226 | // |
| 227 | // In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to |
| 228 | // simulate std::forward() and forward the result of one Callback as a |
| 229 | // parameter to another callback. This is to support Callbacks that return |
| 230 | // the movable-but-not-copyable types whitelisted above. |
| 231 | template <typename T> |
Vitaly Buka | 8750b27 | 2015-08-18 18:39:08 -0700 | [diff] [blame] | 232 | typename std::enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward( |
| 233 | T& t) { |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 234 | return t; |
| 235 | } |
| 236 | |
| 237 | template <typename T> |
Vitaly Buka | 8750b27 | 2015-08-18 18:39:08 -0700 | [diff] [blame] | 238 | typename std::enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward( |
| 239 | T& t) { |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 240 | return std::move(t); |
| 241 | } |
| 242 | |
| 243 | } // namespace internal |
| 244 | } // namespace base |
| 245 | |
| 246 | #endif // BASE_CALLBACK_INTERNAL_H_ |