FTL: Add SmallMap<K, V, N>

SmallMap is a SmallVector of unordered key-value pairs. This CL includes
construction and lookup, while mutators will be added in a follow-up CL.

Bug: 160012986
Test: ftl_test
Change-Id: Id88485304c7d7f515226b4f8edf63ce9af6a2157
diff --git a/include/ftl/InitializerList.h b/include/ftl/InitializerList.h
index 204f79b..bb99280 100644
--- a/include/ftl/InitializerList.h
+++ b/include/ftl/InitializerList.h
@@ -34,6 +34,14 @@
 //
 //     ... = ftl::init::list<std::string>("abc")()(3u, '?');
 //
+// The following syntax is a shorthand for key-value pairs, where the first argument is the
+// key, and the rest construct the value. The types of the key and value are deduced if the
+// first pair contains exactly two arguments:
+//
+//     ... = ftl::init::map<int, std::string>(-1, "abc")(-2)(-3, 3u, '?');
+//
+//     ... = ftl::init::map(0, 'a')(1, 'b')(2, 'c');
+//
 // WARNING: The InitializerList returned by an ftl::init::list expression must be consumed
 // immediately, since temporary arguments are destroyed after the full expression. Storing
 // an InitializerList results in dangling references.
@@ -58,6 +66,29 @@
     std::tuple<Types...> tuple;
 };
 
+template <typename K, typename V>
+struct KeyValue {};
+
+// Shorthand for key-value pairs that assigns the first argument to the key, and the rest to the
+// value. The specialization is on KeyValue rather than std::pair, so that ftl::init::list works
+// with the latter.
+template <typename K, typename V, size_t... Sizes, typename... Types>
+struct InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...> {
+    // Accumulate the three arguments to std::pair's piecewise constructor.
+    template <typename... Args>
+    [[nodiscard]] constexpr auto operator()(K&& k, Args&&... args) && -> InitializerList<
+            KeyValue<K, V>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t,
+            std::tuple<K&&>, std::tuple<Args&&...>> {
+        return {std::tuple_cat(std::move(tuple),
+                               std::forward_as_tuple(std::piecewise_construct,
+                                                     std::forward_as_tuple(std::forward<K>(k)),
+                                                     std::forward_as_tuple(
+                                                             std::forward<Args>(args)...)))};
+    }
+
+    std::tuple<Types...> tuple;
+};
+
 namespace init {
 
 template <typename T, typename... Args>
@@ -65,5 +96,15 @@
     return InitializerList<T>{}(std::forward<Args>(args)...);
 }
 
+template <typename K, typename V, typename... Args>
+[[nodiscard]] constexpr auto map(Args&&... args) {
+    return list<KeyValue<K, V>>(std::forward<Args>(args)...);
+}
+
+template <typename K, typename V>
+[[nodiscard]] constexpr auto map(K&& k, V&& v) {
+    return list<KeyValue<K, V>>(std::forward<K>(k), std::forward<V>(v));
+}
+
 } // namespace init
 } // namespace android::ftl