Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2025 The plumed team
3 : (see the PEOPLE file at the root of the distribution for a list of names)
4 :
5 : See http://www.plumed.org for more information.
6 :
7 : This file is part of plumed, version 2.
8 :
9 : plumed is free software: you can redistribute it and/or modify
10 : it under the terms of the GNU Lesser General Public License as published by
11 : the Free Software Foundation, either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : plumed is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU Lesser General Public License for more details.
18 :
19 : You should have received a copy of the GNU Lesser General Public License
20 : along with plumed. If not, see <http://www.gnu.org/licenses/>.
21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 : #ifndef __PLUMED_tools_View_h
23 : #define __PLUMED_tools_View_h
24 : #include <limits>
25 : #include <type_traits>
26 :
27 : #include "Vector.h"
28 :
29 : namespace PLMD {
30 : namespace helpers {
31 : /// A way of specifying a dynamic extent for a view
32 : inline constexpr std::size_t dynamic_extent =
33 : std::numeric_limits<std::size_t>::max();
34 : template <unsigned N, typename T> static constexpr void _zero(T *d) noexcept {
35 : if constexpr (N == 1) {
36 : d[0] = T(0);
37 : } else {
38 : _zero<N - 1>(d);
39 : d[N - 1] = T(0);
40 : }
41 : }
42 : } // namespace helpers
43 :
44 : /**A not-owning view for generic data
45 :
46 : The main idea is to have something that works like the span from c++20.
47 :
48 : View are CHEAP to copy (pointer and an integer), so it is better to pass
49 : them as values
50 :
51 : Can be used from PLMD::Vectors and standard types
52 :
53 : accessing the data of a PLMD::Vector as double:
54 : @code{.cpp}
55 : std::vector<PLMD::VecorGeneric<3>> v(3);
56 : PLMD::View<double,3> vd(&v[0][0]);
57 : @endcode
58 :
59 : accessing the data of a PLMD::Vector as PLMD::VectorGeneric<3>:
60 : @code{.cpp}
61 : std::vector<PLMD::VecorGeneric<3>> v(3);
62 : PLMD::View<PLMD::VecorGeneric<3>,3> vd(v.data());
63 : @endcode
64 :
65 : @todo ctors from std::array and from iterators to parallel the span
66 : implementatio
67 : */
68 : template <typename T, std::size_t N = helpers::dynamic_extent> class View {
69 : public:
70 : using value_type = T;
71 : using pointer = value_type *;
72 : using iterator = pointer;
73 : using const_iterator = const pointer;
74 : using reference = value_type &;
75 : using const_reference = const value_type &;
76 :
77 : private:
78 : pointer ptr_;
79 : std::size_t size_{N};
80 :
81 : public:
82 : // constructor for fixed size View
83 : template <size_t NN = N,
84 : typename = std::enable_if_t<NN != helpers::dynamic_extent>>
85 64787202 : explicit View(pointer p) noexcept : ptr_(p) {}
86 : // generic constructor, works also for non fixed view (this might change)
87 240391390 : View(pointer p, std::size_t const NN) noexcept : ptr_(p), size_(NN) {}
88 : View(const View &) noexcept = default;
89 : View(View &&) noexcept = default;
90 : View &operator=(const View &) noexcept = default;
91 : View &operator=(View &&) noexcept = default;
92 : // returns the dimension
93 : constexpr size_t size() const noexcept {
94 953325190 : return size_;
95 : }
96 :
97 : /// returns the reference i-th element
98 : constexpr reference operator[](size_t i) noexcept {
99 3332390651 : return ptr_[i];
100 : }
101 :
102 : /// returns the reference i-th element
103 : constexpr const_reference operator[](size_t i) const noexcept {
104 2005286977 : return ptr_[i];
105 : }
106 :
107 : /// return the pointer to the data
108 : constexpr pointer data() const noexcept {
109 175172230 : return ptr_;
110 : }
111 :
112 : /// return a subview on consecutive elements
113 : constexpr View<value_type, helpers::dynamic_extent>
114 : subview(size_t offset,
115 : size_t count = helpers::dynamic_extent) const noexcept {
116 : /// @TODO: enforce these or accept the risk of undefined behaviour in
117 : /// exchange for performance
118 : // assert(offset <= size(), "subview: offset out of range");
119 : // if (count != helpers::dynamic_extent) {
120 : // assert(count <= (size()-offset), "subview: count out of range");
121 : // }
122 256 : return {data() + offset,
123 256 : count != helpers::dynamic_extent ? count : size() - offset};
124 : }
125 :
126 : /// return a subview on consecutive elements
127 : template <size_t Offset, size_t Count = helpers::dynamic_extent>
128 : constexpr auto subview() const noexcept {
129 : // I am more or less implementing the subspan form the std
130 : constexpr size_t FinalExtent =
131 : (Count != helpers::dynamic_extent)
132 : ? Count
133 : : (N != helpers::dynamic_extent ? N - Offset
134 : : helpers::dynamic_extent);
135 : static_assert(Offset <= N, "subview: offset out of range");
136 : if constexpr (Count != helpers::dynamic_extent) {
137 : static_assert(Count <= (N - Offset), "subview: count out of range");
138 : }
139 : return View<T, FinalExtent> {
140 : data() + Offset,
141 : Count != helpers::dynamic_extent ? Count : size() - Offset
142 : };
143 : }
144 :
145 : /// return a subview of specific size consecutive elements
146 : template <size_t Count>
147 : constexpr View<value_type, Count> subview_n(size_t offset) const noexcept {
148 : /// @TODO: enforce these or accept the risk of undefined behaviour in
149 : /// exchange for performance
150 : // assert(offset <= size(), "subview: offset out of range");
151 : // if (count != helpers::dynamic_extent) {
152 : // assert(count <= (size()-offset), "subview: count out of range");
153 : // }
154 : static_assert(Count <= N, "subview: count out of range");
155 16004493 : return View<value_type, Count> {data() + offset};
156 : }
157 :
158 : constexpr iterator begin() noexcept {
159 : return ptr_;
160 : }
161 :
162 : constexpr const_iterator begin() const noexcept {
163 : return ptr_;
164 : }
165 :
166 : constexpr const_iterator cbegin() const noexcept {
167 : return ptr_;
168 : }
169 :
170 : constexpr iterator end() noexcept {
171 15750174 : return ptr_ + size_;
172 : }
173 :
174 : constexpr const_iterator end() const noexcept {
175 119236 : return ptr_ + size_;
176 : }
177 :
178 : constexpr const_iterator cend() const noexcept {
179 : return ptr_ + size_;
180 : }
181 :
182 2 : void zero() noexcept {
183 : if constexpr (N != helpers::dynamic_extent) {
184 2 : LoopUnroller<N>::_zero(ptr_);
185 : } else {
186 : for (unsigned i = 0; i < size_; ++i) {
187 : ptr_[i] = T(0);
188 : }
189 : }
190 2 : }
191 :
192 : /// assignment from a PLMD::VectorTyped of the same type
193 : template <size_t M = N, typename VT, unsigned VD,
194 : typename = std::enable_if_t<
195 : M >= VD && std::is_same_v<T, std::remove_const_t<VT>>>>
196 : auto &operator=(const VectorTyped<VT, VD> &v) noexcept {
197 : // NOTE: if N==dynamic_extent and size_<VD, this is UB
198 946046 : PLMD::LoopUnroller<VD>::_copy(ptr_, v.data());
199 : return *this;
200 : }
201 :
202 : /// assignment from a PLMD::VectorTyped explicitly request an eventual
203 : /// conversion
204 : template <size_t M = N, typename VT, unsigned VD,
205 : typename = std::enable_if_t<M >= VD>>
206 : auto ©Conv(const VectorTyped<VT, VD> &v) noexcept {
207 : // NOTE: if N==dynamic_extent and size_<VD, this is UB
208 : PLMD::LoopUnroller<VD>::_copy(ptr_, v.data());
209 : return *this;
210 : }
211 :
212 : template <size_t M = N, typename VT, unsigned VD,
213 : typename = std::enable_if_t<
214 : M >= VD && std::is_same_v<T, std::remove_const_t<VT>>>>
215 13731677 : auto &operator+=(const VectorTyped<VT, VD> &v) noexcept {
216 : // NOTE: if N==dynamic_extent and size_<VD, this is UB
217 13731677 : PLMD::LoopUnroller<VD>::_add(ptr_, v.data());
218 13731677 : return *this;
219 : }
220 :
221 : template <size_t M = N, typename VT, unsigned VD,
222 : typename = std::enable_if_t<
223 : M >= VD && std::is_same_v<T, std::remove_const_t<VT>>>>
224 13731677 : auto &operator-=(const VectorTyped<VT, VD> &v) noexcept {
225 : // NOTE: if N==dynamic_extent and size_<VD, this is UB
226 13731677 : PLMD::LoopUnroller<VD>::_sub(ptr_, v.data());
227 13731677 : return *this;
228 : }
229 :
230 1012170 : template <typename TT> auto &operator*=(const TT v) noexcept {
231 : if constexpr (N != helpers::dynamic_extent) {
232 1012170 : PLMD::LoopUnroller<N>::_mul(ptr_, v);
233 : } else {
234 : for (unsigned i = 0; i < size_; ++i) {
235 : ptr_[i] *= v;
236 : }
237 : }
238 1012170 : return *this;
239 : }
240 :
241 : template <typename TT> auto &operator/=(const TT v) noexcept {
242 : return operator*=(T(1.0) / v);
243 : }
244 : // some mathematical helper operations
245 : // summed as double for precision concerns, maybe it is paranoid, maybe not
246 : double modulo2() const noexcept {
247 : if constexpr (N != helpers::dynamic_extent) {
248 : return LoopUnroller<N>::_sum2(ptr_);
249 : } else {
250 : double sum = 0.0;
251 : for (unsigned i = 0; i < size_; ++i) {
252 : sum += ptr_[i] * ptr_[i];
253 : }
254 : return sum;
255 : }
256 : }
257 :
258 : double modulo() const noexcept {
259 : return sqrt(modulo2());
260 : ;
261 : }
262 : };
263 :
264 : template <typename T>
265 2261983 : VectorTyped<std::remove_const_t<T>, 3> delta(const View<T, 3> v1,
266 : const View<T, 3> v2) noexcept {
267 : // removing the const will improve some code interactions
268 : return VectorTyped<std::remove_const_t<T>, 3> {
269 : v2[0] - v1[0],
270 : v2[1] - v1[1],
271 : v2[2] - v1[2]
272 2261983 : };
273 : }
274 :
275 : ///Returns a complete dynamic view of a container
276 : ///
277 : ///The container must have defined the methods `data()` and `size()`
278 : ///Also the container must have defined a public type `value_type`
279 : ///For example a std::vector is compatible
280 : ///A const std::vector is not compatible with this signature, to avoid confusion
281 : template <typename CT>
282 : constexpr View<typename CT::value_type> make_view(CT& container) {
283 : return {container.data(),container.size()};
284 : }
285 :
286 : ///Returns a complete constant dynamic view of a container
287 : ///
288 : ///The container must have defined the methods `data()` and `size()`
289 : ///Also the container must have defined a public type `value_type`
290 : ///For example a std::vector is compatible
291 : template <typename CT>
292 : constexpr View<const typename CT::value_type> make_const_view(const CT& container) {
293 : return {container.data(),container.size()};
294 : }
295 : } // namespace PLMD
296 : #endif // __PLUMED_tools_View_h
|