3.2. The code

Let's look at the heading for the source file:


#include <CDataSource.h>             
#include <CDataSourceFactory.h>      
#include <CDataSink.h>                   (1)
#include <CDataSinkFactory.h>            (2)
#include <CRingItem.h>                
#include <DataFormat.h>               
#include <Exception.h>                

#include <iostream>
#include <cstdlib>
#include <memory>
#include <vector>
#include <cstdint>

static void                           (3)
processRingItem(CDataSink& sink, CRingItem& item);


                

(1)
CDataSink.h defines the CDataSink class. That's the abstract base class of the classes that dispose of ring items to some output sink.
(2)
Similarly, CDataSinkFactory.h defines the data sink factory that produces data sinks given a URI.
(3)
Note that we've added a sink parameter to the procdessRingItem function prototype. This is because our ring item processing will involve writing input ring items to the data sink we created.

The usage function has been modified to document the fact that we now need two URIs, one for the data source and one for the sink:


static void
usage(std::ostream& o, const char* msg)
{
    o << msg << std::endl;
    o << "Usage:\n";
    o << "  readrings input-uri output-uri\n";
    o << "      input-uri - The file: or tcp: URI that describes where data comes from\n";
    o << "                   Note that the special value '-' makes the source get data from\n";
    o << "                   standard input.\n";
    o << "      output-uri - The file: or tcp: URI that describes where data will be written\n";
    o << "                   If the URI is a tcp: uri, the host part of the URI must either be\n";
    o << "                   empty or 'localhost\n";
    o << "                   Note that the special value '-' makes the source put data to\n";
    o << "                   standard output\n";
    std::exit(EXIT_FAILURE);
}

                

Very little of the main program is modified. We'll point those bits out below and annotate them.


int
main(int argc, char** argv)
{
    if (argc != 3) {                             (1)
        usage(std::cerr, "Incorrect number of command line parameters");
    }
    std::vector<std::uint16_t> sample;    
    std::vector<std::uint16_t> exclude;   
    CDataSource* pDataSource;
    try {
        pDataSource =
        CDataSourceFactory::makeSource(argv[1], sample, exclude);
    }
    catch (CException& e) {
        std::cerr << "Failed to open ring source: ";
        usage(std::cerr, e.ReasonText());
    }

    CDataSink* pSink;
    try {
        CDataSinkFactory factory;
        pSink = factory.makeSink(argv[2]);      (2)
    }
    catch (CException& e) {
        std::cerr << "Failed to create data sink: ";
        usage(std::cerr, e.ReasonText());
    }
    std::unique_ptr<CDataSink> sink(pSink);

    CRingItem*  pItem;
    while ((pItem = pDataSource->getItem() )) {
        std::unique_ptr>CRingItem< item(pItem);   
        processRingItem(*sink, *item);            (3)
    }

    std::exit(EXIT_SUCCESS);
}

                

(1)
This time we need three command line words. The program name, the data source URI and the data sink URI.
(2)
This code just creates the data sink. Exception handling will report any errors an exit. Note that the pointer to the sink is embedded in an std::unique_ptr. This ensures its destruction when main exits normally or via exception. Deletion of a data sink flushes any internal buffers that might stand between the application and the physical data sink ensuring that all data are written to the output sink.
(3)
The call to processRingItem now also includes the data sink so that function can write the data.

The processRingItem, instead of just outputting a message when a physics item is seen, writes it to the sink. The resulting ring buffer, file or whatever the data sink is attached to, will therefore contain only physics event ring items. The ring items themselves are not altered:


static void
processRingItem(CDataSink& sink, CRingItem& item)
{
    if (item.type() == PHYSICS_EVENT) {
        sink.putItem(item);
    }
}
                

An important program design note. We've essentially used the pattern from the previous chapter unmodified to generate a new program that only differs in what happesn to ring items. This pattern will continue through at least the next two chapters. This pattern basically boils down to:


create a ring data source
while the data source has ring items
   do something to each ring item.
            

I encourage you to use that pattern in your own programs... starting with the code provided if that helps.