Commit d9213455 authored by Zhangyi Chen's avatar Zhangyi Chen

Remove Callback/Bind/Tuple from butil

parent c9039fd4
......@@ -41,13 +41,9 @@ BUTIL_SOURCES = \
src/butil/arena.cpp \
src/butil/at_exit.cc \
src/butil/atomicops_internals_x86_gcc.cc \
src/butil/barrier_closure.cc \
src/butil/base64.cc \
src/butil/base_switches.cc \
src/butil/big_endian.cc \
src/butil/bind_helpers.cc \
src/butil/callback_helpers.cc \
src/butil/callback_internal.cc \
src/butil/cpu.cc \
src/butil/debug/alias.cc \
src/butil/debug/asan_invalid_access.cc \
......
......@@ -7,8 +7,6 @@
#include <stddef.h>
#include <ostream>
#include "butil/bind.h"
#include "butil/callback.h"
#include "butil/logging.h"
namespace butil {
......@@ -44,18 +42,13 @@ AtExitManager::~AtExitManager() {
// static
void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
DCHECK(func);
RegisterTask(butil::Bind(func, param));
}
// static
void AtExitManager::RegisterTask(butil::Closure task) {
if (!g_top_manager) {
NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
return;
}
AutoLock lock(g_top_manager->lock_);
g_top_manager->stack_.push(task);
g_top_manager->stack_.push({func, param});
}
// static
......@@ -68,8 +61,8 @@ void AtExitManager::ProcessCallbacksNow() {
AutoLock lock(g_top_manager->lock_);
while (!g_top_manager->stack_.empty()) {
butil::Closure task = g_top_manager->stack_.top();
task.Run();
Callback task = g_top_manager->stack_.top();
task.func(task.param);
g_top_manager->stack_.pop();
}
}
......
......@@ -9,7 +9,6 @@
#include "butil/base_export.h"
#include "butil/basictypes.h"
#include "butil/callback.h"
#include "butil/synchronization/lock.h"
namespace butil {
......@@ -42,9 +41,6 @@ class BASE_EXPORT AtExitManager {
// the callback function is void func(void*).
static void RegisterCallback(AtExitCallbackType func, void* param);
// Registers the specified task to be called at exit.
static void RegisterTask(butil::Closure task);
// Calls the functions registered with RegisterCallback in LIFO order. It
// is possible to register new callbacks after calling this function.
static void ProcessCallbacksNow();
......@@ -57,8 +53,12 @@ class BASE_EXPORT AtExitManager {
explicit AtExitManager(bool shadow);
private:
struct Callback {
AtExitCallbackType func;
void* param;
};
butil::Lock lock_;
std::stack<butil::Closure> stack_;
std::stack<Callback> stack_;
AtExitManager* next_manager_; // Stack of managers to allow shadowing.
DISALLOW_COPY_AND_ASSIGN(AtExitManager);
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "butil/barrier_closure.h"
#include "butil/atomic_ref_count.h"
#include "butil/bind.h"
namespace {
// Maintains state for a BarrierClosure.
class BarrierInfo {
public:
BarrierInfo(int num_callbacks_left, const butil::Closure& done_closure);
void Run();
private:
butil::AtomicRefCount num_callbacks_left_;
butil::Closure done_closure_;
};
BarrierInfo::BarrierInfo(int num_callbacks, const butil::Closure& done_closure)
: num_callbacks_left_(num_callbacks),
done_closure_(done_closure) {
}
void BarrierInfo::Run() {
DCHECK(!butil::AtomicRefCountIsZero(&num_callbacks_left_));
if (!butil::AtomicRefCountDec(&num_callbacks_left_)) {
done_closure_.Run();
done_closure_.Reset();
}
}
} // namespace
namespace butil {
butil::Closure BarrierClosure(int num_callbacks_left,
const butil::Closure& done_closure) {
DCHECK(num_callbacks_left >= 0);
if (num_callbacks_left == 0)
done_closure.Run();
return butil::Bind(&BarrierInfo::Run,
butil::Owned(
new BarrierInfo(num_callbacks_left, done_closure)));
}
} // namespace butil
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_BARRIER_CLOSURE_H_
#define BASE_BARRIER_CLOSURE_H_
#include "butil/base_export.h"
#include "butil/callback_forward.h"
namespace butil {
// BarrierClosure executes |done_closure| after it has been invoked
// |num_closures| times.
//
// If |num_closures| is 0, |done_closure| is executed immediately.
//
// BarrierClosure is thread-safe - the count of remaining closures is
// maintained as a butil::AtomicRefCount. |done_closure| will be run on
// the thread that calls the final Run() on the returned closures.
//
// |done_closure| is also Reset() on the final calling thread but due to the
// refcounted nature of callbacks, it is hard to know what thread resources
// will be released on.
BASE_EXPORT butil::Closure BarrierClosure(int num_closures,
const butil::Closure& done_closure);
} // namespace butil
#endif // BASE_BARRIER_CLOSURE_H_
// This file was GENERATED by command:
// pump.py bind.h.pump
// DO NOT EDIT BY HAND!!!
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_BIND_H_
#define BASE_BIND_H_
#include "butil/bind_internal.h"
#include "butil/callback_internal.h"
// -----------------------------------------------------------------------------
// Usage documentation
// -----------------------------------------------------------------------------
//
// See butil/callback.h for documentation.
//
//
// -----------------------------------------------------------------------------
// Implementation notes
// -----------------------------------------------------------------------------
//
// If you're reading the implementation, before proceeding further, you should
// read the top comment of butil/bind_internal.h for a definition of common
// terms and concepts.
//
// RETURN TYPES
//
// Though Bind()'s result is meant to be stored in a Callback<> type, it
// cannot actually return the exact type without requiring a large amount
// of extra template specializations. The problem is that in order to
// discern the correct specialization of Callback<>, Bind would need to
// unwrap the function signature to determine the signature's arity, and
// whether or not it is a method.
//
// Each unique combination of (arity, function_type, num_prebound) where
// function_type is one of {function, method, const_method} would require
// one specialization. We eventually have to do a similar number of
// specializations anyways in the implementation (see the Invoker<>,
// classes). However, it is avoidable in Bind if we return the result
// via an indirection like we do below.
//
// TODO(ajwong): We might be able to avoid this now, but need to test.
//
// It is possible to move most of the COMPILE_ASSERT asserts into BindState<>,
// but it feels a little nicer to have the asserts here so people do not
// need to crack open bind_internal.h. On the other hand, it makes Bind()
// harder to read.
namespace butil {
template <typename Functor>
butil::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void()>
::UnboundRunType>
Bind(Functor functor) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
typedef internal::BindState<RunnableType, RunType, void()> BindState;
return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor)));
}
template <typename Functor, typename P1>
butil::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType)>
::UnboundRunType>
Bind(Functor functor, const P1& p1) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
// Use RunnableType::RunType instead of RunType above because our
// checks should below for bound references need to know what the actual
// functor is going to interpret the argument as.
typedef internal::FunctionTraits<typename RunnableType::RunType>
BoundFunctorTraits;
// Do not allow binding a non-const reference parameter. Non-const reference
// parameters are disallowed by the Google style guide. Also, binding a
// non-const reference parameter can make for subtle bugs because the
// invoked function will receive a reference to the stored copy of the
// argument and not the original.
COMPILE_ASSERT(
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ),
do_not_bind_functions_with_nonconst_ref);
// For methods, we need to be careful for parameter 1. We do not require
// a scoped_refptr because BindState<> itself takes care of AddRef() for
// methods. We also disallow binding of an array as the method's target
// object.
COMPILE_ASSERT(
internal::HasIsMethodTag<RunnableType>::value ||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
p1_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
!is_array<P1>::value,
first_bound_argument_to_method_cannot_be_array);
typedef internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType)> BindState;
return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), p1));
}
template <typename Functor, typename P1, typename P2>
butil::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType)>
::UnboundRunType>
Bind(Functor functor, const P1& p1, const P2& p2) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
// Use RunnableType::RunType instead of RunType above because our
// checks should below for bound references need to know what the actual
// functor is going to interpret the argument as.
typedef internal::FunctionTraits<typename RunnableType::RunType>
BoundFunctorTraits;
// Do not allow binding a non-const reference parameter. Non-const reference
// parameters are disallowed by the Google style guide. Also, binding a
// non-const reference parameter can make for subtle bugs because the
// invoked function will receive a reference to the stored copy of the
// argument and not the original.
COMPILE_ASSERT(
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ),
do_not_bind_functions_with_nonconst_ref);
// For methods, we need to be careful for parameter 1. We do not require
// a scoped_refptr because BindState<> itself takes care of AddRef() for
// methods. We also disallow binding of an array as the method's target
// object.
COMPILE_ASSERT(
internal::HasIsMethodTag<RunnableType>::value ||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
p1_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
!is_array<P1>::value,
first_bound_argument_to_method_cannot_be_array);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
p2_is_refcounted_type_and_needs_scoped_refptr);
typedef internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType)> BindState;
return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), p1, p2));
}
template <typename Functor, typename P1, typename P2, typename P3>
butil::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType)>
::UnboundRunType>
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
// Use RunnableType::RunType instead of RunType above because our
// checks should below for bound references need to know what the actual
// functor is going to interpret the argument as.
typedef internal::FunctionTraits<typename RunnableType::RunType>
BoundFunctorTraits;
// Do not allow binding a non-const reference parameter. Non-const reference
// parameters are disallowed by the Google style guide. Also, binding a
// non-const reference parameter can make for subtle bugs because the
// invoked function will receive a reference to the stored copy of the
// argument and not the original.
COMPILE_ASSERT(
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ),
do_not_bind_functions_with_nonconst_ref);
// For methods, we need to be careful for parameter 1. We do not require
// a scoped_refptr because BindState<> itself takes care of AddRef() for
// methods. We also disallow binding of an array as the method's target
// object.
COMPILE_ASSERT(
internal::HasIsMethodTag<RunnableType>::value ||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
p1_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
!is_array<P1>::value,
first_bound_argument_to_method_cannot_be_array);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
p2_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
p3_is_refcounted_type_and_needs_scoped_refptr);
typedef internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType)> BindState;
return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), p1, p2, p3));
}
template <typename Functor, typename P1, typename P2, typename P3, typename P4>
butil::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType)>
::UnboundRunType>
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
// Use RunnableType::RunType instead of RunType above because our
// checks should below for bound references need to know what the actual
// functor is going to interpret the argument as.
typedef internal::FunctionTraits<typename RunnableType::RunType>
BoundFunctorTraits;
// Do not allow binding a non-const reference parameter. Non-const reference
// parameters are disallowed by the Google style guide. Also, binding a
// non-const reference parameter can make for subtle bugs because the
// invoked function will receive a reference to the stored copy of the
// argument and not the original.
COMPILE_ASSERT(
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ),
do_not_bind_functions_with_nonconst_ref);
// For methods, we need to be careful for parameter 1. We do not require
// a scoped_refptr because BindState<> itself takes care of AddRef() for
// methods. We also disallow binding of an array as the method's target
// object.
COMPILE_ASSERT(
internal::HasIsMethodTag<RunnableType>::value ||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
p1_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
!is_array<P1>::value,
first_bound_argument_to_method_cannot_be_array);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
p2_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
p3_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
p4_is_refcounted_type_and_needs_scoped_refptr);
typedef internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType)> BindState;
return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4));
}
template <typename Functor, typename P1, typename P2, typename P3, typename P4,
typename P5>
butil::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType)>
::UnboundRunType>
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
const P5& p5) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
// Use RunnableType::RunType instead of RunType above because our
// checks should below for bound references need to know what the actual
// functor is going to interpret the argument as.
typedef internal::FunctionTraits<typename RunnableType::RunType>
BoundFunctorTraits;
// Do not allow binding a non-const reference parameter. Non-const reference
// parameters are disallowed by the Google style guide. Also, binding a
// non-const reference parameter can make for subtle bugs because the
// invoked function will receive a reference to the stored copy of the
// argument and not the original.
COMPILE_ASSERT(
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ),
do_not_bind_functions_with_nonconst_ref);
// For methods, we need to be careful for parameter 1. We do not require
// a scoped_refptr because BindState<> itself takes care of AddRef() for
// methods. We also disallow binding of an array as the method's target
// object.
COMPILE_ASSERT(
internal::HasIsMethodTag<RunnableType>::value ||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
p1_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
!is_array<P1>::value,
first_bound_argument_to_method_cannot_be_array);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
p2_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
p3_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
p4_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
p5_is_refcounted_type_and_needs_scoped_refptr);
typedef internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType)> BindState;
return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5));
}
template <typename Functor, typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6>
butil::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType,
typename internal::CallbackParamTraits<P6>::StorageType)>
::UnboundRunType>
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
const P5& p5, const P6& p6) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
// Use RunnableType::RunType instead of RunType above because our
// checks should below for bound references need to know what the actual
// functor is going to interpret the argument as.
typedef internal::FunctionTraits<typename RunnableType::RunType>
BoundFunctorTraits;
// Do not allow binding a non-const reference parameter. Non-const reference
// parameters are disallowed by the Google style guide. Also, binding a
// non-const reference parameter can make for subtle bugs because the
// invoked function will receive a reference to the stored copy of the
// argument and not the original.
COMPILE_ASSERT(
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A6Type>::value ),
do_not_bind_functions_with_nonconst_ref);
// For methods, we need to be careful for parameter 1. We do not require
// a scoped_refptr because BindState<> itself takes care of AddRef() for
// methods. We also disallow binding of an array as the method's target
// object.
COMPILE_ASSERT(
internal::HasIsMethodTag<RunnableType>::value ||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
p1_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
!is_array<P1>::value,
first_bound_argument_to_method_cannot_be_array);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
p2_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
p3_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
p4_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
p5_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P6>::value,
p6_is_refcounted_type_and_needs_scoped_refptr);
typedef internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType,
typename internal::CallbackParamTraits<P6>::StorageType)> BindState;
return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6));
}
template <typename Functor, typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6, typename P7>
butil::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType,
typename internal::CallbackParamTraits<P6>::StorageType,
typename internal::CallbackParamTraits<P7>::StorageType)>
::UnboundRunType>
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
const P5& p5, const P6& p6, const P7& p7) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
// Use RunnableType::RunType instead of RunType above because our
// checks should below for bound references need to know what the actual
// functor is going to interpret the argument as.
typedef internal::FunctionTraits<typename RunnableType::RunType>
BoundFunctorTraits;
// Do not allow binding a non-const reference parameter. Non-const reference
// parameters are disallowed by the Google style guide. Also, binding a
// non-const reference parameter can make for subtle bugs because the
// invoked function will receive a reference to the stored copy of the
// argument and not the original.
COMPILE_ASSERT(
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A6Type>::value ||
is_non_const_reference<typename BoundFunctorTraits::A7Type>::value ),
do_not_bind_functions_with_nonconst_ref);
// For methods, we need to be careful for parameter 1. We do not require
// a scoped_refptr because BindState<> itself takes care of AddRef() for
// methods. We also disallow binding of an array as the method's target
// object.
COMPILE_ASSERT(
internal::HasIsMethodTag<RunnableType>::value ||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
p1_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
!is_array<P1>::value,
first_bound_argument_to_method_cannot_be_array);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
p2_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
p3_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
p4_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
p5_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P6>::value,
p6_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P7>::value,
p7_is_refcounted_type_and_needs_scoped_refptr);
typedef internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType,
typename internal::CallbackParamTraits<P6>::StorageType,
typename internal::CallbackParamTraits<P7>::StorageType)> BindState;
return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6,
p7));
}
} // namespace butil
#endif // BASE_BIND_H_
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "butil/bind_helpers.h"
#include "butil/callback.h"
namespace butil {
void DoNothing() {
}
} // namespace butil
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This defines a set of argument wrappers and related factory methods that
// can be used specify the refcounting and reference semantics of arguments
// that are bound by the Bind() function in butil/bind.h.
//
// It also defines a set of simple functions and utilities that people want
// when using Callback<> and Bind().
//
//
// ARGUMENT BINDING WRAPPERS
//
// The wrapper functions are butil::Unretained(), butil::Owned(), butil::Passed(),
// butil::ConstRef(), and butil::IgnoreResult().
//
// Unretained() allows Bind() to bind a non-refcounted class, and to disable
// refcounting on arguments that are refcounted objects.
//
// Owned() transfers ownership of an object to the Callback resulting from
// bind; the object will be deleted when the Callback is deleted.
//
// Passed() is for transferring movable-but-not-copyable types (eg. scoped_ptr)
// through a Callback. Logically, this signifies a destructive transfer of
// the state of the argument into the target function. Invoking
// Callback::Run() twice on a Callback that was created with a Passed()
// argument will CHECK() because the first invocation would have already
// transferred ownership to the target function.
//
// ConstRef() allows binding a constant reference to an argument rather
// than a copy.
//
// IgnoreResult() is used to adapt a function or Callback with a return type to
// one with a void return. This is most useful if you have a function with,
// say, a pesky ignorable bool return that you want to use with PostTask or
// something else that expect a Callback with a void return.
//
// EXAMPLE OF Unretained():
//
// class Foo {
// public:
// void func() { cout << "Foo:f" << endl; }
// };
//
// // In some function somewhere.
// Foo foo;
// Closure foo_callback =
// Bind(&Foo::func, Unretained(&foo));
// foo_callback.Run(); // Prints "Foo:f".
//
// Without the Unretained() wrapper on |&foo|, the above call would fail
// to compile because Foo does not support the AddRef() and Release() methods.
//
//
// EXAMPLE OF Owned():
//
// void foo(int* arg) { cout << *arg << endl }
//
// int* pn = new int(1);
// Closure foo_callback = Bind(&foo, Owned(pn));
//
// foo_callback.Run(); // Prints "1"
// foo_callback.Run(); // Prints "1"
// *n = 2;
// foo_callback.Run(); // Prints "2"
//
// foo_callback.Reset(); // |pn| is deleted. Also will happen when
// // |foo_callback| goes out of scope.
//
// Without Owned(), someone would have to know to delete |pn| when the last
// reference to the Callback is deleted.
//
//
// EXAMPLE OF ConstRef():
//
// void foo(int arg) { cout << arg << endl }
//
// int n = 1;
// Closure no_ref = Bind(&foo, n);
// Closure has_ref = Bind(&foo, ConstRef(n));
//
// no_ref.Run(); // Prints "1"
// has_ref.Run(); // Prints "1"
//
// n = 2;
// no_ref.Run(); // Prints "1"
// has_ref.Run(); // Prints "2"
//
// Note that because ConstRef() takes a reference on |n|, |n| must outlive all
// its bound callbacks.
//
//
// EXAMPLE OF IgnoreResult():
//
// int DoSomething(int arg) { cout << arg << endl; }
//
// // Assign to a Callback with a void return type.
// Callback<void(int)> cb = Bind(IgnoreResult(&DoSomething));
// cb->Run(1); // Prints "1".
//
// // Prints "1" on |ml|.
// ml->PostTask(FROM_HERE, Bind(IgnoreResult(&DoSomething), 1);
//
//
// EXAMPLE OF Passed():
//
// void TakesOwnership(scoped_ptr<Foo> arg) { }
// scoped_ptr<Foo> CreateFoo() { return scoped_ptr<Foo>(new Foo()); }
//
// scoped_ptr<Foo> f(new Foo());
//
// // |cb| is given ownership of Foo(). |f| is now NULL.
// // You can use f.Pass() in place of &f, but it's more verbose.
// Closure cb = Bind(&TakesOwnership, Passed(&f));
//
// // Run was never called so |cb| still owns Foo() and deletes
// // it on Reset().
// cb.Reset();
//
// // |cb| is given a new Foo created by CreateFoo().
// cb = Bind(&TakesOwnership, Passed(CreateFoo()));
//
// // |arg| in TakesOwnership() is given ownership of Foo(). |cb|
// // no longer owns Foo() and, if reset, would not delete Foo().
// cb.Run(); // Foo() is now transferred to |arg| and deleted.
// cb.Run(); // This CHECK()s since Foo() already been used once.
//
// Passed() is particularly useful with PostTask() when you are transferring
// ownership of an argument into a task, but don't necessarily know if the
// task will always be executed. This can happen if the task is cancellable
// or if it is posted to a MessageLoopProxy.
//
//
// SIMPLE FUNCTIONS AND UTILITIES.
//
// DoNothing() - Useful for creating a Closure that does nothing when called.
// DeletePointer<T>() - Useful for creating a Closure that will delete a
// pointer when invoked. Only use this when necessary.
// In most cases MessageLoop::DeleteSoon() is a better
// fit.
#ifndef BASE_BIND_HELPERS_H_
#define BASE_BIND_HELPERS_H_
#include "butil/basictypes.h"
#include "butil/callback.h"
#include "butil/memory/weak_ptr.h"
#include "butil/type_traits.h"
namespace butil {
namespace internal {
// Use the Substitution Failure Is Not An Error (SFINAE) trick to inspect T
// for the existence of AddRef() and Release() functions of the correct
// signature.
//
// http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error
// http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence
// http://stackoverflow.com/questions/4358584/sfinae-approach-comparison
// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions
//
// The last link in particular show the method used below.
//
// For SFINAE to work with inherited methods, we need to pull some extra tricks
// with multiple inheritance. In the more standard formulation, the overloads
// of Check would be:
//
// template <typename C>
// Yes NotTheCheckWeWant(Helper<&C::TargetFunc>*);
//
// template <typename C>
// No NotTheCheckWeWant(...);
//
// static const bool value = sizeof(NotTheCheckWeWant<T>(0)) == sizeof(Yes);
//
// The problem here is that template resolution will not match
// C::TargetFunc if TargetFunc does not exist directly in C. That is, if
// TargetFunc in inherited from an ancestor, &C::TargetFunc will not match,
// |value| will be false. This formulation only checks for whether or
// not TargetFunc exist directly in the class being introspected.
//
// To get around this, we play a dirty trick with multiple inheritance.
// First, We create a class BaseMixin that declares each function that we
// want to probe for. Then we create a class Base that inherits from both T
// (the class we wish to probe) and BaseMixin. Note that the function
// signature in BaseMixin does not need to match the signature of the function
// we are probing for; thus it's easiest to just use void(void).
//
// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an
// ambiguous resolution between BaseMixin and T. This lets us write the
// following:
//
// template <typename C>
// No GoodCheck(Helper<&C::TargetFunc>*);
//
// template <typename C>
// Yes GoodCheck(...);
//
// static const bool value = sizeof(GoodCheck<Base>(0)) == sizeof(Yes);
//
// Notice here that the variadic version of GoodCheck() returns Yes here
// instead of No like the previous one. Also notice that we calculate |value|
// by specializing GoodCheck() on Base instead of T.
//
// We've reversed the roles of the variadic, and Helper overloads.
// GoodCheck(Helper<&C::TargetFunc>*), when C = Base, fails to be a valid
// substitution if T::TargetFunc exists. Thus GoodCheck<Base>(0) will resolve
// to the variadic version if T has TargetFunc. If T::TargetFunc does not
// exist, then &C::TargetFunc is not ambiguous, and the overload resolution
// will prefer GoodCheck(Helper<&C::TargetFunc>*).
//
// This method of SFINAE will correctly probe for inherited names, but it cannot
// typecheck those names. It's still a good enough sanity check though.
//
// Works on gcc-4.2, gcc-4.4, and Visual Studio 2008.
//
// TODO(ajwong): Move to ref_counted.h or type_traits.h when we've vetted
// this works well.
//
// TODO(ajwong): Make this check for Release() as well.
// See http://crbug.com/82038.
template <typename T>
class SupportsAddRefAndRelease {
typedef char Yes[1];
typedef char No[2];
struct BaseMixin {
void AddRef();
};
// MSVC warns when you try to use Base if T has a private destructor, the
// common pattern for refcounted types. It does this even though no attempt to
// instantiate Base is made. We disable the warning for this definition.
#if defined(OS_WIN)
#pragma warning(push)
#pragma warning(disable:4624)
#endif
struct Base : public T, public BaseMixin {
};
#if defined(OS_WIN)
#pragma warning(pop)
#endif
template <void(BaseMixin::*)(void)> struct Helper {};
template <typename C>
static No& Check(Helper<&C::AddRef>*);
template <typename >
static Yes& Check(...);
public:
static const bool value = sizeof(Check<Base>(0)) == sizeof(Yes);
};
// Helpers to assert that arguments of a recounted type are bound with a
// scoped_refptr.
template <bool IsClasstype, typename T>
struct UnsafeBindtoRefCountedArgHelper : false_type {
};
template <typename T>
struct UnsafeBindtoRefCountedArgHelper<true, T>
: integral_constant<bool, SupportsAddRefAndRelease<T>::value> {
};
template <typename T>
struct UnsafeBindtoRefCountedArg : false_type {
};
template <typename T>
struct UnsafeBindtoRefCountedArg<T*>
: UnsafeBindtoRefCountedArgHelper<is_class<T>::value, T> {
};
template <typename T>
class HasIsMethodTag {
typedef char Yes[1];
typedef char No[2];
template <typename U>
static Yes& Check(typename U::IsMethod*);
template <typename U>
static No& Check(...);
public:
static const bool value = sizeof(Check<T>(0)) == sizeof(Yes);
};
template <typename T>
class UnretainedWrapper {
public:
explicit UnretainedWrapper(T* o) : ptr_(o) {}
T* get() const { return ptr_; }
private:
T* ptr_;
};
template <typename T>
class ConstRefWrapper {
public:
explicit ConstRefWrapper(const T& o) : ptr_(&o) {}
const T& get() const { return *ptr_; }
private:
const T* ptr_;
};
template <typename T>
struct IgnoreResultHelper {
explicit IgnoreResultHelper(T functor) : functor_(functor) {}
T functor_;
};
template <typename T>
struct IgnoreResultHelper<Callback<T> > {
explicit IgnoreResultHelper(const Callback<T>& functor) : functor_(functor) {}
const Callback<T>& functor_;
};
// An alternate implementation is to avoid the destructive copy, and instead
// specialize ParamTraits<> for OwnedWrapper<> to change the StorageType to
// a class that is essentially a scoped_ptr<>.
//
// The current implementation has the benefit though of leaving ParamTraits<>
// fully in callback_internal.h as well as avoiding type conversions during
// storage.
template <typename T>
class OwnedWrapper {
public:
explicit OwnedWrapper(T* o) : ptr_(o) {}
~OwnedWrapper() { delete ptr_; }
T* get() const { return ptr_; }
OwnedWrapper(const OwnedWrapper& other) {
ptr_ = other.ptr_;
other.ptr_ = NULL;
}
private:
mutable T* ptr_;
};
// PassedWrapper is a copyable adapter for a scoper that ignores const.
//
// It is needed to get around the fact that Bind() takes a const reference to
// all its arguments. Because Bind() takes a const reference to avoid
// unnecessary copies, it is incompatible with movable-but-not-copyable
// types; doing a destructive "move" of the type into Bind() would violate
// the const correctness.
//
// This conundrum cannot be solved without either C++11 rvalue references or
// a O(2^n) blowup of Bind() templates to handle each combination of regular
// types and movable-but-not-copyable types. Thus we introduce a wrapper type
// that is copyable to transmit the correct type information down into
// BindState<>. Ignoring const in this type makes sense because it is only
// created when we are explicitly trying to do a destructive move.
//
// Two notes:
// 1) PassedWrapper supports any type that has a "Pass()" function.
// This is intentional. The whitelisting of which specific types we
// support is maintained by CallbackParamTraits<>.
// 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL"
// scoper to a Callback and allow the Callback to execute once.
template <typename T>
class PassedWrapper {
public:
explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {}
PassedWrapper(const PassedWrapper& other)
: is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) {
}
T Pass() const {
CHECK(is_valid_);
is_valid_ = false;
return scoper_.Pass();
}
private:
mutable bool is_valid_;
mutable T scoper_;
};
// Unwrap the stored parameters for the wrappers above.
template <typename T>
struct UnwrapTraits {
typedef const T& ForwardType;
static ForwardType Unwrap(const T& o) { return o; }
};
template <typename T>
struct UnwrapTraits<UnretainedWrapper<T> > {
typedef T* ForwardType;
static ForwardType Unwrap(UnretainedWrapper<T> unretained) {
return unretained.get();
}
};
template <typename T>
struct UnwrapTraits<ConstRefWrapper<T> > {
typedef const T& ForwardType;
static ForwardType Unwrap(ConstRefWrapper<T> const_ref) {
return const_ref.get();
}
};
template <typename T>
struct UnwrapTraits<scoped_refptr<T> > {
typedef T* ForwardType;
static ForwardType Unwrap(const scoped_refptr<T>& o) { return o.get(); }
};
template <typename T>
struct UnwrapTraits<WeakPtr<T> > {
typedef const WeakPtr<T>& ForwardType;
static ForwardType Unwrap(const WeakPtr<T>& o) { return o; }
};
template <typename T>
struct UnwrapTraits<OwnedWrapper<T> > {
typedef T* ForwardType;
static ForwardType Unwrap(const OwnedWrapper<T>& o) {
return o.get();
}
};
template <typename T>
struct UnwrapTraits<PassedWrapper<T> > {
typedef T ForwardType;
static T Unwrap(PassedWrapper<T>& o) {
return o.Pass();
}
};
// Utility for handling different refcounting semantics in the Bind()
// function.
template <bool is_method, typename T>
struct MaybeRefcount;
template <typename T>
struct MaybeRefcount<false, T> {
static void AddRef(const T&) {}
static void Release(const T&) {}
};
template <typename T, size_t n>
struct MaybeRefcount<false, T[n]> {
static void AddRef(const T*) {}
static void Release(const T*) {}
};
template <typename T>
struct MaybeRefcount<true, T> {
static void AddRef(const T&) {}
static void Release(const T&) {}
};
template <typename T>
struct MaybeRefcount<true, T*> {
static void AddRef(T* o) { o->AddRef(); }
static void Release(T* o) { o->Release(); }
};
// No need to additionally AddRef() and Release() since we are storing a
// scoped_refptr<> inside the storage object already.
template <typename T>
struct MaybeRefcount<true, scoped_refptr<T> > {
static void AddRef(const scoped_refptr<T>& o) {}
static void Release(const scoped_refptr<T>& o) {}
};
template <typename T>
struct MaybeRefcount<true, const T*> {
static void AddRef(const T* o) { o->AddRef(); }
static void Release(const T* o) { o->Release(); }
};
// IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a
// method. It is used internally by Bind() to select the correct
// InvokeHelper that will no-op itself in the event the WeakPtr<> for
// the target object is invalidated.
//
// P1 should be the type of the object that will be received of the method.
template <bool IsMethod, typename P1>
struct IsWeakMethod : public false_type {};
template <typename T>
struct IsWeakMethod<true, WeakPtr<T> > : public true_type {};
template <typename T>
struct IsWeakMethod<true, ConstRefWrapper<WeakPtr<T> > > : public true_type {};
} // namespace internal
template <typename T>
static inline internal::UnretainedWrapper<T> Unretained(T* o) {
return internal::UnretainedWrapper<T>(o);
}
template <typename T>
static inline internal::ConstRefWrapper<T> ConstRef(const T& o) {
return internal::ConstRefWrapper<T>(o);
}
template <typename T>
static inline internal::OwnedWrapper<T> Owned(T* o) {
return internal::OwnedWrapper<T>(o);
}
// We offer 2 syntaxes for calling Passed(). The first takes a temporary and
// is best suited for use with the return value of a function. The second
// takes a pointer to the scoper and is just syntactic sugar to avoid having
// to write Passed(scoper.Pass()).
template <typename T>
static inline internal::PassedWrapper<T> Passed(T scoper) {
return internal::PassedWrapper<T>(scoper.Pass());
}
template <typename T>
static inline internal::PassedWrapper<T> Passed(T* scoper) {
return internal::PassedWrapper<T>(scoper->Pass());
}
template <typename T>
static inline internal::IgnoreResultHelper<T> IgnoreResult(T data) {
return internal::IgnoreResultHelper<T>(data);
}
template <typename T>
static inline internal::IgnoreResultHelper<Callback<T> >
IgnoreResult(const Callback<T>& data) {
return internal::IgnoreResultHelper<Callback<T> >(data);
}
BASE_EXPORT void DoNothing();
template<typename T>
void DeletePointer(T* obj) {
delete obj;
}
} // namespace butil
#endif // BASE_BIND_HELPERS_H_
This source diff could not be displayed because it is too large. You can view the blob instead.
// This file was GENERATED by command:
// pump.py callback.h.pump
// DO NOT EDIT BY HAND!!!
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_CALLBACK_H_
#define BASE_CALLBACK_H_
#include "butil/callback_forward.h"
#include "butil/callback_internal.h"
#include "butil/type_traits.h"
// NOTE: Header files that do not require the full definition of Callback or
// Closure should #include "butil/callback_forward.h" instead of this file.
// -----------------------------------------------------------------------------
// Introduction
// -----------------------------------------------------------------------------
//
// The templated Callback class is a generalized function object. Together
// with the Bind() function in bind.h, they provide a type-safe method for
// performing partial application of functions.
//
// Partial application (or "currying") is the process of binding a subset of
// a function's arguments to produce another function that takes fewer
// arguments. This can be used to pass around a unit of delayed execution,
// much like lexical closures are used in other languages. For example, it
// is used in Chromium code to schedule tasks on different MessageLoops.
//
// A callback with no unbound input parameters (butil::Callback<void(void)>)
// is called a butil::Closure. Note that this is NOT the same as what other
// languages refer to as a closure -- it does not retain a reference to its
// enclosing environment.
//
// MEMORY MANAGEMENT AND PASSING
//
// The Callback objects themselves should be passed by const-reference, and
// stored by copy. They internally store their state via a refcounted class
// and thus do not need to be deleted.
//
// The reason to pass via a const-reference is to avoid unnecessary
// AddRef/Release pairs to the internal state.
//
//
// -----------------------------------------------------------------------------
// Quick reference for basic stuff
// -----------------------------------------------------------------------------
//
// BINDING A BARE FUNCTION
//
// int Return5() { return 5; }
// butil::Callback<int(void)> func_cb = butil::Bind(&Return5);
// LOG(INFO) << func_cb.Run(); // Prints 5.
//
// BINDING A CLASS METHOD
//
// The first argument to bind is the member function to call, the second is
// the object on which to call it.
//
// class Ref : public butil::RefCountedThreadSafe<Ref> {
// public:
// int Foo() { return 3; }
// void PrintBye() { LOG(INFO) << "bye."; }
// };
// scoped_refptr<Ref> ref = new Ref();
// butil::Callback<void(void)> ref_cb = butil::Bind(&Ref::Foo, ref);
// LOG(INFO) << ref_cb.Run(); // Prints out 3.
//
// By default the object must support RefCounted or you will get a compiler
// error. If you're passing between threads, be sure it's
// RefCountedThreadSafe! See "Advanced binding of member functions" below if
// you don't want to use reference counting.
//
// RUNNING A CALLBACK
//
// Callbacks can be run with their "Run" method, which has the same
// signature as the template argument to the callback.
//
// void DoSomething(const butil::Callback<void(int, std::string)>& callback) {
// callback.Run(5, "hello");
// }
//
// Callbacks can be run more than once (they don't get deleted or marked when
// run). However, this precludes using butil::Passed (see below).
//
// void DoSomething(const butil::Callback<double(double)>& callback) {
// double myresult = callback.Run(3.14159);
// myresult += callback.Run(2.71828);
// }
//
// PASSING UNBOUND INPUT PARAMETERS
//
// Unbound parameters are specified at the time a callback is Run(). They are
// specified in the Callback template type:
//
// void MyFunc(int i, const std::string& str) {}
// butil::Callback<void(int, const std::string&)> cb = butil::Bind(&MyFunc);
// cb.Run(23, "hello, world");
//
// PASSING BOUND INPUT PARAMETERS
//
// Bound parameters are specified when you create thee callback as arguments
// to Bind(). They will be passed to the function and the Run()ner of the
// callback doesn't see those values or even know that the function it's
// calling.
//
// void MyFunc(int i, const std::string& str) {}
// butil::Callback<void(void)> cb = butil::Bind(&MyFunc, 23, "hello world");
// cb.Run();
//
// A callback with no unbound input parameters (butil::Callback<void(void)>)
// is called a butil::Closure. So we could have also written:
//
// butil::Closure cb = butil::Bind(&MyFunc, 23, "hello world");
//
// When calling member functions, bound parameters just go after the object
// pointer.
//
// butil::Closure cb = butil::Bind(&MyClass::MyFunc, this, 23, "hello world");
//
// PARTIAL BINDING OF PARAMETERS
//
// You can specify some parameters when you create the callback, and specify
// the rest when you execute the callback.
//
// void MyFunc(int i, const std::string& str) {}
// butil::Callback<void(const std::string&)> cb = butil::Bind(&MyFunc, 23);
// cb.Run("hello world");
//
// When calling a function bound parameters are first, followed by unbound
// parameters.
//
//
// -----------------------------------------------------------------------------
// Quick reference for advanced binding
// -----------------------------------------------------------------------------
//
// BINDING A CLASS METHOD WITH WEAK POINTERS
//
// butil::Bind(&MyClass::Foo, GetWeakPtr());
//
// The callback will not be run if the object has already been destroyed.
// DANGER: weak pointers are not threadsafe, so don't use this
// when passing between threads!
//
// BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT
//
// butil::Bind(&MyClass::Foo, butil::Unretained(this));
//
// This disables all lifetime management on the object. You're responsible
// for making sure the object is alive at the time of the call. You break it,
// you own it!
//
// BINDING A CLASS METHOD AND HAVING THE CALLBACK OWN THE CLASS
//
// MyClass* myclass = new MyClass;
// butil::Bind(&MyClass::Foo, butil::Owned(myclass));
//
// The object will be deleted when the callback is destroyed, even if it's
// not run (like if you post a task during shutdown). Potentially useful for
// "fire and forget" cases.
//
// IGNORING RETURN VALUES
//
// Sometimes you want to call a function that returns a value in a callback
// that doesn't expect a return value.
//
// int DoSomething(int arg) { cout << arg << endl; }
// butil::Callback<void<int>) cb =
// butil::Bind(butil::IgnoreResult(&DoSomething));
//
//
// -----------------------------------------------------------------------------
// Quick reference for binding parameters to Bind()
// -----------------------------------------------------------------------------
//
// Bound parameters are specified as arguments to Bind() and are passed to the
// function. A callback with no parameters or no unbound parameters is called a
// Closure (butil::Callback<void(void)> and butil::Closure are the same thing).
//
// PASSING PARAMETERS OWNED BY THE CALLBACK
//
// void Foo(int* arg) { cout << *arg << endl; }
// int* pn = new int(1);
// butil::Closure foo_callback = butil::Bind(&foo, butil::Owned(pn));
//
// The parameter will be deleted when the callback is destroyed, even if it's
// not run (like if you post a task during shutdown).
//
// PASSING PARAMETERS AS A scoped_ptr
//
// void TakesOwnership(scoped_ptr<Foo> arg) {}
// scoped_ptr<Foo> f(new Foo);
// // f becomes null during the following call.
// butil::Closure cb = butil::Bind(&TakesOwnership, butil::Passed(&f));
//
// Ownership of the parameter will be with the callback until the it is run,
// when ownership is passed to the callback function. This means the callback
// can only be run once. If the callback is never run, it will delete the
// object when it's destroyed.
//
// PASSING PARAMETERS AS A scoped_refptr
//
// void TakesOneRef(scoped_refptr<Foo> arg) {}
// scoped_refptr<Foo> f(new Foo)
// butil::Closure cb = butil::Bind(&TakesOneRef, f);
//
// This should "just work." The closure will take a reference as long as it
// is alive, and another reference will be taken for the called function.
//
// PASSING PARAMETERS BY REFERENCE
//
// Const references are *copied* unless ConstRef is used. Example:
//
// void foo(const int& arg) { printf("%d %p\n", arg, &arg); }
// int n = 1;
// butil::Closure has_copy = butil::Bind(&foo, n);
// butil::Closure has_ref = butil::Bind(&foo, butil::ConstRef(n));
// n = 2;
// foo(n); // Prints "2 0xaaaaaaaaaaaa"
// has_copy.Run(); // Prints "1 0xbbbbbbbbbbbb"
// has_ref.Run(); // Prints "2 0xaaaaaaaaaaaa"
//
// Normally parameters are copied in the closure. DANGER: ConstRef stores a
// const reference instead, referencing the original parameter. This means
// that you must ensure the object outlives the callback!
//
//
// -----------------------------------------------------------------------------
// Implementation notes
// -----------------------------------------------------------------------------
//
// WHERE IS THIS DESIGN FROM:
//
// The design Callback and Bind is heavily influenced by C++'s
// tr1::function/tr1::bind, and by the "Google Callback" system used inside
// Google.
//
//
// HOW THE IMPLEMENTATION WORKS:
//
// There are three main components to the system:
// 1) The Callback classes.
// 2) The Bind() functions.
// 3) The arguments wrappers (e.g., Unretained() and ConstRef()).
//
// The Callback classes represent a generic function pointer. Internally,
// it stores a refcounted piece of state that represents the target function
// and all its bound parameters. Each Callback specialization has a templated
// constructor that takes an BindState<>*. In the context of the constructor,
// the static type of this BindState<> pointer uniquely identifies the
// function it is representing, all its bound parameters, and a Run() method
// that is capable of invoking the target.
//
// Callback's constructor takes the BindState<>* that has the full static type
// and erases the target function type as well as the types of the bound
// parameters. It does this by storing a pointer to the specific Run()
// function, and upcasting the state of BindState<>* to a
// BindStateBase*. This is safe as long as this BindStateBase pointer
// is only used with the stored Run() pointer.
//
// To BindState<> objects are created inside the Bind() functions.
// These functions, along with a set of internal templates, are responsible for
//
// - Unwrapping the function signature into return type, and parameters
// - Determining the number of parameters that are bound
// - Creating the BindState storing the bound parameters
// - Performing compile-time asserts to avoid error-prone behavior
// - Returning an Callback<> with an arity matching the number of unbound
// parameters and that knows the correct refcounting semantics for the
// target object if we are binding a method.
//
// The Bind functions do the above using type-inference, and template
// specializations.
//
// By default Bind() will store copies of all bound parameters, and attempt
// to refcount a target object if the function being bound is a class method.
// These copies are created even if the function takes parameters as const
// references. (Binding to non-const references is forbidden, see bind.h.)
//
// To change this behavior, we introduce a set of argument wrappers
// (e.g., Unretained(), and ConstRef()). These are simple container templates
// that are passed by value, and wrap a pointer to argument. See the
// file-level comment in butil/bind_helpers.h for more info.
//
// These types are passed to the Unwrap() functions, and the MaybeRefcount()
// functions respectively to modify the behavior of Bind(). The Unwrap()
// and MaybeRefcount() functions change behavior by doing partial
// specialization based on whether or not a parameter is a wrapper type.
//
// ConstRef() is similar to tr1::cref. Unretained() is specific to Chromium.
//
//
// WHY NOT TR1 FUNCTION/BIND?
//
// Direct use of tr1::function and tr1::bind was considered, but ultimately
// rejected because of the number of copy constructors invocations involved
// in the binding of arguments during construction, and the forwarding of
// arguments during invocation. These copies will no longer be an issue in
// C++0x because C++0x will support rvalue reference allowing for the compiler
// to avoid these copies. However, waiting for C++0x is not an option.
//
// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the
// tr1::bind call itself will invoke a non-trivial copy constructor three times
// for each bound parameter. Also, each when passing a tr1::function, each
// bound argument will be copied again.
//
// In addition to the copies taken at binding and invocation, copying a
// tr1::function causes a copy to be made of all the bound parameters and
// state.
//
// Furthermore, in Chromium, it is desirable for the Callback to take a
// reference on a target object when representing a class method call. This
// is not supported by tr1.
//
// Lastly, tr1::function and tr1::bind has a more general and flexible API.
// This includes things like argument reordering by use of
// tr1::bind::placeholder, support for non-const reference parameters, and some
// limited amount of subtyping of the tr1::function object (e.g.,
// tr1::function<int(int)> is convertible to tr1::function<void(int)>).
//
// These are not features that are required in Chromium. Some of them, such as
// allowing for reference parameters, and subtyping of functions, may actually
// become a source of errors. Removing support for these features actually
// allows for a simpler implementation, and a terser Currying API.
//
//
// WHY NOT GOOGLE CALLBACKS?
//
// The Google callback system also does not support refcounting. Furthermore,
// its implementation has a number of strange edge cases with respect to type
// conversion of its arguments. In particular, the argument's constness must
// at times match exactly the function signature, or the type-inference might
// break. Given the above, writing a custom solution was easier.
//
//
// MISSING FUNCTIONALITY
// - Invoking the return of Bind. Bind(&foo).Run() does not work;
// - Binding arrays to functions that take a non-const pointer.
// Example:
// void Foo(const char* ptr);
// void Bar(char* ptr);
// Bind(&Foo, "test");
// Bind(&Bar, "test"); // This fails because ptr is not const.
namespace butil {
// First, we forward declare the Callback class template. This informs the
// compiler that the template only has 1 type parameter which is the function
// signature that the Callback is representing.
//
// After this, create template specializations for 0-7 parameters. Note that
// even though the template typelist grows, the specialization still
// only has one type: the function signature.
//
// If you are thinking of forward declaring Callback in your own header file,
// please include "butil/callback_forward.h" instead.
template <typename Sig>
class Callback;
namespace internal {
template <typename Runnable, typename RunType, typename BoundArgsType>
struct BindState;
} // namespace internal
template <typename R>
class Callback<R(void)> : public internal::CallbackBase {
public:
typedef R(RunType)();
Callback() : CallbackBase(NULL) { }
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
// return the exact Callback<> type. See butil/bind.h for details.
template <typename Runnable, typename BindRunType, typename BoundArgsType>
Callback(internal::BindState<Runnable, BindRunType,
BoundArgsType>* bind_state)
: CallbackBase(bind_state) {
// Force the assignment to a local variable of PolymorphicInvoke
// so the compiler will typecheck that the passed in Run() method has
// the correct type.
PolymorphicInvoke invoke_func =
&internal::BindState<Runnable, BindRunType, BoundArgsType>
::InvokerType::Run;
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
}
bool Equals(const Callback& other) const {
return CallbackBase::Equals(other);
}
R Run() const {
PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get());
}
private:
typedef R(*PolymorphicInvoke)(
internal::BindStateBase*);
};
template <typename R, typename A1>
class Callback<R(A1)> : public internal::CallbackBase {
public:
typedef R(RunType)(A1);
Callback() : CallbackBase(NULL) { }
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
// return the exact Callback<> type. See butil/bind.h for details.
template <typename Runnable, typename BindRunType, typename BoundArgsType>
Callback(internal::BindState<Runnable, BindRunType,
BoundArgsType>* bind_state)
: CallbackBase(bind_state) {
// Force the assignment to a local variable of PolymorphicInvoke
// so the compiler will typecheck that the passed in Run() method has
// the correct type.
PolymorphicInvoke invoke_func =
&internal::BindState<Runnable, BindRunType, BoundArgsType>
::InvokerType::Run;
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
}
bool Equals(const Callback& other) const {
return CallbackBase::Equals(other);
}
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1) const {
PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(a1));
}
private:
typedef R(*PolymorphicInvoke)(
internal::BindStateBase*,
typename internal::CallbackParamTraits<A1>::ForwardType);
};
template <typename R, typename A1, typename A2>
class Callback<R(A1, A2)> : public internal::CallbackBase {
public:
typedef R(RunType)(A1, A2);
Callback() : CallbackBase(NULL) { }
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
// return the exact Callback<> type. See butil/bind.h for details.
template <typename Runnable, typename BindRunType, typename BoundArgsType>
Callback(internal::BindState<Runnable, BindRunType,
BoundArgsType>* bind_state)
: CallbackBase(bind_state) {
// Force the assignment to a local variable of PolymorphicInvoke
// so the compiler will typecheck that the passed in Run() method has
// the correct type.
PolymorphicInvoke invoke_func =
&internal::BindState<Runnable, BindRunType, BoundArgsType>
::InvokerType::Run;
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
}
bool Equals(const Callback& other) const {
return CallbackBase::Equals(other);
}
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
typename internal::CallbackParamTraits<A2>::ForwardType a2) const {
PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(a1),
internal::CallbackForward(a2));
}
private:
typedef R(*PolymorphicInvoke)(
internal::BindStateBase*,
typename internal::CallbackParamTraits<A1>::ForwardType,
typename internal::CallbackParamTraits<A2>::ForwardType);
};
template <typename R, typename A1, typename A2, typename A3>
class Callback<R(A1, A2, A3)> : public internal::CallbackBase {
public:
typedef R(RunType)(A1, A2, A3);
Callback() : CallbackBase(NULL) { }
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
// return the exact Callback<> type. See butil/bind.h for details.
template <typename Runnable, typename BindRunType, typename BoundArgsType>
Callback(internal::BindState<Runnable, BindRunType,
BoundArgsType>* bind_state)
: CallbackBase(bind_state) {
// Force the assignment to a local variable of PolymorphicInvoke
// so the compiler will typecheck that the passed in Run() method has
// the correct type.
PolymorphicInvoke invoke_func =
&internal::BindState<Runnable, BindRunType, BoundArgsType>
::InvokerType::Run;
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
}
bool Equals(const Callback& other) const {
return CallbackBase::Equals(other);
}
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
typename internal::CallbackParamTraits<A2>::ForwardType a2,
typename internal::CallbackParamTraits<A3>::ForwardType a3) const {
PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(a1),
internal::CallbackForward(a2),
internal::CallbackForward(a3));
}
private:
typedef R(*PolymorphicInvoke)(
internal::BindStateBase*,
typename internal::CallbackParamTraits<A1>::ForwardType,
typename internal::CallbackParamTraits<A2>::ForwardType,
typename internal::CallbackParamTraits<A3>::ForwardType);
};
template <typename R, typename A1, typename A2, typename A3, typename A4>
class Callback<R(A1, A2, A3, A4)> : public internal::CallbackBase {
public:
typedef R(RunType)(A1, A2, A3, A4);
Callback() : CallbackBase(NULL) { }
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
// return the exact Callback<> type. See butil/bind.h for details.
template <typename Runnable, typename BindRunType, typename BoundArgsType>
Callback(internal::BindState<Runnable, BindRunType,
BoundArgsType>* bind_state)
: CallbackBase(bind_state) {
// Force the assignment to a local variable of PolymorphicInvoke
// so the compiler will typecheck that the passed in Run() method has
// the correct type.
PolymorphicInvoke invoke_func =
&internal::BindState<Runnable, BindRunType, BoundArgsType>
::InvokerType::Run;
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
}
bool Equals(const Callback& other) const {
return CallbackBase::Equals(other);
}
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
typename internal::CallbackParamTraits<A2>::ForwardType a2,
typename internal::CallbackParamTraits<A3>::ForwardType a3,
typename internal::CallbackParamTraits<A4>::ForwardType a4) const {
PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(a1),
internal::CallbackForward(a2),
internal::CallbackForward(a3),
internal::CallbackForward(a4));
}
private:
typedef R(*PolymorphicInvoke)(
internal::BindStateBase*,
typename internal::CallbackParamTraits<A1>::ForwardType,
typename internal::CallbackParamTraits<A2>::ForwardType,
typename internal::CallbackParamTraits<A3>::ForwardType,
typename internal::CallbackParamTraits<A4>::ForwardType);
};
template <typename R, typename A1, typename A2, typename A3, typename A4,
typename A5>
class Callback<R(A1, A2, A3, A4, A5)> : public internal::CallbackBase {
public:
typedef R(RunType)(A1, A2, A3, A4, A5);
Callback() : CallbackBase(NULL) { }
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
// return the exact Callback<> type. See butil/bind.h for details.
template <typename Runnable, typename BindRunType, typename BoundArgsType>
Callback(internal::BindState<Runnable, BindRunType,
BoundArgsType>* bind_state)
: CallbackBase(bind_state) {
// Force the assignment to a local variable of PolymorphicInvoke
// so the compiler will typecheck that the passed in Run() method has
// the correct type.
PolymorphicInvoke invoke_func =
&internal::BindState<Runnable, BindRunType, BoundArgsType>
::InvokerType::Run;
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
}
bool Equals(const Callback& other) const {
return CallbackBase::Equals(other);
}
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
typename internal::CallbackParamTraits<A2>::ForwardType a2,
typename internal::CallbackParamTraits<A3>::ForwardType a3,
typename internal::CallbackParamTraits<A4>::ForwardType a4,
typename internal::CallbackParamTraits<A5>::ForwardType a5) const {
PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(a1),
internal::CallbackForward(a2),
internal::CallbackForward(a3),
internal::CallbackForward(a4),
internal::CallbackForward(a5));
}
private:
typedef R(*PolymorphicInvoke)(
internal::BindStateBase*,
typename internal::CallbackParamTraits<A1>::ForwardType,
typename internal::CallbackParamTraits<A2>::ForwardType,
typename internal::CallbackParamTraits<A3>::ForwardType,
typename internal::CallbackParamTraits<A4>::ForwardType,
typename internal::CallbackParamTraits<A5>::ForwardType);
};
template <typename R, typename A1, typename A2, typename A3, typename A4,
typename A5, typename A6>
class Callback<R(A1, A2, A3, A4, A5, A6)> : public internal::CallbackBase {
public:
typedef R(RunType)(A1, A2, A3, A4, A5, A6);
Callback() : CallbackBase(NULL) { }
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
// return the exact Callback<> type. See butil/bind.h for details.
template <typename Runnable, typename BindRunType, typename BoundArgsType>
Callback(internal::BindState<Runnable, BindRunType,
BoundArgsType>* bind_state)
: CallbackBase(bind_state) {
// Force the assignment to a local variable of PolymorphicInvoke
// so the compiler will typecheck that the passed in Run() method has
// the correct type.
PolymorphicInvoke invoke_func =
&internal::BindState<Runnable, BindRunType, BoundArgsType>
::InvokerType::Run;
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
}
bool Equals(const Callback& other) const {
return CallbackBase::Equals(other);
}
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
typename internal::CallbackParamTraits<A2>::ForwardType a2,
typename internal::CallbackParamTraits<A3>::ForwardType a3,
typename internal::CallbackParamTraits<A4>::ForwardType a4,
typename internal::CallbackParamTraits<A5>::ForwardType a5,
typename internal::CallbackParamTraits<A6>::ForwardType a6) const {
PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(a1),
internal::CallbackForward(a2),
internal::CallbackForward(a3),
internal::CallbackForward(a4),
internal::CallbackForward(a5),
internal::CallbackForward(a6));
}
private:
typedef R(*PolymorphicInvoke)(
internal::BindStateBase*,
typename internal::CallbackParamTraits<A1>::ForwardType,
typename internal::CallbackParamTraits<A2>::ForwardType,
typename internal::CallbackParamTraits<A3>::ForwardType,
typename internal::CallbackParamTraits<A4>::ForwardType,
typename internal::CallbackParamTraits<A5>::ForwardType,
typename internal::CallbackParamTraits<A6>::ForwardType);
};
template <typename R, typename A1, typename A2, typename A3, typename A4,
typename A5, typename A6, typename A7>
class Callback<R(A1, A2, A3, A4, A5, A6, A7)> : public internal::CallbackBase {
public:
typedef R(RunType)(A1, A2, A3, A4, A5, A6, A7);
Callback() : CallbackBase(NULL) { }
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
// return the exact Callback<> type. See butil/bind.h for details.
template <typename Runnable, typename BindRunType, typename BoundArgsType>
Callback(internal::BindState<Runnable, BindRunType,
BoundArgsType>* bind_state)
: CallbackBase(bind_state) {
// Force the assignment to a local variable of PolymorphicInvoke
// so the compiler will typecheck that the passed in Run() method has
// the correct type.
PolymorphicInvoke invoke_func =
&internal::BindState<Runnable, BindRunType, BoundArgsType>
::InvokerType::Run;
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
}
bool Equals(const Callback& other) const {
return CallbackBase::Equals(other);
}
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
typename internal::CallbackParamTraits<A2>::ForwardType a2,
typename internal::CallbackParamTraits<A3>::ForwardType a3,
typename internal::CallbackParamTraits<A4>::ForwardType a4,
typename internal::CallbackParamTraits<A5>::ForwardType a5,
typename internal::CallbackParamTraits<A6>::ForwardType a6,
typename internal::CallbackParamTraits<A7>::ForwardType a7) const {
PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(a1),
internal::CallbackForward(a2),
internal::CallbackForward(a3),
internal::CallbackForward(a4),
internal::CallbackForward(a5),
internal::CallbackForward(a6),
internal::CallbackForward(a7));
}
private:
typedef R(*PolymorphicInvoke)(
internal::BindStateBase*,
typename internal::CallbackParamTraits<A1>::ForwardType,
typename internal::CallbackParamTraits<A2>::ForwardType,
typename internal::CallbackParamTraits<A3>::ForwardType,
typename internal::CallbackParamTraits<A4>::ForwardType,
typename internal::CallbackParamTraits<A5>::ForwardType,
typename internal::CallbackParamTraits<A6>::ForwardType,
typename internal::CallbackParamTraits<A7>::ForwardType);
};
// Syntactic sugar to make Callbacks<void(void)> easier to declare since it
// will be used in a lot of APIs with delayed execution.
typedef Callback<void(void)> Closure;
} // namespace butil
#endif // BASE_CALLBACK_H
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_CALLBACK_FORWARD_H_
#define BASE_CALLBACK_FORWARD_H_
namespace butil {
template <typename Sig>
class Callback;
typedef Callback<void(void)> Closure;
} // namespace butil
#endif // BASE_CALLBACK_FORWARD_H
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "butil/callback_helpers.h"
#include "butil/callback.h"
namespace butil {
ScopedClosureRunner::ScopedClosureRunner() {
}
ScopedClosureRunner::ScopedClosureRunner(const Closure& closure)
: closure_(closure) {
}
ScopedClosureRunner::~ScopedClosureRunner() {
if (!closure_.is_null())
closure_.Run();
}
void ScopedClosureRunner::Reset() {
Closure old_closure = Release();
if (!old_closure.is_null())
old_closure.Run();
}
void ScopedClosureRunner::Reset(const Closure& closure) {
Closure old_closure = Release();
closure_ = closure;
if (!old_closure.is_null())
old_closure.Run();
}
Closure ScopedClosureRunner::Release() {
Closure result = closure_;
closure_.Reset();
return result;
}
} // namespace butil
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This defines helpful methods for dealing with Callbacks. Because Callbacks
// are implemented using templates, with a class per callback signature, adding
// methods to Callback<> itself is unattractive (lots of extra code gets
// generated). Instead, consider adding methods here.
//
// ResetAndReturn(&cb) is like cb.Reset() but allows executing a callback (via a
// copy) after the original callback is Reset(). This can be handy if Run()
// reads/writes the variable holding the Callback.
#ifndef BASE_CALLBACK_HELPERS_H_
#define BASE_CALLBACK_HELPERS_H_
#include "butil/basictypes.h"
#include "butil/callback.h"
#include "butil/compiler_specific.h"
namespace butil {
template <typename Sig>
butil::Callback<Sig> ResetAndReturn(butil::Callback<Sig>* cb) {
butil::Callback<Sig> ret(*cb);
cb->Reset();
return ret;
}
// ScopedClosureRunner is akin to scoped_ptr for Closures. It ensures that the
// Closure is executed and deleted no matter how the current scope exits.
class BASE_EXPORT ScopedClosureRunner {
public:
ScopedClosureRunner();
explicit ScopedClosureRunner(const Closure& closure);
~ScopedClosureRunner();
void Reset();
void Reset(const Closure& closure);
Closure Release() WARN_UNUSED_RESULT;
private:
Closure closure_;
DISALLOW_COPY_AND_ASSIGN(ScopedClosureRunner);
};
} // namespace butil
#endif // BASE_CALLBACK_HELPERS_H_
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "butil/callback_internal.h"
#include "butil/logging.h"
namespace butil {
namespace internal {
bool CallbackBase::is_null() const {
return bind_state_.get() == NULL;
}
void CallbackBase::Reset() {
polymorphic_invoke_ = NULL;
// NULL the bind_state_ last, since it may be holding the last ref to whatever
// object owns us, and we may be deleted after that.
bind_state_ = NULL;
}
bool CallbackBase::Equals(const CallbackBase& other) const {
return bind_state_.get() == other.bind_state_.get() &&
polymorphic_invoke_ == other.polymorphic_invoke_;
}
CallbackBase::CallbackBase(BindStateBase* bind_state)
: bind_state_(bind_state),
polymorphic_invoke_(NULL) {
DCHECK(!bind_state_.get() || bind_state_->HasOneRef());
}
CallbackBase::~CallbackBase() {
}
} // namespace internal
} // namespace butil
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file contains utility functions and classes that help the
// implementation, and management of the Callback objects.
#ifndef BASE_CALLBACK_INTERNAL_H_
#define BASE_CALLBACK_INTERNAL_H_
#include <stddef.h>
#include "butil/base_export.h"
#include "butil/memory/ref_counted.h"
#include "butil/memory/scoped_ptr.h"
template <typename T>
class ScopedVector;
namespace butil {
namespace internal {
// BindStateBase is used to provide an opaque handle that the Callback
// class can use to represent a function object with bound arguments. It
// behaves as an existential type that is used by a corresponding
// DoInvoke function to perform the function execution. This allows
// us to shield the Callback class from the types of the bound argument via
// "type erasure."
class BindStateBase : public RefCountedThreadSafe<BindStateBase> {
protected:
friend class RefCountedThreadSafe<BindStateBase>;
virtual ~BindStateBase() {}
};
// Holds the Callback methods that don't require specialization to reduce
// template bloat.
class BASE_EXPORT CallbackBase {
public:
// Returns true if Callback is null (doesn't refer to anything).
bool is_null() const;
// Returns the Callback into an uninitialized state.
void Reset();
protected:
// In C++, it is safe to cast function pointers to function pointers of
// another type. It is not okay to use void*. We create a InvokeFuncStorage
// that that can store our function pointer, and then cast it back to
// the original type on usage.
typedef void(*InvokeFuncStorage)(void);
// Returns true if this callback equals |other|. |other| may be null.
bool Equals(const CallbackBase& other) const;
// Allow initializing of |bind_state_| via the constructor to avoid default
// initialization of the scoped_refptr. We do not also initialize
// |polymorphic_invoke_| here because doing a normal assignment in the
// derived Callback templates makes for much nicer compiler errors.
explicit CallbackBase(BindStateBase* bind_state);
// Force the destructor to be instantiated inside this translation unit so
// that our subclasses will not get inlined versions. Avoids more template
// bloat.
~CallbackBase();
scoped_refptr<BindStateBase> bind_state_;
InvokeFuncStorage polymorphic_invoke_;
};
// A helper template to determine if given type is non-const move-only-type,
// i.e. if a value of the given type should be passed via .Pass() in a
// destructive way.
template <typename T> struct IsMoveOnlyType {
template <typename U>
static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
template <typename U>
static NoType Test(...);
static const bool value = sizeof(Test<T>(0)) == sizeof(YesType) &&
!is_const<T>::value;
};
// This is a typetraits object that's used to take an argument type, and
// extract a suitable type for storing and forwarding arguments.
//
// In particular, it strips off references, and converts arrays to
// pointers for storage; and it avoids accidentally trying to create a
// "reference of a reference" if the argument is a reference type.
//
// This array type becomes an issue for storage because we are passing bound
// parameters by const reference. In this case, we end up passing an actual
// array type in the initializer list which C++ does not allow. This will
// break passing of C-string literals.
template <typename T, bool is_move_only = IsMoveOnlyType<T>::value>
struct CallbackParamTraits {
typedef const T& ForwardType;
typedef T StorageType;
};
// The Storage should almost be impossible to trigger unless someone manually
// specifies type of the bind parameters. However, in case they do,
// this will guard against us accidentally storing a reference parameter.
//
// The ForwardType should only be used for unbound arguments.
template <typename T>
struct CallbackParamTraits<T&, false> {
typedef T& ForwardType;
typedef T StorageType;
};
// Note that for array types, we implicitly add a const in the conversion. This
// means that it is not possible to bind array arguments to functions that take
// a non-const pointer. Trying to specialize the template based on a "const
// T[n]" does not seem to match correctly, so we are stuck with this
// restriction.
template <typename T, size_t n>
struct CallbackParamTraits<T[n], false> {
typedef const T* ForwardType;
typedef const T* StorageType;
};
// See comment for CallbackParamTraits<T[n]>.
template <typename T>
struct CallbackParamTraits<T[], false> {
typedef const T* ForwardType;
typedef const T* StorageType;
};
// Parameter traits for movable-but-not-copyable scopers.
//
// Callback<>/Bind() understands movable-but-not-copyable semantics where
// the type cannot be copied but can still have its state destructively
// transferred (aka. moved) to another instance of the same type by calling a
// helper function. When used with Bind(), this signifies transferal of the
// object's state to the target function.
//
// For these types, the ForwardType must not be a const reference, or a
// reference. A const reference is inappropriate, and would break const
// correctness, because we are implementing a destructive move. A non-const
// reference cannot be used with temporaries which means the result of a
// function or a cast would not be usable with Callback<> or Bind().
template <typename T>
struct CallbackParamTraits<T, true> {
typedef T ForwardType;
typedef T StorageType;
};
// CallbackForward() is a very limited simulation of C++11's std::forward()
// used by the Callback/Bind system for a set of movable-but-not-copyable
// types. It is needed because forwarding a movable-but-not-copyable
// argument to another function requires us to invoke the proper move
// operator to create a rvalue version of the type. The supported types are
// whitelisted below as overloads of the CallbackForward() function. The
// default template compiles out to be a no-op.
//
// In C++11, std::forward would replace all uses of this function. However, it
// is impossible to implement a general std::forward with C++11 due to a lack
// of rvalue references.
//
// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
// simulate std::forward() and forward the result of one Callback as a
// parameter to another callback. This is to support Callbacks that return
// the movable-but-not-copyable types whitelisted above.
template <typename T>
typename enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(T& t) {
return t;
}
template <typename T>
typename enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(T& t) {
return t.Pass();
}
} // namespace internal
} // namespace butil
#endif // BASE_CALLBACK_INTERNAL_H_
// This file was GENERATED by command:
// pump.py callback_list.h.pump
// DO NOT EDIT BY HAND!!!
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_CALLBACK_LIST_H_
#define BASE_CALLBACK_LIST_H_
#include <list>
#include "butil/basictypes.h"
#include "butil/callback.h"
#include "butil/callback_internal.h"
#include "butil/compiler_specific.h"
#include "butil/logging.h"
#include "butil/memory/scoped_ptr.h"
// OVERVIEW:
//
// A container for a list of callbacks. Unlike a normal STL vector or list,
// this container can be modified during iteration without invalidating the
// iterator. It safely handles the case of a callback removing itself
// or another callback from the list while callbacks are being run.
//
// TYPICAL USAGE:
//
// class MyWidget {
// public:
// ...
//
// typedef butil::Callback<void(const Foo&)> OnFooCallback;
//
// scoped_ptr<butil::CallbackList<void(const Foo&)>::Subscription>
// RegisterCallback(const OnFooCallback& cb) {
// return callback_list_.Add(cb);
// }
//
// private:
// void NotifyFoo(const Foo& foo) {
// callback_list_.Notify(foo);
// }
//
// butil::CallbackList<void(const Foo&)> callback_list_;
//
// DISALLOW_COPY_AND_ASSIGN(MyWidget);
// };
//
//
// class MyWidgetListener {
// public:
// MyWidgetListener::MyWidgetListener() {
// foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
// butil::Bind(&MyWidgetListener::OnFoo, this)));
// }
//
// MyWidgetListener::~MyWidgetListener() {
// // Subscription gets deleted automatically and will deregister
// // the callback in the process.
// }
//
// private:
// void OnFoo(const Foo& foo) {
// // Do something.
// }
//
// scoped_ptr<butil::CallbackList<void(const Foo&)>::Subscription>
// foo_subscription_;
//
// DISALLOW_COPY_AND_ASSIGN(MyWidgetListener);
// };
namespace butil {
namespace internal {
template <typename CallbackType>
class CallbackListBase {
public:
class Subscription {
public:
Subscription(CallbackListBase<CallbackType>* list,
typename std::list<CallbackType>::iterator iter)
: list_(list),
iter_(iter) {
}
~Subscription() {
if (list_->active_iterator_count_) {
iter_->Reset();
} else {
list_->callbacks_.erase(iter_);
if (!list_->removal_callback_.is_null())
list_->removal_callback_.Run();
}
}
private:
CallbackListBase<CallbackType>* list_;
typename std::list<CallbackType>::iterator iter_;
DISALLOW_COPY_AND_ASSIGN(Subscription);
};
// Add a callback to the list. The callback will remain registered until the
// returned Subscription is destroyed, which must occur before the
// CallbackList is destroyed.
scoped_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
DCHECK(!cb.is_null());
return scoped_ptr<Subscription>(
new Subscription(this, callbacks_.insert(callbacks_.end(), cb)));
}
// Sets a callback which will be run when a subscription list is changed.
void set_removal_callback(const Closure& callback) {
removal_callback_ = callback;
}
// Returns true if there are no subscriptions. This is only valid to call when
// not looping through the list.
bool empty() {
DCHECK_EQ(0, active_iterator_count_);
return callbacks_.empty();
}
protected:
// An iterator class that can be used to access the list of callbacks.
class Iterator {
public:
explicit Iterator(CallbackListBase<CallbackType>* list)
: list_(list),
list_iter_(list_->callbacks_.begin()) {
++list_->active_iterator_count_;
}
Iterator(const Iterator& iter)
: list_(iter.list_),
list_iter_(iter.list_iter_) {
++list_->active_iterator_count_;
}
~Iterator() {
if (list_ && --list_->active_iterator_count_ == 0) {
list_->Compact();
}
}
CallbackType* GetNext() {
while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
++list_iter_;
CallbackType* cb = NULL;
if (list_iter_ != list_->callbacks_.end()) {
cb = &(*list_iter_);
++list_iter_;
}
return cb;
}
private:
CallbackListBase<CallbackType>* list_;
typename std::list<CallbackType>::iterator list_iter_;
};
CallbackListBase() : active_iterator_count_(0) {}
~CallbackListBase() {
DCHECK_EQ(0, active_iterator_count_);
DCHECK_EQ(0U, callbacks_.size());
}
// Returns an instance of a CallbackListBase::Iterator which can be used
// to run callbacks.
Iterator GetIterator() {
return Iterator(this);
}
// Compact the list: remove any entries which were NULLed out during
// iteration.
void Compact() {
typename std::list<CallbackType>::iterator it = callbacks_.begin();
bool updated = false;
while (it != callbacks_.end()) {
if ((*it).is_null()) {
updated = true;
it = callbacks_.erase(it);
} else {
++it;
}
if (updated && !removal_callback_.is_null())
removal_callback_.Run();
}
}
private:
std::list<CallbackType> callbacks_;
int active_iterator_count_;
Closure removal_callback_;
DISALLOW_COPY_AND_ASSIGN(CallbackListBase);
};
} // namespace internal
template <typename Sig> class CallbackList;
template <>
class CallbackList<void(void)>
: public internal::CallbackListBase<Callback<void(void)> > {
public:
typedef Callback<void(void)> CallbackType;
CallbackList() {}
void Notify() {
internal::CallbackListBase<CallbackType>::Iterator it =
this->GetIterator();
CallbackType* cb;
while ((cb = it.GetNext()) != NULL) {
cb->Run();
}
}
private:
DISALLOW_COPY_AND_ASSIGN(CallbackList);
};
template <typename A1>
class CallbackList<void(A1)>
: public internal::CallbackListBase<Callback<void(A1)> > {
public:
typedef Callback<void(A1)> CallbackType;
CallbackList() {}
void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1) {
typename internal::CallbackListBase<CallbackType>::Iterator it =
this->GetIterator();
CallbackType* cb;
while ((cb = it.GetNext()) != NULL) {
cb->Run(a1);
}
}
private:
DISALLOW_COPY_AND_ASSIGN(CallbackList);
};
template <typename A1, typename A2>
class CallbackList<void(A1, A2)>
: public internal::CallbackListBase<Callback<void(A1, A2)> > {
public:
typedef Callback<void(A1, A2)> CallbackType;
CallbackList() {}
void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1,
typename internal::CallbackParamTraits<A2>::ForwardType a2) {
typename internal::CallbackListBase<CallbackType>::Iterator it =
this->GetIterator();
CallbackType* cb;
while ((cb = it.GetNext()) != NULL) {
cb->Run(a1, a2);
}
}
private:
DISALLOW_COPY_AND_ASSIGN(CallbackList);
};
template <typename A1, typename A2, typename A3>
class CallbackList<void(A1, A2, A3)>
: public internal::CallbackListBase<Callback<void(A1, A2, A3)> > {
public:
typedef Callback<void(A1, A2, A3)> CallbackType;
CallbackList() {}
void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1,
typename internal::CallbackParamTraits<A2>::ForwardType a2,
typename internal::CallbackParamTraits<A3>::ForwardType a3) {
typename internal::CallbackListBase<CallbackType>::Iterator it =
this->GetIterator();
CallbackType* cb;
while ((cb = it.GetNext()) != NULL) {
cb->Run(a1, a2, a3);
}
}
private:
DISALLOW_COPY_AND_ASSIGN(CallbackList);
};
template <typename A1, typename A2, typename A3, typename A4>
class CallbackList<void(A1, A2, A3, A4)>
: public internal::CallbackListBase<Callback<void(A1, A2, A3, A4)> > {
public:
typedef Callback<void(A1, A2, A3, A4)> CallbackType;
CallbackList() {}
void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1,
typename internal::CallbackParamTraits<A2>::ForwardType a2,
typename internal::CallbackParamTraits<A3>::ForwardType a3,
typename internal::CallbackParamTraits<A4>::ForwardType a4) {
typename internal::CallbackListBase<CallbackType>::Iterator it =
this->GetIterator();
CallbackType* cb;
while ((cb = it.GetNext()) != NULL) {
cb->Run(a1, a2, a3, a4);
}
}
private:
DISALLOW_COPY_AND_ASSIGN(CallbackList);
};
template <typename A1, typename A2, typename A3, typename A4, typename A5>
class CallbackList<void(A1, A2, A3, A4, A5)>
: public internal::CallbackListBase<Callback<void(A1, A2, A3, A4, A5)> > {
public:
typedef Callback<void(A1, A2, A3, A4, A5)> CallbackType;
CallbackList() {}
void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1,
typename internal::CallbackParamTraits<A2>::ForwardType a2,
typename internal::CallbackParamTraits<A3>::ForwardType a3,
typename internal::CallbackParamTraits<A4>::ForwardType a4,
typename internal::CallbackParamTraits<A5>::ForwardType a5) {
typename internal::CallbackListBase<CallbackType>::Iterator it =
this->GetIterator();
CallbackType* cb;
while ((cb = it.GetNext()) != NULL) {
cb->Run(a1, a2, a3, a4, a5);
}
}
private:
DISALLOW_COPY_AND_ASSIGN(CallbackList);
};
template <typename A1, typename A2, typename A3, typename A4, typename A5,
typename A6>
class CallbackList<void(A1, A2, A3, A4, A5, A6)>
: public internal::CallbackListBase<Callback<void(A1, A2, A3, A4, A5,
A6)> > {
public:
typedef Callback<void(A1, A2, A3, A4, A5, A6)> CallbackType;
CallbackList() {}
void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1,
typename internal::CallbackParamTraits<A2>::ForwardType a2,
typename internal::CallbackParamTraits<A3>::ForwardType a3,
typename internal::CallbackParamTraits<A4>::ForwardType a4,
typename internal::CallbackParamTraits<A5>::ForwardType a5,
typename internal::CallbackParamTraits<A6>::ForwardType a6) {
typename internal::CallbackListBase<CallbackType>::Iterator it =
this->GetIterator();
CallbackType* cb;
while ((cb = it.GetNext()) != NULL) {
cb->Run(a1, a2, a3, a4, a5, a6);
}
}
private:
DISALLOW_COPY_AND_ASSIGN(CallbackList);
};
template <typename A1, typename A2, typename A3, typename A4, typename A5,
typename A6, typename A7>
class CallbackList<void(A1, A2, A3, A4, A5, A6, A7)>
: public internal::CallbackListBase<Callback<void(A1, A2, A3, A4, A5, A6,
A7)> > {
public:
typedef Callback<void(A1, A2, A3, A4, A5, A6, A7)> CallbackType;
CallbackList() {}
void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1,
typename internal::CallbackParamTraits<A2>::ForwardType a2,
typename internal::CallbackParamTraits<A3>::ForwardType a3,
typename internal::CallbackParamTraits<A4>::ForwardType a4,
typename internal::CallbackParamTraits<A5>::ForwardType a5,
typename internal::CallbackParamTraits<A6>::ForwardType a6,
typename internal::CallbackParamTraits<A7>::ForwardType a7) {
typename internal::CallbackListBase<CallbackType>::Iterator it =
this->GetIterator();
CallbackType* cb;
while ((cb = it.GetNext()) != NULL) {
cb->Run(a1, a2, a3, a4, a5, a6, a7);
}
}
private:
DISALLOW_COPY_AND_ASSIGN(CallbackList);
};
} // namespace butil
#endif // BASE_CALLBACK_LIST_H_
......@@ -7,7 +7,6 @@
#include "butil/memory/ref_counted.h"
#include "butil/type_traits.h"
#include "butil/tuple.h"
#include "butil/build_config.h"
// It is dangerous to post a task with a T* argument where T is a subtype of
......
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// A Tuple is a generic templatized container, similar in concept to std::pair.
// There are classes Tuple0 to Tuple6, cooresponding to the number of elements
// it contains. The convenient MakeTuple() function takes 0 to 6 arguments,
// and will construct and return the appropriate Tuple object. The functions
// DispatchToMethod and DispatchToFunction take a function pointer or instance
// and method pointer, and unpack a tuple into arguments to the call.
//
// Tuple elements are copied by value, and stored in the tuple. See the unit
// tests for more details of how/when the values are copied.
//
// Example usage:
// // These two methods of creating a Tuple are identical.
// Tuple2<int, const char*> tuple_a(1, "wee");
// Tuple2<int, const char*> tuple_b = MakeTuple(1, "wee");
//
// void SomeFunc(int a, const char* b) { }
// DispatchToFunction(&SomeFunc, tuple_a); // SomeFunc(1, "wee")
// DispatchToFunction(
// &SomeFunc, MakeTuple(10, "foo")); // SomeFunc(10, "foo")
//
// struct { void SomeMeth(int a, int b, int c) { } } foo;
// DispatchToMethod(&foo, &Foo::SomeMeth, MakeTuple(1, 2, 3));
// // foo->SomeMeth(1, 2, 3);
#ifndef BASE_TUPLE_H__
#define BASE_TUPLE_H__
#include "butil/bind_helpers.h"
// Traits ----------------------------------------------------------------------
//
// A simple traits class for tuple arguments.
//
// ValueType: the bare, nonref version of a type (same as the type for nonrefs).
// RefType: the ref version of a type (same as the type for refs).
// ParamType: what type to pass to functions (refs should not be constified).
template <class P>
struct TupleTraits {
typedef P ValueType;
typedef P& RefType;
typedef const P& ParamType;
};
template <class P>
struct TupleTraits<P&> {
typedef P ValueType;
typedef P& RefType;
typedef P& ParamType;
};
template <class P>
struct TupleTypes { };
// Tuple -----------------------------------------------------------------------
//
// This set of classes is useful for bundling 0 or more heterogeneous data types
// into a single variable. The advantage of this is that it greatly simplifies
// function objects that need to take an arbitrary number of parameters; see
// RunnableMethod and IPC::MessageWithTuple.
//
// Tuple0 is supplied to act as a 'void' type. It can be used, for example,
// when dispatching to a function that accepts no arguments (see the
// Dispatchers below).
// Tuple1<A> is rarely useful. One such use is when A is non-const ref that you
// want filled by the dispatchee, and the tuple is merely a container for that
// output (a "tier"). See MakeRefTuple and its usages.
struct Tuple0 {
typedef Tuple0 ValueTuple;
typedef Tuple0 RefTuple;
typedef Tuple0 ParamTuple;
};
template <class A>
struct Tuple1 {
public:
typedef A TypeA;
Tuple1() {}
explicit Tuple1(typename TupleTraits<A>::ParamType a) : a(a) {}
A a;
};
template <class A, class B>
struct Tuple2 {
public:
typedef A TypeA;
typedef B TypeB;
Tuple2() {}
Tuple2(typename TupleTraits<A>::ParamType a,
typename TupleTraits<B>::ParamType b)
: a(a), b(b) {
}
A a;
B b;
};
template <class A, class B, class C>
struct Tuple3 {
public:
typedef A TypeA;
typedef B TypeB;
typedef C TypeC;
Tuple3() {}
Tuple3(typename TupleTraits<A>::ParamType a,
typename TupleTraits<B>::ParamType b,
typename TupleTraits<C>::ParamType c)
: a(a), b(b), c(c){
}
A a;
B b;
C c;
};
template <class A, class B, class C, class D>
struct Tuple4 {
public:
typedef A TypeA;
typedef B TypeB;
typedef C TypeC;
typedef D TypeD;
Tuple4() {}
Tuple4(typename TupleTraits<A>::ParamType a,
typename TupleTraits<B>::ParamType b,
typename TupleTraits<C>::ParamType c,
typename TupleTraits<D>::ParamType d)
: a(a), b(b), c(c), d(d) {
}
A a;
B b;
C c;
D d;
};
template <class A, class B, class C, class D, class E>
struct Tuple5 {
public:
typedef A TypeA;
typedef B TypeB;
typedef C TypeC;
typedef D TypeD;
typedef E TypeE;
Tuple5() {}
Tuple5(typename TupleTraits<A>::ParamType a,
typename TupleTraits<B>::ParamType b,
typename TupleTraits<C>::ParamType c,
typename TupleTraits<D>::ParamType d,
typename TupleTraits<E>::ParamType e)
: a(a), b(b), c(c), d(d), e(e) {
}
A a;
B b;
C c;
D d;
E e;
};
template <class A, class B, class C, class D, class E, class F>
struct Tuple6 {
public:
typedef A TypeA;
typedef B TypeB;
typedef C TypeC;
typedef D TypeD;
typedef E TypeE;
typedef F TypeF;
Tuple6() {}
Tuple6(typename TupleTraits<A>::ParamType a,
typename TupleTraits<B>::ParamType b,
typename TupleTraits<C>::ParamType c,
typename TupleTraits<D>::ParamType d,
typename TupleTraits<E>::ParamType e,
typename TupleTraits<F>::ParamType f)
: a(a), b(b), c(c), d(d), e(e), f(f) {
}
A a;
B b;
C c;
D d;
E e;
F f;
};
template <class A, class B, class C, class D, class E, class F, class G>
struct Tuple7 {
public:
typedef A TypeA;
typedef B TypeB;
typedef C TypeC;
typedef D TypeD;
typedef E TypeE;
typedef F TypeF;
typedef G TypeG;
Tuple7() {}
Tuple7(typename TupleTraits<A>::ParamType a,
typename TupleTraits<B>::ParamType b,
typename TupleTraits<C>::ParamType c,
typename TupleTraits<D>::ParamType d,
typename TupleTraits<E>::ParamType e,
typename TupleTraits<F>::ParamType f,
typename TupleTraits<G>::ParamType g)
: a(a), b(b), c(c), d(d), e(e), f(f), g(g) {
}
A a;
B b;
C c;
D d;
E e;
F f;
G g;
};
template <class A, class B, class C, class D, class E, class F, class G,
class H>
struct Tuple8 {
public:
typedef A TypeA;
typedef B TypeB;
typedef C TypeC;
typedef D TypeD;
typedef E TypeE;
typedef F TypeF;
typedef G TypeG;
typedef H TypeH;
Tuple8() {}
Tuple8(typename TupleTraits<A>::ParamType a,
typename TupleTraits<B>::ParamType b,
typename TupleTraits<C>::ParamType c,
typename TupleTraits<D>::ParamType d,
typename TupleTraits<E>::ParamType e,
typename TupleTraits<F>::ParamType f,
typename TupleTraits<G>::ParamType g,
typename TupleTraits<H>::ParamType h)
: a(a), b(b), c(c), d(d), e(e), f(f), g(g), h(h) {
}
A a;
B b;
C c;
D d;
E e;
F f;
G g;
H h;
};
// Tuple types ----------------------------------------------------------------
//
// Allows for selection of ValueTuple/RefTuple/ParamTuple without needing the
// definitions of class types the tuple takes as parameters.
template <>
struct TupleTypes< Tuple0 > {
typedef Tuple0 ValueTuple;
typedef Tuple0 RefTuple;
typedef Tuple0 ParamTuple;
};
template <class A>
struct TupleTypes< Tuple1<A> > {
typedef Tuple1<typename TupleTraits<A>::ValueType> ValueTuple;
typedef Tuple1<typename TupleTraits<A>::RefType> RefTuple;
typedef Tuple1<typename TupleTraits<A>::ParamType> ParamTuple;
};
template <class A, class B>
struct TupleTypes< Tuple2<A, B> > {
typedef Tuple2<typename TupleTraits<A>::ValueType,
typename TupleTraits<B>::ValueType> ValueTuple;
typedef Tuple2<typename TupleTraits<A>::RefType,
typename TupleTraits<B>::RefType> RefTuple;
typedef Tuple2<typename TupleTraits<A>::ParamType,
typename TupleTraits<B>::ParamType> ParamTuple;
};
template <class A, class B, class C>
struct TupleTypes< Tuple3<A, B, C> > {
typedef Tuple3<typename TupleTraits<A>::ValueType,
typename TupleTraits<B>::ValueType,
typename TupleTraits<C>::ValueType> ValueTuple;
typedef Tuple3<typename TupleTraits<A>::RefType,
typename TupleTraits<B>::RefType,
typename TupleTraits<C>::RefType> RefTuple;
typedef Tuple3<typename TupleTraits<A>::ParamType,
typename TupleTraits<B>::ParamType,
typename TupleTraits<C>::ParamType> ParamTuple;
};
template <class A, class B, class C, class D>
struct TupleTypes< Tuple4<A, B, C, D> > {
typedef Tuple4<typename TupleTraits<A>::ValueType,
typename TupleTraits<B>::ValueType,
typename TupleTraits<C>::ValueType,
typename TupleTraits<D>::ValueType> ValueTuple;
typedef Tuple4<typename TupleTraits<A>::RefType,
typename TupleTraits<B>::RefType,
typename TupleTraits<C>::RefType,
typename TupleTraits<D>::RefType> RefTuple;
typedef Tuple4<typename TupleTraits<A>::ParamType,
typename TupleTraits<B>::ParamType,
typename TupleTraits<C>::ParamType,
typename TupleTraits<D>::ParamType> ParamTuple;
};
template <class A, class B, class C, class D, class E>
struct TupleTypes< Tuple5<A, B, C, D, E> > {
typedef Tuple5<typename TupleTraits<A>::ValueType,
typename TupleTraits<B>::ValueType,
typename TupleTraits<C>::ValueType,
typename TupleTraits<D>::ValueType,
typename TupleTraits<E>::ValueType> ValueTuple;
typedef Tuple5<typename TupleTraits<A>::RefType,
typename TupleTraits<B>::RefType,
typename TupleTraits<C>::RefType,
typename TupleTraits<D>::RefType,
typename TupleTraits<E>::RefType> RefTuple;
typedef Tuple5<typename TupleTraits<A>::ParamType,
typename TupleTraits<B>::ParamType,
typename TupleTraits<C>::ParamType,
typename TupleTraits<D>::ParamType,
typename TupleTraits<E>::ParamType> ParamTuple;
};
template <class A, class B, class C, class D, class E, class F>
struct TupleTypes< Tuple6<A, B, C, D, E, F> > {
typedef Tuple6<typename TupleTraits<A>::ValueType,
typename TupleTraits<B>::ValueType,
typename TupleTraits<C>::ValueType,
typename TupleTraits<D>::ValueType,
typename TupleTraits<E>::ValueType,
typename TupleTraits<F>::ValueType> ValueTuple;
typedef Tuple6<typename TupleTraits<A>::RefType,
typename TupleTraits<B>::RefType,
typename TupleTraits<C>::RefType,
typename TupleTraits<D>::RefType,
typename TupleTraits<E>::RefType,
typename TupleTraits<F>::RefType> RefTuple;
typedef Tuple6<typename TupleTraits<A>::ParamType,
typename TupleTraits<B>::ParamType,
typename TupleTraits<C>::ParamType,
typename TupleTraits<D>::ParamType,
typename TupleTraits<E>::ParamType,
typename TupleTraits<F>::ParamType> ParamTuple;
};
template <class A, class B, class C, class D, class E, class F, class G>
struct TupleTypes< Tuple7<A, B, C, D, E, F, G> > {
typedef Tuple7<typename TupleTraits<A>::ValueType,
typename TupleTraits<B>::ValueType,
typename TupleTraits<C>::ValueType,
typename TupleTraits<D>::ValueType,
typename TupleTraits<E>::ValueType,
typename TupleTraits<F>::ValueType,
typename TupleTraits<G>::ValueType> ValueTuple;
typedef Tuple7<typename TupleTraits<A>::RefType,
typename TupleTraits<B>::RefType,
typename TupleTraits<C>::RefType,
typename TupleTraits<D>::RefType,
typename TupleTraits<E>::RefType,
typename TupleTraits<F>::RefType,
typename TupleTraits<G>::RefType> RefTuple;
typedef Tuple7<typename TupleTraits<A>::ParamType,
typename TupleTraits<B>::ParamType,
typename TupleTraits<C>::ParamType,
typename TupleTraits<D>::ParamType,
typename TupleTraits<E>::ParamType,
typename TupleTraits<F>::ParamType,
typename TupleTraits<G>::ParamType> ParamTuple;
};
template <class A, class B, class C, class D, class E, class F, class G,
class H>
struct TupleTypes< Tuple8<A, B, C, D, E, F, G, H> > {
typedef Tuple8<typename TupleTraits<A>::ValueType,
typename TupleTraits<B>::ValueType,
typename TupleTraits<C>::ValueType,
typename TupleTraits<D>::ValueType,
typename TupleTraits<E>::ValueType,
typename TupleTraits<F>::ValueType,
typename TupleTraits<G>::ValueType,
typename TupleTraits<H>::ValueType> ValueTuple;
typedef Tuple8<typename TupleTraits<A>::RefType,
typename TupleTraits<B>::RefType,
typename TupleTraits<C>::RefType,
typename TupleTraits<D>::RefType,
typename TupleTraits<E>::RefType,
typename TupleTraits<F>::RefType,
typename TupleTraits<G>::RefType,
typename TupleTraits<H>::RefType> RefTuple;
typedef Tuple8<typename TupleTraits<A>::ParamType,
typename TupleTraits<B>::ParamType,
typename TupleTraits<C>::ParamType,
typename TupleTraits<D>::ParamType,
typename TupleTraits<E>::ParamType,
typename TupleTraits<F>::ParamType,
typename TupleTraits<G>::ParamType,
typename TupleTraits<H>::ParamType> ParamTuple;
};
// Tuple creators -------------------------------------------------------------
//
// Helper functions for constructing tuples while inferring the template
// argument types.
inline Tuple0 MakeTuple() {
return Tuple0();
}
template <class A>
inline Tuple1<A> MakeTuple(const A& a) {
return Tuple1<A>(a);
}
template <class A, class B>
inline Tuple2<A, B> MakeTuple(const A& a, const B& b) {
return Tuple2<A, B>(a, b);
}
template <class A, class B, class C>
inline Tuple3<A, B, C> MakeTuple(const A& a, const B& b, const C& c) {
return Tuple3<A, B, C>(a, b, c);
}
template <class A, class B, class C, class D>
inline Tuple4<A, B, C, D> MakeTuple(const A& a, const B& b, const C& c,
const D& d) {
return Tuple4<A, B, C, D>(a, b, c, d);
}
template <class A, class B, class C, class D, class E>
inline Tuple5<A, B, C, D, E> MakeTuple(const A& a, const B& b, const C& c,
const D& d, const E& e) {
return Tuple5<A, B, C, D, E>(a, b, c, d, e);
}
template <class A, class B, class C, class D, class E, class F>
inline Tuple6<A, B, C, D, E, F> MakeTuple(const A& a, const B& b, const C& c,
const D& d, const E& e, const F& f) {
return Tuple6<A, B, C, D, E, F>(a, b, c, d, e, f);
}
template <class A, class B, class C, class D, class E, class F, class G>
inline Tuple7<A, B, C, D, E, F, G> MakeTuple(const A& a, const B& b, const C& c,
const D& d, const E& e, const F& f,
const G& g) {
return Tuple7<A, B, C, D, E, F, G>(a, b, c, d, e, f, g);
}
template <class A, class B, class C, class D, class E, class F, class G,
class H>
inline Tuple8<A, B, C, D, E, F, G, H> MakeTuple(const A& a, const B& b,
const C& c, const D& d,
const E& e, const F& f,
const G& g, const H& h) {
return Tuple8<A, B, C, D, E, F, G, H>(a, b, c, d, e, f, g, h);
}
// The following set of helpers make what Boost refers to as "Tiers" - a tuple
// of references.
template <class A>
inline Tuple1<A&> MakeRefTuple(A& a) {
return Tuple1<A&>(a);
}
template <class A, class B>
inline Tuple2<A&, B&> MakeRefTuple(A& a, B& b) {
return Tuple2<A&, B&>(a, b);
}
template <class A, class B, class C>
inline Tuple3<A&, B&, C&> MakeRefTuple(A& a, B& b, C& c) {
return Tuple3<A&, B&, C&>(a, b, c);
}
template <class A, class B, class C, class D>
inline Tuple4<A&, B&, C&, D&> MakeRefTuple(A& a, B& b, C& c, D& d) {
return Tuple4<A&, B&, C&, D&>(a, b, c, d);
}
template <class A, class B, class C, class D, class E>
inline Tuple5<A&, B&, C&, D&, E&> MakeRefTuple(A& a, B& b, C& c, D& d, E& e) {
return Tuple5<A&, B&, C&, D&, E&>(a, b, c, d, e);
}
template <class A, class B, class C, class D, class E, class F>
inline Tuple6<A&, B&, C&, D&, E&, F&> MakeRefTuple(A& a, B& b, C& c, D& d, E& e,
F& f) {
return Tuple6<A&, B&, C&, D&, E&, F&>(a, b, c, d, e, f);
}
template <class A, class B, class C, class D, class E, class F, class G>
inline Tuple7<A&, B&, C&, D&, E&, F&, G&> MakeRefTuple(A& a, B& b, C& c, D& d,
E& e, F& f, G& g) {
return Tuple7<A&, B&, C&, D&, E&, F&, G&>(a, b, c, d, e, f, g);
}
template <class A, class B, class C, class D, class E, class F, class G,
class H>
inline Tuple8<A&, B&, C&, D&, E&, F&, G&, H&> MakeRefTuple(A& a, B& b, C& c,
D& d, E& e, F& f,
G& g, H& h) {
return Tuple8<A&, B&, C&, D&, E&, F&, G&, H&>(a, b, c, d, e, f, g, h);
}
// Dispatchers ----------------------------------------------------------------
//
// Helper functions that call the given method on an object, with the unpacked
// tuple arguments. Notice that they all have the same number of arguments,
// so you need only write:
// DispatchToMethod(object, &Object::method, args);
// This is very useful for templated dispatchers, since they don't need to know
// what type |args| is.
// Non-Static Dispatchers with no out params.
template <class ObjT, class Method>
inline void DispatchToMethod(ObjT* obj, Method method, const Tuple0& arg) {
(obj->*method)();
}
template <class ObjT, class Method, class A>
inline void DispatchToMethod(ObjT* obj, Method method, const A& arg) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg));
}
template <class ObjT, class Method, class A>
inline void DispatchToMethod(ObjT* obj, Method method, const Tuple1<A>& arg) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a));
}
template<class ObjT, class Method, class A, class B>
inline void DispatchToMethod(ObjT* obj,
Method method,
const Tuple2<A, B>& arg) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b));
}
template<class ObjT, class Method, class A, class B, class C>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple3<A, B, C>& arg) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c));
}
template<class ObjT, class Method, class A, class B, class C, class D>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple4<A, B, C, D>& arg) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c),
butil::internal::UnwrapTraits<D>::Unwrap(arg.d));
}
template<class ObjT, class Method, class A, class B, class C, class D, class E>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple5<A, B, C, D, E>& arg) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c),
butil::internal::UnwrapTraits<D>::Unwrap(arg.d),
butil::internal::UnwrapTraits<E>::Unwrap(arg.e));
}
template<class ObjT, class Method, class A, class B, class C, class D, class E,
class F>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple6<A, B, C, D, E, F>& arg) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c),
butil::internal::UnwrapTraits<D>::Unwrap(arg.d),
butil::internal::UnwrapTraits<E>::Unwrap(arg.e),
butil::internal::UnwrapTraits<F>::Unwrap(arg.f));
}
template<class ObjT, class Method, class A, class B, class C, class D, class E,
class F, class G>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple7<A, B, C, D, E, F, G>& arg) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c),
butil::internal::UnwrapTraits<D>::Unwrap(arg.d),
butil::internal::UnwrapTraits<E>::Unwrap(arg.e),
butil::internal::UnwrapTraits<F>::Unwrap(arg.f),
butil::internal::UnwrapTraits<G>::Unwrap(arg.g));
}
template<class ObjT, class Method, class A, class B, class C, class D, class E,
class F, class G, class H>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple8<A, B, C, D, E, F, G, H>& arg) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c),
butil::internal::UnwrapTraits<D>::Unwrap(arg.d),
butil::internal::UnwrapTraits<E>::Unwrap(arg.e),
butil::internal::UnwrapTraits<F>::Unwrap(arg.f),
butil::internal::UnwrapTraits<G>::Unwrap(arg.g),
butil::internal::UnwrapTraits<H>::Unwrap(arg.h));
}
// Static Dispatchers with no out params.
template <class Function>
inline void DispatchToFunction(Function function, const Tuple0& arg) {
(*function)();
}
template <class Function, class A>
inline void DispatchToFunction(Function function, const A& arg) {
(*function)(arg);
}
template <class Function, class A>
inline void DispatchToFunction(Function function, const Tuple1<A>& arg) {
(*function)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a));
}
template<class Function, class A, class B>
inline void DispatchToFunction(Function function, const Tuple2<A, B>& arg) {
(*function)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b));
}
template<class Function, class A, class B, class C>
inline void DispatchToFunction(Function function, const Tuple3<A, B, C>& arg) {
(*function)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c));
}
template<class Function, class A, class B, class C, class D>
inline void DispatchToFunction(Function function,
const Tuple4<A, B, C, D>& arg) {
(*function)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c),
butil::internal::UnwrapTraits<D>::Unwrap(arg.d));
}
template<class Function, class A, class B, class C, class D, class E>
inline void DispatchToFunction(Function function,
const Tuple5<A, B, C, D, E>& arg) {
(*function)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c),
butil::internal::UnwrapTraits<D>::Unwrap(arg.d),
butil::internal::UnwrapTraits<E>::Unwrap(arg.e));
}
template<class Function, class A, class B, class C, class D, class E, class F>
inline void DispatchToFunction(Function function,
const Tuple6<A, B, C, D, E, F>& arg) {
(*function)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c),
butil::internal::UnwrapTraits<D>::Unwrap(arg.d),
butil::internal::UnwrapTraits<E>::Unwrap(arg.e),
butil::internal::UnwrapTraits<F>::Unwrap(arg.f));
}
template<class Function, class A, class B, class C, class D, class E, class F,
class G>
inline void DispatchToFunction(Function function,
const Tuple7<A, B, C, D, E, F, G>& arg) {
(*function)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c),
butil::internal::UnwrapTraits<D>::Unwrap(arg.d),
butil::internal::UnwrapTraits<E>::Unwrap(arg.e),
butil::internal::UnwrapTraits<F>::Unwrap(arg.f),
butil::internal::UnwrapTraits<G>::Unwrap(arg.g));
}
template<class Function, class A, class B, class C, class D, class E, class F,
class G, class H>
inline void DispatchToFunction(Function function,
const Tuple8<A, B, C, D, E, F, G, H>& arg) {
(*function)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c),
butil::internal::UnwrapTraits<D>::Unwrap(arg.d),
butil::internal::UnwrapTraits<E>::Unwrap(arg.e),
butil::internal::UnwrapTraits<F>::Unwrap(arg.f),
butil::internal::UnwrapTraits<G>::Unwrap(arg.g),
butil::internal::UnwrapTraits<H>::Unwrap(arg.h));
}
// Dispatchers with 0 out param (as a Tuple0).
template <class ObjT, class Method>
inline void DispatchToMethod(ObjT* obj,
Method method,
const Tuple0& arg, Tuple0*) {
(obj->*method)();
}
template <class ObjT, class Method, class A>
inline void DispatchToMethod(ObjT* obj, Method method, const A& arg, Tuple0*) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg));
}
template <class ObjT, class Method, class A>
inline void DispatchToMethod(ObjT* obj,
Method method,
const Tuple1<A>& arg, Tuple0*) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a));
}
template<class ObjT, class Method, class A, class B>
inline void DispatchToMethod(ObjT* obj,
Method method,
const Tuple2<A, B>& arg, Tuple0*) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b));
}
template<class ObjT, class Method, class A, class B, class C>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple3<A, B, C>& arg, Tuple0*) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c));
}
template<class ObjT, class Method, class A, class B, class C, class D>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple4<A, B, C, D>& arg, Tuple0*) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c),
butil::internal::UnwrapTraits<D>::Unwrap(arg.d));
}
template<class ObjT, class Method, class A, class B, class C, class D, class E>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple5<A, B, C, D, E>& arg, Tuple0*) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c),
butil::internal::UnwrapTraits<D>::Unwrap(arg.d),
butil::internal::UnwrapTraits<E>::Unwrap(arg.e));
}
template<class ObjT, class Method, class A, class B, class C, class D, class E,
class F>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple6<A, B, C, D, E, F>& arg, Tuple0*) {
(obj->*method)(butil::internal::UnwrapTraits<A>::Unwrap(arg.a),
butil::internal::UnwrapTraits<B>::Unwrap(arg.b),
butil::internal::UnwrapTraits<C>::Unwrap(arg.c),
butil::internal::UnwrapTraits<D>::Unwrap(arg.d),
butil::internal::UnwrapTraits<E>::Unwrap(arg.e),
butil::internal::UnwrapTraits<F>::Unwrap(arg.f));
}
// Dispatchers with 1 out param.
template<class ObjT, class Method,
class OutA>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple0& in,
Tuple1<OutA>* out) {
(obj->*method)(&out->a);
}
template<class ObjT, class Method, class InA,
class OutA>
inline void DispatchToMethod(ObjT* obj, Method method,
const InA& in,
Tuple1<OutA>* out) {
(obj->*method)(in, &out->a);
}
template<class ObjT, class Method, class InA,
class OutA>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple1<InA>& in,
Tuple1<OutA>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a), &out->a);
}
template<class ObjT, class Method, class InA, class InB,
class OutA>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple2<InA, InB>& in,
Tuple1<OutA>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
&out->a);
}
template<class ObjT, class Method, class InA, class InB, class InC,
class OutA>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple3<InA, InB, InC>& in,
Tuple1<OutA>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
&out->a);
}
template<class ObjT, class Method, class InA, class InB, class InC, class InD,
class OutA>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple4<InA, InB, InC, InD>& in,
Tuple1<OutA>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
&out->a);
}
template<class ObjT, class Method, class InA, class InB, class InC, class InD,
class InE, class OutA>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple5<InA, InB, InC, InD, InE>& in,
Tuple1<OutA>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
butil::internal::UnwrapTraits<InE>::Unwrap(in.e),
&out->a);
}
template<class ObjT, class Method,
class InA, class InB, class InC, class InD, class InE, class InF,
class OutA>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple6<InA, InB, InC, InD, InE, InF>& in,
Tuple1<OutA>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
butil::internal::UnwrapTraits<InE>::Unwrap(in.e),
butil::internal::UnwrapTraits<InF>::Unwrap(in.f),
&out->a);
}
// Dispatchers with 2 out params.
template<class ObjT, class Method,
class OutA, class OutB>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple0& in,
Tuple2<OutA, OutB>* out) {
(obj->*method)(&out->a, &out->b);
}
template<class ObjT, class Method, class InA,
class OutA, class OutB>
inline void DispatchToMethod(ObjT* obj, Method method,
const InA& in,
Tuple2<OutA, OutB>* out) {
(obj->*method)(in, &out->a, &out->b);
}
template<class ObjT, class Method, class InA,
class OutA, class OutB>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple1<InA>& in,
Tuple2<OutA, OutB>* out) {
(obj->*method)(
butil::internal::UnwrapTraits<InA>::Unwrap(in.a), &out->a, &out->b);
}
template<class ObjT, class Method, class InA, class InB,
class OutA, class OutB>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple2<InA, InB>& in,
Tuple2<OutA, OutB>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
&out->a,
&out->b);
}
template<class ObjT, class Method, class InA, class InB, class InC,
class OutA, class OutB>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple3<InA, InB, InC>& in,
Tuple2<OutA, OutB>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
&out->a,
&out->b);
}
template<class ObjT, class Method, class InA, class InB, class InC, class InD,
class OutA, class OutB>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple4<InA, InB, InC, InD>& in,
Tuple2<OutA, OutB>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
&out->a,
&out->b);
}
template<class ObjT, class Method,
class InA, class InB, class InC, class InD, class InE,
class OutA, class OutB>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple5<InA, InB, InC, InD, InE>& in,
Tuple2<OutA, OutB>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
butil::internal::UnwrapTraits<InE>::Unwrap(in.e),
&out->a,
&out->b);
}
template<class ObjT, class Method,
class InA, class InB, class InC, class InD, class InE, class InF,
class OutA, class OutB>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple6<InA, InB, InC, InD, InE, InF>& in,
Tuple2<OutA, OutB>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
butil::internal::UnwrapTraits<InE>::Unwrap(in.e),
butil::internal::UnwrapTraits<InF>::Unwrap(in.f),
&out->a,
&out->b);
}
// Dispatchers with 3 out params.
template<class ObjT, class Method,
class OutA, class OutB, class OutC>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple0& in,
Tuple3<OutA, OutB, OutC>* out) {
(obj->*method)(&out->a, &out->b, &out->c);
}
template<class ObjT, class Method, class InA,
class OutA, class OutB, class OutC>
inline void DispatchToMethod(ObjT* obj, Method method,
const InA& in,
Tuple3<OutA, OutB, OutC>* out) {
(obj->*method)(in, &out->a, &out->b, &out->c);
}
template<class ObjT, class Method, class InA,
class OutA, class OutB, class OutC>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple1<InA>& in,
Tuple3<OutA, OutB, OutC>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
&out->a,
&out->b,
&out->c);
}
template<class ObjT, class Method, class InA, class InB,
class OutA, class OutB, class OutC>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple2<InA, InB>& in,
Tuple3<OutA, OutB, OutC>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
&out->a,
&out->b,
&out->c);
}
template<class ObjT, class Method, class InA, class InB, class InC,
class OutA, class OutB, class OutC>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple3<InA, InB, InC>& in,
Tuple3<OutA, OutB, OutC>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
&out->a,
&out->b,
&out->c);
}
template<class ObjT, class Method, class InA, class InB, class InC, class InD,
class OutA, class OutB, class OutC>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple4<InA, InB, InC, InD>& in,
Tuple3<OutA, OutB, OutC>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
&out->a,
&out->b,
&out->c);
}
template<class ObjT, class Method,
class InA, class InB, class InC, class InD, class InE,
class OutA, class OutB, class OutC>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple5<InA, InB, InC, InD, InE>& in,
Tuple3<OutA, OutB, OutC>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
butil::internal::UnwrapTraits<InE>::Unwrap(in.e),
&out->a,
&out->b,
&out->c);
}
template<class ObjT, class Method,
class InA, class InB, class InC, class InD, class InE, class InF,
class OutA, class OutB, class OutC>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple6<InA, InB, InC, InD, InE, InF>& in,
Tuple3<OutA, OutB, OutC>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
butil::internal::UnwrapTraits<InE>::Unwrap(in.e),
butil::internal::UnwrapTraits<InF>::Unwrap(in.f),
&out->a,
&out->b,
&out->c);
}
// Dispatchers with 4 out params.
template<class ObjT, class Method,
class OutA, class OutB, class OutC, class OutD>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple0& in,
Tuple4<OutA, OutB, OutC, OutD>* out) {
(obj->*method)(&out->a, &out->b, &out->c, &out->d);
}
template<class ObjT, class Method, class InA,
class OutA, class OutB, class OutC, class OutD>
inline void DispatchToMethod(ObjT* obj, Method method,
const InA& in,
Tuple4<OutA, OutB, OutC, OutD>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in),
&out->a,
&out->b,
&out->c,
&out->d);
}
template<class ObjT, class Method, class InA,
class OutA, class OutB, class OutC, class OutD>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple1<InA>& in,
Tuple4<OutA, OutB, OutC, OutD>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
&out->a,
&out->b,
&out->c,
&out->d);
}
template<class ObjT, class Method, class InA, class InB,
class OutA, class OutB, class OutC, class OutD>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple2<InA, InB>& in,
Tuple4<OutA, OutB, OutC, OutD>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
&out->a,
&out->b,
&out->c,
&out->d);
}
template<class ObjT, class Method, class InA, class InB, class InC,
class OutA, class OutB, class OutC, class OutD>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple3<InA, InB, InC>& in,
Tuple4<OutA, OutB, OutC, OutD>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
&out->a,
&out->b,
&out->c,
&out->d);
}
template<class ObjT, class Method, class InA, class InB, class InC, class InD,
class OutA, class OutB, class OutC, class OutD>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple4<InA, InB, InC, InD>& in,
Tuple4<OutA, OutB, OutC, OutD>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
&out->a,
&out->b,
&out->c,
&out->d);
}
template<class ObjT, class Method,
class InA, class InB, class InC, class InD, class InE,
class OutA, class OutB, class OutC, class OutD>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple5<InA, InB, InC, InD, InE>& in,
Tuple4<OutA, OutB, OutC, OutD>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
butil::internal::UnwrapTraits<InE>::Unwrap(in.e),
&out->a,
&out->b,
&out->c,
&out->d);
}
template<class ObjT, class Method,
class InA, class InB, class InC, class InD, class InE, class InF,
class OutA, class OutB, class OutC, class OutD>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple6<InA, InB, InC, InD, InE, InF>& in,
Tuple4<OutA, OutB, OutC, OutD>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
butil::internal::UnwrapTraits<InE>::Unwrap(in.e),
butil::internal::UnwrapTraits<InF>::Unwrap(in.f),
&out->a,
&out->b,
&out->c,
&out->d);
}
// Dispatchers with 5 out params.
template<class ObjT, class Method,
class OutA, class OutB, class OutC, class OutD, class OutE>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple0& in,
Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
(obj->*method)(&out->a, &out->b, &out->c, &out->d, &out->e);
}
template<class ObjT, class Method, class InA,
class OutA, class OutB, class OutC, class OutD, class OutE>
inline void DispatchToMethod(ObjT* obj, Method method,
const InA& in,
Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in),
&out->a,
&out->b,
&out->c,
&out->d,
&out->e);
}
template<class ObjT, class Method, class InA,
class OutA, class OutB, class OutC, class OutD, class OutE>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple1<InA>& in,
Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
&out->a,
&out->b,
&out->c,
&out->d,
&out->e);
}
template<class ObjT, class Method, class InA, class InB,
class OutA, class OutB, class OutC, class OutD, class OutE>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple2<InA, InB>& in,
Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
&out->a,
&out->b,
&out->c,
&out->d,
&out->e);
}
template<class ObjT, class Method, class InA, class InB, class InC,
class OutA, class OutB, class OutC, class OutD, class OutE>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple3<InA, InB, InC>& in,
Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
&out->a,
&out->b,
&out->c,
&out->d,
&out->e);
}
template<class ObjT, class Method, class InA, class InB, class InC, class InD,
class OutA, class OutB, class OutC, class OutD, class OutE>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple4<InA, InB, InC, InD>& in,
Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
&out->a,
&out->b,
&out->c,
&out->d,
&out->e);
}
template<class ObjT, class Method,
class InA, class InB, class InC, class InD, class InE,
class OutA, class OutB, class OutC, class OutD, class OutE>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple5<InA, InB, InC, InD, InE>& in,
Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
butil::internal::UnwrapTraits<InE>::Unwrap(in.e),
&out->a,
&out->b,
&out->c,
&out->d,
&out->e);
}
template<class ObjT, class Method,
class InA, class InB, class InC, class InD, class InE, class InF,
class OutA, class OutB, class OutC, class OutD, class OutE>
inline void DispatchToMethod(ObjT* obj, Method method,
const Tuple6<InA, InB, InC, InD, InE, InF>& in,
Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
(obj->*method)(butil::internal::UnwrapTraits<InA>::Unwrap(in.a),
butil::internal::UnwrapTraits<InB>::Unwrap(in.b),
butil::internal::UnwrapTraits<InC>::Unwrap(in.c),
butil::internal::UnwrapTraits<InD>::Unwrap(in.d),
butil::internal::UnwrapTraits<InE>::Unwrap(in.e),
butil::internal::UnwrapTraits<InF>::Unwrap(in.f),
&out->a,
&out->b,
&out->c,
&out->d,
&out->e);
}
#endif // BASE_TUPLE_H__
......@@ -21,15 +21,9 @@ LIBPATHS=$(addprefix -L, $(LIBS))
TEST_BUTIL_SOURCES = \
at_exit_unittest.cc \
atomicops_unittest.cc \
barrier_closure_unittest.cc \
base64_unittest.cc \
big_endian_unittest.cc \
bind_unittest.cc \
bits_unittest.cc \
callback_helpers_unittest.cc \
callback_list_unittest.cc \
callback_unittest.cc \
cancelable_callback_unittest.cc \
hash_tables_unittest.cc \
linked_list_unittest.cc \
mru_cache_unittest.cc \
......@@ -98,7 +92,6 @@ TEST_BUTIL_SOURCES = \
time_unittest.cc \
version_unittest.cc \
logging_unittest.cc \
tuple_unittest.cc \
cacheline_unittest.cpp \
class_name_unittest.cpp \
endpoint_unittest.cpp \
......
......@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "butil/at_exit.h"
#include "butil/bind.h"
#include <gtest/gtest.h>
......@@ -78,10 +77,3 @@ TEST_F(AtExitTest, Param) {
&g_test_counter_1);
butil::AtExitManager::ProcessCallbacksNow();
}
TEST_F(AtExitTest, Task) {
ZeroTestCounters();
butil::AtExitManager::RegisterTask(butil::Bind(&ExpectParamIsCounter,
&g_test_counter_1));
butil::AtExitManager::ProcessCallbacksNow();
}
......@@ -5,6 +5,7 @@
#include <gflags/gflags.h>
#include "butil/base_switches.h"
#include "butil/at_exit.h"
#include "butil/logging.h"
#include "test/multiprocess_func_list.h"
// Disable coredumps by default to avoid generating a lot of coredumps
......
......@@ -6,7 +6,6 @@
#include "butil/synchronization/cancellation_flag.h"
#include "butil/bind.h"
#include "butil/logging.h"
#include "butil/synchronization/spin_wait.h"
#include "butil/time/time.h"
......
......@@ -8,7 +8,6 @@
#include <algorithm>
#include <vector>
#include "butil/bind.h"
#include "butil/logging.h"
#include "butil/memory/scoped_ptr.h"
#include "butil/synchronization/condition_variable.h"
......
......@@ -7,7 +7,6 @@
#include <map>
#include <string>
#include "butil/bind.h"
#include <gtest/gtest.h>
namespace {
......
......@@ -5,8 +5,6 @@
#include "butil/memory/scoped_ptr.h"
#include "butil/basictypes.h"
#include "butil/bind.h"
#include "butil/callback.h"
#include <gtest/gtest.h>
namespace {
......
......@@ -4,8 +4,6 @@
#include "butil/memory/scoped_vector.h"
#include "butil/bind.h"
#include "butil/callback.h"
#include "butil/memory/scoped_ptr.h"
#include <gtest/gtest.h>
......@@ -272,10 +270,9 @@ TEST(ScopedVectorTest, Passed) {
ScopedVector<DeleteCounter> deleter_vector;
deleter_vector.push_back(new DeleteCounter(&deletes));
EXPECT_EQ(0, deletes);
butil::Callback<ScopedVector<DeleteCounter>(void)> callback =
butil::Bind(&PassThru<DeleteCounter>, butil::Passed(&deleter_vector));
EXPECT_EQ(0, deletes);
ScopedVector<DeleteCounter> result = callback.Run();
ScopedVector<DeleteCounter> result = deleter_vector.Pass();
EXPECT_EQ(0, deletes);
result.clear();
EXPECT_EQ(1, deletes);
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "test/test_file_util.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
......
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "butil/tuple.h"
#include "butil/compiler_specific.h"
#include <gtest/gtest.h>
namespace {
void DoAdd(int a, int b, int c, int* res) {
*res = a + b + c;
}
struct Addy {
Addy() { }
void DoAdd(int a, int b, int c, int d, int* res) {
*res = a + b + c + d;
}
};
struct Addz {
Addz() { }
void DoAdd(int a, int b, int c, int d, int e, int* res) {
*res = a + b + c + d + e;
}
};
} // namespace
TEST(TupleTest, Basic) {
Tuple0 t0 ALLOW_UNUSED = MakeTuple();
Tuple1<int> t1(1);
Tuple2<int, const char*> t2 = MakeTuple(1, static_cast<const char*>("wee"));
Tuple3<int, int, int> t3(1, 2, 3);
Tuple4<int, int, int, int*> t4(1, 2, 3, &t1.a);
Tuple5<int, int, int, int, int*> t5(1, 2, 3, 4, &t4.a);
Tuple6<int, int, int, int, int, int*> t6(1, 2, 3, 4, 5, &t4.a);
EXPECT_EQ(1, t1.a);
EXPECT_EQ(1, t2.a);
EXPECT_EQ(1, t3.a);
EXPECT_EQ(2, t3.b);
EXPECT_EQ(3, t3.c);
EXPECT_EQ(1, t4.a);
EXPECT_EQ(2, t4.b);
EXPECT_EQ(3, t4.c);
EXPECT_EQ(1, t5.a);
EXPECT_EQ(2, t5.b);
EXPECT_EQ(3, t5.c);
EXPECT_EQ(4, t5.d);
EXPECT_EQ(1, t6.a);
EXPECT_EQ(2, t6.b);
EXPECT_EQ(3, t6.c);
EXPECT_EQ(4, t6.d);
EXPECT_EQ(5, t6.e);
EXPECT_EQ(1, t1.a);
DispatchToFunction(&DoAdd, t4);
EXPECT_EQ(6, t1.a);
int res = 0;
DispatchToFunction(&DoAdd, MakeTuple(9, 8, 7, &res));
EXPECT_EQ(24, res);
Addy addy;
EXPECT_EQ(1, t4.a);
DispatchToMethod(&addy, &Addy::DoAdd, t5);
EXPECT_EQ(10, t4.a);
Addz addz;
EXPECT_EQ(10, t4.a);
DispatchToMethod(&addz, &Addz::DoAdd, t6);
EXPECT_EQ(15, t4.a);
}
namespace {
struct CopyLogger {
CopyLogger() { ++TimesConstructed; }
CopyLogger(const CopyLogger& tocopy) { ++TimesConstructed; ++TimesCopied; }
~CopyLogger() { }
static int TimesCopied;
static int TimesConstructed;
};
void SomeLoggerMethRef(const CopyLogger& logy, const CopyLogger* ptr, bool* b) {
*b = &logy == ptr;
}
void SomeLoggerMethCopy(CopyLogger logy, const CopyLogger* ptr, bool* b) {
*b = &logy == ptr;
}
int CopyLogger::TimesCopied = 0;
int CopyLogger::TimesConstructed = 0;
} // namespace
TEST(TupleTest, Copying) {
CopyLogger logger;
EXPECT_EQ(0, CopyLogger::TimesCopied);
EXPECT_EQ(1, CopyLogger::TimesConstructed);
bool res = false;
// Creating the tuple should copy the class to store internally in the tuple.
Tuple3<CopyLogger, CopyLogger*, bool*> tuple(logger, &logger, &res);
tuple.b = &tuple.a;
EXPECT_EQ(2, CopyLogger::TimesConstructed);
EXPECT_EQ(1, CopyLogger::TimesCopied);
// Our internal Logger and the one passed to the function should be the same.
res = false;
DispatchToFunction(&SomeLoggerMethRef, tuple);
EXPECT_TRUE(res);
EXPECT_EQ(2, CopyLogger::TimesConstructed);
EXPECT_EQ(1, CopyLogger::TimesCopied);
// Now they should be different, since the function call will make a copy.
res = false;
DispatchToFunction(&SomeLoggerMethCopy, tuple);
EXPECT_FALSE(res);
EXPECT_EQ(3, CopyLogger::TimesConstructed);
EXPECT_EQ(2, CopyLogger::TimesCopied);
}
......@@ -6,7 +6,6 @@
#include <string>
#include "butil/bind.h"
#include "butil/debug/leak_annotations.h"
#include "butil/memory/scoped_ptr.h"
#include "butil/synchronization/waitable_event.h"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment