tuple.hpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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. #ifndef BOOST_LOG_UTILITY_MANIPULATORS_TUPLE_HPP_INCLUDED_
  15. #define BOOST_LOG_UTILITY_MANIPULATORS_TUPLE_HPP_INCLUDED_
  16. #include <cstddef>
  17. #include <boost/core/enable_if.hpp>
  18. #include <boost/type_traits/is_scalar.hpp>
  19. #include <boost/type_traits/conditional.hpp>
  20. #include <boost/type_traits/integral_constant.hpp>
  21. #include <boost/fusion/include/fold.hpp>
  22. #include <boost/fusion/include/for_each.hpp>
  23. #include <boost/log/detail/config.hpp>
  24. #include <boost/log/detail/is_ostream.hpp>
  25. #include <boost/log/detail/header.hpp>
  26. #ifdef BOOST_HAS_PRAGMA_ONCE
  27. #pragma once
  28. #endif
  29. namespace boost {
  30. BOOST_LOG_OPEN_NAMESPACE
  31. /*!
  32. * Stream manipulator for inserting a heterogeneous sequence of elements, optionally separated with a delimiter.
  33. */
  34. template< typename TupleT, typename DelimiterT >
  35. class tuple_manipulator
  36. {
  37. private:
  38. typedef typename conditional<
  39. is_scalar< DelimiterT >::value,
  40. DelimiterT,
  41. DelimiterT const&
  42. >::type stored_delimiter_type;
  43. template< typename StreamT >
  44. struct output_visitor
  45. {
  46. typedef boost::true_type result_type;
  47. output_visitor(StreamT& stream, stored_delimiter_type delimiter) BOOST_NOEXCEPT :
  48. m_stream(stream),
  49. m_delimiter(delimiter)
  50. {
  51. }
  52. template< typename T >
  53. result_type operator() (boost::true_type, T const& elem) const
  54. {
  55. m_stream << m_delimiter;
  56. return operator()(boost::false_type(), elem);
  57. }
  58. template< typename T >
  59. result_type operator() (boost::false_type, T const& elem) const
  60. {
  61. m_stream << elem;
  62. return result_type();
  63. }
  64. private:
  65. StreamT& m_stream;
  66. stored_delimiter_type m_delimiter;
  67. };
  68. private:
  69. TupleT const& m_tuple;
  70. stored_delimiter_type m_delimiter;
  71. public:
  72. //! Initializing constructor
  73. tuple_manipulator(TupleT const& tuple, stored_delimiter_type delimiter) BOOST_NOEXCEPT :
  74. m_tuple(tuple),
  75. m_delimiter(delimiter)
  76. {
  77. }
  78. //! The method outputs elements of the sequence separated with delimiter
  79. template< typename StreamT >
  80. void output(StreamT& stream) const
  81. {
  82. boost::fusion::fold(m_tuple, boost::false_type(), output_visitor< StreamT >(stream, m_delimiter));
  83. }
  84. };
  85. /*!
  86. * Stream manipulator for inserting a heterogeneous sequence of elements. Specialization for when there is no delimiter.
  87. */
  88. template< typename TupleT >
  89. class tuple_manipulator< TupleT, void >
  90. {
  91. private:
  92. template< typename StreamT >
  93. struct output_visitor
  94. {
  95. typedef void result_type;
  96. explicit output_visitor(StreamT& stream) BOOST_NOEXCEPT :
  97. m_stream(stream)
  98. {
  99. }
  100. template< typename T >
  101. result_type operator() (T const& elem) const
  102. {
  103. m_stream << elem;
  104. }
  105. private:
  106. StreamT& m_stream;
  107. };
  108. private:
  109. TupleT const& m_tuple;
  110. public:
  111. //! Initializing constructor
  112. explicit tuple_manipulator(TupleT const& tuple) BOOST_NOEXCEPT :
  113. m_tuple(tuple)
  114. {
  115. }
  116. //! The method outputs elements of the sequence
  117. template< typename StreamT >
  118. void output(StreamT& stream) const
  119. {
  120. boost::fusion::for_each(m_tuple, output_visitor< StreamT >(stream));
  121. }
  122. };
  123. /*!
  124. * Stream output operator for \c tuple_manipulator. Outputs every element of the sequence, separated with a delimiter, if one was specified on manipulator construction.
  125. */
  126. template< typename StreamT, typename TupleT, typename DelimiterT >
  127. inline typename boost::enable_if_c< log::aux::is_ostream< StreamT >::value, StreamT& >::type operator<< (StreamT& strm, tuple_manipulator< TupleT, DelimiterT > const& manip)
  128. {
  129. if (BOOST_LIKELY(strm.good()))
  130. manip.output(strm);
  131. return strm;
  132. }
  133. /*!
  134. * Tuple manipulator generator function.
  135. *
  136. * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output.
  137. * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation.
  138. * \returns Manipulator to be inserted into the stream.
  139. *
  140. * \note Both \a tuple and \a delimiter objects must outlive the created manipulator object.
  141. */
  142. template< typename TupleT, typename DelimiterT >
  143. inline typename boost::enable_if_c<
  144. is_scalar< DelimiterT >::value,
  145. tuple_manipulator< TupleT, DelimiterT >
  146. >::type tuple_manip(TupleT const& tuple, DelimiterT delimiter) BOOST_NOEXCEPT
  147. {
  148. return tuple_manipulator< TupleT, DelimiterT >(tuple, delimiter);
  149. }
  150. /*!
  151. * Tuple manipulator generator function.
  152. *
  153. * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output.
  154. * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation.
  155. * \returns Manipulator to be inserted into the stream.
  156. *
  157. * \note Both \a tuple and \a delimiter objects must outlive the created manipulator object.
  158. */
  159. template< typename TupleT, typename DelimiterT >
  160. inline typename boost::disable_if_c<
  161. is_scalar< DelimiterT >::value,
  162. tuple_manipulator< TupleT, DelimiterT >
  163. >::type tuple_manip(TupleT const& tuple, DelimiterT const& delimiter) BOOST_NOEXCEPT
  164. {
  165. return tuple_manipulator< TupleT, DelimiterT >(tuple, delimiter);
  166. }
  167. /*!
  168. * Tuple manipulator generator function.
  169. *
  170. * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output.
  171. * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation.
  172. * \returns Manipulator to be inserted into the stream.
  173. *
  174. * \note Both \a tuple and \a delimiter objects must outlive the created manipulator object.
  175. */
  176. template< typename TupleT, typename DelimiterElementT, std::size_t N >
  177. inline tuple_manipulator< TupleT, DelimiterElementT* > tuple_manip(TupleT const& tuple, DelimiterElementT (&delimiter)[N]) BOOST_NOEXCEPT
  178. {
  179. return tuple_manipulator< TupleT, DelimiterElementT* >(tuple, delimiter);
  180. }
  181. /*!
  182. * Tuple manipulator generator function.
  183. *
  184. * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output.
  185. * \returns Manipulator to be inserted into the stream.
  186. *
  187. * \note \a tuple object must outlive the created manipulator object.
  188. */
  189. template< typename TupleT >
  190. inline tuple_manipulator< TupleT, void > tuple_manip(TupleT const& tuple) BOOST_NOEXCEPT
  191. {
  192. return tuple_manipulator< TupleT, void >(tuple);
  193. }
  194. BOOST_LOG_CLOSE_NAMESPACE // namespace log
  195. } // namespace boost
  196. #include <boost/log/detail/footer.hpp>
  197. #endif // BOOST_LOG_UTILITY_MANIPULATORS_TUPLE_HPP_INCLUDED_