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 129First, 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="https://www.boost.org/users/people/jonathan_turkanis.html" 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>