2.2.1. Overview: InputFilters, OutputFilters and Filter Helpers

Filters are used to modify character sequences. For example, you might use a filter to replace all instances of one word with another, to convert all alphabetic characters to lower case or to encrypt a document. Sometimes the filter is a mere observer; in this case the filtered character sequence if the same as the unfiltered sequence. For example, you might use a filter to count the number of occurrences of a given word.

InputFilters and OutputFilters

The Iostreams library supports two basic categories of Filters, InputFilters and OutputFilters. InputFilters represent a “pull” model of filtering: a source of unfiltered data is provided — represented as a Source — and the Filter is expected to generate a certain number of characters of the filtered sequence. The filtered sequence is generated incrementally, meaning that to filter a given character sequence the Filter typically must be invoked several times. OutputFilters represent a “push” model of filtering: a sequence of unfiltered characters and a Sink are provided, and the Filter is expected to filter the characters and write them to the Sink. Like InputFilters, OutputFilters also process data incrementally.

The simplest InputFilters and OutputFilters process characters one at a time. This type of Filter is easy to write, but is less efficient than Filters that process several characters at a time. Filters which process several characters at a time are called Multi-Character filters.

Filter Helpers

The Iostreams library provides several utilities to make Filter writing easier:

Selecting a Filter Concept

Suppose you need to write a Filter to perform a given filtering task. How do you decide whether to write an InputFilter or OutputFilter, or to use one of the Filter helpers? The first two Filter helpers mentioned above, aggregate_filter and stdio_filter, have high-memory usage and only work with character sequences that have a well-defined end. They allow filtering algorithms to be expressed in a very straightforward way, however, and so provide a good introduction to filtering. The third Filter helper, symmetric_filter, is useful for defining filter based on C-language API such as zlib, libbz2 or OpenSSL. If none of the Filter helpers are appropriate, you should generally write an InputFilter if you plan to use the filter for reading and an OutputFilter if you plan to use it for writing. In some cases, however, it is much easier to express an algorithm as an InputFilter than as an OutputFilter, or vice versa. In such cases, you can write the filter whichever way is easier, and use the class template inverse or the function template invert to turn an InputFilter into an OutputFilter or vice versa.

In all but the last of the filtering examples below, I will first show how to implement an algorithm using stdio_filter before implementing it from scratch as an InputFilter or OutputFilter.