io::JoinReader
The JoinReader
is an adapter class implementing io::IReader. It takes multiple readers
and provides one unified interface to them. This is useful for connection e.g. multiple input
channels with one output channel.
Properties
Memory consumption:
sizeof(::estd::slice<::io::IReader*, N>) + sizeof(size_t) + 1
Template Parameters
JoinReader
is a class template with the following parameters:
* \tparam N Number of IReaders this JoinReader wraps.
Public API
The public API of JoinReader
consists of a constructor and the inherited io::IReader API:
/**
* Constructs a JoinReader from an array of IReader sources.
*
* \param sources Slice of pointers (must not be nullptr) to IReader.
*
* \assert sources[0..N-1] != nullptr
* \assert sources[0]->maxSize() == sources[1]->maxSize() ... == sources[N-1]->maxSize()
*/
explicit JoinReader(::estd::slice<IReader*, N> const& sources);
/**
* \see ::io::IReader::maxSize()
*/
size_t maxSize() const override;
/**
* Returns a slice to the next piece of available data.
*
* The strategy used is a form of round-robin, where one element is returned from each queue
* in turn.
* Note that the same element will keep getting returned until release() is called.
*
* \return - Slice of bytes if one of the underlying queues was not empty
* - Empty slice otherwise
*/
::estd::slice<uint8_t> peek() const override;
/**
* \see ::io::IReader::release()
*/
void release() override;
Usage Example
The following example shows a simplified usage of JoinReader
:
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 two readers to one writer. 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(JoinReader, UsageExample)
32{
33 using Queue = ::io::MemoryQueue<1024, 16>;
34 // Create two input queues.
35 Queue q1;
36 Queue q2;
37 io::MemoryQueueReader<Queue> r1{q1};
38 io::MemoryQueueReader<Queue> r2{q2};
39 ::io::IReader* readers[2] = {&r1, &r2};
40 ::io::JoinReader<2> r{readers};
41
42 // Create output queue
43 Queue q3;
44 io::MemoryQueueWriter<Queue> w3{q3};
45
46 // ...
47
48 // This function can be called cyclically to forward data from q1 and q2 to q3.
49 forwardData(r, w3);
50}
51