VISR  0.12.0
Versatile Interactive Scene Renderer
aligned_array.hpp
Go to the documentation of this file.
1 /* Copyright Institute of Sound and Vibration Research - All rights reserved */
2 
3 #ifndef VISR_LIBEFL_ALIGNED_ARRAY_HPP_INCLUDED
4 #define VISR_LIBEFL_ALIGNED_ARRAY_HPP_INCLUDED
5 
6 #include "alignment.hpp"
7 
8 #include <cstddef> // for std::size_t
9 #include <memory>
10 #include <new>
11 #include <stdexcept>
12 #include <utility> // for std::swap
13 
14 // Workaround for the function std::align() missing in the GNU libstdc++ library
15 // (GCC <= 4.9). See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57350
16 // TODO: Remove as soon as feature has been implemented on all supported platforms
17 #ifdef __GLIBCXX__
18 #include <cstdint> // needed for the type std::uintptr_t used in the workaround implementation
19 #endif
20 
21 namespace visr
22 {
23 namespace efl
24 {
25 
32 template< typename ElementType >
34 {
35 public:
46  explicit AlignedArray( std::size_t alignmentElements );
47 
57  explicit AlignedArray( std::size_t length, std::size_t alignmentElements );
58 
63 
70 
71  ~AlignedArray();
72 
78  void resize( std::size_t newLength );
79 
84  void swap( AlignedArray<ElementType>& rhs );
85 
91  std::size_t size() const { return mLength; }
92 
97  std::size_t alignmentElements() const { return mAlignment; }
98 
103  std::size_t alignmentBytes( ) const { return mAlignment * sizeof(ElementType); }
104 
108  ElementType* data() { return mAlignedStorage; }
109 
113  ElementType const * data( ) const { return mAlignedStorage; }
114 
119  ElementType& operator[]( std::size_t index ) { return mAlignedStorage[index]; }
120 
125  ElementType const & operator[]( std::size_t index ) const { return mAlignedStorage[index]; }
126 
133  ElementType& at( std::size_t index )
134  {
135  if( index >= mLength )
136  {
137  throw std::out_of_range( "Array index exceeded" );
138  }
139  return operator[]( index );
140  }
141 
148  ElementType const & at( std::size_t index ) const
149  {
150  if( index >= mLength ) {
151  throw std::out_of_range( "Array index exceeded" );
152  }
153  return (*this)[index];
154  }
155 
156 private:
160  AlignedArray() = delete;
161 
165  AlignedArray( AlignedArray< ElementType > const & ) = delete;
166 
170  void allocate( std::size_t length );
171 
176  void deallocate( );
177 
181  const std::size_t mAlignment;
182 
187  std::size_t mLength;
188 
193  ElementType* mRawStorage;
194 
200  ElementType* mAlignedStorage;
201 };
202 
203 template< typename ElementType>
204 AlignedArray<ElementType>::AlignedArray( std::size_t alignmentElements )
205  : mAlignment( alignmentElements == 0 ? 1 : alignmentElements )
206  , mLength( 0 )
207  , mRawStorage( nullptr )
208  , mAlignedStorage( nullptr )
209 {
210  if( !alignmentIsPowerOfTwo( mAlignment ) )
211  {
212  throw std::invalid_argument( "AlignedArray: alignment values must be integer powers of 2" );
213  }
214 }
215 
216 template< typename ElementType>
217 AlignedArray<ElementType>::AlignedArray( std::size_t length, std::size_t alignmentElements )
218  : AlignedArray( alignmentElements )
219 {
220  if( length > 0 )
221  {
222  allocate( length );
223  }
224  else
225  {
226  mLength = 0;
227  mRawStorage = nullptr;
228  mAlignedStorage = nullptr;
229  }
230 }
231 
232 template< typename ElementType>
234  : AlignedArray( rhs.alignmentElements() )
235 {
236  swap( rhs );
237 }
238 
239 template< typename ElementType>
241 {
242  if( mAlignment != rhs.mAlignment )
243  {
244  throw std::logic_error( "AlignedArray:: objects in move assignment must have the same alignment." );
245  }
246  swap( rhs );
247  rhs.deallocate(); // Not strictly necessary
248  return *this;
249 }
250 
251 template< typename ElementType>
253 {
254  deallocate();
255 }
256 
257 template< typename ElementType>
258 void AlignedArray<ElementType>::resize( std::size_t newLength )
259 {
260  deallocate();
261  if( newLength > 0 )
262  {
263  allocate( newLength );
264  }
265 }
266 
273 template< typename ElementType>
275 {
276  if( mAlignment != rhs.mAlignment )
277  {
278  throw std::logic_error( "AlignedArray::swap(): objects to be swapped must have the same alignment." );
279  }
280  std::swap( mLength, rhs.mLength );
281  std::swap( mRawStorage, rhs.mRawStorage );
282  std::swap( mAlignedStorage, rhs.mAlignedStorage );
283 }
284 
285 #ifdef __GLIBCXX__
286 // Proposed standard-compliant implementation:
287 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57350
288 // Published under the MIT license http://opensource.org/licenses/MIT
289 // Copyright notice (from https://code.google.com/p/c-plus/source/browse/src/util.h):
290 // // Cplus project, general-purpose utilities.
291 // // copyright David Krauss, created 8/26/11
292 static inline void *alignWorkaround( std::size_t alignment, std::size_t size,
293  void *&ptr, std::size_t &space )
294 {
295  std::uintptr_t pn = reinterpret_cast< std::uintptr_t >(ptr);
296  std::uintptr_t aligned = (pn + alignment - 1) & -alignment;
297  std::size_t padding = aligned - pn;
298  if( space < size + padding ) return nullptr;
299  space -= padding;
300  return ptr = reinterpret_cast< void * >(aligned);
301 }
302 #endif
303 
304 template< typename ElementType>
305 void AlignedArray<ElementType>::allocate( std::size_t length )
306 {
307  const std::size_t worstCaseLengthElements( length + mAlignment - 1 );
308  mRawStorage = new ElementType[worstCaseLengthElements];
309  void* retPtr = static_cast<void*>(mRawStorage);
310  std::size_t space = worstCaseLengthElements*sizeof(ElementType);
311  // ignoring the return value is safe, because it is identical to the updated retPtr parameter.
312 #ifdef __GLIBCXX__
313  alignWorkaround( mAlignment*sizeof(ElementType), length*sizeof(ElementType), retPtr, space );
314 #else
315  std::align( mAlignment*sizeof(ElementType), length*sizeof(ElementType), retPtr, space );
316 #endif
317  if( retPtr == nullptr )
318  {
319  deallocate(); // Set the object into a defined, valid state.
320  throw std::bad_alloc();
321  }
322  // todo: should we check the updated 'space' parameter?
323  mAlignedStorage = static_cast<ElementType*>(retPtr);
324  mLength = length;
325 }
326 
327 template< typename ElementType>
328 void AlignedArray<ElementType>::deallocate()
329 {
330  delete[] mRawStorage;
331  mRawStorage = nullptr;
332  mAlignedStorage = nullptr;
333  mLength = 0;
334 }
335 
336 } // namespace efl
337 } // namespace visr
338 
339 #endif // #ifndef VISR_LIBEFL_ALIGNED_ARRAY_HPP_INCLUDED
ElementType * data()
Definition: aligned_array.hpp:108
bool alignmentIsPowerOfTwo(std::size_t alignmentVal)
Definition: alignment.hpp:27
std::size_t size() const
Definition: aligned_array.hpp:91
ElementType & operator[](std::size_t index)
Definition: aligned_array.hpp:119
ElementType const & at(std::size_t index) const
Definition: aligned_array.hpp:148
void resize(std::size_t newLength)
Definition: aligned_array.hpp:258
std::size_t alignmentBytes() const
Definition: aligned_array.hpp:103
Definition: options.cpp:10
ElementType & at(std::size_t index)
Definition: aligned_array.hpp:133
ElementType const * data() const
Definition: aligned_array.hpp:113
std::size_t alignmentElements() const
Definition: aligned_array.hpp:97
~AlignedArray()
Definition: aligned_array.hpp:252
void swap(AlignedArray< ElementType > &rhs)
Definition: aligned_array.hpp:274
Definition: aligned_array.hpp:33
AlignedArray< ElementType > & operator=(AlignedArray< ElementType > &&rhs)
Definition: aligned_array.hpp:240
ElementType const & operator[](std::size_t index) const
Definition: aligned_array.hpp:125