1 /*=============================================================================
2     Copyright (c) 2017 Paul Fultz II
3     proj.cpp
4     Distributed under the Boost Software License, Version 1.0. (See accompanying
5     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 ==============================================================================*/
7 #include <boost/hof/proj.hpp>
8 #include <boost/hof/placeholders.hpp>
9 #include <boost/hof/mutable.hpp>
10 #include "test.hpp"
11 
12 #include <memory>
13 
14 struct foo
15 {
foofoo16     constexpr foo(int xp) : x(xp)
17     {}
18     int x;
19 };
20 
21 struct select_x
22 {
23     template<class T>
24     constexpr auto operator()(T&& x) const BOOST_HOF_RETURNS(x.x);
25 };
26 
BOOST_HOF_TEST_CASE()27 BOOST_HOF_TEST_CASE()
28 {
29 #ifndef _MSC_VER
30     constexpr
31 #endif
32     auto add = boost::hof::_ + boost::hof::_;
33     BOOST_HOF_STATIC_TEST_CHECK(boost::hof::proj(select_x(), add)(foo(1), foo(2)) == 3);
34     // Using mutable_ as a workaround on libc++, since mem_fn does not meet the
35     // requirements of a FunctionObject
36     BOOST_HOF_TEST_CHECK(boost::hof::proj(boost::hof::mutable_(std::mem_fn(&foo::x)), add)(foo(1), foo(2)) == 3);
37     static_assert(boost::hof::detail::is_default_constructible<decltype(boost::hof::proj(select_x(), add))>::value, "Not default constructible");
38 }
39 
BOOST_HOF_TEST_CASE()40 BOOST_HOF_TEST_CASE()
41 {
42 #ifndef _MSC_VER
43     constexpr
44 #endif
45     auto add = boost::hof::_ + boost::hof::_;
46     BOOST_HOF_STATIC_TEST_CHECK(boost::hof::proj(select_x(), add)(foo(1), foo(2)) == 3);
47     BOOST_HOF_TEST_CHECK(boost::hof::proj(&foo::x, add)(foo(1), foo(2)) == 3);
48     static_assert(boost::hof::detail::is_default_constructible<decltype(boost::hof::proj(select_x(), add))>::value, "Not default constructible");
49 }
50 
BOOST_HOF_TEST_CASE()51 BOOST_HOF_TEST_CASE()
52 {
53     auto indirect_add = boost::hof::proj(*boost::hof::_, boost::hof::_ + boost::hof::_);
54     BOOST_HOF_TEST_CHECK(indirect_add(std::unique_ptr<int>(new int(1)), std::unique_ptr<int>(new int(2))) == 3);
55     static_assert(boost::hof::detail::is_default_constructible<decltype(indirect_add)>::value, "Not default constructible");
56 }
57 
58 struct select_x_1
59 {
60     std::unique_ptr<int> i;
select_x_1select_x_161     select_x_1() : i(new int(2))
62     {}
63     template<class T>
64     auto operator()(T&& x) const BOOST_HOF_RETURNS(x.x * (*i));
65 };
66 
67 struct sum_1
68 {
69     std::unique_ptr<int> i;
sum_1sum_170     sum_1() : i(new int(1))
71     {}
72     template<class T, class U>
73     auto operator()(T&& x, U&& y) const BOOST_HOF_RETURNS(x + y + *i);
74 };
75 
BOOST_HOF_TEST_CASE()76 BOOST_HOF_TEST_CASE()
77 {
78     BOOST_HOF_TEST_CHECK(boost::hof::proj(select_x_1(), sum_1())(foo(1), foo(2)) == 7);
79 }
80 
BOOST_HOF_TEST_CASE()81 BOOST_HOF_TEST_CASE()
82 {
83     std::string s;
84     auto f = [&](const std::string& x)
85     {
86         s += x;
87     };
88     boost::hof::proj(f)("hello", "-", "world");
89     BOOST_HOF_TEST_CHECK(s == "hello-world");
90     boost::hof::proj(f)();
91     BOOST_HOF_TEST_CHECK(s == "hello-world");
92 }
93 
BOOST_HOF_TEST_CASE()94 BOOST_HOF_TEST_CASE()
95 {
96     std::string s;
97     auto f = [&](const std::string& x)
98     {
99         s += x;
100         return s;
101     };
102     auto last = [](const std::string& x, const std::string& y, const std::string& z)
103     {
104         BOOST_HOF_TEST_CHECK(x == "hello");
105         BOOST_HOF_TEST_CHECK(y == "hello-");
106         BOOST_HOF_TEST_CHECK(z == "hello-world");
107         return z;
108     };
109     BOOST_HOF_TEST_CHECK(boost::hof::proj(f, last)("hello", "-", "world") == "hello-world");
110 }
111 
112 template<bool B>
113 struct bool_
114 {
115     static const bool value = B;
116 };
117 
118 struct constexpr_check
119 {
120     template<class T>
operator ()constexpr_check121     constexpr int operator()(T) const
122     {
123         static_assert(T::value, "Failed");
124         return 0;
125     }
126 };
127 
128 struct constexpr_check_each
129 {
130     template<class T>
operator ()constexpr_check_each131     constexpr bool operator()(T x) const
132     {
133         return boost::hof::proj(constexpr_check())(x, x), true;
134     }
135 };
136 
BOOST_HOF_TEST_CASE()137 BOOST_HOF_TEST_CASE()
138 {
139     BOOST_HOF_STATIC_TEST_CHECK(constexpr_check_each()(bool_<true>()));
140 }
141 
BOOST_HOF_TEST_CASE()142 BOOST_HOF_TEST_CASE()
143 {
144     boost::hof::proj(boost::hof::identity, boost::hof::identity)(0);
145 }
146 
147 struct bar {};
148 
BOOST_HOF_TEST_CASE()149 BOOST_HOF_TEST_CASE()
150 {
151     auto f = boost::hof::proj(bar{});
152     static_assert(!boost::hof::is_invocable<decltype(f), int>::value, "Not sfinae friendly");
153     static_assert(!boost::hof::is_invocable<decltype(f), int, int>::value, "Not sfinae friendly");
154     static_assert(!boost::hof::is_invocable<decltype(f), int, int, int>::value, "Not sfinae friendly");
155 }
156 
BOOST_HOF_TEST_CASE()157 BOOST_HOF_TEST_CASE()
158 {
159     auto f = boost::hof::proj(bar{}, bar{});
160     static_assert(!boost::hof::is_invocable<decltype(f), int>::value, "Not sfinae friendly");
161     static_assert(!boost::hof::is_invocable<decltype(f), int, int>::value, "Not sfinae friendly");
162     static_assert(!boost::hof::is_invocable<decltype(f), int, int, int>::value, "Not sfinae friendly");
163     static_assert(!boost::hof::is_invocable<decltype(f)>::value, "Not sfinae friendly");
164 }
165