1 /*
2 * Copyright Andrey Semashev 2007 - 2015.
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 /*!
8 * \file formatters/wrap_formatter.hpp
9 * \author Andrey Semashev
10 * \date 24.11.2012
11 *
12 * The header contains a formatter function wrapper that enables third-party functions to participate in formatting expressions.
13 */
14
15 #ifndef BOOST_LOG_EXPRESSIONS_FORMATTERS_WRAP_FORMATTER_HPP_INCLUDED_
16 #define BOOST_LOG_EXPRESSIONS_FORMATTERS_WRAP_FORMATTER_HPP_INCLUDED_
17
18 #include <string>
19 #include <boost/move/core.hpp>
20 #include <boost/move/utility_core.hpp>
21 #include <boost/mpl/has_xxx.hpp>
22 #include <boost/phoenix/core/actor.hpp>
23 #include <boost/phoenix/core/terminal_fwd.hpp>
24 #include <boost/phoenix/core/is_nullary.hpp>
25 #include <boost/phoenix/core/environment.hpp>
26 #include <boost/type_traits/remove_cv.hpp>
27 #include <boost/type_traits/remove_reference.hpp>
28 #include <boost/fusion/sequence/intrinsic/at_c.hpp>
29 #include <boost/log/detail/config.hpp>
30 #include <boost/log/detail/custom_terminal_spec.hpp>
31 #include <boost/log/detail/function_traits.hpp>
32 #include <boost/log/utility/formatting_ostream.hpp>
33 #include <boost/log/detail/header.hpp>
34
35 #ifdef BOOST_HAS_PRAGMA_ONCE
36 #pragma once
37 #endif
38
39 namespace boost {
40
41 BOOST_LOG_OPEN_NAMESPACE
42
43 namespace expressions {
44
45 namespace aux {
46
47 //! Wrapped formatter stream output terminal
48 template< typename LeftT, typename FunT >
49 class wrapped_formatter_output_terminal
50 {
51 private:
52 //! Self type
53 typedef wrapped_formatter_output_terminal< LeftT, FunT > this_type;
54
55 public:
56 #ifndef BOOST_LOG_DOXYGEN_PASS
57 //! Internal typedef for type categorization
58 typedef void _is_boost_log_terminal;
59 #endif
60
61 //! Wrapped function type
62 typedef FunT function_type;
63
64 //! Result type definition
65 template< typename >
66 struct result;
67
68 template< typename ThisT, typename ContextT >
69 struct result< ThisT(ContextT) >
70 {
71 typedef typename remove_cv< typename remove_reference< ContextT >::type >::type context_type;
72 typedef typename phoenix::evaluator::impl<
73 typename LeftT::proto_base_expr&,
74 context_type,
75 phoenix::unused
76 >::result_type type;
77 };
78
79 private:
80 //! Left argument actor
81 LeftT m_left;
82 //! Wrapped function
83 function_type m_fun;
84
85 public:
86 //! Initializing constructor
wrapped_formatter_output_terminal(LeftT const & left,function_type const & fun)87 wrapped_formatter_output_terminal(LeftT const& left, function_type const& fun) : m_left(left), m_fun(fun)
88 {
89 }
90 //! Copy constructor
wrapped_formatter_output_terminal(wrapped_formatter_output_terminal const & that)91 wrapped_formatter_output_terminal(wrapped_formatter_output_terminal const& that) : m_left(that.m_left), m_fun(that.m_fun)
92 {
93 }
94
95 //! Invokation operator
96 template< typename ContextT >
operator ()(ContextT const & ctx)97 typename result< this_type(ContextT const&) >::type operator() (ContextT const& ctx)
98 {
99 typedef typename result< this_type(ContextT const&) >::type result_type;
100 result_type strm = phoenix::eval(m_left, ctx);
101 m_fun(fusion::at_c< 0 >(phoenix::env(ctx).args()), strm);
102 return strm;
103 }
104
105 //! Invokation operator
106 template< typename ContextT >
operator ()(ContextT const & ctx) const107 typename result< const this_type(ContextT const&) >::type operator() (ContextT const& ctx) const
108 {
109 typedef typename result< const this_type(ContextT const&) >::type result_type;
110 result_type strm = phoenix::eval(m_left, ctx);
111 m_fun(fusion::at_c< 0 >(phoenix::env(ctx).args()), strm);
112 return strm;
113 }
114
115 BOOST_DELETED_FUNCTION(wrapped_formatter_output_terminal())
116 };
117
118 BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_char_type, char_type, false)
119
120 template<
121 typename FunT,
122 bool HasCharTypeV = has_char_type< FunT >::value,
123 bool HasSecondArgumentV = boost::log::aux::has_second_argument_type< FunT >::value,
124 bool HasArg2V = boost::log::aux::has_arg2_type< FunT >::value
125 >
126 struct default_char_type
127 {
128 // Use this char type if all detection fails
129 typedef char type;
130 };
131
132 template< typename FunT, bool HasSecondArgumentV, bool HasArg2V >
133 struct default_char_type< FunT, true, HasSecondArgumentV, HasArg2V >
134 {
135 typedef typename FunT::char_type type;
136 };
137
138 template< typename FunT, bool HasArg2V >
139 struct default_char_type< FunT, false, true, HasArg2V >
140 {
141 typedef typename remove_cv< typename remove_reference< typename FunT::second_argument_type >::type >::type argument_type;
142 typedef typename argument_type::char_type type;
143 };
144
145 template< typename FunT >
146 struct default_char_type< FunT, false, false, true >
147 {
148 typedef typename remove_cv< typename remove_reference< typename FunT::arg2_type >::type >::type argument_type;
149 typedef typename argument_type::char_type type;
150 };
151
152 } // namespace aux
153
154 /*!
155 * Formatter function wrapper terminal.
156 */
157 template< typename FunT, typename CharT >
158 class wrapped_formatter_terminal
159 {
160 public:
161 #ifndef BOOST_LOG_DOXYGEN_PASS
162 //! Internal typedef for type categorization
163 typedef void _is_boost_log_terminal;
164 #endif
165
166 //! Character type
167 typedef CharT char_type;
168 //! String type
169 typedef std::basic_string< char_type > string_type;
170 //! Formatting stream type
171 typedef basic_formatting_ostream< char_type > stream_type;
172 //! Wrapped function type
173 typedef FunT function_type;
174
175 //! Formatter result type
176 typedef string_type result_type;
177
178 private:
179 //! Wrapped function
180 function_type m_fun;
181
182 public:
183 //! Initializing construction
wrapped_formatter_terminal(function_type const & fun)184 explicit wrapped_formatter_terminal(function_type const& fun) : m_fun(fun)
185 {
186 }
187 //! Copy constructor
wrapped_formatter_terminal(wrapped_formatter_terminal const & that)188 wrapped_formatter_terminal(wrapped_formatter_terminal const& that) : m_fun(that.m_fun)
189 {
190 }
191
192 //! Returns the wrapped function
get_function() const193 function_type const& get_function() const
194 {
195 return m_fun;
196 }
197
198 //! Invokation operator
199 template< typename ContextT >
operator ()(ContextT const & ctx)200 result_type operator() (ContextT const& ctx)
201 {
202 string_type str;
203 stream_type strm(str);
204 m_fun(fusion::at_c< 0 >(phoenix::env(ctx).args()), strm);
205 strm.flush();
206 return BOOST_LOG_NRVO_RESULT(str);
207 }
208
209 //! Invokation operator
210 template< typename ContextT >
operator ()(ContextT const & ctx) const211 result_type operator() (ContextT const& ctx) const
212 {
213 string_type str;
214 stream_type strm(str);
215 m_fun(fusion::at_c< 0 >(phoenix::env(ctx).args()), strm);
216 strm.flush();
217 return BOOST_LOG_NRVO_RESULT(str);
218 }
219 };
220
221 /*!
222 * Wrapped formatter function actor.
223 */
224 template< typename FunT, typename CharT, template< typename > class ActorT = phoenix::actor >
225 class wrapped_formatter_actor :
226 public ActorT< wrapped_formatter_terminal< FunT, CharT > >
227 {
228 public:
229 //! Character type
230 typedef CharT char_type;
231 //! Wrapped function type
232 typedef FunT function_type;
233 //! Base terminal type
234 typedef wrapped_formatter_terminal< function_type, char_type > terminal_type;
235
236 //! Base actor type
237 typedef ActorT< terminal_type > base_type;
238
239 public:
240 //! Initializing constructor
wrapped_formatter_actor(base_type const & act)241 explicit wrapped_formatter_actor(base_type const& act) : base_type(act)
242 {
243 }
244
245 /*!
246 * \returns The wrapped function
247 */
get_function() const248 function_type const& get_function() const
249 {
250 return this->proto_expr_.child0.get_function();
251 }
252 };
253
254 #ifndef BOOST_LOG_DOXYGEN_PASS
255
256 #define BOOST_LOG_AUX_OVERLOAD(left_ref, right_ref)\
257 template< typename LeftExprT, typename FunT, typename CharT >\
258 BOOST_FORCEINLINE phoenix::actor< aux::wrapped_formatter_output_terminal< phoenix::actor< LeftExprT >, FunT > >\
259 operator<< (phoenix::actor< LeftExprT > left_ref left, wrapped_formatter_actor< FunT, CharT > right_ref right)\
260 {\
261 typedef aux::wrapped_formatter_output_terminal< phoenix::actor< LeftExprT >, FunT > terminal_type;\
262 phoenix::actor< terminal_type > actor = {{ terminal_type(left, right.get_function()) }};\
263 return actor;\
264 }
265
266 #include <boost/log/detail/generate_overloads.hpp>
267
268 #undef BOOST_LOG_AUX_OVERLOAD
269
270 #endif // BOOST_LOG_DOXYGEN_PASS
271
272 /*!
273 * The function wraps a function object in order it to be able to participate in formatting expressions. The wrapped
274 * function object must be compatible with the following signature:
275 *
276 * <pre>
277 * void (record_view const&, basic_formatting_ostream< CharT >&)
278 * </pre>
279 *
280 * where \c CharT is the character type of the formatting expression.
281 */
282 template< typename FunT >
wrap_formatter(FunT const & fun)283 BOOST_FORCEINLINE wrapped_formatter_actor< FunT, typename aux::default_char_type< FunT >::type > wrap_formatter(FunT const& fun)
284 {
285 typedef wrapped_formatter_actor< FunT, typename aux::default_char_type< FunT >::type > actor_type;
286 typedef typename actor_type::terminal_type terminal_type;
287 typename actor_type::base_type act = {{ terminal_type(fun) }};
288 return actor_type(act);
289 }
290
291 /*!
292 * The function wraps a function object in order it to be able to participate in formatting expressions. The wrapped
293 * function object must be compatible with the following signature:
294 *
295 * <pre>
296 * void (record_view const&, basic_formatting_ostream< CharT >&)
297 * </pre>
298 *
299 * where \c CharT is the character type of the formatting expression.
300 */
301 template< typename CharT, typename FunT >
wrap_formatter(FunT const & fun)302 BOOST_FORCEINLINE wrapped_formatter_actor< FunT, CharT > wrap_formatter(FunT const& fun)
303 {
304 typedef wrapped_formatter_actor< FunT, CharT > actor_type;
305 typedef typename actor_type::terminal_type terminal_type;
306 typename actor_type::base_type act = {{ terminal_type(fun) }};
307 return actor_type(act);
308 }
309
310 } // namespace expressions
311
312 BOOST_LOG_CLOSE_NAMESPACE // namespace log
313
314 #ifndef BOOST_LOG_DOXYGEN_PASS
315
316 namespace phoenix {
317
318 namespace result_of {
319
320 template< typename LeftT, typename FunT >
321 struct is_nullary< custom_terminal< boost::log::expressions::aux::wrapped_formatter_output_terminal< LeftT, FunT > > > :
322 public mpl::false_
323 {
324 };
325
326 template< typename FunT, typename CharT >
327 struct is_nullary< custom_terminal< boost::log::expressions::wrapped_formatter_terminal< FunT, CharT > > > :
328 public mpl::false_
329 {
330 };
331
332 } // namespace result_of
333
334 } // namespace phoenix
335
336 #endif
337
338 } // namespace boost
339
340 #include <boost/log/detail/footer.hpp>
341
342 #endif // BOOST_LOG_EXPRESSIONS_FORMATTERS_WRAP_FORMATTER_HPP_INCLUDED_
343