38#ifndef ETL_BIP_BUFFER_SPSC_ATOMIC_INCLUDED
39#define ETL_BIP_BUFFER_SPSC_ATOMIC_INCLUDED
62 class bip_buffer_exception :
public exception
66 bip_buffer_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
67 : exception(reason_, file_name_, line_number_)
75 class bip_buffer_reserve_invalid :
public bip_buffer_exception
79 bip_buffer_reserve_invalid(string_type file_name_, numeric_type line_number_)
80 : bip_buffer_exception(ETL_ERROR_TEXT(
"bip_buffer:reserve", ETL_BIP_BUFFER_SPSC_ATOMIC_FILE_ID
"A"), file_name_, line_number_)
88 template <
size_t Memory_Model = etl::memory_model::MEMORY_MODEL_LARGE>
89 class bip_buffer_spsc_atomic_base
94 typedef typename etl::size_type_lookup<Memory_Model>::type size_type;
109 return available() == 0;
116 size_type
size()
const
118 size_type write_index =
write.load(etl::memory_order_acquire);
119 size_type read_index =
read.load(etl::memory_order_acquire);
122 if (write_index >= read_index)
125 return write_index - read_index;
129 size_type last_index = last.load(etl::memory_order_acquire);
132 return (write_index - 0) + (last_index - read_index);
139 size_type available()
const
141 size_type write_index =
write.load(etl::memory_order_acquire);
142 size_type read_index =
read.load(etl::memory_order_acquire);
145 if (write_index >= read_index)
147 size_type forward_size = capacity() - write_index;
150 if (read_index > (forward_size + 1))
152 return read_index - 1;
161 return read_index - write_index - 1;
168 size_type capacity()
const
176 size_type max_size()
const
186 bip_buffer_spsc_atomic_base(size_type reserved_)
190 , Reserved(reserved_)
197 read.store(0, etl::memory_order_release);
198 write.store(0, etl::memory_order_release);
199 last.store(0, etl::memory_order_release);
203 size_type get_write_reserve(size_type* psize, size_type fallback_size = numeric_limits<size_type>::max())
205 size_type write_index =
write.load(etl::memory_order_relaxed);
206 size_type read_index =
read.load(etl::memory_order_acquire);
209 if (write_index >= read_index)
211 size_type forward_size = capacity() - write_index;
214 if (*psize <= forward_size)
220 else if ((read_index <= (forward_size + 1)) || (fallback_size <= forward_size))
222 *psize = forward_size;
231 if (*psize >= read_index)
235 *psize = read_index - 1;
249 if (*psize >= read_index - write_index)
251 *psize = read_index - write_index - 1;
259 void apply_write_reserve(size_type windex, size_type wsize)
263 size_type write_index =
write.load(etl::memory_order_relaxed);
264 size_type read_index =
read.load(etl::memory_order_acquire);
267 if (write_index < read_index)
269 ETL_ASSERT_OR_RETURN((windex == write_index) && ((wsize + 1) <= read_index), ETL_ERROR(bip_buffer_reserve_invalid));
272 else if (windex == write_index)
274 ETL_ASSERT_OR_RETURN(wsize <= (capacity() - write_index), ETL_ERROR(bip_buffer_reserve_invalid));
277 last.store(windex + wsize, etl::memory_order_release);
282 ETL_ASSERT_OR_RETURN((windex == 0) && ((wsize + 1) <= read_index), ETL_ERROR(bip_buffer_reserve_invalid));
285 last.store(write_index, etl::memory_order_release);
289 write.store(windex + wsize, etl::memory_order_release);
294 size_type get_read_reserve(size_type* psize)
296 size_type read_index =
read.load(etl::memory_order_relaxed);
297 size_type write_index =
write.load(etl::memory_order_acquire);
299 if (read_index > write_index)
302 size_type last_index = last.load(etl::memory_order_relaxed);
304 if (read_index == last_index)
312 write_index = last_index;
321 if ((write_index - read_index) < *psize)
323 *psize = write_index - read_index;
330 void apply_read_reserve(size_type rindex, size_type rsize)
334 size_type rsize_checker = rsize;
335 ETL_ASSERT_OR_RETURN((rindex == get_read_reserve(&rsize_checker)) && (rsize == rsize_checker), ETL_ERROR(bip_buffer_reserve_invalid));
337 read.store(rindex + rsize, etl::memory_order_release);
343 etl::atomic<size_type>
read;
344 etl::atomic<size_type>
write;
345 etl::atomic<size_type> last;
346 const size_type Reserved;
348 #if defined(ETL_POLYMORPHIC_SPSC_BIP_BUFFER_ATOMIC) || defined(ETL_POLYMORPHIC_CONTAINERS)
352 virtual ~bip_buffer_spsc_atomic_base() {}
357 ~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;
370 using base_t::apply_read_reserve;
371 using base_t::apply_write_reserve;
372 using base_t::get_read_reserve;
373 using base_t::get_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 =
static_cast<size_type
>(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 =
static_cast<size_type
>(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;
493 template <
typename T, const
size_t Size, const
size_t Memory_Model = etl::memory_model::MEMORY_MODEL_LARGE>
494 class bip_buffer_spsc_atomic :
public ibip_buffer_spsc_atomic<T, Memory_Model>
498 typedef typename etl::ibip_buffer_spsc_atomic<T, Memory_Model> base_t;
502 typedef typename base_t::size_type size_type;
506 static ETL_CONSTANT size_type Reserved_Size = size_type(Size);
510 ETL_STATIC_ASSERT((Size <= (etl::integral_limits<size_type>::max)),
"Size too large for memory model");
512 static ETL_CONSTANT size_type MAX_SIZE = size_type(Size);
517 bip_buffer_spsc_atomic()
518 : base_t(reinterpret_cast<T*>(buffer.raw), Reserved_Size)
525 ~bip_buffer_spsc_atomic()
533 etl::uninitialized_buffer_of<T, Reserved_Size> buffer;
536 template <
typename T, const
size_t Size, const
size_t Memory_Model>
537 ETL_CONSTANT
typename bip_buffer_spsc_atomic<T, Size, Memory_Model>::size_type bip_buffer_spsc_atomic<T, Size, Memory_Model>::Reserved_Size;
Definition exception.h:59
etl::optional< T > read(etl::bit_stream_reader &stream)
Read a checked type from a stream.
Definition bit_stream.h:1430
ETL_CONSTEXPR TContainer::size_type size(const TContainer &container)
Definition iterator.h:1434
bool write(etl::bit_stream_writer &stream, bool value)
Definition bit_stream.h:1035