Commit 367d3cfa authored by Andrii Grynenko's avatar Andrii Grynenko Committed by Facebook Github Bot

Reduce KeepAlive object size to 1 pointer

Summary: Use a single pointer to store Executor pointer and dummy flag.

Reviewed By: yfeldblum

Differential Revision: D7857087

fbshipit-source-id: 529fbfdc6ad14954f5bdd9bef3eb1e335b233ec9
parent 021f9853
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <climits> #include <climits>
#include <folly/Function.h> #include <folly/Function.h>
#include <folly/Utility.h>
namespace folly { namespace folly {
...@@ -48,46 +49,48 @@ class Executor { ...@@ -48,46 +49,48 @@ class Executor {
static const int8_t MID_PRI = 0; static const int8_t MID_PRI = 0;
static const int8_t HI_PRI = SCHAR_MAX; static const int8_t HI_PRI = SCHAR_MAX;
class KeepAliveDeleter {
public:
explicit KeepAliveDeleter(bool dummy) : dummy_(dummy) {}
void operator()(folly::Executor* executor) {
if (dummy_) {
return;
}
executor->keepAliveRelease();
}
private:
bool dummy_;
};
template <typename ExecutorT = Executor> template <typename ExecutorT = Executor>
class KeepAlive { class KeepAlive {
public: public:
KeepAlive() : executor_(nullptr, KeepAliveDeleter(true)) {} KeepAlive() = default;
template <typename OtherExecutor> ~KeepAlive() {
/* implicit */ KeepAlive(KeepAlive<OtherExecutor>&& other) : KeepAlive() { reset();
*this = std::move(other);
} }
template <typename OtherExecutor> template <
typename OtherExecutor,
typename = typename std::enable_if<
std::is_convertible<OtherExecutor*, ExecutorT*>::value>::type>
/* implicit */ KeepAlive(KeepAlive<OtherExecutor>&& other) noexcept
: executorAndDummyFlag_(exchange(other.executorAndDummyFlag_, 0)) {}
template <
typename OtherExecutor,
typename = typename std::enable_if<
std::is_convertible<OtherExecutor*, ExecutorT*>::value>::type>
KeepAlive& operator=(KeepAlive<OtherExecutor>&& other) { KeepAlive& operator=(KeepAlive<OtherExecutor>&& other) {
executor_ = std::move(other.executor_); reset();
executorAndDummyFlag_ = exchange(other.executorAndDummyFlag_, 0);
return *this; return *this;
} }
void reset() { void reset() {
executor_.reset(); if (Executor* executor = get()) {
if (exchange(executorAndDummyFlag_, 0) & kDummyFlag) {
return;
}
executor->keepAliveRelease();
}
} }
explicit operator bool() const { explicit operator bool() const {
return executor_ != nullptr; return executorAndDummyFlag_;
} }
ExecutorT* get() const { ExecutorT* get() const {
return executor_.get(); return reinterpret_cast<ExecutorT*>(
executorAndDummyFlag_ & kExecutorMask);
} }
ExecutorT& operator*() const { ExecutorT& operator*() const {
...@@ -99,14 +102,23 @@ class Executor { ...@@ -99,14 +102,23 @@ class Executor {
} }
private: private:
static constexpr intptr_t kDummyFlag = 1;
static constexpr intptr_t kExecutorMask = ~kDummyFlag;
friend class Executor; friend class Executor;
template <typename OtherExecutor> template <typename OtherExecutor>
friend class KeepAlive; friend class KeepAlive;
KeepAlive(ExecutorT* executor, bool dummy) KeepAlive(ExecutorT* executor, bool dummy)
: executor_(executor, KeepAliveDeleter(dummy)) {} : executorAndDummyFlag_(
reinterpret_cast<intptr_t>(executor) | (dummy ? kDummyFlag : 0)) {
assert(executor);
assert(
(reinterpret_cast<intptr_t>(executor) & kExecutorMask) ==
reinterpret_cast<intptr_t>(executor));
}
std::unique_ptr<ExecutorT, KeepAliveDeleter> executor_; intptr_t executorAndDummyFlag_{reinterpret_cast<intptr_t>(nullptr)};
}; };
template <typename ExecutorT> template <typename ExecutorT>
......
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