1 // (C) Copyright Jonathan Turkanis 2003.
2 // Distributed under the Boost Software License, Version 1.0. (See accompanying
3 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
4 // See http://www.boost.org/libs/iostreams for documentation.
6 // This material is heavily indebted to the discussion and code samples in
7 // A. Langer and K. Kreft, "Standard C++ IOStreams and Locales",
8 // Addison-Wesley, 2000, pp. 228-43.
10 #ifndef BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
11 #define BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
13 #include <algorithm> // min, max.
17 #include <boost/config.hpp> // Member template friends.
18 #include <boost/detail/workaround.hpp>
19 #include <boost/iostreams/constants.hpp>
20 #include <boost/iostreams/detail/adapter/concept_adapter.hpp>
21 #include <boost/iostreams/detail/buffer.hpp>
22 #include <boost/iostreams/detail/config/wide_streams.hpp>
23 #include <boost/iostreams/detail/double_object.hpp>
24 #include <boost/iostreams/detail/ios.hpp>
25 #include <boost/iostreams/detail/optional.hpp>
26 #include <boost/iostreams/detail/push.hpp>
27 #include <boost/iostreams/detail/streambuf/linked_streambuf.hpp>
28 #include <boost/iostreams/operations.hpp>
29 #include <boost/iostreams/positioning.hpp>
30 #include <boost/iostreams/traits.hpp>
31 #include <boost/iostreams/operations.hpp>
32 #include <boost/mpl/if.hpp>
33 #include <boost/type_traits/is_convertible.hpp>
36 #include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC, BCC 5.x
38 namespace boost { namespace iostreams { namespace detail {
41 // Description: The implementation of basic_streambuf used by chains.
43 template<typename T, typename Tr, typename Alloc, typename Mode>
44 class indirect_streambuf
45 : public linked_streambuf<BOOST_DEDUCED_TYPENAME char_type_of<T>::type, Tr>
48 typedef typename char_type_of<T>::type char_type;
49 BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr)
51 typedef typename category_of<T>::type category;
52 typedef concept_adapter<T> wrapper;
53 typedef detail::basic_buffer<char_type, Alloc> buffer_type;
54 typedef indirect_streambuf<T, Tr, Alloc, Mode> my_type;
55 typedef detail::linked_streambuf<char_type, traits_type> base_type;
56 typedef linked_streambuf<char_type, Tr> streambuf_type;
60 void open(const T& t BOOST_IOSTREAMS_PUSH_PARAMS());
63 bool auto_close() const;
64 void set_auto_close(bool close);
67 // Declared in linked_streambuf.
68 T* component() { return &*obj(); }
70 #if !BOOST_WORKAROUND(__GNUC__, == 2)
71 BOOST_IOSTREAMS_USING_PROTECTED_STREAMBUF_MEMBERS(base_type)
74 //----------virtual functions---------------------------------------------//
76 #ifndef BOOST_IOSTREAMS_NO_LOCALE
77 void imbue(const std::locale& loc);
79 #ifdef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES
83 int_type pbackfail(int_type c);
84 int_type overflow(int_type c);
86 pos_type seekoff( off_type off, BOOST_IOS::seekdir way,
87 BOOST_IOS::openmode which );
88 pos_type seekpos(pos_type sp, BOOST_IOS::openmode which);
90 // Declared in linked_streambuf.
91 void set_next(streambuf_type* next);
92 void close(BOOST_IOS::openmode m);
93 const std::type_info& component_type() const { return typeid(T); }
94 void* component_impl() { return component(); }
97 //----------Accessor functions--------------------------------------------//
99 wrapper& obj() { return *storage_; }
100 streambuf_type* next() const { return next_; }
101 buffer_type& in() { return buffer_.first(); }
102 buffer_type& out() { return buffer_.second(); }
103 bool can_read() const { return is_convertible<Mode, input>::value; }
104 bool can_write() const { return is_convertible<Mode, output>::value; }
105 bool output_buffered() const { return (flags_ & f_output_buffered) != 0; }
106 bool shared_buffer() const { return is_convertible<Mode, seekable>::value; }
107 void set_flags(int f) { flags_ = f; }
109 //----------State changing functions--------------------------------------//
111 virtual void init_get_area();
112 virtual void init_put_area();
114 //----------Utility function----------------------------------------------//
116 pos_type seek_impl( stream_offset off, BOOST_IOS::seekdir way,
117 BOOST_IOS::openmode which );
119 void close_impl(BOOST_IOS::openmode);
123 f_input_closed = f_open << 1,
124 f_output_closed = f_input_closed << 1,
125 f_output_buffered = f_output_closed << 1,
126 f_auto_close = f_output_buffered << 1
129 optional<wrapper> storage_;
130 streambuf_type* next_;
138 std::streamsize pback_size_;
142 //--------------Implementation of indirect_streambuf--------------------------//
144 template<typename T, typename Tr, typename Alloc, typename Mode>
145 indirect_streambuf<T, Tr, Alloc, Mode>::indirect_streambuf()
146 : next_(0), pback_size_(0), flags_(f_auto_close) { }
148 //--------------Implementation of open, is_open and close---------------------//
150 template<typename T, typename Tr, typename Alloc, typename Mode>
151 void indirect_streambuf<T, Tr, Alloc, Mode>::open
152 (const T& t, int buffer_size, int pback_size)
156 // Normalize buffer sizes.
158 (buffer_size != -1) ?
160 iostreams::optimal_buffer_size(t);
164 default_pback_buffer_size;
166 // Construct input buffer.
168 pback_size_ = (std::max)(2, pback_size); // STLPort needs 2.
171 ( buffer_size ? buffer_size: 1 );
173 if (!shared_buffer())
177 // Construct output buffer.
178 if (can_write() && !shared_buffer()) {
179 if (buffer_size != 0)
180 out().resize(buffer_size);
184 storage_.reset(wrapper(t));
186 if (can_write() && buffer_size > 1)
187 flags_ |= f_output_buffered;
188 this->set_true_eof(false);
191 template<typename T, typename Tr, typename Alloc, typename Mode>
192 inline bool indirect_streambuf<T, Tr, Alloc, Mode>::is_open()
193 { return (flags_ & f_open) != 0; }
195 template<typename T, typename Tr, typename Alloc, typename Mode>
196 void indirect_streambuf<T, Tr, Alloc, Mode>::close()
199 try { close(BOOST_IOS::in); } catch (std::exception&) { }
200 try { close(BOOST_IOS::out); } catch (std::exception&) { }
205 template<typename T, typename Tr, typename Alloc, typename Mode>
206 bool indirect_streambuf<T, Tr, Alloc, Mode>::auto_close() const
207 { return (flags_ & f_auto_close) != 0; }
209 template<typename T, typename Tr, typename Alloc, typename Mode>
210 void indirect_streambuf<T, Tr, Alloc, Mode>::set_auto_close(bool close)
211 { flags_ = (flags_ & ~f_auto_close) | (close ? f_auto_close : 0); }
213 //--------------Implementation virtual functions------------------------------//
215 #ifndef BOOST_IOSTREAMS_NO_LOCALE
216 template<typename T, typename Tr, typename Alloc, typename Mode>
217 void indirect_streambuf<T, Tr, Alloc, Mode>::imbue(const std::locale& loc)
222 next_->pubimbue(loc);
227 template<typename T, typename Tr, typename Alloc, typename Mode>
228 typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
229 indirect_streambuf<T, Tr, Alloc, Mode>::underflow()
232 if (!gptr()) init_get_area();
233 buffer_type& buf = in();
234 if (gptr() < egptr()) return traits_type::to_int_type(*gptr());
236 // Fill putback buffer.
237 streamsize keep = (std::min)( static_cast<streamsize>(gptr() - eback()),
240 traits_type::move( buf.data() + (pback_size_ - keep),
241 gptr() - keep, keep );
243 // Set pointers to reasonable values in case read throws.
244 setg( buf.data() + pback_size_ - keep,
245 buf.data() + pback_size_,
246 buf.data() + pback_size_ );
250 obj().read(buf.data() + pback_size_, buf.size() - pback_size_, next_);
252 this->set_true_eof(true);
255 setg(eback(), gptr(), buf.data() + pback_size_ + chars);
257 traits_type::to_int_type(*gptr()) :
261 template<typename T, typename Tr, typename Alloc, typename Mode>
262 typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
263 indirect_streambuf<T, Tr, Alloc, Mode>::pbackfail(int_type c)
265 if (gptr() != eback()) {
267 if (!traits_type::eq_int_type(c, traits_type::eof()))
268 *gptr() = traits_type::to_char_type(c);
269 return traits_type::not_eof(c);
275 template<typename T, typename Tr, typename Alloc, typename Mode>
276 typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
277 indirect_streambuf<T, Tr, Alloc, Mode>::overflow(int_type c)
279 if ( output_buffered() && pptr() == 0 ||
280 shared_buffer() && gptr() != 0 )
284 if (!traits_type::eq_int_type(c, traits_type::eof())) {
285 if (output_buffered()) {
286 if (pptr() == epptr()) {
288 if (pptr() == epptr())
289 return traits_type::eof();
291 *pptr() = traits_type::to_char_type(c);
294 char_type d = traits_type::to_char_type(c);
295 if (obj().write(&d, 1, next_) != 1)
296 return traits_type::eof();
299 return traits_type::not_eof(c);
302 template<typename T, typename Tr, typename Alloc, typename Mode>
303 int indirect_streambuf<T, Tr, Alloc, Mode>::sync()
305 try { // sync() is no-throw.
309 } catch (std::exception&) { return -1; }
312 template<typename T, typename Tr, typename Alloc, typename Mode>
313 bool indirect_streambuf<T, Tr, Alloc, Mode>::strict_sync()
315 try { // sync() is no-throw.
317 return obj().flush(next_);
318 } catch (std::exception&) { return false; }
321 template<typename T, typename Tr, typename Alloc, typename Mode>
322 inline typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
323 indirect_streambuf<T, Tr, Alloc, Mode>::seekoff
324 (off_type off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which)
325 { return seek_impl(off, way, which); }
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>::seekpos
330 (pos_type sp, BOOST_IOS::openmode)
331 { return seek_impl(sp, BOOST_IOS::beg, BOOST_IOS::in | BOOST_IOS::out); }
333 template<typename T, typename Tr, typename Alloc, typename Mode>
334 typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
335 indirect_streambuf<T, Tr, Alloc, Mode>::seek_impl
336 (stream_offset off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which)
339 this->BOOST_IOSTREAMS_PUBSYNC(); // sync() confuses VisualAge 6.
340 if (way == BOOST_IOS::cur && gptr())
341 off -= static_cast<off_type>(egptr() - gptr());
344 return obj().seek(off, way, which, next_);
347 template<typename T, typename Tr, typename Alloc, typename Mode>
348 inline void indirect_streambuf<T, Tr, Alloc, Mode>::set_next
349 (streambuf_type* next)
352 template<typename T, typename Tr, typename Alloc, typename Mode>
353 inline void indirect_streambuf<T, Tr, Alloc, Mode>::close
354 (BOOST_IOS::openmode which)
357 try { obj().close(which, next_); } catch (std::exception&) { }
360 //----------State changing functions------------------------------------------//
362 template<typename T, typename Tr, typename Alloc, typename Mode>
363 inline void indirect_streambuf<T, Tr, Alloc, Mode>::close_impl
364 (BOOST_IOS::openmode which)
366 if (which == BOOST_IOS::in && (flags_ & f_input_closed) == 0) {
368 flags_ |= f_input_closed;
370 if (which == BOOST_IOS::out && (flags_ & f_output_closed) == 0) {
373 flags_ |= f_output_closed;
377 template<typename T, typename Tr, typename Alloc, typename Mode>
378 void indirect_streambuf<T, Tr, Alloc, Mode>::sync_impl()
380 std::streamsize avail, amt;
381 if ((avail = static_cast<std::streamsize>(pptr() - pbase())) > 0) {
382 if ((amt = obj().write(pbase(), avail, next())) == avail)
383 setp(out().begin(), out().end());
385 const char_type* ptr = pptr();
386 setp(out().begin() + amt, out().end());
392 template<typename T, typename Tr, typename Alloc, typename Mode>
393 void indirect_streambuf<T, Tr, Alloc, Mode>::init_get_area()
395 if (shared_buffer() && pptr() != 0) {
399 setg(in().begin(), in().begin(), in().begin());
402 template<typename T, typename Tr, typename Alloc, typename Mode>
403 void indirect_streambuf<T, Tr, Alloc, Mode>::init_put_area()
406 if (shared_buffer() && gptr() != 0)
408 if (output_buffered())
409 setp(out().begin(), out().end());
414 //----------------------------------------------------------------------------//
416 } } } // End namespaces detail, iostreams, boost.
418 #include <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC, BCC 5.x
420 #endif // #ifndef BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED