$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
From: chris_at_[hidden]
Date: 2008-06-15 20:41:30
Author: chris_kohlhoff
Date: 2008-06-15 20:41:29 EDT (Sun, 15 Jun 2008)
New Revision: 46415
URL: http://svn.boost.org/trac/boost/changeset/46415
Log:
Add an iterator for bytewise traversal of a buffer sequence.
Added:
   trunk/boost/asio/buffers_iterator.hpp   (contents, props changed)
   trunk/libs/asio/test/buffers_iterator.cpp   (contents, props changed)
Text files modified: 
   trunk/boost/asio.hpp            |     1 +                                       
   trunk/libs/asio/test/Jamfile    |     1 +                                       
   trunk/libs/asio/test/Jamfile.v2 |     2 ++                                      
   3 files changed, 4 insertions(+), 0 deletions(-)
Modified: trunk/boost/asio.hpp
==============================================================================
--- trunk/boost/asio.hpp	(original)
+++ trunk/boost/asio.hpp	2008-06-15 20:41:29 EDT (Sun, 15 Jun 2008)
@@ -34,6 +34,7 @@
 #include <boost/asio/buffered_stream.hpp>
 #include <boost/asio/buffered_write_stream_fwd.hpp>
 #include <boost/asio/buffered_write_stream.hpp>
+#include <boost/asio/buffers_iterator.hpp>
 #include <boost/asio/completion_condition.hpp>
 #include <boost/asio/datagram_socket_service.hpp>
 #include <boost/asio/deadline_timer_service.hpp>
