]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/iostreams/doc/tutorial/line_wrapping_filters.html
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / iostreams / doc / tutorial / line_wrapping_filters.html
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='shell_comments_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='tab_expanding_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="line_wrapping"></A>
29 <H2>2.2.4. Line-Wrapping Filters</H2>
30
31 <P>
32 Suppose you want to write a filter which wraps lines of text to ensure that no line exceeds a certain maximum length. For simplicity, let's not bother to wrap lines at word boundaries or to insert hyphens. The basic algorithm is as follows: You examine characters one at a time, fowarding them <I>as-is</I>, keeping track of the current column number. When you encounter a newline character, you forward it and reset the column count. When the column count reaches the maxim value, you insert a newline character before the current character and reset the column count.
33 </P>
34
35 <P>
36 In the next three sections, I'll express this algorithm as a <A HREF="../classes/stdio_filter.html"><CODE>stdio_filter</CODE></A>, an <A HREF="../concepts/input_filter.html">InputFilter</A> and an <A HREF="../concepts/output_filter.html">OutputFilter</A>. The source code can be found in the header <A HREF="../../example/line_wrapping_filter.hpp"><CODE>&lt;libs/iostreams/example/line_wrapping_filter.hpp&gt;</CODE></A>. These examples were inspired by James Kanze's <CODE>LineWrappingInserter.hh</CODE> (<I>see</I> <A CLASS="bib_ref" HREF="../bibliography.html#kanze">[Kanze]</A>).
37 </P>
38
39 <A NAME="line_wrapping_stdio_filter"></A>
40 <H4><CODE>line_wrapping_stdio_filter</CODE></H4>
41
42 <P>You can express a line-wrapping Filter as a <A HREF="../classes/stdio_filter.html"><CODE>stdio_filter</CODE></A> as follows:</P>
43
44 <PRE class="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS="literal">&lt;cstdio&gt;</SPAN> <SPAN CLASS="comment">// EOF</SPAN>
45 <SPAN CLASS="preprocessor">#include</SPAN> <SPAN CLASS="literal">&lt;iostream&gt;</SPAN> <SPAN CLASS="comment">// cin, cout</SPAN>
46 <SPAN CLASS="preprocessor">#include</SPAN> <A CLASS="header" HREF="../../../../boost/iostreams/filter/stdio.hpp"><SPAN CLASS="literal">&lt;boost/iostreams/filter/stdio.hpp&gt;</SPAN></A>
47
48 <SPAN CLASS='keyword'>namespace</SPAN> boost { <SPAN CLASS='keyword'>namespace</SPAN> iostreams { <SPAN CLASS='keyword'>namespace</SPAN> example {
49
50 <SPAN CLASS="keyword">class</SPAN> line_wrapping_stdio_filter : <SPAN CLASS="keyword"><SPAN CLASS="keyword"><SPAN CLASS="keyword">public</SPAN></SPAN></SPAN> stdio_filter {
51 <SPAN CLASS="keyword">public</SPAN>:
52 explicit line_wrapping_stdio_filter(<SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> line_length = <SPAN CLASS='numeric_literal'>80</SPAN>)
53 : line_length_(line_length), col_no_(<SPAN CLASS='numeric_literal'>0</SPAN>)
54 { }
55 <SPAN CLASS="keyword">private</SPAN>:
56 <SPAN CLASS="keyword">void</SPAN> do_filter();
57 <SPAN CLASS="keyword">void</SPAN> do_close();
58 <SPAN CLASS="keyword">void</SPAN> put_char(<SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c);
59 <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> line_length_;
60 <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> col_no_;
61 };
62
63 } } } <SPAN CLASS="comment">// End namespace boost::iostreams:example</SPAN></PRE>
64
65 <P>Let's look first at the definition of the helper function <CODE>put_char</CODE>:</P>
66
67 <PRE class="broken_ie"> <SPAN CLASS="keyword">void</SPAN> put_char(<SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c)
68 {
69 std::cout.put(c);
70 <SPAN CLASS="keyword">if</SPAN> (c != <SPAN CLASS="literal">'\n'</SPAN>)
71 ++col_no_;
72 <SPAN CLASS="keyword">else</SPAN>
73 col_no_ = <SPAN CLASS='numeric_literal'>0</SPAN>;
74 }</PRE>
75
76
77 <P>This function writes the given character to <CODE>std::cout</CODE> and increments the column number, unless the character is a newline, in which case the column number is reset. Using <CODE>put_char</CODE>, you can implement the <CODE>virtual</CODE> function <CODE>do_filter</CODE> as follows:</P>
78
79 <PRE class="broken_ie"> <SPAN CLASS="keyword">void</SPAN> do_filter()
80 {
81 <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c;
82 <SPAN CLASS="keyword">while</SPAN> ((c = std::cin.get()) != <SPAN CLASS='numeric_literal'>EOF</SPAN>) {
83 <SPAN CLASS="keyword">if</SPAN> (c != <SPAN CLASS="literal">'\n'</SPAN> &amp;&amp; col_no_ &gt;= line_length_)
84 put_char(<SPAN CLASS="literal">'\n'</SPAN>);
85 put_char(c);
86 }
87 }</PRE>
88
89 <P>The <CODE>while</CODE> loop simply reads a character from <CODE>std::cin</CODE> and writes it to <CODE>std::cout</CODE>, inserting an extra newline character as needed to prevent the column count from exceeding <CODE>line_length_</CODE>.
90
91 <P>Finally, the member function <CODE>do_close</CODE> overrides a <CODE>private</CODE> <CODE>virtual</CODE> function declared in <CODE>stdio_filter</CODE>.</P>
92
93 <PRE class="broken_ie"> <SPAN CLASS="keyword">void</SPAN> do_close() { col_no_ = <SPAN CLASS='numeric_literal'>0</SPAN>; }</PRE>
94
95 <P>Its purpose is to reset the state of the Filter when a stream is closed.</P>
96
97 <A NAME="line_wrapping_input_filter"></A>
98 <H4><CODE>line_wrapping_input_filter</CODE></H4>
99
100 <P>You can express a line-wrapping Filter as an <A HREF="../concepts/input_filter.html">InputFilter</A> as follows:</P>
101
102 <PRE class="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="header" HREF="../../../../boost/iostreams/char_traits.hpp"><SPAN CLASS="literal">&lt;boost/iostreams/char_traits.hpp&gt;</SPAN></A> <SPAN CLASS="comment">// EOF, WOULD_BLOCK</SPAN>
103 <SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="header" HREF="../../../../boost/iostreams/concepts.hpp"><SPAN CLASS="literal">&lt;boost/iostreams/concepts.hpp&gt;</SPAN></A> <SPAN CLASS="comment">// input_filter</SPAN>
104 <SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="header" HREF="../../../../boost/iostreams/operations.hpp"><SPAN CLASS="literal">&lt;boost/iostreams/operations.hpp&gt;</SPAN></A> <SPAN CLASS="comment">// get</SPAN>
105
106 <SPAN CLASS='keyword'>namespace</SPAN> boost { <SPAN CLASS='keyword'>namespace</SPAN> iostreams { <SPAN CLASS='keyword'>namespace</SPAN> example {
107
108 <SPAN CLASS="keyword">class</SPAN> line_wrapping_input_filter : <SPAN CLASS="keyword"><SPAN CLASS="keyword"><SPAN CLASS="keyword">public</SPAN></SPAN></SPAN> input_filter {
109 <SPAN CLASS="keyword">public</SPAN>:
110 explicit line_wrapping_input_filter(<SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> line_length = 80)
111 : line_length_(line_length), col_no_(0), has_next_(<SPAN CLASS="keyword">false</SPAN>)
112 { }
113
114 <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
115 <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> get(Source&amp; src);
116
117 <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Sink&gt;
118 <SPAN CLASS="keyword">void</SPAN> close(Sink&amp;);
119 <SPAN CLASS="keyword">private</SPAN>:
120 <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> get_char(<SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c);
121 <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> line_length_;
122 <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> col_no_;
123 <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> next_;
124 <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> has_next_;
125 };
126
127 } } } <SPAN CLASS="comment">// End namespace boost::iostreams:example</SPAN></PRE>
128
129 <P>Let's look first at the helper function <CODE>get_char</CODE>:</P>
130
131 <PRE class="broken_ie"> <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> get_char(<SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c)
132 {
133 <SPAN CLASS="keyword">if</SPAN> (c != <SPAN CLASS="literal">'\n'</SPAN>)
134 ++col_no_;
135 <SPAN CLASS="keyword">else</SPAN>
136 col_no_ = 0;
137 <SPAN CLASS="keyword">return</SPAN> c;
138 }</PRE>
139
140 <P>This function updates the column count based on the given character <CODE>c</CODE>, then returns <CODE>c</CODE>. Using <CODE>get_char</CODE>, you can implement <CODE>get</CODE> as follows:</P>
141
142 <PRE class="broken_ie"> <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
143 <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> get(Source&amp; src)
144 {
145 <SPAN CLASS="keyword">if</SPAN> (has_next_) {
146 has_next_ = <SPAN CLASS="keyword">false</SPAN>;
147 <SPAN CLASS="keyword">return</SPAN> get_char(next_);
148 }
149
150 <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c;
151 <SPAN CLASS="keyword">if</SPAN> ((c = iostreams::get(src)) == <SPAN CLASS="numeric_literal">EOF</SPAN> || c == WOULD_BLOCK)
152 <SPAN CLASS="keyword">return</SPAN> c;
153
154 <SPAN CLASS="keyword">if</SPAN> (c != <SPAN CLASS="literal">'\n'</SPAN> &amp;&amp; col_no_ &gt;= line_length_) {
155 next_ = c;
156 has_next_ = <SPAN CLASS="keyword">true</SPAN>;
157 <SPAN CLASS="keyword">return</SPAN> get_char(<SPAN CLASS="literal">'\n'</SPAN>);
158 }
159
160 <SPAN CLASS="keyword">return</SPAN> get_char(c);
161 }</PRE>
162
163 <P>
164 An <A HREF="../concepts/input_filter.html">InputFilter</A> which is not a <A HREF="../concepts/multi_character.html">MultiCharacterFilter</A> can only return a single character at a time. Consequently, if you wish to insert a newline before a character <CODE>c</CODE> read from <CODE>src</CODE>, you must store <CODE>c</CODE> and return it the next time <CODE>get</CODE> is called. The member variable <CODE>next_</CODE> is used to store such a character; the member variable <CODE>has_next_</CODE> keeps track of whether such a character is stored.
165 </P>
166
167 <P>
168 The implementation of <CODE>get</CODE> first checks to see if there is stored character, and returns it if there is. Otherwise, it attemps to read a character from <CODE>src</CODE>. If no character can be read, it returns one of the special values <CODE>EOF</CODE> or <CODE>WOULD_BLOCK</CODE>. Otherwise, it checks whether a newline must be inserted. If so, it stores the current character and returns a newline. Otherwise, it returns the current character.
169 </P>
170
171 <P>Finally, the member function <CODE>close</CODE> resets the Filter's state:</P>
172
173 <PRE class="broken_ie"> <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Sink&gt;
174 <SPAN CLASS="keyword">void</SPAN> close(Sink&amp;)
175 {
176 col_no_ = 0;
177 has_next_ = <SPAN CLASS="keyword">false</SPAN>;
178 }</PRE>
179
180 <A NAME="line_wrapping_output_filter"></A>
181 <H4><CODE>line_wrapping_output_filter</CODE></H4>
182
183 <P>You can express a line-wrapping Filter as an <A HREF="../concepts/output_filter.html">OutputFilter</A> as follows:</P>
184
185 <PRE class="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="header" HREF="../../../../boost/iostreams/concepts.hpp"><SPAN CLASS="literal">&lt;boost/iostreams/concepts.hpp&gt;</SPAN></A> <SPAN CLASS="comment">// output_filter</SPAN>
186 <SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="header" HREF="../../../../boost/iostreams/operations.hpp"><SPAN CLASS="literal">&lt;boost/iostreams/operations.hpp&gt;</SPAN></A> <SPAN CLASS="comment">// put</SPAN>
187
188 <SPAN CLASS='keyword'>namespace</SPAN> boost { <SPAN CLASS='keyword'>namespace</SPAN> iostreams { <SPAN CLASS='keyword'>namespace</SPAN> example {
189
190 <SPAN CLASS="keyword">class</SPAN> line_wrapping_output_filter : <SPAN CLASS="keyword"><SPAN CLASS="keyword"><SPAN CLASS="keyword">public</SPAN></SPAN></SPAN> output_filter {
191 <SPAN CLASS="keyword">public</SPAN>:
192 explicit line_wrapping_output_filter(<SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> line_length = 80)
193 : line_length_(line_length), col_no_(0)
194 { }
195
196 <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Sink&gt;
197 <SPAN CLASS="keyword"><SPAN CLASS="keyword">bool</SPAN></SPAN> put(Sink&amp; dest, <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c);
198
199 <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Sink&gt;
200 <SPAN CLASS="keyword">void</SPAN> close(Sink&amp;);
201 <SPAN CLASS="keyword">private</SPAN>:
202 <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Sink&gt;
203 <SPAN CLASS="keyword"><SPAN CLASS="keyword">bool</SPAN></SPAN> put_char(Sink&amp; dest, <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c);
204 <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> line_length_;
205 <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> col_no_;
206 };
207
208 } } } <SPAN CLASS="comment">// End namespace boost::iostreams:example</SPAN></PRE>
209
210 <P>Let's look first at the helper function <CODE>put_char</CODE>:</P>
211
212 <PRE class="broken_ie"> <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Sink&gt;
213 <SPAN CLASS="keyword"><SPAN CLASS="keyword">bool</SPAN></SPAN> put_char(Sink&amp; dest, <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c)
214 {
215 <SPAN CLASS="keyword">if</SPAN> (!iostreams::put(dest, c))
216 <SPAN CLASS="keyword">return</SPAN> <SPAN CLASS="keyword">false</SPAN>;
217 <SPAN CLASS="keyword">if</SPAN> (c != <SPAN CLASS="literal">'\n'</SPAN>)
218 ++col_no_;
219 <SPAN CLASS="keyword">else</SPAN>
220 col_no_ = 0;
221 <SPAN CLASS="keyword">return</SPAN> <SPAN CLASS="keyword">true</SPAN>;
222 }</PRE>
223
224 <P>This function attempts to write the character <CODE>c</CODE> to the given <A HREF="../concepts/sink.html">Sink</A> and updates the column count if successful. Using <CODE>put_char</CODE>, you can implement <CODE>put</CODE> as follows:</P>
225
226 <PRE class="broken_ie"> <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Sink&gt;
227 <SPAN CLASS="keyword"><SPAN CLASS="keyword">bool</SPAN></SPAN> put(Sink&amp; dest, <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c)
228 {
229 <SPAN CLASS="keyword">if</SPAN> (c != <SPAN CLASS="literal">'\n'</SPAN> &amp;&amp; col_no_ &gt;= line_length_ &amp;&amp; !put_char(dest, <SPAN CLASS="literal">'\n'</SPAN>))
230 <SPAN CLASS="keyword">return</SPAN> <SPAN CLASS="keyword">false</SPAN>;
231 <SPAN CLASS="keyword">return</SPAN> put_char(dest, c);
232 }</PRE>
233
234 <P>
235 This function first checks the given character and the column count to see whether a newline character must be inserted. If so, it attempts to write a newline using <CODE>put_char</CODE> and returns false if the operation fails. Otherwise, it attempts to write the the given character using <CODE>put_char</CODE>. Note that if a newline is successfully inserted but the attempt to write the given character fails, the column count will be updated to reflect the newline character so that the next attempt to write the given character will not cause a newline to be inserted.
236 </P>
237
238 <P>Finally, the member function <CODE>close</CODE> resets the Filter's state:</P>
239
240 <PRE class="broken_ie"> <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Sink&gt;
241 <SPAN CLASS="keyword">void</SPAN> close(Sink&amp;) { col_no_ = 0; }</PRE>
242
243 <!-- Begin Nav -->
244
245 <DIV CLASS='nav'>
246 <A HREF='shell_comments_filters.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/prev.png'></A>
247 <A HREF='tutorial.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/up.png'></A>
248 <A HREF='tab_expanding_filters.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/next.png'></A>
249 </DIV>
250
251 <!-- End Nav -->
252
253 <!-- Begin Footer -->
254
255 <HR>
256
257
258 <P CLASS="copyright">&copy; Copyright 2008 <a href="http://www.coderage.com/" target="_top">CodeRage, LLC</a><br/>&copy; Copyright 2004-2007 <a href="http://www.coderage.com/turkanis/" target="_top">Jonathan Turkanis</a></P>
259 <P CLASS="copyright">
260 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>)
261 </P>
262 <!-- End Footer -->
263
264 </BODY>