]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/iostreams/doc/tutorial/container_device.html
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / iostreams / doc / tutorial / container_device.html
CommitLineData
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_sink.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='writing_filters.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_device"></A>
28<H2>2.1.4. Writing a <CODE>container_device</CODE></H2>
29
30<P>Suppose you want to write a Device for reading from and writing to an STL container. In order for combined reading and writing to be useful, you will also need to support seeking within the container. There are several types of Devices which combine reading and writing; they differ according to whether there are two separate character sequences for input and output, or a single combined sequence, and whether there are separate position indicators for reading and writing or a single read/write position indicator. <I>See</I> <A HREF="../guide/modes.html">Modes</A> for details.</P>
31
32
33<P>A narrow-character Device for read-write access to a single character sequence with a single position indicator is called a <A HREF="../concepts/seekable_device.html">SeekableDevice</A>. A typical SeekableDevice looks like this:</P>
34
35<PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS="literal">&lt;iosfwd&gt;</SPAN> <SPAN CLASS='comment'>// streamsize, seekdir</SPAN>
36<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'>// seekable_device_tag</SPAN>
37<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/positioning.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/positioning.hpp&gt;</SPAN></A> <SPAN CLASS='comment'>// stream_offset</SPAN>
38
39<SPAN CLASS='keyword'>namespace</SPAN> io = boost::iostreams;
40
41<SPAN CLASS='keyword'>class</SPAN> my_device {
42<SPAN CLASS='keyword'>public</SPAN>:
43 <SPAN CLASS='keyword'>typedef</SPAN> <SPAN CLASS='keyword'>char</SPAN> char_type;
44 <SPAN CLASS='keyword'>typedef</SPAN> seekable_device_tag category;
45
46 std::streamsize read(<SPAN CLASS='keyword'>char</SPAN>* s, std::streamsize n)
47 {
48 <SPAN CLASS='comment'>// Read up to n characters from the underlying data source</SPAN>
49 <SPAN CLASS='comment'>// into the buffer s, returning the number of characters</SPAN>
50 <SPAN CLASS='comment'>// read; return -1 to indicate EOF</SPAN>
51 }
52
53 std::streamsize write(const <SPAN CLASS='keyword'>char</SPAN>* s, std::streamsize n)
54 {
55 <SPAN CLASS='comment'>// Write up to n characters to the underlying </SPAN>
56 <SPAN CLASS='comment'>// data sink into the buffer s, returning the </SPAN>
57 <SPAN CLASS='comment'>// number of characters written</SPAN>
58 }
59
60 stream_offset seek(stream_offset off, std::ios_base::seekdir way)
61 {
62 <SPAN CLASS='comment'>// Seek to position off and return the new stream </SPAN>
63 <SPAN CLASS='comment'>// position. The argument way indicates how off is</SPAN>
64 <SPAN CLASS='comment'>// interpretted:</SPAN>
65 <SPAN CLASS='comment'>// - std::ios_base::beg indicates an offset from the </SPAN>
66 <SPAN CLASS='comment'>// sequence beginning </SPAN>
67 <SPAN CLASS='comment'>// - std::ios_base::cur indicates an offset from the </SPAN>
68 <SPAN CLASS='comment'>// current character position </SPAN>
69 <SPAN CLASS='comment'>// - std::ios_base::end indicates an offset from the </SPAN>
70 <SPAN CLASS='comment'>// sequence end </SPAN>
71 }
72
73 <SPAN CLASS='comment'>/* Other members */</SPAN>
74};</PRE>
75
76<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>seekable_tag</CODE></A> indicates that <A HREF="../functions/read.html"><CODE>read</CODE></A>, <A HREF="../functions/write.html"><CODE>write</CODE></A> and the single-sequence version of <A HREF="../functions/seek.html"><CODE>seek</CODE></A> are supported.</P>
77
78<P>The type <A HREF="../functions/positioning.html#synopsis"><CODE>stream_offset</CODE></A> is used by the Iostreams library to hold stream offsets.</P>
79
80<P>You could also write the above example as follows:</P>
81
82<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'>// seekable_device</SPAN>
83
84<SPAN CLASS='keyword'>class</SPAN> my_source : <SPAN CLASS='keyword'>public</SPAN> seekable_device {
85<SPAN CLASS='keyword'>public</SPAN>:
86 std::streamsize read(<SPAN CLASS='keyword'>char</SPAN>* s, std::streamsize n);
87 std::streamsize write(const <SPAN CLASS='keyword'>char</SPAN>* s, std::streamsize n);
88 stream_offset seek(stream_offset off, std::ios_base::seekdir way);
89
90 <SPAN CLASS='comment'>/* Other members */</SPAN>
91};</PRE>
92
93<P>Here <A HREF="../classes/device.html#synopsis"><CODE>seekable_device</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.
94
95<P>You're now ready to write your <CODE>container_device</CODE>. Again, let's assume your container's iterators are RandomAccessIterators.</P>
96
97<PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;algorithm&gt;</SPAN> <SPAN CLASS='comment'>// copy, min</SPAN>
98<SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;iosfwd&gt;</SPAN> <SPAN CLASS='comment'>// streamsize</SPAN>
99<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'>// source_tag</SPAN>
100
101<SPAN CLASS='keyword'>namespace</SPAN> boost { <SPAN CLASS='keyword'>namespace</SPAN> iostreams { <SPAN CLASS='keyword'>namespace</SPAN> example {
102
103<SPAN CLASS='keyword'>template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Container&gt;
104<SPAN CLASS="keyword">class</SPAN> container_device {
105<SPAN CLASS="keyword">public</SPAN>:
106 <SPAN CLASS="keyword">typedef</SPAN> <SPAN CLASS="keyword">typename</SPAN> Container::value_type char_type;
107 <SPAN CLASS="keyword">typedef</SPAN> seekable_device_tag category;
108 container_device(Container&amp; container)
109 : container_(container), pos_(<SPAN CLASS='numeric_literal'>0</SPAN>)
110 { }
111
112 std::streamsize read(char_type* s, std::streamsize n)
113 {
114 <SPAN CLASS="keyword">using</SPAN> <SPAN CLASS="keyword">namespace</SPAN> std;
115 streamsize amt = <SPAN CLASS="keyword">static_cast</SPAN>&lt;streamsize&gt;(container_.size() - pos_);
116 streamsize result = (min)(n, amt);
117 <SPAN CLASS="keyword">if</SPAN> (result != <SPAN CLASS='numeric_literal'>0</SPAN>) {
118 std::copy( container_.begin() + pos_,
119 container_.begin() + pos_ + result,
120 s );
121 pos_ += result;
122 <SPAN CLASS="keyword">return</SPAN> result;
123 } <SPAN CLASS="keyword">else</SPAN> {
124 <SPAN CLASS="keyword">return</SPAN> <SPAN CLASS='numeric_literal'>-1</SPAN>; <SPAN CLASS='comment'>// EOF</SPAN>
125 }
126 }
127 std::streamsize write(<SPAN CLASS="keyword">const</SPAN> char_type* s, std::streamsize n)
128 {
129 <SPAN CLASS="keyword">using</SPAN> <SPAN CLASS="keyword">namespace</SPAN> std;
130 streamsize result = <SPAN CLASS='numeric_literal'>0</SPAN>;
131 <SPAN CLASS="keyword">if</SPAN> (pos_ != container_.size()) {
132 streamsize amt =
133 <SPAN CLASS="keyword">static_cast</SPAN>&lt;streamsize&gt;(container_.size() - pos_);
134 result = (min)(n, amt);
135 std::copy(s, s + result, container_.begin() + pos_);
136 pos_ += result;
137 }
138 <SPAN CLASS="keyword">if</SPAN> (result < n) {
139 container_.insert(container_.end(), s + result, s + n);
140 pos_ = container_.size();
141 }
142 <SPAN CLASS="keyword">return</SPAN> n;
143 }
144 stream_offset seek(stream_offset off, std::ios_base::seekdir way)
145 {
146 <SPAN CLASS="keyword">using</SPAN> <SPAN CLASS="keyword">namespace</SPAN> std;
147
148 <SPAN CLASS='comment'>// Determine new value of pos_</SPAN>
149 stream_offset next;
150 <SPAN CLASS="keyword">if</SPAN> (way == ios_base::beg) {
151 next = off;
152 } <SPAN CLASS="keyword">else</SPAN> <SPAN CLASS="keyword">if</SPAN> (way == ios_base::cur) {
153 next = pos_ + off;
154 } <SPAN CLASS="keyword">else</SPAN> <SPAN CLASS="keyword">if</SPAN> (way == ios_base::end) {
155 next = container_.size() + off - <SPAN CLASS='numeric_literal'>1</SPAN>;
156 } <SPAN CLASS="keyword">else</SPAN> {
157 <SPAN CLASS="keyword">throw</SPAN> ios_base::failure(<SPAN CLASS='numeric_literal'>"bad seek direction"</SPAN>);
158 }
159
160 <SPAN CLASS='comment'>// Check for errors</SPAN>
161 <SPAN CLASS="keyword">if</SPAN> (next < <SPAN CLASS='numeric_literal'>0</SPAN> || next >= static_cast&lt;stream_offset>(container_.size()))
162 <SPAN CLASS="keyword">throw</SPAN> ios_base::failure(<SPAN CLASS='numeric_literal'>"bad seek offset"</SPAN>);
163
164 pos_ = next;
165 <SPAN CLASS="keyword">return</SPAN> pos_;
166 }
167
168 Container&amp; container() { <SPAN CLASS="keyword">return</SPAN> container_; }
169<SPAN CLASS="keyword">private</SPAN>:
170 <SPAN CLASS="keyword">typedef</SPAN> <SPAN CLASS="keyword">typename</SPAN> Container::size_type size_type;
171 Container&amp; container_;
172 size_type pos_;
173};
174
175} } } <SPAN CLASS='comment'>// End namespace boost::iostreams:example</SPAN></PRE>
176
177<P>Here, note that</P>
178<UL>
179<LI>The member type <CODE>char_type</CODE> is defined to be equal to the container's <CODE>value_type</CODE>;
180<LI>The member type <CODE>category</CODE> tells the Iostreams library that <CODE>container_device</CODE> is a model of <A HREF="../concepts/seekable_device.html">SeekableDevice</A>;
181<LI>A <CODE>container_device</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>;
182<LI>The implementation of <CODE>read</CODE> is identical to the implementation in <A HREF="container_source.html"><CODE>container_source</CODE></A>.
183</UL>
184
185<P>The implementation of <CODE>write</CODE> is a bit different from the implementation in <A HREF="container_sink.html"><CODE>container_sink</CODE></A>. Rather than simply appending characters to the container, you first check whether the current character position is somewhere in the middle of the container. If it is, you attempt to satisfy the write request by overwriting existing characters in the container, starting at the current character position. If you reach the end of the container before the write request is satisfied, you insert the remaining characters at the end.</P>
186
187<P>The implementation of <CODE>seek</CODE> is straightforward. First, you calculate the new character position based on <CODE>off</CODE> and <CODE>way</CODE>: if <CODE>way</CODE> is <CODE>ios_base::beg</CODE>, the new character position is simply <CODE>off</CODE>; if <CODE>way</CODE> is <CODE>ios_base::cur</CODE>, the new character position is <CODE>pos_ + off</CODE>; if <CODE>way</CODE> is <CODE>ios_base::end</CODE>, the new character position is <CODE>container_.size() + off - 1</CODE>. Next, you check whether the new character position is a valid offset, and throw an exception if it isn't. Instances of <CODE>std::basic_streambuf</CODE> are allowed to return <CODE>-1</CODE> to indicate failure, but the policy of the Boost Iostreams library is that errors should be indicated by throwing an exception (<I>see</I> <A HREF="../guide/exceptions.html">Exceptions</A>). Finally, you set the new position and return it.</P>
188
189<P>You can use a container_device as follows</P>
190
191<PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;cassert&gt;</SPAN>
192<SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;ios&gt;</SPAN> <SPAN CLASS='comment'>// ios_base::beg</SPAN>
193<SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;string&gt;</SPAN>
194<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="header" HREF="../../../../boost/iostreams/stream.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/stream.hpp&gt;</SPAN></A>
195<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>
196
197<SPAN CLASS="keyword">namespace</SPAN> io = boost::iostreams;
198<SPAN CLASS="keyword">namespace</SPAN> ex = boost::iostreams::example;
199
200<SPAN CLASS="keyword">int</SPAN> main()
201{
202 <SPAN CLASS="keyword">using</SPAN> <SPAN CLASS="keyword">namespace</SPAN> std;
203 <SPAN CLASS="keyword">typedef</SPAN> ex::container_device&lt;string&gt; string_device;
204
205 string one, two;
206 io::stream&lt;string_device&gt; io(one);
207 io &lt;&lt; <SPAN CLASS='literal'>"Hello World!"</SPAN>;
208 io.flush();
209 io.seekg(0, BOOST_IOS::beg); <SPAN CLASS='comment'>// seek to the beginning</SPAN>
210 getline(io, two);
211 assert(one == <SPAN CLASS='literal'>"Hello World!"</SPAN>);
212 assert(two == <SPAN CLASS='literal'>"Hello World!"</SPAN>);
213}</PRE>
214
215<!-- Begin Nav -->
216
217<DIV CLASS='nav'>
218 <A HREF='container_sink.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/prev.png'></A>
219 <A HREF='tutorial.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/up.png'></A>
220 <A HREF='writing_filters.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/next.png'></A>
221</DIV>
222
223<!-- End Nav -->
224
225<!-- Begin Footer -->
226
227<HR>
228
229
230<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>
231<P CLASS="copyright">
232 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>)
233</P>
234<!-- End Footer -->
235
236</BODY>