Added: trunk/boost/asio/buffers_iterator.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/asio/buffers_iterator.hpp	2008-06-15 20:41:29 EDT (Sun, 15 Jun 2008)
@@ -0,0 +1,320 @@
+//
+// 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_BUFFERS_ITERATOR_HPP
+#define BOOST_ASIO_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/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/type_traits/add_const.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/buffer.hpp>
+
+namespace boost {
+namespace asio {
+
+namespace detail
+{
+  template <bool IsMutable>
+  struct buffers_iterator_types_helper;
+
+  template <>
+  struct buffers_iterator_types_helper<false>
+  {
+    typedef const_buffer buffer_type;
+    template <typename ByteType>
+    struct byte_type
+    {
+      typedef typename boost::add_const<ByteType>::type type;
+    };
+  };
+
+  template <>
+  struct buffers_iterator_types_helper<true>
+  {
+    typedef mutable_buffer buffer_type;
+    template <typename ByteType>
+    struct byte_type
+    {
+      typedef ByteType type;
+    };
+  };
+
+  template <typename BufferSequence, typename ByteType>
+  struct buffers_iterator_types
+  {
+    enum
+    {
+      is_mutable = boost::is_convertible<
+        typename BufferSequence::value_type, mutable_buffer>::value
+    };
+    typedef buffers_iterator_types_helper<is_mutable> helper;
+    typedef typename helper::buffer_type buffer_type;
+    typedef typename helper::template byte_type<ByteType>::type byte_type;
+  };
+}
+
+/// A random access iterator over the bytes in a buffer sequence.
+template <typename BufferSequence, typename ByteType = char>
+class buffers_iterator
+  : public boost::iterator_facade<
+        buffers_iterator<BufferSequence, ByteType>,
+        typename detail::buffers_iterator_types<
+          BufferSequence, ByteType>::byte_type,
+        boost::random_access_traversal_tag>
+{
+private:
+  typedef typename detail::buffers_iterator_types<
+      BufferSequence, ByteType>::buffer_type buffer_type;
+  typedef typename detail::buffers_iterator_types<
+      BufferSequence, ByteType>::byte_type byte_type;
+
+public:
+  /// Default constructor. Creates an iterator in an undefined state.
+  buffers_iterator()
+    : current_buffer_(),
+      current_buffer_position_(0),
+      begin_(),
+      current_(),
+      end_(),
+      position_(0)
+  {
+  }
+
+  /// Construct an iterator representing the beginning of the buffers' data.
+  static buffers_iterator begin(const BufferSequence& buffers)
+  {
+    buffers_iterator new_iter;
+    new_iter.begin_ = buffers.begin();
+    new_iter.current_ = buffers.begin();
+    new_iter.end_ = buffers.end();
+    while (new_iter.current_ != new_iter.end_)
+    {
+      new_iter.current_buffer_ = *new_iter.current_;
+      if (boost::asio::buffer_size(new_iter.current_buffer_) > 0)
+        break;
+      ++new_iter.current_;
+    }
+    return new_iter;
+  }
+
+  /// Construct an iterator representing the end of the buffers' data.
+  static buffers_iterator end(const BufferSequence& buffers)
+  {
+    buffers_iterator new_iter;
+    new_iter.begin_ = buffers.begin();
+    new_iter.current_ = buffers.begin();
+    new_iter.end_ = buffers.end();
+    while (new_iter.current_ != new_iter.end_)
+    {
+      buffer_type buffer = *new_iter.current_;
+      new_iter.position_ += boost::asio::buffer_size(buffer);
+      ++new_iter.current_;
+    }
+    return new_iter;
+  }
+
+private:
+  friend class boost::iterator_core_access;
+
+  // Dereference the iterator.
+  byte_type& dereference() const
+  {
+    return buffer_cast<byte_type*>(current_buffer_)[current_buffer_position_];
+  }
+
+  // Compare two iterators for equality.
+  bool equal(const buffers_iterator& other) const
+  {
+    return position_ == other.position_;
+  }
+
+  // Increment the iterator.
+  void increment()
+  {
+    BOOST_ASSERT(current_ != end_ && "iterator out of bounds");
+    ++position_;
+
+    // Check if the increment can be satisfied by the current buffer.
+    ++current_buffer_position_;
+    if (current_buffer_position_ != boost::asio::buffer_size(current_buffer_))
+      return;
+
+    // Find the next non-empty buffer.
+    ++current_;
+    current_buffer_position_ = 0;
+    while (current_ != end_)
+    {
+      current_buffer_ = *current_;
+      if (boost::asio::buffer_size(current_buffer_) > 0)
+        return;
+      ++current_;
+    }
+  }
+
+  // Decrement the iterator.
+  void decrement()
+  {
+    BOOST_ASSERT(position_ > 0 && "iterator out of bounds");
+    --position_;
+
+    // Check if the decrement can be satisfied by the current buffer.
+    if (current_buffer_position_ != 0)
+    {
+      --current_buffer_position_;
+      return;
+    }
+
+    // Find the previous non-empty buffer.
+    typename BufferSequence::const_iterator iter = current_;
+    while (iter != begin_)
+    {
+      --iter;
+      buffer_type 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;
+      }
+    }
+  }
+
+  // Advance the iterator by the specified distance.
+  void advance(std::ptrdiff_t n)
+  {
+    if (n > 0)
+    {
+      BOOST_ASSERT(current_ != end_ && "iterator out of bounds");
+      for (;;)
+      {
+        std::ptrdiff_t current_buffer_balance
+          = boost::asio::buffer_size(current_buffer_)
+          - current_buffer_position_;
+
+        // Check if the advance can be satisfied by the current buffer.
+        if (current_buffer_balance > n)
+        {
+          position_ += n;
+          current_buffer_position_ += n;
+          return;
+        }
+
+        // Update position.
+        n -= current_buffer_balance;
+        position_ += current_buffer_balance;
+
+        // Move to next buffer. If it is empty then it will be skipped on the
+        // next iteration of this loop.
+        if (++current_ == end_)
+        {
+          BOOST_ASSERT(n == 0 && "iterator out of bounds");
+          current_buffer_ = buffer_type();
+          current_buffer_position_ = 0;
+          return;
+        }
+        current_buffer_ = *current_;
+        current_buffer_position_ = 0;
+      }
+    }
+    else if (n < 0)
+    {
+      std::size_t abs_n = -n;
+      BOOST_ASSERT(position_ >= abs_n && "iterator out of bounds");
+      for (;;)
+      {
+        // Check if the advance can be satisfied by the current buffer.
+        if (current_buffer_position_ >= abs_n)
+        {
+          position_ -= abs_n;
+          current_buffer_position_ -= abs_n;
+          return;
+        }
+
+        // Update position.
+        abs_n -= current_buffer_position_;
+        position_ -= current_buffer_position_;
+
+        // Check if we've reached the beginning of the buffers.
+        if (current_ == begin_)
+        {
+          BOOST_ASSERT(abs_n == 0 && "iterator out of bounds");
+          current_buffer_position_ = 0;
+          return;
+        }
+
+        // Find the previous non-empty buffer.
+        typename BufferSequence::const_iterator iter = current_;
+        while (iter != begin_)
+        {
+          --iter;
+          buffer_type 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;
+            break;
+          }
+        }
+      }
+    }
+  }
+
+  // Determine the distance between two iterators.
+  std::ptrdiff_t distance_to(const buffers_iterator& other) const
+  {
+    return other.position_ - position_;
+  }
+
+  buffer_type current_buffer_;
+  std::size_t current_buffer_position_;
+  typename BufferSequence::const_iterator begin_;
+  typename BufferSequence::const_iterator current_;
+  typename BufferSequence::const_iterator end_;
+  std::size_t position_;
+};
+
+/// Construct an iterator representing the beginning of the buffers' data.
+template <typename BufferSequence>
+inline buffers_iterator<BufferSequence> buffers_begin(
+    const BufferSequence& buffers)
+{
+  return buffers_iterator<BufferSequence>::begin(buffers);
+}
+
+/// Construct an iterator representing the end of the buffers' data.
+template <typename BufferSequence>
+inline buffers_iterator<BufferSequence> buffers_end(
+    const BufferSequence& buffers)
+{
+  return buffers_iterator<BufferSequence>::end(buffers);
+}
+
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_BUFFERS_ITERATOR_HPP
Modified: trunk/libs/asio/test/Jamfile
==============================================================================
--- trunk/libs/asio/test/Jamfile	(original)
+++ trunk/libs/asio/test/Jamfile	2008-06-15 20:41:29 EDT (Sun, 15 Jun 2008)
@@ -45,6 +45,7 @@
   [ run buffered_read_stream.cpp <template>asio_unit_test ]
   [ run buffered_stream.cpp <template>asio_unit_test ]
   [ run buffered_write_stream.cpp <template>asio_unit_test ]
