2 * Copyright 2015 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 <glog/logging.h>
21 #include <gtest/gtest.h>
23 namespace folly { namespace test {
25 TEST(TupleOps, Copiable) {
26 auto t = std::make_tuple(10, std::string("hello"), 30);
28 EXPECT_EQ(10, std::get<0>(t));
29 auto t1 = tupleRange<1>(t);
30 EXPECT_EQ("hello", std::get<0>(t1));
31 EXPECT_EQ(2, std::tuple_size<decltype(t1)>::value);
32 auto t2 = tupleRange<1, 1>(t);
33 EXPECT_EQ(1, std::tuple_size<decltype(t2)>::value);
34 EXPECT_EQ("hello", std::get<0>(t2));
35 EXPECT_EQ(30, std::get<0>(tupleRange<1>(tupleRange<1>(t))));
37 EXPECT_TRUE(t == tuplePrepend(std::get<0>(t), tupleRange<1>(t)));
42 explicit MovableInt(int value) : value_(value) { }
43 int value() const { return value_; }
45 MovableInt(MovableInt&&) = default;
46 MovableInt& operator=(MovableInt&&) = default;
47 MovableInt(const MovableInt&) = delete;
48 MovableInt& operator=(const MovableInt&) = delete;
54 bool operator==(const MovableInt& a, const MovableInt& b) {
55 return a.value() == b.value();
58 TEST(TupleOps, Movable) {
59 auto t1 = std::make_tuple(MovableInt(10), std::string("hello"), 30);
60 auto t2 = std::make_tuple(MovableInt(10), std::string("hello"), 30);
61 auto t3 = std::make_tuple(MovableInt(10), std::string("hello"), 30);
63 auto t1car = std::get<0>(std::move(t1));
64 auto t2cdr = tupleRange<1>(std::move(t2));
66 EXPECT_TRUE(t3 == tuplePrepend(std::move(t1car), std::move(t2cdr)));
69 // Given a tuple of As, convert to a tuple of Bs (of the same size)
70 // by calling folly::to on matching types.
72 // There are two example implementation: tupleTo (using tail recursion), which
73 // may create a lot of intermediate tuples, and tupleTo2, using
74 // TemplateTupleRange directly (below).
75 template <class U, class T>
76 U tupleTo(const T& input);
78 template <class U, class T> struct TupleTo;
80 // Base case: empty typle -> empty tuple
82 struct TupleTo<std::tuple<>, std::tuple<>> {
83 static std::tuple<> convert(const std::tuple<>& input) {
84 return std::make_tuple();
88 // Induction case: split off head element and convert it, then call tupleTo on
90 template <class U, class... Us, class T>
94 static std::tuple<U, Us...> convert(const T& input) {
96 folly::to<U>(std::get<0>(input)),
97 tupleTo<std::tuple<Us...>>(tupleRange<1>(input)));
101 template <class U, class T>
102 U tupleTo(const T& input) {
103 return TupleTo<U, T>::convert(input);
106 template <class S> struct TupleTo2;
108 // Destructure all indexes into Ns... and use parameter pack expansion
109 // to repeat the conversion for each individual element, then wrap
110 // all results with make_tuple.
111 template <std::size_t... Ns>
112 struct TupleTo2<TemplateSeq<std::size_t, Ns...>> {
113 template <class U, class T>
114 static U convert(const T& input) {
115 return std::make_tuple(
116 folly::to<typename std::tuple_element<Ns, U>::type>(
117 std::get<Ns>(input))...);
121 template <class U, class T,
122 class Seq = typename TemplateTupleRange<U>::type,
123 class Enable = typename std::enable_if<
124 (std::tuple_size<U>::value == std::tuple_size<T>::value)>::type>
125 U tupleTo2(const T& input) {
126 return TupleTo2<Seq>::template convert<U>(input);
129 #define CHECK_TUPLE_TO(converter) \
131 auto src = std::make_tuple(42, "50", 10); \
132 auto dest = converter<std::tuple<std::string, int, int>>(src); \
133 EXPECT_EQ("42", std::get<0>(dest)); \
134 EXPECT_EQ(50, std::get<1>(dest)); \
135 EXPECT_EQ(10, std::get<2>(dest)); \
138 TEST(TupleOps, TupleTo) {
139 CHECK_TUPLE_TO(tupleTo);
142 TEST(TupleOps, TupleTo2) {
143 CHECK_TUPLE_TO(tupleTo2);
146 #undef CHECK_TUPLE_TO