• 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/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