1 /* 2 * Copyright 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <tuple> 20 #include <utility> 21 22 namespace android::ftl { 23 24 // Compile-time counterpart of std::initializer_list<T> that stores per-element constructor 25 // arguments with heterogeneous types. For a container with elements of type T, given Sizes 26 // (S0, S1, ..., SN), N elements are initialized: the first element is initialized with the 27 // first S0 arguments, the second element is initialized with the next S1 arguments, and so 28 // on. The list of Types (T0, ..., TM) is flattened, so M is equal to the sum of the Sizes. 29 // 30 // An InitializerList is created using ftl::init::list, and is consumed by constructors of 31 // containers. The function call operator is overloaded such that arguments are accumulated 32 // in a tuple with each successive call. For instance, the following calls initialize three 33 // strings using different constructors, i.e. string literal, default, and count/character: 34 // 35 // ... = ftl::init::list<std::string>("abc")()(3u, '?'); 36 // 37 // The following syntax is a shorthand for key-value pairs, where the first argument is the 38 // key, and the rest construct the value. The types of the key and value are deduced if the 39 // first pair contains exactly two arguments: 40 // 41 // ... = ftl::init::map<int, std::string>(-1, "abc")(-2)(-3, 3u, '?'); 42 // 43 // ... = ftl::init::map(0, 'a')(1, 'b')(2, 'c'); 44 // 45 // WARNING: The InitializerList returned by an ftl::init::list expression must be consumed 46 // immediately, since temporary arguments are destroyed after the full expression. Storing 47 // an InitializerList results in dangling references. 48 // 49 template <typename T, typename Sizes = std::index_sequence<>, typename... Types> 50 struct InitializerList; 51 52 template <typename T, std::size_t... Sizes, typename... Types> 53 struct InitializerList<T, std::index_sequence<Sizes...>, Types...> { 54 // Creates a superset InitializerList by appending the number of arguments to Sizes, and 55 // expanding Types with forwarding references for each argument. 56 template <typename... Args> 57 [[nodiscard]] constexpr auto operator()(Args&&... args) && -> InitializerList< 58 T, std::index_sequence<Sizes..., sizeof...(Args)>, Types..., Args&&...> { 59 return {std::tuple_cat(std::move(tuple), std::forward_as_tuple(std::forward<Args>(args)...))}; 60 } 61 62 // The temporary InitializerList returned by operator() is bound to an rvalue reference in 63 // container constructors, which extends the lifetime of any temporary arguments that this 64 // tuple refers to until the completion of the full expression containing the construction. 65 std::tuple<Types...> tuple; 66 }; 67 68 template <typename K, typename V> 69 struct KeyValue {}; 70 71 // Shorthand for key-value pairs that assigns the first argument to the key, and the rest to the 72 // value. The specialization is on KeyValue rather than std::pair, so that ftl::init::list works 73 // with the latter. 74 template <typename K, typename V, std::size_t... Sizes, typename... Types> 75 struct InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...> { 76 // Accumulate the three arguments to std::pair's piecewise constructor. 77 template <typename... Args> 78 [[nodiscard]] constexpr auto operator()(K&& k, Args&&... args) && -> InitializerList< 79 KeyValue<K, V>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t, 80 std::tuple<K&&>, std::tuple<Args&&...>> { 81 return {std::tuple_cat( 82 std::move(tuple), 83 std::forward_as_tuple(std::piecewise_construct, std::forward_as_tuple(std::forward<K>(k)), 84 std::forward_as_tuple(std::forward<Args>(args)...)))}; 85 } 86 87 std::tuple<Types...> tuple; 88 }; 89 90 namespace init { 91 92 template <typename T, typename... Args> 93 [[nodiscard]] constexpr auto list(Args&&... args) { 94 return InitializerList<T>{}(std::forward<Args>(args)...); 95 } 96 97 template <typename K, typename V, typename... Args> 98 [[nodiscard]] constexpr auto map(Args&&... args) { 99 return list<KeyValue<K, V>>(std::forward<Args>(args)...); 100 } 101 102 template <typename K, typename V> 103 [[nodiscard]] constexpr auto map(K&& k, V&& v) { 104 return list<KeyValue<K, V>>(std::forward<K>(k), std::forward<V>(v)); 105 } 106 107 } // namespace init 108 } // namespace android::ftl 109