[iostreams] inverse and "stateful" filters

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

[iostreams] inverse and "stateful" filters

EMalenfant
Hi,

I wanted an InputFilter for removing comments from C++ source files. Since
it seemed easier to write an OutputFilter, I decided to write that, and use
iostreams::inverse to make an InputFilter out of it. However, it seems that
inverse can't be used with "stateful" filters.

Consider the following, using dictionary_output_filter from the tutorial:
(http://www.boost.org/libs/iostreams/doc/index.html?path=2.2.6.3)

    namespace io = boost::iostreams;

    const std::string source("This foo will be bar");

    io::example::dictionary dict;
    dict.add("foo", "bar");

    io::filtering_istream in;
    in.push(io::invert(io::example::dictionary_output_filter(dict)));
    in.push(io::array_source(source.c_str(), source.length()));

    io::copy(in, std::cout);

Output:
    This bar will be
   
instead of the expected:
    This bar will be bar
   
Is this a "known limitation"? Is there a workaround? Am I doing something
silly?
 

-----------------------------
√Čric

A conclusion is the place where you got tired of thinking
_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [iostreams] inverse and "stateful" filters

EMalenfant
From: [hidden email]

> Consider the following, using dictionary_output_filter from
> the tutorial:
> (http://www.boost.org/libs/iostreams/doc/index.html?path=2.2.6.3)
>
>     namespace io = boost::iostreams;
>
>     const std::string source("This foo will be bar");
>
>     io::example::dictionary dict;
>     dict.add("foo", "bar");
>
>     io::filtering_istream in;
>     in.push(io::invert(io::example::dictionary_output_filter(dict)));
>     in.push(io::array_source(source.c_str(), source.length()));
>
>     io::copy(in, std::cout);
>
> Output:
>     This bar will be
>    
> instead of the expected:
>     This bar will be bar
>    

Digging a bit, I found that I could "fix" that problem by modifying
invert::read() as follows:
    template<typename Source>
    std::streamsize read(Source& src, char* s, std::streamsize n)
    {
        typedef detail::counted_array_sink<char_type>  array_sink;
        typedef composite<filter_ref, array_sink>      filtered_array_sink;

        assert((flags() & f_write) == 0);
        if (flags() == 0) {
            flags() = f_read;
            buf().set(0, 0);
        }

        filtered_array_sink snk(filter(), array_sink(s, n));
        int_type status;
        for ( status = traits_type::good();
              snk.second().count() < n && status == traits_type::good(); )
        {
            status = buf().fill(src);
            buf().flush(snk);
        }
// "Fix": When eof is reached on the input, close the filter so that it
writes
// any buffered input it may have.
        if ((snk.second().count() == 0) &&
            (status == traits_type::eof())){
            snk.close();
        }
//... "fix" ends here
        return snk.second().count() == 0 &&
               status == traits_type::eof()
                   ?
               -1
                   :
               snk.second().count();
    }

Looking at this, however, I wondered what would happen if the filter has
buffered more characters than what would fit in the array_sink. So I tested
with a very long (around 300) last word in the input. Result: An infinite
loop in non_blocking_adapter::write(), desperately calling write() on a full
counted_array_sink.

Guess I'll forget about invert and write an InputFilter...

_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users