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 diff is collapsed.
// 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
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
// 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 diff is collapsed.
......@@ -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
......
This diff is collapsed.
......@@ -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