mirror of
https://github.com/bkaradzic/bx.git
synced 2026-02-17 20:52:37 +01:00
Added RingBufferControl get empty, used, reserved counts. (#348)
This commit is contained in:
committed by
GitHub
parent
00b6d1517d
commit
4aaf864875
@@ -10,7 +10,7 @@
|
|||||||
namespace bx
|
namespace bx
|
||||||
{
|
{
|
||||||
inline RingBufferControl::RingBufferControl(uint32_t _size)
|
inline RingBufferControl::RingBufferControl(uint32_t _size)
|
||||||
: m_size(_size)
|
: m_size(max(_size, 2) )
|
||||||
, m_current(0)
|
, m_current(0)
|
||||||
, m_write(0)
|
, m_write(0)
|
||||||
, m_read(0)
|
, m_read(0)
|
||||||
@@ -26,6 +26,45 @@ namespace bx
|
|||||||
return distance(m_read, m_current);
|
return distance(m_read, m_current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool RingBufferControl::isEmpty() const
|
||||||
|
{
|
||||||
|
return m_read == m_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t RingBufferControl::getSize() const
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t RingBufferControl::getNumEmpty() const
|
||||||
|
{
|
||||||
|
return m_size - distance(m_read, m_write) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t RingBufferControl::getNumUsed() const
|
||||||
|
{
|
||||||
|
return distance(m_read, m_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t RingBufferControl::getNumReserved() const
|
||||||
|
{
|
||||||
|
return distance(m_current, m_write);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void RingBufferControl::resize(int32_t _size)
|
||||||
|
{
|
||||||
|
_size = 0 > _size
|
||||||
|
// can shrink only by number of empty slots.
|
||||||
|
? bx::max(_size, -int32_t(getNumEmpty() ) )
|
||||||
|
: _size
|
||||||
|
;
|
||||||
|
|
||||||
|
m_size += _size;
|
||||||
|
|
||||||
|
m_current += m_current >= m_write ? _size : 0;
|
||||||
|
m_read += m_read >= m_write ? _size : 0;
|
||||||
|
}
|
||||||
|
|
||||||
inline uint32_t RingBufferControl::consume(uint32_t _size)
|
inline uint32_t RingBufferControl::consume(uint32_t _size)
|
||||||
{
|
{
|
||||||
const uint32_t maxSize = distance(m_read, m_current);
|
const uint32_t maxSize = distance(m_read, m_current);
|
||||||
|
|||||||
@@ -12,6 +12,13 @@
|
|||||||
|
|
||||||
namespace bx
|
namespace bx
|
||||||
{
|
{
|
||||||
|
/// Ring buffer control structure. Tracking "read", "write", and "current" head.
|
||||||
|
///
|
||||||
|
/// This is not container, and data control represents is user defined. Read/write/current are
|
||||||
|
/// just indices.
|
||||||
|
///
|
||||||
|
/// @notice One slot is always reseved. When creating ring buffer of N slots, N-1 slots can be
|
||||||
|
/// used.
|
||||||
///
|
///
|
||||||
class RingBufferControl
|
class RingBufferControl
|
||||||
{
|
{
|
||||||
@@ -21,34 +28,98 @@ namespace bx
|
|||||||
);
|
);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/// Constructor.
|
||||||
|
///
|
||||||
|
/// @param[in] _size Maximum number of slots.
|
||||||
///
|
///
|
||||||
RingBufferControl(uint32_t _size);
|
RingBufferControl(uint32_t _size);
|
||||||
|
|
||||||
///
|
/// Destructor.
|
||||||
~RingBufferControl();
|
~RingBufferControl();
|
||||||
|
|
||||||
|
/// Returns number of used slots.
|
||||||
|
///
|
||||||
|
/// @returns Number of used slots.
|
||||||
///
|
///
|
||||||
uint32_t available() const;
|
uint32_t available() const;
|
||||||
|
|
||||||
|
/// Returns 'true' if ring buffer is empty.
|
||||||
|
///
|
||||||
|
/// @returns Returns 'true' if ring buffer is empty.
|
||||||
|
///
|
||||||
|
bool isEmpty() const;
|
||||||
|
|
||||||
|
/// Returns total size of ring buffer.
|
||||||
|
///
|
||||||
|
/// @returns Total size of ring buffer.
|
||||||
|
///
|
||||||
|
uint32_t getSize() const;
|
||||||
|
|
||||||
|
/// Returns number of empty slots.
|
||||||
|
///
|
||||||
|
/// @returns Number of empty slots.
|
||||||
|
///
|
||||||
|
uint32_t getNumEmpty() const;
|
||||||
|
|
||||||
|
/// Returns number of used slots.
|
||||||
|
///
|
||||||
|
/// @returns Number of used slots.
|
||||||
|
///
|
||||||
|
uint32_t getNumUsed() const;
|
||||||
|
|
||||||
|
/// Returns number of reserved slots.
|
||||||
|
///
|
||||||
|
/// @returns Number of reserved slots.
|
||||||
|
///
|
||||||
|
uint32_t getNumReserved() const;
|
||||||
|
|
||||||
|
/// Resize ring buffer. Resize happens at write head, read and current head will be moved
|
||||||
|
/// forward or backward if write head is behind them.
|
||||||
|
///
|
||||||
|
/// @param[in] _size Amount to resize. Value can be positive when growing size or negative
|
||||||
|
/// when shrinking size of buffer.
|
||||||
|
///
|
||||||
|
void resize(int32_t _size);
|
||||||
|
|
||||||
|
/// Consume slots, makes slots free to be reserved. Moves "read" head forward.
|
||||||
|
///
|
||||||
|
/// @returns Number of reserved slots reserved.
|
||||||
///
|
///
|
||||||
uint32_t consume(uint32_t _size); // consumer only
|
uint32_t consume(uint32_t _size); // consumer only
|
||||||
|
|
||||||
|
/// Reserve slots, makes slots non-free, but ready to be used yet. Moves "write" head forward.
|
||||||
|
///
|
||||||
|
/// @param[in] _size Number of slots.
|
||||||
|
/// @param[in] _mustSucceed If argument is true it will not reseve any slots unless `_size`
|
||||||
|
/// of slots is reseved.
|
||||||
|
///
|
||||||
|
/// @returns Number of reserved slots reserved.
|
||||||
///
|
///
|
||||||
uint32_t reserve(uint32_t _size, bool _mustSucceed = false); // producer only
|
uint32_t reserve(uint32_t _size, bool _mustSucceed = false); // producer only
|
||||||
|
|
||||||
|
/// Commit slots, makes slots used, and ready to be consumed. Moves "current" head forward.
|
||||||
|
///
|
||||||
|
/// @param[in] _size Number of commited slots.
|
||||||
///
|
///
|
||||||
uint32_t commit(uint32_t _size); // producer only
|
uint32_t commit(uint32_t _size); // producer only
|
||||||
|
|
||||||
|
/// Calculate distance between two slots. Function takes wrapping into account.
|
||||||
|
///
|
||||||
|
/// @param[in] _from From.
|
||||||
|
/// @param[in] _to To.
|
||||||
|
///
|
||||||
|
/// @returns Distance between slots.
|
||||||
///
|
///
|
||||||
uint32_t distance(uint32_t _from, uint32_t _to) const; // both
|
uint32_t distance(uint32_t _from, uint32_t _to) const; // both
|
||||||
|
|
||||||
|
/// Invalidate ring buffer.
|
||||||
///
|
///
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
const uint32_t m_size;
|
uint32_t m_size; //!< Size of ring buffer.
|
||||||
uint32_t m_current;
|
uint32_t m_current; //!< Currently operated area start.
|
||||||
uint32_t m_write;
|
uint32_t m_write; //!< Write head.
|
||||||
uint32_t m_read;
|
uint32_t m_read; //!< Read head.
|
||||||
};
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -8,13 +8,118 @@
|
|||||||
|
|
||||||
TEST_CASE("RingBufferControl", "")
|
TEST_CASE("RingBufferControl", "")
|
||||||
{
|
{
|
||||||
bx::RingBufferControl control(16);
|
constexpr uint32_t kMax = 16;
|
||||||
|
|
||||||
|
bx::RingBufferControl control(kMax);
|
||||||
|
|
||||||
|
REQUIRE(kMax == control.getSize() );
|
||||||
|
REQUIRE(0 == control.getNumUsed() );
|
||||||
|
REQUIRE(0 == control.getNumReserved() );
|
||||||
|
REQUIRE(kMax-1 == control.getNumEmpty() );
|
||||||
|
REQUIRE(control.isEmpty() );
|
||||||
|
|
||||||
|
REQUIRE(1 == control.reserve(1) );
|
||||||
|
|
||||||
|
REQUIRE(kMax == control.getSize() );
|
||||||
|
REQUIRE(0 == control.getNumUsed() );
|
||||||
|
REQUIRE(1 == control.getNumReserved() );
|
||||||
|
REQUIRE(kMax-2 == control.getNumEmpty() );
|
||||||
|
REQUIRE(!control.isEmpty() );
|
||||||
|
|
||||||
|
REQUIRE(0 == control.reserve(16, true) );
|
||||||
|
REQUIRE(kMax-2 == control.reserve(16) );
|
||||||
|
|
||||||
|
REQUIRE(kMax == control.getSize() );
|
||||||
|
REQUIRE(0 == control.getNumUsed() );
|
||||||
|
REQUIRE(kMax-1 == control.getNumReserved() );
|
||||||
|
REQUIRE(0 == control.getNumEmpty() );
|
||||||
|
REQUIRE(!control.isEmpty() );
|
||||||
|
|
||||||
REQUIRE(1 == control.reserve(1) );
|
|
||||||
REQUIRE(0 == control.reserve(16, true) );
|
|
||||||
REQUIRE(14 == control.reserve(16) );
|
|
||||||
REQUIRE(15 == control.commit(15) );
|
REQUIRE(15 == control.commit(15) );
|
||||||
REQUIRE(15 == control.available() );
|
|
||||||
|
REQUIRE(kMax == control.getSize() );
|
||||||
|
REQUIRE(kMax-1 == control.getNumUsed() );
|
||||||
|
REQUIRE(0 == control.getNumReserved() );
|
||||||
|
REQUIRE(0 == control.getNumEmpty() );
|
||||||
|
REQUIRE(!control.isEmpty() );
|
||||||
|
|
||||||
REQUIRE(15 == control.consume(15) );
|
REQUIRE(15 == control.consume(15) );
|
||||||
REQUIRE(0 == control.available() );
|
|
||||||
|
REQUIRE(kMax == control.getSize() );
|
||||||
|
REQUIRE(0 == control.getNumUsed() );
|
||||||
|
REQUIRE(0 == control.getNumReserved() );
|
||||||
|
REQUIRE(kMax-1 == control.getNumEmpty() );
|
||||||
|
REQUIRE(control.isEmpty() );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("RingBufferControl resize", "")
|
||||||
|
{
|
||||||
|
bx::RingBufferControl control(10);
|
||||||
|
|
||||||
|
uint32_t reserved;
|
||||||
|
uint32_t commited;
|
||||||
|
uint32_t consumed;
|
||||||
|
|
||||||
|
reserved = control.reserve(8);
|
||||||
|
REQUIRE(reserved == 8);
|
||||||
|
REQUIRE(control.m_current == 0);
|
||||||
|
REQUIRE(control.m_write == 8);
|
||||||
|
REQUIRE(control.m_read == 0);
|
||||||
|
|
||||||
|
commited = control.commit(4);
|
||||||
|
REQUIRE(commited == 4);
|
||||||
|
REQUIRE(control.m_current == 4);
|
||||||
|
REQUIRE(control.m_write == 8);
|
||||||
|
REQUIRE(control.m_read == 0);
|
||||||
|
|
||||||
|
consumed = control.consume(2);
|
||||||
|
REQUIRE(consumed == 2);
|
||||||
|
REQUIRE(control.m_current == 4);
|
||||||
|
REQUIRE(control.m_write == 8);
|
||||||
|
REQUIRE(control.m_read == 2);
|
||||||
|
|
||||||
|
REQUIRE(10 == control.getSize() );
|
||||||
|
|
||||||
|
control.resize(10);
|
||||||
|
REQUIRE(20 == control.getSize() );
|
||||||
|
|
||||||
|
control.reserve(8);
|
||||||
|
REQUIRE(control.m_current == 4);
|
||||||
|
REQUIRE(control.m_write == 16);
|
||||||
|
REQUIRE(control.m_read == 2);
|
||||||
|
|
||||||
|
control.commit(4);
|
||||||
|
REQUIRE(control.m_current == 8);
|
||||||
|
REQUIRE(control.m_write == 16);
|
||||||
|
REQUIRE(control.m_read == 2);
|
||||||
|
|
||||||
|
control.consume(2);
|
||||||
|
REQUIRE(control.m_current == 8);
|
||||||
|
REQUIRE(control.m_write == 16);
|
||||||
|
REQUIRE(control.m_read == 4);
|
||||||
|
|
||||||
|
reserved = control.reserve(4);
|
||||||
|
REQUIRE(reserved == 4);
|
||||||
|
commited = control.commit(4);
|
||||||
|
REQUIRE(commited == 4);
|
||||||
|
consumed = control.consume(6);
|
||||||
|
REQUIRE(consumed == 6);
|
||||||
|
|
||||||
|
REQUIRE(control.m_current == 12);
|
||||||
|
REQUIRE(control.m_write == 0);
|
||||||
|
REQUIRE(control.m_read == 10);
|
||||||
|
|
||||||
|
REQUIRE(2 == control.getNumUsed() );
|
||||||
|
REQUIRE(8 == control.getNumReserved() );
|
||||||
|
REQUIRE(9 == control.getNumEmpty() );
|
||||||
|
|
||||||
|
control.resize(-10);
|
||||||
|
REQUIRE(11 == control.getSize() );
|
||||||
|
REQUIRE(2 == control.getNumUsed() );
|
||||||
|
REQUIRE(8 == control.getNumReserved() );
|
||||||
|
REQUIRE(0 == control.getNumEmpty() );
|
||||||
|
|
||||||
|
REQUIRE(control.m_current == 3);
|
||||||
|
REQUIRE(control.m_write == 0);
|
||||||
|
REQUIRE(control.m_read == 1);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user