Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 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 | #ifndef BASE_BIND_H_ |
| 6 | #define BASE_BIND_H_ |
| 7 | |
| 8 | #include "base/bind_internal.h" |
| 9 | #include "base/callback_internal.h" |
| 10 | |
| 11 | // ----------------------------------------------------------------------------- |
| 12 | // Usage documentation |
| 13 | // ----------------------------------------------------------------------------- |
| 14 | // |
| 15 | // See base/callback.h for documentation. |
| 16 | // |
| 17 | // |
| 18 | // ----------------------------------------------------------------------------- |
| 19 | // Implementation notes |
| 20 | // ----------------------------------------------------------------------------- |
| 21 | // |
| 22 | // If you're reading the implementation, before proceeding further, you should |
| 23 | // read the top comment of base/bind_internal.h for a definition of common |
| 24 | // terms and concepts. |
| 25 | // |
| 26 | // RETURN TYPES |
| 27 | // |
| 28 | // Though Bind()'s result is meant to be stored in a Callback<> type, it |
| 29 | // cannot actually return the exact type without requiring a large amount |
| 30 | // of extra template specializations. The problem is that in order to |
| 31 | // discern the correct specialization of Callback<>, Bind would need to |
| 32 | // unwrap the function signature to determine the signature's arity, and |
| 33 | // whether or not it is a method. |
| 34 | // |
| 35 | // Each unique combination of (arity, function_type, num_prebound) where |
| 36 | // function_type is one of {function, method, const_method} would require |
| 37 | // one specialization. We eventually have to do a similar number of |
| 38 | // specializations anyways in the implementation (see the Invoker<>, |
| 39 | // classes). However, it is avoidable in Bind if we return the result |
| 40 | // via an indirection like we do below. |
| 41 | // |
| 42 | // TODO(ajwong): We might be able to avoid this now, but need to test. |
| 43 | // |
| 44 | // It is possible to move most of the static_assert into BindState<>, but it |
| 45 | // feels a little nicer to have the asserts here so people do not need to crack |
| 46 | // open bind_internal.h. On the other hand, it makes Bind() harder to read. |
| 47 | |
| 48 | namespace base { |
| 49 | |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 50 | template <typename Functor, typename... Args> |
| 51 | base::Callback< |
| 52 | typename internal::BindState< |
| 53 | typename internal::FunctorTraits<Functor>::RunnableType, |
| 54 | typename internal::FunctorTraits<Functor>::RunType, |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 55 | typename internal::CallbackParamTraits<Args>::StorageType...> |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 56 | ::UnboundRunType> |
| 57 | Bind(Functor functor, const Args&... args) { |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 58 | // Type aliases for how to store and run the functor. |
| 59 | using RunnableType = typename internal::FunctorTraits<Functor>::RunnableType; |
| 60 | using RunType = typename internal::FunctorTraits<Functor>::RunType; |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 61 | |
| 62 | // Use RunnableType::RunType instead of RunType above because our |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 63 | // checks below for bound references need to know what the actual |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 64 | // functor is going to interpret the argument as. |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 65 | using BoundRunType = typename RunnableType::RunType; |
| 66 | |
| 67 | using BoundArgs = |
| 68 | internal::TakeTypeListItem<sizeof...(Args), |
| 69 | internal::ExtractArgs<BoundRunType>>; |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 70 | |
| 71 | // Do not allow binding a non-const reference parameter. Non-const reference |
| 72 | // parameters are disallowed by the Google style guide. Also, binding a |
| 73 | // non-const reference parameter can make for subtle bugs because the |
| 74 | // invoked function will receive a reference to the stored copy of the |
| 75 | // argument and not the original. |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 76 | static_assert(!internal::HasNonConstReferenceItem<BoundArgs>::value, |
| 77 | "do not bind functions with nonconst ref"); |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 78 | |
| 79 | const bool is_method = internal::HasIsMethodTag<RunnableType>::value; |
| 80 | |
| 81 | // For methods, we need to be careful for parameter 1. We do not require |
| 82 | // a scoped_refptr because BindState<> itself takes care of AddRef() for |
| 83 | // methods. We also disallow binding of an array as the method's target |
| 84 | // object. |
| 85 | static_assert(!internal::BindsArrayToFirstArg<is_method, Args...>::value, |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 86 | "first bound argument to method cannot be array"); |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 87 | static_assert( |
| 88 | !internal::HasRefCountedParamAsRawPtr<is_method, Args...>::value, |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 89 | "a parameter is a refcounted type and needs scoped_refptr"); |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 90 | |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 91 | using BindState = internal::BindState< |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 92 | RunnableType, RunType, |
Alex Vakulenko | 674f0eb | 2016-01-20 08:10:48 -0800 | [diff] [blame] | 93 | typename internal::CallbackParamTraits<Args>::StorageType...>; |
Vitaly Buka | cbed206 | 2015-08-17 12:54:05 -0700 | [diff] [blame] | 94 | |
| 95 | return Callback<typename BindState::UnboundRunType>( |
| 96 | new BindState(internal::MakeRunnable(functor), args...)); |
| 97 | } |
| 98 | |
| 99 | } // namespace base |
| 100 | |
| 101 | #endif // BASE_BIND_H_ |