GCC Code Coverage Report


Directory: gridformat/
File: gridformat/common/flat_index_mapper.hpp
Date: 2024-11-10 16:24:00
Exec Total Coverage
Lines: 36 37 97.3%
Functions: 60 63 95.2%
Branches: 16 32 50.0%

Line Branch Exec Source
1 // SPDX-FileCopyrightText: 2022-2023 Dennis Gläser <dennis.glaeser@iws.uni-stuttgart.de>
2 // SPDX-License-Identifier: MIT
3 /*!
4 * \file
5 * \ingroup Common
6 * \copybrief GridFormat::FlatIndexMapper
7 */
8 #ifndef GRIDFORMAT_COMMON_FLAT_INDEX_MAPPER_HPP_
9 #define GRIDFORMAT_COMMON_FLAT_INDEX_MAPPER_HPP_
10
11 #include <array>
12 #include <cstddef>
13 #include <numeric>
14 #include <concepts>
15 #include <iterator>
16 #include <algorithm>
17 #include <functional>
18 #include <cassert>
19
20 #include <gridformat/common/ranges.hpp>
21 #include <gridformat/common/concepts.hpp>
22 #include <gridformat/common/type_traits.hpp>
23 #include <gridformat/common/exceptions.hpp>
24
25 namespace GridFormat {
26
27 #ifndef DOXYGEN
28 namespace FlatIndexMapperDetail {
29
30 template<std::ranges::range Offsets, std::ranges::range E>
31 166726 void fill_offsets(Offsets& offsets, E&& extents) {
32 166726 auto begin = std::ranges::begin(offsets);
33 166726 *begin = 1;
34
1/2
✓ Branch 1 taken 1105 times.
✗ Branch 2 not taken.
331243 std::partial_sum(
35
1/2
✓ Branch 1 taken 1105 times.
✗ Branch 2 not taken.
2209 std::ranges::begin(extents),
36
1/2
✓ Branch 1 taken 1105 times.
✗ Branch 2 not taken.
2209 std::prev(std::ranges::end(extents)),
37 std::next(begin),
38 std::multiplies{}
39 );
40 166726 }
41
42 template<int dim, typename I>
43 struct OffsetHelper {
44 using Storage = std::array<I, dim>;
45
46 template<std::ranges::range R>
47 161875 static Storage make(R&& extents) {
48 if constexpr (Concepts::StaticallySizedRange<R>)
49 static_assert(static_size<R> == dim);
50
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 else if (Ranges::size(extents) != dim)
51
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 throw SizeError("Given extents do not match index mapper dimension");
52 Storage offsets;
53
1/2
✓ Branch 1 taken 19227 times.
✗ Branch 2 not taken.
161873 std::ranges::fill(offsets, default_value<I>);
54 if constexpr (dim > 0)
55
1/2
✓ Branch 2 taken 19235 times.
✗ Branch 3 not taken.
161873 fill_offsets(offsets, std::forward<R>(extents));
56 161873 return offsets;
57 }
58 };
59
60 template<int dim, typename I> requires(dim < 0)
61 struct OffsetHelper<dim, I> {
62 using Storage = std::vector<I>;
63
64 template<std::ranges::range R>
65 3787 static Storage make(R&& extents) {
66
1/2
✓ Branch 2 taken 2427 times.
✗ Branch 3 not taken.
3787 Storage offsets(Ranges::size(extents), default_value<I>);
67
1/2
✓ Branch 1 taken 2427 times.
✗ Branch 2 not taken.
3787 if (offsets.size() > 0)
68
1/2
✓ Branch 2 taken 2427 times.
✗ Branch 3 not taken.
3787 fill_offsets(offsets, std::forward<R>(extents));
69 3787 return offsets;
70 }
71 };
72
73 } // namespace FlatIndexMapperDetail
74 #endif // DOXYGEN
75
76
77 /*!
78 * \ingroup Common
79 * \brief Maps index tuples to flat indices.
80 */
81 template<int dim = -1, typename IndexType = std::size_t>
82 class FlatIndexMapper {
83 using OffsetHelper = typename FlatIndexMapperDetail::OffsetHelper<dim, IndexType>;
84
85 public:
86 1 FlatIndexMapper() requires(dim == 1) : _offsets{1} {}
87
88 template<std::ranges::range R>
89 166728 explicit FlatIndexMapper(R&& extents)
90 166728 : _offsets{OffsetHelper::make(std::forward<R>(extents))}
91 166726 {}
92
93 template<Concepts::StaticallySizedMDRange<1> R>
94 requires(std::integral<std::ranges::range_value_t<R>>)
95 4201270 IndexType map(R&& index_tuple) const {
96 if constexpr (dim < 0)
97
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
6 assert(static_size<R> == Ranges::size(_offsets));
98 4201270 return _map(std::forward<R>(index_tuple));
99 }
100
101 template<std::ranges::range R>
102 requires(!Concepts::StaticallySizedRange<R>
103 and std::integral<std::ranges::range_value_t<R>>)
104 143913 IndexType map(R&& index_tuple) const {
105
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 72743 times.
143913 assert(Ranges::size(index_tuple) == Ranges::size(_offsets));
106 143913 return _map(std::forward<R>(index_tuple));
107 }
108
109 private:
110 template<std::ranges::range R>
111 2173510 IndexType _map(R&& index_tuple) const {
112 2173510 std::size_t i = 0;
113
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 264 times.
✗ Branch 4 not taken.
2173510 return std::accumulate(
114
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1105 std::ranges::begin(index_tuple),
115
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2210 std::ranges::end(index_tuple),
116 std::size_t{0},
117 6243075 [&] (std::size_t current, std::integral auto index) {
118 6243075 return current + index*_offsets.at(i++);
119 }
120 4346992 );
121 }
122
123 typename OffsetHelper::Storage _offsets;
124 bool _is_row_major;
125 };
126
127
128 // Clang doesn't take the call to static_size<R> in the deduction guides,
129 // for some reason it instantiates it also for non statically sized ranges...
130 // This level of indirection makes it work because the template is defined,
131 // and its value should never be used for non-statically-sized-ranges
132 #ifndef DOXYGEN
133 namespace FlatIndexMapperDetail {
134
135 template<typename T>
136 struct StaticSize {
137 static constexpr int value = 1;
138 };
139 template<Concepts::StaticallySizedRange R>
140 struct StaticSize<R> {
141 static constexpr int value = static_cast<int>(static_size<R>);
142 };
143
144 } // namespace Detail
145 #endif // FlatIndexMapperDetail
146
147
148 template<Concepts::StaticallySizedRange R>
149 FlatIndexMapper(R&&) -> FlatIndexMapper<FlatIndexMapperDetail::StaticSize<R>::value, std::ranges::range_value_t<R>>;
150
151 template<std::ranges::range R> requires(!Concepts::StaticallySizedRange<R>)
152 FlatIndexMapper(R&&) -> FlatIndexMapper<-1, std::ranges::range_value_t<R>>;
153
154 } // namespace GridFormat
155
156 #endif // GRIDFORMAT_COMMON_FLAT_INDEX_MAPPER_HPP_
157