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='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>
27 <A NAME=
"container_sink"></A>
28 <H2>2.1.3. Writing a
<CODE>container_sink
</CODE></H2>
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:
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
35 <SPAN CLASS='keyword'
>namespace
</SPAN> io = boost::iostreams;
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;
42 std::streamsize write(const
<SPAN CLASS='keyword'
>char
</SPAN>* s, std::streamsize n)
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>
49 <SPAN CLASS='comment'
>/* Other members */
</SPAN>
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>
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>
56 <P>You could also write the above example as follows:
</P>
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>
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);
64 <SPAN CLASS='comment'
>/* Other members */
</SPAN>
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.
69 <P>You're now ready to write your
<CODE>container_sink
</CODE>.
</P>
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>
75 <SPAN CLASS='keyword'
>namespace
</SPAN> boost {
<SPAN CLASS='keyword'
>namespace
</SPAN> iostreams {
<SPAN CLASS='keyword'
>namespace
</SPAN> example {
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)
85 container_.insert(container_.end(), s, s + n);
86 <SPAN CLASS='keyword'
>return
</SPAN> n;
88 Container
& container() { return container_; }
89 <SPAN CLASS='keyword'
>private
</SPAN>:
90 Container
& container_;
93 } } }
<SPAN CLASS='comment'
>// End namespace boost::iostreams:example
</SPAN></PRE>
95 <P>Here, note that
</P>
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,
103 <P>You can write to a container_sink as follows
</P>
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>
110 <SPAN CLASS='keyword'
>namespace
</SPAN> io = boost::iostreams;
111 <SPAN CLASS='keyword'
>namespace
</SPAN> ex = boost::iostreams::example;
113 <SPAN CLASS='keyword'
>int
</SPAN> main()
115 <SPAN CLASS='keyword'
>using
</SPAN> <SPAN CLASS='keyword'
>namespace
</SPAN> std;
116 <SPAN CLASS='keyword'
>typedef
</SPAN> ex::container_sink
<string
> string_sink;
119 io::stream
<string_sink
> out(result);
120 out
<< <SPAN CLASS='literal'
>"Hello World!"</SPAN>;
122 assert(result ==
<SPAN CLASS='literal'
>"Hello World!"</SPAN>);
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>.
127 <P>Finally, I should mention that the Iostreams library offers easier ways to append to an STL-compatible container.
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>
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>
136 <SPAN CLASS='keyword'
>namespace
</SPAN> io = boost::iostreams;
138 <SPAN CLASS='keyword'
>int
</SPAN> main()
140 <SPAN CLASS='keyword'
>using
</SPAN> <SPAN CLASS='keyword'
>namespace
</SPAN> std;
143 io::filtering_ostream out(back_inserter(result));
144 out
<< <SPAN CLASS='literal'
>"Hello World!"</SPAN>;
146 assert(result ==
<SPAN CLASS='literal'
>"Hello World!"</SPAN>);
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>
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>
156 <SPAN CLASS='keyword'
>namespace
</SPAN> io = boost::iostreams;
158 <SPAN CLASS='keyword'
>int
</SPAN> main()
160 <SPAN CLASS='keyword'
>using
</SPAN> <SPAN CLASS='keyword'
>namespace
</SPAN> std;
163 io::filtering_ostream out(io::back_inserter(result));
164 out
<< <SPAN CLASS='literal'
>"Hello World!"</SPAN>;
166 assert(result ==
<SPAN CLASS='literal'
>"Hello World!"</SPAN>);
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>
179 <!-- Begin Footer -->
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>)