From 5cc37d5e30b015c36f850c0d49a7da35c925c321 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 8 Oct 2008 13:40:50 -0300 Subject: [PATCH] Add posix::basic_buffer template and posix::buffer class 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 | 581 +++++++++++++++++++++++++++++++++++++++++++ src/buffer.hpp | 15 ++ test/buffer.cpp | 426 +++++++++++++++++++++++++++++++ 3 files changed, 1022 insertions(+) create mode 100644 src/basic_buffer.hpp create mode 100644 src/buffer.hpp create mode 100644 test/buffer.cpp diff --git a/src/basic_buffer.hpp b/src/basic_buffer.hpp new file mode 100644 index 0000000..494043f --- /dev/null +++ b/src/basic_buffer.hpp @@ -0,0 +1,581 @@ +#ifndef POSIXX_BASIC_BUFFER_HPP_ +#define POSIXX_BASIC_BUFFER_HPP_ + +#include // std::bad_alloc, std::out_of_range +#include // std::numeric_limits +#include // std::tr1::is_integral, true_type, false_type +#include // std::memcpy(), memset(), memcmp() +#include // 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& x, const basic_buffer & 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 index 0000000..8613d23 --- /dev/null +++ b/src/buffer.hpp @@ -0,0 +1,15 @@ +#ifndef POSIXX_BUFFER_HPP_ +#define POSIXX_BUFFER_HPP_ + +#include "basic_buffer.hpp" // posixx::basic_buffer + +#include // 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 index 0000000..f455ea5 --- /dev/null +++ b/test/buffer.cpp @@ -0,0 +1,426 @@ + +#include // buffer +#include // std::ostream +#include // std::hex, setfill, setw + +// declared here so boost.Test can see it +std::ostream& operator << (std::ostream& os, const posixx::buffer& b); + +#include + +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() + -- 2.43.0