Stimulus[Buffer|Frame]: initial impl, unoptimized for mem use
This commit is contained in:
@@ -2,13 +2,15 @@
|
||||
#define _SP_MC_RING_BUFFER_H
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <new>
|
||||
#include <user/stimulusFrame.h>
|
||||
#include <user/sequenceLock.h>
|
||||
|
||||
namespace smo {
|
||||
namespace stim_buff {
|
||||
|
||||
/**
|
||||
* @brief Single-producer, multi-consumer ring buffer w/per-slot sequence locks
|
||||
@@ -20,120 +22,83 @@ namespace smo {
|
||||
*/
|
||||
class SpMcRingBuffer
|
||||
{
|
||||
public:
|
||||
class InputEngineConstraints
|
||||
{
|
||||
public:
|
||||
InputEngineConstraints(
|
||||
size_t slotStartAlignmentNBytes_,
|
||||
size_t slotPadToNBytes_)
|
||||
: slotStartAlignmentNBytes(slotStartAlignmentNBytes_),
|
||||
slotPadToNBytes(slotPadToNBytes_)
|
||||
{}
|
||||
|
||||
~InputEngineConstraints() = default;
|
||||
|
||||
// Input-engine layout/constraints
|
||||
size_t slotStartAlignmentNBytes; // power-of-2 alignment (e.g., 4096)
|
||||
size_t slotPadToNBytes; // minimum size per slot
|
||||
};
|
||||
|
||||
public:
|
||||
/** EXPLANATION:
|
||||
* Constructor initializes the ring buffer with the given constraints and
|
||||
* number of slots. Calculates stride and allocates data buffer and sequence
|
||||
* locks array.
|
||||
* number of buffers. Allocates slots vector with properly constructed
|
||||
* StimulusFrame instances.
|
||||
*/
|
||||
explicit SpMcRingBuffer(
|
||||
size_t nSlots_,
|
||||
const InputEngineConstraints& constraints_)
|
||||
: nSlots(nSlots_), strideNBytes(0), bufferNBytes(0),
|
||||
constraints(constraints_)
|
||||
size_t nBuffers_,
|
||||
const StagingBuffer::IOEngineConstraints& inputEngineConstraints,
|
||||
const StagingBuffer::IOEngineConstraints& outputEngineConstraints,
|
||||
size_t nSlotsPerStimFrame)
|
||||
: nBuffers(nBuffers_),
|
||||
// Default-construct all frames
|
||||
slots(nBuffers)
|
||||
{
|
||||
if (nSlots == 0)
|
||||
if (nBuffers == 0)
|
||||
{
|
||||
throw std::invalid_argument(std::string(__func__)
|
||||
+ ": SpMcRingBuffer: nSlots must be > 0");
|
||||
+ ": SpMcRingBuffer: nBuffers must be > 0");
|
||||
}
|
||||
|
||||
computeStrideAndBufferSize();
|
||||
// Allocate data buffer: bufferNBytes (aligned up to alignment)
|
||||
data.resize(bufferNBytes);
|
||||
// Initialize sequence locks array: one lock per slot
|
||||
// Use unique_ptr array since SequenceLock is not copyable or movable
|
||||
sequenceLocks = std::make_unique<SequenceLock[]>(nSlots);
|
||||
// Re-invoke constructors w/placement new on default-constructed frames
|
||||
for (size_t i = 0; i < nBuffers; ++i)
|
||||
{
|
||||
slots[i].~StimulusFrame(); // Destroy default-constructed object
|
||||
new (&slots[i]) StimulusFrame(
|
||||
inputEngineConstraints, outputEngineConstraints,
|
||||
nSlotsPerStimFrame);
|
||||
}
|
||||
}
|
||||
|
||||
~SpMcRingBuffer() = default;
|
||||
|
||||
// Non-copyable, movable
|
||||
// Non-copyable, non-movable (slots are non-movable)
|
||||
SpMcRingBuffer(const SpMcRingBuffer&) = delete;
|
||||
SpMcRingBuffer& operator=(const SpMcRingBuffer&) = delete;
|
||||
SpMcRingBuffer(SpMcRingBuffer&&) = default;
|
||||
SpMcRingBuffer& operator=(SpMcRingBuffer&&) = default;
|
||||
SpMcRingBuffer(SpMcRingBuffer&&) = delete;
|
||||
SpMcRingBuffer& operator=(SpMcRingBuffer&&) = delete;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Get a reference to data at the specified slot
|
||||
* @brief Get a reference to the StimulusFrame at the specified slot
|
||||
*
|
||||
* @tparam T The type of data stored in the slot
|
||||
* @param slotIndex The index of the slot (0-based)
|
||||
* @return Reference to T at the slot
|
||||
* @throws std::out_of_range if slotIndex >= nSlots
|
||||
* @return Reference to StimulusFrame at the slot
|
||||
* @throws std::out_of_range if slotIndex >= nBuffers
|
||||
*/
|
||||
template<typename T>
|
||||
T& getDataAtSlot(size_t slotIndex)
|
||||
StimulusFrame& getDataAtSlot(size_t slotIndex)
|
||||
{
|
||||
if (slotIndex >= nSlots)
|
||||
if (slotIndex >= nBuffers)
|
||||
{
|
||||
throw std::out_of_range(std::string(__func__)
|
||||
+ ": SpMcRingBuffer: slotIndex must be < nSlots");
|
||||
+ ": SpMcRingBuffer: slotIndex must be < nBuffers");
|
||||
}
|
||||
|
||||
size_t offset = slotIndex * strideNBytes;
|
||||
return *reinterpret_cast<T*>(data.data() + offset);
|
||||
return slots[slotIndex];
|
||||
}
|
||||
|
||||
SequenceLock& getSequenceLockAtSlot(size_t slotIndex)
|
||||
{
|
||||
if (slotIndex >= nSlots)
|
||||
if (slotIndex >= nBuffers)
|
||||
{
|
||||
throw std::out_of_range(std::string(__func__)
|
||||
+ ": SpMcRingBuffer: slotIndex must be < nSlots");
|
||||
+ ": SpMcRingBuffer: slotIndex must be < nBuffers");
|
||||
}
|
||||
return sequenceLocks[slotIndex];
|
||||
return slots[slotIndex].lock;
|
||||
}
|
||||
|
||||
private:
|
||||
void computeStrideAndBufferSize()
|
||||
{
|
||||
// Stride is the maximum of alignment and padding
|
||||
strideNBytes = std::max(
|
||||
constraints.slotStartAlignmentNBytes,
|
||||
constraints.slotPadToNBytes);
|
||||
|
||||
// Buffer size is nSlots * strideNBytes, aligned up to alignment
|
||||
size_t rawSize = nSlots * strideNBytes;
|
||||
bufferNBytes = ((rawSize + constraints.slotStartAlignmentNBytes - 1)
|
||||
/ constraints.slotStartAlignmentNBytes)
|
||||
* constraints.slotStartAlignmentNBytes;
|
||||
}
|
||||
|
||||
// Buffer data
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
// Sequence locks array: one lock per slot
|
||||
// Use unique_ptr array since SequenceLock is not copyable or movable
|
||||
std::unique_ptr<SequenceLock[]> sequenceLocks;
|
||||
|
||||
public:
|
||||
// Layout/invariants
|
||||
size_t nSlots;
|
||||
size_t strideNBytes;
|
||||
size_t bufferNBytes;
|
||||
InputEngineConstraints constraints;
|
||||
size_t nBuffers;
|
||||
|
||||
private:
|
||||
// Frames vector: each frame contains a sequence lock and staging buffer
|
||||
std::vector<StimulusFrame> slots;
|
||||
};
|
||||
|
||||
} // namespace stim_buff
|
||||
} // namespace smo
|
||||
|
||||
#endif // _SP_MC_RING_BUFFER_H
|
||||
|
||||
Reference in New Issue
Block a user