io::SplitWriter
The SplitWriter
is an adapter class implementing io::IWriter. It takes multiple writers
and provides one unified interface to them writing a copy of the committed data to each of them.
This is useful for connection e.g. one input channel to multiple output channels.
Properties
Memory consumption:
sizeof(::estd::slice<::io::IWriter*, N>) + sizeof(::estd::slice<uint8_t>) + sizeof(size_t)
Template Parameters
SplitWriter
is a class template with the following parameters:
* \tparam N Number of IWriter this SplitWriter wraps.
Public API
The public API of SplitWriter
consists of a constructor and the inherited io::IWriter API:
/**
* Constructs a SplitWriter from an array of IWriter destinations.
*
* \assert destinations[0..N-1] != nullptr
* \assert destinations[0]->maxSize() == destinations[1]->maxSize() ... ==
* destinations[N-1]->maxSize()
*/
explicit SplitWriter(::estd::slice<IWriter*, N> destinations);
/**
* \see ::io::IWriter::maxSize()
*/
size_t maxSize() const override;
/**
* Allocates a slice of bytes of a given size from the first queue that has free space
*
* \param size Number of bytes to allocate
* \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 to all destinations. If a destination is not
* capable of receiving the data, the corresponding drop counter is increased. If the
* data has been committed successfully, the corresponding sent counter is increased.
*/
void commit() override;
/**
* Empty function, nothing special to do for flushing to the other end.
*/
void flush() override;
Usage Example
The following example shows a simplified usage of SplitWriter
:
1/**
2 * Forwards all data from an IReader to an IWriter basically connecting them.
3 * \param source IReader acting as source of the connection.
4 * \param destination IWriter acting as destination of the connection.
5 *
6 * This function will forward one slice of data when being called. If data is available
7 * from the source but no space is available in the destination, the source data will be kept
8 * and retried when the function is called the next time.
9 */
10void forwardData(::io::IReader& source, ::io::IWriter& destination)
11{
12 auto const srcData = source.peek();
13 if (srcData.size() > 0)
14 {
15 auto dstData = destination.allocate(srcData.size());
16 if (dstData.size() >= srcData.size())
17 {
18 ::estd::memory::copy(dstData, srcData);
19 destination.commit();
20 // Only release data after successful forwarding.
21 source.release();
22 }
23 }
24}
25
26/**
27 * This usage example demonstrates how to forward data from one reader to two writers. It
28 * focuses on the setup and forwarding not on how the actual data is put into the queues or
29 * read from it.
30 */
31TEST(SplitWriter, UsageExample)
32{
33 using Queue = ::io::MemoryQueue<1024, 16>;
34 // Create two output queues.
35 Queue q1;
36 Queue q2;
37 io::MemoryQueueWriter<Queue> w1{q1};
38 io::MemoryQueueWriter<Queue> w2{q2};
39 ::io::IWriter* writers[2] = {&w1, &w2};
40 ::io::SplitWriter<2> w{writers};
41
42 // Create input queue
43 Queue q3;
44 io::MemoryQueueReader<Queue> r3{q3};
45
46 // ...
47
48 // This function can be called cyclically to forward data from q3 to q1 and q2.
49 forwardData(r3, w);
50}
51