1 <!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN">
4 <TITLE>Tutorial
</TITLE>
5 <LINK REL=
"stylesheet" HREF=
"../../../../boost.css">
6 <LINK REL=
"stylesheet" HREF=
"../theme/iostreams.css">
12 <H1 CLASS=
"title">Tutorial
</H1>
20 <A HREF='unix2dos_filters.html'
><IMG BORDER=
0 WIDTH=
19 HEIGHT=
19 SRC='../../../../doc/src/images/prev.png'
></A>
21 <A HREF='tutorial.html'
><IMG BORDER=
0 WIDTH=
19 HEIGHT=
19 SRC='../../../../doc/src/images/up.png'
></A>
22 <A HREF='dual_use_filters.html'
><IMG BORDER=
0 WIDTH=
19 HEIGHT=
19 SRC='../../../../doc/src/images/next.png'
></A>
28 <A NAME=
"multichar"></A>
29 <H2>2.2.8. Multi-Character Filters
</H2>
32 All the Filters you've seen so far
— except for those that derive from
<CODE>stdio_filter
</CODE> — process characters one at a time. If you instead process several characters at once, you can often reduce the number of function calls it takes to filter a character sequence, resulting in more efficient code. This is what
<A HREF=
"../concepts/multi_character.html">Multi-Character Filters
</A> allow you to do.
35 <A NAME=
"multichar_input_filters"></A>
36 <H4>Multi-Character InputFilters
</H4>
38 <P>A typical narrow-character
<A HREF=
"../concepts/multi_character.html">Multi-Character
</A> <A HREF=
"../concepts/input_filter.html">InputFilter
</A> looks like this:
<P>
40 <PRE CLASS=
"broken_ie"><SPAN CLASS='preprocessor'
>#include
</SPAN> <SPAN CLASS=
"literal"><iosfwd
></SPAN> <SPAN CLASS='comment'
>// streamsize
</SPAN>
41 <SPAN CLASS='preprocessor'
>#include
</SPAN> <A CLASS=
"HEADER" HREF=
"../../../../boost/iostreams/categories.hpp"><SPAN CLASS='literal'
><boost/iostreams/categories.hpp
></SPAN></A> <SPAN CLASS='comment'
>// tags
43 <SPAN CLASS='keyword'
>class
</SPAN> my_input_filter {
44 <SPAN CLASS='keyword'
>public
</SPAN>:
45 <SPAN CLASS='keyword'
>typedef
</SPAN> <SPAN CLASS='keyword'
>char
</SPAN> char_type;
46 <SPAN CLASS='keyword'
>struct
</SPAN> category
51 <SPAN CLASS=
"keyword">template
</SPAN><<SPAN CLASS=
"keyword">typename
</SPAN> Source
>
52 std::streamsize read(Source
& src,
<SPAN CLASS='keyword'
>char
</SPAN>* s, std::streamsize n)
54 <SPAN CLASS='comment'
>// Read up to n filtered characters into the buffer s,
</SPAN>
55 <SPAN CLASS='comment'
>// returning the number of characters read or -
1 for EOF.
</SPAN>
56 <SPAN CLASS='comment'
>// Use src to access the unfiltered character sequence
</SPAN>
59 <SPAN CLASS='comment'
>/* Other members */
</SPAN>
63 Notice that the member type category is a
<CODE>struct
</CODE> convertible to
<CODE>input_filter_tag
</CODE> and to
<CODE>multichar_tag
</CODE>. This tells the Iostream library that
<CODE>my_input_filter
</CODE> is a
<A HREF=
"../concepts/multi_character.html">Multi-Character Filter
</A> and an
<A HREF=
"../concepts/input_filter.html">InputFilter
</A>. You could have achieved the same effect several ways.
<I>E.g.
</I>,
66 <PRE CLASS=
"broken_ie"> <SPAN CLASS='keyword'
>struct
</SPAN> category
72 <SPAN CLASS='comment'
>/* or */
</SPAN>
74 <SPAN CLASS='keyword'
>typedef
</SPAN> multichar_input_filter_tag category;
</PRE>
76 <P>(For details,
<I>see
</I> <A HREF=
"../guide/modes.html#mode_tags">Mode Tags
</A> and
<A HREF=
"../guide/traits.html#category_tags">Category Tags
</A>.)
78 <P> You could also write the above example as follows:
</P>
80 <PRE CLASS=
"broken_ie"><SPAN CLASS='preprocessor'
>#include
</SPAN> <SPAN CLASS=
"literal"><iosfwd
></SPAN> <SPAN CLASS='comment'
>// streamsize
</SPAN>
81 <SPAN CLASS='preprocessor'
>#include
</SPAN> <A CLASS=
"HEADER" HREF=
"../../../../boost/iostreams/concepts.hpp"><SPAN CLASS='literal'
><boost/iostreams/concepts.hpp
></SPAN></A> <SPAN CLASS='comment'
>// multichar_input_filter
</SPAN>
83 <SPAN CLASS='keyword'
>class
</SPAN> my_input_filter :
<SPAN CLASS='keyword'
>public
</SPAN> multichar_input_filter {
84 <SPAN CLASS='keyword'
>public
</SPAN>:
85 <SPAN CLASS=
"keyword">template
</SPAN><<SPAN CLASS=
"keyword">typename
</SPAN> Source
>
86 std::streamsize read(
<SPAN CLASS='keyword'
>char
</SPAN>* s, std::streamsize n);
88 <SPAN CLASS='comment'
>/* Other members */
</SPAN>
91 <P>Here
<A HREF=
"../classes/filter.html#synopsis"><CODE>multichar_input_filter
</CODE></A> is a convenience base class which provides the member types
<CODE>char_type
</CODE> and
<CODE>category
</CODE>, as well as no-op implementations of member functions
<CODE>close
</CODE> and
<CODE>imbue
</CODE>.
93 <A NAME=
"shell_comments_multichar_input_filter"></A>
94 <H4><CODE>shell_comments_multichar_input_filter
</CODE></H4>
96 <P>You can express a
<A HREF=
"shell_comments_filters.html">shell comments Filter
</A> as an
<A HREF=
"../concepts/multi_character.html">Multi-Character
</A> <A HREF=
"../concepts/input_filter.html">InputFilter
</A> as follows:
</P>
98 <PRE CLASS=
"broken_ie"><SPAN CLASS='preprocessor'
>#include
</SPAN> <A CLASS=
"header" HREF=
"../../../../boost/iostreams/char_traits.hpp"><SPAN CLASS=
"literal"><boost/iostreams/char_traits.hpp
></SPAN></A> <SPAN CLASS=
"comment">// EOF, WOULD_BLOCK
</SPAN>
99 <SPAN CLASS='preprocessor'
>#include
</SPAN> <A CLASS=
"header" HREF=
"../../../../boost/iostreams/concepts.hpp"><SPAN CLASS=
"literal"><boost/iostreams/concepts.hpp
></SPAN></A> <SPAN CLASS=
"comment">// multichar_input_filter
</SPAN>
100 <SPAN CLASS='preprocessor'
>#include
</SPAN> <A CLASS=
"header" HREF=
"../../../../boost/iostreams/operations.hpp"><SPAN CLASS=
"literal"><boost/iostreams/operations.hpp
></SPAN></A> <SPAN CLASS=
"comment">// get
</SPAN>
102 <SPAN CLASS='keyword'
>namespace
</SPAN> boost {
<SPAN CLASS='keyword'
>namespace
</SPAN> iostreams {
<SPAN CLASS='keyword'
>namespace
</SPAN> example {
104 <SPAN CLASS=
"keyword">class
</SPAN> shell_comments_multichar_input_filter :
<SPAN CLASS=
"keyword">public
</SPAN> multichar_input_filter {
105 <SPAN CLASS=
"keyword">public
</SPAN>:
106 <SPAN CLASS=
"keyword">explicit
</SPAN> shell_comments_multichar_input_filter(
<SPAN CLASS=
"keyword">char
</SPAN> comment_char = '#')
107 : comment_char_(comment_char), skip_(
<SPAN CLASS=
"keyword">false
</SPAN>)
110 <SPAN CLASS=
"keyword">template
</SPAN><<SPAN CLASS=
"keyword">typename
</SPAN> Source
>
111 std::streamsize read(Source
& src,
<SPAN CLASS=
"keyword">char
</SPAN>* s, std::streamsize n)
113 <SPAN CLASS=
"keyword">for
</SPAN> (std::streamsize z =
<SPAN CLASS='numeric_literal'
>0</SPAN>; z
< n; ++z) {
114 <SPAN CLASS=
"keyword">int
</SPAN> c;
115 <SPAN CLASS=
"keyword">while
</SPAN> (true) {
116 <SPAN CLASS=
"keyword">if
</SPAN> ((c = boost::iostreams::get(src)) ==
<SPAN CLASS='numeric_literal'
>EOF
</SPAN>)
117 <SPAN CLASS=
"keyword">return
</SPAN> z !=
<SPAN CLASS='numeric_literal'
>0</SPAN> ? z :
<SPAN CLASS='numeric_literal'
>-
1</SPAN>;
118 <SPAN CLASS=
"keyword">else
</SPAN> <SPAN CLASS=
"keyword">if
</SPAN> (c == WOULD_BLOCK)
119 <SPAN CLASS=
"keyword">return
</SPAN> z;
120 skip_ = c == comment_char_ ?
121 <SPAN CLASS=
"keyword">true
</SPAN> :
123 <SPAN CLASS=
"keyword">false
</SPAN> :
125 <SPAN CLASS=
"keyword">if
</SPAN> (!skip_)
126 <SPAN CLASS=
"keyword">break
</SPAN>;
130 <SPAN CLASS=
"keyword">return
</SPAN> n;
133 <SPAN CLASS=
"keyword">template
</SPAN><<SPAN CLASS=
"keyword">typename
</SPAN> Source
>
134 <SPAN CLASS=
"keyword">void
</SPAN> close(Source
&) { skip_ = false; }
135 <SPAN CLASS=
"keyword">private
</SPAN>:
136 <SPAN CLASS=
"keyword">char
</SPAN> comment_char_;
137 <SPAN CLASS=
"keyword">bool
</SPAN> skip_;
140 } } }
<SPAN CLASS=
"comment">// End namespace boost::iostreams:example
</SPAN></PRE>
143 Note that the implementation of
<CODE>read
</CODE> is very similar to what you would get if you put the implementation of
<A HREF=
"shell_comments_filters.html#shell_comments_input_filter"><CODE>shell_comments_input_filter::get
</CODE></A> inside a
<CODE>for
</CODE> loop iterating from
<CODE>0</CODE> to
<CODE>n
</CODE>. InputFilters which call themselves recursively, such as
<A HREF=
"tab_expanding_filters.html#tab_expanding_input_filter"><CODE>tab_expanding_input_filter
</CODE></A>, are much harder to transform into Multi-Character filters.
146 <A NAME=
"multichar_output_filters"></A>
147 <H4>Multi-Character OutputFilters
</H4>
149 <P>A typical narrow-character
<A HREF=
"../concepts/multi_character.html">Multi-Character
</A> <A HREF=
"../concepts/output_filter.html">OutputFilter
</A> looks like this:
<P>
151 <PRE CLASS=
"broken_ie"><SPAN CLASS='preprocessor'
>#include
</SPAN> <SPAN CLASS=
"literal"><iosfwd
></SPAN> <SPAN CLASS='comment'
>// streamsize
</SPAN>
152 <SPAN CLASS='preprocessor'
>#include
</SPAN> <A CLASS=
"HEADER" HREF=
"../../../../boost/iostreams/categories.hpp"><SPAN CLASS='literal'
><boost/iostreams/categories.hpp
></SPAN></A> <SPAN CLASS='comment'
>// tags
154 <SPAN CLASS='keyword'
>class
</SPAN> my_output_filter {
155 <SPAN CLASS='keyword'
>public
</SPAN>:
156 <SPAN CLASS='keyword'
>typedef
</SPAN> <SPAN CLASS='keyword'
>char
</SPAN> char_type;
157 <SPAN CLASS='keyword'
>struct
</SPAN> category
162 <SPAN CLASS=
"keyword">template
</SPAN><<SPAN CLASS=
"keyword">typename
</SPAN> Sink
>
163 std::streamsize write(Sink
& dest,
<SPAN CLASS='keyword'
>const
</SPAN> <SPAN CLASS='keyword'
>char
</SPAN>* s, std::streamsize n)
165 <SPAN CLASS='comment'
>// Consume up to n filtered characters from the buffer s,
</SPAN>
166 <SPAN CLASS='comment'
>// writing filtered characters to dest. Return the number
</SPAN>
167 <SPAN CLASS='comment'
>// of characters consumed.
</SPAN>
170 <SPAN CLASS='comment'
>/* Other members */
</SPAN>
174 Notice that the member type category is a
<CODE>struct
</CODE> convertible to
<CODE>keyword
</CODE> and to
<CODE>multichar_tag
</CODE>. This tells the Iostream library that
<CODE>my_output_filter
</CODE> is a
<A HREF=
"../concepts/multi_character.html">Multi-Character Filter
</A> and an
<A HREF=
"../concepts/output_filter.html">OutputFilter
</A>. As with
<A HREF=
"../concepts/multi_character.html">Multi-Character
</A> <A HREF=
"../concepts/input_filter.html">InputFilters
</A>, you could have achieved the same effect several different ways.
<I>E.g.
</I>,
177 <PRE CLASS=
"broken_ie"> <SPAN CLASS='keyword'
>struct
</SPAN> category
183 <SPAN CLASS='comment'
>/* or */
</SPAN>
185 <SPAN CLASS='keyword'
>typedef
</SPAN> multichar_output_filter_tag category;
</PRE>
187 <P>(For details,
<I>see
</I> <A HREF=
"../guide/modes.html#mode_tags">Mode Tags
</A> and
<A HREF=
"../guide/traits.html#category_tags">Category Tags
</A>.)
189 <P> You could also write the above example as follows:
</P>
191 <PRE CLASS=
"broken_ie"><SPAN CLASS='preprocessor'
>#include
</SPAN> <SPAN CLASS=
"literal"><iosfwd
></SPAN> <SPAN CLASS='comment'
>// streamsize
</SPAN>
192 <SPAN CLASS='preprocessor'
>#include
</SPAN> <A CLASS=
"HEADER" HREF=
"../../../../boost/iostreams/concepts.hpp"><SPAN CLASS='literal'
><boost/iostreams/concepts.hpp
></SPAN></A> <SPAN CLASS='comment'
>// multichar_output_filter
</SPAN>
194 <SPAN CLASS='keyword'
>class
</SPAN> my_output_filter :
<SPAN CLASS='keyword'
>public
</SPAN> multichar_output_filter {
195 <SPAN CLASS='keyword'
>public
</SPAN>:
196 <SPAN CLASS=
"keyword">template
</SPAN><<SPAN CLASS=
"keyword">typename
</SPAN> Sink
>
197 std::streamsize write(Sink
& dest,
<SPAN CLASS='keyword'
>const
</SPAN> <SPAN CLASS='keyword'
>char
</SPAN>* s, std::streamsize n);
199 <SPAN CLASS='comment'
>/* Other members */
</SPAN>
202 <P>Here
<A HREF=
"../classes/filter.html#synopsis"><CODE>multichar_output_filter
</CODE></A> is a convenience base class which provides the member types
<CODE>char_type
</CODE> and
<CODE>category
</CODE>, as well as no-op implementations of member functions
<CODE>close
</CODE> and
<CODE>imbue
</CODE>.
204 <A NAME=
"shell_comments_multichar_ouput_filter"></A>
205 <H4><CODE>shell_comments_multichar_output_filter
</CODE></H4>
207 <P>You can express a
<A HREF=
"shell_comments_filters.html">shell comments Filter
</A> as an
<A HREF=
"../concepts/multi_character.html">Multi-Character
</A> <A HREF=
"../concepts/output_filter.html">OutputFilter
</A> as follows:
</P>
209 <PRE CLASS=
"broken_ie"><SPAN CLASS='preprocessor'
>#include
</SPAN> <A CLASS=
"header" HREF=
"../../../../boost/iostreams/char_traits.hpp"><SPAN CLASS=
"literal"><boost/iostreams/char_traits.hpp
></SPAN></A> <SPAN CLASS=
"comment">// EOF, WOULD_BLOCK
</SPAN>
210 <SPAN CLASS='preprocessor'
>#include
</SPAN> <A CLASS=
"header" HREF=
"../../../../boost/iostreams/concepts.hpp"><SPAN CLASS=
"literal"><boost/iostreams/concepts.hpp
></SPAN></A> <SPAN CLASS=
"comment">// multichar_output_filter
</SPAN>
211 <SPAN CLASS='preprocessor'
>#include
</SPAN> <A CLASS=
"header" HREF=
"../../../../boost/iostreams/operations.hpp"><SPAN CLASS=
"literal"><boost/iostreams/operations.hpp
></SPAN></A> <SPAN CLASS=
"comment">// get
</SPAN>
213 <SPAN CLASS='keyword'
>namespace
</SPAN> boost {
<SPAN CLASS='keyword'
>namespace
</SPAN> iostreams {
<SPAN CLASS='keyword'
>namespace
</SPAN> example {
215 <SPAN CLASS=
"keyword">class
</SPAN> shell_comments_multichar_output_filter :
<SPAN CLASS=
"keyword">public
</SPAN> multichar_output_filter {
216 <SPAN CLASS=
"keyword">public
</SPAN>:
217 <SPAN CLASS=
"keyword">explicit
</SPAN> shell_comments_multichar_output_filter(
<SPAN CLASS=
"keyword">char
</SPAN> comment_char = '#')
218 : comment_char_(comment_char), skip_(
<SPAN CLASS=
"keyword">false
</SPAN>)
221 <SPAN CLASS=
"keyword">template
</SPAN><<SPAN CLASS=
"keyword">typename
</SPAN> Sink
>
222 std::streamsize write(Sink
& dest,
<SPAN CLASS=
"keyword">const
</SPAN> char* s, std::streamsize n)
225 <SPAN CLASS=
"keyword">for
</SPAN> (z =
<SPAN CLASS='numeric_literal'
>0</SPAN>; z
< n; ++z) {
226 <SPAN CLASS=
"keyword">int
</SPAN> c = s[z];
227 skip_ = c == comment_char_ ?
228 <SPAN CLASS=
"keyword">true
</SPAN> :
229 c ==
<SPAN CLASS='literal'
>'\n'
</SPAN> ?
230 <SPAN CLASS=
"keyword">false
</SPAN> :
232 <SPAN CLASS=
"keyword">if
</SPAN> (skip_)
233 <SPAN CLASS=
"keyword">continue
</SPAN>;
234 <SPAN CLASS=
"keyword">if
</SPAN> (!iostreams::put(dest, c))
235 <SPAN CLASS=
"keyword">break
</SPAN>;
237 <SPAN CLASS=
"keyword">return
</SPAN> z;
240 <SPAN CLASS=
"keyword">template
</SPAN><<SPAN CLASS=
"keyword">typename
</SPAN> Source
>
241 <SPAN CLASS=
"keyword">void
</SPAN> close(Source
&) { skip_ =
<SPAN CLASS=
"keyword">false
</SPAN>; }
242 <SPAN CLASS=
"keyword">private
</SPAN>:
243 <SPAN CLASS=
"keyword">char
</SPAN> comment_char_;
244 <SPAN CLASS=
"keyword">bool
</SPAN> skip_;
247 } } }
<SPAN CLASS=
"comment">// End namespace boost::iostreams:example
</SPAN></PRE>
250 Note that the implementation of
<CODE>write
</CODE> is very similar to what you would get if you put the implementation of
<A HREF=
"shell_comments_filters.html#shell_comments_output_filter"><CODE>shell_comments_output_filter::put
</CODE></A> inside a
<CODE>for
</CODE> loop iterating from
<CODE>0</CODE> to
<CODE>n
</CODE>. OutputFilters which call themselves recursively, such as
<A HREF=
"unix2dos_filters.html#unix2dos_output_filter"><CODE>unix2dos_output_filter
</CODE></A>, are much harder to transform into Multi-Character filters.
256 <A HREF='unix2dos_filters.html'
><IMG BORDER=
0 WIDTH=
19 HEIGHT=
19 SRC='../../../../doc/src/images/prev.png'
></A>
257 <A HREF='tutorial.html'
><IMG BORDER=
0 WIDTH=
19 HEIGHT=
19 SRC='../../../../doc/src/images/up.png'
></A>
258 <A HREF='dual_use_filters.html'
><IMG BORDER=
0 WIDTH=
19 HEIGHT=
19 SRC='../../../../doc/src/images/next.png'
></A>
263 <!-- Begin Footer -->
268 <P CLASS=
"copyright">© Copyright
2008 <a href=
"http://www.coderage.com/" target=
"_top">CodeRage, LLC
</a><br/>© Copyright
2004-
2007 <a href=
"http://www.coderage.com/turkanis/" target=
"_top">Jonathan Turkanis
</a></P>
269 <P CLASS=
"copyright">
270 Use, modification, and distribution are subject to the Boost Software License, Version
2.0. (See accompanying file
<A HREF=
"../../../../LICENSE_1_0.txt">LICENSE_1_0.txt
</A> or copy at
<A HREF=
"http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt
</A>)