PLaSK library

Loading...
Searching...
No Matches
lazydata.hpp
Go to the documentation of this file.
1/*
2 * This file is part of PLaSK (https://plask.app) by Photonics Group at TUL
3 * Copyright (c) 2022 Lodz University of Technology
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14#ifndef PLASK__LAZYDATA_H
15#define PLASK__LAZYDATA_H
16
17#include "data.hpp"
18#include "parallel.hpp"
19#include "utils/openmp.hpp"
20
21#include "vector/tensor2.hpp"
22#include "vector/tensor3.hpp"
23#include "utils/iterators.hpp"
24
25 namespace plask {
26
33 template <typename T>
34 struct LazyDataImpl {
35
36 typedef T CellType;
37
38 virtual ~LazyDataImpl() {}
39
45 virtual T at(std::size_t index) const = 0;
46
51 virtual std::size_t size() const = 0;
52
57 virtual DataVector<const T> getAll() const {
58 DataVector<T> res(this->size());
59 std::exception_ptr error;
60 PLASK_OMP_PARALLEL_FOR
61 for (openmp_size_t i = 0; i < res.size(); ++i) {
62 if (error) continue;
63 try {
64 res[i] = this->at(i);
65 } catch(...) {
66 #pragma omp critical
67 error = std::current_exception();
68 }
69 }
70 if (error) std::rethrow_exception(error);
71 return res;
72 }
73
74 virtual DataVector<T> claim() const {
75 return this->getAll().claim();
76 }
77};
78
82 template <typename T>
83 struct ConstValueLazyDataImpl: public LazyDataImpl<T> {
84
85 T value_;
86 std::size_t size_;
87
88 ConstValueLazyDataImpl(std::size_t size, const T& value): value_(value), size_(size) {}
89
90 T at(std::size_t) const override { return value_; }
91
92 std::size_t size() const override { return size_; }
93
94 DataVector<const T> getAll() const override { return DataVector<const T>(size_, value_); }
95
96};
97
103 template <typename T>
104 struct LazyDataFromVectorImpl: public LazyDataImpl<T> {
105
106 DataVector<const T> vec;
107
108 LazyDataFromVectorImpl(DataVector<const T> vec): vec(vec) {}
109
110 T at(std::size_t index) const override { return vec[index]; }
111
112 std::size_t size() const override { return vec.size(); }
113
114 DataVector<const T> getAll() const override { return vec; }
115
116 DataVector<T> claim() const override { return vec.claim(); }
117};
118
122 template <typename T>
123 struct LazyDataDelegateImpl: public LazyDataImpl<T> {
124
125 protected:
126 std::size_t siz;
127 std::function<T(std::size_t)> func;
128
129 public:
130 LazyDataDelegateImpl(std::size_t size, std::function<T(std::size_t)> func): siz(size), func(std::move(func)) {}
131
132 T at(std::size_t index) const override { return func(index); }
133
134 std::size_t size() const override { return siz; }
135};
136
137
138
139/*
140 * Base class for lazy data (vector) that holds reference to destination mesh (dst_mesh).
141 */
142/*template <typename T, typename DstMeshType>
143 struct LazyDataWithMeshImpl: public LazyDataImpl<T> {
144
145 shared_ptr<const DstMeshType> dst_mesh;
146
147 LazyDataWithMeshImpl(shared_ptr<const DstMeshType> dst_mesh): dst_mesh(dst_mesh) {}
148
149 std::size_t size() const override { return dst_mesh->size(); }
150
151};*/
152
160 template <typename T>
161 class LazyData {
162
163 //TODO change back to unique_ptr when move to lambda capture (C++14) will be supported:
164 //std::unique_ptr< const LazyDataImpl<T> > impl;
165 shared_ptr< const LazyDataImpl<T> > impl;
166
167 public:
168
169 typedef T CellType;
170 typedef DataVector<T> DataVectorType;
171 typedef DataVector<const T> DataVectorOfConstType;
172
177 LazyData(const LazyDataImpl<T>* impl = nullptr): impl(impl) {}
178
184 LazyData(std::size_t size, T value): impl(new ConstValueLazyDataImpl<T>(size, value)) {}
185
190 LazyData(DataVector<const T> data_vector): impl(new LazyDataFromVectorImpl<T>(data_vector)) {}
191 LazyData(DataVector<T> data_vector): impl(new LazyDataFromVectorImpl<T>(data_vector)) {}
192
198 LazyData(std::size_t size, std::function<T(std::size_t)> func):
199 impl(new LazyDataDelegateImpl<T>(size, std::move(func))) {}
200
201 void reset(const LazyDataImpl<T>* new_impl = nullptr) { impl.reset(new_impl); }
202
203 void reset(std::size_t size, T value) { impl.reset(new ConstValueLazyDataImpl<T>(size, value)); }
204
205 void reset(DataVector<const T> data_vector) { impl.reset(new LazyDataFromVectorImpl<T>(data_vector)); }
206 void reset(DataVector<T> data_vector) { impl.reset(new LazyDataFromVectorImpl<T>(data_vector)); }
207
208 void reset(std::size_t size, std::function<T(std::size_t)> func) {
209 impl.reset(new LazyDataDelegateImpl<T>(size, std::move(func)));
210 }
211
212 /*LazyData(const LazyData&) = default;
213 LazyData(LazyData&&) = default;
214 LazyData& operator=(const LazyData&) & = default;
215 LazyData& operator=(LazyData&&) & = default;*/
216
222 T operator[](std::size_t index) const { return impl->at(index); }
223
229 T at(std::size_t index) const { return impl->at(index); }
230
231 DataVector<const T> nonLazy() const { return impl->getAll(); }
232
233 operator DataVector<const T> () const { return impl->getAll(); }
234
235 DataVector<T> claim() const {
236 return impl->claim();
237 //TODO jeśli używany shared_ptr, to co z przypadkiem gdy impl ma więcej niż 1 referencję? wtedy powinno być zrobione impl->getAll()->claim();
238 // (w przypadku trzymania data vectora zostanie on skopiowany)
239 }
240
245 std::size_t size() const { return impl->size(); }
246
251 typedef IndexedIterator< const LazyData, T > const_iterator;
252 typedef const_iterator iterator;
253 typedef const_iterator Iterator;
254
256 const_iterator begin() const { return const_iterator(this, 0); }
257
259 const_iterator end() const { return const_iterator(this, size()); }
260
261 bool isNotNull() const { return bool(impl); }
262
263 bool isNull() const { return !impl; }
264};
265
266 template <typename T, typename ScaleT, typename ReturnedType = typename std::remove_cv<decltype(T()*ScaleT())>::type>
267 struct ScaledLazyDataImpl: public LazyDataImpl<ReturnedType> {
268
269 LazyData<T> data;
270
271 ScaleT scale;
272
273 ScaledLazyDataImpl(LazyData<T> data, const ScaleT& scale)
274 : data(std::move(data)), scale(scale) {}
275
276 ReturnedType at(std::size_t index) const override { return data[index] * scale; }
277
278 std::size_t size() const override { return data.size(); }
279
280};
281
288 template<typename T, typename S>
289 LazyData<typename ScaledLazyDataImpl<T, S>::CellType> operator*(LazyData<T> data, const S& scale) {
290 return new ScaledLazyDataImpl<T, S>(std::move(data), scale);
291}
292
299 template<typename T, typename S>
300 LazyData<typename ScaledLazyDataImpl<T, S>::CellType> operator*(const S& scale, LazyData<T> data) {
301 return new ScaledLazyDataImpl<T, S>(std::move(data), scale);
302}
303
309 template<class T1, class T2> inline
310 bool operator== ( LazyData<T1> const& a, LazyData<T2> const& b)
311{ return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin()); }
312
318 template<class T1, class T2> inline
319 bool operator==(LazyData<T1> const& a, DataVector<T2> const& b)
320{ return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin()); }
321
327 template<class T1, class T2> inline
328 bool operator== (DataVector<T1> const& a, LazyData<T2> const& b) { return b == a; }
329
335 template<class T1, class T2> inline bool operator!=(LazyData<T1> const& a, LazyData<T2> const& b) { return !(a==b); }
336 template<class T1, class T2> inline bool operator!=(LazyData<T1> const& a, DataVector<T2> const& b) { return !(a==b); }
337 template<class T1, class T2> inline bool operator!=(DataVector<T1> const& a, LazyData<T2> const& b) { return !(a==b); }
338
344 template<class T1, class T2> inline bool
345 operator< (LazyData<T1> const& a, LazyData<T2> const& b) { return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); }
346
347 template<class T1, class T2> inline bool
348 operator< (DataVector<T1> const& a, LazyData<T2> const& b) { return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); }
349
350 template<class T1, class T2> inline bool
351 operator< (LazyData<T1> const& a, DataVector<T2> const& b) { return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); }
352
358 template<class T1, class T2> inline bool operator> (LazyData<T1> const& a, LazyData<T2> const& b) { return b < a; }
359 template<class T1, class T2> inline bool operator> (DataVector<T1> const& a, LazyData<T2> const& b) { return b < a; }
360 template<class T1, class T2> inline bool operator> (LazyData<T1> const& a, DataVector<T2> const& b) { return b < a; }
361
367 template<class T1, class T2> inline bool operator<= (LazyData<T1> const& a, LazyData<T2> const& b) { return !(b < a); }
368 template<class T1, class T2> inline bool operator<= (DataVector<T1> const& a, LazyData<T2> const& b) { return !(b < a); }
369 template<class T1, class T2> inline bool operator<= (LazyData<T1> const& a, DataVector<T2> const& b) { return !(b < a); }
370
376 template<class T1, class T2> inline bool operator>= (LazyData<T1> const& a, LazyData<T2> const& b) { return !(a < b); }
377 template<class T1, class T2> inline bool operator>= (DataVector<T1> const& a, LazyData<T2> const& b) { return !(a < b); }
378 template<class T1, class T2> inline bool operator>= (LazyData<T1> const& a, DataVector<T2> const& b) { return !(a < b); }
379
386 template<class T>
387std::ostream& operator<<(std::ostream& out, LazyData<T> const& to_print) {
388 out << '['; return print_seq(out, to_print.begin(), to_print.end()) << ']';
389}
390
391
392#ifdef _MSC_VER // MSVC requires this while MingW does not accept it
393
394#define PLASK_API_EXTERN_TEMPLATE_SPECIALIZATION_FOR_LAZY_DATA(...) \
395 PLASK_API_EXTERN_TEMPLATE_SPECIALIZATION_CLASS(LazyData<__VA_ARGS__>); \
396 PLASK_API_EXTERN_TEMPLATE_SPECIALIZATION_STRUCT(LazyDataImpl<__VA_ARGS__>);
397
398 PLASK_API_EXTERN_TEMPLATE_SPECIALIZATION_FOR_LAZY_DATA(Tensor3<complex<double>>)
399 PLASK_API_EXTERN_TEMPLATE_SPECIALIZATION_FOR_LAZY_DATA(Tensor2<double>)
400 PLASK_API_EXTERN_TEMPLATE_SPECIALIZATION_FOR_LAZY_DATA(Vec<3,complex<double>>)
401 PLASK_API_EXTERN_TEMPLATE_SPECIALIZATION_FOR_LAZY_DATA(Vec<3,double>)
402 PLASK_API_EXTERN_TEMPLATE_SPECIALIZATION_FOR_LAZY_DATA(Vec<2,double>)
403 PLASK_API_EXTERN_TEMPLATE_SPECIALIZATION_FOR_LAZY_DATA(double)
404 PLASK_API_EXTERN_TEMPLATE_SPECIALIZATION_FOR_LAZY_DATA(complex<double>)
405
406#endif
407
408
413 template <typename T>
414 struct SafeDataImpl: public LazyDataImpl<T> {
415
416 const LazyData<T> src;
417 const T safe_value;
418
424 SafeDataImpl(const LazyData<T>& src, const T safe_value=Zero<T>()): src(src), safe_value(safe_value) {}
425
426 std::size_t size() const override { return src.size(); }
427
428 T at(std::size_t i) const override { return remove_nan(src.at(i), safe_value); }
429};
430
436 template <typename T>
437 inline LazyData<T> SafeData(const LazyData<T>& src, const T safe_value=Zero<T>()) {
438 return LazyData<T>(new SafeDataImpl<T>(src, safe_value));
439}
440
441} // namespace plask
442
443#if FMT_VERSION >= 90000
444 template <typename T> struct fmt::formatter<plask::LazyData<T>> : ostream_formatter {};
445#endif
446
447#endif // PLASK__LAZYDATA_H