51 template <
typename Tp>
74 void init(
size_t size);
80 template <
typename Tp>
81 std::pair<size_t, Tp*>
write(Tp* in,
85 template <
typename Tp>
86 std::pair<size_t, Tp*>
write(Tp* in,
92 template <
typename Tp>
99 template <
typename Tp>
100 std::pair<size_t, Tp*>
read(
104 template <
typename Tp>
105 std::pair<size_t, Tp*>
read(
109 template <
typename Tp>
116 size_t count()
const {
return (m_write_count - m_read_count); }
128 size_t rewind(
size_t n)
const;
145 void* write_ptr()
const
147 return static_cast<char*
>(m_ptr) + (m_write_count % m_size);
151 void* read_ptr()
const {
return static_cast<char*
>(m_ptr) + (m_read_count % m_size); }
155 bool m_use_mmap =
true;
156 bool m_use_mmap_explicit =
false;
158 void* m_ptr =
nullptr;
160 mutable size_t m_read_count = 0;
161 size_t m_write_count = 0;
164template <
typename Tp>
165std::pair<size_t, Tp*>
168 if(in ==
nullptr || m_ptr ==
nullptr)
169 return { 0,
nullptr };
171 auto _length =
sizeof(Tp);
176 throw std::runtime_error(
"heap-buffer-overflow :: ring buffer is full. read data "
177 "to avoid data corruption");
180 auto _modulo = m_size - (m_write_count % m_size);
181 if(_modulo < _length)
182 m_write_count += _modulo;
185 Tp* out =
reinterpret_cast<Tp*
>(write_ptr());
188 new((
void*) out) Tp{ std::move(*in) };
191 m_write_count += _length;
193 return { _length, out };
196template <
typename Tp>
197std::pair<size_t, Tp*>
200 if(in ==
nullptr || m_ptr ==
nullptr)
201 return { 0,
nullptr };
203 auto _length =
sizeof(Tp);
208 throw std::runtime_error(
"heap-buffer-overflow :: ring buffer is full. read data "
209 "to avoid data corruption");
212 auto _modulo = m_size - (m_write_count % m_size);
213 if(_modulo < _length)
214 m_write_count += _modulo;
217 Tp* out =
reinterpret_cast<Tp*
>(write_ptr());
220 memcpy((
void*) out, in, _length);
223 m_write_count += _length;
225 return { _length, out };
228template <
typename Tp>
235 auto _length =
sizeof(Tp);
240 throw std::runtime_error(
"heap-buffer-overflow :: ring buffer is full. read data "
241 "to avoid data corruption");
244 auto _modulo = m_size - (m_write_count % m_size);
245 if(_modulo < _length)
246 m_write_count += _modulo;
249 Tp* _out =
reinterpret_cast<Tp*
>(write_ptr());
252 m_write_count += _length;
257template <
typename Tp>
258std::pair<size_t, Tp*>
262 return { 0,
nullptr };
264 auto _length =
sizeof(Tp);
267 if(_length >
count())
268 throw std::runtime_error(
"ring buffer is empty");
271 auto _modulo = m_size - (m_read_count % m_size);
272 if(_modulo < _length)
273 m_read_count += _modulo;
276 Tp* in =
reinterpret_cast<Tp*
>(read_ptr());
282 m_read_count += _length;
284 return { _length, in };
287template <
typename Tp>
288std::pair<size_t, Tp*>
292 return { 0,
nullptr };
294 auto _length =
sizeof(Tp);
296 using Up =
typename std::remove_const<Tp>::type;
299 if(_length >
count())
300 throw std::runtime_error(
"ring buffer is empty");
303 auto _modulo = m_size - (m_read_count % m_size);
304 if(_modulo < _length)
305 m_read_count += _modulo;
308 Tp* in =
reinterpret_cast<Tp*
>(read_ptr());
311 Up* _out =
const_cast<Up*
>(out);
312 memcpy(_out, in, _length);
315 m_read_count += _length;
317 return { _length, in };
320template <
typename Tp>
327 auto _length =
sizeof(Tp);
331 if(_length >
count())
332 throw std::runtime_error(
"ring buffer is empty");
335 auto _modulo = m_size - (m_read_count % m_size);
336 if(_modulo < _length)
337 m_read_count += _modulo;
340 Tp* _out =
reinterpret_cast<Tp*
>(read_ptr());
343 m_read_count += _length;
350namespace data_storage
359template <
typename Tp>
376 :
base_type{ _size * sizeof(Tp), _use_mmap }
401 Tp*
write(Tp* in) {
return add_copy(base_type::write<Tp>(in).second); }
404 Tp*
read(Tp* out)
const {
return remove_copy(base_type::read<Tp>(out).second); }
407 Tp*
request() {
return add_copy(base_type::request<Tp>()); }
410 Tp*
retrieve() {
return remove_copy(base_type::retrieve<Tp>()); }
427 template <
typename... Args>
430 Tp _obj{ std::forward<Args>(args)... };
439 std::ostringstream ss{};
441 ss << std::boolalpha << std::right <<
"data size: " << std::setw(_w)
443 <<
", is_empty: " << std::setw(5) <<
is_empty()
444 <<
", is_full: " << std::setw(5) <<
is_full()
445 <<
", capacity: " << std::setw(_w) <<
capacity()
446 <<
", count: " << std::setw(_w) <<
count() <<
", free: " << std::setw(_w)
450 <<
" B, pointer: " << std::setw(15) << base_type::m_ptr
451 <<
", raw read count: " << std::setw(_w) << base_type::m_read_count
452 <<
", raw write count: " << std::setw(_w) << base_type::m_write_count;
462 using copy_function_t = std::function<void(
ring_buffer&, Tp*)>;
463 using copy_entry_t = std::pair<Tp*, copy_function_t>;
465 Tp* add_copy(Tp*)
const;
466 Tp* remove_copy(Tp*)
const;
467 mutable std::vector<copy_entry_t> m_copy = {};
470template <
typename Tp>
474 for(
const auto& itr : rhs.m_copy)
475 itr.second(*
this, itr.first);
478template <
typename Tp>
485 base_type::operator=(rhs);
486 for(
const auto& itr : rhs.m_copy)
487 itr.second(*
this, itr.first);
492template <
typename Tp>
497 auto itr = m_copy.begin();
498 for(; itr != m_copy.end(); ++itr)
502 itr->second = std::move(_copy_func);
506 if(itr == m_copy.end())
507 m_copy.emplace_back(_v, std::move(_copy_func));
511template <
typename Tp>
513ring_buffer<Tp>::remove_copy(Tp* _v)
const
516 std::remove_if(m_copy.begin(), m_copy.end(),
517 [_v](
const copy_entry_t& _entry) { return _entry.first == _v; }),
526#if !defined(TIMEMORY_COMMON_SOURCE) && !defined(TIMEMORY_USE_COMMON_EXTERN)
527# if !defined(TIMEMORY_RING_BUFFER_INLINE)
528# define TIMEMORY_RING_BUFFER_INLINE inline
532# if !defined(TIMEMORY_RING_BUFFER_INLINE)
533# define TIMEMORY_RING_BUFFER_INLINE
typename std::enable_if< B, T >::type enable_if_t
tim::mpl::apply< std::string > string
const std::string std::ostream * os
Ring buffer implementation, with support for mmap as backend (Linux only).
bool is_full() const
Returns if the buffer is full.
std::string as_string() const
bool get_use_mmap() const
query whether using mmap
friend std::ostream & operator<<(std::ostream &os, const ring_buffer &obj)
void destroy()
Destroy ring buffer.
void init(size_t size)
Creates new ring buffer.
std::pair< size_t, Tp * > read(Tp *out, std::enable_if_t< std::is_class< Tp >::value, int >=0) const
Read class-type data from buffer (uses placement new).
Tp * retrieve()
Retrieve a pointer to the head allocation (read).
void set_use_mmap(bool)
explicitly configure to use mmap if avail
bool is_empty() const
Returns if the buffer is empty.
ring_buffer(ring_buffer &&) noexcept=delete
Tp * request()
Request a pointer to an allocation. This is similar to a "write" except the memory is uninitialized....
ring_buffer(bool _use_mmap)
size_t free() const
Returns how many bytes are availiable in the buffer.
std::pair< size_t, Tp * > write(Tp *in, std::enable_if_t< std::is_class< Tp >::value, int >=0)
Write class-type data to buffer (uses placement new).
bool is_initialized() const
Returns whether the buffer has been allocated.
size_t capacity() const
Get the total number of bytes supported.
ring_buffer(size_t _size)
size_t rewind(size_t n) const
Rewind the read position n bytes.
size_t count() const
Returns number of bytes currently held by the buffer.
Ring buffer wrapper around tim::base::ring_buffer for data of type Tp. If the data object size is lar...
size_t capacity() const
Get the total number of Tp instances supported.
size_t count() const
Returns number of Tp instances currently held by the buffer.
bool is_initialized() const
Returns whether the buffer has been allocated.
friend std::ostream & operator<<(std::ostream &os, const ring_buffer &obj)
ring_buffer(bool _use_mmap)
bool is_full() const
Returns if the buffer is full.
auto emplace(Args &&... args)
ring_buffer(ring_buffer &&) noexcept=default
size_t free() const
Returns how many Tp instances are availiable in the buffer.
ring_buffer & operator=(const ring_buffer &)
void init(size_t _size)
Creates new ring buffer.
size_t data_size() const
Write data to buffer.
ring_buffer(size_t _size)
bool is_empty() const
Returns if the buffer is empty.
ring_buffer(size_t _size, bool _use_mmap)
Tp * request()
Get an uninitialized address at tail of buffer.
size_t rewind(size_t n) const
Rewinds the read pointer.
std::string as_string() const
Tp * write(Tp *in)
Write data to buffer. Return pointer to location of write.
Tp * read(Tp *out) const
Read data from buffer. Return pointer to location of read.
void destroy()
Destroy ring buffer.
Tp * retrieve()
Read data from head of buffer.