MakeArray.hpp
Go to the documentation of this file.
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 /// \file
5 /// Defines function make_array.
6 
7 #pragma once
8 
9 #include <array>
10 #include <cstddef>
11 #include <iterator>
12 #include <utility>
13 
15 #include "Utilities/Requires.hpp"
16 #include "Utilities/TMPL.hpp"
17 #include "Utilities/TypeTraits.hpp"
18 
19 // Much of this is taken from
20 // http://stackoverflow.com/questions/1065774/initialization-of
21 // -a-normal-array-with-one-default-value
22 // with some modifications.
23 namespace MakeArray_detail {
24 // We handle the zero size case separately below because both for size zero
25 // and size one arrays the index_sequence is empty.
26 // We use the index_sequence to be able to fill the first Size-1 (which is
27 // sizeof...(Is)) via constructor calls `T(args...)`. The final element is
28 // forwarded to avoid a possible copy if an rvalue reference is passed to
29 // make_array. The generic implementation handles both the make_array(T&&) case
30 // and the make_array(Args&&...) case below.
31 // The (void)Is cast is to avoid any potential trouble with overloaded comma
32 // operators.
33 template <bool SizeZero>
34 struct MakeArray {
35  template <typename T, typename... Args, size_t... Is>
36  static SPECTRE_ALWAYS_INLINE constexpr std::array<T, sizeof...(Is) + 1> apply(
37  std::index_sequence<Is...> /* unused */,
38  Args&&... args) noexcept(noexcept(std::array<T, sizeof...(Is) + 1>{
39  {((void)Is, T(args...))..., T(std::forward<Args>(args)...)}})) {
40  return {{((void)Is, T(args...))..., T(std::forward<Args>(args)...)}};
41  }
42 };
43 
44 template <>
45 struct MakeArray<true> {
46  template <typename T, typename... Args>
48  std::index_sequence<> /* unused */, Args&&... args) noexcept {
49 #ifndef HAVE_BROKEN_ARRAY0
50  expand_pack(args...); // Used in other preprocessor branch
51  return std::array<T, 0>{{}};
52 #else // HAVE_BROKEN_ARRAY0
53  // https://bugs.llvm.org/show_bug.cgi?id=35491
54  return {{T(std::forward<Args>(args)...)}};
55 #endif // HAVE_BROKEN_ARRAY0
56  }
57 };
58 } // namespace MakeArray_detail
59 
60 /*!
61  * \ingroup UtilitiesGroup
62  * \brief Create a `std::array<T, Size>{{T(args...), T(args...), ...}}`
63  * \tparam Size the size of the array
64  * \tparam T the type of the element in the array
65  */
66 template <size_t Size, typename T, typename... Args>
68 make_array(Args&&... args) noexcept(
69  noexcept(MakeArray_detail::MakeArray<Size == 0>::template apply<T>(
70  std::make_index_sequence<(Size == 0 ? Size : Size - 1)>{},
71  std::forward<Args>(args)...))) {
72  return MakeArray_detail::MakeArray<Size == 0>::template apply<T>(
73  std::make_index_sequence<(Size == 0 ? Size : Size - 1)>{},
74  std::forward<Args>(args)...);
75 }
76 
77 /*!
78  * \ingroup UtilitiesGroup
79  * \brief Create a `std::array<std::decay_t<T>, Size>{{t, t, ...}}`
80  * \tparam Size the size of the array
81  */
82 template <size_t Size, typename T>
83 SPECTRE_ALWAYS_INLINE constexpr auto make_array(T&& t) noexcept(noexcept(
84  MakeArray_detail::MakeArray<Size == 0>::template apply<std::decay_t<T>>(
85  std::make_index_sequence<(Size == 0 ? Size : Size - 1)>{},
86  std::forward<T>(t)))) -> std::array<std::decay_t<T>, Size> {
87  return MakeArray_detail::MakeArray<Size == 0>::template apply<
89  std::make_index_sequence<(Size == 0 ? Size : Size - 1)>{},
90  std::forward<T>(t));
91 }
92 
93 /*!
94  * \ingroup UtilitiesGroup
95  * \brief Helper function to initialize a std::array with varying number of
96  * arguments
97  */
98 template <typename T, typename... V, Requires<(sizeof...(V) > 0)> = nullptr>
99 SPECTRE_ALWAYS_INLINE constexpr auto make_array(T&& t, V&&... values) noexcept(
100  noexcept(std::array<std::decay_t<T>, sizeof...(V) + 1>{
101  {std::forward<T>(t), std::forward<V>(values)...}}))
102  -> std::array<typename std::decay_t<T>, sizeof...(V) + 1> {
103  static_assert(
105  "all types to make_array(...) must be the same");
106  return std::array<std::decay_t<T>, sizeof...(V) + 1>{
107  {std::forward<T>(t), std::forward<V>(values)...}};
108 }
109 
110 namespace MakeArray_detail {
111 template <typename Seq, typename T,
113 constexpr T&& forward_element(T& t) noexcept {
114  return std::move(t);
115 }
116 template <typename Seq, typename T,
118 constexpr T& forward_element(T& t) noexcept {
119  return t;
120 }
121 
122 template <typename T, size_t size, typename Seq, size_t... indexes>
123 constexpr std::array<T, size> make_array_from_iterator_impl(
124  Seq&& s,
126  size_t, indexes...> /*meta*/) noexcept(noexcept(std::array<T, size>{
127  {forward_element<decltype(s)>(*(std::begin(s) + indexes))...}})) {
128  // clang-tidy: do not use pointer arithmetic
129  return std::array<T, size>{
130  {forward_element<decltype(s)>(*(std::begin(s) + indexes))...}}; // NOLINT
131 }
132 } // namespace MakeArray_detail
133 
134 /*!
135  * \ingroup UtilitiesGroup
136  * \brief Create an `std::array<T, size>` from the first `size` values of `seq`
137  *
138  * \requires `Seq` has a `begin` function
139  * \tparam T the type held by the array
140  * \tparam size the size of the created array
141  */
142 template <typename T, size_t size, typename Seq>
143 constexpr std::array<T, size> make_array(Seq&& seq) noexcept(
144  noexcept(MakeArray_detail::make_array_from_iterator_impl<T, size>(
145  std::forward<Seq>(seq), std::make_index_sequence<size>{}))) {
146  return MakeArray_detail::make_array_from_iterator_impl<T, size>(
147  std::forward<Seq>(seq), std::make_index_sequence<size>{});
148 }
constexpr bool flat_all_v
A non-short-circuiting logical AND between bools &#39;B"".
Definition: TMPL.hpp:504
Defines the type alias Requires.
constexpr auto apply(F &&f, const DataBox< BoxTags > &box, Args &&... args)
Apply the function f with argument Tags TagsList from DataBox box
Definition: DataBox.hpp:1595
Definition: MakeArray.hpp:23
#define SPECTRE_ALWAYS_INLINE
Always inline a function. Only use this if you benchmarked the code.
Definition: ForceInline.hpp:20
constexpr std::array< T, Size > make_array(Args &&... args) noexcept(noexcept(MakeArray_detail::MakeArray< Size==0 >::template apply< T >(std::make_index_sequence<(Size==0 ? Size :Size - 1)>{}, std::forward< Args >(args)...)))
Create a std::array<T, Size>{{T(args...), T(args...), ...}}
Definition: MakeArray.hpp:68
constexpr bool is_same_v
Variable template for is_same.
Definition: TypeTraits.hpp:221
Defines macro to always inline a function.
Wraps the template metaprogramming library used (brigand)
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t ...
Definition: Requires.hpp:67
Defines type traits, some of which are future STL type_traits header.
constexpr void expand_pack(Ts &&...) noexcept
Allows zero-cost unordered expansion of a parameter.
Definition: TMPL.hpp:545