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.)
6 // See http://www.boost.org/libs/iostreams for documentation.
8 #ifndef BOOST_IOSTREAMS_DETAIL_DIRECT_ADAPTER_HPP_INCLUDED
9 #define BOOST_IOSTREAMS_DETAIL_DIRECT_ADAPTER_HPP_INCLUDED
11 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
15 #include <boost/config.hpp> // SFINAE, MSVC, put ptrdiff_t in std.
16 #include <algorithm> // copy, min.
17 #include <cstddef> // ptrdiff_t.
18 #include <boost/detail/workaround.hpp>
19 #include <boost/iostreams/categories.hpp>
20 #include <boost/iostreams/detail/config/limits.hpp> // forwarding.
21 #include <boost/iostreams/detail/config/wide_streams.hpp> // locale.
22 #include <boost/iostreams/detail/double_object.hpp>
23 #include <boost/iostreams/detail/error.hpp>
24 #include <boost/iostreams/detail/ios.hpp> // openmode, seekdir, int types.
25 #include <boost/iostreams/traits.hpp> // mode_of, is_direct.
26 #include <boost/iostreams/operations.hpp>
27 #include <boost/mpl/bool.hpp>
28 #include <boost/mpl/or.hpp>
29 #include <boost/preprocessor/iteration/local.hpp>
30 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
31 #include <boost/preprocessor/repetition/enum_params.hpp>
32 #include <boost/static_assert.hpp>
33 #include <boost/type_traits/is_convertible.hpp>
36 #include <boost/iostreams/detail/config/disable_warnings.hpp> // VC7.1
38 namespace boost
{ namespace iostreams
{ namespace detail
{
40 //------------------Definition of direct_adapter_base-------------------------//
42 // Put all initialization in base class to faciliate forwarding.
43 template<typename Direct
>
44 class direct_adapter_base
{
46 typedef typename char_type_of
<Direct
>::type char_type
;
47 typedef typename mode_of
<Direct
>::type mode_type
;
52 #ifndef BOOST_IOSTREAMS_NO_LOCALE
57 explicit direct_adapter_base(const Direct
& d
);
58 typedef is_convertible
<category
, two_sequence
> is_double
;
60 char_type
*beg
, *ptr
, *end
;
62 void init_input(mpl::true_
);
63 void init_input(mpl::false_
) { }
64 void init_output(mpl::true_
);
65 void init_output(mpl::false_
) { }
66 double_object
<pointers
, is_double
> ptrs_
;
70 template<typename Direct
>
71 class direct_adapter
: private direct_adapter_base
<Direct
> {
73 typedef direct_adapter_base
<Direct
> base_type
;
74 typedef typename
base_type::pointers pointers
;
75 typedef typename
base_type::is_double is_double
;
76 using base_type::ptrs_
;
79 typedef typename
base_type::char_type char_type
;
80 typedef typename
base_type::category category
;
84 #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
85 direct_adapter(const Direct
& d
) : base_type(d
) { }
86 direct_adapter(const direct_adapter
& d
) : base_type(d
) { }
87 # define BOOST_PP_LOCAL_LIMITS (1, BOOST_IOSTREAMS_MAX_FORWARDING_ARITY)
92 is_same
<U
, direct_adapter
<Direct
> >,
97 direct_adapter(const U
& u
)
98 : base_type(forward(u
, is_direct
<U
>()))
100 # define BOOST_PP_LOCAL_LIMITS (2, BOOST_IOSTREAMS_MAX_FORWARDING_ARITY)
103 #define BOOST_PP_LOCAL_MACRO(n) \
104 template<BOOST_PP_ENUM_PARAMS(n, typename P)> \
105 direct_adapter(BOOST_PP_ENUM_BINARY_PARAMS(n, const P, &p)) \
106 : base_type(Direct(BOOST_PP_ENUM_PARAMS(n, p))) \
109 #include BOOST_PP_LOCAL_ITERATE()
110 #undef BOOST_PP_LOCAL_MACRO
114 std::streamsize
read(char_type
* s
, std::streamsize n
);
115 std::streamsize
write(const char_type
* s
, std::streamsize n
);
116 std::streampos
seek( stream_offset
, BOOST_IOS::seekdir
,
117 BOOST_IOS::openmode
= BOOST_IOS::in
| BOOST_IOS::out
);
119 void close(BOOST_IOS::openmode which
);
120 #ifndef BOOST_IOSTREAMS_NO_LOCALE
121 void imbue(const std::locale
&);
124 // Direct device access.
126 Direct
& operator*() { return d_
; }
127 Direct
* operator->() { return &d_
; }
128 #if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
131 static Direct
forward(const U
& u
, mpl::true_
) { return u
; }
133 static Direct
forward(const U
& u
, mpl::false_
) { return Direct(u
); }
137 //--------------Definition of wrap_direct and unwrap_direct-------------------//
139 template<typename Device
>
140 struct wrap_direct_traits
143 direct_adapter
<Device
>,
148 template<typename Device
>
149 typename wrap_direct_traits
<Device
>::type
150 inline wrap_direct(Device dev
)
152 typedef typename wrap_direct_traits
<Device
>::type type
;
156 template<typename Device
>
157 inline Device
& unwrap_direct(Device
& d
) { return d
; }
159 template<typename Device
>
160 inline Device
& unwrap_direct(direct_adapter
<Device
>& d
) { return *d
; }
162 //--------------Implementation of direct_adapter_base-------------------------//
164 template<typename Direct
>
165 direct_adapter_base
<Direct
>::direct_adapter_base(const Direct
& d
) : d_(d
)
167 init_input(is_convertible
<category
, input
>());
168 init_output(is_convertible
<category
, output
>());
171 template<typename Direct
>
172 void direct_adapter_base
<Direct
>::init_input(mpl::true_
)
174 std::pair
<char_type
*, char_type
*> seq
= iostreams::input_sequence(d_
);
175 ptrs_
.first().beg
= seq
.first
;
176 ptrs_
.first().ptr
= seq
.first
;
177 ptrs_
.first().end
= seq
.second
;
180 template<typename Direct
>
181 void direct_adapter_base
<Direct
>::init_output(mpl::true_
)
183 std::pair
<char_type
*, char_type
*> seq
= iostreams::output_sequence(d_
);
184 ptrs_
.second().beg
= seq
.first
;
185 ptrs_
.second().ptr
= seq
.first
;
186 ptrs_
.second().end
= seq
.second
;
189 //--------------Implementation of direct_adapter------------------------------//
191 template<typename Direct
>
192 inline std::streamsize direct_adapter
<Direct
>::read
193 (char_type
* s
, std::streamsize n
)
196 pointers
& get
= ptrs_
.first();
197 std::streamsize avail
=
198 static_cast<std::streamsize
>(get
.end
- get
.ptr
);
199 std::streamsize result
= (std::min
)(n
, avail
);
200 std::copy(get
.ptr
, get
.ptr
+ result
, s
);
202 return result
!= 0 ? result
: -1;
205 template<typename Direct
>
206 inline std::streamsize direct_adapter
<Direct
>::write
207 (const char_type
* s
, std::streamsize n
)
210 pointers
& put
= ptrs_
.second();
211 if (n
> static_cast<std::streamsize
>(put
.end
- put
.ptr
))
212 throw write_area_exhausted();
213 std::copy(s
, s
+ n
, put
.ptr
);
218 template<typename Direct
>
219 inline std::streampos direct_adapter
<Direct
>::seek
220 ( stream_offset off
, BOOST_IOS::seekdir way
,
221 BOOST_IOS::openmode which
)
224 pointers
& get
= ptrs_
.first();
225 pointers
& put
= ptrs_
.second();
226 if (way
== BOOST_IOS::cur
&& get
.ptr
!= put
.ptr
)
229 if ((which
& BOOST_IOS::in
) || !is_double::value
) {
230 if (way
== BOOST_IOS::beg
)
232 else if (way
== BOOST_IOS::cur
)
233 next
= get
.ptr
- get
.beg
+ off
;
235 next
= get
.end
- get
.beg
+ off
;
236 if (next
>= 0 && next
<= get
.end
- get
.beg
)
237 get
.ptr
= get
.beg
+ next
;
241 if ((which
& BOOST_IOS::out
) && is_double::value
) {
242 if (way
== BOOST_IOS::beg
)
244 else if (way
== BOOST_IOS::cur
)
245 next
= put
.ptr
- put
.beg
+ off
;
247 next
= put
.end
- put
.beg
+ off
;
248 if (next
>= 0 && next
<= put
.end
- put
.beg
)
249 put
.ptr
= put
.beg
+ next
;
253 return offset_to_position(next
);
256 template<typename Direct
>
257 void direct_adapter
<Direct
>::close()
259 BOOST_STATIC_ASSERT((!is_convertible
<category
, two_sequence
>::value
));
260 detail::close_all(d_
);
263 template<typename Direct
>
264 void direct_adapter
<Direct
>::close(BOOST_IOS::openmode which
)
266 BOOST_STATIC_ASSERT((is_convertible
<category
, two_sequence
>::value
));
267 boost::iostreams::close(d_
, which
);
270 #ifndef BOOST_IOSTREAMS_NO_LOCALE
271 template<typename Direct
>
272 void direct_adapter
<Direct
>::imbue(const std::locale
& loc
)
273 { boost::iostreams::imbue(d_
, loc
); }
276 } } } // End namespaces detail, iostreams, boost.
278 #include <boost/iostreams/detail/config/enable_warnings.hpp>
280 #endif // #ifndef BOOST_IOSTREAMS_DETAIL_DIRECT_ADAPTER_HPP_INCLUDED