Monado OpenXR Runtime
u_id_ringbuffer.h
Go to the documentation of this file.
1// Copyright 2022, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief Ring buffer for things keyed on an ID but otherwise maintained externally, for C usage.
6 * @author Rylie Pavlik <rylie.pavlik@collabora.com>
7 * @ingroup aux_util
8 */
9
10#pragma once
11
12#include <stdint.h>
13#include <stddef.h>
14
15#ifdef __cplusplus
16extern "C" {
17#endif
18
19/**
20 * Container type to let you store IDs in a ring buffer, and maybe your own data in your own parallel array.
21 *
22 * The IDs are uint64_t. If you don't need any of the order-dependent functionality, you can treat use them for any
23 * purpose you like.
24 *
25 * Some functionality requires that IDs be pushed in increasing order, but it's highlighted in the docs.
26 * If you need more than this, either extend this or use the underlying C++ container if that's an OK solution for you.
27 *
28 */
29struct u_id_ringbuffer;
30
31/**
32 * Create a ringbuffer for storing IDs.
33 *
34 * You might keep an array of equivalent capacity locally: methods of this container will tell you which index in that
35 * array to interact with.
36 *
37 * @param capacity
38 * @return struct u_id_ringbuffer*
39 *
40 * @public @memberof u_id_ringbuffer
41 */
42struct u_id_ringbuffer *
43u_id_ringbuffer_create(uint32_t capacity);
44
45/**
46 * Push a new element to the back
47 *
48 * @param uirb self pointer
49 * @param id The ID to push back. It is your responsibility to make sure you insert in order if you want to use ordered
50 * methods.
51 * @return the "inner" index in your array to store any associated data, or negative if error.
52 *
53 * @public @memberof u_id_ringbuffer
54 */
55int64_t
56u_id_ringbuffer_push_back(struct u_id_ringbuffer *uirb, uint64_t id);
57
58/**
59 * Pop an element from the front, if any
60 *
61 * @param uirb self pointer.
62 *
63 * @public @memberof u_id_ringbuffer
64 */
65void
67
68/**
69 * Pop an element from the back, if any
70 *
71 * @param uirb self pointer.
72 *
73 * @public @memberof u_id_ringbuffer
74 */
75void
77
78/**
79 * Get the back (most recent) of the buffer
80 *
81 * @param uirb self pointer
82 * @param[out] out_id Where to store the back ID
83 * @return the "inner" index in your array with any associated data, or negative if error (empty, etc).
84 *
85 * @public @memberof u_id_ringbuffer
86 */
87int32_t
88u_id_ringbuffer_get_back(struct u_id_ringbuffer *uirb, uint64_t *out_id);
89
90/**
91 * Get the front (least recent) of the buffer
92 *
93 * @param uirb self pointer
94 * @param[out] out_id Where to store the front ID
95 * @return the "inner" index in your array with any associated data, or negative if error (empty, etc).
96 *
97 * @public @memberof u_id_ringbuffer
98 */
99int32_t
100u_id_ringbuffer_get_front(struct u_id_ringbuffer *uirb, uint64_t *out_id);
101
102/**
103 * Get the number of elements in the buffer
104 *
105 * @param uirb self pointer
106 * @return the size
107 *
108 * @public @memberof u_id_ringbuffer
109 */
110uint32_t
111u_id_ringbuffer_get_size(struct u_id_ringbuffer const *uirb);
112
113/**
114 * Get whether the buffer is empty
115 *
116 * @param uirb self pointer
117 * @return true if empty
118 *
119 * @public @memberof u_id_ringbuffer
120 */
121bool
122u_id_ringbuffer_is_empty(struct u_id_ringbuffer const *uirb);
123
124/**
125 * Get an element a certain distance ("age") from the back of the buffer
126 *
127 * See u_id_ringbuffer_get_at_clamped_age() if you want to clamp the age
128 *
129 * @param uirb self pointer
130 * @param age the distance from the back (0 is the same as back, 1 is previous, etc)
131 * @param[out] out_id Where to store the ID, if successful (optional)
132 * @return the "inner" index in your array with any associated data, or negative if error (empty, out of range, etc).
133 *
134 * @public @memberof u_id_ringbuffer
135 */
136int32_t
137u_id_ringbuffer_get_at_age(struct u_id_ringbuffer *uirb, uint32_t age, uint64_t *out_id);
138
139/**
140 * Get an element a certain distance ("age") from the back of the buffer, clamping age to stay in bounds as long as the
141 * buffer is not empty.
142 *
143 * See u_id_ringbuffer_get_at_age() if you don't want clamping.
144 *
145 * @param uirb self pointer
146 * @param age the distance from the back (0 is the same as back, 1 is previous, etc)
147 * @param[out] out_id Where to store the ID, if successful (optional)
148 * @return the "inner" index in your array with any associated data, or negative if error (empty, etc).
149 *
150 * @public @memberof u_id_ringbuffer
151 */
152int32_t
153u_id_ringbuffer_get_at_clamped_age(struct u_id_ringbuffer *uirb, uint32_t age, uint64_t *out_id);
154
155/**
156 * Get an element a certain index from the front of the (logical) buffer
157 *
158 * @param uirb self pointer
159 * @param index the distance from the front (0 is the same as front, 1 is newer, etc)
160 * @param[out] out_id Where to store the ID, if successful (optional)
161 * @return the "inner" index in your array with any associated data, or negative if error (empty, out of range, etc).
162 *
163 * @public @memberof u_id_ringbuffer
164 */
165int32_t
166u_id_ringbuffer_get_at_index(struct u_id_ringbuffer *uirb, uint32_t index, uint64_t *out_id);
167
168/**
169 * Find the latest element not less than the supplied ID @p search_id .
170 *
171 * Assumes/depends on your maintenance of entries in ascending order. If you aren't ensuring this, use
172 * u_id_ringbuffer_find_id_unordered() instead.
173 *
174 * (Wraps `std::lower_bound`)
175 *
176 * @param uirb self pointer
177 * @param search_id the ID to search for.
178 * @param[out] out_id Where to store the ID found, if successful (optional)
179 * @param[out] out_index Where to store the ring buffer index (not the inner index) found, if successful (optional)
180 * @return the "inner" index in your array with any associated data, or negative if error (empty, etc).
181 *
182 * @public @memberof u_id_ringbuffer
183 */
184int32_t
185u_id_ringbuffer_lower_bound_id(struct u_id_ringbuffer *uirb, uint64_t search_id, uint64_t *out_id, uint32_t *out_index);
186
187/**
188 * Find the element with the supplied ID @p search_id in an unordered buffer.
189 *
190 * This does *not* depend on order so does a linear search. If you are keeping your IDs in ascending order, use
191 * u_id_ringbuffer_lower_bound_id() instead.
192 *
193 * @param uirb self pointer
194 * @param search_id the ID to search for.
195 * @param[out] out_id Where to store the ID found, if successful (optional)
196 * @param[out] out_index Where to store the ring buffer index (not the inner index) found, if successful (optional)
197 * @return the "inner" index in your array with any associated data, or negative if error (empty, etc).
198 *
199 * @public @memberof u_id_ringbuffer
200 */
201int32_t
203 uint64_t search_id,
204 uint64_t *out_id,
205 uint32_t *out_index);
206
207/**
208 * Destroy an ID ring buffer.
209 *
210 * Does null checks.
211 *
212 * @param ptr_to_uirb Address of your ring buffer pointer. Will be set to zero.
213 *
214 * @public @memberof u_id_ringbuffer
215 */
216void
217u_id_ringbuffer_destroy(struct u_id_ringbuffer **ptr_to_uirb);
218
219#ifdef __cplusplus
220} // extern "C"
221#endif
Definition: u_id_ringbuffer.cpp:25
void u_id_ringbuffer_pop_back(struct u_id_ringbuffer *uirb)
Pop an element from the back, if any.
Definition: u_id_ringbuffer.cpp:169
int32_t u_id_ringbuffer_find_id_unordered(struct u_id_ringbuffer *uirb, uint64_t search_id, uint64_t *out_id, uint32_t *out_index)
Find the element with the supplied ID search_id in an unordered buffer.
Definition: u_id_ringbuffer.cpp:309
int32_t u_id_ringbuffer_get_back(struct u_id_ringbuffer *uirb, uint64_t *out_id)
Get the back (most recent) of the buffer.
Definition: u_id_ringbuffer.cpp:179
void u_id_ringbuffer_destroy(struct u_id_ringbuffer **ptr_to_uirb)
Destroy an ID ring buffer.
Definition: u_id_ringbuffer.cpp:327
int32_t u_id_ringbuffer_get_front(struct u_id_ringbuffer *uirb, uint64_t *out_id)
Get the front (least recent) of the buffer.
Definition: u_id_ringbuffer.cpp:193
int32_t u_id_ringbuffer_lower_bound_id(struct u_id_ringbuffer *uirb, uint64_t search_id, uint64_t *out_id, uint32_t *out_index)
Find the latest element not less than the supplied ID search_id .
Definition: u_id_ringbuffer.cpp:294
int32_t u_id_ringbuffer_get_at_clamped_age(struct u_id_ringbuffer *uirb, uint32_t age, uint64_t *out_id)
Get an element a certain distance ("age") from the back of the buffer, clamping age to stay in bounds...
Definition: u_id_ringbuffer.cpp:250
int32_t u_id_ringbuffer_get_at_age(struct u_id_ringbuffer *uirb, uint32_t age, uint64_t *out_id)
Get an element a certain distance ("age") from the back of the buffer.
Definition: u_id_ringbuffer.cpp:236
struct u_id_ringbuffer * u_id_ringbuffer_create(uint32_t capacity)
Create a ringbuffer for storing IDs.
Definition: u_id_ringbuffer.cpp:126
int64_t u_id_ringbuffer_push_back(struct u_id_ringbuffer *uirb, uint64_t id)
Push a new element to the back.
Definition: u_id_ringbuffer.cpp:149
uint32_t u_id_ringbuffer_get_size(struct u_id_ringbuffer const *uirb)
Get the number of elements in the buffer.
Definition: u_id_ringbuffer.cpp:208
bool u_id_ringbuffer_is_empty(struct u_id_ringbuffer const *uirb)
Get whether the buffer is empty.
Definition: u_id_ringbuffer.cpp:217
int32_t u_id_ringbuffer_get_at_index(struct u_id_ringbuffer *uirb, uint32_t index, uint64_t *out_id)
Get an element a certain index from the front of the (logical) buffer.
Definition: u_id_ringbuffer.cpp:264
void u_id_ringbuffer_pop_front(struct u_id_ringbuffer *uirb)
Pop an element from the front, if any.
Definition: u_id_ringbuffer.cpp:160