Skip to content
Snippets Groups Projects
Commit 89219e1f authored by Simon Praetorius's avatar Simon Praetorius
Browse files

Align the mixin class better with other dune data structures

parent 0d002c5a
No related branches found
No related tags found
No related merge requests found
......@@ -11,8 +11,10 @@
#include <type_traits>
#include <utility>
#include <dune/common/boundschecking.hh>
#include <dune/common/ftraits.hh>
#include <dune/common/indices.hh>
#include <dune/common/concepts/number.hh>
#include <dune/common/std/type_traits.hh>
namespace Dune {
......@@ -21,7 +23,7 @@ namespace Dune {
* \brief A tensor interface-class providing common functionality.
* \nosubgrouping
*
* The CRTP interface mixin-class for tensors extends the mdarray and mdspan implementations
* The CRTP interface mixin-class for tensors extending the mdarray and mdspan implementations
* by common functionality for element access and size information and mathematical
* operations.
*
......@@ -42,6 +44,7 @@ class TensorMixin
public:
using element_type = typename base_type::element_type;
using value_type = std::remove_const_t<element_type>;
using field_type = typename FieldTraits<value_type>::field_type;
using extents_type = typename base_type::extents_type;
using index_type = typename base_type::index_type;
using layout_type = typename base_type::layout_type;
......@@ -56,11 +59,13 @@ protected:
/// \brief base copy constructor
constexpr TensorMixin (const base_type& tensor)
noexcept(std::is_nothrow_copy_constructible_v<base_type>)
: base_type{tensor}
{}
/// \brief base move constructor
constexpr TensorMixin (base_type&& tensor)
noexcept(std::is_nothrow_move_constructible_v<base_type>)
: base_type{std::move(tensor)}
{}
......@@ -73,6 +78,7 @@ public:
requires (sizeof...(Indices) == extents_type::rank())
constexpr reference operator() (Indices... indices)
{
DUNE_ASSERT_BOUNDS(indexInIndexSpace(indices...));
return base_type::operator[](std::array<index_type,extents_type::rank()>{index_type(indices)...});
}
......@@ -81,6 +87,7 @@ public:
requires (sizeof...(Indices) == extents_type::rank())
constexpr const_reference operator() (Indices... indices) const
{
DUNE_ASSERT_BOUNDS(indexInIndexSpace(indices...));
return base_type::operator[](std::array<index_type,extents_type::rank()>{index_type(indices)...});
}
......@@ -93,7 +100,7 @@ public:
constexpr reference at (Indices... indices)
{
if (not indexInIndexSpace(indices...))
throw std::out_of_range("Indices out of index space");
DUNE_THROW(Dune::RangeError, "Indices out of bounds.");
return base_type::operator[](std::array<index_type,extents_type::rank()>{index_type(indices)...});
}
......@@ -106,7 +113,7 @@ public:
constexpr const_reference at (Indices... indices) const
{
if (not indexInIndexSpace(indices...))
throw std::out_of_range("Indices out of index space");
DUNE_THROW(Dune::RangeError, "Indices out of bounds.");
return base_type::operator[](std::array<index_type,extents_type::rank()>{index_type(indices)...});
}
......@@ -114,6 +121,7 @@ public:
template <std::convertible_to<index_type> Index>
constexpr reference operator[] (const std::array<Index,extents_type::rank()>& indices)
{
DUNE_ASSERT_BOUNDS(indexInIndexSpace(indices));
return base_type::operator[](indices);
}
......@@ -121,20 +129,23 @@ public:
template <std::convertible_to<index_type> Index>
constexpr const_reference operator[] (const std::array<Index,extents_type::rank()>& indices) const
{
DUNE_ASSERT_BOUNDS(indexInIndexSpace(indices));
return base_type::operator[](indices);
}
/// \brief Access vector-element at position [i0] with mutable access.
constexpr reference operator[] (index_type index) noexcept
constexpr reference operator[] (index_type index)
requires (extents_type::rank() == 1)
{
DUNE_ASSERT_BOUNDS(indexInIndexSpace(index));
return base_type::operator[](std::array{index});
}
/// \brief Access vector-element at position [i0] with const access.
constexpr const_reference operator[] (index_type index) const noexcept
constexpr const_reference operator[] (index_type index) const
requires (extents_type::rank() == 1)
{
DUNE_ASSERT_BOUNDS(indexInIndexSpace(index));
return base_type::operator[](std::array{index});
}
......@@ -175,12 +186,16 @@ public:
/// \name Conversion to the underlying value if rank is zero
// @{
template <class ScalarType>
requires std::convertible_to<value_type,ScalarType>
constexpr operator ScalarType () const noexcept
constexpr operator reference () noexcept
requires (extents_type::rank() == 0)
{
return ScalarType(base_type::operator[](std::array<index_type,0>{}));
return base_type::operator[](std::array<index_type,0>{});
}
constexpr operator const_reference () const noexcept
requires (extents_type::rank() == 0)
{
return base_type::operator[](std::array<index_type,0>{});
}
/// @}
......@@ -202,6 +217,15 @@ private:
}, std::make_index_sequence<sizeof...(Indices)>{});
}
// Check whether a tuple of indices is in the index space `[0,extent_0)x...x[0,extent_{r-1})`.
template <class Index>
[[nodiscard]] constexpr bool indexInIndexSpace (const std::array<Index,extents_type::rank()>& indices) const noexcept
{
return unpackIntegerSequence([&](auto... i) {
return ( (0 <= indices[i] && index_type(indices[i]) < asBase().extent(i)) && ... );
}, std::make_index_sequence<extents_type::rank()>{});
}
private:
derived_type const& asDerived () const
......@@ -226,21 +250,19 @@ private:
};
// specialization for rank-0 tensor and comparison with scalar
template <class D, class B, std::convertible_to<typename B::value_type> V>
requires (B::extents_type::rank() == 0 &&
std::is_constructible_v<typename B::value_type, V>)
constexpr bool operator== (const TensorMixin<D,B>& lhs, const V& rhs) noexcept
template <class D, class B, Concept::Number S>
requires (B::extents_type::rank() == 0)
constexpr bool operator== (const TensorMixin<D,B>& lhs, const S& number) noexcept
{
return lhs() == rhs;
return lhs() == number;
}
// specialization for rank-0 tensor and comparison with scalar
template <class D, class B, std::convertible_to<typename B::value_type> V>
requires (B::extents_type::rank() == 0 &&
std::is_constructible_v<typename B::value_type, V>)
constexpr bool operator== (const V& lhs, const TensorMixin<D,B>& rhs) noexcept
template <Concept::Number S, class D, class B>
requires (B::extents_type::rank() == 0)
constexpr bool operator== (const S& number, const TensorMixin<D,B>& rhs) noexcept
{
return lhs == rhs();
return number == rhs();
}
template <class D, class B>
......
......@@ -165,8 +165,8 @@ void checkAccess(Dune::TestSuite& testSuite)
subTestSuite.check(tensor[i] == 42.0);
subTestSuite.check(tensor.at(i) == 42.0);
}
subTestSuite.checkThrow<std::out_of_range>([&]{tensor.at(-1);});
subTestSuite.checkThrow<std::out_of_range>([&]{tensor.at(tensor.extent(0));});
subTestSuite.checkThrow<Dune::RangeError>([&]{tensor.at(-1);});
subTestSuite.checkThrow<Dune::RangeError>([&]{tensor.at(tensor.extent(0));});
}
else if constexpr(Tensor::rank() == 2) {
for (std::size_t i = 0; i < Tensor::static_extent(0); ++i) {
......@@ -175,8 +175,8 @@ void checkAccess(Dune::TestSuite& testSuite)
subTestSuite.check(tensor(i,j) == 42.0);
subTestSuite.check(tensor.at(i,j) == 42.0);
}
subTestSuite.checkThrow<std::out_of_range>([&]{tensor.at(-1,-2);});
subTestSuite.checkThrow<std::out_of_range>([&]{tensor.at(tensor.extent(0),tensor.extent(1));});
subTestSuite.checkThrow<Dune::RangeError>([&]{tensor.at(-1,-2);});
subTestSuite.checkThrow<Dune::RangeError>([&]{tensor.at(tensor.extent(0),tensor.extent(1));});
}
}
else if constexpr(Tensor::rank() == 3) {
......@@ -187,8 +187,8 @@ void checkAccess(Dune::TestSuite& testSuite)
subTestSuite.check(tensor(i,j,k) == 42.0);
subTestSuite.check(tensor.at(i,j,k) == 42.0);
}
subTestSuite.checkThrow<std::out_of_range>([&]{tensor.at(-1,-2,-3);});
subTestSuite.checkThrow<std::out_of_range>([&]{tensor.at(tensor.extent(0),tensor.extent(1),tensor.extent(2));});
subTestSuite.checkThrow<Dune::RangeError>([&]{tensor.at(-1,-2,-3);});
subTestSuite.checkThrow<Dune::RangeError>([&]{tensor.at(tensor.extent(0),tensor.extent(1),tensor.extent(2));});
}
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment