1 /*
2 * Copyright Andrey Semashev 2020.
3 * Distributed under the Boost Software License, Version 1.0.
4 * (See accompanying file LICENSE_1_0.txt or copy at
5 * https://www.boost.org/LICENSE_1_0.txt)
6 */
7 /*!
8 * \file utility/manipulators/tuple.hpp
9 * \author Andrey Semashev
10 * \date 11.05.2020
11 *
12 * The header contains implementation of a stream manipulator for inserting a tuple or any heterogeneous sequence of elements, optionally separated with a delimiter.
13 */
14
15 #ifndef BOOST_LOG_UTILITY_MANIPULATORS_TUPLE_HPP_INCLUDED_
16 #define BOOST_LOG_UTILITY_MANIPULATORS_TUPLE_HPP_INCLUDED_
17
18 #include <cstddef>
19 #include <boost/core/enable_if.hpp>
20 #include <boost/type_traits/is_scalar.hpp>
21 #include <boost/type_traits/conditional.hpp>
22 #include <boost/type_traits/integral_constant.hpp>
23 #include <boost/fusion/include/fold.hpp>
24 #include <boost/fusion/include/for_each.hpp>
25 #include <boost/log/detail/config.hpp>
26 #include <boost/log/detail/is_ostream.hpp>
27 #include <boost/log/detail/header.hpp>
28
29 #ifdef BOOST_HAS_PRAGMA_ONCE
30 #pragma once
31 #endif
32
33 namespace boost {
34
35 BOOST_LOG_OPEN_NAMESPACE
36
37 /*!
38 * Stream manipulator for inserting a heterogeneous sequence of elements, optionally separated with a delimiter.
39 */
40 template< typename TupleT, typename DelimiterT >
41 class tuple_manipulator
42 {
43 private:
44 typedef typename conditional<
45 is_scalar< DelimiterT >::value,
46 DelimiterT,
47 DelimiterT const&
48 >::type stored_delimiter_type;
49
50 template< typename StreamT >
51 struct output_visitor
52 {
53 typedef boost::true_type result_type;
54
output_visitorboost::tuple_manipulator::output_visitor55 output_visitor(StreamT& stream, stored_delimiter_type delimiter) BOOST_NOEXCEPT :
56 m_stream(stream),
57 m_delimiter(delimiter)
58 {
59 }
60
61 template< typename T >
operator ()boost::tuple_manipulator::output_visitor62 result_type operator() (boost::true_type, T const& elem) const
63 {
64 m_stream << m_delimiter;
65 return operator()(boost::false_type(), elem);
66 }
67
68 template< typename T >
operator ()boost::tuple_manipulator::output_visitor69 result_type operator() (boost::false_type, T const& elem) const
70 {
71 m_stream << elem;
72 return result_type();
73 }
74
75 private:
76 StreamT& m_stream;
77 stored_delimiter_type m_delimiter;
78 };
79
80 private:
81 TupleT const& m_tuple;
82 stored_delimiter_type m_delimiter;
83
84 public:
85 //! Initializing constructor
tuple_manipulator(TupleT const & tuple,stored_delimiter_type delimiter)86 tuple_manipulator(TupleT const& tuple, stored_delimiter_type delimiter) BOOST_NOEXCEPT :
87 m_tuple(tuple),
88 m_delimiter(delimiter)
89 {
90 }
91
92 //! The method outputs elements of the sequence separated with delimiter
93 template< typename StreamT >
output(StreamT & stream) const94 void output(StreamT& stream) const
95 {
96 boost::fusion::fold(m_tuple, boost::false_type(), output_visitor< StreamT >(stream, m_delimiter));
97 }
98 };
99
100 /*!
101 * Stream manipulator for inserting a heterogeneous sequence of elements. Specialization for when there is no delimiter.
102 */
103 template< typename TupleT >
104 class tuple_manipulator< TupleT, void >
105 {
106 private:
107 template< typename StreamT >
108 struct output_visitor
109 {
110 typedef void result_type;
111
output_visitorboost::tuple_manipulator::output_visitor112 explicit output_visitor(StreamT& stream) BOOST_NOEXCEPT :
113 m_stream(stream)
114 {
115 }
116
117 template< typename T >
operator ()boost::tuple_manipulator::output_visitor118 result_type operator() (T const& elem) const
119 {
120 m_stream << elem;
121 }
122
123 private:
124 StreamT& m_stream;
125 };
126
127 private:
128 TupleT const& m_tuple;
129
130 public:
131 //! Initializing constructor
tuple_manipulator(TupleT const & tuple)132 explicit tuple_manipulator(TupleT const& tuple) BOOST_NOEXCEPT :
133 m_tuple(tuple)
134 {
135 }
136
137 //! The method outputs elements of the sequence
138 template< typename StreamT >
output(StreamT & stream) const139 void output(StreamT& stream) const
140 {
141 boost::fusion::for_each(m_tuple, output_visitor< StreamT >(stream));
142 }
143 };
144
145 /*!
146 * Stream output operator for \c tuple_manipulator. Outputs every element of the sequence, separated with a delimiter, if one was specified on manipulator construction.
147 */
148 template< typename StreamT, typename TupleT, typename DelimiterT >
operator <<(StreamT & strm,tuple_manipulator<TupleT,DelimiterT> const & manip)149 inline typename boost::enable_if_c< log::aux::is_ostream< StreamT >::value, StreamT& >::type operator<< (StreamT& strm, tuple_manipulator< TupleT, DelimiterT > const& manip)
150 {
151 if (BOOST_LIKELY(strm.good()))
152 manip.output(strm);
153
154 return strm;
155 }
156
157 /*!
158 * Tuple manipulator generator function.
159 *
160 * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output.
161 * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation.
162 * \returns Manipulator to be inserted into the stream.
163 *
164 * \note Both \a tuple and \a delimiter objects must outlive the created manipulator object.
165 */
166 template< typename TupleT, typename DelimiterT >
167 inline typename boost::enable_if_c<
168 is_scalar< DelimiterT >::value,
169 tuple_manipulator< TupleT, DelimiterT >
tuple_manip(TupleT const & tuple,DelimiterT delimiter)170 >::type tuple_manip(TupleT const& tuple, DelimiterT delimiter) BOOST_NOEXCEPT
171 {
172 return tuple_manipulator< TupleT, DelimiterT >(tuple, delimiter);
173 }
174
175 /*!
176 * Tuple manipulator generator function.
177 *
178 * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output.
179 * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation.
180 * \returns Manipulator to be inserted into the stream.
181 *
182 * \note Both \a tuple and \a delimiter objects must outlive the created manipulator object.
183 */
184 template< typename TupleT, typename DelimiterT >
185 inline typename boost::disable_if_c<
186 is_scalar< DelimiterT >::value,
187 tuple_manipulator< TupleT, DelimiterT >
tuple_manip(TupleT const & tuple,DelimiterT const & delimiter)188 >::type tuple_manip(TupleT const& tuple, DelimiterT const& delimiter) BOOST_NOEXCEPT
189 {
190 return tuple_manipulator< TupleT, DelimiterT >(tuple, delimiter);
191 }
192
193 /*!
194 * Tuple manipulator generator function.
195 *
196 * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output.
197 * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation.
198 * \returns Manipulator to be inserted into the stream.
199 *
200 * \note Both \a tuple and \a delimiter objects must outlive the created manipulator object.
201 */
202 template< typename TupleT, typename DelimiterElementT, std::size_t N >
tuple_manip(TupleT const & tuple,DelimiterElementT (& delimiter)[N])203 inline tuple_manipulator< TupleT, DelimiterElementT* > tuple_manip(TupleT const& tuple, DelimiterElementT (&delimiter)[N]) BOOST_NOEXCEPT
204 {
205 return tuple_manipulator< TupleT, DelimiterElementT* >(tuple, delimiter);
206 }
207
208 /*!
209 * Tuple manipulator generator function.
210 *
211 * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output.
212 * \returns Manipulator to be inserted into the stream.
213 *
214 * \note \a tuple object must outlive the created manipulator object.
215 */
216 template< typename TupleT >
tuple_manip(TupleT const & tuple)217 inline tuple_manipulator< TupleT, void > tuple_manip(TupleT const& tuple) BOOST_NOEXCEPT
218 {
219 return tuple_manipulator< TupleT, void >(tuple);
220 }
221
222 BOOST_LOG_CLOSE_NAMESPACE // namespace log
223
224 } // namespace boost
225
226 #include <boost/log/detail/footer.hpp>
227
228 #endif // BOOST_LOG_UTILITY_MANIPULATORS_TUPLE_HPP_INCLUDED_
229