blob: 204f79bb92447fd86ceb1465406733059c32aed4 [file] [log] [blame]
Dominik Laskowskiccd50a42020-10-30 19:56:38 -07001/*
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
22namespace 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// The 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// WARNING: The InitializerList returned by an ftl::init::list expression must be consumed
38// immediately, since temporary arguments are destroyed after the full expression. Storing
39// an InitializerList results in dangling references.
40//
41template <typename T, typename Sizes = std::index_sequence<>, typename... Types>
42struct InitializerList;
43
44template <typename T, size_t... Sizes, typename... Types>
45struct InitializerList<T, std::index_sequence<Sizes...>, Types...> {
46 // Creates a superset InitializerList by appending the number of arguments to Sizes, and
47 // expanding Types with forwarding references for each argument.
48 template <typename... Args>
49 [[nodiscard]] constexpr auto operator()(Args&&... args) && -> InitializerList<
50 T, std::index_sequence<Sizes..., sizeof...(Args)>, Types..., Args&&...> {
51 return {std::tuple_cat(std::move(tuple),
52 std::forward_as_tuple(std::forward<Args>(args)...))};
53 }
54
55 // The temporary InitializerList returned by operator() is bound to an rvalue reference in
56 // container constructors, which extends the lifetime of any temporary arguments that this
57 // tuple refers to until the completion of the full expression containing the construction.
58 std::tuple<Types...> tuple;
59};
60
61namespace init {
62
63template <typename T, typename... Args>
64[[nodiscard]] constexpr auto list(Args&&... args) {
65 return InitializerList<T>{}(std::forward<Args>(args)...);
66}
67
68} // namespace init
69} // namespace android::ftl