From bccb3498e7276ae4f02d73ffed02a23b9511649a Mon Sep 17 00:00:00 2001 From: David Wells Date: Thu, 27 Jul 2017 00:15:57 -0400 Subject: [PATCH] Add iterator-friendly make_array_view functions. --- include/deal.II/base/array_view.h | 50 ++++++++++- tests/base/array_view_09.cc | 134 ++++++++++++++++++++++++++++++ tests/base/array_view_09.output | 4 + 3 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 tests/base/array_view_09.cc create mode 100644 tests/base/array_view_09.output diff --git a/include/deal.II/base/array_view.h b/include/deal.II/base/array_view.h index b62234234b..f08e0e72bf 100644 --- a/include/deal.II/base/array_view.h +++ b/include/deal.II/base/array_view.h @@ -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 class ArrayView @@ -349,6 +349,54 @@ make_array_view (std::vector &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 + * boost::container::small_vector or std::vector and + * will not work correctly with, e.g., + * boost::container::stable_vector or std::deque. + * + * @relates ArrayView + */ +template +ArrayView::reference>::type> +make_array_view (const Iterator begin, const Iterator end) +{ + static_assert(std::is_same::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::reference>::type> + (&*begin, end - begin); +} + +/** + * Create a view from a pair of pointers. ElementType 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 +ArrayView +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(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 index 0000000000..dad664ad23 --- /dev/null +++ b/tests/base/array_view_09.cc @@ -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 + +#include + +#include + +template +constexpr +bool +is_const_reference() +{ + return std::is_reference::value && + std::is_const::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 v; + std::fill(v.begin(), v.end(), 42.0); + const std::array &v2 = v; + const auto a = make_array_view(v2.begin(), v2.end()); + static_assert(is_const_reference(), + "type should be const"); + static_assert(is_const_reference(), + "type should be const"); + + v[5] = 10; + AssertThrow(a[5] == 10, ExcInternalError()); + } + + // test for a vector (preserve iterator constness) + { + std::vector v(10); + std::fill(v.begin(), v.end(), 42.0); + auto a = make_array_view(v.cbegin() + 2, v.cend()); + // a should be ArrayView + static_assert(!std::is_const::value, + "a should not be const (but has const value)"); + static_assert(std::is_const::value, + "a::value_type should be const"); + static_assert(is_const_reference(), + "type should be const"); + static_assert(is_const_reference(), + "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 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 + static_assert(std::is_const::value, + "a should not be const (but has const value)"); + static_assert(std::is_const::value, + "a::value_type should be const"); + static_assert(is_const_reference(), + "type should be const"); + static_assert(is_const_reference(), + "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 index 0000000000..78b054254c --- /dev/null +++ b/tests/base/array_view_09.output @@ -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 -- 2.39.5