1 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
2 // https://github.com/Dobiasd/FunctionalPlus
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 //  http://www.boost.org/LICENSE_1_0.txt)
6 
7 #include <doctest/doctest.h>
8 #include <fplus/fplus.hpp>
9 
10 namespace {
__anond3ffbf540202(int x) 11     auto squareLambda = [](int x) -> int { return x*x; };
__anond3ffbf540302(int x) 12     auto cubeLambda = [](int x) -> int { return x*x*x; };
13     typedef std::vector<int> IntVector;
14     typedef std::list<int> IntList;
15     typedef std::pair<int, int> IntPair;
16     typedef std::vector<IntPair> IntPairs;
17     IntVector xs = {1,2,2,3,2};
18 
19     struct dummy
20     {
21       int i;
22     };
23 }
24 
25 TEST_CASE("pairs_test - zip_with")
26 {
27     using namespace fplus;
__anond3ffbf540402(int x, int y)28     const auto multiply = [](int x, int y){ return x * y; };
29     REQUIRE_EQ(zip_with(multiply, xs, xs), transform(squareLambda, xs));
__anond3ffbf540502(int x, int y)30     const auto add = [](int x, int y){ return x + y; };
31     REQUIRE_EQ(zip_with(add, IntVector({1,2,3}), IntVector({1,2})), IntVector({2,4}));
32     REQUIRE_EQ(zip_with(add, IntVector({1,2}), IntVector({1,2,3})), IntVector({2,4}));
33     REQUIRE_EQ(zip_with(add, IntVector({1,2}), IntList({1,2,3})), IntVector({2,4}));
34 
__anond3ffbf540602(auto x, int y) 35     const auto add_generic = [](auto x, int y) {return x + y;};
36     REQUIRE_EQ(zip_with(add_generic, IntVector({1,2,3}), IntVector({1,2})), IntVector({2,4}));
37     REQUIRE_EQ(zip_with(std::plus<>{}, IntVector({1,2,3}), IntVector({1,2})), IntVector({2,4}));
38 }
39 
40 TEST_CASE("pairs_test - zip_with_3")
41 {
42     using namespace fplus;
__anond3ffbf540702(int x, int y, int z)43     const auto multiply = [](int x, int y, int z){ return x * y * z; };
__anond3ffbf540802(auto x, auto y, auto z)44     const auto multiply_generic = [](auto x, auto y, auto z){ return x * y * z; };
45     const auto cubed = transform(cubeLambda, xs);
46     REQUIRE_EQ(zip_with_3(multiply, xs, xs, xs), cubed);
47     REQUIRE_EQ(zip_with_3(multiply_generic, xs, xs, xs), cubed);
48 }
49 
50 TEST_CASE("pairs_test - zip_with_defaults")
51 {
52     using namespace fplus;
__anond3ffbf540902(int x, int y)53     const auto add = [](int x, int y){ return x + y; };
__anond3ffbf540a02(auto x, auto y)54     const auto add_generic = [](auto x, auto y){ return x + y; };
55     REQUIRE_EQ(zip_with_defaults(add, 6, 7, IntVector({1,2,3}), IntVector({1,2})), IntVector({2,4,10}));
56     REQUIRE_EQ(zip_with_defaults(add, 6, 7, IntVector({1,2}), IntVector({1,2,3})), IntVector({2,4,9}));
57     REQUIRE_EQ(zip_with_defaults(add_generic, 6, 7, IntVector({1,2}), IntVector({1,2,3})), IntVector({2,4,9}));
58 }
59 
60 TEST_CASE("pairs_test - zip")
61 {
62     using namespace fplus;
63     auto xsZippedWithXs = zip(xs, xs);
64     REQUIRE_EQ(unzip(xsZippedWithXs).first, xs);
65 }
66 
67 TEST_CASE("pairs_test - pair functions")
68 {
69     using namespace fplus;
70     IntPair intPair = std::make_pair(2, 3);
71     IntPairs intPairs = {{1,2}, {3,4}};
72     IntPairs intPairsSwapped = {{2,1}, {4,3}};
73     REQUIRE_EQ(fst(intPair), 2);
74     REQUIRE_EQ(snd(intPair), 3);
75     REQUIRE_EQ(swap_pair_elems(intPair), std::make_pair(3, 2));
76     REQUIRE_EQ(swap_pairs_elems(intPairs), intPairsSwapped);
77     REQUIRE_EQ(transform_fst(squareLambda, intPair), std::make_pair(4, 3));
78     REQUIRE_EQ(transform_snd(squareLambda, intPair), std::make_pair(2, 9));
__anond3ffbf540b02(auto i) 79     REQUIRE_EQ(transform_fst([](auto i) { return i * i; }, intPair), std::make_pair(4, 3));
__anond3ffbf540c02(auto i) 80     REQUIRE_EQ(transform_snd([](auto i) { return i * i; }, intPair), std::make_pair(2, 9));
81     REQUIRE_EQ(transform_pair(squareLambda, squareLambda, intPair), std::make_pair(4, 9));
82 
83     typedef std::vector<std::pair<std::string, int>> StringIntPairs;
84     StringIntPairs stringIntPairs = {{"a", 1}, {"a", 2}, {"b", 6}, {"a", 4}};
85     auto stringIntPairsAsMapGrouped = pairs_to_map_grouped(stringIntPairs);
86     auto groupNames = transform(fst<std::string, int>, stringIntPairs);
87     auto groupNameToMedianMap = transform_map_values(median<std::vector<int>>, stringIntPairsAsMapGrouped);
88     auto getMedianValue = bind_1st_and_2nd_of_3(get_from_map_with_def<std::map<std::string, int>>, groupNameToMedianMap, 0);
89     auto groupMendianValues = transform(getMedianValue, groupNames);
90     auto stringIntPairsSndReplacedWithGroupMedian = zip(groupNames, groupMendianValues);
91     REQUIRE_EQ(stringIntPairsSndReplacedWithGroupMedian, StringIntPairs({{"a", 2}, {"a", 2}, {"b", 6}, {"a", 2}}));
__anond3ffbf540d02(int x) 92     const std::function<int(int)> double_int = [](int x) -> int {
93       return 2 * x;
94     };
95     REQUIRE_EQ(transform_pair(double_int, double_int, IntPair({2, 3})),
96         IntPair({4, 6}));
97     // Thanks to invoke, such code works.
98     // (I don't have a use case for it though)
99     dummy dumb;
100     dumb.i = 42;
101 
102     auto p = std::make_pair(dumb, dumb);
103     auto result = transform_pair(&dummy::i, &dummy::i, p);
104     REQUIRE_EQ(result, std::make_pair(42, 42));
105 }
106 
107 TEST_CASE("pairs_test - enumerate")
108 {
109     using namespace fplus;
110     REQUIRE_EQ(enumerate(xs), (std::vector<std::pair<std::size_t, int>>({{0,1}, {1,2}, {2,2}, {3,3}, {4,2}})));
111 }
112 
113 TEST_CASE("pairs_test - adjacent_pairs")
114 {
115     using namespace fplus;
116     REQUIRE_EQ(adjacent_pairs(xs), IntPairs({{1,2},{2,3}}));
117     REQUIRE_EQ(adjacent_pairs(IntVector({1,2,2,3})), IntPairs({{1,2},{2,3}}));
118 }
119 
120 TEST_CASE("pairs_test - overlapping_pairs")
121 {
122     using namespace fplus;
123     REQUIRE_EQ(overlapping_pairs(xs), IntPairs({{1,2},{2,2},{2,3},{3,2}}));
124 }
125 
126 TEST_CASE("pairs_test - overlapping_pairs_cyclic")
127 {
128     using namespace fplus;
129     REQUIRE_EQ(overlapping_pairs_cyclic(xs), IntPairs({{1,2},{2,2},{2,3},{3,2},{2,1}}));
130 }
131 
132 TEST_CASE("pairs_test - first_mismatch_idx_on")
133 {
134     using namespace fplus;
135     REQUIRE_EQ(first_mismatch_idx_on(is_even<int>, IntVector({1,2,3}), IntVector({3,5,3})), just<std::size_t>(1));
136     REQUIRE_EQ(first_mismatch_idx_on(is_even<int>, IntVector({1,2,3}), IntVector({1,5})), just<std::size_t>(1));
137     REQUIRE_EQ(first_mismatch_idx_on(is_even<int>, IntVector({1,2,3}), IntVector({1,6})), nothing<std::size_t>());
138     REQUIRE_EQ(first_mismatch_idx_on(is_even<int>, IntVector(), IntVector({1,2})), nothing<std::size_t>());
139 }
140 
141 TEST_CASE("pairs_test - first_mismatch_on")
142 {
143     using namespace fplus;
144     REQUIRE_EQ(first_mismatch_on(is_even<int>, IntVector({1,2,3}), IntVector({3,5,3})), just(IntPair(2,5)));
145     REQUIRE_EQ(first_mismatch_on(is_even<int>, IntVector({1,2,3}), IntVector({1,5})), just(IntPair(2,5)));
146     REQUIRE_EQ(first_mismatch_on(is_even<int>, IntVector({1,2,3}), IntVector({1,6})), nothing<IntPair>());
147     REQUIRE_EQ(first_mismatch_on(is_even<int>, IntVector(), IntVector({1,2})), nothing<IntPair>());
148 }
149 
150 TEST_CASE("pairs_test - first_mismatch_idx")
151 {
152     using namespace fplus;
153     REQUIRE_EQ(first_mismatch_idx(IntVector({1,2,3}), IntVector({1,4,3})), just<std::size_t>(1));
154     REQUIRE_EQ(first_mismatch_idx(IntVector({1,2,3}), IntVector({1,4})), just<std::size_t>(1));
155     REQUIRE_EQ(first_mismatch_idx(IntVector({1,2,3}), IntVector({1,2})), nothing<std::size_t>());
156     REQUIRE_EQ(first_mismatch_idx(IntVector(), IntVector({1,2})), nothing<std::size_t>());
157 }
158 
159 TEST_CASE("pairs_test - first_mismatch")
160 {
161     using namespace fplus;
162     REQUIRE_EQ(first_mismatch(IntVector({1,2,3}), IntVector({1,4,3})), just(IntPair(2,4)));
163     REQUIRE_EQ(first_mismatch(IntVector({1,2,3}), IntVector({1,4})), just(IntPair(2,4)));
164     REQUIRE_EQ(first_mismatch(IntVector({1,2,3}), IntVector({1,2})), nothing<IntPair>());
165     REQUIRE_EQ(first_mismatch(IntVector(), IntVector({1,2})), nothing<IntPair>());
166 }
167 
168 TEST_CASE("pairs_test - first_match_idx_on")
169 {
170     using namespace fplus;
171     REQUIRE_EQ(first_match_idx_on(is_even<int>, IntVector({1,2,3}), IntVector({2,4,3})), just<std::size_t>(1));
172     REQUIRE_EQ(first_match_idx_on(is_even<int>, IntVector(), IntVector({1,2})), nothing<std::size_t>());
173 }
174 
175 TEST_CASE("pairs_test - first_match")
176 {
177     using namespace fplus;
178     REQUIRE_EQ(first_match(IntVector({1,2,3}), IntVector({5,2,3})), just(IntPair(2,2)));
179     REQUIRE_EQ(first_match(IntVector(), IntVector({1,2})), nothing<IntPair>());
180 }
181 
182 TEST_CASE("pairs_test - zip_repeat")
183 {
184     using namespace fplus;
185     typedef std::vector<std::string> Strings;
186     typedef std::pair<std::string, int> Pairs;
187     Strings label{"even", "odd"};
188     std::vector<Pairs> expected{{"even", 0}, {"odd", 1}, {"even", 2}};
189     REQUIRE_EQ(zip_repeat(label, IntVector{0,1}), zip(label, IntVector{0, 1}));
190     REQUIRE_EQ(zip_repeat(label, IntVector{0,1,2}), expected);
191     REQUIRE_EQ(zip_repeat(IntVector{0,1,2}, label), transform(fwd::swap_pair_elems(), expected));
192 }