Reference documentation for deal.II version 8.4.2
aligned_vector.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2011 - 2016 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #ifndef dealii__aligned_vector_h
18 #define dealii__aligned_vector_h
19 
20 #include <deal.II/base/config.h>
21 #include <deal.II/base/std_cxx11/type_traits.h>
22 #include <deal.II/base/exceptions.h>
23 #include <deal.II/base/memory_consumption.h>
24 #include <deal.II/base/utilities.h>
25 #include <deal.II/base/parallel.h>
26 #include <boost/serialization/array.hpp>
27 #include <boost/serialization/split_member.hpp>
28 
29 #include <cstring>
30 
31 
32 
33 DEAL_II_NAMESPACE_OPEN
34 
35 
51 template < class T >
53 {
54 public:
59  typedef T value_type;
60  typedef value_type *pointer;
61  typedef const value_type *const_pointer;
62  typedef value_type *iterator;
63  typedef const value_type *const_iterator;
64  typedef value_type &reference;
65  typedef const value_type &const_reference;
66  typedef std::size_t size_type;
67 
71  AlignedVector ();
72 
79  AlignedVector (const size_type size,
80  const T &init = T());
81 
85  ~AlignedVector ();
86 
92  AlignedVector (const AlignedVector<T> &vec);
93 
100  operator = (const AlignedVector<T> &vec);
101 
110  void resize_fast (const size_type size);
111 
120  void resize (const size_type size_in,
121  const T &init = T());
122 
131  void reserve (const size_type size_alloc);
132 
137  void clear ();
138 
144  void push_back (const T in_data);
145 
149  reference back ();
150 
154  const_reference back () const;
155 
160  template <typename ForwardIterator>
161  void insert_back (ForwardIterator begin,
162  ForwardIterator end);
163 
172  void fill (const T &element);
173 
177  void swap (AlignedVector<T> &vec);
178 
182  bool empty () const;
183 
187  size_type size () const;
188 
193  size_type capacity () const;
194 
198  reference
199  operator [] (const size_type index);
200 
204  const_reference operator [] (const size_type index) const;
205 
209  iterator begin ();
210 
214  iterator end ();
215 
219  const_iterator begin () const;
220 
224  const_iterator end () const;
225 
231  size_type memory_consumption () const;
232 
237  template <class Archive>
238  void save (Archive &ar, const unsigned int version) const;
239 
244  template <class Archive>
245  void load (Archive &ar, const unsigned int version);
246 
247  BOOST_SERIALIZATION_SPLIT_MEMBER()
248 
249 private:
250 
254  T *_data;
255 
260 
265 };
266 
267 
268 // ------------------------------- inline functions --------------------------
269 
275 namespace internal
276 {
292  template <typename T>
294  {
295  static const std::size_t minimum_parallel_grain_size = 160000/sizeof(T)+1;
296  public:
307  AlignedVectorMove (T *source_begin,
308  T *source_end,
309  T *destination,
310  const bool copy_source)
311  :
312  source_ (source_begin),
313  destination_ (destination),
314  copy_source_ (copy_source)
315  {
316  Assert (source_end >= source_begin, ExcInternalError());
317  const std::size_t size = source_end - source_begin;
318  if (size < minimum_parallel_grain_size)
319  apply_to_subrange (0, size);
320  else
321  apply_parallel (0, size, minimum_parallel_grain_size);
322  }
323 
328  virtual void apply_to_subrange (const std::size_t begin,
329  const std::size_t end) const
330  {
331  // for classes trivial assignment can use memcpy. cast element to
332  // (void*) to silence compiler warning for virtual classes (they will
333  // never arrive here because they are non-trivial).
334 
335  if (std_cxx11::is_trivial<T>::value == true)
336  std::memcpy ((void *)(destination_+begin), source_+begin,
337  (end-begin)*sizeof(T));
338  else if (copy_source_ == false)
339  for (std::size_t i=begin; i<end; ++i)
340  {
341  // initialize memory (copy construct by placement new), and
342  // destruct the source
343  new (&destination_[i]) T(source_[i]);
344  source_[i].~T();
345  }
346  else
347  for (std::size_t i=begin; i<end; ++i)
348  new (&destination_[i]) T(source_[i]);
349  }
350 
351  private:
352  T *source_;
353  T *destination_;
354  const bool copy_source_;
355  };
356 
368  template <typename T, bool initialize_memory>
370  {
371  static const std::size_t minimum_parallel_grain_size = 160000/sizeof(T)+1;
372  public:
377  AlignedVectorSet (const std::size_t size,
378  const T &element,
379  T *destination)
380  :
381  element_ (element),
382  destination_ (destination),
383  trivial_element (false)
384  {
385  if (size == 0)
386  return;
387 
388  // do not use memcmp for long double because on some systems it does not
389  // completely fill its memory and may lead to false positives in
390  // e.g. valgrind
391  if (std_cxx11::is_trivial<T>::value == true &&
393  {
394  const unsigned char zero [sizeof(T)] = {};
395  // cast element to (void*) to silence compiler warning for virtual
396  // classes (they will never arrive here because they are
397  // non-trivial).
398  if (std::memcmp(zero, (void *)&element, sizeof(T)) == 0)
399  trivial_element = true;
400  }
401  if (size < minimum_parallel_grain_size)
402  apply_to_subrange (0, size);
403  else
404  apply_parallel (0, size, minimum_parallel_grain_size);
405  }
406 
410  virtual void apply_to_subrange (const std::size_t begin,
411  const std::size_t end) const
412  {
413  // for classes with trivial assignment of zero can use memset. cast
414  // element to (void*) to silence compiler warning for virtual
415  // classes (they will never arrive here because they are
416  // non-trivial).
417  if (std_cxx11::is_trivial<T>::value == true && trivial_element)
418  std::memset ((void *)(destination_+begin), 0, (end-begin)*sizeof(T));
419  else
420  copy_construct_or_assign(begin, end,
422  }
423 
424  private:
425  const T &element_;
426  mutable T *destination_;
427  bool trivial_element;
428 
429  // copy assignment operation
430  void copy_construct_or_assign(const std::size_t begin,
431  const std::size_t end,
433  {
434  for (std::size_t i=begin; i<end; ++i)
435  destination_[i] = element_;
436  }
437 
438  // copy constructor (memory initialization)
439  void copy_construct_or_assign(const std::size_t begin,
440  const std::size_t end,
442  {
443  for (std::size_t i=begin; i<end; ++i)
444  new (&destination_[i]) T(element_);
445  }
446  };
447 
448 } // end of namespace internal
449 
450 
451 #ifndef DOXYGEN
452 
453 
454 template < class T >
455 inline
457  :
458  _data (0),
459  _end_data (0),
460  _end_allocated (0)
461 {}
462 
463 
464 
465 template < class T >
466 inline
467 AlignedVector<T>::AlignedVector (const size_type size,
468  const T &init)
469  :
470  _data (0),
471  _end_data (0),
472  _end_allocated (0)
473 {
474  if (size > 0)
475  resize (size, init);
476 }
477 
478 
479 
480 template < class T >
481 inline
483 {
484  clear();
485 }
486 
487 
488 
489 template < class T >
490 inline
492  :
493  _data (0),
494  _end_data (0),
495  _end_allocated (0)
496 {
497  // copy the data from vec
498  reserve (vec._end_data - vec._data);
501 }
502 
503 
504 
505 template < class T >
506 inline
509 {
510  resize(0);
511  resize_fast (vec._end_data - vec._data);
513  return *this;
514 }
515 
516 
517 
518 template < class T >
519 inline
520 void
521 AlignedVector<T>::resize_fast (const size_type size_in)
522 {
523  const size_type old_size = size();
524  if (std_cxx11::is_trivial<T>::value == false && size_in < old_size)
525  {
526  // call destructor on fields that are released. doing it backward
527  // releases the elements in reverse order as compared to how they were
528  // created
529  while (_end_data != _data+size_in)
530  (--_end_data)->~T();
531  }
532  reserve (size_in);
533  _end_data = _data + size_in;
534 
535  // need to still set the values in case the class is non-trivial because
536  // virtual classes etc. need to run their (default) constructor
537  if (std_cxx11::is_trivial<T>::value == false && size_in > old_size)
538  ::internal::AlignedVectorSet<T,true> (size_in-old_size, T(), _data+old_size);
539 }
540 
541 
542 
543 template < class T >
544 inline
545 void
546 AlignedVector<T>::resize (const size_type size_in,
547  const T &init)
548 {
549  const size_type old_size = size();
550  if (std_cxx11::is_trivial<T>::value == false && size_in < old_size)
551  {
552  // call destructor on fields that are released. doing it backward
553  // releases the elements in reverse order as compared to how they were
554  // created
555  while (_end_data != _data+size_in)
556  (--_end_data)->~T();
557  }
558  reserve (size_in);
559  _end_data = _data + size_in;
560 
561  // finally set the desired init values
562  if (size_in > old_size)
563  ::internal::AlignedVectorSet<T,true> (size_in-old_size, init, _data+old_size);
564 }
565 
566 
567 
568 template < class T >
569 inline
570 void
571 AlignedVector<T>::reserve (const size_type size_alloc)
572 {
573  const size_type old_size = _end_data - _data;
574  const size_type allocated_size = _end_allocated - _data;
575  if (size_alloc > allocated_size)
576  {
577  // if we continuously increase the size of the vector, we might be
578  // reallocating a lot of times. therefore, try to increase the size more
579  // aggressively
580  size_type new_size = size_alloc;
581  if (size_alloc < (2 * allocated_size))
582  new_size = 2 * allocated_size;
583 
584  const size_type size_actual_allocate = new_size * sizeof(T);
585 
586  // allocate and align along 64-byte boundaries (this is enough for all
587  // levels of vectorization currently supported by deal.II)
588  T *new_data;
589  Utilities::System::posix_memalign ((void **)&new_data, 64, size_actual_allocate);
590 
591  // copy data in case there was some content before and release the old
592  // memory with the function corresponding to the one used for allocating
593  std::swap (_data, new_data);
594  _end_data = _data + old_size;
595  _end_allocated = _data + new_size;
596  if (_end_data != _data)
597  {
598  ::internal::AlignedVectorMove<T>(new_data, new_data + old_size,
599  _data, false);
600  free(new_data);
601  }
602  else
603  Assert(new_data == 0, ExcInternalError());
604  }
605  else if (size_alloc == 0)
606  clear();
607 }
608 
609 
610 
611 template < class T >
612 inline
613 void
615 {
616  if (_data != 0)
617  {
618  if (std_cxx11::is_trivial<T>::value == false)
619  while (_end_data != _data)
620  (--_end_data)->~T();
621 
622  free(_data);
623  }
624  _data = 0;
625  _end_data = 0;
626  _end_allocated = 0;
627 }
628 
629 
630 
631 template < class T >
632 inline
633 void
634 AlignedVector<T>::push_back (const T in_data)
635 {
636  Assert (_end_data <= _end_allocated, ExcInternalError());
637  if (_end_data == _end_allocated)
638  reserve (std::max(2*capacity(),static_cast<size_type>(16)));
639  if (std_cxx11::is_trivial<T>::value == false)
640  new (_end_data) T;
641  *_end_data++ = in_data;
642 }
643 
644 
645 
646 template < class T >
647 inline
648 typename AlignedVector<T>::reference
650 {
651  AssertIndexRange (0, size());
652  T *field = _end_data - 1;
653  return *field;
654 }
655 
656 
657 
658 template < class T >
659 inline
660 typename AlignedVector<T>::const_reference
661 AlignedVector<T>::back () const
662 {
663  AssertIndexRange (0, size());
664  const T *field = _end_data - 1;
665  return *field;
666 }
667 
668 
669 
670 template < class T >
671 template <typename ForwardIterator>
672 inline
673 void
674 AlignedVector<T>::insert_back (ForwardIterator begin,
675  ForwardIterator end)
676 {
677  const unsigned int old_size = size();
678  reserve (old_size + (end-begin));
679  for ( ; begin != end; ++begin, ++_end_data)
680  {
681  if (std_cxx11::is_trivial<T>::value == false)
682  new (_end_data) T;
683  *_end_data = *begin;
684  }
685 }
686 
687 
688 
689 template < class T >
690 inline
691 void
692 AlignedVector<T>::fill (const T &value)
693 {
695 }
696 
697 
698 
699 template < class T >
700 inline
701 void
703 {
704  std::swap (_data, vec._data);
705  std::swap (_end_data, vec._end_data);
706  std::swap (_end_allocated, vec._end_allocated);
707 }
708 
709 
710 
711 template < class T >
712 inline
713 bool
715 {
716  return _end_data == _data;
717 }
718 
719 
720 
721 template < class T >
722 inline
723 typename AlignedVector<T>::size_type
724 AlignedVector<T>::size () const
725 {
726  return _end_data - _data;
727 }
728 
729 
730 
731 template < class T >
732 inline
733 typename AlignedVector<T>::size_type
735 {
736  return _end_allocated - _data;
737 }
738 
739 
740 
741 template < class T >
742 inline
743 typename AlignedVector<T>::reference
744 AlignedVector<T>::operator [] (const size_type index)
745 {
746  AssertIndexRange (index, size());
747  return _data[index];
748 }
749 
750 
751 
752 template < class T >
753 inline
754 typename AlignedVector<T>::const_reference
755 AlignedVector<T>::operator [] (const size_type index) const
756 {
757  AssertIndexRange (index, size());
758  return _data[index];
759 }
760 
761 
762 
763 template < class T >
764 inline
765 typename AlignedVector<T>::iterator
767 {
768  return _data;
769 }
770 
771 
772 
773 template < class T >
774 inline
775 typename AlignedVector<T>::iterator
777 {
778  return _end_data;
779 }
780 
781 
782 
783 template < class T >
784 inline
785 typename AlignedVector<T>::const_iterator
787 {
788  return _data;
789 }
790 
791 
792 
793 template < class T >
794 inline
795 typename AlignedVector<T>::const_iterator
796 AlignedVector<T>::end () const
797 {
798  return _end_data;
799 }
800 
801 
802 
803 template < class T >
804 template < class Archive >
805 inline
806 void
807 AlignedVector<T>::save (Archive &ar, const unsigned int) const
808 {
809  size_type vec_size (size());
810  ar &vec_size;
811  if (vec_size > 0)
812  ar &boost::serialization::make_array(_data, vec_size);
813 }
814 
815 
816 
817 template < class T >
818 template < class Archive >
819 inline
820 void
821 AlignedVector<T>::load (Archive &ar, const unsigned int)
822 {
823  size_type vec_size = 0;
824  ar &vec_size ;
825 
826  if (vec_size > 0)
827  {
828  reserve(vec_size);
829  ar &boost::serialization::make_array(_data, vec_size);
830  _end_data = _data + vec_size;
831  }
832 }
833 
834 
835 
836 template < class T >
837 inline
838 typename AlignedVector<T>::size_type
840 {
841  size_type memory = sizeof(*this);
842  for (const T *t = _data ; t != _end_data; ++t)
844  memory += sizeof(T) * (_end_allocated-_end_data);
845  return memory;
846 }
847 
848 
849 #endif // ifndef DOXYGEN
850 
851 
857 template < class T >
859  const AlignedVector<T> &rhs)
860 {
861  if (lhs.size() != rhs.size())
862  return false;
863  for (typename AlignedVector<T>::const_iterator lit = lhs.begin(),
864  rit = rhs.begin(); lit != lhs.end(); ++lit, ++rit)
865  if (*lit != *rit)
866  return false;
867  return true;
868 }
869 
870 
871 
872 
878 template < class T >
880  const AlignedVector<T> &rhs)
881 {
882  return !(operator==(lhs, rhs));
883 }
884 
885 
886 DEAL_II_NAMESPACE_CLOSE
887 
888 #endif
#define AssertIndexRange(index, range)
Definition: exceptions.h:1081
void load(Archive &ar, const unsigned int version)
AlignedVector & operator=(const AlignedVector< T > &vec)
void reserve(const size_type size_alloc)
void push_back(const T in_data)
reference operator[](const size_type index)
AlignedVectorSet(const std::size_t size, const T &element, T *destination)
bool operator==(const AlignedVector< T > &lhs, const AlignedVector< T > &rhs)
#define Assert(cond, exc)
Definition: exceptions.h:294
virtual void apply_to_subrange(const std::size_t begin, const std::size_t end) const
void resize(const size_type size_in, const T &init=T())
void posix_memalign(void **memptr, size_t alignment, size_t size)
Definition: utilities.cc:687
void insert_back(ForwardIterator begin, ForwardIterator end)
size_type memory_consumption() const
void swap(AlignedVector< T > &vec)
std_cxx11::enable_if< std_cxx11::is_fundamental< T >::value, std::size_t >::type memory_consumption(const T &t)
void resize_fast(const size_type size)
void save(Archive &ar, const unsigned int version) const
iterator end()
iterator begin()
virtual void apply_to_subrange(const std::size_t begin, const std::size_t end) const
size_type size() const
bool operator!=(const AlignedVector< T > &lhs, const AlignedVector< T > &rhs)
void fill(const T &element)
bool empty() const
AlignedVectorMove(T *source_begin, T *source_end, T *destination, const bool copy_source)
size_type capacity() const
reference back()