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
95 typedef typename etl::size_type_lookup<Memory_Model>::type size_type;
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
177 size_type max_size()
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 (*psize >= read_index - write_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));
286 last.store(write_index, etl::memory_order_release);
290 write.store(windex + wsize, etl::memory_order_release);
295 size_type get_read_reserve(size_type* psize)
297 size_type read_index =
read.load(etl::memory_order_relaxed);
298 size_type write_index =
write.load(etl::memory_order_acquire);
300 if (read_index > write_index)
303 size_type last_index = last.load(etl::memory_order_relaxed);
305 if (read_index == last_index)
313 write_index = last_index;
322 if ((write_index - read_index) < *psize)
324 *psize = write_index - read_index;
331 void apply_read_reserve(size_type rindex, size_type rsize)
335 size_type rsize_checker = rsize;
336 ETL_ASSERT_OR_RETURN((rindex == get_read_reserve(&rsize_checker)) && (rsize == rsize_checker), ETL_ERROR(bip_buffer_reserve_invalid));
338 read.store(rindex + rsize, etl::memory_order_release);
344 etl::atomic<size_type>
read;
345 etl::atomic<size_type>
write;
346 etl::atomic<size_type> last;
347 const size_type Reserved;
349 #if defined(ETL_POLYMORPHIC_SPSC_BIP_BUFFER_ATOMIC) || defined(ETL_POLYMORPHIC_CONTAINERS)
353 virtual ~bip_buffer_spsc_atomic_base() {}
358 ~bip_buffer_spsc_atomic_base() {}
365 template <
typename T, const
size_t Memory_Model = etl::memory_model::MEMORY_MODEL_LARGE>
366 class ibip_buffer_spsc_atomic :
public bip_buffer_spsc_atomic_base<Memory_Model>
370 typedef typename etl::bip_buffer_spsc_atomic_base<Memory_Model> base_t;
371 using base_t::apply_read_reserve;
372 using base_t::apply_write_reserve;
373 using base_t::get_read_reserve;
374 using base_t::get_write_reserve;
379 typedef T value_type;
380 typedef T& reference;
381 typedef const T& const_reference;
383 typedef T&& rvalue_reference;
385 typedef typename base_t::size_type size_type;
387 using base_t::max_size;
392 span<T> read_reserve(size_type max_reserve_size = numeric_limits<size_type>::max())
394 size_type reserve_size = max_reserve_size;
395 size_type rindex = get_read_reserve(&reserve_size);
397 return span<T>(p_buffer + rindex, reserve_size);
405 void read_commit(
const span<T>& reserve)
407 size_type rindex = etl::distance(p_buffer, reserve.data());
408 apply_read_reserve(rindex, reserve.size());
414 span<T> write_reserve(size_type max_reserve_size)
416 size_type reserve_size = max_reserve_size;
417 size_type windex = get_write_reserve(&reserve_size);
419 return span<T>(p_buffer + windex, reserve_size);
426 span<T> write_reserve_optimal(size_type min_reserve_size = 1U)
428 size_type reserve_size = numeric_limits<size_type>::max();
429 size_type windex = get_write_reserve(&reserve_size, min_reserve_size);
431 return span<T>(p_buffer + windex, reserve_size);
439 void write_commit(
const span<T>& reserve)
441 size_type windex = etl::distance(p_buffer, reserve.data());
442 apply_write_reserve(windex, reserve.size());
451 for (span<T> reader = read_reserve(); reader.size() > 0; reader = read_reserve())
453 destroy(reader.begin(), reader.end());
466 ibip_buffer_spsc_atomic(T* p_buffer_, size_type reserved_)
468 , p_buffer(p_buffer_)
475 ibip_buffer_spsc_atomic(
const ibip_buffer_spsc_atomic&) ETL_DELETE;
476 ibip_buffer_spsc_atomic& operator=(
const ibip_buffer_spsc_atomic&) ETL_DELETE;
479 ibip_buffer_spsc_atomic(ibip_buffer_spsc_atomic&&) =
delete;
480 ibip_buffer_spsc_atomic& operator=(ibip_buffer_spsc_atomic&&) =
delete;
494 template <
typename T, const
size_t Size, const
size_t Memory_Model = etl::memory_model::MEMORY_MODEL_LARGE>
495 class bip_buffer_spsc_atomic :
public ibip_buffer_spsc_atomic<T, Memory_Model>
499 typedef typename etl::ibip_buffer_spsc_atomic<T, Memory_Model> base_t;
503 typedef typename base_t::size_type size_type;
507 static ETL_CONSTANT size_type Reserved_Size = size_type(Size);
511 ETL_STATIC_ASSERT((Size <= (etl::integral_limits<size_type>::max)),
"Size too large for memory model");
513 static ETL_CONSTANT size_type MAX_SIZE = size_type(Size);
518 bip_buffer_spsc_atomic()
519 : base_t(reinterpret_cast<T*>(buffer.raw), Reserved_Size)
526 ~bip_buffer_spsc_atomic()
534 etl::uninitialized_buffer_of<T, Reserved_Size> buffer;
537 template <
typename T, const
size_t Size, const
size_t Memory_Model>
538 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
bitset_ext
Definition absolute.h:40
etl::optional< T > read(etl::bit_stream_reader &stream)
Read a checked type from a stream.
Definition bit_stream.h:1377
ETL_CONSTEXPR TContainer::size_type size(const TContainer &container)
Definition iterator.h:1192
bool write(etl::bit_stream_writer &stream, bool value)
Definition bit_stream.h:995