| // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) |
| // (C) Copyright 2003-2007 Jonathan Turkanis |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) |
| |
| // See http://www.boost.org/libs/iostreams for documentation. |
| |
| #ifndef NDNBOOST_IOSTREAMS_DETAIL_RANGE_ADAPTER_HPP_INCLUDED |
| #define NDNBOOST_IOSTREAMS_DETAIL_RANGE_ADAPTER_HPP_INCLUDED |
| |
| #if defined(_MSC_VER) && (_MSC_VER >= 1020) |
| # pragma once |
| #endif |
| |
| #include <algorithm> // min. |
| #include <ndnboost/assert.hpp> |
| #include <cstddef> // ptrdiff_t. |
| #include <iosfwd> // streamsize, streamoff. |
| #include <ndnboost/detail/iterator.hpp> // ndnboost::iterator_traits. |
| #include <ndnboost/iostreams/categories.hpp> |
| #include <ndnboost/iostreams/detail/error.hpp> |
| #include <ndnboost/iostreams/positioning.hpp> |
| #include <ndnboost/mpl/if.hpp> |
| #include <ndnboost/throw_exception.hpp> |
| #include <ndnboost/type_traits/is_convertible.hpp> |
| #include <ndnboost/utility/enable_if.hpp> |
| |
| // Must come last. |
| #include <ndnboost/iostreams/detail/config/disable_warnings.hpp> // MSVC. |
| |
| namespace ndnboost { namespace iostreams { namespace detail { |
| |
| // Used for simulated tag dispatch. |
| template<typename Traversal> struct range_adapter_impl; |
| |
| // |
| // Template name: range_adapter |
| // Description: Device based on an instance of ndnboost::iterator_range. |
| // Template parameters: |
| // Mode - A mode tag. |
| // Range - An instance of iterator_range. |
| // |
| template<typename Mode, typename Range> |
| class range_adapter { |
| private: |
| typedef typename Range::iterator iterator; |
| typedef ndnboost::detail::iterator_traits<iterator> iter_traits; |
| typedef typename iter_traits::iterator_category iter_cat; |
| public: |
| typedef typename Range::value_type char_type; |
| struct category : Mode, device_tag { }; |
| typedef typename |
| mpl::if_< |
| is_convertible< |
| iter_cat, |
| std::random_access_iterator_tag |
| >, |
| std::random_access_iterator_tag, |
| std::forward_iterator_tag |
| >::type tag; |
| typedef range_adapter_impl<tag> impl; |
| |
| explicit range_adapter(const Range& rng); |
| range_adapter(iterator first, iterator last); |
| std::streamsize read(char_type* s, std::streamsize n); |
| std::streamsize write(const char_type* s, std::streamsize n); |
| std::streampos seek(stream_offset off, NDNBOOST_IOS::seekdir way); |
| private: |
| iterator first_, cur_, last_; |
| }; |
| |
| //------------------Implementation of range_adapter---------------------------// |
| |
| template<typename Mode, typename Range> |
| range_adapter<Mode, Range>::range_adapter(const Range& rng) |
| : first_(rng.begin()), cur_(rng.begin()), last_(rng.end()) { } |
| |
| template<typename Mode, typename Range> |
| range_adapter<Mode, Range>::range_adapter(iterator first, iterator last) |
| : first_(first), cur_(first), last_(last) { } |
| |
| template<typename Mode, typename Range> |
| inline std::streamsize range_adapter<Mode, Range>::read |
| (char_type* s, std::streamsize n) |
| { return impl::read(cur_, last_, s, n); } |
| |
| template<typename Mode, typename Range> |
| inline std::streamsize range_adapter<Mode, Range>::write |
| (const char_type* s, std::streamsize n) |
| { return impl::write(cur_, last_, s, n); } |
| |
| |
| template<typename Mode, typename Range> |
| std::streampos range_adapter<Mode, Range>::seek |
| (stream_offset off, NDNBOOST_IOS::seekdir way) |
| { |
| impl::seek(first_, cur_, last_, off, way); |
| return offset_to_position(cur_ - first_); |
| } |
| |
| //------------------Implementation of range_adapter_impl----------------------// |
| |
| template<> |
| struct range_adapter_impl<std::forward_iterator_tag> { |
| template<typename Iter, typename Ch> |
| static std::streamsize read |
| (Iter& cur, Iter& last, Ch* s,std::streamsize n) |
| { |
| std::streamsize rem = n; // No. of chars remaining. |
| while (cur != last && rem-- > 0) *s++ = *cur++; |
| return n - rem != 0 ? n - rem : -1; |
| } |
| |
| template<typename Iter, typename Ch> |
| static std::streamsize write |
| (Iter& cur, Iter& last, const Ch* s, std::streamsize n) |
| { |
| while (cur != last && n-- > 0) *cur++ = *s++; |
| if (cur == last && n > 0) |
| ndnboost::throw_exception(write_area_exhausted()); |
| return n; |
| } |
| }; |
| |
| template<> |
| struct range_adapter_impl<std::random_access_iterator_tag> { |
| template<typename Iter, typename Ch> |
| static std::streamsize read |
| (Iter& cur, Iter& last, Ch* s,std::streamsize n) |
| { |
| std::streamsize result = |
| (std::min)(static_cast<std::streamsize>(last - cur), n); |
| if (result) |
| std::copy(cur, cur + result, s); |
| cur += result; |
| return result != 0 ? result : -1; |
| } |
| |
| template<typename Iter, typename Ch> |
| static std::streamsize write |
| (Iter& cur, Iter& last, const Ch* s, std::streamsize n) |
| { |
| std::streamsize count = |
| (std::min)(static_cast<std::streamsize>(last - cur), n); |
| std::copy(s, s + count, cur); |
| cur += count; |
| if (count < n) |
| ndnboost::throw_exception(write_area_exhausted()); |
| return n; |
| } |
| |
| template<typename Iter> |
| static void seek |
| ( Iter& first, Iter& cur, Iter& last, stream_offset off, |
| NDNBOOST_IOS::seekdir way ) |
| { |
| using namespace std; |
| switch (way) { |
| case NDNBOOST_IOS::beg: |
| if (off > last - first || off < 0) |
| ndnboost::throw_exception(bad_seek()); |
| cur = first + off; |
| break; |
| case NDNBOOST_IOS::cur: |
| { |
| std::ptrdiff_t newoff = cur - first + off; |
| if (newoff > last - first || newoff < 0) |
| ndnboost::throw_exception(bad_seek()); |
| cur += off; |
| break; |
| } |
| case NDNBOOST_IOS::end: |
| if (last - first + off < 0 || off > 0) |
| ndnboost::throw_exception(bad_seek()); |
| cur = last + off; |
| break; |
| default: |
| NDNBOOST_ASSERT(0); |
| } |
| } |
| }; |
| |
| } } } // End namespaces detail, iostreams, boost. |
| |
| #include <ndnboost/iostreams/detail/config/enable_warnings.hpp> // MSVC. |
| |
| #endif // #ifndef NDNBOOST_IOSTREAMS_DETAIL_RANGE_ADAPTER_HPP_INCLUDED //---------------// |