]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Introduce an ndarray type alias
authorMatthias Maier <tamiko@43-1.org>
Sat, 13 Feb 2021 19:35:04 +0000 (13:35 -0600)
committerMatthias Maier <tamiko@43-1.org>
Sat, 20 Feb 2021 00:43:53 +0000 (18:43 -0600)
The ndarray type alias models an multidimensional array. It has a
variable number of template arguments denoting the size of each index
that get internally converted to stacked std::arrays. For example:

    dealii::ndarray<double, 1, 2, 3, 4> my_array

is an alias for the following construct:

    std::array<std::array<std::array<std::array<double, 4>, 3>, 2>, 1>

include/deal.II/base/ndarray.h [new file with mode: 0644]

diff --git a/include/deal.II/base/ndarray.h b/include/deal.II/base/ndarray.h
new file mode 100644 (file)
index 0000000..74b558e
--- /dev/null
@@ -0,0 +1,112 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2021 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_ndarray_h
+#define dealii_ndarray_h
+
+#include <deal.II/base/config.h>
+
+#include <deal.II/base/exceptions.h>
+
+#include <array>
+
+DEAL_II_NAMESPACE_OPEN
+
+#ifndef DOXYGEN
+namespace internal
+{
+  namespace ndarray
+  {
+    // clang-format off
+    /**
+     * A variadic template helper class to recursively "unroll" the size
+     * information of the ndarray. This is best explained on an example:
+     * @code
+     *    HelperArray<double, 1, 2, 3, 4>::type
+     * == std::array<HelperArray<double, 2, 3, 4>::type, 1>
+     * == std::array<std::array<HelperArray<double, 3, 4>::type, 2>, 1>
+     * == std::array<std::array<std::array<HelperArray<double, 4>::type, 3>, 2>, 1>
+     * == std::array<std::array<std::array<std::array<HelperArray<double>::type, 4>, 3>, 2>, 1>
+     * == std::array<std::array<std::array<std::array<double, 4>, 3>, 2>, 1>
+     * @endcode
+     */
+    template <typename T, std::size_t... Ns>
+    struct HelperArray;
+    // clang-format on
+
+    /**
+     * Recursively define the type alias "type" of HelperArray<T, N, ...Ns>
+     * by wrapping a std::array around HelperArray<T, Ns...>::type
+     */
+    template <typename T, std::size_t N, std::size_t... Ns>
+    struct HelperArray<T, N, Ns...>
+    {
+      using type = std::array<typename HelperArray<T, Ns...>::type, N>;
+    };
+
+    /**
+     * End recursion once no std::size_t template parameters are left and
+     * simply set the type alias to type T
+     */
+    template <typename T>
+    struct HelperArray<T>
+    {
+      using type = T;
+    };
+  } // namespace ndarray
+} // namespace internal
+#endif // DOXYGEN
+
+/**
+ * A (variadic template) type alias for conveniently defining multidimensional
+ * <a href="https://en.cppreference.com/w/cpp/container/array">std::array</a>s
+ *
+ * The problem we try to address with the type alias is the following.
+ * Suppose you want to create a multdimensional array of doubles of, for
+ * example, rank 3, with sizes 2, 3, 4 for the first, middle, and last
+ * index. Then using C-style arrays you could simply write
+ * @code
+ *   double my_array[2][3][4] = { ... };
+ * @endcode
+ * Nowadays, there are a number of good reasons why using C-style arrays is
+ * usually discouraged (ranging from incompatibilities with STL functions
+ * requiring awkward wrappers, surprises when comparing for equality, etc.)
+ * If you want to do the same, however, using the more modern (and
+ * encouraged) `std::array` class, then you would have to declare
+ * @code
+ *   std::array<std::array<std::array<double, 4>, 3>, 2> = { ... };
+ * @endcode
+ * The repetitions of `std::array` look awkward and, worse, the index
+ * ranges have reversed: the leftmost index has range [0,2), the middle
+ * index has rnage [0,3) and the rightmost index has range [0,4).
+ * We address this issue by providing a class ndarray that allows to you
+ * declare the above stacked `std::array` type by simply writing:
+ * @code
+ *   dealii::ndarray<double, 2, 3, 4> my_array = { ... };
+ * @endcode
+ *
+ * @note dealii::ndarray is merely syntactic sugar in form of a
+ * <a href="https://en.cppreference.com/w/cpp/language/type_alias">type
+ * alias</a>
+ * (`using` declaration). It is not a deal.II specific class, but merely a
+ * helper to cleanly define multidimensional arrays realized by "stacked"
+ * `std::array` classes.
+ */
+template <typename T, std::size_t... Ns>
+using ndarray = typename internal::ndarray::HelperArray<T, Ns...>::type;
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.