source: NonGTP/Boost/boost/iostreams/detail/streambuf/indirect_streambuf.hpp @ 857

Revision 857, 14.5 KB checked in by igarcia, 19 years ago (diff)
Line 
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.
5
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.
9
10#ifndef BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
11#define BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
12
13#include <algorithm>                             // min, max.
14#include <cassert>
15#include <exception>
16#include <typeinfo>
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>
34
35// Must come last.
36#include <boost/iostreams/detail/config/disable_warnings.hpp>  // MSVC, BCC 5.x
37
38namespace boost { namespace iostreams { namespace detail {
39
40//
41// Description: The implementation of basic_streambuf used by chains.
42//
43template<typename T, typename Tr, typename Alloc, typename Mode>
44class indirect_streambuf
45    : public linked_streambuf<BOOST_DEDUCED_TYPENAME char_type_of<T>::type, Tr>
46{
47public:
48    typedef typename char_type_of<T>::type                    char_type;
49    BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr)
50private:
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;
57public:
58    indirect_streambuf();
59
60    void open(const T& t BOOST_IOSTREAMS_PUSH_PARAMS());
61    bool is_open() const;
62    void close();
63    bool auto_close() const;
64    void set_auto_close(bool close);
65    bool strict_sync();
66
67    // Declared in linked_streambuf.
68    T* component() { return &*obj(); }
69protected:
70#if !BOOST_WORKAROUND(__GNUC__, == 2)
71    BOOST_IOSTREAMS_USING_PROTECTED_STREAMBUF_MEMBERS(base_type)
72#endif
73
74    //----------virtual functions---------------------------------------------//
75
76#ifndef BOOST_IOSTREAMS_NO_LOCALE
77    void imbue(const std::locale& loc);
78#endif
79#ifdef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES
80    public:
81#endif
82    int_type underflow();
83    int_type pbackfail(int_type c);
84    int_type overflow(int_type c);
85    int sync();
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);
89
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(); }
95private:
96
97    //----------Accessor functions--------------------------------------------//
98
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; }
108
109    //----------State changing functions--------------------------------------//
110
111    virtual void init_get_area();
112    virtual void init_put_area();
113
114    //----------Utility function----------------------------------------------//
115
116    pos_type seek_impl( stream_offset off, BOOST_IOS::seekdir way,
117                        BOOST_IOS::openmode which );
118    void sync_impl();
119    void close_impl(BOOST_IOS::openmode);
120
121    enum flag_type {
122        f_open             = 1,
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
127    };
128
129    optional<wrapper>           storage_;
130    streambuf_type*             next_;
131    double_object<
132        buffer_type,
133        is_convertible<
134            Mode,
135            two_sequence
136        >
137    >                           buffer_;
138    std::streamsize             pback_size_;
139    int                         flags_;
140};
141
142//--------------Implementation of indirect_streambuf--------------------------//
143
144template<typename T, typename Tr, typename Alloc, typename Mode>
145indirect_streambuf<T, Tr, Alloc, Mode>::indirect_streambuf()
146    : next_(0), pback_size_(0), flags_(f_auto_close) { }
147
148//--------------Implementation of open, is_open and close---------------------//
149
150template<typename T, typename Tr, typename Alloc, typename Mode>
151void indirect_streambuf<T, Tr, Alloc, Mode>::open
152    (const T& t, int buffer_size, int pback_size)
153{
154    using namespace std;
155
156    // Normalize buffer sizes.
157    buffer_size =
158        (buffer_size != -1) ?
159        buffer_size :
160        iostreams::optimal_buffer_size(t);
161    pback_size =
162        (pback_size != -1) ?
163        pback_size :
164        default_pback_buffer_size;
165
166    // Construct input buffer.
167    if (can_read()) {
168        pback_size_ = (std::max)(2, pback_size); // STLPort needs 2.
169        streamsize size =
170            pback_size_ +
171            ( buffer_size ? buffer_size: 1 );
172        in().resize(size);
173        if (!shared_buffer())
174            init_get_area();
175    }
176
177    // Construct output buffer.
178    if (can_write() && !shared_buffer()) {
179        if (buffer_size != 0)
180            out().resize(buffer_size);
181        init_put_area();
182    }
183
184    storage_.reset(wrapper(t));
185    flags_ |= f_open;
186    if (can_write() && buffer_size > 1)
187        flags_ |= f_output_buffered;
188    this->set_true_eof(false);
189}
190
191template<typename T, typename Tr, typename Alloc, typename Mode>
192inline bool indirect_streambuf<T, Tr, Alloc, Mode>::is_open() const
193{ return (flags_ & f_open) != 0; }
194
195template<typename T, typename Tr, typename Alloc, typename Mode>
196void indirect_streambuf<T, Tr, Alloc, Mode>::close()
197{
198    using namespace std;
199    try { close(BOOST_IOS::in); } catch (std::exception&) { }
200    try { close(BOOST_IOS::out); } catch (std::exception&) { }
201    storage_.reset();
202    flags_ = 0;
203}
204
205template<typename T, typename Tr, typename Alloc, typename Mode>
206bool indirect_streambuf<T, Tr, Alloc, Mode>::auto_close() const
207{ return (flags_ & f_auto_close) != 0; }
208
209template<typename T, typename Tr, typename Alloc, typename Mode>
210void indirect_streambuf<T, Tr, Alloc, Mode>::set_auto_close(bool close)
211{ flags_ = (flags_ & ~f_auto_close) | (close ? f_auto_close : 0); }
212
213//--------------Implementation virtual functions------------------------------//
214
215#ifndef BOOST_IOSTREAMS_NO_LOCALE
216template<typename T, typename Tr, typename Alloc, typename Mode>
217void indirect_streambuf<T, Tr, Alloc, Mode>::imbue(const std::locale& loc)
218{
219    if (is_open()) {
220        obj().imbue(loc);
221        if (next_)
222            next_->pubimbue(loc);
223    }
224}
225#endif
226
227template<typename T, typename Tr, typename Alloc, typename Mode>
228typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
229indirect_streambuf<T, Tr, Alloc, Mode>::underflow()
230{
231    using namespace std;
232    if (!gptr()) init_get_area();
233    buffer_type& buf = in();
234    if (gptr() < egptr()) return traits_type::to_int_type(*gptr());
235
236    // Fill putback buffer.
237    streamsize keep = (std::min)( static_cast<streamsize>(gptr() - eback()),
238                                  pback_size_ );
239    if (keep)
240        traits_type::move( buf.data() + (pback_size_ - keep),
241                           gptr() - keep, keep );
242
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_ );
247
248    // Read from source.
249    streamsize chars =
250        obj().read(buf.data() + pback_size_, buf.size() - pback_size_, next_);
251    if (chars == -1) {
252        this->set_true_eof(true);
253        chars = 0;
254    }
255    setg(eback(), gptr(), buf.data() + pback_size_ + chars);
256    return chars != 0 ?
257        traits_type::to_int_type(*gptr()) :
258        traits_type::eof();
259}
260
261template<typename T, typename Tr, typename Alloc, typename Mode>
262typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
263indirect_streambuf<T, Tr, Alloc, Mode>::pbackfail(int_type c)
264{
265    if (gptr() != eback()) {
266        gbump(-1);
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);
270    } else {
271        throw bad_putback();
272    }
273}
274
275template<typename T, typename Tr, typename Alloc, typename Mode>
276typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
277indirect_streambuf<T, Tr, Alloc, Mode>::overflow(int_type c)
278{
279    if ( output_buffered() && pptr() == 0 ||
280         shared_buffer() && gptr() != 0 )
281    {
282        init_put_area();
283    }
284    if (!traits_type::eq_int_type(c, traits_type::eof())) {
285        if (output_buffered()) {
286            if (pptr() == epptr()) {
287                sync_impl();
288                if (pptr() == epptr())
289                    return traits_type::eof();
290            }
291            *pptr() = traits_type::to_char_type(c);
292            pbump(1);
293        } else {
294            char_type d = traits_type::to_char_type(c);
295            if (obj().write(&d, 1, next_) != 1)
296                return traits_type::eof();
297        }
298    }
299    return traits_type::not_eof(c);
300}
301
302template<typename T, typename Tr, typename Alloc, typename Mode>
303int indirect_streambuf<T, Tr, Alloc, Mode>::sync()
304{
305    try { // sync() is no-throw.
306        sync_impl();
307        obj().flush(next_);
308        return 0;
309    } catch (std::exception&) { return -1; }
310}
311
312template<typename T, typename Tr, typename Alloc, typename Mode>
313bool indirect_streambuf<T, Tr, Alloc, Mode>::strict_sync()
314{
315    try { // sync() is no-throw.
316        sync_impl();
317        return obj().flush(next_);
318    } catch (std::exception&) { return false; }
319}
320
321template<typename T, typename Tr, typename Alloc, typename Mode>
322inline typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
323indirect_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); }
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>::seekpos
330    (pos_type sp, BOOST_IOS::openmode)
331{
332    return seek_impl( position_to_offset(sp), BOOST_IOS::beg,
333                      BOOST_IOS::in | BOOST_IOS::out );
334}
335
336template<typename T, typename Tr, typename Alloc, typename Mode>
337typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
338indirect_streambuf<T, Tr, Alloc, Mode>::seek_impl
339    (stream_offset off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which)
340{
341    if (pptr() != 0)
342        this->BOOST_IOSTREAMS_PUBSYNC(); // sync() confuses VisualAge 6.
343    if (way == BOOST_IOS::cur && gptr())
344        off -= static_cast<off_type>(egptr() - gptr());
345    setg(0, 0, 0);
346    setp(0, 0);
347    return obj().seek(off, way, which, next_);
348}
349
350template<typename T, typename Tr, typename Alloc, typename Mode>
351inline void indirect_streambuf<T, Tr, Alloc, Mode>::set_next
352    (streambuf_type* next)
353{ next_ = next; }
354
355template<typename T, typename Tr, typename Alloc, typename Mode>
356inline void indirect_streambuf<T, Tr, Alloc, Mode>::close
357    (BOOST_IOS::openmode which)
358{
359    close_impl(which);
360    try { obj().close(which, next_); } catch (std::exception&) { }
361}
362
363//----------State changing functions------------------------------------------//
364
365template<typename T, typename Tr, typename Alloc, typename Mode>
366inline void indirect_streambuf<T, Tr, Alloc, Mode>::close_impl
367    (BOOST_IOS::openmode which)
368{
369    if (which == BOOST_IOS::in && (flags_ & f_input_closed) == 0) {
370        setg(0, 0, 0);
371        flags_ |= f_input_closed;
372    }
373    if (which == BOOST_IOS::out && (flags_ & f_output_closed) == 0) {
374        sync();
375        setp(0, 0);
376        flags_ |= f_output_closed;
377    }
378}
379
380template<typename T, typename Tr, typename Alloc, typename Mode>
381void indirect_streambuf<T, Tr, Alloc, Mode>::sync_impl()
382{
383    std::streamsize avail, amt;
384    if ((avail = static_cast<std::streamsize>(pptr() - pbase())) > 0) {
385        if ((amt = obj().write(pbase(), avail, next())) == avail)
386            setp(out().begin(), out().end());
387        else {
388            const char_type* ptr = pptr();
389            setp(out().begin() + amt, out().end());
390            pbump(ptr - pptr());
391        }
392    }
393}
394
395template<typename T, typename Tr, typename Alloc, typename Mode>
396void indirect_streambuf<T, Tr, Alloc, Mode>::init_get_area()
397{
398    if (shared_buffer() && pptr() != 0) {
399        sync_impl();
400        setp(0, 0);
401    }
402    setg(in().begin(), in().begin(), in().begin());
403}
404
405template<typename T, typename Tr, typename Alloc, typename Mode>
406void indirect_streambuf<T, Tr, Alloc, Mode>::init_put_area()
407{
408    using namespace std;
409    if (shared_buffer() && gptr() != 0)
410        setg(0, 0, 0);
411    if (output_buffered())
412        setp(out().begin(), out().end());
413    else
414        setp(0, 0);
415}
416
417//----------------------------------------------------------------------------//
418
419} } } // End namespaces detail, iostreams, boost.
420
421#include <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC, BCC 5.x
422
423#endif // #ifndef BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
Note: See TracBrowser for help on using the repository browser.