Reference documentation for deal.II version 8.5.1
aligned_vector.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2011 - 2017 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 
27 // boost::serialization::make_array used to be in array.hpp, but was
28 // moved to a different file in BOOST 1.64
29 #include <boost/version.hpp>
30 #if BOOST_VERSION >= 106400
31 # include <boost/serialization/array_wrapper.hpp>
32 #else
33 # include <boost/serialization/array.hpp>
34 #endif
35 #include <boost/serialization/split_member.hpp>
36 
37 #include <cstring>
38 
39 
40 
41 DEAL_II_NAMESPACE_OPEN
42 
43 
59 template < class T >
61 {
62 public:
67  typedef T value_type;
68  typedef value_type *pointer;
69  typedef const value_type *const_pointer;
70  typedef value_type *iterator;
71  typedef const value_type *const_iterator;
72  typedef value_type &reference;
73  typedef const value_type &const_reference;
74  typedef std::size_t size_type;
75 
79  AlignedVector ();
80 
87  AlignedVector (const size_type size,
88  const T &init = T());
89 
93  ~AlignedVector ();
94 
100  AlignedVector (const AlignedVector<T> &vec);
101 
102 #ifdef DEAL_II_WITH_CXX11
103 
110 #endif
111 
117  AlignedVector &
118  operator = (const AlignedVector<T> &vec);
119 
120 #ifdef DEAL_II_WITH_CXX11
121 
126  AlignedVector &
128 #endif
129 
138  void resize_fast (const size_type size);
139 
148  void resize (const size_type size_in,
149  const T &init = T());
150 
159  void reserve (const size_type size_alloc);
160 
165  void clear ();
166 
172  void push_back (const T in_data);
173 
177  reference back ();
178 
182  const_reference back () const;
183 
188  template <typename ForwardIterator>
189  void insert_back (ForwardIterator begin,
190  ForwardIterator end);
191 
200  void fill (const T &element);
201 
205  void swap (AlignedVector<T> &vec);
206 
210  bool empty () const;
211 
215  size_type size () const;
216 
221  size_type capacity () const;
222 
226  reference
227  operator [] (const size_type index);
228 
232  const_reference operator [] (const size_type index) const;
233 
237  iterator begin ();
238 
242  iterator end ();
243 
247  const_iterator begin () const;
248 
252  const_iterator end () const;
253 
259  size_type memory_consumption () const;
260 
265  template <class Archive>
266  void save (Archive &ar, const unsigned int version) const;
267 
272  template <class Archive>
273  void load (Archive &ar, const unsigned int version);
274 
275  BOOST_SERIALIZATION_SPLIT_MEMBER()
276 
277 private:
278 
282  T *_data;
283 
288 
293 };
294 
295 
296 // ------------------------------- inline functions --------------------------
297 
303 namespace internal
304 {
320  template <typename T>
322  {
323  static const std::size_t minimum_parallel_grain_size = 160000/sizeof(T)+1;
324  public:
335  AlignedVectorMove (T *source_begin,
336  T *source_end,
337  T *destination,
338  const bool copy_source)
339  :
340  source_ (source_begin),
341  destination_ (destination),
342  copy_source_ (copy_source)
343  {
344  Assert (source_end >= source_begin, ExcInternalError());
345  const std::size_t size = source_end - source_begin;
346  if (size < minimum_parallel_grain_size)
347  apply_to_subrange (0, size);
348  else
349  apply_parallel (0, size, minimum_parallel_grain_size);
350  }
351 
356  virtual void apply_to_subrange (const std::size_t begin,
357  const std::size_t end) const
358  {
359  if (end == begin)
360  return;
361 
362  // for classes trivial assignment can use memcpy. cast element to
363  // (void*) to silence compiler warning for virtual classes (they will
364  // never arrive here because they are non-trivial).
365 
366  if (std_cxx11::is_trivial<T>::value == true)
367  std::memcpy ((void *)(destination_+begin), (void *)(source_+begin),
368  (end-begin)*sizeof(T));
369  else if (copy_source_ == false)
370  for (std::size_t i=begin; i<end; ++i)
371  {
372  // initialize memory (copy construct by placement new), and
373  // destruct the source
374  new (&destination_[i]) T(source_[i]);
375  source_[i].~T();
376  }
377  else
378  for (std::size_t i=begin; i<end; ++i)
379  new (&destination_[i]) T(source_[i]);
380  }
381 
382  private:
383  T *source_;
384  T *destination_;
385  const bool copy_source_;
386  };
387 
399  template <typename T, bool initialize_memory>
401  {
402  static const std::size_t minimum_parallel_grain_size = 160000/sizeof(T)+1;
403  public:
408  AlignedVectorSet (const std::size_t size,
409  const T &element,
410  T *destination)
411  :
412  element_ (element),
413  destination_ (destination),
414  trivial_element (false)
415  {
416  if (size == 0)
417  return;
418 
419  // do not use memcmp for long double because on some systems it does not
420  // completely fill its memory and may lead to false positives in
421  // e.g. valgrind
422  if (std_cxx11::is_trivial<T>::value == true &&
424  {
425  const unsigned char zero [sizeof(T)] = {};
426  // cast element to (void*) to silence compiler warning for virtual
427  // classes (they will never arrive here because they are
428  // non-trivial).
429  if (std::memcmp(zero, (void *)&element, sizeof(T)) == 0)
430  trivial_element = true;
431  }
432  if (size < minimum_parallel_grain_size)
433  apply_to_subrange (0, size);
434  else
435  apply_parallel (0, size, minimum_parallel_grain_size);
436  }
437 
441  virtual void apply_to_subrange (const std::size_t begin,
442  const std::size_t end) const
443  {
444  // for classes with trivial assignment of zero can use memset. cast
445  // element to (void*) to silence compiler warning for virtual
446  // classes (they will never arrive here because they are
447  // non-trivial).
448  if (std_cxx11::is_trivial<T>::value == true && trivial_element)
449  std::memset ((void *)(destination_+begin), 0, (end-begin)*sizeof(T));
450  else
451  copy_construct_or_assign(begin, end,
453  }
454 
455  private:
456  const T &element_;
457  mutable T *destination_;
458  bool trivial_element;
459 
460  // copy assignment operation
461  void copy_construct_or_assign(const std::size_t begin,
462  const std::size_t end,
464  {
465  for (std::size_t i=begin; i<end; ++i)
466  destination_[i] = element_;
467  }
468 
469  // copy constructor (memory initialization)
470  void copy_construct_or_assign(const std::size_t begin,
471  const std::size_t end,
473  {
474  for (std::size_t i=begin; i<end; ++i)
475  new (&destination_[i]) T(element_);
476  }
477  };
478 
479 } // end of namespace internal
480 
481 
482 #ifndef DOXYGEN
483 
484 
485 template < class T >
486 inline
488  :
489  _data (0),
490  _end_data (0),
491  _end_allocated (0)
492 {}
493 
494 
495 
496 template < class T >
497 inline
498 AlignedVector<T>::AlignedVector (const size_type size,
499  const T &init)
500  :
501  _data (0),
502  _end_data (0),
503  _end_allocated (0)
504 {
505  if (size > 0)
506  resize (size, init);
507 }
508 
509 
510 
511 template < class T >
512 inline
514 {
515  clear();
516 }
517 
518 
519 
520 template < class T >
521 inline
523  :
524  _data (0),
525  _end_data (0),
526  _end_allocated (0)
527 {
528  // copy the data from vec
529  reserve (vec._end_data - vec._data);
530  _end_data = _end_allocated;
531  internal::AlignedVectorMove<T> (vec._data, vec._end_data, _data, true);
532 }
533 
534 
535 
536 #ifdef DEAL_II_WITH_CXX11
537 template < class T >
538 inline
540  :
541  _data (vec._data),
542  _end_data (vec._end_data),
543  _end_allocated (vec._end_allocated)
544 {
545  vec._data = nullptr;
546  vec._end_data = nullptr;
547  vec._end_allocated = nullptr;
548 }
549 #endif
550 
551 
552 
553 template < class T >
554 inline
557 {
558  resize(0);
559  resize_fast (vec._end_data - vec._data);
560  internal::AlignedVectorMove<T> (vec._data, vec._end_data, _data, true);
561  return *this;
562 }
563 
564 
565 
566 #ifdef DEAL_II_WITH_CXX11
567 template < class T >
568 inline
571 {
572  clear();
573 
574  _data = vec._data;
575  _end_data = vec._end_data;
576  _end_allocated = vec._end_allocated;
577 
578  vec._data = nullptr;
579  vec._end_data = nullptr;
580  vec._end_allocated = nullptr;
581 
582  return *this;
583 }
584 #endif
585 
586 
587 
588 template < class T >
589 inline
590 void
591 AlignedVector<T>::resize_fast (const size_type size_in)
592 {
593  const size_type old_size = size();
594  if (std_cxx11::is_trivial<T>::value == false && size_in < old_size)
595  {
596  // call destructor on fields that are released. doing it backward
597  // releases the elements in reverse order as compared to how they were
598  // created
599  while (_end_data != _data+size_in)
600  (--_end_data)->~T();
601  }
602  reserve (size_in);
603  _end_data = _data + size_in;
604 
605  // need to still set the values in case the class is non-trivial because
606  // virtual classes etc. need to run their (default) constructor
607  if (std_cxx11::is_trivial<T>::value == false && size_in > old_size)
608  ::internal::AlignedVectorSet<T,true> (size_in-old_size, T(), _data+old_size);
609 }
610 
611 
612 
613 template < class T >
614 inline
615 void
616 AlignedVector<T>::resize (const size_type size_in,
617  const T &init)
618 {
619  const size_type old_size = size();
620  if (std_cxx11::is_trivial<T>::value == false && size_in < old_size)
621  {
622  // call destructor on fields that are released. doing it backward
623  // releases the elements in reverse order as compared to how they were
624  // created
625  while (_end_data != _data+size_in)
626  (--_end_data)->~T();
627  }
628  reserve (size_in);
629  _end_data = _data + size_in;
630 
631  // finally set the desired init values
632  if (size_in > old_size)
633  ::internal::AlignedVectorSet<T,true> (size_in-old_size, init, _data+old_size);
634 }
635 
636 
637 
638 template < class T >
639 inline
640 void
641 AlignedVector<T>::reserve (const size_type size_alloc)
642 {
643  const size_type old_size = _end_data - _data;
644  const size_type allocated_size = _end_allocated - _data;
645  if (size_alloc > allocated_size)
646  {
647  // if we continuously increase the size of the vector, we might be
648  // reallocating a lot of times. therefore, try to increase the size more
649  // aggressively
650  size_type new_size = size_alloc;
651  if (size_alloc < (2 * allocated_size))
652  new_size = 2 * allocated_size;
653 
654  const size_type size_actual_allocate = new_size * sizeof(T);
655 
656  // allocate and align along 64-byte boundaries (this is enough for all
657  // levels of vectorization currently supported by deal.II)
658  T *new_data;
659  Utilities::System::posix_memalign ((void **)&new_data, 64, size_actual_allocate);
660 
661  // copy data in case there was some content before and release the old
662  // memory with the function corresponding to the one used for allocating
663  std::swap (_data, new_data);
664  _end_data = _data + old_size;
665  _end_allocated = _data + new_size;
666  if (_end_data != _data)
667  {
668  ::internal::AlignedVectorMove<T>(new_data, new_data + old_size,
669  _data, false);
670  free(new_data);
671  }
672  else
673  Assert(new_data == 0, ExcInternalError());
674  }
675  else if (size_alloc == 0)
676  clear();
677 }
678 
679 
680 
681 template < class T >
682 inline
683 void
685 {
686  if (_data != 0)
687  {
688  if (std_cxx11::is_trivial<T>::value == false)
689  while (_end_data != _data)
690  (--_end_data)->~T();
691 
692  free(_data);
693  }
694  _data = 0;
695  _end_data = 0;
696  _end_allocated = 0;
697 }
698 
699 
700 
701 template < class T >
702 inline
703 void
704 AlignedVector<T>::push_back (const T in_data)
705 {
706  Assert (_end_data <= _end_allocated, ExcInternalError());
707  if (_end_data == _end_allocated)
708  reserve (std::max(2*capacity(),static_cast<size_type>(16)));
709  if (std_cxx11::is_trivial<T>::value == false)
710  new (_end_data++) T(in_data);
711  else
712  *_end_data++ = in_data;
713 }
714 
715 
716 
717 template < class T >
718 inline
719 typename AlignedVector<T>::reference
721 {
722  AssertIndexRange (0, size());
723  T *field = _end_data - 1;
724  return *field;
725 }
726 
727 
728 
729 template < class T >
730 inline
731 typename AlignedVector<T>::const_reference
732 AlignedVector<T>::back () const
733 {
734  AssertIndexRange (0, size());
735  const T *field = _end_data - 1;
736  return *field;
737 }
738 
739 
740 
741 template < class T >
742 template <typename ForwardIterator>
743 inline
744 void
745 AlignedVector<T>::insert_back (ForwardIterator begin,
746  ForwardIterator end)
747 {
748  const unsigned int old_size = size();
749  reserve (old_size + (end-begin));
750  for ( ; begin != end; ++begin, ++_end_data)
751  {
752  if (std_cxx11::is_trivial<T>::value == false)
753  new (_end_data) T;
754  *_end_data = *begin;
755  }
756 }
757 
758 
759 
760 template < class T >
761 inline
762 void
763 AlignedVector<T>::fill (const T &value)
764 {
765  ::internal::AlignedVectorSet<T,false> (size(), value, _data);
766 }
767 
768 
769 
770 template < class T >
771 inline
772 void
774 {
775  std::swap (_data, vec._data);
776  std::swap (_end_data, vec._end_data);
777  std::swap (_end_allocated, vec._end_allocated);
778 }
779 
780 
781 
782 template < class T >
783 inline
784 bool
786 {
787  return _end_data == _data;
788 }
789 
790 
791 
792 template < class T >
793 inline
794 typename AlignedVector<T>::size_type
795 AlignedVector<T>::size () const
796 {
797  return _end_data - _data;
798 }
799 
800 
801 
802 template < class T >
803 inline
804 typename AlignedVector<T>::size_type
806 {
807  return _end_allocated - _data;
808 }
809 
810 
811 
812 template < class T >
813 inline
814 typename AlignedVector<T>::reference
815 AlignedVector<T>::operator [] (const size_type index)
816 {
817  AssertIndexRange (index, size());
818  return _data[index];
819 }
820 
821 
822 
823 template < class T >
824 inline
825 typename AlignedVector<T>::const_reference
826 AlignedVector<T>::operator [] (const size_type index) const
827 {
828  AssertIndexRange (index, size());
829  return _data[index];
830 }
831 
832 
833 
834 template < class T >
835 inline
836 typename AlignedVector<T>::iterator
838 {
839  return _data;
840 }
841 
842 
843 
844 template < class T >
845 inline
846 typename AlignedVector<T>::iterator
848 {
849  return _end_data;
850 }
851 
852 
853 
854 template < class T >
855 inline
856 typename AlignedVector<T>::const_iterator
858 {
859  return _data;
860 }
861 
862 
863 
864 template < class T >
865 inline
866 typename AlignedVector<T>::const_iterator
867 AlignedVector<T>::end () const
868 {
869  return _end_data;
870 }
871 
872 
873 
874 template < class T >
875 template < class Archive >
876 inline
877 void
878 AlignedVector<T>::save (Archive &ar, const unsigned int) const
879 {
880  size_type vec_size (size());
881  ar &vec_size;
882  if (vec_size > 0)
883  ar &boost::serialization::make_array(_data, vec_size);
884 }
885 
886 
887 
888 template < class T >
889 template < class Archive >
890 inline
891 void
892 AlignedVector<T>::load (Archive &ar, const unsigned int)
893 {
894  size_type vec_size = 0;
895  ar &vec_size ;
896 
897  if (vec_size > 0)
898  {
899  reserve(vec_size);
900  ar &boost::serialization::make_array(_data, vec_size);
901  _end_data = _data + vec_size;
902  }
903 }
904 
905 
906 
907 template < class T >
908 inline
909 typename AlignedVector<T>::size_type
911 {
912  size_type memory = sizeof(*this);
913  for (const T *t = _data ; t != _end_data; ++t)
915  memory += sizeof(T) * (_end_allocated-_end_data);
916  return memory;
917 }
918 
919 
920 #endif // ifndef DOXYGEN
921 
922 
928 template < class T >
929 bool operator == (const AlignedVector<T> &lhs,
930  const AlignedVector<T> &rhs)
931 {
932  if (lhs.size() != rhs.size())
933  return false;
934  for (typename AlignedVector<T>::const_iterator lit = lhs.begin(),
935  rit = rhs.begin(); lit != lhs.end(); ++lit, ++rit)
936  if (*lit != *rit)
937  return false;
938  return true;
939 }
940 
941 
942 
943 
949 template < class T >
950 bool operator != (const AlignedVector<T> &lhs,
951  const AlignedVector<T> &rhs)
952 {
953  return !(operator==(lhs, rhs));
954 }
955 
956 
957 DEAL_II_NAMESPACE_CLOSE
958 
959 #endif
#define AssertIndexRange(index, range)
Definition: exceptions.h:1170
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)
#define Assert(cond, exc)
Definition: exceptions.h:313
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:690
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
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()
static ::ExceptionBase & ExcInternalError()