Add replacements for pbc enumerations
[gromacs.git] / src / gromacs / mdspan / extents.h
blob06f1ef0f51486bb4737749d8d1f191c89de49b87
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2018,2019, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS 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 GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
36 * This file is a modified version of original work of Sandia Corporation.
37 * In the spirit of the original code, this particular file can be distributed
38 * on the terms of Sandia Corporation.
41 * Kokkos v. 2.0
42 * Copyright (2014) Sandia Corporation
44 * Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
45 * the U.S. Government retains certain rights in this software.
47 * Kokkos is licensed under 3-clause BSD terms of use:
49 * Redistribution and use in source and binary forms, with or without
50 * modification, are permitted provided that the following conditions are
51 * met:
53 * 1. Redistributions of source code must retain the above copyright
54 * notice, this list of conditions and the following disclaimer.
56 * 2. Redistributions in binary form must reproduce the above copyright
57 * notice, this list of conditions and the following disclaimer in the
58 * documentation and/or other materials provided with the distribution.
60 * 3. Neither the name of the Corporation nor the names of the
61 * contributors may be used to endorse or promote products derived from
62 * this software without specific prior written permission.
64 * THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
65 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
67 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
68 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
69 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
70 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
71 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
72 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
73 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
74 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
76 * Questions? Contact Christian R. Trott (crtrott@sandia.gov)
78 /*! \libinternal \file
79 * \brief Declares gmx::extents for mdspan.
81 * \author Christian Trott <crtrott@sandia.gov>
82 * \author Ronan Keryell <ronan.keryell@xilinx.com>
83 * \author Carter Edwards <hedwards@nvidia.com>
84 * \author David Hollman <dshollm@sandia.gov>
85 * \author Christian Blau <cblau@gwdg.de>
86 * \ingroup mdspan
88 #ifndef MDSPAN_EXTENTS_H
89 #define MDSPAN_EXTENTS_H
91 #include <cstddef>
93 #include <array>
95 namespace gmx
98 /*! \brief Define constant that signals dynamic extent.
100 enum : std::ptrdiff_t {
101 dynamic_extent = -1
104 template< std::ptrdiff_t ... StaticExtents >
105 class extents;
107 template<std::ptrdiff_t... LHS, std::ptrdiff_t... RHS>
108 constexpr bool operator==(const extents<LHS...> &lhs,
109 const extents<RHS...> &rhs) noexcept;
111 template<std::ptrdiff_t... LHS, std::ptrdiff_t... RHS>
112 constexpr bool operator!=(const extents<LHS...> &lhs,
113 const extents<RHS...> &rhs) noexcept;
115 namespace detail
118 template< int R, std::ptrdiff_t ... StaticExtents >
119 struct extents_analyse;
121 /*! \libinternal \brief Enable querying extent of specific rank by splitting
122 * a static extents off the variadic template arguments.
125 template< int R, std::ptrdiff_t E0, std::ptrdiff_t ... StaticExtents >
126 struct extents_analyse<R, E0, StaticExtents...> {
128 //! The extent analysis of the next lower rank.
129 using next_extents_analyse = extents_analyse<R-1, StaticExtents...>;
131 /*! \brief Accumulate the total rank from all extents.
132 * \returns incremented rank of the next extent
134 static constexpr std::size_t rank() noexcept { return next_extents_analyse::rank()+1; }
135 /*! \brief Accumulate the dynamic rank from all extents.
136 * This extent is static, so hand down query to the next extent analysis.
137 * \returns the dynamic rank of the next extent analysis.
139 static constexpr std::size_t rank_dynamic() noexcept { return next_extents_analyse::rank_dynamic(); }
141 //! Store analysis of the next extent of next lower rank.
142 next_extents_analyse next;
144 //! Trivial constructor.
145 constexpr extents_analyse() : next() {}
147 /*! \brief Construction from dynamic extents hands the extents down
148 * to the next extents analysis of lower rank.
149 * \param[in] de dynamic extents
151 template<class ... DynamicExtents>
152 constexpr extents_analyse(DynamicExtents... de) : next(de ...) {}
154 /*! \brief Construct from an array of dynamic extentes and rank.
155 * Hand down the dynamic rank parameters to the next extents analysis rank
156 * \param[in] de dynamic extents
157 * \param[in] r rank to read from the dynamic extent
159 template<std::size_t Rank>
160 constexpr extents_analyse(const std::array<std::ptrdiff_t, Rank> &de, const std::size_t r) : next(de, r) {}
162 //! Copy constructor.
163 template<std::ptrdiff_t... OtherStaticExtents>
164 extents_analyse(extents_analyse<R, OtherStaticExtents...> rhs) : next(rhs.next) {}
166 //! Assignment operator.
167 template<std::ptrdiff_t... OtherStaticExtents>
168 extents_analyse &operator= (extents_analyse<R, OtherStaticExtents...> rhs)
170 next = rhs.next;
171 return *this;
174 /*! \brief Report extent of dimension r.
175 * \param[in] r the dimension to query
176 * \returns the extent in dimension r.
178 constexpr std::ptrdiff_t extent(const std::size_t r) const noexcept
180 return (r == R) ? E0 : next.extent(r);
182 /*! \brief Report the static extent of dimension r.
183 * \param[in] r the dimension to query
184 * \returns the static extent in dimension r.
186 static constexpr std::ptrdiff_t static_extent(const std::size_t r) noexcept
188 return (r == R) ? E0 : next_extents_analyse::static_extent(r);
191 //! Returns the extent with the first dimension sliced off
192 constexpr auto sliced_extents() const noexcept
194 return next;
198 /*! \libinternal \brief Enable querying extent of specific rank by splitting
199 * a dynamic extent off the variadic template arguments.
201 template< int R, std::ptrdiff_t ... StaticExtents >
202 struct extents_analyse<R, dynamic_extent, StaticExtents...> {
203 //! The extent analysis of the next lower rank.
204 using next_extents_analyse = extents_analyse<R-1, StaticExtents...>;
205 /*! \brief Accumulate the total rank from all extents.
206 * \returns incremented rank of the next extent
208 static constexpr std::size_t rank() noexcept { return next_extents_analyse::rank()+1; }
209 /*! \brief Accumulate the dynamic rank from all extents.
210 * \returns the dynamic rank of the next extent analysis.
212 static constexpr std::size_t rank_dynamic() noexcept { return next_extents_analyse::rank_dynamic()+1; }
214 //! Store analysis of the next extent of next lower rank.
215 next_extents_analyse next;
216 //! The dynamic extent of this rank
217 std::ptrdiff_t this_extent;
219 //! Trivial constructor.
220 extents_analyse() : next(), this_extent(0) {}
222 /*! \brief Construction from dynamic extents hands the extents down
223 * to the next extents analysis of lower rank.
224 * \param[in] E the dynamic extent of this rank.
225 * \param[in] de dynamic extents
227 template<class ... DynamicExtents>
228 extents_analyse(std::ptrdiff_t E, DynamicExtents... de) : next(de ...), this_extent(E) {}
230 /*! \brief Construct from an array of dynamic extentes and rank.
231 * Hand down the dynamic rank parameters to the next extents analysis rank
232 * \param[in] de dynamic extents
233 * \param[in] r rank to read from the dynamic extent
235 template<std::size_t Rank>
236 extents_analyse(const std::array<std::ptrdiff_t, Rank> &de, const std::size_t r) : next(de, r+1), this_extent(de[r]) {}
238 //! Copy constructor.
239 template<std::ptrdiff_t... OtherStaticExtents>
240 extents_analyse(extents_analyse<R, OtherStaticExtents...> rhs) : next(rhs.next), this_extent(rhs.extent(R)) {}
242 //! Assignment operator.
243 template<std::ptrdiff_t... OtherStaticExtents>
244 extents_analyse &operator= (extents_analyse<R, OtherStaticExtents...> rhs)
246 next = rhs.next;
247 this_extent = rhs.extent(R);
248 return *this;
251 /*! \brief Report extent of dimension r.
252 * \param[in] r the dimension to query
253 * \returns the extent in dimension r.
255 constexpr std::ptrdiff_t extent(const std::size_t r) const noexcept
257 return (r == R) ? this_extent : next.extent(r);
259 /*! \brief Report the static extent of dimension r.
260 * \param[in] r the dimension to query
261 * \returns the static extent in dimension r.
263 static constexpr std::ptrdiff_t static_extent(const std::size_t r) noexcept
265 return (r == R) ? dynamic_extent : next_extents_analyse::static_extent(r);
268 //! Returns the extent with the first dimension sliced off
269 constexpr auto sliced_extents() const noexcept
271 return next;
275 /*! \libinternal \brief Specialisation for rank 0 extents analysis.
276 * Ends recursive rank analysis.
278 template<>
279 struct extents_analyse<0> {
280 /*! \brief Rank of extent of rank 0.
281 * \returns 0
283 static constexpr std::size_t rank() noexcept { return 0; }
284 /*! \brief Dynamic rank of extent of rank 0.
285 * \returns 0
287 static constexpr std::size_t rank_dynamic() noexcept { return 0; }
289 //! Trivial constructor.
290 constexpr extents_analyse() {}
292 //! Construct from array and rank, doing nothing.
293 template<std::size_t Rank>
294 extents_analyse(const std::array<std::ptrdiff_t, Rank> & /*de*/, const std::size_t /*r*/) {}
296 //extents_analyse & operator=(extents_analyse) = default;
298 /*! \brief Extent of rank 0 is 1, ensuring that product of extents yields required size and not zero.
299 * NOTE changed from ORNL reference implementation in making this static constexpr instead of constexpr .. const
301 static constexpr std::ptrdiff_t extent(const std::size_t /*r*/) noexcept
303 return 1;
306 //! Static extent of rank 0 is 1, ensuring that product of extents yields required size and not zero.
307 static constexpr std::ptrdiff_t static_extent(const std::size_t /*r*/) noexcept
309 return 1;
314 template< std::ptrdiff_t E0, std::ptrdiff_t ... StaticExtents >
315 struct sliced_extents
317 using type = extents<StaticExtents...>;
319 } // namespace detail
321 /*! \libinternal \brief Multidimensional extents with static and dynamic dimensions.
323 * Describes a multidimensional index space of rank R.
324 * This is equivalent to the Cartesian product space of integer intervals
325 * [0, N_0) x [0, N_1) x ... x [0,N_{R-1} )
327 * Confer to P0009r8 of the Library Evolution Working Group and mdspan.extents
329 * \tparam StaticExtents rank number of extents, where the dynamic_extent
330 * constant for static extent is used to signal a dynamic extent.
332 template< std::ptrdiff_t ... StaticExtents >
333 class extents
335 private:
336 using extents_analyse_t = detail::extents_analyse<sizeof ... (StaticExtents), StaticExtents...>;
338 public:
339 //! Type used to index elements.
340 using index_type = std::ptrdiff_t;
341 //! Trivial constructor
342 constexpr extents() noexcept {}
343 //! Move constructor
344 constexpr extents( extents && ) noexcept = default;
345 //! Copy constructor.
346 constexpr extents( const extents & ) noexcept = default;
347 /*! \brief Construct with dynamic extents.
349 * Allows for extents(u,v,w..) syntax when setting dynamic extents
351 * \tparam IndexType type of index
352 * \param[in] dn first dynamic index
353 * \param[in] DynamicExtents parameter pack
355 template< class ... IndexType >
356 constexpr extents( std::ptrdiff_t dn,
357 IndexType ... DynamicExtents ) noexcept
358 : impl( dn, DynamicExtents ... )
359 { static_assert( 1+sizeof ... (DynamicExtents) == rank_dynamic(), "" ); }
361 /*! \brief Construct from array of dynamic extents.
363 * Allows for extents({{u,v,w..}}) syntax when setting dynamic extents
365 * \param[in] dynamic_extents array of dynamic rank size containing extents
367 constexpr extents( const std::array<std::ptrdiff_t, extents_analyse_t::rank_dynamic()> dynamic_extents) noexcept
368 : impl(dynamic_extents, 0) {}
370 //! Copy constructor
371 template<std::ptrdiff_t... OtherStaticExtents>
372 extents( const extents<OtherStaticExtents...> &other )
373 : impl( other.impl ) {}
375 //! Default move assignment
376 extents &operator= ( extents && ) noexcept = default;
377 //! Default copy assignment
378 extents &operator= ( const extents & ) noexcept = default;
379 //! Copy assignment
380 template<std::ptrdiff_t... OtherStaticExtents>
381 extents &operator= ( const extents<OtherStaticExtents...> &other )
382 { impl = other.impl; return *this; }
383 //! Default destructor
384 ~extents() = default;
386 // [mdspan.extents.obs]
387 /*! \brief The rank of the extent.
388 * \returns the rank all extents together
390 static constexpr std::size_t rank() noexcept
391 { return sizeof ... (StaticExtents); }
392 /*! \brief The rank of the dynamic extents.
393 * \returns Only the dynamic extents.
395 static constexpr std::size_t rank_dynamic() noexcept
396 { return extents_analyse_t::rank_dynamic(); }
397 /*! \brief The rank of the static extents.
398 * \returns Only the static extents.
400 static constexpr index_type static_extent(std::size_t k) noexcept
401 { return extents_analyse_t::static_extent(rank()-k); }
402 /*! \brief The extent along a specific dimension.
403 * \param[in] k the dimension
404 * \returns the extent along that dimension
406 constexpr index_type extent(std::size_t k) const noexcept
407 { return impl.extent(rank()-k); }
408 //! Returns the extent with the first dimension sliced off
409 constexpr auto sliced_extents() const noexcept
410 { return typename detail::sliced_extents<StaticExtents...>::type(impl.sliced_extents()); }
412 private:
413 extents(extents_analyse_t o) : impl(o) {}
414 //! For copy assignment, extents are friends of extents.
415 template< std::ptrdiff_t... > friend class extents;
416 //! The implementation class.
417 extents_analyse_t impl;
421 /*! \brief Comparison operator.
422 * \returns true if extents are equal
424 template<std::ptrdiff_t... LHS, std::ptrdiff_t... RHS>
425 constexpr bool operator==(const extents<LHS...> &lhs,
426 const extents<RHS...> &rhs) noexcept
428 bool equal = lhs.rank() == rhs.rank();
429 for (std::size_t r = 0; r < lhs.rank(); r++)
431 equal = equal && ( lhs.extent(r) == rhs.extent(r) );
433 return equal;
436 /*! \brief Check for non-equality.
437 * \returns true if extents are unequal
439 template<std::ptrdiff_t... LHS, std::ptrdiff_t... RHS>
440 constexpr bool operator!=(const extents<LHS...> &lhs,
441 const extents<RHS...> &rhs) noexcept
443 return !(lhs == rhs);
446 } // namespace gmx
447 #endif /* end of include guard: MDSPAN_EXTENTS_H */