--- /dev/null
+#ifndef POSIXX_BASIC_BUFFER_HPP_
+#define POSIXX_BASIC_BUFFER_HPP_
+
+#include <stdexcept> // std::bad_alloc, std::out_of_range
+#include <limits> // std::numeric_limits
+#include <tr1/type_traits> // std::tr1::is_integral, true_type, false_type
+#include <cstring> // std::memcpy(), memset(), memcmp()
+#include <cassert> // assert()
+
+namespace posixx {
+
+/**
+ * A low-level buffer.
+ *
+ * This is pretty much like using a plain C-style array using dynamic memory,
+ * with a STL-ish interface.
+ *
+ * The buffer will use Allocator (which should be a function with realloc(3)
+ * semantics) for all storage management.
+ */
+template< void* (*Allocator)(void*, size_t) >
+struct basic_buffer {
+
+ // Types
+ //////////////////////////////////////////////////////////////////////
+
+ ///
+ typedef unsigned char value_type; // TODO: use char to be more
+ // std::string-friendly?
+
+ ///
+ typedef value_type& reference;
+
+ ///
+ typedef const value_type& const_reference;
+
+ ///
+ typedef value_type* iterator; // TODO: make a real iterator
+
+ ///
+ typedef const value_type* const_iterator;
+
+ ///
+ typedef size_t size_type;
+
+ ///
+ typedef ptrdiff_t difference_type;
+
+ ///
+ typedef value_type* pointer;
+
+ ///
+ typedef const pointer const_pointer;
+
+ ///
+ // TODO: reverse iterator
+ //typedef typename std::reverse_iterator< iterator > reverse_iterator;
+
+ ///
+ //typedef typename std::reverse_iterator< const iterator >
+ // const_reverse_iterator;
+
+
+ // Construct/Copy/Destroy
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Creates a buffer of length zero (the default constructor).
+ */
+ explicit basic_buffer(): _data(NULL), _size(0) {}
+
+ /**
+ * Creates a buffer with a capacity() of n (uninitialized) elements.
+ *
+ * @throw std::bad_alloc
+ */
+ explicit basic_buffer(size_type n):
+ _data(_allocate(NULL, n * sizeof(value_type))), _size(n)
+ {
+ }
+
+ /**
+ * Creates a buffer of length n, containing n copies of value.
+ *
+ * @throw std::bad_alloc
+ */
+ basic_buffer(size_type n, const_reference value):
+ _data(NULL), _size(0)
+ {
+ assign(n, value);
+ std::memset(_data, value, n);
+ }
+
+ /**
+ * Creates a copy of x.
+ *
+ * @throw std::bad_alloc
+ */
+ basic_buffer(const basic_buffer< Allocator >& x):
+ _data(_allocate(NULL, x.size() * sizeof(value_type))),
+ _size(x.size())
+ {
+ std::memcpy(_data, x.c_array(), x.size());
+ }
+
+ /**
+ * Creates a buffer of length finish - start, filled with all values
+ * obtained by dereferencing the InputIterators on the range [start,
+ * finish).
+ *
+ * @throw std::bad_alloc
+ */
+ template < typename InputIterator >
+ basic_buffer(InputIterator start, InputIterator finish):
+ _data(NULL), _size(0)
+ {
+ assign(start, finish);
+ }
+
+ /**
+ * Erases all elements in self then inserts into self a copy of each
+ * element in x.
+ *
+ * Invalidates all references and iterators.
+ *
+ * @returns a reference to self.
+ *
+ * @throw std::bad_alloc
+ */
+ basic_buffer< Allocator >& operator = (
+ const basic_buffer< Allocator >& x)
+ {
+ if (this != &x) {
+ resize(x.size());
+ std::memcpy(_data, x.c_array(), x.size());
+ }
+ return *this;
+ }
+
+ /**
+ * Frees the memory holded by the buffer
+ */
+ ~basic_buffer()
+ { clear(); }
+
+
+ // Iterators
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns a random access iterator that points to the first element.
+ */
+ iterator begin()
+ { return _data; }
+
+ /**
+ * Returns a random access const_iterator that points to the first
+ * element.
+ */
+ const_iterator begin() const
+ { return _data; }
+
+ /**
+ * Returns a random access iterator that points to the past-the-end
+ * value.
+ */
+ iterator end()
+ { return _data ? _data + _size : NULL; }
+
+ /**
+ * Returns a random access const_iterator that points to the
+ * past-the-end value.
+ */
+ const_iterator end() const
+ { return _data ? _data + _size : NULL; }
+
+ /**
+ * Returns a random access reverse_iterator that points to the
+ * past-the-end value.
+ */
+ //reverse_iterator rbegin()
+ //{ return std::reverse_iterator< iterator >(end()); }
+
+ /**
+ * Returns a random access const_reverse_iterator that points to the
+ * past-the-end value.
+ */
+ //const_reverse_iterator rbegin() const
+ //{ return std::reverse_iterator< const iterator >(end()); }
+
+ /**
+ * Returns a random access reverse_iterator that points to the first
+ * element.
+ */
+ //reverse_iterator rend()
+ //{ return std::reverse_iterator< iterator >(begin()); }
+
+ /**
+ * Returns a random access const_reverse_iterator that points to the
+ * first element.
+ */
+ //const_reverse_iterator rend() const
+ //{ return std::reverse_iterator< const iterator >(begin()); }
+
+
+ // Capacity
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns the number of elements.
+ */
+ size_type size() const
+ { return _size; }
+
+ /**
+ * Returns size() of the largest possible buffer.
+ */
+ size_type max_size() const
+ { return std::numeric_limits< size_type >::max(); }
+
+ /**
+ * Alters the size of self.
+ *
+ * If the new size (sz) is greater than the current size, then
+ * sz-size() (uninitialized) elements are inserted at the end of the
+ * buffer. If the new size is smaller than the current capacity, then
+ * the buffer is truncated by erasing size()-sz elements off the end.
+ * If sz is equal to capacity then no action is taken.
+ *
+ * Invalidates all references and iterators.
+ *
+ * @throw std::bad_alloc
+ */
+ void resize(size_type sz)
+ {
+ pointer n_data = _allocate(_data, sz * sizeof(value_type));
+ _data = n_data;
+ _size = sz;
+ }
+
+ /**
+ * Alters the size of self.
+ *
+ * If the new size (sz) is greater than the current size, then
+ * sz-size() copies of value are inserted at the end of the buffer. If
+ * the new size is smaller than the current capacity, then the buffer
+ * is truncated by erasing size()-sz elements off the end. If sz is
+ * equal to capacity then no action is taken.
+ *
+ * Invalidates all references and iterators.
+ *
+ * @throw std::bad_alloc
+ */
+ void resize(size_type sz, value_type value)
+ {
+ size_type old_size = size();
+ resize(sz);
+ if (old_size < sz)
+ std::memset(_data + old_size, value, sz - old_size);
+ }
+
+ /**
+ * Same as size().
+ */
+ size_type capacity() const
+ { return _size; }
+
+ /**
+ * Returns true if the size is zero.
+ */
+ bool empty() const
+ { return !_size; }
+
+ /**
+ * If sz > size() call resize(sz), otherwise do nothing.
+ *
+ * Invalidates all references and iterators in the first case.
+ *
+ * @throw std::bad_alloc
+ */
+ void reserve(size_type sz)
+ {
+ if (sz > size())
+ resize(sz);
+ }
+
+
+ // Element Access
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns a reference to element n of self.
+ *
+ * The result can be used as an lvalue. The index n must be between
+ * 0 and the size less one.
+ */
+ reference operator[](size_type n)
+ { assert(n < _size); return _data[n]; }
+
+ /**
+ * Returns a constant reference to element n of self.
+ *
+ * The index n must be between 0 and the size less one.
+ */
+ const_reference operator[](size_type n) const
+ { assert(n < _size); return _data[n]; }
+
+ /**
+ * Returns a reference to element n of self.
+ *
+ * The result can be used as an lvalue. If index n is not between
+ * 0 and the size less one, a std::out_of_range exception.
+ */
+ reference at(size_type n)
+ {
+ if (n >= _size)
+ throw std::out_of_range("posixx::basic_buffer::at(n)");
+ return _data[n];
+ }
+
+ /**
+ * Returns a constant reference to element n of self.
+ *
+ * If index n is not between 0 and the size less one,
+ * a std::out_of_range exception.
+ */
+ const_reference at(size_type n) const
+ {
+ if (n >= _size)
+ throw std::out_of_range("posixx::basic_buffer::at(n)");
+ return _data[n];
+ }
+
+ /**
+ * Returns a reference to the first element.
+ */
+ reference front()
+ { assert(_size); return _data[0]; }
+
+ /**
+ * Returns a constant reference to the first element.
+ */
+ const_reference front() const
+ { assert(_size); return _data[0]; }
+
+ /**
+ * Returns a reference to the last element.
+ */
+ reference back()
+ { assert(_size); return _data[_size - 1]; }
+
+ /**
+ * Returns a constant reference to the last element.
+ */
+ const_reference back() const
+ { assert(_size); return _data[_size - 1]; }
+
+ /**
+ * Returns a pointer to a C-style array.
+ */
+ pointer c_array()
+ { return _data; }
+
+ /**
+ * Returns a pointer to a read-only C-style array.
+ */
+ const_pointer c_array() const
+ { return _data; }
+
+
+ // Modifiers
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Replaces elements with copies of those in the range [start, finish).
+ *
+ * The function invalidates all iterators and references to elements in
+ * *this.
+ *
+ * Invalidates all references and iterators.
+ */
+ template < typename InputIterator >
+ void assign(InputIterator start, InputIterator finish)
+ {
+ // Check whether it's an integral type. If so, it's not an
+ // iterator.
+ typename std::tr1::is_integral< InputIterator >::type is_int;
+ _assign_dispatch(start, finish, is_int);
+ }
+
+ /**
+ * Replaces elements in *this with n copies of value.
+ *
+ * The function invalidates all iterators and references to elements in
+ * *this.
+ *
+ * Invalidates all references and iterators.
+ */
+ void assign(size_type n, const_reference value)
+ {
+ resize(n);
+ std::memset(_data, value, n);
+ }
+
+ /**
+ * Efficiently swaps the contents of x and y.
+ *
+ * Invalidates all references and iterators.
+ */
+ void swap(basic_buffer< Allocator >& x)
+ {
+ pointer tmp_data = x._data;
+ size_type tmp_size = x._size;
+ x._data = _data;
+ x._size = _size;
+ _data = tmp_data;
+ _size = tmp_size;
+ }
+
+ /**
+ * Deletes all elements from the buffer.
+ *
+ * Invalidates all references and iterators.
+ */
+ void clear()
+ {
+ _data = _allocate(_data, 0);
+ _size = 0;
+ }
+
+protected:
+
+ // The underlying data
+ pointer _data;
+
+ // Size in number of items
+ size_t _size;
+
+ // Allocator wrapper for automatic casting
+ static pointer _allocate(void* ptr, size_t sz)
+ {
+ if (ptr == NULL && sz == 0)
+ return NULL;
+ void* new_ptr = Allocator(ptr, sz);
+ if (sz != 0 && new_ptr == NULL)
+ throw std::bad_alloc();
+ return static_cast< pointer >(new_ptr);
+ }
+
+
+ /*
+ * Helper assign functions to disambiguate the Iterator based and the
+ * N-value copy assign() methods. The last arguments indicates if
+ * InputIterator is an integral type.
+ */
+
+ // This is the version for the integral types, we should use the
+ // "regular" N-value copy assign().
+ template < typename InputIterator >
+ void _assign_dispatch(InputIterator start, InputIterator finish,
+ std::tr1::true_type)
+ {
+ assign(static_cast< size_type >(start),
+ static_cast< value_type >(finish));
+ }
+
+ // This is the version for the real iterators.
+ template < typename InputIterator >
+ void _assign_dispatch(InputIterator start, InputIterator finish,
+ std::tr1::false_type)
+ {
+ // TODO: provide an efficient version for random iterators
+ while (start != finish) {
+ resize(size() + 1);
+ (*this)[size() - 1] = *start;
+ ++start;
+ }
+ }
+
+};
+
+// Nonmember Operators
+//////////////////////////////////////////////////////////////////////
+
+/**
+ * Returns true if x hass the same contents as y.
+ */
+template < void* (*Allocator)(void*, size_t) >
+bool operator == (const basic_buffer< Allocator >& x, const basic_buffer < Allocator >& y)
+{
+ if (&x == &y)
+ return true;
+ if (x.size() != y.size())
+ return false;
+ if (x.empty() && y.empty())
+ return true;
+ if (x.empty() || y.empty())
+ return false;
+ int r = std::memcmp(x.c_array(), y.c_array(),
+ (x.size() < y.size()) ? x.size() : y.size());
+ if (r == 0)
+ return x.size() == y.size();
+ return r == 0;
+}
+
+/**
+ * Returns !(x==y).
+ */
+template < void* (*Allocator)(void*, size_t) >
+bool operator != (const basic_buffer<Allocator>& x, const basic_buffer <Allocator>& y)
+{
+ return !(x == y);
+}
+
+/**
+ * Returns true if the elements contained in x are lexicographically less than
+ * the elements contained in y.
+ */
+template < void* (*Allocator)(void*, size_t) >
+bool operator < (const basic_buffer< Allocator >& x, const basic_buffer< Allocator >& y)
+{
+ if (&x == &y)
+ return false;
+ if (x.empty() && y.empty())
+ return false;
+ if (x.empty())
+ return true;
+ if (y.empty())
+ return false;
+ int r = std::memcmp(x.c_array(), y.c_array(),
+ (x.size() < y.size()) ? x.size() : y.size());
+ if (r == 0)
+ return x.size() < y.size();
+ return r < 0;
+}
+
+/**
+ * Returns y < x.
+ */
+template < void* (*Allocator)(void*, size_t) >
+bool operator > (const basic_buffer< Allocator >& x, const basic_buffer< Allocator >& y)
+{
+ return y < x;
+}
+
+/**
+ * Returns !(y < x).
+ */
+template < void* (*Allocator)(void*, size_t) >
+bool operator <= (const basic_buffer< Allocator >& x, const basic_buffer< Allocator >& y)
+{
+ return !(y < x);
+}
+
+/**
+ * Returns !(x < y).
+ */
+template < void* (*Allocator)(void*, size_t) >
+bool operator >= (const basic_buffer< Allocator >& x, const basic_buffer< Allocator >& y)
+{
+ return !(x < y);
+}
+
+
+// Specialized Algorithms
+//////////////////////////////////////////////////////////////////////
+
+/**
+ * Exchanges self with x, by swapping all elements.
+ *
+ * Invalidates all references and iterators.
+ */
+template < void* (*Allocator)(void*, size_t) >
+void swap(basic_buffer< Allocator >& x, basic_buffer< Allocator >& y)
+{
+ x.swap(y);
+}
+
+} // namespace posixx
+
+#endif // POSIXX_BASIC_BUFFER_HPP_
--- /dev/null
+
+#include <posixx/buffer.hpp> // buffer
+#include <ostream> // std::ostream
+#include <iomanip> // std::hex, setfill, setw
+
+// declared here so boost.Test can see it
+std::ostream& operator << (std::ostream& os, const posixx::buffer& b);
+
+#include <boost/test/unit_test.hpp>
+
+using posixx::buffer;
+
+std::ostream& operator << (std::ostream& os, const posixx::buffer& b)
+{
+ os << "buffer(size=" << b.size() << ", data=";
+ for (posixx::buffer::const_iterator i = b.begin(); i != b.end(); ++i)
+ os << std::hex << std::setfill('0') << std::setw(2) << *i;
+ return os << ")";
+}
+
+// buffer iterators are char*, so they are printed as C-style string, leading
+// to memory problems because they are not usually null-terminated.
+BOOST_TEST_DONT_PRINT_LOG_VALUE( buffer ) // FIXME
+BOOST_TEST_DONT_PRINT_LOG_VALUE( buffer::iterator )
+BOOST_TEST_DONT_PRINT_LOG_VALUE( buffer::const_iterator )
+
+// avoid compilation warning concerning unused variables
+void dummy(buffer::const_iterator i) {}
+
+BOOST_AUTO_TEST_SUITE( buffer_suite )
+
+BOOST_AUTO_TEST_CASE( types_test )
+{
+ buffer::value_type v = 1;
+ buffer::reference r = v;
+ BOOST_CHECK_EQUAL(r, 1);
+ r = 2;
+ BOOST_CHECK_EQUAL(v, 2);
+ buffer::const_reference cr = v;
+ BOOST_CHECK_EQUAL(cr, 2);
+ buffer::iterator i;
+ buffer::const_iterator ci = i;
+ dummy(ci);
+ buffer::size_type s = 5;
+ ++s;
+ buffer::pointer p = &v;
+ BOOST_CHECK_EQUAL(*p, 2);
+ *p = 3;
+ BOOST_CHECK_EQUAL(v, 3);
+ BOOST_CHECK_EQUAL(r, 3);
+ BOOST_CHECK_EQUAL(cr, 3);
+ buffer::const_pointer cp = p;
+ BOOST_CHECK_EQUAL(*cp, 3);
+ buffer::difference_type d = p - cp;
+ BOOST_CHECK_EQUAL(d, 0);
+}
+
+BOOST_AUTO_TEST_CASE( default_constructor_test )
+{
+ buffer b;
+ BOOST_CHECK_EQUAL(b.size(), 0);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ BOOST_CHECK(b.empty());
+ BOOST_CHECK_LT(b.size(), b.max_size());
+ BOOST_CHECK(b.begin() == b.end());
+ //BOOST_CHECK_EQUAL(b.rbegin(), b.rend());
+ BOOST_CHECK_THROW(b.at(b.size()), std::out_of_range);
+ BOOST_CHECK(!b.c_array());
+}
+
+BOOST_AUTO_TEST_CASE( const_default_constructor_test )
+{
+ const buffer b;
+ BOOST_CHECK_EQUAL(b.size(), 0);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ BOOST_CHECK(b.empty());
+ BOOST_CHECK_LT(b.size(), b.max_size());
+ BOOST_CHECK(b.begin() == b.end());
+ //BOOST_CHECK_EQUAL(b.rbegin(), b.rend());
+ BOOST_CHECK_THROW(b.at(b.size()), std::out_of_range);
+ BOOST_CHECK(!b.c_array());
+}
+
+BOOST_AUTO_TEST_CASE( n_constructor_test )
+{
+ buffer b(100);
+ BOOST_CHECK_EQUAL(b.size(), 100);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_LT(b.size(), b.max_size());
+ BOOST_CHECK(b.begin() != b.end());
+ BOOST_CHECK_EQUAL(b.end() - b.begin(), b.size());
+ //BOOST_CHECK_EQUAL(b.rbegin(), b.rend());
+ b[0] = b[b.size()-1];
+ b.at(1) = b.at(b.size()-2);
+ BOOST_CHECK_THROW(b.at(b.size()), std::out_of_range);
+ BOOST_CHECK(b.c_array());
+}
+
+BOOST_AUTO_TEST_CASE( const_n_constructor_test )
+{
+ const buffer b(100);
+ BOOST_CHECK_EQUAL(b.size(), 100);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_LT(b.size(), b.max_size());
+ BOOST_CHECK(b.begin() != b.end());
+ BOOST_CHECK_EQUAL(b.end() - b.begin(), b.size());
+ //BOOST_CHECK_EQUAL(b.rbegin(), b.rend());
+ buffer::value_type x = b[50];
+ ++x;
+ BOOST_CHECK_THROW(b.at(b.size()), std::out_of_range);
+ BOOST_CHECK(b.c_array());
+ for (buffer::const_iterator i = b.begin(); i != b.end(); ++i);
+}
+
+BOOST_AUTO_TEST_CASE( default_n_copy_constructor_test )
+{
+ buffer b(100, 0x5f);
+ BOOST_CHECK_EQUAL(b.size(), 100);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_LT(b.size(), b.max_size());
+ BOOST_CHECK(b.begin() != b.end());
+ BOOST_CHECK_EQUAL(b.end() - b.begin(), b.size());
+ //BOOST_CHECK_EQUAL(b.rbegin(), b.rend());
+ buffer::value_type x = b[50];
+ ++x;
+ BOOST_CHECK_THROW(b.at(b.size()), std::out_of_range);
+ BOOST_CHECK(b.c_array());
+ for (buffer::iterator i = b.begin(); i != b.end(); ++i)
+ BOOST_CHECK_EQUAL(*i, 0x5f);
+ b[b.size()-1] = 0xf5;
+ b[0] = b[b.size()-1];
+ BOOST_CHECK_EQUAL(b[b.size()-1], 0xf5);
+ BOOST_CHECK_EQUAL(b.back(), 0xf5);
+ BOOST_CHECK_EQUAL(*(b.end()-1), 0xf5);
+ BOOST_CHECK_EQUAL(b[0], 0xf5);
+ BOOST_CHECK_EQUAL(b.front(), 0xf5);
+ BOOST_CHECK_EQUAL(*b.begin(), 0xf5);
+ b.at(b.size()-2) = 0xff;
+ b.at(1) = b.at(b.size()-2);
+ BOOST_CHECK_EQUAL(b[b.size()-2], 0xff);
+ BOOST_CHECK_EQUAL(*(b.end()-2), 0xff);
+ BOOST_CHECK_EQUAL(b[1], 0xff);
+ BOOST_CHECK_EQUAL(*(b.begin()+1), 0xff);
+}
+
+BOOST_AUTO_TEST_CASE( copy_constructor_test )
+{
+ buffer b(2);
+ b[0] = 56;
+ b[1] = 123;
+ const buffer bb(b);
+ BOOST_CHECK_EQUAL(b.size(), bb.size());
+ BOOST_CHECK_EQUAL(b.capacity(), bb.capacity());
+ BOOST_CHECK_EQUAL(b.empty(), bb.empty());
+ BOOST_CHECK_EQUAL(b.at(0), bb.at(0));
+ BOOST_CHECK_EQUAL(b.at(1), bb.at(1));
+}
+
+BOOST_AUTO_TEST_CASE( iterator_constructor_test )
+{
+ buffer::value_type a[5] = { 5, 6, 7, 8, 9 };
+ buffer b(a, a + 5);
+ BOOST_CHECK_EQUAL(b.size(), 5);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_LT(b.size(), b.max_size());
+ BOOST_CHECK(b.begin() != b.end());
+ BOOST_CHECK_EQUAL(b.end() - b.begin(), b.size());
+ //BOOST_CHECK_EQUAL(b.rbegin(), b.rend());
+ BOOST_CHECK_THROW(b.at(b.size()), std::out_of_range);
+ BOOST_CHECK(b.c_array());
+ for (int i = 0; i != 5; ++i)
+ BOOST_CHECK_EQUAL(b.at(i), i + 5);
+}
+
+BOOST_AUTO_TEST_CASE( const_iterator_constructor_test )
+{
+ buffer::value_type a[5] = { 5, 6, 7, 8, 9 };
+ const buffer b(a, a + 5);
+ BOOST_CHECK_EQUAL(b.size(), 5);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_LT(b.size(), b.max_size());
+ BOOST_CHECK(b.begin() != b.end());
+ BOOST_CHECK_EQUAL(b.end() - b.begin(), b.size());
+ //BOOST_CHECK_EQUAL(b.rbegin(), b.rend());
+ BOOST_CHECK_THROW(b.at(b.size()), std::out_of_range);
+ BOOST_CHECK(b.c_array());
+ for (int i = 0; i != 5; ++i)
+ BOOST_CHECK_EQUAL(b.at(i), i + 5);
+}
+
+BOOST_AUTO_TEST_CASE( operator_equals_test )
+{
+ buffer::value_type a[] = { 56, 123 };
+ const buffer b(a, a + 2);
+ buffer bb;
+ bb = b;
+ BOOST_CHECK_EQUAL(b.size(), bb.size());
+ BOOST_CHECK_EQUAL(b.capacity(), bb.capacity());
+ BOOST_CHECK_EQUAL(b.empty(), bb.empty());
+ BOOST_CHECK_EQUAL(b.at(0), bb.at(0));
+ BOOST_CHECK_EQUAL(b.at(1), bb.at(1));
+ buffer::pointer p = bb.c_array();
+ bb = bb;
+ BOOST_CHECK_EQUAL(bb.c_array(), p);
+ BOOST_CHECK_EQUAL(b.size(), 2);
+}
+
+BOOST_AUTO_TEST_CASE( iterators_test )
+{
+ buffer::value_type a[] = { 56, 123, 253 };
+ buffer b(a, a + 3);
+ BOOST_CHECK_NE(b.begin(), b.end());
+ BOOST_CHECK_LT(b.begin(), b.end());
+ buffer::iterator i = b.begin();
+ BOOST_CHECK_EQUAL(*i, 56);
+ i++;
+ BOOST_CHECK_EQUAL(*i, 123);
+ ++i;
+ BOOST_CHECK_EQUAL(*i, 253);
+ i += 1;
+ BOOST_CHECK_EQUAL(i, b.end());
+ i--;
+ BOOST_CHECK_EQUAL(*i, 253);
+ --i;
+ BOOST_CHECK_EQUAL(*i, 123);
+ i -= 1;
+ BOOST_CHECK_EQUAL(*i, 56);
+ i++;
+ BOOST_CHECK_EQUAL(*(i + 1), 253);
+ BOOST_CHECK_EQUAL(*(i - 1), 56);
+ BOOST_CHECK_EQUAL(i - 1, b.begin());
+ BOOST_CHECK_EQUAL(i + 2, b.end());
+ BOOST_CHECK_EQUAL(i - b.begin(), 1);
+ *i = 77;
+ BOOST_CHECK_EQUAL(*i, 77);
+ BOOST_CHECK_EQUAL(*(b.begin() + 1), 77);
+}
+
+BOOST_AUTO_TEST_CASE( resize_test )
+{
+ buffer b;
+ BOOST_CHECK(!b.c_array());
+ BOOST_CHECK(b.empty());
+ BOOST_CHECK_EQUAL(b.size(), 0);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ b.resize(10);
+ BOOST_CHECK(b.c_array());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_EQUAL(b.size(), 10);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ b[9] = 1;
+ BOOST_CHECK_EQUAL(b[9], 1);
+ BOOST_CHECK_EQUAL(b.at(9), 1);
+ BOOST_CHECK_EQUAL(b.c_array()[9], 1);
+ b.resize(15, 0x77);
+ BOOST_CHECK(b.c_array());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_EQUAL(b.size(), 15);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ BOOST_CHECK_EQUAL(b[9], 1);
+ BOOST_CHECK_EQUAL(b.at(9), 1);
+ BOOST_CHECK_EQUAL(b.c_array()[9], 1);
+ for (buffer::const_iterator i = b.begin()+10; i != b.end(); ++i)
+ BOOST_CHECK_EQUAL(*i, 0x77);
+ b.resize(0);
+ BOOST_CHECK(!b.c_array());
+ BOOST_CHECK(b.empty());
+ BOOST_CHECK_EQUAL(b.size(), 0);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+}
+
+BOOST_AUTO_TEST_CASE( reserve_test )
+{
+ buffer b;
+ b.reserve(10);
+ BOOST_CHECK(b.c_array());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_EQUAL(b.size(), 10);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ b[9] = 1;
+ BOOST_CHECK_EQUAL(b[9], 1);
+ BOOST_CHECK_EQUAL(b.at(9), 1);
+ BOOST_CHECK_EQUAL(b.c_array()[9], 1);
+ b.reserve(5);
+ BOOST_CHECK(b.c_array());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_EQUAL(b.size(), 10);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ BOOST_CHECK_EQUAL(b[9], 1);
+ b.reserve(20);
+ BOOST_CHECK(b.c_array());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_EQUAL(b.size(), 20);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ BOOST_CHECK_EQUAL(b[9], 1);
+ b.reserve(0);
+ BOOST_CHECK(b.c_array());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_EQUAL(b.size(), 20);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ BOOST_CHECK_EQUAL(b[9], 1);
+}
+
+BOOST_AUTO_TEST_CASE( assign_iterator_test )
+{
+ buffer::value_type a[5] = { 5, 6, 7, 8, 9 };
+ buffer b;
+ BOOST_CHECK(!b.c_array());
+ BOOST_CHECK(b.empty());
+ BOOST_CHECK_EQUAL(b.size(), 0);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ b.assign(a, a + 5);
+ BOOST_CHECK_EQUAL(b.size(), 5);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_LT(b.size(), b.max_size());
+ BOOST_CHECK(b.begin() != b.end());
+ BOOST_CHECK_EQUAL(b.end() - b.begin(), b.size());
+ //BOOST_CHECK_EQUAL(b.rbegin(), b.rend());
+ BOOST_CHECK_THROW(b.at(b.size()), std::out_of_range);
+ BOOST_CHECK(b.c_array());
+ for (int i = 0; i != 5; ++i)
+ BOOST_CHECK_EQUAL(b.at(i), i + 5);
+}
+
+BOOST_AUTO_TEST_CASE( assign_n_copy_test )
+{
+ buffer b(100, 0x5f);
+ b.assign(5, 0x33);
+ BOOST_CHECK_EQUAL(b.size(), 5);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_LT(b.size(), b.max_size());
+ BOOST_CHECK(b.begin() != b.end());
+ BOOST_CHECK_EQUAL(b.end() - b.begin(), b.size());
+ //BOOST_CHECK_EQUAL(b.rbegin(), b.rend());
+ buffer::value_type x = b[2];
+ ++x;
+ BOOST_CHECK_THROW(b.at(b.size()), std::out_of_range);
+ BOOST_CHECK(b.c_array());
+ for (buffer::iterator i = b.begin(); i != b.end(); ++i)
+ BOOST_CHECK_EQUAL(*i, 0x33);
+ b[b.size()-1] = 0x66;
+ b[0] = b[b.size()-1];
+ BOOST_CHECK_EQUAL(b[b.size()-1], 0x66);
+ BOOST_CHECK_EQUAL(b.back(), 0x66);
+ BOOST_CHECK_EQUAL(*(b.end()-1), 0x66);
+ BOOST_CHECK_EQUAL(b[0], 0x66);
+ BOOST_CHECK_EQUAL(b.front(), 0x66);
+ BOOST_CHECK_EQUAL(*b.begin(), 0x66);
+ b.at(b.size()-2) = 0xff;
+ b.at(1) = b.at(b.size()-2);
+ BOOST_CHECK_EQUAL(b[b.size()-2], 0xff);
+ BOOST_CHECK_EQUAL(*(b.end()-2), 0xff);
+ BOOST_CHECK_EQUAL(b[1], 0xff);
+ BOOST_CHECK_EQUAL(*(b.begin()+1), 0xff);
+}
+
+BOOST_AUTO_TEST_CASE( clear_test )
+{
+ buffer b(10);
+ b.clear();
+ BOOST_CHECK(!b.c_array());
+ BOOST_CHECK(b.empty());
+ BOOST_CHECK_EQUAL(b.size(), 0);
+ BOOST_CHECK_EQUAL(b.capacity(), b.size());
+}
+
+BOOST_AUTO_TEST_CASE( operators_test )
+{
+ const buffer b1(5, 78);
+ const buffer b2(5, 78);
+ buffer bb(5, 78);
+ bb[4] = 79;
+ const buffer b3 = bb;
+ bb[4] = 77;
+ const buffer b4 = bb;
+ const buffer b5(4, 78);
+ const buffer b6;
+ bb.clear();
+ const buffer b7 = bb;
+ BOOST_CHECK_EQUAL(b1, b1);
+ BOOST_CHECK_EQUAL(b1, b2);
+ BOOST_CHECK_LE(b1, b2);
+ BOOST_CHECK_GE(b1, b2);
+ BOOST_CHECK_NE(b1, b3);
+ BOOST_CHECK_NE(b1, b4);
+ BOOST_CHECK_NE(b1, b5);
+ BOOST_CHECK_NE(b1, b6);
+ BOOST_CHECK_GT(b1, b4);
+ BOOST_CHECK_GE(b1, b4);
+ BOOST_CHECK_LT(b1, b3);
+ BOOST_CHECK_LE(b1, b3);
+ BOOST_CHECK_GT(b1, b6);
+ BOOST_CHECK_LT(b6, b2);
+ BOOST_CHECK_GE(b3, b6);
+ BOOST_CHECK_LE(b6, b4);
+ BOOST_CHECK_EQUAL(b6, b6);
+ BOOST_CHECK_EQUAL(b6, b7);
+ BOOST_CHECK_GE(b6, b7);
+ BOOST_CHECK_LE(b6, b7);
+}
+
+BOOST_AUTO_TEST_CASE( swap_test )
+{
+ buffer::value_type a1[5] = { 5, 6, 7, 8, 9 };
+ buffer::value_type a2[3] = { 55, 77, 99 };
+ const buffer b1c(a1, a1 + 5);
+ const buffer b2c(a2, a2 + 3);
+ buffer b1 = b1c;
+ buffer b2 = b2c;
+ b1.swap(b2);
+ BOOST_CHECK_EQUAL(b1, b2c);
+ BOOST_CHECK_EQUAL(b2, b1c);
+ posixx::swap(b2, b1);
+ BOOST_CHECK_EQUAL(b1, b1c);
+ BOOST_CHECK_EQUAL(b2, b2c);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+