io::BufferedWriter
The BufferedWriter
is a helper class implementing io::IWriter allowing a buffered
transfer of smaller slices using an io::IWriter which provides these buffers. Using a
BufferedWriter
only makes sense, if the chunks of data being transferred via this channel
are much smaller compared to the maximum allocation size of this channel.
A typical use case would be transmission of multiple 8-byte CAN frames via UDP packets of e.g.
1400 bytes.
Properties
Internally the
BufferedWriter
manages slices ofdestination.maxSize()
bytes and provides subslices of it to the user.Call to
flush()
required to commit currently buffered data.Memory consumption:
sizeof(::io::IWriter&) + sizeof(::estd::slice<uint8_t>) + sizeof(size_t)
Public API
The public API of BufferedWriter
consists of a constructor and the inherited IWriter
API:
/**
* Constructs a BufferedWriter from a given IWriter destination.
*/
explicit BufferedWriter(IWriter& destination);
/**
* \see IWriter::maxSize()
*/
size_t maxSize() const override;
/**
* Allocates a slice of bytes of a given size.
*
* If not enough memory is available in the current buffer, it will be flushed and a
* new allocation of destination.maxSize() bytes will be done.
*
* \param size Number of bytes to allocate from this BufferedWriter.
* \return - Empty slice, if requested size was greater as MAX_ELEMENT_SIZE or no memory
* is available
* - Slice of bytes otherwise.
*/
::estd::slice<uint8_t> allocate(size_t size) override;
/**
* Commits the previously allocated data. It is not guaranteed that this data is immediately
* available to the reader as a call to flush() might be required for that.
*/
void commit() override;
/**
* Commits the data currently written to slice allocated from destination making it available to
* the reader.
*/
void flush() override;
Usage example
Here is an example:
1
2class CanFrameForwarder
3{
4 ::io::IReader& _canFrameInput;
5 ::io::BufferedWriter _udpOutput;
6
7public:
8 CanFrameForwarder(::io::IReader& canFrameInput, ::io::IWriter& udpOutput)
9 : _canFrameInput(canFrameInput), _udpOutput(udpOutput)
10 {}
11
12 void operator()()
13 {
14 // Input format is: uint32_t id, payload.
15 ::estd::slice<uint8_t const> frame = _canFrameInput.peek();
16 while (frame.size() > 0)
17 {
18 // Output format is uint8_t size, uint32_t id, payload
19 ::estd::slice<uint8_t> dst = _udpOutput.allocate(frame.size() + 1);
20 if (dst.size() == 0)
21 {
22 break;
23 }
24 // Format: uint8_t payload length, uint32_t id, payload
25 ::estd::memory::take<uint8_t>(dst) = frame.size();
26 ::estd::memory::copy(dst, frame);
27 _udpOutput.commit();
28 _canFrameInput.release();
29 frame = _canFrameInput.peek();
30 }
31 _udpOutput.flush();
32 }
33};
34
35/**
36 * This usage example demonstrates how to read small input slices of bytes and accumulate them,
37 * using a BufferedWriter into a writer that support much larger allocations.
38 */
39TEST(BufferedWriter, UsageExample)
40{
41 using CanQueue = ::io::MemoryQueue<1024, 12>;
42 using UdpQueue = ::io::MemoryQueue<10240, 1400>;
43 // Create output channel.
44 UdpQueue outputQueue;
45 ::io::MemoryQueueWriter<UdpQueue> output{outputQueue};
46 ::io::BufferedWriter udpWriter{output};
47 // Create input channel.
48 CanQueue inputQueue;
49 ::io::MemoryQueueReader<CanQueue> input{inputQueue};
50
51 CanFrameForwarder canFrameForwarder{input, udpWriter};
52
53 // Call this cyclically
54 canFrameForwarder();
55}
56