Commit 33344a23 authored by Pavlo Kushnir's avatar Pavlo Kushnir Committed by Facebook Github Bot 3

Faster onDestroy

Summary: there is no need to call `std::function::invoke` for every DestructorGuard.

Reviewed By: yfeldblum

Differential Revision: D3229345

fb-gh-sync-id: c42f8cd05576d56b6a9b2f9d06878d9b01a36e94
fbshipit-source-id: c42f8cd05576d56b6a9b2f9d06878d9b01a36e94
parent b609f8ee
...@@ -54,7 +54,7 @@ class DelayedDestruction : public DelayedDestructionBase { ...@@ -54,7 +54,7 @@ class DelayedDestruction : public DelayedDestructionBase {
if (getDestructorGuardCount() != 0) { if (getDestructorGuardCount() != 0) {
destroyPending_ = true; destroyPending_ = true;
} else { } else {
onDestroy_(false); onDelayedDestroy(false);
} }
} }
...@@ -98,15 +98,6 @@ class DelayedDestruction : public DelayedDestructionBase { ...@@ -98,15 +98,6 @@ class DelayedDestruction : public DelayedDestructionBase {
DelayedDestruction() DelayedDestruction()
: destroyPending_(false) { : destroyPending_(false) {
onDestroy_ = [this] (bool delayed) {
// check if it is ok to destroy now
if (delayed && !destroyPending_) {
return;
}
destroyPending_ = false;
delete this;
};
} }
private: private:
...@@ -118,5 +109,14 @@ class DelayedDestruction : public DelayedDestructionBase { ...@@ -118,5 +109,14 @@ class DelayedDestruction : public DelayedDestructionBase {
* guardCount_ drops to 0. * guardCount_ drops to 0.
*/ */
bool destroyPending_; bool destroyPending_;
void onDelayedDestroy(bool delayed) override {
// check if it is ok to destroy now
if (delayed && !destroyPending_) {
return;
}
destroyPending_ = false;
delete this;
}
}; };
} // folly } // folly
...@@ -37,7 +37,7 @@ namespace folly { ...@@ -37,7 +37,7 @@ namespace folly {
* *
* Classes needing this functionality should: * Classes needing this functionality should:
* - derive from DelayedDestructionBase directly * - derive from DelayedDestructionBase directly
* - pass a callback to onDestroy_ which'll be called before the object is * - implement onDelayedDestroy which'll be called before the object is
* going to be destructed * going to be destructed
* - create a DestructorGuard object on the stack in each public method that * - create a DestructorGuard object on the stack in each public method that
* may invoke a callback * may invoke a callback
...@@ -93,7 +93,7 @@ class DelayedDestructionBase : private boost::noncopyable { ...@@ -93,7 +93,7 @@ class DelayedDestructionBase : private boost::noncopyable {
assert(dd_->guardCount_ > 0); assert(dd_->guardCount_ > 0);
--dd_->guardCount_; --dd_->guardCount_;
if (dd_->guardCount_ == 0) { if (dd_->guardCount_ == 0) {
dd_->onDestroy_(true); dd_->onDelayedDestroy(true);
} }
} }
} }
...@@ -213,14 +213,15 @@ class DelayedDestructionBase : private boost::noncopyable { ...@@ -213,14 +213,15 @@ class DelayedDestructionBase : private boost::noncopyable {
} }
/** /**
* Implement onDestroy_ in subclasses. * Implement onDelayedDestroy in subclasses.
* onDestroy_() is invoked when the object is potentially being destroyed. * onDelayedDestroy() is invoked when the object is potentially being
* destroyed.
* *
* @param delayed This parameter is true if destruction was delayed because * @param delayed This parameter is true if destruction was delayed because
* of a DestructorGuard object, or false if onDestroy_() is * of a DestructorGuard object, or false if onDelayedDestroy()
* being called directly from the destructor. * is being called directly from the destructor.
*/ */
std::function<void(bool)> onDestroy_; virtual void onDelayedDestroy(bool delayed) = 0;
private: private:
/** /**
......
...@@ -43,11 +43,6 @@ using namespace folly; ...@@ -43,11 +43,6 @@ using namespace folly;
class DestructionOnCallback : public DelayedDestructionBase { class DestructionOnCallback : public DelayedDestructionBase {
public: public:
DestructionOnCallback() : state_(0), deleted_(false) { DestructionOnCallback() : state_(0), deleted_(false) {
onDestroy_ = [this] (bool delayed) {
deleted_ = true;
delete this;
(void)delayed; // prevent unused variable warnings
};
} }
void onComplete(int n, int& state) { void onComplete(int n, int& state) {
...@@ -58,10 +53,6 @@ class DestructionOnCallback : public DelayedDestructionBase { ...@@ -58,10 +53,6 @@ class DestructionOnCallback : public DelayedDestructionBase {
state = state_; state = state_;
} }
void setOnDestroy(std::function<void(bool)> onDestroy) {
onDestroy_ = onDestroy;
}
int state() const { return state_; } int state() const { return state_; }
bool deleted() const { return deleted_; } bool deleted() const { return deleted_; }
...@@ -77,6 +68,12 @@ class DestructionOnCallback : public DelayedDestructionBase { ...@@ -77,6 +68,12 @@ class DestructionOnCallback : public DelayedDestructionBase {
private: private:
int state_; int state_;
bool deleted_; bool deleted_;
void onDelayedDestroy(bool delayed) override {
deleted_ = true;
delete this;
(void)delayed; // prevent unused variable warnings
}
}; };
struct DelayedDestructionBaseTest : public ::testing::Test { struct DelayedDestructionBaseTest : public ::testing::Test {
...@@ -89,17 +86,3 @@ TEST_F(DelayedDestructionBaseTest, basic) { ...@@ -89,17 +86,3 @@ TEST_F(DelayedDestructionBaseTest, basic) {
d->onComplete(3, state); d->onComplete(3, state);
EXPECT_EQ(state, 10); // 10 = 6 + 3 + 1 EXPECT_EQ(state, 10); // 10 = 6 + 3 + 1
} }
TEST_F(DelayedDestructionBaseTest, destructFromContainer) {
std::list<DestructionOnCallback> l;
l.emplace_back();
l.back().setOnDestroy([&] (bool delayed) {
l.erase(l.begin());
(void)delayed;
});
EXPECT_NE(l.size(), 0);
int32_t state;
l.back().onComplete(3, state);
EXPECT_EQ(state, 10); // 10 = 6 + 3 + 1
EXPECT_EQ(l.size(), 0);
}
...@@ -58,16 +58,6 @@ class UndelayedDestruction : public TDD { ...@@ -58,16 +58,6 @@ class UndelayedDestruction : public TDD {
template<typename ...Args> template<typename ...Args>
explicit UndelayedDestruction(Args&& ...args) explicit UndelayedDestruction(Args&& ...args)
: TDD(std::forward<Args>(args)...) { : TDD(std::forward<Args>(args)...) {
this->TDD::onDestroy_ = [&, this] (bool delayed) {
if (delayed && !this->TDD::getDestroyPending()) {
return;
}
// Do nothing. This will always be invoked from the call to destroy
// inside our destructor.
assert(!delayed);
// prevent unused variable warnings when asserts are compiled out.
(void)delayed;
};
} }
/** /**
...@@ -91,6 +81,17 @@ class UndelayedDestruction : public TDD { ...@@ -91,6 +81,17 @@ class UndelayedDestruction : public TDD {
this->destroy(); this->destroy();
} }
void onDelayedDestroy(bool delayed) override {
if (delayed && !this->TDD::getDestroyPending()) {
return;
}
// Do nothing. This will always be invoked from the call to destroy
// inside our destructor.
assert(!delayed);
// prevent unused variable warnings when asserts are compiled out.
(void)delayed;
}
protected: protected:
/** /**
* Override our parent's destroy() method to make it protected. * Override our parent's destroy() method to make it protected.
......
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