Skip to content

Instantly share code, notes, and snippets.

@duarten
Last active March 27, 2017 19:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save duarten/d22c1eb643aba1dfb24ca479143302c7 to your computer and use it in GitHub Desktop.
Save duarten/d22c1eb643aba1dfb24ca479143302c7 to your computer and use it in GitHub Desktop.
Task holder with internal and external storage.
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