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