+  [ run buffers_iterator.cpp <template>asio_unit_test ]
   [ run completion_condition.cpp <template>asio_unit_test ]
   [ run datagram_socket_service.cpp <template>asio_unit_test ]
   [ run deadline_timer_service.cpp <template>asio_unit_test ]
Modified: trunk/libs/asio/test/Jamfile.v2
==============================================================================
--- trunk/libs/asio/test/Jamfile.v2	(original)
+++ trunk/libs/asio/test/Jamfile.v2	2008-06-15 20:41:29 EDT (Sun, 15 Jun 2008)
@@ -68,6 +68,8 @@
   [ run buffered_stream.cpp : : : $(USE_SELECT) : buffered_stream_select ]
   [ run buffered_write_stream.cpp ]
   [ run buffered_write_stream.cpp : : : $(USE_SELECT) : buffered_write_stream_select ]
+  [ run buffers_iterator.cpp ]
+  [ run buffers_iterator.cpp : : : $(USE_SELECT) : buffers_iterator_select ]
   [ link completion_condition.cpp ]
   [ link completion_condition.cpp : $(USE_SELECT) : completion_condition_select ]
   [ link datagram_socket_service.cpp ]
Added: trunk/libs/asio/test/buffers_iterator.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/buffers_iterator.cpp	2008-06-15 20:41:29 EDT (Sun, 15 Jun 2008)
@@ -0,0 +1,230 @@
+//
+// buffers_iterator.cpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// 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)
+//
+
+// Disable autolinking for unit tests.
+#if !defined(BOOST_ALL_NO_LIB)
+#define BOOST_ALL_NO_LIB 1
+#endif // !defined(BOOST_ALL_NO_LIB)
+
+// Test that header file is self-contained.
+#include <boost/asio/buffers_iterator.hpp>
+
+#include <boost/asio.hpp>
+#include "unit_test.hpp"
+
+//------------------------------------------------------------------------------
+
+// buffers_iterator_compile test
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The following test checks that all operations on the buffers_iterator compile
+// and link correctly. Runtime failures are ignored.
+
+namespace buffers_iterator_compile {
+
+using boost::array;
+using std::vector;
+using namespace boost::asio;
+
+void test()
+{
+  try
+  {
+    char data1[16], data2[16];
+    const char cdata1[16] = "", cdata2[16] = "";
+    mutable_buffers_1 mb1 = buffer(data1);
+    array<mutable_buffer, 2> mb2 = {{ buffer(data1), buffer(data2) }};
+    std::vector<mutable_buffer> mb3;
+    mb3.push_back(buffer(data1));
+    const_buffers_1 cb1 = buffer(cdata1);
+    array<const_buffer, 2> cb2 = {{ buffer(cdata1), buffer(cdata2) }};
+    vector<const_buffer> cb3;
+    cb3.push_back(buffer(cdata1));
+
+
+    // buffers_iterator constructors.
+
+    buffers_iterator<mutable_buffers_1, char> bi1;
+    buffers_iterator<mutable_buffers_1, const char> bi2;
+    buffers_iterator<array<mutable_buffer, 2>, char> bi3;
+    buffers_iterator<array<mutable_buffer, 2>, const char> bi4;
+    buffers_iterator<vector<mutable_buffer>, char> bi5;
+    buffers_iterator<vector<mutable_buffer>, const char> bi6;
+    buffers_iterator<const_buffers_1, char> bi7;
+    buffers_iterator<const_buffers_1, const char> bi8;
+    buffers_iterator<array<const_buffer, 2>, char> bi9;
+    buffers_iterator<array<const_buffer, 2>, const char> bi10;
+    buffers_iterator<vector<const_buffer>, char> bi11;
+    buffers_iterator<vector<const_buffer>, const char> bi12;
+
+    buffers_iterator<mutable_buffers_1, char> bi13(bi1);
+    buffers_iterator<mutable_buffers_1, const char> bi14(bi2);
+    buffers_iterator<array<mutable_buffer, 2>, char> bi15(bi3);
+    buffers_iterator<array<mutable_buffer, 2>, const char> bi16(bi4);
+    buffers_iterator<vector<mutable_buffer>, char> bi17(bi5);
+    buffers_iterator<vector<mutable_buffer>, const char> bi18(bi6);
+    buffers_iterator<const_buffers_1, char> bi19(bi7);
+    buffers_iterator<const_buffers_1, const char> bi20(bi8);
+    buffers_iterator<array<const_buffer, 2>, char> bi21(bi9);
+    buffers_iterator<array<const_buffer, 2>, const char> bi22(bi10);
+    buffers_iterator<vector<const_buffer>, char> bi23(bi11);
+    buffers_iterator<vector<const_buffer>, const char> bi24(bi12);
+
+    // buffers_iterator member functions.
+
+    bi1 = buffers_iterator<mutable_buffers_1, char>::begin(mb1);
+    bi2 = buffers_iterator<mutable_buffers_1, const char>::begin(mb1);
+    bi3 = buffers_iterator<array<mutable_buffer, 2>, char>::begin(mb2);
+    bi4 = buffers_iterator<array<mutable_buffer, 2>, const char>::begin(mb2);
+    bi5 = buffers_iterator<vector<mutable_buffer>, char>::begin(mb3);
+    bi6 = buffers_iterator<vector<mutable_buffer>, const char>::begin(mb3);
+    bi7 = buffers_iterator<const_buffers_1, char>::begin(cb1);
+    bi8 = buffers_iterator<const_buffers_1, const char>::begin(cb1);
+    bi9 = buffers_iterator<array<const_buffer, 2>, char>::begin(cb2);
+    bi10 = buffers_iterator<array<const_buffer, 2>, const char>::begin(cb2);
+    bi11 = buffers_iterator<vector<const_buffer>, char>::begin(cb3);
+    bi12 = buffers_iterator<vector<const_buffer>, const char>::begin(cb3);
+
+    bi1 = buffers_iterator<mutable_buffers_1, char>::end(mb1);
+    bi2 = buffers_iterator<mutable_buffers_1, const char>::end(mb1);
+    bi3 = buffers_iterator<array<mutable_buffer, 2>, char>::end(mb2);
+    bi4 = buffers_iterator<array<mutable_buffer, 2>, const char>::end(mb2);
+    bi5 = buffers_iterator<vector<mutable_buffer>, char>::end(mb3);
+    bi6 = buffers_iterator<vector<mutable_buffer>, const char>::end(mb3);
+    bi7 = buffers_iterator<const_buffers_1, char>::end(cb1);
+    bi8 = buffers_iterator<const_buffers_1, const char>::end(cb1);
+    bi9 = buffers_iterator<array<const_buffer, 2>, char>::end(cb2);
+    bi10 = buffers_iterator<array<const_buffer, 2>, const char>::end(cb2);
+    bi11 = buffers_iterator<vector<const_buffer>, char>::end(cb3);
+    bi12 = buffers_iterator<vector<const_buffer>, const char>::end(cb3);
+
+    // buffers_iterator related functions.
+
+    bi1 = buffers_begin(mb1);
+    bi3 = buffers_begin(mb2);
+    bi5 = buffers_begin(mb3);
+    bi7 = buffers_begin(cb1);
+    bi9 = buffers_begin(cb2);
+    bi11 = buffers_begin(cb3);
+
+    bi1 = buffers_end(mb1);
+    bi3 = buffers_end(mb2);
+    bi5 = buffers_end(mb3);
+    bi7 = buffers_end(cb1);
+    bi9 = buffers_end(cb2);
+    bi11 = buffers_end(cb3);
+
+    // RandomAccessIterator operations.
+
+    --bi1;
+    --bi2;
+    --bi3;
+    --bi4;
+    --bi5;
+    --bi6;
+    --bi7;
+    --bi8;
+    --bi9;
+    --bi10;
+    --bi11;
+    --bi12;
+
+    ++bi1;
+    ++bi2;
+    ++bi3;
+    ++bi4;
+    ++bi5;
+    ++bi6;
+    ++bi7;
+    ++bi8;
+    ++bi9;
+    ++bi10;
+    ++bi11;
+    ++bi12;
+
+    bi1--;
+    bi2--;
+    bi3--;
+    bi4--;
+    bi5--;
+    bi6--;
+    bi7--;
+    bi8--;
+    bi9--;
+    bi10--;
+    bi11--;
+    bi12--;
+
+    bi1++;
+    bi2++;
+    bi3++;
+    bi4++;
+    bi5++;
+    bi6++;
+    bi7++;
+    bi8++;
+    bi9++;
+    bi10++;
+    bi11++;
+    bi12++;
+
+    bi1 -= 1;
+    bi2 -= 1;
+    bi3 -= 1;
+    bi4 -= 1;
+    bi5 -= 1;
+    bi6 -= 1;
+    bi7 -= 1;
+    bi8 -= 1;
+    bi9 -= 1;
+    bi10 -= 1;
+    bi11 -= 1;
+    bi12 -= 1;
+
+    bi1 += 1;
+    bi2 += 1;
+    bi3 += 1;
+    bi4 += 1;
+    bi5 += 1;
+    bi6 += 1;
+    bi7 += 1;
+    bi8 += 1;
+    bi9 += 1;
+    bi10 += 1;
+    bi11 += 1;
+    bi12 += 1;
+
+    static_cast<std::ptrdiff_t>(bi13 - bi1);
+    static_cast<std::ptrdiff_t>(bi14 - bi2);
+    static_cast<std::ptrdiff_t>(bi15 - bi3);
+    static_cast<std::ptrdiff_t>(bi16 - bi4);
+    static_cast<std::ptrdiff_t>(bi17 - bi5);
+    static_cast<std::ptrdiff_t>(bi18 - bi6);
+    static_cast<std::ptrdiff_t>(bi19 - bi7);
+    static_cast<std::ptrdiff_t>(bi20 - bi8);
+    static_cast<std::ptrdiff_t>(bi21 - bi9);
+    static_cast<std::ptrdiff_t>(bi22 - bi10);
+    static_cast<std::ptrdiff_t>(bi23 - bi11);
+    static_cast<std::ptrdiff_t>(bi24 - bi12);
+  }
+  catch (std::exception&)
+  {
+  }
+}
+
+} // namespace buffers_iterator_compile
+
+//------------------------------------------------------------------------------
+
+test_suite* init_unit_test_suite(int, char*[])
+{
+  test_suite* test = BOOST_TEST_SUITE("buffers_iterator");
+  test->add(BOOST_TEST_CASE(&buffers_iterator_compile::test));
+  return test;
+}