Boost logo

Boost-Commit :

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;
+}


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk