Let's look at the heading for the source file:
#include <CDataSource.h> #include <CDataSourceFactory.h> #include <CDataSink.h> #include <CDataSinkFactory.h> #include <CRingItem.h> #include <DataFormat.h> #include <Exception.h> #include <iostream> #include <cstdlib> #include <memory> #include <vector> #include <cstdint> static void processRingItem(CDataSink& sink, CRingItem& item);
CDataSink
class. That's the abstract base class of the classes that dispose of ring items to some output sink.
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) { 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]); } 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); } std::exit(EXIT_SUCCESS); }
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.
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:
I encourage you to use that pattern in your own programs... starting with the code provided if that helps.