/libs/co/base/buffer.h

https://github.com/MichaelVlad/Equalizer · C Header · 255 lines · 129 code · 40 blank · 86 comment · 8 complexity · a8438e42112fe321c9c6b428e8ffd9b3 MD5 · raw file

  1. /* Copyright (c) 2007-2011, Stefan Eilemann <eile@equalizergraphics.com>
  2. *
  3. * This library is free software; you can redistribute it and/or modify it under
  4. * the terms of the GNU Lesser General Public License version 2.1 as published
  5. * by the Free Software Foundation.
  6. *
  7. * This library is distributed in the hope that it will be useful, but WITHOUT
  8. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  10. * details.
  11. *
  12. * You should have received a copy of the GNU Lesser General Public License
  13. * along with this library; if not, write to the Free Software Foundation, Inc.,
  14. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #ifndef COBASE_BUFFER_H
  17. #define COBASE_BUFFER_H
  18. #include <co/base/debug.h> // EQASSERT macro
  19. #include <co/base/types.h>
  20. #include <cstdlib> // for malloc
  21. namespace co
  22. {
  23. namespace base
  24. {
  25. /**
  26. * A simple memory buffer with some helper functions.
  27. *
  28. * For bigger data (>100k) using a std::vector< uint8_t > has a high
  29. * overhead when resizing (>1ms). This buffer just memcpy's elements, i.e.,
  30. * it should only be used for PODs since the copy constructor or assignment
  31. * operator is not called on the copied elements. Primarily used for binary
  32. * data, e.g., in eq::Image. The implementation works like a pool, that is,
  33. * data is only released when the buffer is deleted or clear() is called.
  34. */
  35. template< typename T > class Buffer
  36. {
  37. public:
  38. /** Construct a new, empty buffer. @version 1.0 */
  39. Buffer() : _data(0), _size(0), _maxSize(0) {}
  40. /** Construct a new buffer of the given size. @version 1.0 */
  41. Buffer( const uint64_t size ) : _data(0), _size(0), _maxSize(0)
  42. { reset( size ); }
  43. /** Destruct the buffer. @version 1.0 */
  44. ~Buffer() { clear(); }
  45. /** Flush the buffer, deleting all data. @version 1.0 */
  46. void clear()
  47. { if( _data ) free( _data ); _data=0; _size=0; _maxSize=0; }
  48. /**
  49. * Tighten the allocated memory to the size of the buffer.
  50. * @return the new pointer to the first element.
  51. * @version 1.0
  52. */
  53. T* pack()
  54. {
  55. if( _maxSize != _size )
  56. {
  57. _data = static_cast< T* >( realloc( _data,
  58. _size * sizeof( T )));
  59. _maxSize = _size;
  60. }
  61. return _data;
  62. }
  63. /** Copy constructor, transfers ownership to new Buffer. @version 1.0 */
  64. Buffer( Buffer& from )
  65. {
  66. _data = from._data; _size = from._size; _maxSize =from._maxSize;
  67. from._data = 0; from._size = 0; from._maxSize = 0;
  68. }
  69. /** Assignment operator, copies data from Buffer. @version 1.0 */
  70. const Buffer& operator = ( Buffer& from )
  71. {
  72. replace( from._data, from._size );
  73. return *this;
  74. }
  75. /** Direct access to the element at the given index. @version 1.0 */
  76. T& operator[]( const uint64_t position )
  77. { EQASSERT( _size > position ); return _data[ position ]; }
  78. /** Direct const access to an element. @version 1.0 */
  79. const T& operator[]( const uint64_t position ) const
  80. { EQASSERT( _size > position ); return _data[ position ]; }
  81. /**
  82. * Ensure that the buffer contains at least newSize elements.
  83. *
  84. * Existing data is retained. The size is set.
  85. * @return the new pointer to the first element.
  86. * @version 1.0
  87. */
  88. T* resize( const uint64_t newSize )
  89. {
  90. _size = newSize;
  91. if( newSize <= _maxSize )
  92. return _data;
  93. // avoid excessive reallocs
  94. const uint64_t nElems = newSize + (newSize >> 3);
  95. const uint64_t nBytes = nElems * sizeof( T );
  96. _data = static_cast< T* >( realloc( _data, nBytes ));
  97. _maxSize = nElems;
  98. return _data;
  99. }
  100. /**
  101. * Ensure that the buffer contains at least newSize elements.
  102. *
  103. * Existing data is retained. The size is increased, if necessary.
  104. * @version 1.0
  105. */
  106. void grow( const uint64_t newSize )
  107. {
  108. if( newSize > _size )
  109. resize( newSize );
  110. }
  111. /**
  112. * Ensure that the buffer contains at least newSize elements.
  113. *
  114. * Existing data may be deleted.
  115. * @return the new pointer to the first element.
  116. * @version 1.0
  117. */
  118. T* reserve( const uint64_t newSize )
  119. {
  120. if( newSize <= _maxSize )
  121. return _data;
  122. if( _data )
  123. free( _data );
  124. _data = static_cast< T* >( malloc( newSize * sizeof( T )));
  125. _maxSize = newSize;
  126. return _data;
  127. }
  128. /**
  129. * Set the buffer size and malloc enough memory.
  130. *
  131. * Existing data may be deleted.
  132. * @return the new pointer to the first element.
  133. * @version 1.0
  134. */
  135. T* reset( const uint64_t newSize )
  136. {
  137. reserve( newSize );
  138. setSize( newSize );
  139. return _data;
  140. }
  141. /** Append elements to the buffer, increasing the size. @version 1.0 */
  142. void append( const T* data, const uint64_t size )
  143. {
  144. EQASSERT( data );
  145. EQASSERT( size );
  146. const uint64_t oldSize = _size;
  147. resize( oldSize + size );
  148. memcpy( _data + oldSize, data, size * sizeof( T ));
  149. }
  150. /** Append one element to the buffer. @version 1.0 */
  151. void append( const T& element )
  152. {
  153. resize( _size + 1 );
  154. _data[ _size - 1 ] = element;
  155. }
  156. /** Replace the existing data with new data. @version 1.0 */
  157. void replace( const void* data, const uint64_t size )
  158. {
  159. EQASSERT( data );
  160. EQASSERT( size );
  161. reserve( size );
  162. memcpy( _data, data, size * sizeof( T ));
  163. _size = size;
  164. }
  165. /** Swap the buffer contents with another Buffer. @version 1.0 */
  166. void swap( Buffer& buffer )
  167. {
  168. T* tmpData = buffer._data;
  169. const uint64_t tmpSize = buffer._size;
  170. const uint64_t tmpMaxSize = buffer._maxSize;
  171. buffer._data = _data;
  172. buffer._size = _size;
  173. buffer._maxSize = _maxSize;
  174. _data = tmpData;
  175. _size = tmpSize;
  176. _maxSize = tmpMaxSize;
  177. }
  178. /** @return a pointer to the data. @version 1.0 */
  179. T* getData() { return _data; }
  180. /** @return a const pointer to the data. @version 1.0 */
  181. const T* getData() const { return _data; }
  182. /**
  183. * Set the size of the buffer without changing its allocation.
  184. *
  185. * This method only modifies the size parameter. If the current
  186. * allocation of the buffer is too small, it asserts, returns false and
  187. * does not change the size.
  188. * @version 1.0
  189. */
  190. bool setSize( const uint64_t size )
  191. {
  192. EQASSERT( size <= _maxSize );
  193. if( size > _maxSize )
  194. return false;
  195. _size = size;
  196. return true;
  197. }
  198. /** @return the current size. @version 1.0 */
  199. uint64_t getSize() const { return _size; }
  200. /** @return true if the buffer is empty, false if not. @version 1.0 */
  201. bool isEmpty() const { return (_size==0); }
  202. /** @return the maximum size of the buffer. @version 1.0 */
  203. uint64_t getMaxSize() const { return _maxSize; }
  204. private:
  205. /** A pointer to the data. */
  206. T* _data;
  207. /** The number of valid items in _data. */
  208. uint64_t _size;
  209. /** The allocation _size of the buffer. */
  210. uint64_t _maxSize;
  211. };
  212. typedef Buffer< uint8_t > Bufferb;
  213. }
  214. }
  215. #endif //COBASE_BUFFER_H