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.
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
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>
88 #ifndef MDSPAN_EXTENTS_H
89 #define MDSPAN_EXTENTS_H
98 /*! \brief Define constant that signals dynamic extent.
100 enum : std::ptrdiff_t {
104 template< std::ptrdiff_t ... StaticExtents
>
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
;
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
)
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
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
)
247 this_extent
= rhs
.extent(R
);
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
275 /*! \libinternal \brief Specialisation for rank 0 extents analysis.
276 * Ends recursive rank analysis.
279 struct extents_analyse
<0> {
280 /*! \brief Rank of extent of rank 0.
283 static constexpr std::size_t rank() noexcept
{ return 0; }
284 /*! \brief Dynamic rank of extent of rank 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
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
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
>
336 using extents_analyse_t
= detail::extents_analyse
<sizeof ... (StaticExtents
), StaticExtents
...>;
339 //! Type used to index elements.
340 using index_type
= std::ptrdiff_t;
341 //! Trivial constructor
342 constexpr extents() noexcept
{}
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) {}
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;
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()); }
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
) );
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
);
447 #endif /* end of include guard: MDSPAN_EXTENTS_H */