//

// const_buffers_iterator.hpp

// ~~~~~~~~~~~~~~~~~~~~~~~~~~

//

// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)

//

// 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)

//



#ifndef BOOST_ASIO_DETAIL_CONST_BUFFERS_ITERATOR_HPP

#define BOOST_ASIO_DETAIL_CONST_BUFFERS_ITERATOR_HPP



#if defined(_MSC_VER) && (_MSC_VER >= 1200)

# pragma once

#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)



#include <boost/asio/detail/push_options.hpp>



#include <boost/asio/detail/push_options.hpp>

#include <cstddef>

#include <boost/config.hpp>

#include <boost/iterator/iterator_facade.hpp>

#include <boost/asio/detail/pop_options.hpp>



#include <boost/asio/buffer.hpp>



namespace boost {

namespace asio {

namespace detail {



// A proxy iterator for a sub-range in a list of buffers.

template <typename ConstBufferSequence>

class const_buffers_iterator

  : public boost::iterator_facade<const_buffers_iterator<ConstBufferSequence>,

        const char, boost::bidirectional_traversal_tag>

{

public:

  // Default constructor creates an iterator in an undefined state.

  const_buffers_iterator()

  {

  }



  // Create an iterator for the specified position.

  const_buffers_iterator(const ConstBufferSequence& buffers,

      std::size_t position)

    : begin_(buffers.begin()),

      current_(buffers.begin()),

      end_(buffers.end()),

      position_(0)

  {

    while (current_ != end_)

    {

      current_buffer_ = *current_;

      std::size_t buffer_size = boost::asio::buffer_size(current_buffer_);

      if (position - position_ < buffer_size)

      {

        current_buffer_position_ = position - position_;

        position_ = position;

        return;

      }

      position_ += buffer_size;

      ++current_;

    }

    current_buffer_ = boost::asio::const_buffer();

    current_buffer_position_ = 0;

  }



  std::size_t position() const

  {

    return position_;

  }



private:

  friend class boost::iterator_core_access;



  void increment()

  {

    if (current_ == end_)

      return;



    ++position_;



    ++current_buffer_position_;

    if (current_buffer_position_ != boost::asio::buffer_size(current_buffer_))

      return;



    ++current_;

    current_buffer_position_ = 0;

    while (current_ != end_)

    {

      current_buffer_ = *current_;

      if (boost::asio::buffer_size(current_buffer_) > 0)

        return;

      ++current_;

    }

  }



  void decrement()

  {

    if (position_ == 0)

      return;



    --position_;



    if (current_buffer_position_ != 0)

    {

      --current_buffer_position_;

      return;

    }



    typename ConstBufferSequence::const_iterator iter = current_;

    while (iter != begin_)

    {

      --iter;

      boost::asio::const_buffer buffer = *iter;

      std::size_t buffer_size = boost::asio::buffer_size(buffer);

      if (buffer_size > 0)

      {

        current_ = iter;

        current_buffer_ = buffer;

        current_buffer_position_ = buffer_size - 1;

        return;

      }

    }

  }



  bool equal(const const_buffers_iterator& other) const

  {

    return position_ == other.position_;

  }



  const char& dereference() const

  {

    return boost::asio::buffer_cast<const char*>(

        current_buffer_)[current_buffer_position_];

  }



  boost::asio::const_buffer current_buffer_;

  std::size_t current_buffer_position_;

  typename ConstBufferSequence::const_iterator begin_;

  typename ConstBufferSequence::const_iterator current_;

  typename ConstBufferSequence::const_iterator end_;

  std::size_t position_;

};



} // namespace detail

} // namespace asio

} // namespace boost



#include <boost/asio/detail/pop_options.hpp>



#endif // BOOST_ASIO_DETAIL_CONST_BUFFERS_ITERATOR_HPP

