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.
6
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.
10
11// User "GMSB" provided an optimization for small seeks.
12
13#ifndef BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
14#define BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
15
16#include <algorithm> // min, max.
17#include <cassert>
18#include <exception>
19#include <boost/config.hpp> // Member template friends.
20#include <boost/detail/workaround.hpp>
21#include <boost/core/typeinfo.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/throw_exception.hpp>
39#include <boost/type_traits/is_convertible.hpp>
40
41// Must come last.
42#include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC, BCC 5.x
43
44namespace boost { namespace iostreams { namespace detail {
45
46//
47// Description: The implementation of basic_streambuf used by chains.
48//
49template<typename T, typename Tr, typename Alloc, typename Mode>
50class indirect_streambuf
51 : public linked_streambuf<BOOST_DEDUCED_TYPENAME char_type_of<T>::type, Tr>
52{
53public:
54 typedef typename char_type_of<T>::type char_type;
55 BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr)
56private:
57 typedef typename category_of<T>::type category;
58 typedef concept_adapter<T> wrapper;
59 typedef detail::basic_buffer<char_type, Alloc> buffer_type;
60 typedef indirect_streambuf<T, Tr, Alloc, Mode> my_type;
61 typedef detail::linked_streambuf<char_type, traits_type> base_type;
62 typedef linked_streambuf<char_type, Tr> streambuf_type;
63public:
64 indirect_streambuf();
65
66 void open(const T& t BOOST_IOSTREAMS_PUSH_PARAMS());
67 bool is_open() const;
68 void close();
69 bool auto_close() const;
70 void set_auto_close(bool close);
71 bool strict_sync();
72
73 // Declared in linked_streambuf.
74 T* component() { return &*obj(); }
75protected:
76 BOOST_IOSTREAMS_USING_PROTECTED_STREAMBUF_MEMBERS(base_type)
77
78 //----------virtual functions---------------------------------------------//
79
80#ifndef BOOST_IOSTREAMS_NO_LOCALE
81 void imbue(const std::locale& loc);
82#endif
83#ifdef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES
84 public:
85#endif
86 int_type underflow();
87 int_type pbackfail(int_type c);
88 int_type overflow(int_type c);
89 int sync();
90 pos_type seekoff( off_type off, BOOST_IOS::seekdir way,
91 BOOST_IOS::openmode which );
92 pos_type seekpos(pos_type sp, BOOST_IOS::openmode which);
93
94 // Declared in linked_streambuf.
95 void set_next(streambuf_type* next);
96 void close_impl(BOOST_IOS::openmode m);
97 const boost::core::typeinfo& component_type() const { return BOOST_CORE_TYPEID(T); }
98 void* component_impl() { return component(); }
99private:
100
101 //----------Accessor functions--------------------------------------------//
102
103 wrapper& obj() { return *storage_; }
104 streambuf_type* next() const { return next_; }
105 buffer_type& in() { return buffer_.first(); }
106 buffer_type& out() { return buffer_.second(); }
107 bool can_read() const { return is_convertible<Mode, input>::value; }
108 bool can_write() const { return is_convertible<Mode, output>::value; }
109 bool output_buffered() const { return (flags_ & f_output_buffered) != 0; }
110 bool shared_buffer() const { return is_convertible<Mode, seekable>::value || is_convertible<Mode, dual_seekable>::value; }
111 void set_flags(int f) { flags_ = f; }
112
113 //----------State changing functions--------------------------------------//
114
115 virtual void init_get_area();
116 virtual void init_put_area();
117
118 //----------Utility function----------------------------------------------//
119
120 pos_type seek_impl( stream_offset off, BOOST_IOS::seekdir way,
121 BOOST_IOS::openmode which );
122 void sync_impl();
123
124 enum flag_type {
125 f_open = 1,
126 f_output_buffered = f_open << 1,
127 f_auto_close = f_output_buffered << 1
128 };
129
130 optional<wrapper> storage_;
131 streambuf_type* next_;
132 double_object<
133 buffer_type,
134 is_convertible<
135 Mode,
136 two_sequence
137 >
138 > buffer_;
139 std::streamsize pback_size_;
140 int flags_;
141};
142
143//--------------Implementation of indirect_streambuf--------------------------//
144
145template<typename T, typename Tr, typename Alloc, typename Mode>
146indirect_streambuf<T, Tr, Alloc, Mode>::indirect_streambuf()
147 : next_(0), pback_size_(0), flags_(f_auto_close) { }
148
149//--------------Implementation of open, is_open and close---------------------//
150
151template<typename T, typename Tr, typename Alloc, typename Mode>
152void indirect_streambuf<T, Tr, Alloc, Mode>::open
153 (const T& t, std::streamsize buffer_size, std::streamsize pback_size)
154{
155 using namespace std;
156
157 // Normalize buffer sizes.
158 buffer_size =
159 (buffer_size != -1) ?
160 buffer_size :
161 iostreams::optimal_buffer_size(t);
162 pback_size =
163 (pback_size != -1) ?
164 pback_size :
165 default_pback_buffer_size;
166
167 // Construct input buffer.
168 if (can_read()) {
169 pback_size_ = (std::max)(a: std::streamsize(2), b: pback_size); // STLPort needs 2.
170 std::streamsize size =
171 pback_size_ +
172 ( buffer_size ? buffer_size: std::streamsize(1) );
173 in().resize(static_cast<int>(size));
174 if (!shared_buffer())
175 init_get_area();
176 }
177
178 // Construct output buffer.
179 if (can_write() && !shared_buffer()) {
180 if (buffer_size != std::streamsize(0))
181 out().resize(static_cast<int>(buffer_size));
182 init_put_area();
183 }
184
185 storage_.reset(wrapper(t));
186 flags_ |= f_open;
187 if (can_write() && buffer_size > 1)
188 flags_ |= f_output_buffered;
189 this->set_true_eof(false);
190 this->set_needs_close();
191}
192
193template<typename T, typename Tr, typename Alloc, typename Mode>
194inline bool indirect_streambuf<T, Tr, Alloc, Mode>::is_open() const
195{ return (flags_ & f_open) != 0; }
196
197template<typename T, typename Tr, typename Alloc, typename Mode>
198void indirect_streambuf<T, Tr, Alloc, Mode>::close()
199{
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(t&: flags_)
207 );
208}
209
210template<typename T, typename Tr, typename Alloc, typename Mode>
211bool indirect_streambuf<T, Tr, Alloc, Mode>::auto_close() const
212{ return (flags_ & f_auto_close) != 0; }
213
214template<typename T, typename Tr, typename Alloc, typename Mode>
215void indirect_streambuf<T, Tr, Alloc, Mode>::set_auto_close(bool close)
216{ flags_ = (flags_ & ~f_auto_close) | (close ? f_auto_close : 0); }
217
218//--------------Implementation virtual functions------------------------------//
219
220#ifndef BOOST_IOSTREAMS_NO_LOCALE
221template<typename T, typename Tr, typename Alloc, typename Mode>
222void indirect_streambuf<T, Tr, Alloc, Mode>::imbue(const std::locale& loc)
223{
224 if (is_open()) {
225 obj().imbue(loc);
226 if (next_)
227 next_->pubimbue(loc);
228 }
229}
230#endif
231
232template<typename T, typename Tr, typename Alloc, typename Mode>
233typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
234indirect_streambuf<T, Tr, Alloc, Mode>::underflow()
235{
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());
240
241 // Fill putback buffer.
242 std::streamsize keep =
243 (std::min)( a: static_cast<std::streamsize>(gptr() - eback()),
244 b: pback_size_ );
245 if (keep)
246 traits_type::move( buf.data() + (pback_size_ - keep),
247 gptr() - keep, keep );
248
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_ );
253
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;
260 }
261 setg(eback(), gptr(), buf.data() + pback_size_ + chars);
262 return chars != 0 ?
263 traits_type::to_int_type(*gptr()) :
264 traits_type::eof();
265}
266
267template<typename T, typename Tr, typename Alloc, typename Mode>
268typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
269indirect_streambuf<T, Tr, Alloc, Mode>::pbackfail(int_type c)
270{
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 boost::throw_exception(e: bad_putback());
278 }
279}
280
281template<typename T, typename Tr, typename Alloc, typename Mode>
282typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
283indirect_streambuf<T, Tr, Alloc, Mode>::overflow(int_type c)
284{
285 if ( (output_buffered() && pptr() == 0) ||
286 (shared_buffer() && gptr() != 0) )
287 {
288 init_put_area();
289 }
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();
296 }
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();
303 }
304 }
305 return traits_type::not_eof(c);
306}
307
308template<typename T, typename Tr, typename Alloc, typename Mode>
309int indirect_streambuf<T, Tr, Alloc, Mode>::sync()
310{
311 try { // sync() is no-throw.
312 sync_impl();
313 obj().flush(next_);
314 return 0;
315 } catch (...) { return -1; }
316}
317
318template<typename T, typename Tr, typename Alloc, typename Mode>
319bool indirect_streambuf<T, Tr, Alloc, Mode>::strict_sync()
320{
321 try { // sync() is no-throw.
322 sync_impl();
323 return obj().flush(next_);
324 } catch (...) { return false; }
325}
326
327template<typename T, typename Tr, typename Alloc, typename Mode>
328inline typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
329indirect_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); }
332
333template<typename T, typename Tr, typename Alloc, typename Mode>
334inline typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
335indirect_streambuf<T, Tr, Alloc, Mode>::seekpos
336 (pos_type sp, BOOST_IOS::openmode which)
337{
338 return seek_impl(off: position_to_offset(sp), BOOST_IOS::beg, which);
339}
340
341template<typename T, typename Tr, typename Alloc, typename Mode>
342typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
343indirect_streambuf<T, Tr, Alloc, Mode>::seek_impl
344 (stream_offset off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which)
345{
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(static_cast<int>(off));
350 return obj().seek(stream_offset(0), BOOST_IOS::cur, BOOST_IOS::in, next_) -
351 static_cast<off_type>(egptr() - gptr());
352 }
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 bool two_head = is_convertible<category, dual_seekable>::value ||
358 is_convertible<category, bidirectional_seekable>::value;
359 if (two_head) {
360 BOOST_IOS::openmode both = BOOST_IOS::in | BOOST_IOS::out;
361 if ((which & both) == both)
362 boost::throw_exception(e: bad_seek());
363 if (which & BOOST_IOS::in) {
364 setg(0, 0, 0);
365 }
366 if (which & BOOST_IOS::out) {
367 setp(0, 0);
368 }
369 }
370 else {
371 setg(0, 0, 0);
372 setp(0, 0);
373 }
374 return obj().seek(off, way, which, next_);
375}
376
377template<typename T, typename Tr, typename Alloc, typename Mode>
378inline void indirect_streambuf<T, Tr, Alloc, Mode>::set_next
379 (streambuf_type* next)
380{ next_ = next; }
381
382template<typename T, typename Tr, typename Alloc, typename Mode>
383inline void indirect_streambuf<T, Tr, Alloc, Mode>::close_impl
384 (BOOST_IOS::openmode which)
385{
386 if (which == BOOST_IOS::in && is_convertible<Mode, input>::value) {
387 setg(0, 0, 0);
388 }
389 if (which == BOOST_IOS::out && is_convertible<Mode, output>::value) {
390 sync();
391 setp(0, 0);
392 }
393 #if defined(BOOST_MSVC)
394 #pragma warning(push)
395 #pragma warning(disable: 4127) // conditional expression is constant
396 #endif
397 if ( !is_convertible<category, dual_use>::value ||
398 is_convertible<Mode, input>::value == (which == BOOST_IOS::in) )
399 {
400 obj().close(which, next_);
401 }
402 #if defined(BOOST_MSVC)
403 #pragma warning(pop)
404 #endif
405}
406
407//----------State changing functions------------------------------------------//
408
409template<typename T, typename Tr, typename Alloc, typename Mode>
410void indirect_streambuf<T, Tr, Alloc, Mode>::sync_impl()
411{
412 std::streamsize avail, amt;
413 if ((avail = static_cast<std::streamsize>(pptr() - pbase())) > 0) {
414 if ((amt = obj().write(pbase(), avail, next())) == avail)
415 setp(out().begin(), out().end());
416 else {
417 const char_type* ptr = pptr();
418 setp(out().begin() + amt, out().end());
419 pbump(static_cast<int>(ptr - pptr()));
420 }
421 }
422}
423
424template<typename T, typename Tr, typename Alloc, typename Mode>
425void indirect_streambuf<T, Tr, Alloc, Mode>::init_get_area()
426{
427 if (shared_buffer() && pptr() != 0) {
428 sync_impl();
429 setp(0, 0);
430 }
431 setg(in().begin(), in().begin(), in().begin());
432}
433
434template<typename T, typename Tr, typename Alloc, typename Mode>
435void indirect_streambuf<T, Tr, Alloc, Mode>::init_put_area()
436{
437 using namespace std;
438 if (shared_buffer() && gptr() != 0) {
439 obj().seek(static_cast<off_type>(gptr() - egptr()), BOOST_IOS::cur, BOOST_IOS::in, next_);
440 setg(0, 0, 0);
441 }
442 if (output_buffered())
443 setp(out().begin(), out().end());
444 else
445 setp(0, 0);
446}
447
448//----------------------------------------------------------------------------//
449
450} } } // End namespaces detail, iostreams, boost.
451
452#include <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC, BCC 5.x
453
454#endif // #ifndef BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
455

source code of boost/libs/iostreams/include/boost/iostreams/detail/streambuf/indirect_streambuf.hpp