File indexing completed on 2025-01-18 09:38:48
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_IOSTREAMS_DETAIL_RANGE_ADAPTER_HPP_INCLUDED
0009 #define BOOST_IOSTREAMS_DETAIL_RANGE_ADAPTER_HPP_INCLUDED
0010
0011 #if defined(_MSC_VER)
0012 # pragma once
0013 #endif
0014
0015 #include <algorithm> // min.
0016 #include <boost/assert.hpp>
0017 #include <cstddef> // ptrdiff_t.
0018 #include <iosfwd> // streamsize, streamoff.
0019 #include <iterator> // iterator_traits.
0020 #include <boost/iostreams/categories.hpp>
0021 #include <boost/iostreams/detail/error.hpp>
0022 #include <boost/iostreams/positioning.hpp>
0023 #include <boost/mpl/if.hpp>
0024 #include <boost/throw_exception.hpp>
0025 #include <boost/type_traits/is_convertible.hpp>
0026 #include <boost/core/enable_if.hpp>
0027
0028
0029 #include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC.
0030
0031 namespace boost { namespace iostreams { namespace detail {
0032
0033
0034 template<typename Traversal> struct range_adapter_impl;
0035
0036
0037
0038
0039
0040
0041
0042
0043 template<typename Mode, typename Range>
0044 class range_adapter {
0045 private:
0046 typedef typename Range::iterator iterator;
0047 typedef std::iterator_traits<iterator> iter_traits;
0048 typedef typename iter_traits::iterator_category iter_cat;
0049 public:
0050 typedef typename Range::value_type char_type;
0051 struct category : Mode, device_tag { };
0052 typedef typename
0053 mpl::if_<
0054 is_convertible<
0055 iter_cat,
0056 std::random_access_iterator_tag
0057 >,
0058 std::random_access_iterator_tag,
0059 std::forward_iterator_tag
0060 >::type tag;
0061 typedef range_adapter_impl<tag> impl;
0062
0063 explicit range_adapter(const Range& rng);
0064 range_adapter(iterator first, iterator last);
0065 std::streamsize read(char_type* s, std::streamsize n);
0066 std::streamsize write(const char_type* s, std::streamsize n);
0067 std::streampos seek(stream_offset off, BOOST_IOS::seekdir way);
0068 private:
0069 iterator first_, cur_, last_;
0070 };
0071
0072
0073
0074 template<typename Mode, typename Range>
0075 range_adapter<Mode, Range>::range_adapter(const Range& rng)
0076 : first_(rng.begin()), cur_(rng.begin()), last_(rng.end()) { }
0077
0078 template<typename Mode, typename Range>
0079 range_adapter<Mode, Range>::range_adapter(iterator first, iterator last)
0080 : first_(first), cur_(first), last_(last) { }
0081
0082 template<typename Mode, typename Range>
0083 inline std::streamsize range_adapter<Mode, Range>::read
0084 (char_type* s, std::streamsize n)
0085 { return impl::read(cur_, last_, s, n); }
0086
0087 template<typename Mode, typename Range>
0088 inline std::streamsize range_adapter<Mode, Range>::write
0089 (const char_type* s, std::streamsize n)
0090 { return impl::write(cur_, last_, s, n); }
0091
0092
0093 template<typename Mode, typename Range>
0094 std::streampos range_adapter<Mode, Range>::seek
0095 (stream_offset off, BOOST_IOS::seekdir way)
0096 {
0097 impl::seek(first_, cur_, last_, off, way);
0098 return offset_to_position(cur_ - first_);
0099 }
0100
0101
0102
0103 template<>
0104 struct range_adapter_impl<std::forward_iterator_tag> {
0105 template<typename Iter, typename Ch>
0106 static std::streamsize read
0107 (Iter& cur, Iter& last, Ch* s,std::streamsize n)
0108 {
0109 std::streamsize rem = n;
0110 while (cur != last && rem-- > 0) *s++ = *cur++;
0111 return n - rem != 0 ? n - rem : -1;
0112 }
0113
0114 template<typename Iter, typename Ch>
0115 static std::streamsize write
0116 (Iter& cur, Iter& last, const Ch* s, std::streamsize n)
0117 {
0118 while (cur != last && n-- > 0) *cur++ = *s++;
0119 if (cur == last && n > 0)
0120 boost::throw_exception(write_area_exhausted());
0121 return n;
0122 }
0123 };
0124
0125 template<>
0126 struct range_adapter_impl<std::random_access_iterator_tag> {
0127 template<typename Iter, typename Ch>
0128 static std::streamsize read
0129 (Iter& cur, Iter& last, Ch* s,std::streamsize n)
0130 {
0131 std::streamsize result =
0132 (std::min)(static_cast<std::streamsize>(last - cur), n);
0133 if (result)
0134 std::copy(cur, cur + result, s);
0135 cur += result;
0136 return result != 0 ? result : -1;
0137 }
0138
0139 template<typename Iter, typename Ch>
0140 static std::streamsize write
0141 (Iter& cur, Iter& last, const Ch* s, std::streamsize n)
0142 {
0143 std::streamsize count =
0144 (std::min)(static_cast<std::streamsize>(last - cur), n);
0145 std::copy(s, s + count, cur);
0146 cur += count;
0147 if (count < n)
0148 boost::throw_exception(write_area_exhausted());
0149 return n;
0150 }
0151
0152 template<typename Iter>
0153 static void seek
0154 ( Iter& first, Iter& cur, Iter& last, stream_offset off,
0155 BOOST_IOS::seekdir way )
0156 {
0157 using namespace std;
0158 switch (way) {
0159 case BOOST_IOS::beg:
0160 if (off > last - first || off < 0)
0161 boost::throw_exception(bad_seek());
0162 cur = first + off;
0163 break;
0164 case BOOST_IOS::cur:
0165 {
0166 std::ptrdiff_t newoff = cur - first + off;
0167 if (newoff > last - first || newoff < 0)
0168 boost::throw_exception(bad_seek());
0169 cur += off;
0170 break;
0171 }
0172 case BOOST_IOS::end:
0173 if (last - first + off < 0 || off > 0)
0174 boost::throw_exception(bad_seek());
0175 cur = last + off;
0176 break;
0177 default:
0178 BOOST_ASSERT(0);
0179 }
0180 }
0181 };
0182
0183 } } }
0184
0185 #include <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC.
0186
0187 #endif