]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Add iterator-friendly make_array_view functions. 4670/head
authorDavid Wells <wellsd2@rpi.edu>
Thu, 27 Jul 2017 04:15:57 +0000 (00:15 -0400)
committerDavid Wells <wellsd2@rpi.edu>
Sat, 29 Jul 2017 17:53:39 +0000 (13:53 -0400)
include/deal.II/base/array_view.h
tests/base/array_view_09.cc [new file with mode: 0644]
tests/base/array_view_09.output [new file with mode: 0644]

index b62234234be3c6a3ed8051a42d73f37a22bf132c..f08e0e72bfd937346ff17a904a512770ffc38a7e 100644 (file)
@@ -64,7 +64,7 @@ DEAL_II_NAMESPACE_OPEN
  * std::vector::operator[] is non-@p const.
  *
  * @ingroup data
- * @author Wolfgang Bangerth, 2015
+ * @author Wolfgang Bangerth, 2015, David Wells, 2017
  */
 template <typename ElementType>
 class ArrayView
@@ -349,6 +349,54 @@ make_array_view (std::vector<ElementType> &vector,
 }
 
 
+/**
+ * Create an ArrayView that takes a pair of iterators as arguments. The type
+ * of the ArrayView is inferred from the value type of the iterator (e.g., the
+ * view created from two const iterators will have a const type).
+ *
+ * @warning The iterators @begin and @p end must bound (in the usual half-open
+ * way) a contiguous in memory range of values. This function is intended for
+ * use with iterators into containers like
+ * <code>boost::container::small_vector</code> or <code>std::vector</code> and
+ * will not work correctly with, e.g.,
+ * <code>boost::container::stable_vector</code> or <code>std::deque</code>.
+ *
+ * @relates ArrayView
+ */
+template <typename Iterator>
+ArrayView<typename std::remove_reference<typename std::iterator_traits<Iterator>::reference>::type>
+make_array_view (const Iterator begin, const Iterator end)
+{
+  static_assert(std::is_same<typename std::iterator_traits<Iterator>::iterator_category,
+                typename std::random_access_iterator_tag>::value,
+                "The provided iterator should be a random access iterator.");
+  Assert(begin <= end,
+         ExcMessage("The beginning of the array view should be before the end."));
+  // the reference type, not the value type, knows the constness of the iterator
+  return ArrayView<typename std::remove_reference
+         <typename std::iterator_traits<Iterator>::reference>::type>
+         (&*begin, end - begin);
+}
+
+/**
+ * Create a view from a pair of pointers. <code>ElementType</code> may be
+ * const-qualified.
+ *
+ * @warning The pointers @p begin and @p end must bound (in the usual
+ * half-open way) a contiguous in memory range of values.
+ *
+ * @relates ArrayView
+ */
+template <typename ElementType>
+ArrayView<ElementType>
+make_array_view (ElementType *const begin, ElementType *const end)
+{
+  Assert(begin <= end,
+         ExcMessage("The beginning of the array view should be before the end."));
+  return ArrayView<ElementType>(begin, end - begin);
+}
+
+
 
 /**
  * Create a view to a part of a std::vector object. This is equivalent to
diff --git a/tests/base/array_view_09.cc b/tests/base/array_view_09.cc
new file mode 100644 (file)
index 0000000..dad664a
--- /dev/null
@@ -0,0 +1,134 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2017 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+
+// test the make_array_view functions that create ArrayViews from iterators
+
+#include "../tests.h"
+
+#include <deal.II/base/array_view.h>
+
+#include <boost/container/static_vector.hpp>
+
+#include <type_traits>
+
+template <typename T>
+constexpr
+bool
+is_const_reference()
+{
+  return std::is_reference<T>::value &&
+         std::is_const<typename std::remove_reference<T>::type>::value;
+}
+
+void test ()
+{
+  // test on a built-in array
+  {
+    int v[10];
+    auto a = make_array_view(std::begin(v) + 1, std::end(v));
+    AssertThrow (a.begin() == v + 1, ExcInternalError());
+    AssertThrow (a.end() == v + sizeof(v)/sizeof(v[0]),
+                 ExcInternalError());
+    AssertThrow (a.begin() + 2 == &v[3], ExcInternalError());
+    a[2] = 42;
+    AssertThrow (v[3] == 42, ExcInternalError());
+
+    // check that we cannot create a backwards array
+    try
+      {
+        make_array_view(std::end(v), std::begin(v));
+      }
+    catch (const ExceptionBase &exc)
+      {
+        deallog << exc.get_exc_name() << std::endl;
+      }
+  }
+
+  // test on the std::array class template
+  {
+    std::array<double, 10> v;
+    std::fill(v.begin(), v.end(), 42.0);
+    const std::array<double, 10> &v2 = v;
+    const auto a = make_array_view(v2.begin(), v2.end());
+    static_assert(is_const_reference<decltype(*a.begin())>(),
+                  "type should be const");
+    static_assert(is_const_reference<decltype(*a.end())>(),
+                  "type should be const");
+
+    v[5] = 10;
+    AssertThrow(a[5] == 10, ExcInternalError());
+  }
+
+  // test for a vector (preserve iterator constness)
+  {
+    std::vector<double> v(10);
+    std::fill(v.begin(), v.end(), 42.0);
+    auto a = make_array_view(v.cbegin() + 2, v.cend());
+    // a should be ArrayView<const double>
+    static_assert(!std::is_const<decltype(a)>::value,
+                  "a should not be const (but has const value)");
+    static_assert(std::is_const<decltype(a)::value_type>::value,
+                  "a::value_type should be const");
+    static_assert(is_const_reference<decltype(*a.begin())>(),
+                  "type should be const");
+    static_assert(is_const_reference<decltype(*a.end())>(),
+                  "type should be const");
+    v[2] = 10.0;
+    AssertThrow(a[0] == v[2], ExcInternalError());
+  }
+
+  // test for a (new in boost 1.54) vector class
+  {
+    boost::container::static_vector<double, 20> v(10);
+    std::fill(v.begin(), v.end(), 42.0);
+
+    const auto a = make_array_view(v.cbegin() + 2, v.cend());
+    AssertThrow(a.size() + 2 == v.size(), ExcInternalError());
+    // a should be const ArrayView<const double>
+    static_assert(std::is_const<decltype(a)>::value,
+                  "a should not be const (but has const value)");
+    static_assert(std::is_const<decltype(a)::value_type>::value,
+                  "a::value_type should be const");
+    static_assert(is_const_reference<decltype(*a.begin())>(),
+                  "type should be const");
+    static_assert(is_const_reference<decltype(*a.end())>(),
+                  "type should be const");
+    v[2] = 10.0;
+    AssertThrow(a[0] == v[2], ExcInternalError());
+
+    // check that we cannot create a backwards array
+    try
+      {
+        make_array_view(std::end(v), std::begin(v));
+      }
+    catch (const ExceptionBase &exc)
+      {
+        deallog << exc.get_exc_name() << std::endl;
+      }
+  }
+
+  deallog << "OK" << std::endl;
+}
+
+
+
+int main()
+{
+  initlog();
+
+  deal_II_exceptions::disable_abort_on_exception();
+  test ();
+}
diff --git a/tests/base/array_view_09.output b/tests/base/array_view_09.output
new file mode 100644 (file)
index 0000000..78b0542
--- /dev/null
@@ -0,0 +1,4 @@
+
+DEAL::ExcMessage("The beginning of the array view should be before the end.")
+DEAL::ExcMessage("The beginning of the array view should be before the end.")
+DEAL::OK

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.