38#ifndef ETL_BIP_BUFFER_SPSC_ATOMIC_INCLUDED
39#define ETL_BIP_BUFFER_SPSC_ATOMIC_INCLUDED
63 class bip_buffer_exception:
public exception
67 bip_buffer_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
68 : exception(reason_, file_name_, line_number_)
76 class bip_buffer_reserve_invalid:
public bip_buffer_exception
80 bip_buffer_reserve_invalid(string_type file_name_, numeric_type line_number_)
81 : bip_buffer_exception(ETL_ERROR_TEXT(
"bip_buffer:reserve", ETL_BIP_BUFFER_SPSC_ATOMIC_FILE_ID
"A"), file_name_, line_number_)
89 template <
size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
90 class bip_buffer_spsc_atomic_base
110 return available() == 0;
117 size_type size()
const
119 size_type write_index =
write.load(etl::memory_order_acquire);
120 size_type read_index =
read.load(etl::memory_order_acquire);
123 if (write_index >= read_index)
126 return write_index - read_index;
130 size_type last_index = last.load(etl::memory_order_acquire);
133 return (write_index - 0) + (last_index - read_index);
140 size_type available()
const
142 size_type write_index =
write.load(etl::memory_order_acquire);
143 size_type read_index =
read.load(etl::memory_order_acquire);
146 if (write_index >= read_index)
148 size_type forward_size = capacity() - write_index;
151 if (read_index > (forward_size + 1))
153 return read_index - 1;
162 return read_index - write_index - 1;
169 size_type capacity()
const
187 bip_buffer_spsc_atomic_base(size_type reserved_)
191 , RESERVED(reserved_)
198 read.store(0, etl::memory_order_release);
199 write.store(0, etl::memory_order_release);
200 last.store(0, etl::memory_order_release);
204 size_type get_write_reserve(size_type* psize, size_type fallback_size = numeric_limits<size_type>::max())
206 size_type write_index =
write.load(etl::memory_order_relaxed);
207 size_type read_index =
read.load(etl::memory_order_acquire);
210 if (write_index >= read_index)
212 size_type forward_size = capacity() - write_index;
215 if (*psize <= forward_size)
221 else if ((read_index <= (forward_size + 1)) || (fallback_size <= forward_size))
223 *psize = forward_size;
232 if (*psize >= read_index)
236 *psize = read_index - 1;
250 if ((write_index + *psize) >= read_index)
252 *psize = read_index - write_index - 1;
260 void apply_write_reserve(size_type windex, size_type wsize)
264 size_type write_index =
write.load(etl::memory_order_relaxed);
265 size_type read_index =
read.load(etl::memory_order_acquire);
268 if (write_index < read_index)
270 ETL_ASSERT_OR_RETURN((windex == write_index) && ((wsize + 1) <= read_index), ETL_ERROR(bip_buffer_reserve_invalid));
273 else if (windex == write_index)
275 ETL_ASSERT_OR_RETURN(wsize <= (capacity() - write_index), ETL_ERROR(bip_buffer_reserve_invalid));
278 last.store(windex + wsize, etl::memory_order_release);
283 ETL_ASSERT_OR_RETURN((windex == 0) && ((wsize + 1) <= read_index), ETL_ERROR(bip_buffer_reserve_invalid));
287 write.store(windex + wsize, etl::memory_order_release);
292 size_type get_read_reserve(size_type* psize)
294 size_type read_index =
read.load(etl::memory_order_relaxed);
295 size_type write_index =
write.load(etl::memory_order_acquire);
297 if (read_index > write_index)
300 size_type last_index = last.load(etl::memory_order_relaxed);
302 if (read_index == last_index)
310 write_index = last_index;
319 if ((write_index - read_index) < *psize)
321 *psize = write_index - read_index;
328 void apply_read_reserve(size_type rindex, size_type rsize)
332 size_type rsize_checker = rsize;
333 ETL_ASSERT_OR_RETURN((rindex == get_read_reserve(&rsize_checker)) && (rsize == rsize_checker), ETL_ERROR(bip_buffer_reserve_invalid));
335 read.store(rindex + rsize, etl::memory_order_release);
341 etl::atomic<size_type>
read;
342 etl::atomic<size_type>
write;
343 etl::atomic<size_type> last;
344 const size_type RESERVED;
346#if defined(ETL_POLYMORPHIC_SPSC_BIP_BUFFER_ATOMIC) || defined(ETL_POLYMORPHIC_CONTAINERS)
349 virtual ~bip_buffer_spsc_atomic_base()
355 ~bip_buffer_spsc_atomic_base()
364 template <
typename T, const
size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
365 class ibip_buffer_spsc_atomic :
public bip_buffer_spsc_atomic_base<MEMORY_MODEL>
369 typedef typename etl::bip_buffer_spsc_atomic_base<MEMORY_MODEL> base_t;
371 using base_t::get_read_reserve;
372 using base_t::apply_read_reserve;
373 using base_t::get_write_reserve;
374 using base_t::apply_write_reserve;
378 typedef T value_type;
379 typedef T& reference;
380 typedef const T& const_reference;
382 typedef T&& rvalue_reference;
384 typedef typename base_t::size_type size_type;
386 using base_t::max_size;
391 span<T> read_reserve(size_type max_reserve_size = numeric_limits<size_type>::max())
393 size_type reserve_size = max_reserve_size;
394 size_type rindex = get_read_reserve(&reserve_size);
396 return span<T>(p_buffer + rindex, reserve_size);
404 void read_commit(
const span<T> &reserve)
406 size_type rindex = etl::distance(p_buffer, reserve.data());
407 apply_read_reserve(rindex, reserve.size());
413 span<T> write_reserve(size_type max_reserve_size)
415 size_type reserve_size = max_reserve_size;
416 size_type windex = get_write_reserve(&reserve_size);
418 return span<T>(p_buffer + windex, reserve_size);
425 span<T> write_reserve_optimal(size_type min_reserve_size = 1U)
427 size_type reserve_size = numeric_limits<size_type>::max();
428 size_type windex = get_write_reserve(&reserve_size, min_reserve_size);
430 return span<T>(p_buffer + windex, reserve_size);
438 void write_commit(
const span<T> &reserve)
440 size_type windex = etl::distance(p_buffer, reserve.data());
441 apply_write_reserve(windex, reserve.size());
450 for (span<T> reader = read_reserve(); reader.size() > 0; reader = read_reserve())
452 destroy(reader.begin(), reader.end());
465 ibip_buffer_spsc_atomic(T* p_buffer_, size_type reserved_)
467 , p_buffer(p_buffer_)
474 ibip_buffer_spsc_atomic(
const ibip_buffer_spsc_atomic&) ETL_DELETE;
475 ibip_buffer_spsc_atomic& operator =(
const ibip_buffer_spsc_atomic&) ETL_DELETE;
478 ibip_buffer_spsc_atomic(ibip_buffer_spsc_atomic&&) =
delete;
479 ibip_buffer_spsc_atomic& operator =(ibip_buffer_spsc_atomic&&) =
delete;
492 template <
typename T, const
size_t SIZE, const
size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
493 class bip_buffer_spsc_atomic :
public ibip_buffer_spsc_atomic<T, MEMORY_MODEL>
497 typedef typename etl::ibip_buffer_spsc_atomic<T, MEMORY_MODEL> base_t;
501 typedef typename base_t::size_type size_type;
505 static ETL_CONSTANT size_type RESERVED_SIZE = size_type(SIZE);
511 static ETL_CONSTANT size_type MAX_SIZE = size_type(SIZE);
516 bip_buffer_spsc_atomic()
517 : base_t(reinterpret_cast<T*>(buffer.raw), RESERVED_SIZE)
524 ~bip_buffer_spsc_atomic()
535 template <
typename T, const
size_t SIZE, const
size_t MEMORY_MODEL>
536 ETL_CONSTANT
typename bip_buffer_spsc_atomic<T, SIZE, MEMORY_MODEL>::size_type bip_buffer_spsc_atomic<T, SIZE, MEMORY_MODEL>::RESERVED_SIZE;
Definition: memory.h:2164
Definition: integral_limits.h:468
bitset_ext
Definition: absolute.h:38
size_t max_size() const
Returns the maximum number of items in the variant_pool.
Definition: variant_pool_generator.h:281
etl::optional< T > read(etl::bit_stream_reader &stream)
Read a checked type from a stream.
Definition: bit_stream.h:1348
void destroy(const T *const p)
Destroys the object.
Definition: variant_pool_generator.h:256
bool write(etl::bit_stream_writer &stream, bool value)
Definition: bit_stream.h:992
Definition: memory_model.h:50