]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
2 | <HTML> | |
3 | <HEAD> | |
4 | <TITLE>Tutorial</TITLE> | |
5 | <LINK REL="stylesheet" HREF="../../../../boost.css"> | |
6 | <LINK REL="stylesheet" HREF="../theme/iostreams.css"> | |
7 | </HEAD> | |
8 | <BODY> | |
9 | ||
10 | <!-- Begin Banner --> | |
11 | ||
12 | <H1 CLASS="title">Tutorial</H1> | |
13 | <HR CLASS="banner"> | |
14 | ||
15 | <!-- End Banner --> | |
16 | ||
17 | <!-- Begin Nav --> | |
18 | ||
19 | <DIV CLASS='nav'> | |
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> | |
23 | </DIV> | |
24 | ||
25 | <!-- End Nav --> | |
26 | ||
27 | ||
28 | <A NAME="multichar"></A> | |
29 | <H2>2.2.8. Multi-Character Filters</H2> | |
30 | ||
31 | <P> | |
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. | |
33 | </P> | |
34 | ||
35 | <A NAME="multichar_input_filters"></A> | |
36 | <H4>Multi-Character InputFilters</H4> | |
37 | ||
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> | |
39 | ||
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 | |
42 | </SPAN> | |
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 | |
47 | : input_filter_tag, | |
48 | multichar_tag | |
49 | { }; | |
50 | ||
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) | |
53 | { | |
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> | |
57 | } | |
58 | ||
59 | <SPAN CLASS='comment'>/* Other members */</SPAN> | |
60 | };</PRE> | |
61 | ||
62 | <P> | |
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>, | |
64 | </P> | |
65 | ||
66 | <PRE CLASS="broken_ie"> <SPAN CLASS='keyword'>struct</SPAN> category | |
67 | : input, | |
68 | filter_tag, | |
69 | multichar_tag | |
70 | { }; | |
71 | ||
72 | <SPAN CLASS='comment'>/* or */</SPAN> | |
73 | ||
74 | <SPAN CLASS='keyword'>typedef</SPAN> multichar_input_filter_tag category;</PRE> | |
75 | ||
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>.) | |
77 | ||
78 | <P> You could also write the above example as follows:</P> | |
79 | ||
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> | |
82 | ||
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); | |
87 | ||
88 | <SPAN CLASS='comment'>/* Other members */</SPAN> | |
89 | };</PRE> | |
90 | ||
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>. | |
92 | ||
93 | <A NAME="shell_comments_multichar_input_filter"></A> | |
94 | <H4><CODE>shell_comments_multichar_input_filter</CODE></H4> | |
95 | ||
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> | |
97 | ||
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> | |
101 | ||
102 | <SPAN CLASS='keyword'>namespace</SPAN> boost { <SPAN CLASS='keyword'>namespace</SPAN> iostreams { <SPAN CLASS='keyword'>namespace</SPAN> example { | |
103 | ||
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>) | |
108 | { } | |
109 | ||
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) | |
112 | { | |
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> : | |
122 | c == '\n' ? | |
123 | <SPAN CLASS="keyword">false</SPAN> : | |
124 | skip_; | |
125 | <SPAN CLASS="keyword">if</SPAN> (!skip_) | |
126 | <SPAN CLASS="keyword">break</SPAN>; | |
127 | } | |
128 | s[z] = c; | |
129 | } | |
130 | <SPAN CLASS="keyword">return</SPAN> n; | |
131 | } | |
132 | ||
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_; | |
138 | }; | |
139 | ||
140 | } } } <SPAN CLASS="comment">// End namespace boost::iostreams:example</SPAN></PRE> | |
141 | ||
142 | <P> | |
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. | |
144 | </P> | |
145 | ||
146 | <A NAME="multichar_output_filters"></A> | |
147 | <H4>Multi-Character OutputFilters</H4> | |
148 | ||
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> | |
150 | ||
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 | |
153 | </SPAN> | |
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 | |
158 | : output_filter_tag, | |
159 | multichar_tag | |
160 | { }; | |
161 | ||
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) | |
164 | { | |
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> | |
168 | } | |
169 | ||
170 | <SPAN CLASS='comment'>/* Other members */</SPAN> | |
171 | };</PRE> | |
172 | ||
173 | <P> | |
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>, | |
175 | </P> | |
176 | ||
177 | <PRE CLASS="broken_ie"> <SPAN CLASS='keyword'>struct</SPAN> category | |
178 | : output, | |
179 | filter_tag, | |
180 | multichar_tag | |
181 | { }; | |
182 | ||
183 | <SPAN CLASS='comment'>/* or */</SPAN> | |
184 | ||
185 | <SPAN CLASS='keyword'>typedef</SPAN> multichar_output_filter_tag category;</PRE> | |
186 | ||
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>.) | |
188 | ||
189 | <P> You could also write the above example as follows:</P> | |
190 | ||
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> | |
193 | ||
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); | |
198 | ||
199 | <SPAN CLASS='comment'>/* Other members */</SPAN> | |
200 | };</PRE> | |
201 | ||
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>. | |
203 | ||
204 | <A NAME="shell_comments_multichar_ouput_filter"></A> | |
205 | <H4><CODE>shell_comments_multichar_output_filter</CODE></H4> | |
206 | ||
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> | |
208 | ||
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> | |
212 | ||
213 | <SPAN CLASS='keyword'>namespace</SPAN> boost { <SPAN CLASS='keyword'>namespace</SPAN> iostreams { <SPAN CLASS='keyword'>namespace</SPAN> example { | |
214 | ||
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>) | |
219 | { } | |
220 | ||
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) | |
223 | { | |
224 | std::streamsize z; | |
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> : | |
231 | skip_; | |
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>; | |
236 | } | |
237 | <SPAN CLASS="keyword">return</SPAN> z; | |
238 | } | |
239 | ||
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_; | |
245 | }; | |
246 | ||
247 | } } } <SPAN CLASS="comment">// End namespace boost::iostreams:example</SPAN></PRE> | |
248 | ||
249 | <P> | |
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. | |
251 | </P> | |
252 | ||
253 | <!-- Begin Nav --> | |
254 | ||
255 | <DIV CLASS='nav'> | |
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> | |
259 | </DIV> | |
260 | ||
261 | <!-- End Nav --> | |
262 | ||
263 | <!-- Begin Footer --> | |
264 | ||
265 | <HR> | |
266 | ||
267 | ||
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>) | |
271 | </P> | |
272 | <!-- End Footer --> | |
273 | ||
274 | </BODY> |