• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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