File: container_sink.html

package info (click to toggle)
boost 1.34.1-14
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 116,412 kB
  • ctags: 259,566
  • sloc: cpp: 642,395; xml: 56,450; python: 17,612; ansic: 14,520; sh: 2,265; yacc: 858; perl: 481; makefile: 478; lex: 94; sql: 74; csh: 6
file content (197 lines) | stat: -rw-r--r-- 11,909 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
    <TITLE>Tutorial</TITLE>
    <LINK REL="stylesheet" HREF="../../../../boost.css">
    <LINK REL="stylesheet" HREF="../theme/iostreams.css">
</HEAD>
<BODY>

<!-- Begin Banner -->

    <H1 CLASS="title">Tutorial</H1>
    <HR CLASS="banner">

<!-- End Banner -->

<!-- Begin Nav -->

<DIV CLASS='nav'>
    <A HREF='container_source.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/html/images/prev.png'></A>
    <A HREF='tutorial.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/html/images/up.png'></A>
    <A HREF='container_device.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/html/images/next.png'></A>
</DIV>

<!-- End Nav -->

<A NAME="container_sink"></A>
<H2>2.1.3. Writing a <CODE>container_sink</CODE></H2>

<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:

<PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS="literal">&lt;iosfwd&gt;</SPAN>                          <SPAN CLASS='comment'>// streamsize</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/categories.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/categories.hpp&gt;</SPAN></A>  <SPAN CLASS='comment'>// sink_tag
</SPAN>
<SPAN CLASS='keyword'>namespace</SPAN> io = boost::iostreams;

<SPAN CLASS='keyword'>class</SPAN> my_sink {
<SPAN CLASS='keyword'>public</SPAN>:
    <SPAN CLASS='keyword'>typedef</SPAN> <SPAN CLASS='keyword'>char</SPAN>      char_type;
    <SPAN CLASS='keyword'>typedef</SPAN> sink_tag  category;

    std::streamsize write(const <SPAN CLASS='keyword'>char</SPAN>* s, std::streamsize n)
    {
        <SPAN CLASS='comment'>// Write up to n characters to the underlying </SPAN>
        <SPAN CLASS='comment'>// data sink into the buffer s, returning the </SPAN>
        <SPAN CLASS='comment'>// number of characters written</SPAN>
    }

    <SPAN CLASS='comment'>/* Other members */</SPAN>
};</PRE>

<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>

<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>

<P>You could also write the above example as follows:</P>

<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'>// sink</SPAN>

<SPAN CLASS='keyword'>class</SPAN> my_sink : <SPAN CLASS='keyword'>public</SPAN> sink {
<SPAN CLASS='keyword'>public</SPAN>:
    std::streamsize write(const <SPAN CLASS='keyword'>char</SPAN>* s, std::streamsize n);

    <SPAN CLASS='comment'>/* Other members */</SPAN>
};</PRE>

<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.

<P>You're now ready to write your <CODE>container_source</CODE>.</P>

<PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;algorithm&gt;</SPAN>                       <SPAN CLASS='comment'>// copy, min</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;iosfwd&gt;</SPAN>                          <SPAN CLASS='comment'>// streamsize</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS='header' HREF="../../../../boost/iostreams/categories.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/categories.hpp&gt;</SPAN></A>  <SPAN CLASS='comment'>// sink_tag</SPAN>

<SPAN CLASS='keyword'>namespace</SPAN> boost { <SPAN CLASS='keyword'>namespace</SPAN> iostreams { <SPAN CLASS='keyword'>namespace</SPAN> example {

<SPAN CLASS='keyword'>template</SPAN>&lt;<SPAN CLASS='keyword'>typename</SPAN> Container&gt;
<SPAN CLASS='keyword'>class</SPAN> container_sink {
<SPAN CLASS='keyword'>public</SPAN>:
    <SPAN CLASS='keyword'>typedef</SPAN> <SPAN CLASS='keyword'>typename</SPAN> Container::value_type  char_type;
    <SPAN CLASS='keyword'>typedef</SPAN> sink_tag                        category;
    container_sink(Container& container) : container_(container) { }
    std::streamsize write(const char_type* s, std::streamsize n)
    {
        container_.insert(container_.end(), s, s + n);
        <SPAN CLASS='keyword'>return</SPAN> n;
    }
    Container& container() { return container_; }
<SPAN CLASS='keyword'>private</SPAN>:
    Container& container_;
};

} } } <SPAN CLASS='comment'>// End namespace boost::iostreams:example</SPAN></PRE>

