1 // Copyright Leandro Lucarella 2008 - 2010.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file COPYING or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
7 #ifndef POSIXX_BASIC_BUFFER_HPP_
8 #define POSIXX_BASIC_BUFFER_HPP_
10 #include <stdexcept> // std::bad_alloc, std::out_of_range
11 #include <limits> // std::numeric_limits
12 #include <tr1/type_traits> // std::tr1::is_integral, true_type, false_type
13 #include <cstdlib> // std::realloc()
14 #include <cstring> // std::memcpy(), memset(), memcmp()
15 #include <cassert> // assert()
16 #include <cstddef> // std::size_t, ptrdiff_t
23 * This is pretty much like using a plain C-style array using dynamic memory,
24 * with a STL-ish interface. Only POD should be stored, since no constructors
25 * or destructors are called.
27 * The buffer will use Allocator (which should be a function with realloc(3)
28 * semantics) for all storage management.
30 template< typename T, void* (*Allocator)(void*, size_t) = &std::realloc >
34 //////////////////////////////////////////////////////////////////////
40 typedef value_type& reference;
43 typedef const value_type& const_reference;
46 typedef value_type* iterator;
49 typedef const value_type* const_iterator;
52 typedef std::size_t size_type;
55 typedef std::ptrdiff_t difference_type;
58 typedef value_type* pointer;
61 typedef const pointer const_pointer;
64 typedef std::reverse_iterator< iterator > reverse_iterator;
67 typedef std::reverse_iterator< const_iterator > const_reverse_iterator;
70 // Construct/Copy/Destroy
71 //////////////////////////////////////////////////////////////////////
74 * Creates a buffer of length zero (the default constructor).
76 explicit basic_buffer(): _data(NULL), _size(0) {}
79 * Creates a buffer with a capacity() of n (uninitialized) elements.
81 * @throw std::bad_alloc
83 explicit basic_buffer(size_type n):
84 _data(_allocate(NULL, n * sizeof(value_type))), _size(n)
89 * Creates a buffer of length n, containing n copies of value.
91 * @throw std::bad_alloc
93 basic_buffer(size_type n, const_reference value):
97 std::memset(_data, value, n);
101 * Creates a copy of x.
103 * @throw std::bad_alloc
105 basic_buffer(const basic_buffer< T, Allocator >& x):
106 _data(_allocate(NULL, x.size() * sizeof(value_type))),
109 std::memcpy(_data, x.c_array(), x.size());
113 * Creates a buffer of length finish - start, filled with all values
114 * obtained by dereferencing the InputIterators on the range [start,
117 * @throw std::bad_alloc
119 template < typename InputIterator >
120 basic_buffer(InputIterator start, InputIterator finish):
121 _data(NULL), _size(0)
123 assign(start, finish);
127 * Erases all elements in self then inserts into self a copy of each
130 * Invalidates all references and iterators.
132 * @returns a reference to self.
134 * @throw std::bad_alloc
136 basic_buffer< T, Allocator >& operator = (
137 const basic_buffer< T, Allocator >& x)
141 std::memcpy(_data, x.c_array(), x.size());
147 * Frees the memory holded by the buffer
154 //////////////////////////////////////////////////////////////////////
157 * Returns a random access iterator that points to the first element.
163 * Returns a random access const_iterator that points to the first
166 const_iterator begin() const
170 * Returns a random access iterator that points to the past-the-end
174 { return _data ? _data + _size : NULL; }
177 * Returns a random access const_iterator that points to the
178 * past-the-end value.
180 const_iterator end() const
181 { return _data ? _data + _size : NULL; }
184 * Returns a random access reverse_iterator that points to the
185 * past-the-end value.
187 reverse_iterator rbegin()
188 { return reverse_iterator(end()); }
191 * Returns a random access const_reverse_iterator that points to the
192 * past-the-end value.
194 const_reverse_iterator rbegin() const
195 { return const_reverse_iterator(end()); }
198 * Returns a random access reverse_iterator that points to the first
201 reverse_iterator rend()
202 { return reverse_iterator(begin()); }
205 * Returns a random access const_reverse_iterator that points to the
208 const_reverse_iterator rend() const
209 { return const_reverse_iterator(begin()); }
213 //////////////////////////////////////////////////////////////////////
216 * Returns the number of elements.
218 size_type size() const
222 * Returns size() of the largest possible buffer.
224 size_type max_size() const
225 { return std::numeric_limits< size_type >::max(); }
228 * Alters the size of self.
230 * If the new size (sz) is greater than the current size, then
231 * sz-size() (uninitialized) elements are inserted at the end of the
232 * buffer. If the new size is smaller than the current capacity, then
233 * the buffer is truncated by erasing size()-sz elements off the end.
234 * If sz is equal to capacity then no action is taken.
236 * Invalidates all references and iterators.
238 * @throw std::bad_alloc
240 void resize(size_type sz)
242 pointer n_data = _allocate(_data, sz * sizeof(value_type));
248 * Alters the size of self.
250 * If the new size (sz) is greater than the current size, then
251 * sz-size() copies of value are inserted at the end of the buffer. If
252 * the new size is smaller than the current capacity, then the buffer
253 * is truncated by erasing size()-sz elements off the end. If sz is
254 * equal to capacity then no action is taken.
256 * Invalidates all references and iterators.
258 * @throw std::bad_alloc
260 void resize(size_type sz, value_type value)
262 size_type old_size = size();
265 std::memset(_data + old_size, value, sz - old_size);
271 size_type capacity() const
275 * Returns true if the size is zero.
281 * If sz > size() call resize(sz), otherwise do nothing.
283 * Invalidates all references and iterators in the first case.
285 * @throw std::bad_alloc
287 void reserve(size_type sz)
295 //////////////////////////////////////////////////////////////////////
298 * Returns a reference to element n of self.
300 * The result can be used as an lvalue. The index n must be between
301 * 0 and the size less one.
303 reference operator[](size_type n)
304 { assert(n < _size); return _data[n]; }
307 * Returns a constant reference to element n of self.
309 * The index n must be between 0 and the size less one.
311 const_reference operator[](size_type n) const
312 { assert(n < _size); return _data[n]; }
315 * Returns a reference to element n of self.
317 * The result can be used as an lvalue. If index n is not between
318 * 0 and the size less one, a std::out_of_range exception.
320 reference at(size_type n)
323 throw std::out_of_range("posixx::basic_buffer::at(n)");
328 * Returns a constant reference to element n of self.
330 * If index n is not between 0 and the size less one,
331 * a std::out_of_range exception.
333 const_reference at(size_type n) const
336 throw std::out_of_range("posixx::basic_buffer::at(n)");
341 * Returns a reference to the first element.
344 { assert(_size); return _data[0]; }
347 * Returns a constant reference to the first element.
349 const_reference front() const
350 { assert(_size); return _data[0]; }
353 * Returns a reference to the last element.
356 { assert(_size); return _data[_size - 1]; }
359 * Returns a constant reference to the last element.
361 const_reference back() const
362 { assert(_size); return _data[_size - 1]; }
365 * Returns a pointer to a C-style array.
371 * Returns a pointer to a read-only C-style array.
373 const_pointer c_array() const
378 //////////////////////////////////////////////////////////////////////
381 * Replaces elements with copies of those in the range [start, finish).
383 * The function invalidates all iterators and references to elements in
386 * Invalidates all references and iterators.
388 template < typename InputIterator >
389 void assign(InputIterator start, InputIterator finish)
391 // Check whether it's an integral type. If so, it's not an
393 typename std::tr1::is_integral< InputIterator >::type is_int;
394 _assign_dispatch(start, finish, is_int);
398 * Replaces elements in *this with n copies of value.
400 * The function invalidates all iterators and references to elements in
403 * Invalidates all references and iterators.
405 void assign(size_type n, const_reference value)
408 std::memset(_data, value, n);
412 * Efficiently swaps the contents of x and y.
414 * Invalidates all references and iterators.
416 void swap(basic_buffer< T, Allocator >& x)
418 pointer tmp_data = x._data;
419 size_type tmp_size = x._size;
427 * Deletes all elements from the buffer.
429 * Invalidates all references and iterators.
433 _data = _allocate(_data, 0);
439 // The underlying data
442 // Size in number of items
445 // Allocator wrapper for automatic casting
446 static pointer _allocate(void* ptr, std::size_t sz)
448 if (ptr == NULL && sz == 0)
450 void* new_ptr = Allocator(ptr, sz);
451 if (sz != 0 && new_ptr == NULL)
452 throw std::bad_alloc();
453 return static_cast< pointer >(new_ptr);
458 * Helper assign functions to disambiguate the Iterator based and the
459 * N-value copy assign() methods. The last arguments indicates if
460 * InputIterator is an integral type.
463 // This is the version for the integral types, we should use the
464 // "regular" N-value copy assign().
465 template < typename InputIterator >
466 void _assign_dispatch(InputIterator start, InputIterator finish,
469 assign(static_cast< size_type >(start),
470 static_cast< value_type >(finish));
473 // This is the version for the real iterators.
474 template < typename InputIterator >
475 void _assign_dispatch(InputIterator start, InputIterator finish,
476 std::tr1::false_type)
478 // TODO: provide an efficient version for random iterators
479 while (start != finish) {
481 (*this)[size() - 1] = *start;
488 // Nonmember Operators
489 //////////////////////////////////////////////////////////////////////
492 * Returns true if x hass the same contents as y.
494 template < typename T, void* (*Allocator)(void*, std::size_t) >
495 bool operator == (const basic_buffer< T, Allocator >& x,
496 const basic_buffer < T, Allocator >& y)
500 if (x.size() != y.size())
502 if (x.empty() && y.empty())
504 if (x.empty() || y.empty())
506 int r = std::memcmp(x.c_array(), y.c_array(),
507 (x.size() < y.size()) ? x.size() : y.size());
509 return x.size() == y.size();
516 template < typename T, void* (*Allocator)(void*, std::size_t) >
517 bool operator != (const basic_buffer< T, Allocator >& x,
518 const basic_buffer < T, Allocator >& y)
524 * Returns true if the elements contained in x are lexicographically less than
525 * the elements contained in y.
527 template < typename T, void* (*Allocator)(void*, std::size_t) >
528 bool operator < (const basic_buffer< T, Allocator >& x,
529 const basic_buffer< T, Allocator >& y)
533 if (x.empty() && y.empty())
539 int r = std::memcmp(x.c_array(), y.c_array(),
540 (x.size() < y.size()) ? x.size() : y.size());
542 return x.size() < y.size();
549 template < typename T, void* (*Allocator)(void*, std::size_t) >
550 bool operator > (const basic_buffer< T, Allocator >& x,
551 const basic_buffer< T, Allocator >& y)
559 template < typename T, void* (*Allocator)(void*, std::size_t) >
560 bool operator <= (const basic_buffer< T, Allocator >& x,
561 const basic_buffer< T, Allocator >& y)
569 template < typename T, void* (*Allocator)(void*, std::size_t) >
570 bool operator >= (const basic_buffer< T, Allocator >& x,
571 const basic_buffer< T, Allocator >& y)
577 // Specialized Algorithms
578 //////////////////////////////////////////////////////////////////////
581 * Exchanges self with x, by swapping all elements.
583 * Invalidates all references and iterators.
585 template < typename T, void* (*Allocator)(void*, std::size_t) >
586 void swap(basic_buffer< T, Allocator >& x, basic_buffer< T, Allocator >& y)
591 } // namespace posixx
593 #endif // POSIXX_BASIC_BUFFER_HPP_