1 /*=============================================================================
2     Copyright (c) 2014 Paul Fultz II
3     always.h
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 
8 #ifndef BOOST_HOF_GUARD_FUNCTION_ALWAYS_H
9 #define BOOST_HOF_GUARD_FUNCTION_ALWAYS_H
10 
11 #include <boost/hof/detail/delegate.hpp>
12 #include <boost/hof/detail/unwrap.hpp>
13 #include <boost/hof/detail/static_const_var.hpp>
14 
15 /// always
16 /// ======
17 ///
18 /// Description
19 /// -----------
20 ///
21 /// The `always` function returns a function object that will always return
22 /// the value given to it, no matter what parameters are passed to the
23 /// function object. The nullary version(i.e. `always(void)`) will return
24 /// `void`. On compilers, that don't support constexpr functions returning
25 /// `void`, a private empty type is returned instead. This return type is
26 /// specified as `BOOST_HOF_ALWAYS_VOID_RETURN`.
27 ///
28 /// Synopsis
29 /// --------
30 ///
31 ///     template<class T>
32 ///     constexpr auto always(T value);
33 ///
34 ///     template<class T>
35 ///     constexpr auto always(void);
36 ///
37 ///
38 /// Semantics
39 /// ---------
40 ///
41 ///     assert(always(x)(xs...) == x);
42 ///
43 /// Requirements
44 /// ------------
45 ///
46 /// T must be:
47 ///
48 /// * CopyConstructible
49 ///
50 /// Example
51 /// -------
52 ///
53 ///     #include <boost/hof.hpp>
54 ///     #include <algorithm>
55 ///     #include <cassert>
56 ///     using namespace boost::hof;
57 ///
58 ///     int main() {
59 ///         int ten = 10;
60 ///         assert( always(ten)(1,2,3,4,5) == 10 );
61 ///     }
62 ///
63 ///     // Count all
64 ///     template<class Iterator, class T>
65 ///     auto count(Iterator first, Iterator last)
66 ///     {
67 ///         return std::count_if(first, last, always(true));
68 ///     }
69 ///
70 
71 
72 #ifndef BOOST_HOF_NO_CONSTEXPR_VOID
73 #if defined(__clang__) && BOOST_HOF_HAS_RELAXED_CONSTEXPR
74 #define BOOST_HOF_NO_CONSTEXPR_VOID 0
75 #else
76 #define BOOST_HOF_NO_CONSTEXPR_VOID 1
77 #endif
78 #endif
79 
80 namespace boost { namespace hof { namespace always_detail {
81 
82 template<class T, class=void>
83 struct always_base
84 {
85     T x;
86 
87     BOOST_HOF_DELEGATE_CONSTRUCTOR(always_base, T, x)
88 
89     typedef typename detail::unwrap_reference<T>::type result_type;
90 
91     template<class... As>
92     constexpr result_type
operator ()boost::hof::always_detail::always_base93     operator()(As&&...) const
94     noexcept(std::is_reference<result_type>::value || BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(result_type))
95     {
96         return this->x;
97     }
98 };
99 
100 template<class T>
101 struct always_base<T, typename std::enable_if<!BOOST_HOF_IS_EMPTY(T)>::type>
102 {
103     T x;
104 
always_baseboost::hof::always_detail::always_base105     constexpr always_base(T xp) noexcept(BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(T))
106     : x(xp)
107     {}
108 
109     typedef typename detail::unwrap_reference<T>::type result_type;
110 
111     template<class... As>
112     constexpr result_type
operator ()boost::hof::always_detail::always_base113     operator()(As&&...) const
114     noexcept(std::is_reference<result_type>::value || BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(result_type))
115     {
116         return this->x;
117     }
118 };
119 
120 #if BOOST_HOF_NO_CONSTEXPR_VOID
121 #define BOOST_HOF_ALWAYS_VOID_RETURN boost::hof::always_detail::always_base<void>::void_
122 #else
123 #define BOOST_HOF_ALWAYS_VOID_RETURN void
124 #endif
125 
126 template<>
127 struct always_base<void>
128 {
129 
always_baseboost::hof::always_detail::always_base130     constexpr always_base() noexcept
131     {}
132 
133     struct void_ {};
134 
135     template<class... As>
136     constexpr BOOST_HOF_ALWAYS_VOID_RETURN
operator ()boost::hof::always_detail::always_base137     operator()(As&&...) const noexcept
138     {
139 #if BOOST_HOF_NO_CONSTEXPR_VOID
140         return void_();
141 #endif
142     }
143 };
144 
145 struct always_f
146 {
147     template<class T>
operator ()boost::hof::always_detail::always_f148     constexpr always_detail::always_base<T> operator()(T x) const noexcept(BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(T))
149     {
150         return always_detail::always_base<T>(x);
151     }
152 
operator ()boost::hof::always_detail::always_f153     constexpr always_detail::always_base<void> operator()() const noexcept
154     {
155         return always_detail::always_base<void>();
156     }
157 };
158 
159 struct always_ref_f
160 {
161     template<class T>
operator ()boost::hof::always_detail::always_ref_f162     constexpr always_detail::always_base<T&> operator()(T& x) const noexcept
163     {
164         return always_detail::always_base<T&>(x);
165     }
166 };
167 
168 }
169 BOOST_HOF_DECLARE_STATIC_VAR(always, always_detail::always_f);
170 BOOST_HOF_DECLARE_STATIC_VAR(always_ref, always_detail::always_ref_f);
171 
172 }} // namespace boost::hof
173 
174 #endif
175