|
Boost : |
From: Jonathan Turkanis (technews_at_[hidden])
Date: 2005-01-09 02:02:25
christopher diggins wrote:
> Thank you very much to everyone who has been helping me out, and have
> made some suggestions. It took me a bit to realize the implications
> of what some people were suggesting, so I apologize if I am a bit
> slow to catch up.
>
> I now have code which allows two arbitrary functions ( which have no
> parameters and return void ) to be chained together from cout of one
> to the cin of the other:
Hi Christopher,
I don't have much time to write today but I'd like to make several observations
about this discussion.
It seems to me that what you are trying to achieve is something that is already
well-supported by the iostreams library. The iostreams library offers users a
number of different ways to write filters, with the understanding that some
methods will be more efficient or convenient for a particular purpose than
another.
---- The basic types of filters are these: - push filter (aka output filter): given a sequence of characters and a model of Sink, the filter writes filtered characters to the Sink using the generic output functions put() and write(). - pull filter (aka input filter): Given a model of Source, the filter returns a specified number of characters from the filtered sequence. Two important criteria in designing the filter and device concepts were these: - They should not be hard-wired to deal with a particular type of upstream or downstream object; e.g., they should not be forced to deal with standard input and output streams. This is important for flexibility and efficiency. - They should be able to filter small subsequences from the middle of an input sequence, rather than processing entire streams at once. This is important for memory usage and because some input sequences, such as continuous stock-tickers, have no natural end. On top of these basic filters can be built filters with a more user-friendly interface or filters which are suited to some specific purpose. For instance, - symmetric filter (useful for wrapping C filtering APIs such as zlib): given two character arrays, one for input and one for output, the filter consumes some characters from the input array and writes some characters from the filtered sequence to the output array. - one_step_filter: given an entire input sequence as a std::vector, the filter appends the entire filtered sequence to a second std::vector. ---- one_step_filters are useful when memory usage is not an issue and when streams have a well-defined beginning and end. Using one_step_filters, it is simple to define filters which take an input stream and an output stream, read input from the input stream and write filtered output to the output stream: #include <boost/iostreams/device/back_inserter.hpp> #include <boost/iostreams/filter/one_step_filter.hpp> #include <boost/iostreams/stream_facade.hpp> template<typename Ch> class co_filter : public one_step_filter<Ch> { typedef std::vector<Ch> vector_type; virtual void do_filter( std::basic_istream<Ch>& in, std::basic_ostream<Ch>& out ) = 0; // declared in one_step_filter: virtual void do_filter(const vector_type& src, vector_type& dest) { // Input stream which reads from src: stream_facade< basic_array_source<Ch> > in( &src[0], &src[0] + src.size() ); // Output stream which appends to dest stream_facade< boost::io::back_insert_device<vector_type> > out(boost::io::back_inserter(dest)); do_filter(in, out); } }; Given the above definition, if you write a class which derives from co_filter and override the pure virtual function do_filter, you can add it to the filtering streams from the iostreams library and it will work as you have described, if I understand you correctly. ---- Regarding the pipe notation, currently it can only be used as follows: filtering_istream in(filter1() | filter2() | filter3() | source()); or filtering_ostream out(filter1() | filter2() | filter3() | sink()); However, I should be able to extend it so that if a chain contains both a source and a sink, boost::io::copy is invoked. E.g., source() | filter1() | filter2() | filter3() | sink() would be equivalent to filtering_ostream out(filter1() | filter2() | filter3() | sink()); boost::io::copy(source, out); If I can make this work, and there are no objections, I'll add it. ---- > 1) create wrapper objects around the filters, this would allow the > passing of data to functions, like a command line string Filters can already be passed arbitrary data. > 2) chain arbitrarily long sequences by creating a pipeline object, > and doing the piping in its destructor Arbitrarily long sequences can already be chained. > 3) allow the chaining of streams I'm not sure what this means, but it can probably already be done ;-) > 4) allow the chaining of the various iostreams concepts See above. > 5) allow the chaining of FILE* (i.e. popen, etc.) > 6) allow the chaining of processes This would be a good addition to the library, in the form of the system_filter I described here: http://tinyurl.com/53w9o > 7) allow threading of functions Do you mean this: support filters which think they are processing an entire stream at once, but really their threads are waiting on some syncronization object whenever there is no more input available, or output buffers are full? Jonathan
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk