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

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