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 : }