Line data Source code
1 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 :
14 : #include "Utilities/ForceInline.hpp"
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 */, Args&&... args) {
38 : return {{((void)Is, T(args...))..., T(std::forward<Args>(args)...)}};
39 : }
40 : };
41 :
42 : template <>
43 : struct MakeArray<true> {
44 : template <typename T, typename... Args>
45 : static SPECTRE_ALWAYS_INLINE constexpr std::array<T, 0> apply(
46 : std::index_sequence<> /* unused */, Args&&... args) {
47 : #ifndef HAVE_BROKEN_ARRAY0
48 : expand_pack(args...); // Used in other preprocessor branch
49 : return std::array<T, 0>{{}};
50 : #else // HAVE_BROKEN_ARRAY0
51 : // https://bugs.llvm.org/show_bug.cgi?id=35491
52 : return {{T(std::forward<Args>(args)...)}};
53 : #endif // HAVE_BROKEN_ARRAY0
54 : }
55 : };
56 : } // namespace MakeArray_detail
57 :
58 : /*!
59 : * \ingroup UtilitiesGroup
60 : * \brief Create a `std::array<T, Size>{{T(args...), T(args...), ...}}`
61 : * \tparam Size the size of the array
62 : * \tparam T the type of the element in the array
63 : */
64 : template <size_t Size, typename T, typename... Args>
65 1 : SPECTRE_ALWAYS_INLINE constexpr std::array<T, Size> make_array(Args&&... args) {
66 : return MakeArray_detail::MakeArray<Size == 0>::template apply<T>(
67 : std::make_index_sequence<(Size == 0 ? Size : Size - 1)>{},
68 : std::forward<Args>(args)...);
69 : }
70 :
71 : /*!
72 : * \ingroup UtilitiesGroup
73 : * \brief Create a `std::array<std::decay_t<T>, Size>{{t, t, ...}}`
74 : * \tparam Size the size of the array
75 : */
76 : template <size_t Size, typename T>
77 1 : SPECTRE_ALWAYS_INLINE constexpr auto make_array(T&& t)
78 : -> std::array<std::decay_t<T>, Size> {
79 : return MakeArray_detail::MakeArray<Size == 0>::template apply<
80 : std::decay_t<T>>(
81 : std::make_index_sequence<(Size == 0 ? Size : Size - 1)>{},
82 : std::forward<T>(t));
83 : }
84 :
85 : /*!
86 : * \ingroup UtilitiesGroup
87 : * \brief Helper function to initialize a std::array with varying number of
88 : * arguments
89 : */
90 : template <typename T, typename... V, Requires<(sizeof...(V) > 0)> = nullptr>
91 1 : SPECTRE_ALWAYS_INLINE constexpr auto make_array(T&& t, V&&... values)
92 : -> std::array<typename std::decay_t<T>, sizeof...(V) + 1> {
93 : static_assert(
94 : tmpl2::flat_all_v<std::is_same_v<std::decay_t<T>, std::decay_t<V>>...>,
95 : "all types to make_array(...) must be the same");
96 : return std::array<std::decay_t<T>, sizeof...(V) + 1>{
97 : {std::forward<T>(t), std::forward<V>(values)...}};
98 : }
99 :
100 : namespace MakeArray_detail {
101 : template <typename Seq, typename T,
102 : Requires<std::is_rvalue_reference_v<Seq>> = nullptr>
103 : constexpr T&& forward_element(T& t) {
104 : return std::move(t);
105 : }
106 : template <typename Seq, typename T,
107 : Requires<not std::is_rvalue_reference_v<Seq>> = nullptr>
108 : constexpr T& forward_element(T& t) {
109 : return t;
110 : }
111 :
112 : template <typename T, size_t size, typename Seq, size_t... indexes>
113 : constexpr std::array<T, size> make_array_from_iterator_impl(
114 : Seq&& s, std::integer_sequence<size_t, indexes...> /*meta*/) {
115 : // clang-tidy: do not use pointer arithmetic
116 : return std::array<T, size>{
117 : {forward_element<decltype(s)>(*(std::begin(s) + indexes))...}}; // NOLINT
118 : }
119 : } // namespace MakeArray_detail
120 :
121 : /*!
122 : * \ingroup UtilitiesGroup
123 : * \brief Create an `std::array<T, size>` from the first `size` values of `seq`
124 : *
125 : * \requires `Seq` has a `begin` function
126 : * \tparam T the type held by the array
127 : * \tparam size the size of the created array
128 : */
129 : template <typename T, size_t size, typename Seq>
130 1 : constexpr std::array<T, size> make_array(Seq&& seq) {
131 : return MakeArray_detail::make_array_from_iterator_impl<T, size>(
132 : std::forward<Seq>(seq), std::make_index_sequence<size>{});
133 : }
|