]> git.llucax.com Git - software/posixx.git/commitdiff
Add posix::basic_buffer template and posix::buffer class
authorLeandro Lucarella <llucarella@integratech.com.ar>
Wed, 8 Oct 2008 16:40:50 +0000 (13:40 -0300)
committerLeandro Lucarella <llucarella@integratech.com.ar>
Wed, 8 Oct 2008 19:03:46 +0000 (16:03 -0300)
posixx::basic_buffer provides easy to use, STL-container-lke and
exception-safe class to manipulate buffers. It's a pseudo-static array
(you can resize it but you can't append or insert/remove arbitrary
elements). It's parametrized to support different kinds of allocators (not
in the STL-sense, it uses a realloc-like function).

posix::buffer is just a posix::basic_buffer< &realloc >.

src/basic_buffer.hpp [new file with mode: 0644]
src/buffer.hpp [new file with mode: 0644]
test/buffer.cpp [new file with mode: 0644]

diff --git a/src/basic_buffer.hpp b/src/basic_buffer.hpp
new file mode 100644 (file)
index 0000000..494043f
--- /dev/null
@@ -0,0 +1,581 @@
+#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_
diff --git a/src/buffer.hpp b/src/buffer.hpp
new file mode 100644 (file)
index 0000000..8613d23
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef POSIXX_BUFFER_HPP_
+#define POSIXX_BUFFER_HPP_
+
+#include "basic_buffer.hpp" // posixx::basic_buffer
+
+#include <cstdlib> // std::realloc()
+
+namespace posixx {
+
+/// A buffer that uses realloc(3) for memory management.
+typedef basic_buffer< &std::realloc > buffer;
+
+} // namespace posixx
+
+#endif // POSIXX_BUFFER_HPP_
diff --git a/test/buffer.cpp b/test/buffer.cpp
new file mode 100644 (file)
index 0000000..f455ea5
--- /dev/null
@@ -0,0 +1,426 @@
+
+#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()
+