]>
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='container_source.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='container_device.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/next.png'></A> | |
23 | </DIV> | |
24 | ||
25 | <!-- End Nav --> | |
26 | ||
27 | <A NAME="container_sink"></A> | |
28 | <H2>2.1.3. Writing a <CODE>container_sink</CODE></H2> | |
29 | ||
30 | <P>Suppose you want to write a Device for appending characters to an STL container. A Device which only supports writing is called a <A HREF="../concepts/sink.html">Sink</A>. A typical narrow-character Sink looks like this: | |
31 | ||
32 | <PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS="literal"><iosfwd></SPAN> <SPAN CLASS='comment'>// streamsize</SPAN> | |
33 | <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'>// sink_tag | |
34 | </SPAN> | |
35 | <SPAN CLASS='keyword'>namespace</SPAN> io = boost::iostreams; | |
36 | ||
37 | <SPAN CLASS='keyword'>class</SPAN> my_sink { | |
38 | <SPAN CLASS='keyword'>public</SPAN>: | |
39 | <SPAN CLASS='keyword'>typedef</SPAN> <SPAN CLASS='keyword'>char</SPAN> char_type; | |
40 | <SPAN CLASS='keyword'>typedef</SPAN> sink_tag category; | |
41 | ||
42 | std::streamsize write(const <SPAN CLASS='keyword'>char</SPAN>* s, std::streamsize n) | |
43 | { | |
44 | <SPAN CLASS='comment'>// Write up to n characters to the underlying </SPAN> | |
45 | <SPAN CLASS='comment'>// data sink into the buffer s, returning the </SPAN> | |
46 | <SPAN CLASS='comment'>// number of characters written</SPAN> | |
47 | } | |
48 | ||
49 | <SPAN CLASS='comment'>/* Other members */</SPAN> | |
50 | };</PRE> | |
51 | ||
52 | <P>Here the member type <A HREF="../guide/traits.html#char_type"><CODE>char_type</CODE></A> indicates the type of characters handled by my_source, which will almost always be <CODE>char</CODE> or <CODE>wchar_t</CODE>. The member type <A HREF="../guide/traits.html#char_type">category</A> indicates which of the fundamental i/o operations are supported by the device. The category tag <A HREF="../guide/traits.html#category_tags"><CODE>sink_tag</CODE></A> indicates that only <A HREF="../functions/write.html"><CODE>write</CODE></A> is supported.</P> | |
53 | ||
54 | <P>The member function <CODE>write</CODE> writes up to <CODE>n</CODE> character into the buffer <CODE>s</CODE> and returns the number of character written. In general, <CODE>write</CODE> may return fewer characters than requested, in which case the Sink is call <I>non-blocking</I>. Non-blocking Devices do not interact well with stanard streams and stream buffers, however, so most devices should be <A HREF="../concepts/blocking.html">Blocking</A>. <I>See</I> <A HREF="../guide/asynchronous.html">Asynchronous and Non-Blocking I/O</A>.</P> | |
55 | ||
56 | <P>You could also write the above example as follows:</P> | |
57 | ||
58 | <PRE CLASS="broken_ie"><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'>// sink</SPAN> | |
59 | ||
60 | <SPAN CLASS='keyword'>class</SPAN> my_sink : <SPAN CLASS='keyword'>public</SPAN> sink { | |
61 | <SPAN CLASS='keyword'>public</SPAN>: | |
62 | std::streamsize write(const <SPAN CLASS='keyword'>char</SPAN>* s, std::streamsize n); | |
63 | ||
64 | <SPAN CLASS='comment'>/* Other members */</SPAN> | |
65 | };</PRE> | |
66 | ||
67 | <P>Here <A HREF="../classes/device.html#synopsis"><CODE>sink</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>, not needed here. | |
68 | ||
69 | <P>You're now ready to write your <CODE>container_sink</CODE>.</P> | |
70 | ||
71 | <PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'><algorithm></SPAN> <SPAN CLASS='comment'>// copy, min</SPAN> | |
72 | <SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'><iosfwd></SPAN> <SPAN CLASS='comment'>// streamsize</SPAN> | |
73 | <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'>// sink_tag</SPAN> | |
74 | ||
75 | <SPAN CLASS='keyword'>namespace</SPAN> boost { <SPAN CLASS='keyword'>namespace</SPAN> iostreams { <SPAN CLASS='keyword'>namespace</SPAN> example { | |
76 | ||
77 | <SPAN CLASS='keyword'>template</SPAN><<SPAN CLASS='keyword'>typename</SPAN> Container> | |
78 | <SPAN CLASS='keyword'>class</SPAN> container_sink { | |
79 | <SPAN CLASS='keyword'>public</SPAN>: | |
80 | <SPAN CLASS='keyword'>typedef</SPAN> <SPAN CLASS='keyword'>typename</SPAN> Container::value_type char_type; | |
81 | <SPAN CLASS='keyword'>typedef</SPAN> sink_tag category; | |
82 | container_sink(Container& container) : container_(container) { } | |
83 | std::streamsize write(const char_type* s, std::streamsize n) | |
84 | { | |
85 | container_.insert(container_.end(), s, s + n); | |
86 | <SPAN CLASS='keyword'>return</SPAN> n; | |
87 | } | |
88 | Container& container() { return container_; } | |
89 | <SPAN CLASS='keyword'>private</SPAN>: | |
90 | Container& container_; | |
91 | }; | |
92 | ||
93 | } } } <SPAN CLASS='comment'>// End namespace boost::iostreams:example</SPAN></PRE> | |
94 | ||
95 | <P>Here, note that</P> | |
96 | <UL> | |
97 | <LI>The member type <CODE>char_type</CODE> is defined to be equal to the containers's <CODE>value_type</CODE>; | |
98 | <LI>The member type <CODE>category</CODE> tells the Iostreams library that <CODE>container_sink</CODE> is a model of <A HREF="../concepts/sink.html">Sink</A>; | |
99 | <LI>A <CODE>container_sink</CODE> can be constructed from a instance of <CODE>Container</CODE>, which is passed and stored by reference, and accessible <I>via</I> the member function <CODE>container()</CODE>; and | |
100 | <LI>The implementation of <CODE>write()</CODE> simply appends the characters in the specified buffer to the underlying container using the container's <CODE>insert</CODE> funcion, | |
101 | </UL> | |
102 | ||
103 | <P>You can write to a container_sink as follows</P> | |
104 | ||
105 | <PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'><cassert></SPAN> | |
106 | <SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'><string></SPAN> | |
107 | <SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/stream.hpp"><SPAN CLASS='literal'><boost/iostreams/stream.hpp></SPAN></A> | |
108 | <SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../example/container_device.hpp"><SPAN CLASS='literal'><libs/iostreams/example/container_device.hpp></SPAN></A> <SPAN CLASS='comment'>// container_sink</SPAN> | |
109 | ||
110 | <SPAN CLASS='keyword'>namespace</SPAN> io = boost::iostreams; | |
111 | <SPAN CLASS='keyword'>namespace</SPAN> ex = boost::iostreams::example; | |
112 | ||
113 | <SPAN CLASS='keyword'>int</SPAN> main() | |
114 | { | |
115 | <SPAN CLASS='keyword'>using</SPAN> <SPAN CLASS='keyword'>namespace</SPAN> std; | |
116 | <SPAN CLASS='keyword'>typedef</SPAN> ex::container_sink<string> string_sink; | |
117 | ||
118 | string result; | |
119 | io::stream<string_sink> out(result); | |
120 | out << <SPAN CLASS='literal'>"Hello World!"</SPAN>; | |
121 | out.flush(); | |
122 | assert(result == <SPAN CLASS='literal'>"Hello World!"</SPAN>); | |
123 | }</PRE> | |
124 | ||
125 | <P>Note that the Iostreams library provides buffering by default. Consequently, the stream <CODE>out</CODE> must be flushed before the characters written are guaranteed to be reflected in the underlying <CODE>string</CODE>. | |
126 | ||
127 | <P>Finally, I should mention that the Iostreams library offers easier ways to append to an STL-compatible container. | |
128 | ||
129 | First, OutputIterators can be added directly to <A HREF="../guide/filtering_streams.html">filtering streams and stream buffers</A>. So you could write:</P> | |
130 | ||
131 | <PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'><cassert></SPAN> | |
132 | <SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'><iterator></SPAN> <SPAN CLASS='comment'>// back_inserter</SPAN> | |
133 | <SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'><string></SPAN> | |
134 | <SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/filtering_stream.hpp"><SPAN CLASS='literal'><boost/iostreams/filtering_stream.hpp></SPAN></A> | |
135 | ||
136 | <SPAN CLASS='keyword'>namespace</SPAN> io = boost::iostreams; | |
137 | ||
138 | <SPAN CLASS='keyword'>int</SPAN> main() | |
139 | { | |
140 | <SPAN CLASS='keyword'>using</SPAN> <SPAN CLASS='keyword'>namespace</SPAN> std; | |
141 | ||
142 | string result; | |
143 | io::filtering_ostream out(back_inserter(result)); | |
144 | out << <SPAN CLASS='literal'>"Hello World!"</SPAN>; | |
145 | out.flush(); | |
146 | assert(result == <SPAN CLASS='literal'>"Hello World!"</SPAN>); | |
147 | }</PRE> | |
148 | ||
149 | <P>Second, the Iostreams library provides a version of <CODE>back_inserter</CODE> that is somewhat more efficient than <CODE>std::back_inserter</CODE> because the Sink it returns uses <CODE>insert</CODE> rather than <CODE>push_back</CODE>. So you could write:</P> | |
150 | ||
151 | <PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'><cassert></SPAN> | |
152 | <SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'><string></SPAN> | |
153 | <SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/device/back_inserter.hpp"><SPAN CLASS='literal'><boost/iostreams/device/back_inserter.hpp></SPAN></A> | |
154 | <SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/filtering_stream.hpp"><SPAN CLASS='literal'><boost/iostreams/filtering_stream.hpp></SPAN></A> | |
155 | ||
156 | <SPAN CLASS='keyword'>namespace</SPAN> io = boost::iostreams; | |
157 | ||
158 | <SPAN CLASS='keyword'>int</SPAN> main() | |
159 | { | |
160 | <SPAN CLASS='keyword'>using</SPAN> <SPAN CLASS='keyword'>namespace</SPAN> std; | |
161 | ||
162 | string result; | |
163 | io::filtering_ostream out(io::back_inserter(result)); | |
164 | out << <SPAN CLASS='literal'>"Hello World!"</SPAN>; | |
165 | out.flush(); | |
166 | assert(result == <SPAN CLASS='literal'>"Hello World!"</SPAN>); | |
167 | }</PRE> | |
168 | ||
169 | <!-- Begin Nav --> | |
170 | ||
171 | <DIV CLASS='nav'> | |
172 | <A HREF='container_source.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/prev.png'></A> | |
173 | <A HREF='tutorial.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/up.png'></A> | |
174 | <A HREF='container_device.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/next.png'></A> | |
175 | </DIV> | |
176 | ||
177 | <!-- End Nav --> | |
178 | ||
179 | <!-- Begin Footer --> | |
180 | ||
181 | <HR> | |
182 | ||
183 | ||
184 | <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> | |
185 | <P CLASS="copyright"> | |
186 | 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>) | |
187 | </P> | |
188 | <!-- End Footer --> | |
189 | ||
190 | </BODY> |