158
158
#include < stop_token> // std::stop_source, std::stop_token
159
159
#include < optional>
160
160
#include < utility> // std::move, std::move_if_noexcept
161
- #include < type_traits> // for noexcept specs
161
+ #include < type_traits> // for requires clauses and noexcept specs
162
162
163
163
namespace chops {
164
164
165
165
template <typename T, typename Container = std::deque<T> >
166
+ requires std::is_copy_constructible_v<T> || std::is_move_constructible_v<T>
166
167
class wait_queue {
167
168
private:
168
169
mutable std::mutex m_mut;
@@ -195,8 +196,10 @@ class wait_queue {
195
196
* @post @c stop_requested returns @c false.
196
197
*/
197
198
wait_queue ()
198
- // noexcept(std::is_nothrow_constructible<Container>::value)
199
- : m_stop_src(std::stop_source{}), m_stop_tok((*m_stop_src).get_token()) {
199
+ requires std::is_default_constructible_v<Container>
200
+ // noexcept(std::is_nothrow_constructible_v<Container>)
201
+ : m_stop_src(std::stop_source{}), m_stop_tok((*m_stop_src).get_token())
202
+ {
200
203
assert (empty ());
201
204
assert (size () == size_type (0 ));
202
205
assert (!stop_requested ());
@@ -212,8 +215,10 @@ class wait_queue {
212
215
* @post @c size returns 0.
213
216
*/
214
217
wait_queue (std::stop_token stop_tok)
215
- // noexcept(std::is_nothrow_constructible<Container>::value)
216
- : m_stop_tok(stop_tok) {
218
+ requires std::is_default_constructible_v<Container>
219
+ // noexcept(std::is_nothrow_constructible_v<Container, std::stop_token>)
220
+ : m_stop_tok(stop_tok)
221
+ {
217
222
assert (empty ());
218
223
assert (size () == size_type (0 ));
219
224
}
@@ -236,15 +241,16 @@ class wait_queue {
236
241
* @param container Container object to be moved from (or copied from if not
237
242
* movable).
238
243
*
239
- * @post @c empty returns @c true if @c beg equals @c end otherwise returns @c false.
240
- * @post @c size returns the distance between @c beg and @c end parameters.
244
+ * @post @c empty and @c size match moved (or copied) in container.
241
245
*/
242
246
wait_queue (Container&& container)
243
- // noexcept(std::is_ something movable or maybe copyable )
247
+ requires std::is_move_constructible_v<Container> ||
248
+ std::is_copy_constructible_v<Container>
249
+ // noexcept(std::is_nnthrow_constructible_v<Container, Container&&>)
244
250
: m_stop_src(std::stop_source{}), m_stop_tok((*m_stop_src).get_token()),
245
- m_data_queue (std::move(container)) {
246
- // assert(empty() == (beg == end));
247
- // assert((size() == size_type(0)) == (beg == end)); // std::distance constrains beg, end.
251
+ m_data_queue (std::move(container))
252
+ {
253
+ // not easily assertible until contracts added to C++
248
254
}
249
255
250
256
/* *
@@ -257,14 +263,14 @@ class wait_queue {
257
263
* @param container Container object to be moved from (or copied from if not
258
264
* movable).
259
265
*
260
- * @post @c empty returns @c true if @c beg equals @c end otherwise returns @c false.
261
- * @post @c size returns the distance between @c beg and @c end parameters.
266
+ * @post @c empty and @c size match moved (or copied) in container.
262
267
*/
263
268
wait_queue (std::stop_token stop_tok, Container&& container)
264
- // noexcept(std::is_nothrow_constructible<Container, Iter, Iter>::value)
265
- : m_stop_tok(stop_tok), m_data_queue(std::move(container)) {
266
- // assert(empty() == (beg == end));
267
- // assert((size() == size_type(0)) == (beg == end)); // std::distance constrains beg, end.
269
+ requires std::is_move_constructible_v<Container> ||
270
+ std::is_copy_constructible_v<Container>
271
+ // noexcept(std::is_nothrow_constructible_v<Container, std::stop_token, Container&&>)
272
+ : m_stop_tok(stop_tok), m_data_queue(std::move(container))
273
+ {
268
274
}
269
275
270
276
/* *
@@ -290,9 +296,11 @@ class wait_queue {
290
296
* @post @c size returns 0 or @c sz depending on container used.
291
297
*/
292
298
wait_queue (size_type sz)
293
- // noexcept(std::is_nothrow_constructible<Container, size_type>::value)
299
+ requires std::is_constructible_v<Container, size_type>
300
+ // noexcept(std::is_nothrow_constructible_v<Container, size_type>)
294
301
: m_stop_src(std::stop_source{}), m_stop_tok((*m_stop_src).get_token()),
295
- m_data_queue (sz) {
302
+ m_data_queue (sz)
303
+ {
296
304
assert ((sz != size_type (0 )) || empty ());
297
305
assert ((size () == size_type (0 )) || (size () == sz));
298
306
}
@@ -310,8 +318,10 @@ class wait_queue {
310
318
* @post @c size returns 0 or @c sz depending on container used.
311
319
*/
312
320
wait_queue (std::stop_token stop_tok, size_type sz)
313
- // noexcept(std::is_nothrow_constructible<Container, size_type>::value)
314
- : m_stop_tok((*m_stop_src).get_token()), m_data_queue(sz) {
321
+ requires std::is_constructible_v<Container, std::stop_token, size_type>
322
+ // noexcept(std::is_nothrow_constructible_v<Container, std::stop_token, size_type>)
323
+ : m_stop_tok((*m_stop_src).get_token()), m_data_queue(sz)
324
+ {
315
325
assert ((sz != size_type (0 )) || empty ());
316
326
assert ((size () == size_type (0 )) || (size () == sz));
317
327
}
@@ -341,13 +351,12 @@ class wait_queue {
341
351
* external @c std::stop_token was passed in.
342
352
*/
343
353
auto request_stop () noexcept
344
- -> bool {
345
-
354
+ -&g
F438
t; bool
355
+ {
346
356
if (m_stop_src) {
347
357
return (*m_stop_src).request_stop ();
348
358
}
349
359
return false ;
350
-
351
360
}
352
361
353
362
/* *
@@ -364,9 +373,11 @@ class wait_queue {
364
373
* @post If @c true is returned and @c empty is @c false, one of any threads waiting for a
365
374
* value will be unblocked.
366
375
*/
367
- auto push (const T& val) /* noexcept(std::is_nothrow_copy_constructible<T>::value) */
368
- -> bool {
376
+ auto push (const T& val) /* noexcept(std::is_nothrow_copy_constructible_v<T>) */
377
+ -> bool
378
+ requires requires (T val, Container c) { c.push_back (val); }
369
379
380
+ {
370
381
if (m_stop_tok.stop_requested ()) {
371
382
return false ;
372
383
}
@@ -386,9 +397,11 @@ class wait_queue {
386
397
* @post If @c true is returned and @c empty is @c false, one of any threads waiting for a
387
398
* value will be unblocked.
388
399
*/
389
- auto push (T&& val) /* noexcept(std::is_nothrow_move_constructible<T>::value) */
390
- -> bool {
400
+ auto push (T&& val) /* noexcept(std::is_nothrow_move_constructible_v<T>) */
401
+ -> bool
402
+ requires requires (T val, Container c) { c.push_back (val); }
391
403
404
+ {
392
405
if (m_stop_tok.stop_requested ()) {
393
406
return false ;
394
407
}
@@ -416,17 +429,18 @@ class wait_queue {
416
429
* value will be unblocked.
417
430
*/
418
431
template <typename ... Args>
419
- auto emplace_push (Args &&... args) /* noexcept(std::is_nothrow_constructible<T, Args...>::value)*/
420
- -> bool {
421
-
432
+ auto emplace_push (Args &&... args) /* noexcept(std::is_nothrow_constructible_v<T, Args...>)*/
433
+ -> bool
434
+ requires requires (Args && args, Container c) { c.emplace_back (args); }
435
+
436
+ {
422
437
if (m_stop_tok.stop_requested ()) {
423
438
return false ;
424
439
}
425
440
lock_guard lk{m_mut};
426
441
m_data_queue.emplace_back (std::forward<Args>(args)...);
427
442
m_data_cond.notify_one ();
428
443
return true ;
429
-
430
444
}
431
445
432
446
/* *
@@ -443,9 +457,11 @@ class wait_queue {
443
457
* @post If a non empty value is returned, until a push function is called, @c size is one
444
458
* less than before this function was called.
445
459
*/
446
- auto wait_and_pop () /* noexcept(std::is_nothrow_constructible<T>::value) */
447
- -> std::optional<T> {
460
+ [[nodiscard]] auto wait_and_pop () /* noexcept(std::is_nothrow_constructible_v<T>) */
461
+ -> std::optional<T>
462
+ requires requires (Container c) { c.empty (); c.pop_front (); }
448
463
464
+ {
449
465
std::unique_lock<std::mutex> lk{m_mut};
450
466
if (!m_data_cond.wait ( lk, m_stop_tok, [this ] { return !m_data_queue.empty (); } )) {
451
467
return std::optional<T> {}; // queue was request to stop, no data available
@@ -472,9 +488,10 @@ class wait_queue {
472
488
* @post If a non empty value is returned, until a push function is called, @c size is one
473
489
* less than before this function was called.
474
490
*/
475
- auto try_pop () /* noexcept(std::is_nothrow_constructible<T>::value) */
476
- -> std::optional<T> {
477
-
491
+ [[nodiscard]] auto try_pop () /* noexcept(std::is_nothrow_constructible_v<T>) */
492
+ -> std::optional<T>
493
+ requires requires (Container c) { c.empty (); c.pop_front (); }
494
+ {
478
495
if (m_stop_tok.stop_requested ()) {
479
496
return std::optional<T> {};
480
497
}
@@ -520,9 +537,11 @@ class wait_queue {
520
537
* same @c wait_queue since it results in recursive mutex locks.
521
538
*/
522
539
template <typename F>
523
- auto apply (F&& func) const /* noexcept(std::is_nothrow_invocable<F&&, const T&>::value) */
524
- -> void {
540
+ auto apply (F&& func) const /* noexcept(std::is_nothrow_invocable_v<F&&, const T&>) */
541
+ -> void
542
+ requires requires (T elem, F func) { func (elem); }
525
543
544
+ {
526
545
lock_guard lk{m_mut};
527
546
for (const T& elem : m_data_queue) {
528
547
func (elem);
@@ -536,21 +555,23 @@ class wait_queue {
536
555
*
537
556
* @return @c true if the @c stop_requested has been called.
538
557
*/
539
- auto stop_requested () const noexcept
540
- -> bool {
558
+ [[nodiscard]] auto stop_requested () const noexcept
559
+ -> bool
541
560
561
+ {
542
562
return m_stop_tok.stop_requested ();
543
-
544
563
}
545
564
546
565
/* *
547
566
* Query whether the @c wait_queue is empty or not.
548
567
*
549
568
* @return @c true if the @c wait_queue is empty.
550
569
*/
551
- auto empty () const /* noexcept */
552
- -> bool {
570
+ [[nodiscard]] auto empty () const /* noexcept */
571
+ -> bool
572
+ requires requires (Container c) { c.empty (); }
553
573
574
+ {
554
575
lock_guard lk{m_mut};
555
576
return m_data_queue.empty ();
556
577
@@ -561,9 +582,11 @@ class wait_queue {
561
582
*
562
583
* @return Number of elements in the @c wait_queue.
563
584
*/
564
- auto size () const /* noexcept */
565
- -> size_type {
585
+ [[nodiscard]] auto size () const /* noexcept */
586
+ -> size_type
587
+ requires requires (Container c) { c.size (); }
566
588
589
+ {
567
590
lock_guard lk{m_mut};
568
591
return m_data_queue.size ();
569
592
0 commit comments