C/C++ API Reference
Loading...
Searching...
No Matches
poll.h
1// Copyright 2023 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <optional>
17
18#include "lib/stdcompat/type_traits.h"
19#include "pw_async2/internal/poll_internal.h"
20#include "pw_polyfill/language_feature_macros.h"
21#include "pw_preprocessor/compiler.h"
22#include "pw_string/to_string.h"
23
24namespace pw {
25
26template <typename>
27class Result;
28
29namespace async2 {
30
32
40struct ReadyType final {};
41
42#define PW_ASYNC2_POLL_NODISCARD \
43 PW_NODISCARD_STR( \
44 "`Poll`-returning functions may or may not have completed. Their " \
45 "return value should be examined.")
46
52struct PW_ASYNC2_POLL_NODISCARD PendingType final {};
53
54template <typename T = void>
55class PW_ASYNC2_POLL_NODISCARD Poll;
56
64template <>
65class PW_ASYNC2_POLL_NODISCARD Poll<void> {
66 public:
67 using value_type = void;
68
69 Poll() = delete;
70
71 constexpr Poll(const Poll&) = default;
72 constexpr Poll& operator=(const Poll&) = default;
73 constexpr Poll(Poll&&) = default;
74 constexpr Poll& operator=(Poll&&) = default;
75
76 constexpr Poll(std::in_place_t) : Poll(ReadyType{}) {}
77 constexpr Poll(std::in_place_t, ReadyType) : Poll(ReadyType{}) {}
78
79 constexpr Poll(ReadyType) : ready_(true) {}
80 constexpr Poll& operator=(ReadyType) {
81 ready_ = true;
82 return *this;
83 }
84
85 constexpr Poll(PendingType) : ready_(false) {}
86 constexpr Poll& operator=(PendingType) {
87 ready_ = false;
88 return *this;
89 }
90
91 constexpr bool IsReady() const noexcept { return ready_; }
92 constexpr bool IsPending() const noexcept { return !ready_; }
93
94 constexpr Poll Readiness() const noexcept { return *this; }
95
97 constexpr ReadyType& value() noexcept { return value_; }
99 constexpr const ReadyType& value() const noexcept { return value_; }
100
102 constexpr const ReadyType* operator->() const noexcept { return &value_; }
104 constexpr ReadyType* operator->() noexcept { return &value_; }
105
107 constexpr const ReadyType& operator*() const noexcept { return value_; }
109 constexpr ReadyType& operator*() noexcept { return value_; }
110
111 constexpr void IgnorePoll() const {}
112
113 friend constexpr bool operator==(const Poll& lhs, const Poll& rhs) {
114 return lhs.ready_ == rhs.ready_;
115 }
116
117 friend constexpr bool operator!=(const Poll& lhs, const Poll& rhs) {
118 return lhs.ready_ != rhs.ready_;
119 }
120
121 private:
123 bool ready_;
124};
125
137template <typename T>
138class PW_ASYNC2_POLL_NODISCARD Poll {
139 public:
140 using value_type = T;
141
143 Poll() = delete;
144 constexpr Poll(const Poll&) = default;
145 constexpr Poll& operator=(const Poll&) = default;
146 constexpr Poll(Poll&&) = default;
147 constexpr Poll& operator=(Poll&&) = default;
148
157 template <
158 typename U,
159 internal_poll::EnableIfImplicitlyConvertible<value_type, const U&> = 0>
160 constexpr Poll(const Poll<U>& other) : value_(other.value_) {}
161 template <
162 typename U,
163 internal_poll::EnableIfExplicitlyConvertible<value_type, const U&> = 0>
164 explicit constexpr Poll(const Poll<U>& other) : value_(other.value_) {}
165
166 template <typename U,
167 internal_poll::EnableIfImplicitlyConvertible<value_type, U&&> = 0>
168 constexpr Poll(Poll<U>&& other) // NOLINT
169 : value_(std::move(other.value_)) {}
170 template <typename U,
171 internal_poll::EnableIfExplicitlyConvertible<value_type, U&&> = 0>
172 explicit constexpr Poll(Poll<U>&& other) : value_(std::move(other.value_)) {}
173
174 // Constructs the inner value `T` in-place using the provided args, using the
175 // `T(U)` (direct-initialization) constructor. This constructor is only valid
176 // if `T` can be constructed from a `U`. Can accept move or copy constructors.
177 //
178 // This constructor is explicit if `U` is not convertible to `T`. To avoid
179 // ambiguity, this constructor is disabled if `U` is a `Poll<J>`, where `J` is
180 // convertible to `T`.
181 template <typename U = value_type,
182 internal_poll::EnableIfImplicitlyInitializable<value_type, U> = 0>
183 constexpr Poll(U&& u) // NOLINT
184 : Poll(std::in_place, std::forward<U>(u)) {}
185
186 template <typename U = value_type,
187 internal_poll::EnableIfExplicitlyInitializable<value_type, U> = 0>
188 explicit constexpr Poll(U&& u) // NOLINT
189 : Poll(std::in_place, std::forward<U>(u)) {}
190
191 // In-place construction of `Ready` variant.
192 template <typename... Args>
193 constexpr Poll(std::in_place_t, Args&&... args)
194 : value_(std::in_place, std::move(args)...) {}
195
196 // Convert from `T`
197 constexpr Poll(value_type&& value) : value_(std::move(value)) {}
198 constexpr Poll& operator=(value_type&& value) {
199 value_ = std::optional<value_type>(std::move(value));
200 return *this;
201 }
202
203 // Convert from `Pending`
204 constexpr Poll(PendingType) noexcept : value_() {}
205 constexpr Poll& operator=(PendingType) noexcept {
206 value_ = std::nullopt;
207 return *this;
208 }
209
211 constexpr bool IsReady() const noexcept { return value_.has_value(); }
212
214 constexpr bool IsPending() const noexcept { return !value_.has_value(); }
215
218 constexpr Poll<> Readiness() const noexcept {
219 if (IsReady()) {
220 return ReadyType();
221 }
222 return PendingType();
223 }
224
228 constexpr value_type& value() & noexcept { return *value_; }
229 constexpr const value_type& value() const& noexcept { return *value_; }
230 constexpr value_type&& value() && noexcept { return std::move(*value_); }
231 constexpr const value_type&& value() const&& noexcept {
232 return std::move(*value_);
233 }
234
238 constexpr const value_type* operator->() const noexcept { return &*value_; }
239 constexpr value_type* operator->() noexcept { return &*value_; }
240
244 constexpr const value_type& operator*() const& noexcept { return *value_; }
245 constexpr value_type& operator*() & noexcept { return *value_; }
246 constexpr const value_type&& operator*() const&& noexcept {
247 return std::move(*value_);
248 }
249 constexpr value_type&& operator*() && noexcept { return std::move(*value_); }
250
255 constexpr void IgnorePoll() const {}
256
257 private:
258 static_assert(!std::is_same_v<cpp20::remove_cvref_t<T>, ReadyType>,
259 "Poll<ReadyType> is not permitted; use Poll<void> instead");
260
261 template <typename U>
262 friend class Poll;
263 std::optional<value_type> value_;
264};
265
266#undef PW_ASYNC2_POLL_NODISCARD
267
268// Deduction guide to allow `Poll(v)` rather than `Poll<T>(v)`.
269template <typename T>
270Poll(T value) -> Poll<T>;
271
273template <typename T>
275
277template <typename T>
279
285template <typename T>
286constexpr bool operator==(const Poll<T>& lhs, const Poll<T>& rhs) {
287 if (lhs.IsReady() && rhs.IsReady()) {
288 return *lhs == *rhs;
289 }
290 return lhs.IsReady() == rhs.IsReady();
291}
292
298template <typename T>
299constexpr bool operator!=(const Poll<T>& lhs, const Poll<T>& rhs) {
300 return !(lhs == rhs);
301}
302
304template <typename T>
305constexpr bool operator==(const Poll<T>& lhs, PendingType) {
306 return lhs.IsPending();
307}
308
310template <typename T>
311constexpr bool operator!=(const Poll<T>& lhs, PendingType) {
312 return !lhs.IsPending();
313}
314
316template <typename T>
317constexpr bool operator==(PendingType, const Poll<T>& rhs) {
318 return rhs.IsPending();
319}
320
322template <typename T>
323constexpr bool operator!=(PendingType, const Poll<T>& rhs) {
324 return !rhs.IsPending();
325}
326
327// `ReadyType` is the value type for `Poll<T>` and has no value, so it should
328// always compare equal.
329constexpr bool operator==(ReadyType, ReadyType) { return true; }
330constexpr bool operator!=(ReadyType, ReadyType) { return false; }
331
332// The `Pending` case holds no value, so is always equal.
333constexpr bool operator==(PendingType, PendingType) { return true; }
334constexpr bool operator!=(PendingType, PendingType) { return false; }
335
337inline constexpr Poll<> Ready() { return Poll<>(ReadyType{}); }
338
341template <typename T, typename... Args>
342constexpr Poll<T> Ready(std::in_place_t, Args&&... args) {
343 return Poll<T>(std::in_place, std::forward<Args>(args)...);
344}
345
347template <typename T>
349 return Poll<std::remove_reference_t<T>>(std::forward<T>(value));
350}
351
353inline constexpr PendingType Pending() { return PendingType(); }
354
355template <typename T>
357 using Type = T;
358};
359
360template <typename T>
361struct UnwrapPoll<Poll<T>> {
362 using Type = T;
363};
364
365} // namespace async2
366
367// --- ToString implementations for `Poll` types ---
368
369template <>
370inline StatusWithSize ToString(const async2::ReadyType&, span<char> buffer) {
371 return ToString("Ready", buffer);
372}
373
374template <>
375inline StatusWithSize ToString(const async2::PendingType&, span<char> buffer) {
376 return ToString("Pending", buffer);
377}
378
379// Implement `ToString` for `Poll<T>`.
380template <typename T>
381inline StatusWithSize ToString(const async2::Poll<T>& poll, span<char> buffer) {
382 if (poll.IsReady()) {
383 StatusWithSize s;
384 s.UpdateAndAdd(ToString("Ready(", buffer));
385 s.UpdateAndAdd(ToString(*poll, buffer.subspan(s.size())));
386 s.UpdateAndAdd(ToString(")", buffer.subspan(s.size())));
387 s.ZeroIfNotOk();
388 return s;
389 }
390 return ToString(async2::PendingType{}, buffer);
391}
392
393template <>
394inline StatusWithSize ToString(const async2::Poll<>& poll, span<char> buffer) {
395 if (poll.IsReady()) {
396 return ToString(async2::ReadyType{}, buffer);
397 }
398 return ToString(async2::PendingType{}, buffer);
399}
400
402
403} // namespace pw
Definition: status_with_size.h:51
constexpr void UpdateAndAdd(StatusWithSize new_status_with_size)
Definition: status_with_size.h:128
Definition: poll.h:138
Definition: span_impl.h:235
friend constexpr bool operator!=(const Poll &lhs, const Poll &rhs)
Definition: poll.h:117
constexpr ReadyType & operator*() noexcept
Returns a ReadyType for compatibility with non-void Poll.
Definition: poll.h:109
constexpr const value_type & operator*() const &noexcept
Definition: poll.h:244
constexpr bool operator!=(const Poll< T > &lhs, const Poll< T > &rhs)
Definition: poll.h:299
constexpr ReadyType & value() noexcept
Returns a ReadyType for compatibility with non-void Poll.
Definition: poll.h:97
constexpr bool IsReady() const noexcept
Returns whether or not this value is Ready.
Definition: poll.h:211
constexpr bool operator==(const Poll< T > &lhs, const Poll< T > &rhs)
Definition: poll.h:286
constexpr const ReadyType * operator->() const noexcept
Returns a ReadyType for compatibility with non-void Poll.
Definition: poll.h:102
constexpr const ReadyType & value() const noexcept
Returns a ReadyType for compatibility with non-void Poll.
Definition: poll.h:99
constexpr Poll Readiness() const noexcept
Definition: poll.h:218
constexpr const value_type * operator->() const noexcept
Definition: poll.h:238
constexpr bool IsPending() const noexcept
Returns whether or not this value is Pending.
Definition: poll.h:214
friend constexpr bool operator==(const Poll &lhs, const Poll &rhs)
Definition: poll.h:113
constexpr Poll(const Poll< U > &other)
Definition: poll.h:160
constexpr ReadyType * operator->() noexcept
Returns a ReadyType for compatibility with non-void Poll.
Definition: poll.h:104
constexpr PendingType Pending()
Returns a value indicating that an operation was not yet able to complete.
Definition: poll.h:353
constexpr const ReadyType & operator*() const noexcept
Returns a ReadyType for compatibility with non-void Poll.
Definition: poll.h:107
constexpr value_type & value() &noexcept
Definition: poll.h:228
Poll()=delete
Basic constructors.
constexpr void IgnorePoll() const
Definition: poll.h:255
constexpr Poll Ready()
Returns a value indicating completion.
Definition: poll.h:337
#define PW_NO_UNIQUE_ADDRESS
Definition: compiler.h:297
Result(T value) -> Result< T >
Deduction guide to allow Result(v) rather than Result<T>(v).
The Pigweed namespace.
Definition: alignment.h:27
Definition: poll.h:52
Definition: poll.h:40
Definition: poll.h:356