<P>Here, note that</P>
<UL>
<LI>The member type <CODE>char_type</CODE> is defined to be equal to the containers's <CODE>value_type</CODE>;
<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>;
<LI>A <CODE>container_source</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
<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,
</UL>

<P>It's tempting to make <CODE>pos_</CODE> an iterator instead of an integral value. That would be fine here, but when you turn to Devices for <I>writing</I> to containers, a stored iterator could easily be invalidated if you're not careful. Since you're only dealing with RandomAccessIterators, maintaining the current reading position as an integral value is sufficient.</P>

<P>You can write to a container_sink as follows</P>

<PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;cassert&gt;</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;string&gt;</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/stream.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/stream.hpp&gt;</SPAN></A>
<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../example/container_device.hpp"><SPAN CLASS='literal'>&lt;libs/iostreams/example/container_device.hpp&gt;</SPAN></A> <SPAN CLASS='comment'>// container_source</SPAN>

<SPAN CLASS='keyword'>namespace</SPAN> io = boost::iostreams;
<SPAN CLASS='keyword'>namespace</SPAN> ex = boost::iostreams::example;

<SPAN CLASS='keyword'>int</SPAN> main()
{
    <SPAN CLASS='keyword'>using</SPAN> <SPAN CLASS='keyword'>namespace</SPAN> std;
    <SPAN CLASS='keyword'>typedef</SPAN> ex::container_sink&lt;string&gt; string_sink;

    string                          result;
    io::stream&lt;string_sink&gt;  out(result);
    out &lt;&lt; <SPAN CLASS='literal'>"Hello World!"</SPAN>;
    out.flush();
    assert(result == <SPAN CLASS='literal'>"Hello World!"</SPAN>);
}</PRE>

<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>.

<P>Finally, I should mention that the Iostreams library offers easier ways to append to an STL-compatible container.

First, OutputIterators can be added directly to <A HREF="../guide/filtering_streams.html">filtering streams and stream buffers</A>. So you could write:</P>

<PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;cassert&gt;</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;iterator&gt;</SPAN>  <SPAN CLASS='comment'>// back_inserter</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;string&gt;</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/filtering_stream.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/filtering_stream.hpp&gt;</SPAN></A>

<SPAN CLASS='keyword'>namespace</SPAN> io = boost::iostreams;

<SPAN CLASS='keyword'>int</SPAN> main()
{
    <SPAN CLASS='keyword'>using</SPAN> <SPAN CLASS='keyword'>namespace</SPAN> std;

    string                 result;
    io::filtering_ostream  out(back_inserter(result));
    out &lt;&lt; <SPAN CLASS='literal'>"Hello World!"</SPAN>;
    out.flush();
    assert(result == <SPAN CLASS='literal'>"Hello World!"</SPAN>);
}</PRE>

<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>

<PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;cassert&gt;</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;string&gt;</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/device/back_inserter.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/device/back_inserter.hpp&gt;</SPAN></A>
<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/filtering_stream.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/filtering_stream.hpp&gt;</SPAN></A>

<SPAN CLASS='keyword'>namespace</SPAN> io = boost::iostreams;

<SPAN CLASS='keyword'>int</SPAN> main()
{
    <SPAN CLASS='keyword'>using</SPAN> <SPAN CLASS='keyword'>namespace</SPAN> std;

    string                 result;
    io::filtering_ostream  out(io::back_inserter(result));
    out &lt;&lt; <SPAN CLASS='literal'>"Hello World!"</SPAN>;
    out.flush();
    assert(result == <SPAN CLASS='literal'>"Hello World!"</SPAN>);
}</PRE>

<!-- Begin Nav -->

<DIV CLASS='nav'>
    <A HREF='container_source.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/html/images/prev.png'></A>
    <A HREF='tutorial.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/html/images/up.png'></A>
    <A HREF='container_device.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/html/images/next.png'></A>
</DIV>

<!-- End Nav -->

<!-- Begin Footer -->

<HR>

<P CLASS="copyright">Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
20 May, 2004
<!--webbot bot="Timestamp" endspan i-checksum="38504" -->
</P>

<P CLASS="copyright">&copy; Copyright <A HREF="http://www.kangaroologic.com" TARGET="_top">Jonathan Turkanis</A>, 2004</P>
<P CLASS="copyright"> 
    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>)
</P>
<!-- End Footer -->

</BODY>