GCC Code Coverage Report


Directory: gridformat/
File: gridformat/grid/discontinuous.hpp
Date: 2024-11-10 16:24:00
Exec Total Coverage
Lines: 97 98 99.0%
Functions: 624 624 100.0%
Branches: 43 80 53.8%

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 Grid
6 * \copybrief GridFormat::DiscontinousGrid
7 */
8 #ifndef GRIDFORMAT_GRID_DISCONTINUOUS_HPP_
9 #define GRIDFORMAT_GRID_DISCONTINUOUS_HPP_
10
11 #include <utility>
12 #include <functional>
13 #include <type_traits>
14 #include <iterator>
15 #include <optional>
16 #include <cassert>
17
18 #include <gridformat/common/iterator_facades.hpp>
19 #include <gridformat/common/enumerated_range.hpp>
20 #include <gridformat/common/type_traits.hpp>
21
22 #include <gridformat/grid/grid.hpp>
23 #include <gridformat/grid/concepts.hpp>
24 #include <gridformat/grid/type_traits.hpp>
25
26 namespace GridFormat {
27
28 #ifndef DOXYGEN
29 namespace DiscontinuousGridDetail {
30
31 template<typename R> struct PointRangeStorage;
32 template<typename R> requires(std::is_lvalue_reference_v<R>)
33 struct PointRangeStorage<R> {
34 using type = decltype(std::ref(std::declval<R>()));
35 };
36 template<typename R> requires(!std::is_lvalue_reference_v<R>)
37 struct PointRangeStorage<R> {
38 using type = std::remove_cvref_t<R>;
39 };
40
41
42 template<typename _C>
43 class Cell {
44 using HostCellStorage = LVReferenceOrValue<_C>;
45
46 public:
47 using HostCell = std::remove_cvref_t<_C>;
48
49 template<typename C>
50 requires(std::convertible_to<HostCellStorage, C>)
51 18848 Cell(C&& host_cell, std::size_t index)
52 18848 : _host_cell{std::forward<C>(host_cell)}
53 18848 , _index{index}
54 18848 {}
55
56 21128 std::size_t index() const { return _index; }
57 18280 const HostCell& host_cell() const { return *this; }
58 18280 operator const HostCell&() const { return _host_cell; }
59
60 private:
61 HostCellStorage _host_cell;
62 std::size_t _index;
63 };
64
65 template<typename C>
66 Cell(C&&, std::size_t) -> Cell<C>;
67
68 template<typename T> struct IsDiscontinuousCell : public std::false_type {};
69 template<typename C> struct IsDiscontinuousCell<Cell<C>> : public std::true_type {};
70 template<typename T> struct OwnsHostCell;
71 template<typename C> struct OwnsHostCell<Cell<C>> {
72 static constexpr bool value = !std::is_lvalue_reference_v<LVReferenceOrValue<C>>;
73 };
74
75 template<typename P, typename C>
76 class Point {
77 using PStorage = LVReferenceOrValue<P>;
78 using CStorage = LVReferenceOrValue<C>;
79 static_assert(IsDiscontinuousCell<std::remove_cvref_t<C>>::value);
80
81 public:
82 using Cell = std::remove_cvref_t<C>;
83 using HostCell = typename Cell::HostCell;
84 using HostPoint = std::remove_cvref_t<P>;
85
86 template<typename _P, typename _C>
87 requires(std::convertible_to<_P, PStorage> and
88 std::convertible_to<_C, CStorage>)
89 36488 Point(_P&& point, _C&& cell, std::size_t i)
90 36488 : _host_point{std::forward<_P>(point)}
91 36488 , _cell{std::forward<_C>(cell)}
92 36488 , _index_in_host{i}
93 36488 {}
94
95 21368 const Cell& cell() const { return _cell; }
96 240 const HostCell& host_cell() const { return _cell.host_cell(); }
97 4920 const HostPoint& host_point() const { return _host_point; }
98 operator const HostPoint&() const { return _host_point; }
99 16208 std::size_t index_in_host() const { return _index_in_host; }
100
101 private:
102 PStorage _host_point;
103 CStorage _cell;
104 std::size_t _index_in_host;
105 };
106
107 template<typename P, typename C>
108 Point(P&&, C&&, std::size_t) -> Point<P, C>;
109
110 template<typename HostGrid>
111 using HostCellRange = decltype(GridFormat::cells(std::declval<const HostGrid&>()));
112
113 template<typename HostGrid>
114 using HostCellPointRange = decltype(GridFormat::points(
115 std::declval<const HostGrid&>(),
116 std::declval<const GridFormat::Cell<HostGrid>&>())
117 );
118
119 template<typename HostGrid>
120 using HostCellPointRangeStorage = typename PointRangeStorage<HostCellPointRange<HostGrid>>::type;
121
122 template<typename T>
123 using AsConstReference = std::conditional_t<
124 std::is_lvalue_reference_v<T>,
125 std::add_lvalue_reference_t<std::add_const_t<std::remove_reference_t<T>>>,
126 T
127 >;
128
129 template<typename HostGrid>
130 using HostCellPointReference = AsConstReference<
131 typename std::iterator_traits<std::ranges::iterator_t<HostCellPointRangeStorage<HostGrid>>>::reference
132 >;
133
134 template<typename HostGrid>
135 using CellType = Cell<std::ranges::range_reference_t<HostCellRange<HostGrid>>>;
136
137 template<typename HostGrid>
138 using CellPointType = Point<HostCellPointReference<HostGrid>, CellType<HostGrid>>;
139
140
141 template<typename HostGrid, typename CellIt, typename CellSentinel>
142 class CellPointIterator
143 : public ForwardIteratorFacade<CellPointIterator<HostGrid, CellIt, CellSentinel>,
144 CellPointType<HostGrid>,
145 CellPointType<HostGrid>> {
146 using PointRangeStorage = HostCellPointRangeStorage<HostGrid>;
147 using PointRangeIterator = std::ranges::iterator_t<PointRangeStorage>;
148 using PointRangeSentinel = std::ranges::sentinel_t<PointRangeStorage>;
149
150 // if the cell iterator yields rvalue references, we have to cache
151 // the current cell, so that we can safely obtain a point range from it.
152 // This is necessary for the case that the user returns a transformed range,
153 // capturing the given cell by reference. That reference would otherwise be
154 // dangling...
155 using Cell = std::iterator_traits<CellIt>::value_type;
156 static_assert(IsDiscontinuousCell<Cell>::value);
157 static constexpr bool owns_host_cell = OwnsHostCell<Cell>::value;
158 using StoredCell = std::conditional_t<owns_host_cell, Cell, None>;
159
160 public:
161 CellPointIterator() = default;
162 1504 CellPointIterator(const HostGrid& grid, CellIt it, CellSentinel sentinel)
163 1504 : _grid{&grid}
164 1504 , _cell_it{it}
165 1504 , _cell_sentinel{sentinel} {
166
2/4
✓ Branch 1 taken 761 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
1504 if (!_is_cell_end())
167
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
1504 _set_point_range();
168 1504 }
169
170 96056 friend bool operator==(const CellPointIterator& self,
171 const std::default_sentinel_t&) noexcept {
172 96056 return self._cell_it == self._cell_sentinel;
173 }
174
175 friend bool operator==(const std::default_sentinel_t& s,
176 const CellPointIterator& self) noexcept {
177 return self == s;
178 }
179
180 private:
181 14768 void _set_point_range() {
182 if constexpr (owns_host_cell)
183
1/2
✓ Branch 1 taken 11160 times.
✗ Branch 2 not taken.
13680 _cell = (*_cell_it);
184
3/6
✓ Branch 1 taken 11704 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11704 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 11704 times.
✗ Branch 8 not taken.
14768 _points = GridFormat::points(*_grid, _get_cell().host_cell());
185
3/6
✓ Branch 1 taken 11704 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11704 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8940 times.
✗ Branch 8 not taken.
14768 _point_it = std::ranges::begin(_points.value());
186
3/6
✓ Branch 1 taken 11704 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11704 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8940 times.
✗ Branch 8 not taken.
14768 _point_end_it = std::ranges::end(_points.value());
187 14768 _local_point_index = 0;
188 14768 }
189
190 friend IteratorAccess;
191 bool _is_equal(CellPointIterator& other) const {
192 if (_grid != other._grid) return false;
193 if (_cell_it != other._cell_it) return false;
194 return _point_it.value() == other._point_it.value();
195 }
196
197 94552 void _increment() {
198
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 81836 times.
94552 if (_is_cell_end())
199 return;
200
201 94552 _local_point_index++;
202
2/2
✓ Branch 5 taken 11704 times.
✓ Branch 6 taken 70132 times.
94552 if (++_point_it.value(); _point_it.value() == _point_end_it.value()) {
203
2/2
✓ Branch 2 taken 10943 times.
✓ Branch 3 taken 761 times.
14768 if (++_cell_it; _cell_it != _cell_sentinel) {
204 13264 _set_point_range();
205 } else {
206 1504 _points.reset();
207 1504 _point_it.reset();
208 1504 _point_end_it.reset();
209 1504 _local_point_index = 0;
210 }
211 }
212 }
213
214 16208 CellPointType<HostGrid> _dereference() const {
215
3/6
✓ Branch 1 taken 13864 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13864 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 13864 times.
✗ Branch 8 not taken.
16208 return {*(_point_it.value()), Cell{_get_cell()}, _local_point_index};
216 }
217
218 30976 decltype(auto) _get_cell() const {
219 if constexpr (owns_host_cell)
220 28920 return _cell.value();
221 else
222 2056 return *_cell_it;
223 }
224
225 96056 bool _is_cell_end() const {
226 96056 return _cell_it == _cell_sentinel;
227 }
228
229 const HostGrid* _grid{nullptr};
230 CellIt _cell_it;
231 CellSentinel _cell_sentinel;
232 std::optional<StoredCell> _cell;
233
234 std::optional<PointRangeStorage> _points;
235 std::optional<PointRangeIterator> _point_it;
236 std::optional<PointRangeSentinel> _point_end_it;
237 unsigned int _local_point_index{0};
238 };
239
240 template<typename Grid, typename IT, typename S>
241 CellPointIterator(const Grid&, IT&&, S&&) -> CellPointIterator<Grid, std::remove_cvref_t<IT>, std::remove_cvref_t<S>>;
242
243
244 template<typename Grid, typename CellRange>
245 class CellPointRange {
246 public:
247 template<typename _Cells>
248 1504 explicit CellPointRange(const Grid& grid, _Cells&& range)
249 1504 : _grid{&grid}
250 1504 , _range{std::forward<_Cells>(range)}
251 1504 {}
252
253
2/4
✓ Branch 1 taken 761 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 761 times.
✗ Branch 6 not taken.
1504 auto begin() const { return CellPointIterator{*_grid, std::ranges::begin(_range), std::ranges::end(_range)}; }
254 1504 auto end() const { return std::default_sentinel_t{}; }
255
256 private:
257 const Grid* _grid{nullptr};
258 LVReferenceOrValue<CellRange> _range;
259 };
260
261 template<typename G, typename R>
262 CellPointRange(const G&, R&&) -> CellPointRange<G, R>;
263
264
265 template<typename IT, typename Sentinel>
266 class CellIterator
267 : public ForwardIteratorFacade<CellIterator<IT, Sentinel>,
268 Cell<typename std::iterator_traits<IT>::reference>,
269 Cell<typename std::iterator_traits<IT>::reference>> {
270 public:
271 CellIterator() = default;
272 2262 CellIterator(IT iterator, Sentinel sentinel)
273 2262 : _it{iterator}
274
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
2262 , _sentinel{sentinel}
275 2262 {}
276
277 215682 friend bool operator==(const CellIterator& self, const std::default_sentinel_t&) {
278 215682 return self._it == self._sentinel;
279 }
280
281 friend bool operator==(const std::default_sentinel_t&, const CellIterator& self) {
282 return self._it == self._sentinel;
283 }
284
285 private:
286 friend IteratorAccess;
287
288 22600 void _increment() {
289 22600 ++_it;
290 22600 ++_index;
291 22600 }
292
293 18848 auto _dereference() const {
294
1/2
✓ Branch 1 taken 13604 times.
✗ Branch 2 not taken.
18848 return Cell{*_it, _index};
295 }
296
297 bool _is_equal(const CellIterator& other) const {
298 return _it == other._it;
299 }
300
301 IT _it;
302 Sentinel _sentinel;
303 std::size_t _index{0};
304 };
305
306 template<typename It, typename S>
307 CellIterator(It&&, S&&) -> CellIterator<std::remove_cvref_t<It>, std::remove_cvref_t<S>>;
308
309
310 template<typename Grid>
311 class CellRange {
312 using _Range = decltype(GridFormat::cells(std::declval<const Grid&>()));
313
314 public:
315 2076 explicit CellRange(const Grid& grid)
316 2076 : _range{GridFormat::cells(grid)}
317 2076 {}
318
319
3/6
✓ Branch 1 taken 1142 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1142 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 112 times.
✗ Branch 8 not taken.
2262 auto begin() const { return CellIterator{std::ranges::begin(_range), std::ranges::end(_range)}; }
320 2262 auto end() const { return std::default_sentinel_t{}; }
321
322 private:
323 LVReferenceOrValue<_Range> _range;
324 };
325
326 } // namespace DiscontinuousGridDetail
327 #endif // DOXYGEN
328
329 //! \addtogroup Grid
330 //! \{
331
332 template<Concepts::UnstructuredGrid Grid>
333 class DiscontinuousGrid {
334 using This = DiscontinuousGrid<Grid>;
335 public:
336 using HostGrid = Grid;
337 using Point = DiscontinuousGridDetail::CellPointType<HostGrid>;
338 using Cell = DiscontinuousGridDetail::CellType<HostGrid>;
339
340 77 explicit DiscontinuousGrid(const Grid& grid)
341 77 : _grid{grid}
342 77 {}
343
344 1504 std::ranges::forward_range auto points() const {
345 return DiscontinuousGridDetail::CellPointRange{
346 _grid,
347 DiscontinuousGridDetail::CellRange{_grid}
348
2/4
✓ Branch 1 taken 761 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 61 times.
✗ Branch 5 not taken.
1504 };
349 }
350
351 572 std::ranges::forward_range auto cells() const {
352
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
572 return DiscontinuousGridDetail::CellRange{_grid};
353 }
354
355 8192 operator const Grid&() const { return _grid; }
356 8192 const Grid& host_grid() const { return *this; }
357
358 private:
359 const Grid& _grid;
360 };
361
362 template<typename Grid>
363 requires(std::is_lvalue_reference_v<Grid>)
364 auto make_discontinuous(Grid&& grid) {
365 return DiscontinuousGrid<std::remove_cvref_t<Grid>>{grid};
366 }
367
368 namespace Traits {
369
370 template<typename G>
371 struct Points<DiscontinuousGrid<G>> {
372 1504 static std::ranges::range auto get(const DiscontinuousGrid<G>& grid) {
373 1504 return grid.points();
374 }
375 };
376
377 template<typename G>
378 struct Cells<DiscontinuousGrid<G>> {
379 572 static std::ranges::range decltype(auto) get(const DiscontinuousGrid<G>& grid) {
380 572 return grid.cells();
381 }
382 };
383
384 template<typename G>
385 struct PointCoordinates<DiscontinuousGrid<G>, typename DiscontinuousGrid<G>::Point> {
386 4920 static decltype(auto) get(const DiscontinuousGrid<G>& grid,
387 const typename DiscontinuousGrid<G>::Point& p) {
388 4920 return PointCoordinates<G, Point<G>>::get(grid.host_grid(), p.host_point());
389 }
390 };
391
392 template<typename G>
393 struct CellPoints<DiscontinuousGrid<G>, typename DiscontinuousGrid<G>::Cell> {
394 2244 static auto get(const DiscontinuousGrid<G>& grid,
395 const typename DiscontinuousGrid<G>::Cell& c) {
396
6/10
✓ Branch 1 taken 1842 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1842 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1668 times.
✓ Branch 8 taken 174 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1668 times.
✓ Branch 11 taken 174 times.
✗ Branch 12 not taken.
2244 return Ranges::enumerated(CellPoints<G, Cell<G>>::get(grid.host_grid(), c.host_cell()))
397
2/4
✓ Branch 1 taken 1842 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1842 times.
✗ Branch 5 not taken.
7272 | std::views::transform([&] <typename Index, typename Point> (std::pair<Index, Point>&& pair) {
398 if constexpr (std::is_lvalue_reference_v<Point>) {
399 return typename DiscontinuousGrid<G>::Point{pair.second, c, pair.first};
400 } else {
401 4380 auto index = std::get<0>(pair);
402 4380 return typename DiscontinuousGrid<G>::Point{std::move(pair).second, c, index};
403 }
404 4488 });
405 }
406 };
407
408 template<typename G>
409 struct PointId<DiscontinuousGrid<G>, typename DiscontinuousGrid<G>::Point> {
410 15364 static std::size_t get(const DiscontinuousGrid<G>&, const typename DiscontinuousGrid<G>::Point& p) {
411 // create a unique id by hashing the cell/point index tuple
412
4/8
✓ Branch 2 taken 13140 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 13140 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 13140 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 13140 times.
✗ Branch 14 not taken.
15364 return std::hash<std::string>{}(std::to_string(p.cell().index()) + "/" + std::to_string(p.index_in_host()));
413 }
414 };
415
416 template<typename G>
417 struct CellType<DiscontinuousGrid<G>, typename DiscontinuousGrid<G>::Cell> {
418 754 static auto get(const DiscontinuousGrid<G>& grid,
419 const typename DiscontinuousGrid<G>::Cell& cell) {
420 754 return CellType<G, Cell<G>>::get(grid.host_grid(), cell.host_cell());
421 }
422 };
423
424 } // namespace Traits
425
426 //! \} group Grid
427
428 } // namespace GridFormat
429
430 #endif // GRIDFORMAT_GRID_DISCONTINUOUS_HPP_
431