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.
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>
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
>
53 typedef typename char_type_of
<T
>::type char_type
;
54 BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr
)
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
;
65 void open(const T
& t
BOOST_IOSTREAMS_PUSH_PARAMS());
68 bool auto_close() const;
69 void set_auto_close(bool close
);
72 // Declared in linked_streambuf.
73 T
* component() { return &*obj(); }
75 #if !BOOST_WORKAROUND(__GNUC__, == 2)
76 BOOST_IOSTREAMS_USING_PROTECTED_STREAMBUF_MEMBERS(base_type
)
79 //----------virtual functions---------------------------------------------//
81 #ifndef BOOST_IOSTREAMS_NO_LOCALE
82 void imbue(const std::locale
& loc
);
84 #ifdef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES
88 int_type
pbackfail(int_type c
);
89 int_type
overflow(int_type c
);
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(); }
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
);
127 f_output_buffered
= f_open
<< 1,
128 f_auto_close
= f_output_buffered
<< 1
131 optional
<wrapper
> storage_
;
132 streambuf_type
* next_
;
140 std::streamsize pback_size_
;
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
)
158 // Normalize buffer sizes.
160 (buffer_size
!= -1) ?
162 iostreams::optimal_buffer_size(t
);
166 default_pback_buffer_size
;
168 // Construct input buffer.
170 pback_size_
= (std::max
)(2, pback_size
); // STLPort needs 2.
171 std::streamsize size
=
173 ( buffer_size
? buffer_size
: 1 );
175 if (!shared_buffer())
179 // Construct output buffer.
180 if (can_write() && !shared_buffer()) {
181 if (buffer_size
!= 0)
182 out().resize(buffer_size
);
186 storage_
.reset(wrapper(t
));
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()
201 base_type
* self
= this;
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
)
227 next_
->pubimbue(loc
);
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()
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()),
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_
);
255 std::streamsize chars
=
256 obj().read(buf
.data() + pback_size_
, buf
.size() - pback_size_
, next_
);
258 this->set_true_eof(true);
261 setg(eback(), gptr(), buf
.data() + pback_size_
+ chars
);
263 traits_type::to_int_type(*gptr()) :
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()) {
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
);
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 )
290 if (!traits_type::eq_int_type(c
, traits_type::eof())) {
291 if (output_buffered()) {
292 if (pptr() == epptr()) {
294 if (pptr() == epptr())
295 return traits_type::eof();
297 *pptr() = traits_type::to_char_type(c
);
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.
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.
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
350 return obj().seek(0, BOOST_IOS::cur
, BOOST_IOS::in
, next_
) -
351 static_cast<off_type
>(egptr() - gptr());
354 this->BOOST_IOSTREAMS_PUBSYNC(); // sync() confuses VisualAge 6.
355 if (way
== BOOST_IOS::cur
&& gptr())
356 off
-= static_cast<off_type
>(egptr() - gptr());
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
)
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
) {
374 if (which
== BOOST_IOS::out
&& is_convertible
<Mode
, output
>::value
) {
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());
395 const char_type
* ptr
= pptr();
396 setp(out().begin() + amt
, out().end());
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) {
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()
416 if (shared_buffer() && gptr() != 0)
418 if (output_buffered())
419 setp(out().begin(), out().end());
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