Skip to content
Snippets Groups Projects
Commit 4cd25a42 authored by Stéphane Del Pino's avatar Stéphane Del Pino
Browse files

Add SubArray class

This allow to manipulate contiguous sub parts of arrays in the same
way as arrays themselves

Note that for performances reasons, SubArray cannot be Array
parent 134e340c
Branches
Tags
1 merge request!84Add SubArray class
#ifndef SUB_ARRAY_HPP
#define SUB_ARRAY_HPP
#include <utils/Array.hpp>
#include <utils/PugsAssert.hpp>
#include <utils/PugsMacros.hpp>
#include <utils/PugsUtils.hpp>
#include <algorithm>
template <typename DataType>
class [[nodiscard]] SubArray
{
public:
using data_type = DataType;
using index_type = size_t;
private:
// underlying array
Array<DataType> m_array;
DataType* m_sub_values;
size_t m_size;
// Allows const version to access our data
friend SubArray<std::add_const_t<DataType>>;
public:
PUGS_INLINE size_t size() const noexcept
{
return m_size;
}
PUGS_INLINE DataType& operator[](index_type i) const noexcept(NO_ASSERT)
{
Assert(i < m_size);
return m_sub_values[i];
}
PUGS_INLINE
void fill(const DataType& data) const
{
static_assert(not std::is_const<DataType>(), "Cannot modify SubArray of const");
// could consider to use std::fill
parallel_for(
this->size(), PUGS_LAMBDA(index_type i) { m_sub_values[i] = data; });
}
template <typename DataType2>
PUGS_INLINE SubArray& operator=(const SubArray<DataType2>& sub_array) noexcept
{
// ensures that DataType is the same as source DataType2
static_assert(std::is_same<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>(),
"Cannot assign SubArray of different type");
// ensures that const is not lost through copy
static_assert(((std::is_const<DataType2>() and std::is_const<DataType>()) or not std::is_const<DataType2>()),
"Cannot assign SubArray of const to SubArray of non-const");
m_array = sub_array.m_array;
m_size = sub_array.m_size;
m_sub_values = sub_array.m_sub_values;
return *this;
}
PUGS_INLINE
SubArray& operator=(const SubArray&) = default;
PUGS_INLINE
SubArray& operator=(SubArray&&) = default;
PUGS_INLINE
explicit SubArray(Array<DataType> array, size_t begin, size_t size)
: m_array{array}, m_sub_values{&array[0] + begin}, m_size{size}
{
Assert(begin + size <= array.size(), "SubView is not contained in the source Array");
static_assert(not std::is_const<DataType>(), "Cannot allocate SubArray of const data: only view is "
"supported");
}
PUGS_INLINE
SubArray() = default;
PUGS_INLINE
SubArray(const SubArray&) = default;
template <typename DataType2>
PUGS_INLINE SubArray(const SubArray<DataType2>& sub_array) noexcept
{
this->operator=(sub_array);
}
PUGS_INLINE
SubArray(SubArray &&) = default;
PUGS_INLINE
~SubArray() = default;
};
#endif // SUB_ARRAY_HPP
......@@ -85,6 +85,7 @@ add_executable (unit_tests
test_PugsUtils.cpp
test_RevisionInfo.cpp
test_SparseMatrixDescriptor.cpp
test_SubArray.cpp
test_SymbolTable.cpp
test_Timer.cpp
test_TinyMatrix.cpp
......
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_all.hpp>
#include <utils/PugsAssert.hpp>
#include <utils/SubArray.hpp>
#include <utils/Types.hpp>
// Instantiate to ensure full coverage is performed
template class SubArray<int>;
// clazy:excludeall=non-pod-global-static
TEST_CASE("SubArray", "[utils]")
{
Array<int> a(10);
REQUIRE(a.size() == 10);
SECTION("shared values")
{
SubArray sub_a{a, 0, 10};
for (size_t i = 0; i < sub_a.size(); ++i) {
sub_a[i] = 2 * i;
}
REQUIRE(((a[0] == 0) and (a[1] == 2) and (a[2] == 4) and (a[3] == 6) and (a[4] == 8) and (a[5] == 10) and
(a[6] == 12) and (a[7] == 14) and (a[8] == 16) and (a[9] == 18)));
for (size_t i = 0; i < a.size(); ++i) {
a[i] = (i + 1) * (2 * i + 1);
}
REQUIRE(((sub_a[0] == 1) and (sub_a[1] == 6) and (sub_a[2] == 15) and (sub_a[3] == 28) and (sub_a[4] == 45) and
(sub_a[5] == 66) and (sub_a[6] == 91) and (sub_a[7] == 120) and (sub_a[8] == 153) and (sub_a[9] == 190)));
}
SECTION("sub array")
{
a.fill(0);
SubArray sub_a{a, 5, 5};
for (size_t i = 0; i < sub_a.size(); ++i) {
sub_a[i] = i + 1;
}
REQUIRE(((a[0] == 0) and (a[1] == 0) and (a[2] == 0) and (a[3] == 0) and (a[4] == 0) and (a[5] == 1) and
(a[6] == 2) and (a[7] == 3) and (a[8] == 4) and (a[9] == 5)));
for (size_t i = 0; i < a.size(); ++i) {
a[i] = (i + 1) * (2 * i + 1);
}
REQUIRE(((sub_a[0] == 66) and (sub_a[1] == 91) and (sub_a[2] == 120) and (sub_a[3] == 153) and (sub_a[4] == 190)));
}
SECTION("sub array copy")
{
a.fill(0);
SubArray<int> sub_a;
sub_a = SubArray{a, 5, 5};
for (size_t i = 0; i < sub_a.size(); ++i) {
sub_a[i] = i + 1;
}
REQUIRE(((a[0] == 0) and (a[1] == 0) and (a[2] == 0) and (a[3] == 0) and (a[4] == 0) and (a[5] == 1) and
(a[6] == 2) and (a[7] == 3) and (a[8] == 4) and (a[9] == 5)));
for (size_t i = 0; i < a.size(); ++i) {
a[i] = (i + 1) * (2 * i + 1);
}
REQUIRE(((sub_a[0] == 66) and (sub_a[1] == 91) and (sub_a[2] == 120) and (sub_a[3] == 153) and (sub_a[4] == 190)));
SubArray sub_b = sub_a;
REQUIRE(((sub_b[0] == 66) and (sub_b[1] == 91) and (sub_b[2] == 120) and (sub_b[3] == 153) and (sub_b[4] == 190)));
sub_b = sub_a;
REQUIRE(((sub_b[0] == 66) and (sub_b[1] == 91) and (sub_b[2] == 120) and (sub_b[3] == 153) and (sub_b[4] == 190)));
SubArray<const int> const_sub_a{sub_a};
REQUIRE(((const_sub_a[0] == 66) and (const_sub_a[1] == 91) and (const_sub_a[2] == 120) and
(const_sub_a[3] == 153) and (const_sub_a[4] == 190)));
sub_a.fill(2);
REQUIRE(((const_sub_a[0] == 2) and (const_sub_a[1] == 2) and (const_sub_a[2] == 2) and (const_sub_a[3] == 2) and
(const_sub_a[4] == 2)));
SubArray sub_c{SubArray{a, 3, 6}};
REQUIRE(((sub_c[0] == a[3]) and (sub_c[1] == a[4]) and (sub_c[2] == a[5]) and (sub_c[3] == a[6]) and
(sub_c[4] == a[7]) and (sub_c[5] == a[8])));
}
#ifndef NDEBUG
SECTION("errors")
{
a.fill(0);
SubArray<int> sub_a;
sub_a = SubArray{a, 5, 5};
for (size_t i = 0; i < sub_a.size(); ++i) {
sub_a[i] = i + 1;
}
REQUIRE_THROWS_AS(sub_a[5], AssertError);
}
#endif // NDEBUG
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment