blob: 3017e1b81a51b42b0eae8f7e00fa56f5960db129 [file] [log] [blame]
William A. Kennington III458aeae2021-06-14 15:07:16 -07001#pragma once
2#include <stdplus/handle/managed.hpp>
3
William A. Kennington III20cab0c2021-06-14 15:13:19 -07004#include <tuple>
5#include <utility>
6
William A. Kennington III458aeae2021-06-14 15:07:16 -07007namespace stdplus
8{
9
10struct Cancelable
11{
12 virtual ~Cancelable() = default;
13 virtual void cancel() noexcept = 0;
14};
William A. Kennington III16f6add2021-06-29 11:01:17 -070015
16namespace detail
17{
18
William A. Kennington III458aeae2021-06-14 15:07:16 -070019struct CancelableF
20{
21 inline void operator()(Cancelable* c) noexcept
22 {
23 c->cancel();
24 }
25};
William A. Kennington III16f6add2021-06-29 11:01:17 -070026
William A. Kennington IIIa4f71f92022-08-18 14:17:00 -070027using CancelHandle = Managed<Cancelable*>::HandleF<CancelableF>;
William A. Kennington III16f6add2021-06-29 11:01:17 -070028
29} // namespace detail
30
31struct Cancel : detail::CancelHandle
32{
Patrick Williamsd1984dd2023-05-10 16:12:44 -050033 Cancel() : detail::CancelHandle(std::nullopt) {}
William A. Kennington III8ec04ce2021-06-29 18:08:30 -070034 template <typename T>
35 explicit Cancel(T&& t) : detail::CancelHandle(t)
Patrick Williamsd1984dd2023-05-10 16:12:44 -050036 {}
William A. Kennington III16f6add2021-06-29 11:01:17 -070037};
William A. Kennington III458aeae2021-06-14 15:07:16 -070038
William A. Kennington III20cab0c2021-06-14 15:13:19 -070039namespace detail
40{
41
42struct fAny
Patrick Williamsd1984dd2023-05-10 16:12:44 -050043{};
William A. Kennington III20cab0c2021-06-14 15:13:19 -070044struct fPtr : fAny
Patrick Williamsd1984dd2023-05-10 16:12:44 -050045{};
William A. Kennington III20cab0c2021-06-14 15:13:19 -070046
47template <typename>
48struct validator
49{
50 typedef int type;
51};
52
53template <typename F,
54 typename validator<decltype(std::declval<F>() == nullptr)>::type = 0>
55inline bool fPop(const F& f, fPtr)
56{
57 return !(f == nullptr);
58}
59
60template <typename F>
61inline bool fPop(const F&, fAny)
62{
63 return true;
64}
65
66template <typename F>
67inline bool fPop(const F& f)
68{
69 return fPop(f, fPtr());
70}
71
72} // namespace detail
73
74template <typename F, typename... DefaultArgs>
75class AlwaysCallOnce
76{
77 public:
78 template <typename Fi, typename... Vs>
79 explicit AlwaysCallOnce(Fi&& fi, Vs&&... default_args) :
80 f(std::forward<Fi>(fi)), default_args(std::forward<Vs>(default_args)...)
Patrick Williamsd1984dd2023-05-10 16:12:44 -050081 {}
William A. Kennington III20cab0c2021-06-14 15:13:19 -070082 AlwaysCallOnce(const AlwaysCallOnce&) = delete;
83 AlwaysCallOnce(AlwaysCallOnce&& other) noexcept :
84 f(std::move(other.f)), default_args(std::move(other.default_args)),
85 called(std::exchange(other.called, true))
Patrick Williamsd1984dd2023-05-10 16:12:44 -050086 {}
William A. Kennington III20cab0c2021-06-14 15:13:19 -070087 AlwaysCallOnce& operator=(const AlwaysCallOnce&) = delete;
88 AlwaysCallOnce& operator=(AlwaysCallOnce&& other) noexcept
89 {
90 finalCall();
91 f = std::move(other.f);
92 default_args = std::move(other.default_args);
93 called = std::exchange(other.called, true);
94 return *this;
95 }
96 ~AlwaysCallOnce()
97 {
98 finalCall();
99 }
100
101 template <typename... Args>
102 auto operator()(Args&&... args) noexcept
103 {
104 called = true;
105 return f(std::forward<Args>(args)...);
106 }
107
108 private:
109 F f;
110 std::tuple<DefaultArgs...> default_args;
111 bool called = false;
112
113 void finalCall() noexcept
114 {
115 if (!called && detail::fPop(f))
116 {
117 std::apply(f, default_args);
118 }
119 }
120};
121
122template <typename... Args>
123inline auto alwaysCallOnce(Args&&... args)
124{
125 return AlwaysCallOnce<std::remove_cv_t<std::remove_reference_t<Args>>...>(
126 std::forward<Args>(args)...);
127}
128
William A. Kennington III458aeae2021-06-14 15:07:16 -0700129} // namespace stdplus