1 // Copyright (c) 2011 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 #pragma once 11 12 #include <stddef.h> 13 14 #include "base/base_api.h" 15 #include "base/memory/ref_counted.h" 16 17 namespace base { 18 namespace internal { 19 20 // InvokerStorageBase is used to provide an opaque handle that the Callback 21 // class can use to represent a function object with bound arguments. It 22 // behaves as an existential type that is used by a corresponding 23 // DoInvoke function to perform the function execution. This allows 24 // us to shield the Callback class from the types of the bound argument via 25 // "type erasure." 26 class InvokerStorageBase : public RefCountedThreadSafe<InvokerStorageBase> { 27 protected: 28 friend class RefCountedThreadSafe<InvokerStorageBase>; 29 virtual ~InvokerStorageBase() {} 30 }; 31 32 // This structure exists purely to pass the returned |invoker_storage_| from 33 // Bind() to Callback while avoiding an extra AddRef/Release() pair. 34 // 35 // To do this, the constructor of Callback<> must take a const-ref. The 36 // reference must be to a const object otherwise the compiler will emit a 37 // warning about taking a reference to a temporary. 38 // 39 // Unfortunately, this means that the internal |invoker_storage_| field must 40 // be made mutable. 41 template <typename T> 42 struct InvokerStorageHolder { 43 explicit InvokerStorageHolder(T* invoker_storage) 44 : invoker_storage_(invoker_storage) { 45 } 46 47 mutable scoped_refptr<InvokerStorageBase> invoker_storage_; 48 }; 49 50 template <typename T> 51 InvokerStorageHolder<T> MakeInvokerStorageHolder(T* o) { 52 return InvokerStorageHolder<T>(o); 53 } 54 55 // Holds the Callback methods that don't require specialization to reduce 56 // template bloat. 57 class BASE_API CallbackBase { 58 public: 59 // Returns true if Callback is null (doesn't refer to anything). 60 bool is_null() const; 61 62 // Returns the Callback into an uninitalized state. 63 void Reset(); 64 65 bool Equals(const CallbackBase& other) const; 66 67 protected: 68 // In C++, it is safe to cast function pointers to function pointers of 69 // another type. It is not okay to use void*. We create a InvokeFuncStorage 70 // that that can store our function pointer, and then cast it back to 71 // the original type on usage. 72 typedef void(*InvokeFuncStorage)(void); 73 74 CallbackBase(InvokeFuncStorage polymorphic_invoke, 75 scoped_refptr<InvokerStorageBase>* invoker_storage); 76 77 // Force the destructor to be instaniated inside this translation unit so 78 // that our subclasses will not get inlined versions. Avoids more template 79 // bloat. 80 ~CallbackBase(); 81 82 scoped_refptr<InvokerStorageBase> invoker_storage_; 83 InvokeFuncStorage polymorphic_invoke_; 84 }; 85 86 // This is a typetraits object that's used to take an argument type, and 87 // extract a suitable type for storing and forwarding arguments. 88 // 89 // In particular, it strips off references, and converts arrays to 90 // pointers for storage; and it avoids accidentally trying to create a 91 // "reference of a reference" if the argument is a reference type. 92 // 93 // This array type becomes an issue for storage because we are passing bound 94 // parameters by const reference. In this case, we end up passing an actual 95 // array type in the initializer list which C++ does not allow. This will 96 // break passing of C-string literals. 97 template <typename T> 98 struct ParamTraits { 99 typedef const T& ForwardType; 100 typedef T StorageType; 101 }; 102 103 // The Storage should almost be impossible to trigger unless someone manually 104 // specifies type of the bind parameters. However, in case they do, 105 // this will guard against us accidentally storing a reference parameter. 106 // 107 // The ForwardType should only be used for unbound arguments. 108 template <typename T> 109 struct ParamTraits<T&> { 110 typedef T& ForwardType; 111 typedef T StorageType; 112 }; 113 114 // Note that for array types, we implicitly add a const in the conversion. This 115 // means that it is not possible to bind array arguments to functions that take 116 // a non-const pointer. Trying to specialize the template based on a "const 117 // T[n]" does not seem to match correctly, so we are stuck with this 118 // restriction. 119 template <typename T, size_t n> 120 struct ParamTraits<T[n]> { 121 typedef const T* ForwardType; 122 typedef const T* StorageType; 123 }; 124 125 // See comment for ParamTraits<T[n]>. 126 template <typename T> 127 struct ParamTraits<T[]> { 128 typedef const T* ForwardType; 129 typedef const T* StorageType; 130 }; 131 132 } // namespace internal 133 } // namespace base 134 135 #endif // BASE_CALLBACK_INTERNAL_H_ 136