]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
6 | // See http://www.boost.org/libs/iostreams for documentation. | |
7 | ||
8 | #ifndef BOOST_IOSTREAMS_DETAIL_RANGE_ADAPTER_HPP_INCLUDED | |
9 | #define BOOST_IOSTREAMS_DETAIL_RANGE_ADAPTER_HPP_INCLUDED | |
10 | ||
11 | #if defined(_MSC_VER) | |
12 | # pragma once | |
13 | #endif | |
14 | ||
15 | #include <algorithm> // min. | |
16 | #include <boost/assert.hpp> | |
17 | #include <cstddef> // ptrdiff_t. | |
18 | #include <iosfwd> // streamsize, streamoff. | |
19 | #include <boost/detail/iterator.hpp> // boost::iterator_traits. | |
20 | #include <boost/iostreams/categories.hpp> | |
21 | #include <boost/iostreams/detail/error.hpp> | |
22 | #include <boost/iostreams/positioning.hpp> | |
23 | #include <boost/mpl/if.hpp> | |
24 | #include <boost/throw_exception.hpp> | |
25 | #include <boost/type_traits/is_convertible.hpp> | |
26 | #include <boost/utility/enable_if.hpp> | |
27 | ||
28 | // Must come last. | |
29 | #include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC. | |
30 | ||
31 | namespace boost { namespace iostreams { namespace detail { | |
32 | ||
33 | // Used for simulated tag dispatch. | |
34 | template<typename Traversal> struct range_adapter_impl; | |
35 | ||
36 | // | |
37 | // Template name: range_adapter | |
38 | // Description: Device based on an instance of boost::iterator_range. | |
39 | // Template parameters: | |
40 | // Mode - A mode tag. | |
41 | // Range - An instance of iterator_range. | |
42 | // | |
43 | template<typename Mode, typename Range> | |
44 | class range_adapter { | |
45 | private: | |
46 | typedef typename Range::iterator iterator; | |
47 | typedef boost::detail::iterator_traits<iterator> iter_traits; | |
48 | typedef typename iter_traits::iterator_category iter_cat; | |
49 | public: | |
50 | typedef typename Range::value_type char_type; | |
51 | struct category : Mode, device_tag { }; | |
52 | typedef typename | |
53 | mpl::if_< | |
54 | is_convertible< | |
55 | iter_cat, | |
56 | std::random_access_iterator_tag | |
57 | >, | |
58 | std::random_access_iterator_tag, | |
59 | std::forward_iterator_tag | |
60 | >::type tag; | |
61 | typedef range_adapter_impl<tag> impl; | |
62 | ||
63 | explicit range_adapter(const Range& rng); | |
64 | range_adapter(iterator first, iterator last); | |
65 | std::streamsize read(char_type* s, std::streamsize n); | |
66 | std::streamsize write(const char_type* s, std::streamsize n); | |
67 | std::streampos seek(stream_offset off, BOOST_IOS::seekdir way); | |
68 | private: | |
69 | iterator first_, cur_, last_; | |
70 | }; | |
71 | ||
72 | //------------------Implementation of range_adapter---------------------------// | |
73 | ||
74 | template<typename Mode, typename Range> | |
75 | range_adapter<Mode, Range>::range_adapter(const Range& rng) | |
76 | : first_(rng.begin()), cur_(rng.begin()), last_(rng.end()) { } | |
77 | ||
78 | template<typename Mode, typename Range> | |
79 | range_adapter<Mode, Range>::range_adapter(iterator first, iterator last) | |
80 | : first_(first), cur_(first), last_(last) { } | |
81 | ||
82 | template<typename Mode, typename Range> | |
83 | inline std::streamsize range_adapter<Mode, Range>::read | |
84 | (char_type* s, std::streamsize n) | |
85 | { return impl::read(cur_, last_, s, n); } | |
86 | ||
87 | template<typename Mode, typename Range> | |
88 | inline std::streamsize range_adapter<Mode, Range>::write | |
89 | (const char_type* s, std::streamsize n) | |
90 | { return impl::write(cur_, last_, s, n); } | |
91 | ||
92 | ||
93 | template<typename Mode, typename Range> | |
94 | std::streampos range_adapter<Mode, Range>::seek | |
95 | (stream_offset off, BOOST_IOS::seekdir way) | |
96 | { | |
97 | impl::seek(first_, cur_, last_, off, way); | |
98 | return offset_to_position(cur_ - first_); | |
99 | } | |
100 | ||
101 | //------------------Implementation of range_adapter_impl----------------------// | |
102 | ||
103 | template<> | |
104 | struct range_adapter_impl<std::forward_iterator_tag> { | |
105 | template<typename Iter, typename Ch> | |
106 | static std::streamsize read | |
107 | (Iter& cur, Iter& last, Ch* s,std::streamsize n) | |
108 | { | |
109 | std::streamsize rem = n; // No. of chars remaining. | |
110 | while (cur != last && rem-- > 0) *s++ = *cur++; | |
111 | return n - rem != 0 ? n - rem : -1; | |
112 | } | |
113 | ||
114 | template<typename Iter, typename Ch> | |
115 | static std::streamsize write | |
116 | (Iter& cur, Iter& last, const Ch* s, std::streamsize n) | |
117 | { | |
118 | while (cur != last && n-- > 0) *cur++ = *s++; | |
119 | if (cur == last && n > 0) | |
120 | boost::throw_exception(write_area_exhausted()); | |
121 | return n; | |
122 | } | |
123 | }; | |
124 | ||
125 | template<> | |
126 | struct range_adapter_impl<std::random_access_iterator_tag> { | |
127 | template<typename Iter, typename Ch> | |
128 | static std::streamsize read | |
129 | (Iter& cur, Iter& last, Ch* s,std::streamsize n) | |
130 | { | |
131 | std::streamsize result = | |
132 | (std::min)(static_cast<std::streamsize>(last - cur), n); | |
133 | if (result) | |
134 | std::copy(cur, cur + result, s); | |
135 | cur += result; | |
136 | return result != 0 ? result : -1; | |
137 | } | |
138 | ||
139 | template<typename Iter, typename Ch> | |
140 | static std::streamsize write | |
141 | (Iter& cur, Iter& last, const Ch* s, std::streamsize n) | |
142 | { | |
143 | std::streamsize count = | |
144 | (std::min)(static_cast<std::streamsize>(last - cur), n); | |
145 | std::copy(s, s + count, cur); | |
146 | cur += count; | |
147 | if (count < n) | |
148 | boost::throw_exception(write_area_exhausted()); | |
149 | return n; | |
150 | } | |
151 | ||
152 | template<typename Iter> | |
153 | static void seek | |
154 | ( Iter& first, Iter& cur, Iter& last, stream_offset off, | |
155 | BOOST_IOS::seekdir way ) | |
156 | { | |
157 | using namespace std; | |
158 | switch (way) { | |
159 | case BOOST_IOS::beg: | |
160 | if (off > last - first || off < 0) | |
161 | boost::throw_exception(bad_seek()); | |
162 | cur = first + off; | |
163 | break; | |
164 | case BOOST_IOS::cur: | |
165 | { | |
166 | std::ptrdiff_t newoff = cur - first + off; | |
167 | if (newoff > last - first || newoff < 0) | |
168 | boost::throw_exception(bad_seek()); | |
169 | cur += off; | |
170 | break; | |
171 | } | |
172 | case BOOST_IOS::end: | |
173 | if (last - first + off < 0 || off > 0) | |
174 | boost::throw_exception(bad_seek()); | |
175 | cur = last + off; | |
176 | break; | |
177 | default: | |
178 | BOOST_ASSERT(0); | |
179 | } | |
180 | } | |
181 | }; | |
182 | ||
183 | } } } // End namespaces detail, iostreams, boost. | |
184 | ||
185 | #include <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC. | |
186 | ||
187 | #endif // #ifndef BOOST_IOSTREAMS_DETAIL_RANGE_ADAPTER_HPP_INCLUDED //---------------// |