blob: b8bc82de86861a038774d51c98a553d1186af1cc [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{
33 Cancel() : detail::CancelHandle(std::nullopt)
34 {
35 }
William A. Kennington III8ec04ce2021-06-29 18:08:30 -070036 template <typename T>
37 explicit Cancel(T&& t) : detail::CancelHandle(t)
William A. Kennington III16f6add2021-06-29 11:01:17 -070038 {
39 }
40};
William A. Kennington III458aeae2021-06-14 15:07:16 -070041
William A. Kennington III20cab0c2021-06-14 15:13:19 -070042namespace detail
43{
44
45struct fAny
46{
47};
48struct fPtr : fAny
49{
50};
51
52template <typename>
53struct validator
54{
55 typedef int type;
56};
57
58template <typename F,
59 typename validator<decltype(std::declval<F>() == nullptr)>::type = 0>
60inline bool fPop(const F& f, fPtr)
61{
62 return !(f == nullptr);
63}
64
65template <typename F>
66inline bool fPop(const F&, fAny)
67{
68 return true;
69}
70
71template <typename F>
72inline bool fPop(const F& f)
73{
74 return fPop(f, fPtr());
75}
76
77} // namespace detail
78
79template <typename F, typename... DefaultArgs>
80class AlwaysCallOnce
81{
82 public:
83 template <typename Fi, typename... Vs>
84 explicit AlwaysCallOnce(Fi&& fi, Vs&&... default_args) :
85 f(std::forward<Fi>(fi)), default_args(std::forward<Vs>(default_args)...)
86 {
87 }
88 AlwaysCallOnce(const AlwaysCallOnce&) = delete;
89 AlwaysCallOnce(AlwaysCallOnce&& other) noexcept :
90 f(std::move(other.f)), default_args(std::move(other.default_args)),
91 called(std::exchange(other.called, true))
92 {
93 }
94 AlwaysCallOnce& operator=(const AlwaysCallOnce&) = delete;
95 AlwaysCallOnce& operator=(AlwaysCallOnce&& other) noexcept
96 {
97 finalCall();
98 f = std::move(other.f);
99 default_args = std::move(other.default_args);
100 called = std::exchange(other.called, true);
101 return *this;
102 }
103 ~AlwaysCallOnce()
104 {
105 finalCall();
106 }
107
108 template <typename... Args>
109 auto operator()(Args&&... args) noexcept
110 {
111 called = true;
112 return f(std::forward<Args>(args)...);
113 }
114
115 private:
116 F f;
117 std::tuple<DefaultArgs...> default_args;
118 bool called = false;
119
120 void finalCall() noexcept
121 {
122 if (!called && detail::fPop(f))
123 {
124 std::apply(f, default_args);
125 }
126 }
127};
128
129template <typename... Args>
130inline auto alwaysCallOnce(Args&&... args)
131{
132 return AlwaysCallOnce<std::remove_cv_t<std::remove_reference_t<Args>>...>(
133 std::forward<Args>(args)...);
134}
135
William A. Kennington III458aeae2021-06-14 15:07:16 -0700136} // namespace stdplus