2 * Copyright 2015-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/experimental/TupleOps.h>
19 #include <folly/Conv.h>
20 #include <folly/portability/GTest.h>
22 #include <glog/logging.h>
24 namespace folly { namespace test {
26 TEST(TupleOps, Copiable) {
27 auto t = std::make_tuple(10, std::string("hello"), 30);
29 EXPECT_EQ(10, std::get<0>(t));
30 auto t1 = tupleRange<1>(t);
31 EXPECT_EQ("hello", std::get<0>(t1));
32 EXPECT_EQ(2, std::tuple_size<decltype(t1)>::value);
33 auto t2 = tupleRange<1, 1>(t);
34 EXPECT_EQ(1, std::tuple_size<decltype(t2)>::value);
35 EXPECT_EQ("hello", std::get<0>(t2));
36 EXPECT_EQ(30, std::get<0>(tupleRange<1>(tupleRange<1>(t))));
38 EXPECT_TRUE(t == tuplePrepend(std::get<0>(t), tupleRange<1>(t)));
43 explicit MovableInt(int value) : value_(value) { }
44 int value() const { return value_; }
46 MovableInt(MovableInt&&) = default;
47 MovableInt& operator=(MovableInt&&) = default;
48 MovableInt(const MovableInt&) = delete;
49 MovableInt& operator=(const MovableInt&) = delete;
55 bool operator==(const MovableInt& a, const MovableInt& b) {
56 return a.value() == b.value();
59 TEST(TupleOps, Movable) {
60 auto t1 = std::make_tuple(MovableInt(10), std::string("hello"), 30);
61 auto t2 = std::make_tuple(MovableInt(10), std::string("hello"), 30);
62 auto t3 = std::make_tuple(MovableInt(10), std::string("hello"), 30);
64 auto t1car = std::get<0>(std::move(t1));
65 auto t2cdr = tupleRange<1>(std::move(t2));
67 EXPECT_TRUE(t3 == tuplePrepend(std::move(t1car), std::move(t2cdr)));
70 // Given a tuple of As, convert to a tuple of Bs (of the same size)
71 // by calling folly::to on matching types.
73 // There are two example implementation: tupleTo (using tail recursion), which
74 // may create a lot of intermediate tuples, and tupleTo2, using
75 // TemplateTupleRange directly (below).
76 template <class U, class T>
77 U tupleTo(const T& input);
79 template <class U, class T> struct TupleTo;
81 // Base case: empty typle -> empty tuple
83 struct TupleTo<std::tuple<>, std::tuple<>> {
84 static std::tuple<> convert(const std::tuple<>& /* input */) {
85 return std::make_tuple();
89 // Induction case: split off head element and convert it, then call tupleTo on
91 template <class U, class... Us, class T>
95 static std::tuple<U, Us...> convert(const T& input) {
97 folly::to<U>(std::get<0>(input)),
98 tupleTo<std::tuple<Us...>>(tupleRange<1>(input)));
102 template <class U, class T>
103 U tupleTo(const T& input) {
104 return TupleTo<U, T>::convert(input);
107 template <class S> struct TupleTo2;
109 // Destructure all indexes into Ns... and use parameter pack expansion
110 // to repeat the conversion for each individual element, then wrap
111 // all results with make_tuple.
112 template <std::size_t... Ns>
113 struct TupleTo2<TemplateSeq<std::size_t, Ns...>> {
114 template <class U, class T>
115 static U convert(const T& input) {
116 return std::make_tuple(
117 folly::to<typename std::tuple_element<Ns, U>::type>(
118 std::get<Ns>(input))...);
125 class Seq = typename TemplateTupleRange<U>::type,
126 class Enable = typename std::enable_if<
127 (std::tuple_size<U>::value == std::tuple_size<T>::value)>::type>
128 U tupleTo2(const T& input) {
129 return TupleTo2<Seq>::template convert<U>(input);
132 #define CHECK_TUPLE_TO(converter) \
134 auto src = std::make_tuple(42, "50", 10); \
135 auto dest = converter<std::tuple<std::string, int, int>>(src); \
136 EXPECT_EQ("42", std::get<0>(dest)); \
137 EXPECT_EQ(50, std::get<1>(dest)); \
138 EXPECT_EQ(10, std::get<2>(dest)); \
141 TEST(TupleOps, TupleTo) {
142 CHECK_TUPLE_TO(tupleTo);
145 TEST(TupleOps, TupleTo2) {
146 CHECK_TUPLE_TO(tupleTo2);
149 #undef CHECK_TUPLE_TO