|  | #pragma once | 
|  | #include <stdplus/handle/managed.hpp> | 
|  |  | 
|  | #include <tuple> | 
|  | #include <utility> | 
|  |  | 
|  | namespace stdplus | 
|  | { | 
|  |  | 
|  | struct Cancelable | 
|  | { | 
|  | virtual ~Cancelable() = default; | 
|  | virtual void cancel() noexcept = 0; | 
|  | }; | 
|  |  | 
|  | namespace detail | 
|  | { | 
|  |  | 
|  | struct CancelableF | 
|  | { | 
|  | inline void operator()(Cancelable* c) noexcept | 
|  | { | 
|  | c->cancel(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | using CancelHandle = Managed<Cancelable*>::HandleF<CancelableF>; | 
|  |  | 
|  | } // namespace detail | 
|  |  | 
|  | struct Cancel : detail::CancelHandle | 
|  | { | 
|  | Cancel() : detail::CancelHandle(std::nullopt) {} | 
|  | template <typename T> | 
|  | explicit Cancel(T&& t) : detail::CancelHandle(t) | 
|  | {} | 
|  | }; | 
|  |  | 
|  | namespace detail | 
|  | { | 
|  |  | 
|  | struct fAny | 
|  | {}; | 
|  | struct fPtr : fAny | 
|  | {}; | 
|  |  | 
|  | template <typename> | 
|  | struct validator | 
|  | { | 
|  | typedef int type; | 
|  | }; | 
|  |  | 
|  | template <typename F, | 
|  | typename validator<decltype(std::declval<F>() == nullptr)>::type = 0> | 
|  | inline bool fPop(const F& f, fPtr) | 
|  | { | 
|  | return !(f == nullptr); | 
|  | } | 
|  |  | 
|  | template <typename F> | 
|  | inline bool fPop(const F&, fAny) | 
|  | { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename F> | 
|  | inline bool fPop(const F& f) | 
|  | { | 
|  | return fPop(f, fPtr()); | 
|  | } | 
|  |  | 
|  | } // namespace detail | 
|  |  | 
|  | template <typename F, typename... DefaultArgs> | 
|  | class AlwaysCallOnce | 
|  | { | 
|  | public: | 
|  | template <typename Fi, typename... Vs> | 
|  | explicit AlwaysCallOnce(Fi&& fi, Vs&&... default_args) : | 
|  | f(std::forward<Fi>(fi)), default_args(std::forward<Vs>(default_args)...) | 
|  | {} | 
|  | AlwaysCallOnce(const AlwaysCallOnce&) = delete; | 
|  | AlwaysCallOnce(AlwaysCallOnce&& other) noexcept : | 
|  | f(std::move(other.f)), default_args(std::move(other.default_args)), | 
|  | called(std::exchange(other.called, true)) | 
|  | {} | 
|  | AlwaysCallOnce& operator=(const AlwaysCallOnce&) = delete; | 
|  | AlwaysCallOnce& operator=(AlwaysCallOnce&& other) noexcept | 
|  | { | 
|  | finalCall(); | 
|  | f = std::move(other.f); | 
|  | default_args = std::move(other.default_args); | 
|  | called = std::exchange(other.called, true); | 
|  | return *this; | 
|  | } | 
|  | ~AlwaysCallOnce() | 
|  | { | 
|  | finalCall(); | 
|  | } | 
|  |  | 
|  | template <typename... Args> | 
|  | auto operator()(Args&&... args) noexcept | 
|  | { | 
|  | called = true; | 
|  | return f(std::forward<Args>(args)...); | 
|  | } | 
|  |  | 
|  | private: | 
|  | F f; | 
|  | std::tuple<DefaultArgs...> default_args; | 
|  | bool called = false; | 
|  |  | 
|  | void finalCall() noexcept | 
|  | { | 
|  | if (!called && detail::fPop(f)) | 
|  | { | 
|  | std::apply(f, default_args); | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename... Args> | 
|  | inline auto alwaysCallOnce(Args&&... args) | 
|  | { | 
|  | return AlwaysCallOnce<std::remove_cv_t<std::remove_reference_t<Args>>...>( | 
|  | std::forward<Args>(args)...); | 
|  | } | 
|  |  | 
|  | } // namespace stdplus |