fix doc example typo
[boost.git] / boost / iostreams / detail / streambuf / indirect_streambuf.hpp
blob4744b5a3641d726c2bb50c9b83edbd1734142429
1 // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2 // (C) Copyright 2003-2007 Jonathan Turkanis
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
5 // See http://www.boost.org/libs/iostreams for documentation.
7 // This material is heavily indebted to the discussion and code samples in
8 // A. Langer and K. Kreft, "Standard C++ IOStreams and Locales",
9 // Addison-Wesley, 2000, pp. 228-43.
11 // User "GMSB" provided an optimization for small seeks.
13 #ifndef BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
14 #define BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
16 #include <algorithm> // min, max.
17 #include <cassert>
18 #include <exception>
19 #include <typeinfo>
20 #include <boost/config.hpp> // Member template friends.
21 #include <boost/detail/workaround.hpp>
22 #include <boost/iostreams/constants.hpp>
23 #include <boost/iostreams/detail/adapter/concept_adapter.hpp>
24 #include <boost/iostreams/detail/buffer.hpp>
25 #include <boost/iostreams/detail/config/wide_streams.hpp>
26 #include <boost/iostreams/detail/double_object.hpp>
27 #include <boost/iostreams/detail/execute.hpp>
28 #include <boost/iostreams/detail/functional.hpp>
29 #include <boost/iostreams/detail/ios.hpp>
30 #include <boost/iostreams/detail/optional.hpp>
31 #include <boost/iostreams/detail/push.hpp>
32 #include <boost/iostreams/detail/streambuf/linked_streambuf.hpp>
33 #include <boost/iostreams/operations.hpp>
34 #include <boost/iostreams/positioning.hpp>
35 #include <boost/iostreams/traits.hpp>
36 #include <boost/iostreams/operations.hpp>
37 #include <boost/mpl/if.hpp>
38 #include <boost/type_traits/is_convertible.hpp>
40 // Must come last.
41 #include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC, BCC 5.x
43 namespace boost { namespace iostreams { namespace detail {
46 // Description: The implementation of basic_streambuf used by chains.
48 template<typename T, typename Tr, typename Alloc, typename Mode>
49 class indirect_streambuf
50 : public linked_streambuf<BOOST_DEDUCED_TYPENAME char_type_of<T>::type, Tr>
52 public:
53 typedef typename char_type_of<T>::type char_type;
54 BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr)
55 private:
56 typedef typename category_of<T>::type category;
57 typedef concept_adapter<T> wrapper;
58 typedef detail::basic_buffer<char_type, Alloc> buffer_type;
59 typedef indirect_streambuf<T, Tr, Alloc, Mode> my_type;
60 typedef detail::linked_streambuf<char_type, traits_type> base_type;
61 typedef linked_streambuf<char_type, Tr> streambuf_type;
62 public:
63 indirect_streambuf();
65 void open(const T& t BOOST_IOSTREAMS_PUSH_PARAMS());
66 bool is_open() const;
67 void close();
68 bool auto_close() const;
69 void set_auto_close(bool close);
70 bool strict_sync();
72 // Declared in linked_streambuf.
73 T* component() { return &*obj(); }
74 protected:
75 #if !BOOST_WORKAROUND(__GNUC__, == 2)
76 BOOST_IOSTREAMS_USING_PROTECTED_STREAMBUF_MEMBERS(base_type)
77 #endif
79 //----------virtual functions---------------------------------------------//
81 #ifndef BOOST_IOSTREAMS_NO_LOCALE
82 void imbue(const std::locale& loc);
83 #endif
84 #ifdef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES
85 public:
86 #endif
87 int_type underflow();
88 int_type pbackfail(int_type c);
89 int_type overflow(int_type c);
90 int sync();
91 pos_type seekoff( off_type off, BOOST_IOS::seekdir way,
92 BOOST_IOS::openmode which );
93 pos_type seekpos(pos_type sp, BOOST_IOS::openmode which);
95 // Declared in linked_streambuf.
96 void set_next(streambuf_type* next);
97 void close_impl(BOOST_IOS::openmode m);
98 const std::type_info& component_type() const { return typeid(T); }
99 void* component_impl() { return component(); }
100 private:
102 //----------Accessor functions--------------------------------------------//
104 wrapper& obj() { return *storage_; }
105 streambuf_type* next() const { return next_; }
106 buffer_type& in() { return buffer_.first(); }
107 buffer_type& out() { return buffer_.second(); }
108 bool can_read() const { return is_convertible<Mode, input>::value; }
109 bool can_write() const { return is_convertible<Mode, output>::value; }
110 bool output_buffered() const { return (flags_ & f_output_buffered) != 0; }
111 bool shared_buffer() const { return is_convertible<Mode, seekable>::value; }
112 void set_flags(int f) { flags_ = f; }
114 //----------State changing functions--------------------------------------//
116 virtual void init_get_area();
117 virtual void init_put_area();
119 //----------Utility function----------------------------------------------//
121 pos_type seek_impl( stream_offset off, BOOST_IOS::seekdir way,
122 BOOST_IOS::openmode which );
123 void sync_impl();
125 enum flag_type {
126 f_open = 1,
127 f_output_buffered = f_open << 1,
128 f_auto_close = f_output_buffered << 1
131 optional<wrapper> storage_;
132 streambuf_type* next_;
133 double_object<
134 buffer_type,
135 is_convertible<
136 Mode,
137 two_sequence
139 > buffer_;
140 std::streamsize pback_size_;
141 int flags_;
144 //--------------Implementation of indirect_streambuf--------------------------//
146 template<typename T, typename Tr, typename Alloc, typename Mode>
147 indirect_streambuf<T, Tr, Alloc, Mode>::indirect_streambuf()
148 : next_(0), pback_size_(0), flags_(f_auto_close) { }
150 //--------------Implementation of open, is_open and close---------------------//
152 template<typename T, typename Tr, typename Alloc, typename Mode>
153 void indirect_streambuf<T, Tr, Alloc, Mode>::open
154 (const T& t, int buffer_size, int pback_size)
156 using namespace std;
158 // Normalize buffer sizes.
159 buffer_size =
160 (buffer_size != -1) ?
161 buffer_size :
162 iostreams::optimal_buffer_size(t);
163 pback_size =
164 (pback_size != -1) ?
165 pback_size :
166 default_pback_buffer_size;
168 // Construct input buffer.
169 if (can_read()) {
170 pback_size_ = (std::max)(2, pback_size); // STLPort needs 2.
171 std::streamsize size =
172 pback_size_ +
173 ( buffer_size ? buffer_size: 1 );
174 in().resize(size);
175 if (!shared_buffer())
176 init_get_area();
179 // Construct output buffer.
180 if (can_write() && !shared_buffer()) {
181 if (buffer_size != 0)
182 out().resize(buffer_size);
183 init_put_area();
186 storage_.reset(wrapper(t));
187 flags_ |= f_open;
188 if (can_write() && buffer_size > 1)
189 flags_ |= f_output_buffered;
190 this->set_true_eof(false);
193 template<typename T, typename Tr, typename Alloc, typename Mode>
194 inline bool indirect_streambuf<T, Tr, Alloc, Mode>::is_open() const
195 { return (flags_ & f_open) != 0; }
197 template<typename T, typename Tr, typename Alloc, typename Mode>
198 void indirect_streambuf<T, Tr, Alloc, Mode>::close()
200 using namespace std;
201 base_type* self = this;
202 detail::execute_all(
203 detail::call_member_close(*self, BOOST_IOS::in),
204 detail::call_member_close(*self, BOOST_IOS::out),
205 detail::call_reset(storage_),
206 detail::clear_flags(flags_)
210 template<typename T, typename Tr, typename Alloc, typename Mode>
211 bool indirect_streambuf<T, Tr, Alloc, Mode>::auto_close() const
212 { return (flags_ & f_auto_close) != 0; }
214 template<typename T, typename Tr, typename Alloc, typename Mode>
215 void indirect_streambuf<T, Tr, Alloc, Mode>::set_auto_close(bool close)
216 { flags_ = (flags_ & ~f_auto_close) | (close ? f_auto_close : 0); }
218 //--------------Implementation virtual functions------------------------------//
220 #ifndef BOOST_IOSTREAMS_NO_LOCALE
221 template<typename T, typename Tr, typename Alloc, typename Mode>
222 void indirect_streambuf<T, Tr, Alloc, Mode>::imbue(const std::locale& loc)
224 if (is_open()) {
225 obj().imbue(loc);
226 if (next_)
227 next_->pubimbue(loc);
230 #endif
232 template<typename T, typename Tr, typename Alloc, typename Mode>
233 typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
234 indirect_streambuf<T, Tr, Alloc, Mode>::underflow()
236 using namespace std;
237 if (!gptr()) init_get_area();
238 buffer_type& buf = in();
239 if (gptr() < egptr()) return traits_type::to_int_type(*gptr());
241 // Fill putback buffer.
242 std::streamsize keep =
243 (std::min)( static_cast<std::streamsize>(gptr() - eback()),
244 pback_size_ );
245 if (keep)
246 traits_type::move( buf.data() + (pback_size_ - keep),
247 gptr() - keep, keep );
249 // Set pointers to reasonable values in case read throws.
250 setg( buf.data() + pback_size_ - keep,
251 buf.data() + pback_size_,
252 buf.data() + pback_size_ );
254 // Read from source.
255 std::streamsize chars =
256 obj().read(buf.data() + pback_size_, buf.size() - pback_size_, next_);
257 if (chars == -1) {
258 this->set_true_eof(true);
259 chars = 0;
261 setg(eback(), gptr(), buf.data() + pback_size_ + chars);
262 return chars != 0 ?
263 traits_type::to_int_type(*gptr()) :
264 traits_type::eof();
267 template<typename T, typename Tr, typename Alloc, typename Mode>
268 typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
269 indirect_streambuf<T, Tr, Alloc, Mode>::pbackfail(int_type c)
271 if (gptr() != eback()) {
272 gbump(-1);
273 if (!traits_type::eq_int_type(c, traits_type::eof()))
274 *gptr() = traits_type::to_char_type(c);
275 return traits_type::not_eof(c);
276 } else {
277 throw bad_putback();
281 template<typename T, typename Tr, typename Alloc, typename Mode>
282 typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
283 indirect_streambuf<T, Tr, Alloc, Mode>::overflow(int_type c)
285 if ( output_buffered() && pptr() == 0 ||
286 shared_buffer() && gptr() != 0 )
288 init_put_area();
290 if (!traits_type::eq_int_type(c, traits_type::eof())) {
291 if (output_buffered()) {
292 if (pptr() == epptr()) {
293 sync_impl();
294 if (pptr() == epptr())
295 return traits_type::eof();
297 *pptr() = traits_type::to_char_type(c);
298 pbump(1);
299 } else {
300 char_type d = traits_type::to_char_type(c);
301 if (obj().write(&d, 1, next_) != 1)
302 return traits_type::eof();
305 return traits_type::not_eof(c);
308 template<typename T, typename Tr, typename Alloc, typename Mode>
309 int indirect_streambuf<T, Tr, Alloc, Mode>::sync()
311 try { // sync() is no-throw.
312 sync_impl();
313 obj().flush(next_);
314 return 0;
315 } catch (...) { return -1; }
318 template<typename T, typename Tr, typename Alloc, typename Mode>
319 bool indirect_streambuf<T, Tr, Alloc, Mode>::strict_sync()
321 try { // sync() is no-throw.
322 sync_impl();
323 return obj().flush(next_);
324 } catch (...) { return false; }
327 template<typename T, typename Tr, typename Alloc, typename Mode>
328 inline typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
329 indirect_streambuf<T, Tr, Alloc, Mode>::seekoff
330 (off_type off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which)
331 { return seek_impl(off, way, which); }
333 template<typename T, typename Tr, typename Alloc, typename Mode>
334 inline typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
335 indirect_streambuf<T, Tr, Alloc, Mode>::seekpos
336 (pos_type sp, BOOST_IOS::openmode which)
338 return seek_impl(position_to_offset(sp), BOOST_IOS::beg, which);
341 template<typename T, typename Tr, typename Alloc, typename Mode>
342 typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
343 indirect_streambuf<T, Tr, Alloc, Mode>::seek_impl
344 (stream_offset off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which)
346 if ( gptr() != 0 && way == BOOST_IOS::cur && which == BOOST_IOS::in &&
347 eback() - gptr() <= off && off <= egptr() - gptr() )
348 { // Small seek optimization
349 gbump(off);
350 return obj().seek(0, BOOST_IOS::cur, BOOST_IOS::in, next_) -
351 static_cast<off_type>(egptr() - gptr());
353 if (pptr() != 0)
354 this->BOOST_IOSTREAMS_PUBSYNC(); // sync() confuses VisualAge 6.
355 if (way == BOOST_IOS::cur && gptr())
356 off -= static_cast<off_type>(egptr() - gptr());
357 setg(0, 0, 0);
358 setp(0, 0);
359 return obj().seek(off, way, which, next_);
362 template<typename T, typename Tr, typename Alloc, typename Mode>
363 inline void indirect_streambuf<T, Tr, Alloc, Mode>::set_next
364 (streambuf_type* next)
365 { next_ = next; }
367 template<typename T, typename Tr, typename Alloc, typename Mode>
368 inline void indirect_streambuf<T, Tr, Alloc, Mode>::close_impl
369 (BOOST_IOS::openmode which)
371 if (which == BOOST_IOS::in && is_convertible<Mode, input>::value) {
372 setg(0, 0, 0);
374 if (which == BOOST_IOS::out && is_convertible<Mode, output>::value) {
375 sync();
376 setp(0, 0);
378 if ( !is_convertible<category, dual_use>::value ||
379 is_convertible<Mode, input>::value == (which == BOOST_IOS::in) )
381 obj().close(which, next_);
385 //----------State changing functions------------------------------------------//
387 template<typename T, typename Tr, typename Alloc, typename Mode>
388 void indirect_streambuf<T, Tr, Alloc, Mode>::sync_impl()
390 std::streamsize avail, amt;
391 if ((avail = static_cast<std::streamsize>(pptr() - pbase())) > 0) {
392 if ((amt = obj().write(pbase(), avail, next())) == avail)
393 setp(out().begin(), out().end());
394 else {
395 const char_type* ptr = pptr();
396 setp(out().begin() + amt, out().end());
397 pbump(ptr - pptr());
402 template<typename T, typename Tr, typename Alloc, typename Mode>
403 void indirect_streambuf<T, Tr, Alloc, Mode>::init_get_area()
405 if (shared_buffer() && pptr() != 0) {
406 sync_impl();
407 setp(0, 0);
409 setg(in().begin(), in().begin(), in().begin());
412 template<typename T, typename Tr, typename Alloc, typename Mode>
413 void indirect_streambuf<T, Tr, Alloc, Mode>::init_put_area()
415 using namespace std;
416 if (shared_buffer() && gptr() != 0)
417 setg(0, 0, 0);
418 if (output_buffered())
419 setp(out().begin(), out().end());
420 else
421 setp(0, 0);
424 //----------------------------------------------------------------------------//
426 } } } // End namespaces detail, iostreams, boost.
428 #include <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC, BCC 5.x
430 #endif // #ifndef BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED