Last active
March 27, 2017 19:19
-
-
Save duarten/d22c1eb643aba1dfb24ca479143302c7 to your computer and use it in GitHub Desktop.
Task holder with internal and external storage.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class task { | |
public: | |
virtual ~task() noexcept {} | |
virtual void run() noexcept = 0; | |
}; | |
template <typename Func> | |
class lambda_task final : public task { | |
Func _func; | |
public: | |
lambda_task(const Func& func) : _func(func) {} | |
lambda_task(Func&& func) : _func(std::move(func)) {} | |
virtual void run() noexcept override { _func(); } | |
}; | |
union task_holder { | |
static constexpr size_t storage_size = 128; | |
std::aligned_storage_t<storage_size> _storage; | |
task* ignored; | |
task_holder() noexcept { | |
set_task([] { }); | |
} | |
task_holder(std::unique_ptr<task>&& t) noexcept { | |
set_task([t = std::move(t)] { t->run(); }); | |
} | |
~task_holder() noexcept { | |
reinterpret_cast<task*>(&_storage)->~task(); | |
} | |
task_holder(task_holder&& other) noexcept { | |
set_task([] { }); | |
*reinterpret_cast<task*>(&_storage) = std::move(*reinterpret_cast<task*>(&other._storage)); | |
} | |
task_holder& operator=(task_holder&& other) noexcept { | |
if (this != &other) { | |
*reinterpret_cast<task*>(&_storage) = std::move(*reinterpret_cast<task*>(&other._storage)); | |
} | |
return *this; | |
} | |
void run() noexcept { | |
reinterpret_cast<task*>(&_storage)->run(); | |
} | |
template<typename Func> | |
void set_task(Func func) { | |
constexpr bool fits_in_storage = sizeof(lambda_task<Func>) <= task_holder::storage_size; | |
task_holder_initializer<Func, fits_in_storage>().set_task(*this, std::forward<Func>(func)); | |
} | |
template<typename Func, bool FitsInInternalStorage> | |
struct task_holder_initializer; | |
template<typename Func> | |
struct task_holder_initializer<Func, true> { | |
void set_task(task_holder& th, Func&& func) { | |
new (&th._storage) lambda_task<Func>(std::forward<Func>(func)); | |
} | |
}; | |
template<typename Func> | |
struct task_holder_initializer<Func, false> { | |
void set_task(task_holder& th, Func&& func) { | |
auto delegate = std::make_unique<Func>(std::forward<Func>(func)); | |
auto run_delegate = [delegate = std::move(delegate)] { (*delegate)(); }; | |
new (&th._storage) lambda_task<decltype(run_delegate)>(std::move(run_delegate)); | |
} | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment