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/range.hpp
9 * \author Andrey Semashev
10 * \date 11.05.2020
11 *
12 * The header contains implementation of a stream manipulator for inserting a range of elements, optionally separated with a delimiter.
13 */
14
15 #ifndef BOOST_LOG_UTILITY_MANIPULATORS_RANGE_HPP_INCLUDED_
16 #define BOOST_LOG_UTILITY_MANIPULATORS_RANGE_HPP_INCLUDED_
17
18 #include <cstddef>
19 #include <boost/range/begin.hpp>
20 #include <boost/range/end.hpp>
21 #include <boost/range/const_iterator.hpp>
22 #include <boost/core/enable_if.hpp>
23 #include <boost/type_traits/is_scalar.hpp>
24 #include <boost/type_traits/conditional.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 range of elements, optionally separated with a delimiter.
39 */
40 template< typename RangeT, typename DelimiterT >
41 class range_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 private:
51 RangeT const& m_range;
52 stored_delimiter_type m_delimiter;
53
54 public:
55 //! Initializing constructor
range_manipulator(RangeT const & range,stored_delimiter_type delimiter)56 range_manipulator(RangeT const& range, stored_delimiter_type delimiter) BOOST_NOEXCEPT :
57 m_range(range),
58 m_delimiter(delimiter)
59 {
60 }
61
62 //! The method outputs elements of the range separated with delimiter
63 template< typename StreamT >
output(StreamT & stream) const64 void output(StreamT& stream) const
65 {
66 typedef typename boost::range_const_iterator< RangeT >::type const_iterator;
67 const_iterator it = boost::begin(m_range);
68 const const_iterator end = boost::end(m_range);
69 if (BOOST_LIKELY(it != end))
70 {
71 stream << *it;
72
73 for (++it; it != end; ++it)
74 {
75 stream << m_delimiter;
76 stream << *it;
77 }
78 }
79 }
80 };
81
82 /*!
83 * Stream manipulator for inserting a range of elements. Specialization for when there is no delimiter.
84 */
85 template< typename RangeT >
86 class range_manipulator< RangeT, void >
87 {
88 private:
89 RangeT const& m_range;
90
91 public:
92 //! Initializing constructor
range_manipulator(RangeT const & range)93 explicit range_manipulator(RangeT const& range) BOOST_NOEXCEPT :
94 m_range(range)
95 {
96 }
97
98 //! The method outputs elements of the range
99 template< typename StreamT >
output(StreamT & stream) const100 void output(StreamT& stream) const
101 {
102 typedef typename boost::range_const_iterator< RangeT >::type const_iterator;
103 const_iterator it = boost::begin(m_range);
104 const const_iterator end = boost::end(m_range);
105 for (; it != end; ++it)
106 {
107 stream << *it;
108 }
109 }
110 };
111
112 /*!
113 * Stream output operator for \c range_manipulator. Outputs every element of the range, separated with a delimiter, if one was specified on manipulator construction.
114 */
115 template< typename StreamT, typename RangeT, typename DelimiterT >
operator <<(StreamT & strm,range_manipulator<RangeT,DelimiterT> const & manip)116 inline typename boost::enable_if_c< log::aux::is_ostream< StreamT >::value, StreamT& >::type operator<< (StreamT& strm, range_manipulator< RangeT, DelimiterT > const& manip)
117 {
118 if (BOOST_LIKELY(strm.good()))
119 manip.output(strm);
120
121 return strm;
122 }
123
124 /*!
125 * Range manipulator generator function.
126 *
127 * \param range Range of elements to output. The range must support begin and end iterators, and its elements must support stream output.
128 * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation.
129 * \returns Manipulator to be inserted into the stream.
130 *
131 * \note Both \a range and \a delimiter objects must outlive the created manipulator object.
132 */
133 template< typename RangeT, typename DelimiterT >
134 inline typename boost::enable_if_c<
135 is_scalar< DelimiterT >::value,
136 range_manipulator< RangeT, DelimiterT >
range_manip(RangeT const & range,DelimiterT delimiter)137 >::type range_manip(RangeT const& range, DelimiterT delimiter) BOOST_NOEXCEPT
138 {
139 return range_manipulator< RangeT, DelimiterT >(range, delimiter);
140 }
141
142 /*!
143 * Range manipulator generator function.
144 *
145 * \param range Range of elements to output. The range must support begin and end iterators, and its elements must support stream output.
146 * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation.
147 * \returns Manipulator to be inserted into the stream.
148 *
149 * \note Both \a range and \a delimiter objects must outlive the created manipulator object.
150 */
151 template< typename RangeT, typename DelimiterT >
152 inline typename boost::disable_if_c<
153 is_scalar< DelimiterT >::value,
154 range_manipulator< RangeT, DelimiterT >
range_manip(RangeT const & range,DelimiterT const & delimiter)155 >::type range_manip(RangeT const& range, DelimiterT const& delimiter) BOOST_NOEXCEPT
156 {
157 return range_manipulator< RangeT, DelimiterT >(range, delimiter);
158 }
159
160 /*!
161 * Range manipulator generator function.
162 *
163 * \param range Range of elements to output. The range must support begin and end iterators, and its elements must support stream output.
164 * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation.
165 * \returns Manipulator to be inserted into the stream.
166 *
167 * \note Both \a range and \a delimiter objects must outlive the created manipulator object.
168 */
169 template< typename RangeT, typename DelimiterElementT, std::size_t N >
range_manip(RangeT const & range,DelimiterElementT (& delimiter)[N])170 inline range_manipulator< RangeT, DelimiterElementT* > range_manip(RangeT const& range, DelimiterElementT (&delimiter)[N]) BOOST_NOEXCEPT
171 {
172 return range_manipulator< RangeT, DelimiterElementT* >(range, delimiter);
173 }
174
175 /*!
176 * Range manipulator generator function.
177 *
178 * \param range Range of elements to output. The range must support begin and end iterators, and its elements must support stream output.
179 * \returns Manipulator to be inserted into the stream.
180 *
181 * \note \a delimiter object must outlive the created manipulator object.
182 */
183 template< typename RangeT >
range_manip(RangeT const & range)184 inline range_manipulator< RangeT, void > range_manip(RangeT const& range) BOOST_NOEXCEPT
185 {
186 return range_manipulator< RangeT, void >(range);
187 }
188
189 BOOST_LOG_CLOSE_NAMESPACE // namespace log
190
191 } // namespace boost
192
193 #include <boost/log/detail/footer.hpp>
194
195 #endif // BOOST_LOG_UTILITY_MANIPULATORS_RANGE_HPP_INCLUDED_
196