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> |
| 14 | #include <vector> |
| 15 | |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 16 | #include "base/base_export.h" |
| 17 | #include "base/macros.h" |
| 18 | #include "base/memory/ref_counted.h" |
| 19 | #include "base/memory/scoped_ptr.h" |
| 20 | #include "base/template_util.h" |
| 21 | |
| 22 | template <typename T> |
| 23 | class ScopedVector; |
| 24 | |
| 25 | namespace base { |
| 26 | namespace internal { |
| 27 | class CallbackBase; |
| 28 | |
| 29 | // BindStateBase is used to provide an opaque handle that the Callback |
| 30 | // class can use to represent a function object with bound arguments. It |
| 31 | // behaves as an existential type that is used by a corresponding |
| 32 | // DoInvoke function to perform the function execution. This allows |
| 33 | // us to shield the Callback class from the types of the bound argument via |
| 34 | // "type erasure." |
| 35 | // At the base level, the only task is to add reference counting data. Don't use |
| 36 | // RefCountedThreadSafe since it requires the destructor to be a virtual method. |
| 37 | // Creating a vtable for every BindState template instantiation results in a lot |
| 38 | // of bloat. Its only task is to call the destructor which can be done with a |
| 39 | // function pointer. |
| 40 | class BindStateBase { |
| 41 | protected: |
| 42 | explicit BindStateBase(void (*destructor)(BindStateBase*)) |
| 43 | : ref_count_(0), destructor_(destructor) {} |
| 44 | ~BindStateBase() = default; |
| 45 | |
| 46 | private: |
| 47 | friend class scoped_refptr<BindStateBase>; |
| 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. |
| 63 | class BASE_EXPORT CallbackBase { |
| 64 | public: |
| 65 | CallbackBase(const CallbackBase& c); |
| 66 | CallbackBase& operator=(const CallbackBase& c); |
| 67 | |
| 68 | // Returns true if Callback is null (doesn't refer to anything). |
| 69 | bool is_null() const { return bind_state_.get() == NULL; } |
| 70 | |
| 71 | // Returns the Callback into an uninitialized state. |
| 72 | void Reset(); |
| 73 | |
| 74 | protected: |
| 75 | // In C++, it is safe to cast function pointers to function pointers of |
| 76 | // another type. It is not okay to use void*. We create a InvokeFuncStorage |
| 77 | // that that can store our function pointer, and then cast it back to |
| 78 | // the original type on usage. |
| 79 | typedef void(*InvokeFuncStorage)(void); |
| 80 | |
| 81 | // Returns true if this callback equals |other|. |other| may be null. |
| 82 | bool Equals(const CallbackBase& other) const; |
| 83 | |
| 84 | // Allow initializing of |bind_state_| via the constructor to avoid default |
| 85 | // initialization of the scoped_refptr. We do not also initialize |
| 86 | // |polymorphic_invoke_| here because doing a normal assignment in the |
| 87 | // derived Callback templates makes for much nicer compiler errors. |
| 88 | explicit CallbackBase(BindStateBase* bind_state); |
| 89 | |
| 90 | // Force the destructor to be instantiated inside this translation unit so |
| 91 | // that our subclasses will not get inlined versions. Avoids more template |
| 92 | // bloat. |
| 93 | ~CallbackBase(); |
| 94 | |
| 95 | scoped_refptr<BindStateBase> bind_state_; |
| 96 | InvokeFuncStorage polymorphic_invoke_; |
| 97 | }; |
| 98 | |
| 99 | // A helper template to determine if given type is non-const move-only-type, |
| 100 | // i.e. if a value of the given type should be passed via .Pass() in a |
| 101 | // destructive way. |
| 102 | template <typename T> struct IsMoveOnlyType { |
| 103 | template <typename U> |
| 104 | static YesType Test(const typename U::MoveOnlyTypeForCPP03*); |
| 105 | |
| 106 | template <typename U> |
| 107 | static NoType Test(...); |
| 108 | |
| 109 | static const bool value = sizeof((Test<T>(0))) == sizeof(YesType) && |
Vitaly Buka | 8750b27 | 2015-08-18 18:39:08 -0700 | [diff] [blame] | 110 | !std::is_const<T>::value; |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 111 | }; |
| 112 | |
| 113 | // Mark std::unique_ptr<T> and common containers using unique_ptr as MoveOnly |
| 114 | // type for base::Callback, so it is stored by value and not a const reference |
| 115 | // inside Callback. |
| 116 | template<typename T, typename D> |
| 117 | struct IsMoveOnlyType<std::unique_ptr<T, D>> : public std::true_type {}; |
| 118 | |
| 119 | template<typename T, typename D, typename A> |
| 120 | struct IsMoveOnlyType<std::vector<std::unique_ptr<T, D>, A>> |
| 121 | : public std::true_type {}; |
| 122 | |
| 123 | template<typename K, typename T, typename D, typename C, typename A> |
| 124 | struct IsMoveOnlyType<std::map<K, std::unique_ptr<T, D>, C, A>> |
| 125 | : public std::true_type {}; |
| 126 | |
| 127 | // Returns |Then| as SelectType::Type if |condition| is true. Otherwise returns |
| 128 | // |Else|. |
| 129 | template <bool condition, typename Then, typename Else> |
| 130 | struct SelectType { |
| 131 | typedef Then Type; |
| 132 | }; |
| 133 | |
| 134 | template <typename Then, typename Else> |
| 135 | struct SelectType<false, Then, Else> { |
| 136 | typedef Else Type; |
| 137 | }; |
| 138 | |
| 139 | template <typename> |
| 140 | struct CallbackParamTraitsForMoveOnlyType; |
| 141 | |
| 142 | template <typename> |
| 143 | struct CallbackParamTraitsForNonMoveOnlyType; |
| 144 | |
| 145 | // TODO(tzik): Use a default parameter once MSVS supports variadic templates |
| 146 | // with default values. |
| 147 | // http://connect.microsoft.com/VisualStudio/feedbackdetail/view/957801/compilation-error-with-variadic-templates |
| 148 | // |
| 149 | // This is a typetraits object that's used to take an argument type, and |
| 150 | // extract a suitable type for storing and forwarding arguments. |
| 151 | // |
| 152 | // In particular, it strips off references, and converts arrays to |
| 153 | // pointers for storage; and it avoids accidentally trying to create a |
| 154 | // "reference of a reference" if the argument is a reference type. |
| 155 | // |
| 156 | // This array type becomes an issue for storage because we are passing bound |
| 157 | // parameters by const reference. In this case, we end up passing an actual |
| 158 | // array type in the initializer list which C++ does not allow. This will |
| 159 | // break passing of C-string literals. |
| 160 | template <typename T> |
| 161 | struct CallbackParamTraits |
| 162 | : SelectType<IsMoveOnlyType<T>::value, |
| 163 | CallbackParamTraitsForMoveOnlyType<T>, |
| 164 | CallbackParamTraitsForNonMoveOnlyType<T> >::Type { |
| 165 | }; |
| 166 | |
| 167 | template <typename T> |
| 168 | struct CallbackParamTraitsForNonMoveOnlyType { |
| 169 | typedef const T& ForwardType; |
| 170 | typedef T StorageType; |
| 171 | }; |
| 172 | |
| 173 | // The Storage should almost be impossible to trigger unless someone manually |
| 174 | // specifies type of the bind parameters. However, in case they do, |
| 175 | // this will guard against us accidentally storing a reference parameter. |
| 176 | // |
| 177 | // The ForwardType should only be used for unbound arguments. |
| 178 | template <typename T> |
| 179 | struct CallbackParamTraitsForNonMoveOnlyType<T&> { |
| 180 | typedef T& ForwardType; |
| 181 | typedef T StorageType; |
| 182 | }; |
| 183 | |
| 184 | // Note that for array types, we implicitly add a const in the conversion. This |
| 185 | // means that it is not possible to bind array arguments to functions that take |
| 186 | // a non-const pointer. Trying to specialize the template based on a "const |
| 187 | // T[n]" does not seem to match correctly, so we are stuck with this |
| 188 | // restriction. |
| 189 | template <typename T, size_t n> |
| 190 | struct CallbackParamTraitsForNonMoveOnlyType<T[n]> { |
| 191 | typedef const T* ForwardType; |
| 192 | typedef const T* StorageType; |
| 193 | }; |
| 194 | |
| 195 | // See comment for CallbackParamTraits<T[n]>. |
| 196 | template <typename T> |
| 197 | struct CallbackParamTraitsForNonMoveOnlyType<T[]> { |
| 198 | typedef const T* ForwardType; |
| 199 | typedef const T* StorageType; |
| 200 | }; |
| 201 | |
| 202 | // Parameter traits for movable-but-not-copyable scopers. |
| 203 | // |
| 204 | // Callback<>/Bind() understands movable-but-not-copyable semantics where |
| 205 | // the type cannot be copied but can still have its state destructively |
| 206 | // transferred (aka. moved) to another instance of the same type by calling a |
| 207 | // helper function. When used with Bind(), this signifies transferal of the |
| 208 | // object's state to the target function. |
| 209 | // |
| 210 | // For these types, the ForwardType must not be a const reference, or a |
| 211 | // reference. A const reference is inappropriate, and would break const |
| 212 | // correctness, because we are implementing a destructive move. A non-const |
| 213 | // reference cannot be used with temporaries which means the result of a |
| 214 | // function or a cast would not be usable with Callback<> or Bind(). |
| 215 | template <typename T> |
| 216 | struct CallbackParamTraitsForMoveOnlyType { |
| 217 | typedef T ForwardType; |
| 218 | typedef T StorageType; |
| 219 | }; |
| 220 | |
| 221 | // CallbackForward() is a very limited simulation of C++11's std::forward() |
| 222 | // used by the Callback/Bind system for a set of movable-but-not-copyable |
| 223 | // types. It is needed because forwarding a movable-but-not-copyable |
| 224 | // argument to another function requires us to invoke the proper move |
| 225 | // operator to create a rvalue version of the type. The supported types are |
| 226 | // whitelisted below as overloads of the CallbackForward() function. The |
| 227 | // default template compiles out to be a no-op. |
| 228 | // |
| 229 | // In C++11, std::forward would replace all uses of this function. However, it |
| 230 | // is impossible to implement a general std::forward with C++11 due to a lack |
| 231 | // of rvalue references. |
| 232 | // |
| 233 | // In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to |
| 234 | // simulate std::forward() and forward the result of one Callback as a |
| 235 | // parameter to another callback. This is to support Callbacks that return |
| 236 | // the movable-but-not-copyable types whitelisted above. |
| 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 t; |
| 241 | } |
| 242 | |
| 243 | template <typename T> |
Vitaly Buka | 8750b27 | 2015-08-18 18:39:08 -0700 | [diff] [blame] | 244 | typename std::enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward( |
| 245 | T& t) { |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 246 | return t.Pass(); |
| 247 | } |
| 248 | |
| 249 | // Overload base::internal::CallbackForward() to forward unique_ptr and common |
| 250 | // containers with unique_ptr by using std::move instead of default T::Pass() |
| 251 | // used with scoped_ptr<U>. |
| 252 | template <typename T, typename D> |
| 253 | std::unique_ptr<T, D> CallbackForward(std::unique_ptr<T, D>& t) { |
| 254 | return std::move(t); |
| 255 | } |
| 256 | |
| 257 | template <typename T, typename D, typename A> |
| 258 | std::vector<std::unique_ptr<T, D>, A> |
| 259 | CallbackForward(std::vector<std::unique_ptr<T, D>, A>& t) { |
| 260 | return std::move(t); |
| 261 | } |
| 262 | |
| 263 | template <typename K, typename T, typename D, typename C, typename A> |
| 264 | std::map<K, std::unique_ptr<T, D>, C, A> |
| 265 | CallbackForward(std::map<K, std::unique_ptr<T, D>, C, A>& t) { |
| 266 | return std::move(t); |
| 267 | } |
| 268 | |
| 269 | } // namespace internal |
| 270 | } // namespace base |
| 271 | |
| 272 | #endif // BASE_CALLBACK_INTERNAL_H_ |