]> https://gitweb.dealii.org/ - dealii.git/commitdiff
AlignedVector: add AlignedVector::insert(). 17734/head
authorDavid Wells <drwells@email.unc.edu>
Thu, 27 Jun 2024 19:05:27 +0000 (15:05 -0400)
committerDavid Wells <drwells@email.unc.edu>
Sat, 28 Sep 2024 12:58:18 +0000 (08:58 -0400)
doc/news/changes/minor/20240926DavidWells [new file with mode: 0644]
include/deal.II/base/aligned_vector.h
tests/base/aligned_vector_01.cc
tests/base/aligned_vector_01.output

diff --git a/doc/news/changes/minor/20240926DavidWells b/doc/news/changes/minor/20240926DavidWells
new file mode 100644 (file)
index 0000000..c034e34
--- /dev/null
@@ -0,0 +1,4 @@
+Improved: Added AlignedVector::insert(), which works the same way as
+std::vector::insert().
+<br>
+(David Wells, 2024/09/26)
index 84e74980d3f15b4ab328f769a8ac56a8d99f63a1..96507769405d6cba7ec4b6c9372dc6f6a44c5ef4 100644 (file)
@@ -255,6 +255,24 @@ public:
   void
   insert_back(ForwardIterator begin, ForwardIterator end);
 
+  /**
+   * Insert the range specified by @p begin and @p end after the element @p position.
+   *
+   * @note Unlike std::vector, this function uses random-access iterators so
+   * that the copy may be parallelized.
+   *
+   * @dealiiOperationIsMultithreaded
+   */
+  template <
+    typename RandomAccessIterator,
+    typename = std::enable_if_t<std::is_convertible_v<
+      typename std::iterator_traits<RandomAccessIterator>::iterator_category,
+      std::random_access_iterator_tag>>>
+  iterator
+  insert(const_iterator       position,
+         RandomAccessIterator begin,
+         RandomAccessIterator end);
+
   /**
    * Fills the vector with size() copies of a default constructed object.
    *
@@ -1572,6 +1590,53 @@ AlignedVector<T>::insert_back(ForwardIterator begin, ForwardIterator end)
 
 
 
+template <class T>
+template <typename RandomAccessIterator, typename>
+inline typename AlignedVector<T>::iterator
+AlignedVector<T>::insert(const_iterator       position,
+                         RandomAccessIterator begin,
+                         RandomAccessIterator end)
+{
+  Assert(replicated_across_communicator == false,
+         ExcAlignedVectorChangeAfterReplication());
+  Assert(this->begin() <= position && position <= this->end(),
+         ExcMessage("The position iterator is not valid."));
+  const auto offset = position - this->begin();
+
+  const size_type old_size   = size();
+  const size_type range_size = end - begin;
+  const size_type new_size   = old_size + range_size;
+  if (range_size != 0)
+    {
+      // This is similar to allocate_and_move(), except that we need to move
+      // whatever was before position and whatever is after it into two
+      // different places
+      T *new_data_ptr = nullptr;
+      Utilities::System::posix_memalign(
+        reinterpret_cast<void **>(&new_data_ptr), 64, new_size * sizeof(T));
+
+      // Correctly handle the case where the range is inside the present array
+      // by creating a temporary.
+      AlignedVector<T> temporary(begin, end);
+      dealii::internal::AlignedVectorMoveConstruct<T *, T>(
+        elements.get(), elements.get() + offset, new_data_ptr);
+      dealii::internal::AlignedVectorMoveConstruct<T *, T>(
+        temporary.begin(), temporary.end(), new_data_ptr + offset);
+      dealii::internal::AlignedVectorMoveConstruct<T *, T>(
+        elements.get() + offset,
+        elements.get() + old_size,
+        new_data_ptr + offset + range_size);
+
+      Deleter deleter(this);
+      elements          = decltype(elements)(new_data_ptr, std::move(deleter));
+      used_elements_end = elements.get() + new_size;
+      allocated_elements_end = elements.get() + new_size;
+    }
+  return this->begin() + offset;
+}
+
+
+
 template <class T>
 inline void
 AlignedVector<T>::fill()
index af0831ef6f4ebae8f247240fda38e6993c0ca67b..6d3b748b383442bbd021d3c0d5d8e6783c7d7549 100644 (file)
@@ -62,7 +62,42 @@ test()
                 ExcInternalError());
   }
 
-  deallog << "Insertion: ";
+  // Also check large insertions for equality and iterator position
+  {
+    std::deque<unsigned int> temp(8192);
+    std::iota(temp.begin(), temp.end(), 0u);
+
+    VEC        f(temp.begin(), temp.begin() + temp.size() / 4);
+    const auto it0 =
+      f.insert(f.end(), temp.begin() + temp.size() / 2, temp.end());
+    AssertThrow(static_cast<std::size_t>(it0 - f.begin()) == temp.size() / 4,
+                ExcInternalError());
+    AssertThrow(*it0 == temp[temp.size() / 2], ExcInternalError());
+    AssertThrow(*(it0 - 1) == temp[temp.size() / 4 - 1], ExcInternalError());
+    AssertThrow(f.back() == temp.back(), ExcInternalError());
+
+    const auto it1 = f.insert(f.begin() + temp.size() / 4,
+                              temp.begin() + temp.size() / 4,
+                              temp.begin() + temp.size() / 2);
+    AssertThrow(static_cast<std::size_t>(it1 - f.begin()) == temp.size() / 4,
+                ExcInternalError());
+    AssertThrow(*it1 == temp[temp.size() / 4], ExcInternalError());
+    AssertThrow(std::equal(f.begin(), f.end(), temp.begin()),
+                ExcInternalError());
+  }
+
+  deallog << "back Insertion: ";
+  for (unsigned int i = 0; i < a.size(); ++i)
+    deallog << a[i] << ' ';
+  deallog << std::endl;
+
+  {
+    AlignedVector<unsigned short> temp(4);
+    std::fill(temp.begin(), temp.end(), 42u);
+    a.insert(a.begin() + 4, temp.begin(), temp.end());
+  }
+  deallog << "Insertion at position 4: ";
+
   for (unsigned int i = 0; i < a.size(); ++i)
     deallog << a[i] << ' ';
   deallog << std::endl;
index 17920c6f64dd51a9a6e997e8804ab3a3f3318eb6..22827eac2e6cb04ce7ffc539bd4f82f544aef3a9 100644 (file)
@@ -1,7 +1,8 @@
 
 DEAL::Constructor: 0 0 0 0 
-DEAL::Insertion: 0 0 1 0 5 42 0 0 1 0 5 42 27 
-DEAL::Memory Shrinking: 112 to 64
+DEAL::back Insertion: 0 0 1 0 5 42 0 0 1 0 5 42 27 
+DEAL::Insertion at position 4: 0 0 1 0 42 42 42 42 5 42 0 0 1 0 5 42 27 
+DEAL::Memory Shrinking: 116 to 64
 DEAL::Shrinking: 0 0 1 0 
 DEAL::Reserve: 0 0 1 0 
 DEAL::Assignment: 0 0 1 0 5 42 27 

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.