Symbian platform (C++)
SDK native APIs, runtime and tooling
Loading...
Searching...
No Matches
cases.h
Go to the documentation of this file.
1// Copyright 2026 The Action Engine Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://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,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef THREAD_FIBER_CASES_H_
16#define THREAD_FIBER_CASES_H_
17
18#include <cstddef>
19#include <type_traits>
20
21#include <absl/container/inlined_vector.h>
22#include <absl/log/check.h>
23#include <absl/log/log.h>
24
25#include "thread/boost_primitives.h"
26
27namespace thread {
28namespace internal {
29template <typename T>
30concept IsPointer = std::is_pointer_v<T>;
31
32template <typename T>
33concept IsNonConstPointer =
34 IsPointer<T> && !std::is_const_v<std::remove_pointer_t<T>>;
35
36template <typename T>
37concept IsConstPointer =
38 IsPointer<T> && std::is_const_v<std::remove_pointer_t<T>>;
39
40struct Selector {
41 static constexpr int kNonePicked = -1;
42
43 bool TryPick(int case_index) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu) {
44 if (picked_case_index != kNonePicked) {
45 return false; // Already picked.
46 }
47
48 picked_case_index = case_index;
49 cv.Signal();
50 return true;
51 }
52
53 // Returns true iff a case was picked before the deadline.
54 bool WaitForPickUntil(absl::Time deadline) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu) {
55 while (picked_case_index == internal::Selector::kNonePicked) {
56 if (cv.WaitWithDeadline(&mu, deadline) &&
57 picked_case_index == internal::Selector::kNonePicked) {
58 return false;
59 }
60 }
61 return true;
62 }
63
64 // kNonePicked until a case is picked, or the index of picked case
66 int picked_case_index ABSL_GUARDED_BY(mu) = kNonePicked;
67 thread::CondVar cv ABSL_GUARDED_BY(mu);
68};
69
70class Selectable;
71} // namespace internal
72
82struct [[nodiscard]] Case {
83 internal::Selectable* absl_nonnull selectable;
84 absl::InlinedVector<void* absl_nullable, 2> arguments;
85
86 Case(internal::Selectable* absl_nonnull s) : selectable(s) {}
87
88 Case(internal::Selectable* absl_nullable s, internal::IsPointer auto... args)
89 : selectable(s) {
90 (arguments.push_back(const_cast<void*>(static_cast<const void*>(args))),
91 ...);
92 }
93
94 Case(const Case&) = default;
95 Case& operator=(const Case&) = default;
96
97 // // Disallow casting from bool
98 // // ReSharper disable once CppNonExplicitConvertingConstructor
99 template <typename... Args>
100 Case(bool, Args... args) = delete;
101
102 template <typename T>
103 void AddArg(const T* absl_nonnull arg) {
104 arguments.push_back(const_cast<void*>(static_cast<const void*>(arg)));
105 }
106
107 template <typename T>
108 void AddArg(T* absl_nonnull arg) {
109 arguments.push_back(static_cast<void*>(arg));
110 }
111
112 [[nodiscard]] void* absl_nonnull GetArgPtr(int index) const {
113 if (index < 0 || static_cast<size_t>(index) >= arguments.size()) {
114 LOG(FATAL) << "Case::GetArgOrDie: index out of bounds: " << index
115 << ", arguments.size() = " << arguments.size();
116 ABSL_ASSUME(false);
117 }
118 return arguments[static_cast<size_t>(index)];
119 }
120
121 template <typename T>
122 [[nodiscard]] T* absl_nonnull GetArgPtr(int index) const {
123 return static_cast<T*>(GetArgPtr(index));
124 }
125
126 [[nodiscard]] size_t GetNumArgs() const { return arguments.size(); }
127};
128
129// An array of cases; the type supplied to Select. Must be initializer list
130// compatible.
131typedef absl::InlinedVector<Case, 4> CaseArray;
132
133namespace internal {
134struct CaseInSelectClause {
135 const Case* absl_nullable case_ptr = nullptr; // Initialized by Select().
136 int index = -1; // Provided by Select(): index in parameter list.
137 internal::Selector* absl_nonnull selector =
138 nullptr; // Provided by Select(): owning selector.
139 CaseInSelectClause* absl_nullable prev =
140 nullptr; // Initialized by Select(), nullptr -> not on list.
141 CaseInSelectClause* absl_nullable next = nullptr;
142
143 [[nodiscard]] const Case* absl_nonnull GetCase() const { return case_ptr; }
144
145 // Attempt to cause the owning Selector to choose this case.
146 bool TryPick() ABSL_EXCLUSIVE_LOCKS_REQUIRED(selector->mu) {
147 return selector->TryPick(index);
148 }
149
150 bool Handle(bool enqueue);
151 void Unregister();
152};
153
154using CaseStateArray = absl::InlinedVector<CaseInSelectClause, 4>;
155
156// The interface implemented by objects that can be used with Select().
157class Selectable {
158 public:
159 virtual ~Selectable() = default;
160
161 // If this selectable is ready to be picked up by c's Select, call
162 // c->TryPick() (which may or may not pick this selectable), and return true.
163 virtual bool Handle(CaseInSelectClause* absl_nonnull case_state,
164 bool enqueue) = 0;
165
166 // Unregister a case against future transitions for this Selectable.
167 virtual void Unregister(CaseInSelectClause* absl_nonnull case_state) = 0;
168};
169
170inline bool CaseInSelectClause::Handle(bool enqueue) {
171 return GetCase()->selectable->Handle(this, enqueue);
172}
173
174inline void CaseInSelectClause::Unregister() {
175 GetCase()->selectable->Unregister(this);
176}
177
178// Shared linked list code. Implements a doubly-linked list where the list head
179// is a pointer to the oldest element added to the list.
180inline void PushBack(CaseInSelectClause* absl_nonnull* absl_nonnull head,
181 CaseInSelectClause* absl_nonnull element) {
182 CHECK_EQ(element->prev, nullptr)
183 << "Attempted to enqueue a CaseInSelectClause that is already on a list";
184
185 if (*head == nullptr) {
186 // Queue is empty; make singleton queue.
187 element->next = element;
188 element->prev = element;
189 *head = element;
190 } else {
191 CHECK_NE((*head)->prev, nullptr)
192 << "Waiter list head is corrupt: non-null head has null prev";
193
194 // Add just before the oldest element (*head).
195 element->next = *head;
196 element->prev = element->next->prev;
197 element->prev->next = element;
198 element->next->prev = element;
199 }
200}
201
202inline void UnlinkFromList(CaseInSelectClause* absl_nonnull* absl_nonnull head,
203 CaseInSelectClause* absl_nonnull element) {
204 if (element->next == element) {
205 // Single entry; clear list
206 *head = nullptr;
207 } else {
208 // Remove from list
209 element->next->prev = element->prev;
210 element->prev->next = element->next;
211 if (*head == element) {
212 *head = element->next;
213 }
214 }
215 // Maintaining this state in "prev" allows the safe removal of the current
216 // element while iterating forwards.
217 element->prev = nullptr;
218}
219} // namespace internal
220} // namespace thread
221
222#endif // THREAD_FIBER_CASES_H_
Definition boost_primitives.h:110
Definition boost_primitives.h:34
static bool reader selector mu
Definition channel_waiter_state.cc:61
void PushBack(CaseInSelectClause **head, CaseInSelectClause *element)
Definition cases.h:133
void UnlinkFromList(CaseInSelectClause **head, CaseInSelectClause *element)
Definition cases.h:149
absl::InlinedVector< CaseInSelectClause, 4 > CaseStateArray
Definition cases.h:116
Definition channel.h:29
absl::InlinedVector< Case, 4 > CaseArray
Definition cases.h:98
A Case represents a selectable case in a Select statement.
Definition cases.h:55
Case(internal::Selectable *absl_nullable s, internal::IsPointer auto... args)
Definition cases.h:88
Case(internal::Selectable *absl_nonnull s)
Definition cases.h:86
void AddArg(T *absl_nonnull arg)
Definition cases.h:108
T *absl_nonnull GetArgPtr(int index) const
Definition cases.h:122
size_t GetNumArgs() const
Definition cases.h:126
void AddArg(const T *absl_nonnull arg)
Definition cases.h:103
Case(const Case &)=default
Case & operator=(const Case &)=default
void *absl_nonnull GetArgPtr(int index) const
Definition cases.h:112
internal::Selectable *absl_nonnull selectable
Definition cases.h:83
Case(bool, Args... args)=delete
absl::InlinedVector< void *absl_nullable, 2 > arguments
Definition cases.h:84