source: NonGTP/Boost/boost/iostreams/restrict.hpp @ 857

Revision 857, 14.3 KB checked in by igarcia, 18 years ago (diff)
Line 
1// (C) Copyright Jonathan Turkanis 2005.
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_RESTRICT_HPP_INCLUDED
8#define BOOST_IOSTREAMS_RESTRICT_HPP_INCLUDED
9
10#if defined(_MSC_VER) && (_MSC_VER >= 1020)
11# pragma once
12#endif
13
14#include <algorithm>          // min.
15#include <utility>            // pair.
16#include <boost/cstdint.hpp>  // intmax_t.
17#include <boost/config.hpp>   // DEDUCED_TYPENAME.
18#include <boost/iostreams/categories.hpp>
19#include <boost/iostreams/char_traits.hpp>
20#include <boost/iostreams/detail/adapter/basic_adapter.hpp>
21#include <boost/iostreams/detail/call_traits.hpp>
22#include <boost/iostreams/detail/enable_if_stream.hpp>
23#include <boost/iostreams/detail/error.hpp>
24#include <boost/iostreams/detail/ios.hpp>     // failure.
25#include <boost/iostreams/detail/select.hpp>
26#include <boost/iostreams/operations.hpp>
27#include <boost/iostreams/skip.hpp>
28#include <boost/iostreams/traits.hpp>         // mode_of, is_direct.
29#include <boost/mpl/bool.hpp>
30#include <boost/static_assert.hpp>
31#include <boost/type_traits/is_convertible.hpp>
32
33#include <boost/iostreams/detail/config/disable_warnings.hpp> // VC7.1 C4244.
34
35namespace boost { namespace iostreams {
36
37namespace detail {
38
39//
40// Template name: restricted_indirect_device.
41// Description: Provides an restricted view of an indirect Device.
42// Template paramters:
43//      Device - An indirect model of Device that models either Source or
44//          SeekableDevice.
45//
46template<typename Device>
47class restricted_indirect_device : public basic_adapter<Device> {
48private:
49    typedef typename detail::param_type<Device>::type  param_type;
50public:
51    typedef typename char_type_of<Device>::type        char_type;
52    struct category
53        : mode_of<Device>::type,
54          device_tag,
55          closable_tag,
56          flushable_tag,
57          localizable_tag,
58          optimally_buffered_tag
59        { };
60    restricted_indirect_device( param_type dev, stream_offset off,
61                                stream_offset len = -1 );
62    std::streamsize read(char_type* s, std::streamsize n);
63    std::streamsize write(const char_type* s, std::streamsize n);
64    std::streampos seek(stream_offset off, BOOST_IOS::seekdir way);
65private:
66    stream_offset beg_, pos_, end_;
67};
68
69//
70// Template name: restricted_direct_device.
71// Description: Provides an restricted view of a Direct Device.
72// Template paramters:
73//      Device - A model of Direct and Device.
74//
75template<typename Device>
76class restricted_direct_device : public basic_adapter<Device> {
77public:
78    typedef typename char_type_of<Device>::type  char_type;
79    typedef std::pair<char_type*, char_type*>    pair_type;
80    struct category
81        : mode_of<Device>::type,
82          device_tag,
83          direct_tag,
84          closable_tag,
85          localizable_tag
86        { };
87    restricted_direct_device( const Device& dev, stream_offset off,
88                              stream_offset len = -1 );
89    pair_type input_sequence();
90    pair_type output_sequence();
91private:
92    pair_type sequence(mpl::true_);
93    pair_type sequence(mpl::false_);
94    char_type *beg_, *end_;
95};
96
97//
98// Template name: restricted_filter.
99// Description: Provides an restricted view of a Filter.
100// Template paramters:
101//      Filter - An indirect model of Filter.
102//
103template<typename Filter>
104class restricted_filter : public basic_adapter<Filter> {
105public:
106    typedef typename char_type_of<Filter>::type char_type;
107    struct category
108        : mode_of<Filter>::type,
109          filter_tag,
110          multichar_tag,
111          closable_tag,
112          localizable_tag,
113          optimally_buffered_tag
114        { };
115    restricted_filter( const Filter& flt, stream_offset off,
116                       stream_offset len = -1 );
117
118    template<typename Source>
119    std::streamsize read(Source& src, char_type* s, std::streamsize n)
120    {
121        using namespace std;
122        if (!open_)
123            open(src);
124        streamsize amt =
125            end_ != -1 ?
126                (std::min) (n, static_cast<streamsize>(end_ - pos_)) :
127                n;
128        streamsize result = iostreams::read(this->component(), src, s, amt);
129        if (result != -1)
130            pos_ += result;
131        return result;
132    }
133
134    template<typename Sink>
135    std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
136    {
137        if (!open_)
138            open(snk);
139        if (end_ != -1 && pos_ + n >= end_)
140            bad_write();
141        std::streamsize result =
142            iostreams::write(this->component(), snk, s, n);
143        pos_ += result;
144        return result;
145    }
146
147    template<typename Device>
148    std::streampos seek(Device& dev, stream_offset off, BOOST_IOS::seekdir way)
149    {
150        stream_offset next;
151        if (way == BOOST_IOS::beg) {
152            next = beg_ + off;
153        } else if (way == BOOST_IOS::cur) {
154            next = pos_ + off;
155        } else if (end_ != -1) {
156            next = end_ + off;
157        } else {
158            // Restriction is half-open; seek relative to the actual end.
159            pos_ = this->component().seek(dev, off, BOOST_IOS::end);
160            if (pos_ < beg_)
161                bad_seek();
162            return offset_to_position(pos_ - beg_);
163        }
164        if (next < beg_ || end_ != -1 && next >= end_)
165            bad_seek();
166        pos_ = this->component().seek(dev, next, BOOST_IOS::cur);
167        return offset_to_position(pos_ - beg_);
168    }
169private:
170    template<typename Device>
171    void open(Device& dev)
172    {
173        open_ = true;
174        iostreams::skip(this->component(), dev, beg_);
175    }
176    stream_offset  beg_, pos_, end_;
177    bool           open_;
178};
179
180template<typename T>
181struct restriction_traits
182    : iostreams::select<  // Disambiguation for Tru64.
183          is_filter<T>,  restricted_filter<T>,
184          is_direct<T>,  restricted_direct_device<T>,
185          else_,         restricted_indirect_device<T>
186      >
187    { };
188
189} // End namespace detail.
190
191template<typename T>
192struct restriction : public detail::restriction_traits<T>::type {
193    typedef typename detail::param_type<T>::type          param_type;
194    typedef typename detail::restriction_traits<T>::type  base_type;
195    restriction(param_type t, stream_offset off, stream_offset len = -1)
196        : base_type(t, off, len)
197        { }
198};
199
200//--------------Implementation of restrict------------------------------------//
201
202// Note: The following workarounds are patterned after resolve.hpp. It has not
203// yet been confirmed that they are necessary.
204
205#ifndef BOOST_IOSTREAMS_BROKEN_OVERLOAD_RESOLUTION //-------------------------//
206# ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES //-------------------------------//
207
208template<typename T>
209restriction<T> restrict( const T& t, stream_offset off, stream_offset len = -1
210                         BOOST_IOSTREAMS_DISABLE_IF_STREAM(T) )
211{ return restriction<T>(t, off, len); }
212
213template<typename Ch, typename Tr>
214restriction< std::basic_streambuf<Ch, Tr> >
215restrict(std::basic_streambuf<Ch, Tr>& sb, stream_offset off, stream_offset len = -1)
216{ return restriction< std::basic_streambuf<Ch, Tr> >(sb, off, len); }
217
218template<typename Ch, typename Tr>
219restriction< std::basic_istream<Ch, Tr> >
220restrict(std::basic_istream<Ch, Tr>& is, stream_offset off, stream_offset len = -1)
221{ return restriction< std::basic_istream<Ch, Tr> >(is, off, len); }
222
223template<typename Ch, typename Tr>
224restriction< std::basic_ostream<Ch, Tr> >
225restrict(std::basic_ostream<Ch, Tr>& os, stream_offset off, stream_offset len = -1)
226{ return restriction< std::basic_ostream<Ch, Tr> >(os, off, len); }
227
228template<typename Ch, typename Tr>
229restriction< std::basic_iostream<Ch, Tr> >
230restrict(std::basic_iostream<Ch, Tr>& io, stream_offset off, stream_offset len = -1)
231{ return restriction< std::basic_iostream<Ch, Tr> >(io, off, len); }
232
233# else // # ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES //---------------------//
234
235template<typename T>
236restriction<T> restrict( const T& t, stream_offset off, stream_offset len = -1
237                         BOOST_IOSTREAMS_DISABLE_IF_STREAM(T) )
238{ return restriction<T>(t, off, len); }
239
240restriction<std::streambuf>
241restrict(std::streambuf& sb, stream_offset off, stream_offset len = -1)
242{ return restriction<std::streambuf>(sb, off, len); }
243
244restriction<std::istream>
245restrict(std::istream<Ch, Tr>& is, stream_offset off, stream_offset len = -1)
246{ return restriction<std::istream>(is, off, len); }
247
248restriction<std::ostream>
249restrict(std::ostream<Ch, Tr>& os, stream_offset off, stream_offset len = -1)
250{ return restriction<std::ostream>(os, off, len); }
251
252restriction<std::iostream>
253restrict(std::iostream<Ch, Tr>& io, stream_offset off, stream_offset len = -1)
254{ return restriction<std::iostream>(io, off, len); }
255
256# endif // # ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES //--------------------//
257#else // #ifndef BOOST_IOSTREAMS_BROKEN_OVERLOAD_RESOLUTION //----------------//
258
259template<typename T>
260restriction<T>
261restrict(const T& t, stream_offset off, stream_offset len, mpl::true_)
262{   // Bad overload resolution.
263    return restriction<T>(const_cast<T&>(t, off, len));
264}
265
266template<typename T>
267restriction<T>
268restrict(const T& t, stream_offset off, stream_offset len, mpl::false_)
269{ return restriction<T>(t, off, len); }
270
271template<typename T>
272restriction<T>
273restrict( const T& t, stream_offset off, stream_offset len = -1
274          BOOST_IOSTREAMS_DISABLE_IF_STREAM(T) )
275{ return restrict(t, off, len, is_std_io<T>()); }
276
277# if !BOOST_WORKAROUND(__BORLANDC__, < 0x600) && \
278     !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) && \
279     !defined(__GNUC__) // ---------------------------------------------------//
280
281template<typename T>
282restriction<T>
283restrict(T& t, stream_offset off, stream_offset len = -1)
284{ return restriction<T>(t, off, len); }
285
286# endif // Borland 5.x, VC6-7.0 or GCC 2.9x //--------------------------------//
287#endif // #ifndef BOOST_IOSTREAMS_BROKEN_OVERLOAD_RESOLUTION //---------------//
288//----------------------------------------------------------------------------//
289
290namespace detail {
291
292//--------------Implementation of restricted_indirect_device------------------//
293
294template<typename Device>
295restricted_indirect_device<Device>::restricted_indirect_device
296    (param_type dev, stream_offset off, stream_offset len)
297    : basic_adapter<Device>(dev), beg_(off), pos_(off),
298      end_(len != -1 ? off + len : -1)
299{
300    if (len < -1 || off < 0)
301        throw BOOST_IOSTREAMS_FAILURE("bad offset");
302    iostreams::skip(this->component(), off);
303}
304
305template<typename Device>
306inline std::streamsize restricted_indirect_device<Device>::read
307    (char_type* s, std::streamsize n)
308{
309    using namespace std;
310    streamsize amt =
311        end_ != -1 ?
312            (std::min) (n, static_cast<streamsize>(end_ - pos_)) :
313            n;
314    streamsize result = iostreams::read(this->component(), s, amt);
315    if (result != -1)
316        pos_ += result;
317    return result;
318}
319
320template<typename Device>
321inline std::streamsize restricted_indirect_device<Device>::write
322    (const char_type* s, std::streamsize n)
323{
324    if (end_ != -1 && pos_ + n >= end_)
325        bad_write();
326    std::streamsize result = iostreams::write(this->component(), s, n);
327    pos_ += result;
328    return result;
329}
330
331template<typename Device>
332std::streampos restricted_indirect_device<Device>::seek
333    (stream_offset off, BOOST_IOS::seekdir way)
334{
335    stream_offset next;
336    if (way == BOOST_IOS::beg) {
337        next = beg_ + off;
338    } else if (way == BOOST_IOS::cur) {
339        next = pos_ + off;
340    } else if (end_ != -1) {
341        next = end_ + off;
342    } else {
343        // Restriction is half-open; seek relative to the actual end.
344        pos_ = iostreams::seek(this->component(), off, BOOST_IOS::end);
345        if (pos_ < beg_)
346            bad_seek();
347        return offset_to_position(pos_ - beg_);
348    }
349    if (next < beg_ || end_ != -1 && next >= end_)
350        bad_seek();
351    pos_ = iostreams::seek(this->component(), next - pos_, BOOST_IOS::cur);
352    return offset_to_position(pos_ - beg_);
353}
354
355//--------------Implementation of restricted_direct_device--------------------//
356
357template<typename Device>
358restricted_direct_device<Device>::restricted_direct_device
359    (const Device& dev, stream_offset off, stream_offset len)
360    : basic_adapter<Device>(dev), beg_(0), end_(0)
361{
362    std::pair<char_type*, char_type*> seq =
363        sequence(is_convertible<category, input>());
364    if ( off < 0 || len < -1 ||
365         len != -1 && off + len > seq.second - seq.first )
366    {
367        throw BOOST_IOSTREAMS_FAILURE("bad offset");
368    }
369    beg_ = seq.first + off;
370    end_ = len != -1 ?
371        seq.first + off + len :
372        seq.second;
373}
374
375template<typename Device>
376typename restricted_direct_device<Device>::pair_type
377restricted_direct_device<Device>::input_sequence()
378{
379    BOOST_STATIC_ASSERT((is_convertible<category, input>::value));
380    return std::make_pair(beg_, end_);
381}
382
383template<typename Device>
384typename restricted_direct_device<Device>::pair_type
385restricted_direct_device<Device>::output_sequence()
386{
387    BOOST_STATIC_ASSERT((is_convertible<category, output>::value));
388    return std::make_pair(beg_, end_);
389}
390
391template<typename Device>
392typename restricted_direct_device<Device>::pair_type
393restricted_direct_device<Device>::sequence(mpl::true_)
394{ return iostreams::input_sequence(this->component()); }
395
396template<typename Device>
397typename restricted_direct_device<Device>::pair_type
398restricted_direct_device<Device>::sequence(mpl::false_)
399{ return iostreams::output_sequence(this->component()); }
400
401//--------------Implementation of restricted_filter---------------------------//
402
403template<typename Filter>
404restricted_filter<Filter>::restricted_filter
405    (const Filter& flt, stream_offset off, stream_offset len)
406    : basic_adapter<Filter>(flt), beg_(off),
407      pos_(off), end_(len != -1 ? off + len : -1), open_(false)
408{
409    if (len < -1 || off < 0)
410        throw BOOST_IOSTREAMS_FAILURE("bad offset");
411}
412
413} // End namespace detail.
414
415} } // End namespaces iostreams, boost.
416
417
418#endif // #ifndef BOOST_IOSTREAMS_RESTRICT_HPP_INCLUDED
Note: See TracBrowser for help on using the repository browser.