ros2_control - rolling
Loading...
Searching...
No Matches
lock_free_pooled_queue.hpp
1// Copyright 2025 PAL Robotics S.L.
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 REALTIME_TOOLS__LOCK_FREE_POOLED_QUEUE_HPP_
16#define REALTIME_TOOLS__LOCK_FREE_POOLED_QUEUE_HPP_
17
18#include <array>
19#include <cstddef>
20#include <type_traits>
21#include <utility>
22
23#include "realtime_tools/lock_free_queue.hpp"
24
25namespace realtime_tools
26{
43template <typename T, std::size_t Capacity>
45{
46 static_assert(Capacity > 0, "Capacity must be greater than zero");
47
48public:
51 {
52 for (std::size_t i = 0; i < Capacity; ++i) {
53 (void)free_.push(i); // cannot fail, the free queue has room for every slot
54 }
55 }
56
64 template <typename Fill>
65 [[nodiscard]] bool produce(Fill && fill)
66 {
67 std::size_t index;
68 if (!free_.pop(index)) {
69 return false;
70 }
71 fill(slots_[index]);
72 return filled_.push(index); // cannot fail, at most Capacity indices exist
73 }
74
83 // SFINAE instead of a C++20 requires-clause so the header stays usable from C++17 code. U must be
84 // T, otherwise an explicit push<U>() / pop<U>() would bypass the nothrow check on T.
85 template <
86 typename U = T,
87 std::enable_if_t<std::is_same_v<U, T> && std::is_nothrow_move_assignable_v<U>, int> = 0>
88 [[nodiscard]] bool push(T && value)
89 {
90 return produce([&value](T & slot) { slot = std::move(value); });
91 }
92
99 template <typename Use>
100 [[nodiscard]] bool consume(Use && use)
101 {
102 std::size_t index;
103 if (!filled_.pop(index)) {
104 return false;
105 }
106 use(slots_[index]);
107 return free_.push(index); // cannot fail, at most Capacity indices exist
108 }
109
117 template <
118 typename U = T,
119 std::enable_if_t<std::is_same_v<U, T> && std::is_nothrow_move_assignable_v<U>, int> = 0>
120 [[nodiscard]] bool pop(T & out)
121 {
122 return consume([&out](T & slot) { out = std::move(slot); });
123 }
124
126 bool empty() const { return filled_.empty(); }
127
128private:
129 std::array<T, Capacity> slots_;
132};
133} // namespace realtime_tools
134#endif // REALTIME_TOOLS__LOCK_FREE_POOLED_QUEUE_HPP_
Wait-free SPSC queue for large or move-only types, backed by a preallocated pool.
Definition lock_free_pooled_queue.hpp:45
bool push(T &&value)
Move the value into a free slot and publish it to the consumer.
Definition lock_free_pooled_queue.hpp:88
bool consume(Use &&use)
Read the oldest published slot in place and release it back to the pool.
Definition lock_free_pooled_queue.hpp:100
bool empty() const
Definition lock_free_pooled_queue.hpp:126
LockFreePooledSPSCQueue()
Construct the queue with all slots free.
Definition lock_free_pooled_queue.hpp:50
bool pop(T &out)
Move the oldest element out of the queue.
Definition lock_free_pooled_queue.hpp:120
bool produce(Fill &&fill)
Fill a free slot in place and publish it to the consumer.
Definition lock_free_pooled_queue.hpp:65
A pthread mutex wrapper that provides a mutex with the priority inheritance protocol and a priority c...
Definition async_function_handler.hpp:42
std::conditional_t< Capacity==0, LockFreeQueueBase< DataType, boost::lockfree::spsc_queue< DataType > >, LockFreeQueueBase< DataType, boost::lockfree::spsc_queue< DataType, boost::lockfree::capacity< Capacity > > > > LockFreeSPSCQueue
Lock-free Single Producer Single Consumer Queue.
Definition lock_free_queue.hpp:338