source: NonGTP/Boost/boost/iostreams/detail/adapter/direct_adapter.hpp @ 857

Revision 857, 9.0 KB checked in by igarcia, 18 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
5// See http://www.boost.org/libs/iostreams for documentation.
6
7#ifndef BOOST_IOSTREAMS_DETAIL_DIRECT_ADAPTER_HPP_INCLUDED
8#define BOOST_IOSTREAMS_DETAIL_DIRECT_ADAPTER_HPP_INCLUDED
9
10#if defined(_MSC_VER) && (_MSC_VER >= 1020)
11# pragma once
12#endif             
13
14#include <boost/config.hpp>       // SFINAE, MSVC, put ptrdiff_t in std.
15#include <algorithm>              // copy, min.
16#include <cstddef>                // ptrdiff_t.
17#include <boost/detail/workaround.hpp>
18#include <boost/iostreams/categories.hpp>
19#include <boost/iostreams/detail/config/limits.hpp>        // forwarding.
20#include <boost/iostreams/detail/config/wide_streams.hpp>  // locale.
21#include <boost/iostreams/detail/double_object.hpp>
22#include <boost/iostreams/detail/error.hpp>
23#include <boost/iostreams/detail/ios.hpp>  // openmode, seekdir, int types.
24#include <boost/iostreams/traits.hpp>      // mode_of, is_direct.
25#include <boost/iostreams/operations.hpp>
26#include <boost/mpl/bool.hpp>
27#include <boost/mpl/or.hpp>
28#include <boost/preprocessor/iteration/local.hpp>
29#include <boost/preprocessor/repetition/enum_binary_params.hpp>
30#include <boost/preprocessor/repetition/enum_params.hpp>
31#include <boost/static_assert.hpp>
32#include <boost/type_traits/is_convertible.hpp>
33
34// Must come last.
35#include <boost/iostreams/detail/config/disable_warnings.hpp> // VC7.1
36
37namespace boost { namespace iostreams { namespace detail {
38                   
39//------------------Definition of direct_adapter_base-------------------------//
40
41// Put all initialization in base class to faciliate forwarding.
42template<typename Direct>
43class direct_adapter_base {
44public:
45    typedef typename char_type_of<Direct>::type char_type;
46    struct category
47        : mode_of<Direct>::type,
48          device_tag,
49          closable_tag
50          #ifndef BOOST_IOSTREAMS_NO_LOCALE
51          , localizable_tag
52          #endif
53        { };
54protected:
55    explicit direct_adapter_base(const Direct& d);
56    typedef is_convertible<category, two_sequence> is_double;
57    struct pointers {
58        char_type *beg, *ptr, *end;
59    };
60    void init_input(mpl::true_);
61    void init_input(mpl::false_) { }
62    void init_output(mpl::true_);
63    void init_output(mpl::false_) { }
64    double_object<pointers, is_double>  ptrs_;
65    Direct                              d_;
66};
67
68template<typename Direct>
69class direct_adapter : private direct_adapter_base<Direct> {
70private:
71    typedef direct_adapter_base<Direct>      base_type;
72    typedef typename base_type::pointers     pointers;
73    typedef typename base_type::is_double    is_double;
74    using base_type::ptrs_;
75    using base_type::d_;
76public:
77    typedef typename base_type::char_type    char_type;
78    typedef typename base_type::category     category;
79
80        // Constructors
81
82#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
83    direct_adapter(const Direct& d) : base_type(d) { }   
84    direct_adapter(const direct_adapter& d) : base_type(d) { }
85# define BOOST_PP_LOCAL_LIMITS (1, BOOST_IOSTREAMS_MAX_FORWARDING_ARITY)
86#else
87    template<typename U>
88    struct is_direct
89        : mpl::or_<
90              is_same<U, direct_adapter<Direct> >,
91              is_same<U, Direct>
92          >
93        { };
94    template<typename U>
95    direct_adapter(const U& u)
96        : base_type(forward(u, is_direct<U>()))
97        { }
98# define BOOST_PP_LOCAL_LIMITS (2, BOOST_IOSTREAMS_MAX_FORWARDING_ARITY)
99#endif
100
101#define BOOST_PP_LOCAL_MACRO(n) \
102    template<BOOST_PP_ENUM_PARAMS(n, typename P)> \
103    direct_adapter(BOOST_PP_ENUM_BINARY_PARAMS(n, const P, &p)) \
104        : base_type(Direct(BOOST_PP_ENUM_PARAMS(n, p))) \
105        { } \
106    /**/
107#include BOOST_PP_LOCAL_ITERATE()
108#undef BOOST_PP_LOCAL_MACRO
109
110        // Device interface.
111
112    std::streamsize read(char_type* s, std::streamsize n);
113    std::streamsize write(const char_type* s, std::streamsize n);
114    std::streampos seek( stream_offset, BOOST_IOS::seekdir,
115                         BOOST_IOS::openmode = BOOST_IOS::in | BOOST_IOS::out );
116    void close();
117    void close(BOOST_IOS::openmode which);
118#ifndef BOOST_IOSTREAMS_NO_LOCALE
119    void imbue(const std::locale&);
120#endif
121
122        // Direct device access.
123
124    Direct& operator*() { return d_; }
125    Direct* operator->() { return &d_; }
126#if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
127private:
128    template<typename U>
129    static Direct forward(const U& u, mpl::true_) { return u; }
130    template<typename U>
131    static Direct forward(const U& u, mpl::false_) { return Direct(u); }
132#endif
133};
134
135//--------------Definition of wrap_direct and unwrap_direct-------------------//
136
137template<typename Device>
138struct wrap_direct_traits
139    : mpl::if_<
140          is_direct<Device>,
141          direct_adapter<Device>,
142          Device
143      >
144    { };
145
146template<typename Device>
147typename wrap_direct_traits<Device>::type
148inline wrap_direct(Device dev)
149{
150    typedef typename wrap_direct_traits<Device>::type type;
151    return type(dev);
152}
153
154template<typename Device>
155inline Device& unwrap_direct(Device& d) { return d; } 
156
157template<typename Device>
158inline Device& unwrap_direct(direct_adapter<Device>& d) { return *d; } 
159
160//--------------Implementation of direct_adapter_base-------------------------//
161
162template<typename Direct>
163direct_adapter_base<Direct>::direct_adapter_base(const Direct& d) : d_(d)
164{
165    init_input(is_convertible<category, input>());
166    init_output(is_convertible<category, output>());
167}
168
169template<typename Direct>
170void direct_adapter_base<Direct>::init_input(mpl::true_)
171{
172    std::pair<char_type*, char_type*> seq = iostreams::input_sequence(d_);
173    ptrs_.first().beg = seq.first;
174    ptrs_.first().ptr = seq.first;
175    ptrs_.first().end = seq.second;
176}
177
178template<typename Direct>
179void direct_adapter_base<Direct>::init_output(mpl::true_)
180{
181    std::pair<char_type*, char_type*> seq = iostreams::output_sequence(d_);
182    ptrs_.second().beg = seq.first;
183    ptrs_.second().ptr = seq.first;
184    ptrs_.second().end = seq.second;
185}
186
187//--------------Implementation of direct_adapter------------------------------//
188
189template<typename Direct>
190inline std::streamsize direct_adapter<Direct>::read
191    (char_type* s, std::streamsize n)
192{
193    using namespace std;
194    pointers& get = ptrs_.first();
195    streamsize avail =
196        static_cast<streamsize>(get.end - get.ptr);
197    streamsize result = (std::min)(n, avail);
198    std::copy(get.ptr, get.ptr + result, s);
199    get.ptr += result;
200    return result != 0 ? result : -1;
201}
202
203template<typename Direct>
204inline std::streamsize direct_adapter<Direct>::write
205    (const char_type* s, std::streamsize n)
206{
207    using namespace std;
208    pointers& put = ptrs_.second();
209    if (n > static_cast<streamsize>(put.end - put.ptr))
210        throw write_area_exhausted();
211    std::copy(s, s + n, put.ptr);
212    put.ptr += n;
213    return n;
214}
215
216template<typename Direct>
217inline std::streampos direct_adapter<Direct>::seek
218    ( stream_offset off, BOOST_IOS::seekdir way,
219      BOOST_IOS::openmode which )
220{
221    using namespace std;
222    pointers& get = ptrs_.first();
223    pointers& put = ptrs_.second();
224    if (way == BOOST_IOS::cur && get.ptr != put.ptr)
225       bad_seek();
226    ptrdiff_t next = 0;
227    if ((which & BOOST_IOS::in) || !is_double::value) {
228        if (way == BOOST_IOS::beg)
229            next = off;
230        else if (way == BOOST_IOS::cur)
231            next = get.ptr - get.beg + off;
232        else
233            next = get.end - get.beg + off;
234        if (next >= 0 && next < get.end - get.beg)
235            get.ptr = get.beg + next;
236        else
237            bad_seek();
238    }
239    if ((which & BOOST_IOS::out) && is_double::value) {
240        if (way == BOOST_IOS::beg)
241            next = off;
242        else if (way == BOOST_IOS::cur)
243            next = put.ptr - put.beg + off;
244        else
245            next = put.end - put.beg + off;
246        if (next >= 0 && next < put.end - put.beg)
247            put.ptr = put.beg + next;
248        else
249            bad_seek();
250    }
251    return offset_to_position(next);
252}
253
254template<typename Direct>
255void direct_adapter<Direct>::close()
256{
257    BOOST_STATIC_ASSERT((!is_convertible<category, two_sequence>::value));
258    boost::iostreams::close(d_, BOOST_IOS::in | BOOST_IOS::out);
259}
260
261template<typename Direct>
262void direct_adapter<Direct>::close(BOOST_IOS::openmode which)
263{
264    BOOST_STATIC_ASSERT((is_convertible<category, two_sequence>::value));
265    boost::iostreams::close(d_, which);
266}
267
268#ifndef BOOST_IOSTREAMS_NO_LOCALE
269    template<typename Direct>
270    void direct_adapter<Direct>::imbue(const std::locale& loc)
271    { boost::iostreams::imbue(d_, loc); }
272#endif
273
274} } } // End namespaces detail, iostreams, boost.
275
276#include <boost/iostreams/detail/config/enable_warnings.hpp>
277
278#endif // #ifndef BOOST_IOSTREAMS_DETAIL_DIRECT_ADAPTER_HPP_INCLUDED
Note: See TracBrowser for help on using the repository browser.