blob: 90889d54a965209744d5d91698e9e7bb9a6e11dc [file] [log] [blame]
ajwong@chromium.orge2cca632011-02-15 10:27:38 +09001// 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_INTERNAL_H_
6#define BASE_BIND_INTERNAL_H_
ajwong@chromium.orge2cca632011-02-15 10:27:38 +09007
avia6a6a682015-12-27 07:15:14 +09008#include <stddef.h>
9
vmpstr495da402015-11-18 17:43:26 +090010#include <type_traits>
11
ajwong@chromium.orge2cca632011-02-15 10:27:38 +090012#include "base/bind_helpers.h"
ajwong@chromium.orgfa0ff432011-02-19 08:29:31 +090013#include "base/callback_internal.h"
ajwong@chromium.org27e56852011-10-01 15:31:41 +090014#include "base/memory/raw_scoped_refptr_mismatch_checker.h"
ajwong@chromium.orgc711b822011-05-17 07:35:14 +090015#include "base/memory/weak_ptr.h"
ajwong@chromium.orge2cca632011-02-15 10:27:38 +090016#include "base/template_util.h"
tzik07e99402015-02-06 04:11:26 +090017#include "base/tuple.h"
ajwong@chromium.orgcb175342011-02-27 10:25:59 +090018#include "build/build_config.h"
19
20#if defined(OS_WIN)
21#include "base/bind_internal_win.h"
22#endif
ajwong@chromium.orge2cca632011-02-15 10:27:38 +090023
24namespace base {
25namespace internal {
26
brettw@chromium.org11e3bfd2012-07-13 05:06:40 +090027// See base/callback.h for user documentation.
28//
29//
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090030// CONCEPTS:
31// Runnable -- A type (really a type class) that has a single Run() method
32// and a RunType typedef that corresponds to the type of Run().
33// A Runnable can declare that it should treated like a method
34// call by including a typedef named IsMethod. The value of
35// this typedef is NOT inspected, only the existence. When a
36// Runnable declares itself a method, Bind() will enforce special
37// refcounting + WeakPtr handling semantics for the first
38// parameter which is expected to be an object.
39// Functor -- A copyable type representing something that should be called.
40// All function pointers, Callback<>, and Runnables are functors
41// even if the invocation syntax differs.
42// RunType -- A function type (as opposed to function _pointer_ type) for
43// a Run() function. Usually just a convenience typedef.
tzikb0632222015-12-15 15:41:49 +090044// (Bound)Args -- A set of types that stores the arguments.
ajwong@chromium.orge2cca632011-02-15 10:27:38 +090045//
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090046// Types:
47// RunnableAdapter<> -- Wraps the various "function" pointer types into an
48// object that adheres to the Runnable interface.
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090049// ForceVoidReturn<> -- Helper class for translating function signatures to
50// equivalent forms with a "void" return type.
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090051// FunctorTraits<> -- Type traits used determine the correct RunType and
52// RunnableType for a Functor. This is where function
53// signature adapters are applied.
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090054// MakeRunnable<> -- Takes a Functor and returns an object in the Runnable
55// type class that represents the underlying Functor.
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090056// InvokeHelper<> -- Take a Runnable + arguments and actully invokes it.
tzik07e99402015-02-06 04:11:26 +090057// Handle the differing syntaxes needed for WeakPtr<>
58// support, and for ignoring return values. This is separate
59// from Invoker to avoid creating multiple version of
60// Invoker<>.
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090061// Invoker<> -- Unwraps the curried parameters and executes the Runnable.
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090062// BindState<> -- Stores the curried parameters, and is the main entry point
63// into the Bind() system, doing most of the type resolution.
64// There are ARITY BindState types.
ajwong@chromium.orge0648232011-02-19 09:52:15 +090065
tzik8df08a52014-11-26 16:54:58 +090066// HasNonConstReferenceParam selects true_type when any of the parameters in
67// |Sig| is a non-const reference.
68// Implementation note: This non-specialized case handles zero-arity case only.
69// Non-zero-arity cases should be handled by the specialization below.
tzik5b8bf3f2015-12-18 11:23:26 +090070template <typename List>
71struct HasNonConstReferenceItem : false_type {};
tzik8df08a52014-11-26 16:54:58 +090072
73// Implementation note: Select true_type if the first parameter is a non-const
74// reference. Otherwise, skip the first parameter and check rest of parameters
75// recursively.
tzik5b8bf3f2015-12-18 11:23:26 +090076template <typename T, typename... Args>
77struct HasNonConstReferenceItem<TypeList<T, Args...>>
vmpstr495da402015-11-18 17:43:26 +090078 : std::conditional<is_non_const_reference<T>::value,
79 true_type,
tzik5b8bf3f2015-12-18 11:23:26 +090080 HasNonConstReferenceItem<TypeList<Args...>>>::type {};
tzik8df08a52014-11-26 16:54:58 +090081
82// HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw
83// pointer to a RefCounted type.
84// Implementation note: This non-specialized case handles zero-arity case only.
85// Non-zero-arity cases should be handled by the specialization below.
86template <typename... Args>
87struct HasRefCountedTypeAsRawPtr : false_type {};
88
89// Implementation note: Select true_type if the first parameter is a raw pointer
90// to a RefCounted type. Otherwise, skip the first parameter and check rest of
91// parameters recursively.
92template <typename T, typename... Args>
93struct HasRefCountedTypeAsRawPtr<T, Args...>
vmpstr495da402015-11-18 17:43:26 +090094 : std::conditional<NeedsScopedRefptrButGetsRawPtr<T>::value,
95 true_type,
96 HasRefCountedTypeAsRawPtr<Args...>>::type {};
tzik8df08a52014-11-26 16:54:58 +090097
98// BindsArrayToFirstArg selects true_type when |is_method| is true and the first
99// item of |Args| is an array type.
100// Implementation note: This non-specialized case handles !is_method case and
101// zero-arity case only. Other cases should be handled by the specialization
102// below.
103template <bool is_method, typename... Args>
104struct BindsArrayToFirstArg : false_type {};
105
106template <typename T, typename... Args>
tzik56453de2016-02-03 13:42:30 +0900107struct BindsArrayToFirstArg<true, T, Args...>
108 : is_array<typename std::remove_reference<T>::type> {};
tzik8df08a52014-11-26 16:54:58 +0900109
110// HasRefCountedParamAsRawPtr is the same to HasRefCountedTypeAsRawPtr except
111// when |is_method| is true HasRefCountedParamAsRawPtr skips the first argument.
112// Implementation note: This non-specialized case handles !is_method case and
113// zero-arity case only. Other cases should be handled by the specialization
114// below.
115template <bool is_method, typename... Args>
116struct HasRefCountedParamAsRawPtr : HasRefCountedTypeAsRawPtr<Args...> {};
117
118template <typename T, typename... Args>
119struct HasRefCountedParamAsRawPtr<true, T, Args...>
120 : HasRefCountedTypeAsRawPtr<Args...> {};
121
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900122// RunnableAdapter<>
123//
124// The RunnableAdapter<> templates provide a uniform interface for invoking
125// a function pointer, method pointer, or const method pointer. The adapter
126// exposes a Run() method with an appropriate signature. Using this wrapper
127// allows for writing code that supports all three pointer types without
128// undue repetition. Without it, a lot of code would need to be repeated 3
129// times.
130//
131// For method pointers and const method pointers the first argument to Run()
132// is considered to be the received of the method. This is similar to STL's
133// mem_fun().
134//
135// This class also exposes a RunType typedef that is the function type of the
136// Run() function.
137//
138// If and only if the wrapper contains a method or const method pointer, an
139// IsMethod typedef is exposed. The existence of this typedef (NOT the value)
140// marks that the wrapper should be considered a method wrapper.
ajwong@chromium.orgc711b822011-05-17 07:35:14 +0900141
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900142template <typename Functor>
143class RunnableAdapter;
ajwong@chromium.orge0648232011-02-19 09:52:15 +0900144
tzik012481a2014-11-20 19:09:45 +0900145// Function.
146template <typename R, typename... Args>
147class RunnableAdapter<R(*)(Args...)> {
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900148 public:
tzik260fab52015-12-19 18:18:46 +0900149 // MSVC 2013 doesn't support Type Alias of function types.
150 // Revisit this after we update it to newer version.
151 typedef R RunType(Args...);
ajwong@chromium.orga7e74822011-03-24 11:02:17 +0900152
tzik012481a2014-11-20 19:09:45 +0900153 explicit RunnableAdapter(R(*function)(Args...))
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900154 : function_(function) {
155 }
ajwong@chromium.orgc711b822011-05-17 07:35:14 +0900156
tzik4b1cea42016-02-16 05:51:34 +0900157 template <typename... RunArgs>
158 R Run(RunArgs&&... args) {
159 return function_(std::forward<RunArgs>(args)...);
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900160 }
161
162 private:
tzik012481a2014-11-20 19:09:45 +0900163 R (*function_)(Args...);
ajwong@chromium.orge0648232011-02-19 09:52:15 +0900164};
165
tzik012481a2014-11-20 19:09:45 +0900166// Method.
167template <typename R, typename T, typename... Args>
168class RunnableAdapter<R(T::*)(Args...)> {
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900169 public:
tzik260fab52015-12-19 18:18:46 +0900170 // MSVC 2013 doesn't support Type Alias of function types.
171 // Revisit this after we update it to newer version.
172 typedef R RunType(T*, Args...);
173 using IsMethod = true_type;
ajwong@chromium.orga7e74822011-03-24 11:02:17 +0900174
tzik012481a2014-11-20 19:09:45 +0900175 explicit RunnableAdapter(R(T::*method)(Args...))
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900176 : method_(method) {
177 }
ajwong@chromium.orgc711b822011-05-17 07:35:14 +0900178
tzik4b1cea42016-02-16 05:51:34 +0900179 template <typename... RunArgs>
180 R Run(T* object, RunArgs&&... args) {
181 return (object->*method_)(std::forward<RunArgs>(args)...);
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900182 }
ajwong@chromium.orga7e74822011-03-24 11:02:17 +0900183
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900184 private:
tzik012481a2014-11-20 19:09:45 +0900185 R (T::*method_)(Args...);
ajwong@chromium.orge0648232011-02-19 09:52:15 +0900186};
187
tzik012481a2014-11-20 19:09:45 +0900188// Const Method.
189template <typename R, typename T, typename... Args>
190class RunnableAdapter<R(T::*)(Args...) const> {
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900191 public:
tzik260fab52015-12-19 18:18:46 +0900192 using RunType = R(const T*, Args...);
193 using IsMethod = true_type;
ajwong@chromium.orga7e74822011-03-24 11:02:17 +0900194
tzik012481a2014-11-20 19:09:45 +0900195 explicit RunnableAdapter(R(T::*method)(Args...) const)
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900196 : method_(method) {
197 }
ajwong@chromium.orgc711b822011-05-17 07:35:14 +0900198
tzik4b1cea42016-02-16 05:51:34 +0900199 template <typename... RunArgs>
200 R Run(const T* object, RunArgs&&... args) {
201 return (object->*method_)(std::forward<RunArgs>(args)...);
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900202 }
ajwong@chromium.orga7e74822011-03-24 11:02:17 +0900203
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900204 private:
tzik012481a2014-11-20 19:09:45 +0900205 R (T::*method_)(Args...) const;
ajwong@chromium.orge0648232011-02-19 09:52:15 +0900206};
207
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900208
209// ForceVoidReturn<>
210//
211// Set of templates that support forcing the function return type to void.
212template <typename Sig>
213struct ForceVoidReturn;
214
tzik012481a2014-11-20 19:09:45 +0900215template <typename R, typename... Args>
216struct ForceVoidReturn<R(Args...)> {
tzik260fab52015-12-19 18:18:46 +0900217 // MSVC 2013 doesn't support Type Alias of function types.
218 // Revisit this after we update it to newer version.
219 typedef void RunType(Args...);
ajwong@chromium.org6f015bd2011-11-29 07:13:54 +0900220};
221
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900222
223// FunctorTraits<>
224//
225// See description at top of file.
226template <typename T>
227struct FunctorTraits {
tzik260fab52015-12-19 18:18:46 +0900228 using RunnableType = RunnableAdapter<T>;
229 using RunType = typename RunnableType::RunType;
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900230};
231
232template <typename T>
tzik07e99402015-02-06 04:11:26 +0900233struct FunctorTraits<IgnoreResultHelper<T>> {
tzik260fab52015-12-19 18:18:46 +0900234 using RunnableType = typename FunctorTraits<T>::RunnableType;
235 using RunType =
236 typename ForceVoidReturn<typename RunnableType::RunType>::RunType;
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900237};
238
239template <typename T>
tzik07e99402015-02-06 04:11:26 +0900240struct FunctorTraits<Callback<T>> {
tzik260fab52015-12-19 18:18:46 +0900241 using RunnableType = Callback<T> ;
242 using RunType = typename Callback<T>::RunType;
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900243};
244
245
246// MakeRunnable<>
247//
248// Converts a passed in functor to a RunnableType using type inference.
249
250template <typename T>
251typename FunctorTraits<T>::RunnableType MakeRunnable(const T& t) {
252 return RunnableAdapter<T>(t);
253}
254
255template <typename T>
256typename FunctorTraits<T>::RunnableType
257MakeRunnable(const IgnoreResultHelper<T>& t) {
258 return MakeRunnable(t.functor_);
259}
260
261template <typename T>
tzik07e99402015-02-06 04:11:26 +0900262const typename FunctorTraits<Callback<T>>::RunnableType&
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900263MakeRunnable(const Callback<T>& t) {
hashimoto@chromium.orgbc14c572012-11-20 17:28:14 +0900264 DCHECK(!t.is_null());
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900265 return t;
266}
267
268
269// InvokeHelper<>
270//
271// There are 3 logical InvokeHelper<> specializations: normal, void-return,
272// WeakCalls.
273//
274// The normal type just calls the underlying runnable.
275//
276// We need a InvokeHelper to handle void return types in order to support
277// IgnoreResult(). Normally, if the Runnable's RunType had a void return,
278// the template system would just accept "return functor.Run()" ignoring
279// the fact that a void function is being used with return. This piece of
280// sugar breaks though when the Runnable's RunType is not void. Thus, we
281// need a partial specialization to change the syntax to drop the "return"
282// from the invocation call.
283//
284// WeakCalls similarly need special syntax that is applied to the first
285// argument to check if they should no-op themselves.
tzik4b1cea42016-02-16 05:51:34 +0900286template <bool IsWeakCall, typename ReturnType, typename Runnable>
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900287struct InvokeHelper;
288
tzik4b1cea42016-02-16 05:51:34 +0900289template <typename ReturnType, typename Runnable>
290struct InvokeHelper<false, ReturnType, Runnable> {
291 template <typename... RunArgs>
292 static ReturnType MakeItSo(Runnable runnable, RunArgs&&... args) {
293 return runnable.Run(std::forward<RunArgs>(args)...);
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900294 }
295};
296
tzik4b1cea42016-02-16 05:51:34 +0900297template <typename Runnable>
298struct InvokeHelper<false, void, Runnable> {
299 template <typename... RunArgs>
300 static void MakeItSo(Runnable runnable, RunArgs&&... args) {
301 runnable.Run(std::forward<RunArgs>(args)...);
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900302 }
303};
304
tzik4b1cea42016-02-16 05:51:34 +0900305template <typename Runnable>
306struct InvokeHelper<true, void, Runnable> {
307 template <typename BoundWeakPtr, typename... RunArgs>
308 static void MakeItSo(Runnable runnable,
309 BoundWeakPtr weak_ptr,
310 RunArgs&&... args) {
akalin@chromium.orgd276ffa2013-06-04 07:15:21 +0900311 if (!weak_ptr.get()) {
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900312 return;
313 }
tzik4b1cea42016-02-16 05:51:34 +0900314 runnable.Run(weak_ptr.get(), std::forward<RunArgs>(args)...);
ajwong@chromium.org6f015bd2011-11-29 07:13:54 +0900315 }
316};
317
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900318#if !defined(_MSC_VER)
319
tzik4b1cea42016-02-16 05:51:34 +0900320template <typename ReturnType, typename Runnable>
321struct InvokeHelper<true, ReturnType, Runnable> {
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900322 // WeakCalls are only supported for functions with a void return type.
323 // Otherwise, the function result would be undefined if the the WeakPtr<>
324 // is invalidated.
avi486c61f2015-11-24 23:26:24 +0900325 static_assert(is_void<ReturnType>::value,
326 "weak_ptrs can only bind to methods without return values");
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900327};
ajwong@chromium.orga7e74822011-03-24 11:02:17 +0900328
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900329#endif
ajwong@chromium.orge2cca632011-02-15 10:27:38 +0900330
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900331// Invoker<>
332//
333// See description at the top of the file.
tzik07e99402015-02-06 04:11:26 +0900334template <typename BoundIndices,
335 typename StorageType, typename Unwrappers,
336 typename InvokeHelperType, typename UnboundForwardRunType>
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900337struct Invoker;
338
tzik07e99402015-02-06 04:11:26 +0900339template <size_t... bound_indices,
340 typename StorageType,
341 typename... Unwrappers,
342 typename InvokeHelperType,
343 typename R,
344 typename... UnboundForwardArgs>
345struct Invoker<IndexSequence<bound_indices...>,
346 StorageType, TypeList<Unwrappers...>,
347 InvokeHelperType, R(UnboundForwardArgs...)> {
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900348 static R Run(BindStateBase* base,
tzik07e99402015-02-06 04:11:26 +0900349 UnboundForwardArgs... unbound_args) {
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900350 StorageType* storage = static_cast<StorageType*>(base);
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900351 // Local references to make debugger stepping easier. If in a debugger,
352 // you really want to warp ahead and step through the
353 // InvokeHelper<>::MakeItSo() call below.
tzik07e99402015-02-06 04:11:26 +0900354 return InvokeHelperType::MakeItSo(
355 storage->runnable_,
356 Unwrappers::Unwrap(get<bound_indices>(storage->bound_args_))...,
357 CallbackForward(unbound_args)...);
ajwong@chromium.org6f015bd2011-11-29 07:13:54 +0900358 }
359};
360
ajwong@chromium.orge2cca632011-02-15 10:27:38 +0900361
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900362// BindState<>
363//
364// This stores all the state passed into Bind() and is also where most
365// of the template resolution magic occurs.
366//
367// Runnable is the functor we are binding arguments to.
368// RunType is type of the Run() function that the Invoker<> should use.
369// Normally, this is the same as the RunType of the Runnable, but it can
370// be different if an adapter like IgnoreResult() has been used.
371//
tzikb0632222015-12-15 15:41:49 +0900372// BoundArgs contains the storage type for all the bound arguments.
373template <typename Runnable, typename RunType, typename... BoundArgs>
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900374struct BindState;
375
tzik07e99402015-02-06 04:11:26 +0900376template <typename Runnable,
tapted9cef4212015-05-14 17:03:32 +0900377 typename R,
378 typename... Args,
tzik07e99402015-02-06 04:11:26 +0900379 typename... BoundArgs>
tzikb0632222015-12-15 15:41:49 +0900380struct BindState<Runnable, R(Args...), BoundArgs...> final
tzik07e99402015-02-06 04:11:26 +0900381 : public BindStateBase {
382 private:
tzikb0632222015-12-15 15:41:49 +0900383 using StorageType = BindState<Runnable, R(Args...), BoundArgs...>;
tzik07e99402015-02-06 04:11:26 +0900384 using RunnableType = Runnable;
385
386 // true_type if Runnable is a method invocation and the first bound argument
387 // is a WeakPtr.
388 using IsWeakCall =
389 IsWeakMethod<HasIsMethodTag<Runnable>::value, BoundArgs...>;
390
391 using BoundIndices = MakeIndexSequence<sizeof...(BoundArgs)>;
392 using Unwrappers = TypeList<UnwrapTraits<BoundArgs>...>;
393 using UnboundForwardArgs = DropTypeListItem<
394 sizeof...(BoundArgs),
395 TypeList<typename CallbackParamTraits<Args>::ForwardType...>>;
396 using UnboundForwardRunType = MakeFunctionType<R, UnboundForwardArgs>;
tzik4b1cea42016-02-16 05:51:34 +0900397 using InvokeHelperType = InvokeHelper<IsWeakCall::value, R, Runnable>;
tzik07e99402015-02-06 04:11:26 +0900398
399 using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), TypeList<Args...>>;
400
401 public:
402 using InvokerType = Invoker<BoundIndices, StorageType, Unwrappers,
403 InvokeHelperType, UnboundForwardRunType>;
404 using UnboundRunType = MakeFunctionType<R, UnboundArgs>;
405
tzik56453de2016-02-03 13:42:30 +0900406 template <typename... ForwardArgs>
407 BindState(const Runnable& runnable, ForwardArgs&&... bound_args)
tapted9cef4212015-05-14 17:03:32 +0900408 : BindStateBase(&Destroy),
409 runnable_(runnable),
410 ref_(bound_args...),
tzik56453de2016-02-03 13:42:30 +0900411 bound_args_(std::forward<ForwardArgs>(bound_args)...) {}
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900412
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900413 RunnableType runnable_;
tzik07e99402015-02-06 04:11:26 +0900414 MaybeScopedRefPtr<HasIsMethodTag<Runnable>::value, BoundArgs...> ref_;
415 Tuple<BoundArgs...> bound_args_;
dmichael2f7bc202014-12-19 07:30:11 +0900416
417 private:
tapted9cef4212015-05-14 17:03:32 +0900418 ~BindState() {}
419
420 static void Destroy(BindStateBase* self) {
421 delete static_cast<BindState*>(self);
422 }
ajwong@chromium.org6f015bd2011-11-29 07:13:54 +0900423};
424
ajwong@chromium.orge2cca632011-02-15 10:27:38 +0900425} // namespace internal
426} // namespace base
427
428#endif // BASE_BIND_INTERNAL_H_