io_fields.hpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // Copyright (c) 2016-2025 Antony Polukhin
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_PFR_IO_FIELDS_HPP
  6. #define BOOST_PFR_IO_FIELDS_HPP
  7. #pragma once
  8. #include <boost/pfr/detail/config.hpp>
  9. #if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
  10. #include <boost/pfr/detail/core.hpp>
  11. #include <boost/pfr/detail/sequence_tuple.hpp>
  12. #include <boost/pfr/detail/io.hpp>
  13. #include <boost/pfr/detail/make_integer_sequence.hpp>
  14. #include <boost/pfr/tuple_size.hpp>
  15. #if !defined(BOOST_PFR_INTERFACE_UNIT)
  16. #include <type_traits>
  17. #include <utility> // metaprogramming stuff
  18. #endif
  19. /// \file boost/pfr/io_fields.hpp
  20. /// Contains IO manipulator \forcedlink{io_fields} to read/write any \aggregate field-by-field.
  21. ///
  22. /// \b Example:
  23. /// \code
  24. /// struct my_struct {
  25. /// int i;
  26. /// short s;
  27. /// };
  28. ///
  29. /// std::ostream& operator<<(std::ostream& os, const my_struct& x) {
  30. /// return os << boost::pfr::io_fields(x); // Equivalent to: os << "{ " << x.i << " ," << x.s << " }"
  31. /// }
  32. ///
  33. /// std::istream& operator>>(std::istream& is, my_struct& x) {
  34. /// return is >> boost::pfr::io_fields(x); // Equivalent to: is >> "{ " >> x.i >> " ," >> x.s >> " }"
  35. /// }
  36. /// \endcode
  37. ///
  38. /// \podops for other ways to define operators and more details.
  39. ///
  40. /// \b Synopsis:
  41. namespace boost { namespace pfr {
  42. namespace detail {
  43. template <class T>
  44. struct io_fields_impl {
  45. T value;
  46. };
  47. BOOST_PFR_BEGIN_MODULE_EXPORT
  48. template <class Char, class Traits, class T>
  49. std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, io_fields_impl<const T&>&& x) {
  50. const T& value = x.value;
  51. constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<T>();
  52. out << '{';
  53. #if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
  54. detail::print_impl<0, fields_count_val>::print(out, detail::tie_as_tuple(value));
  55. #else
  56. ::boost::pfr::detail::for_each_field_dispatcher(
  57. value,
  58. [&out](const auto& val) {
  59. // We can not reuse `fields_count_val` in lambda because compilers had issues with
  60. // passing constexpr variables into lambdas. Computing is again is the most portable solution.
  61. constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<T>();
  62. detail::print_impl<0, fields_count_val_lambda>::print(out, val);
  63. },
  64. detail::make_index_sequence<fields_count_val>{}
  65. );
  66. #endif
  67. return out << '}';
  68. }
  69. template <class Char, class Traits, class T>
  70. std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, io_fields_impl<T>&& x) {
  71. return out << io_fields_impl<const std::remove_reference_t<T>&>{x.value};
  72. }
  73. template <class Char, class Traits, class T>
  74. std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, io_fields_impl<T&>&& x) {
  75. T& value = x.value;
  76. constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<T>();
  77. const auto prev_exceptions = in.exceptions();
  78. in.exceptions( typename std::basic_istream<Char, Traits>::iostate(0) );
  79. const auto prev_flags = in.flags( typename std::basic_istream<Char, Traits>::fmtflags(0) );
  80. char parenthis = {};
  81. in >> parenthis;
  82. if (parenthis != '{') in.setstate(std::basic_istream<Char, Traits>::failbit);
  83. #if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
  84. detail::read_impl<0, fields_count_val>::read(in, detail::tie_as_tuple(value));
  85. #else
  86. ::boost::pfr::detail::for_each_field_dispatcher(
  87. value,
  88. [&in](const auto& val) {
  89. // We can not reuse `fields_count_val` in lambda because compilers had issues with
  90. // passing constexpr variables into lambdas. Computing is again is the most portable solution.
  91. constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<T>();
  92. detail::read_impl<0, fields_count_val_lambda>::read(in, val);
  93. },
  94. detail::make_index_sequence<fields_count_val>{}
  95. );
  96. #endif
  97. in >> parenthis;
  98. if (parenthis != '}') in.setstate(std::basic_istream<Char, Traits>::failbit);
  99. in.flags(prev_flags);
  100. in.exceptions(prev_exceptions);
  101. return in;
  102. }
  103. template <class Char, class Traits, class T>
  104. std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, io_fields_impl<const T&>&& ) {
  105. static_assert(sizeof(T) && false, "====================> Boost.PFR: Attempt to use istream operator on a boost::pfr::io_fields wrapped type T with const qualifier.");
  106. return in;
  107. }
  108. template <class Char, class Traits, class T>
  109. std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, io_fields_impl<T>&& ) {
  110. static_assert(sizeof(T) && false, "====================> Boost.PFR: Attempt to use istream operator on a boost::pfr::io_fields wrapped temporary of type T.");
  111. return in;
  112. }
  113. BOOST_PFR_END_MODULE_EXPORT
  114. } // namespace detail
  115. BOOST_PFR_BEGIN_MODULE_EXPORT
  116. /// IO manipulator to read/write \aggregate `value` field-by-field.
  117. ///
  118. /// \b Example:
  119. /// \code
  120. /// struct my_struct {
  121. /// int i;
  122. /// short s;
  123. /// };
  124. ///
  125. /// std::ostream& operator<<(std::ostream& os, const my_struct& x) {
  126. /// return os << boost::pfr::io_fields(x); // Equivalent to: os << "{ " << x.i << " ," << x.s << " }"
  127. /// }
  128. ///
  129. /// std::istream& operator>>(std::istream& is, my_struct& x) {
  130. /// return is >> boost::pfr::io_fields(x); // Equivalent to: is >> "{ " >> x.i >> " ," >> x.s >> " }"
  131. /// }
  132. /// \endcode
  133. ///
  134. /// Input and output streaming operators for `boost::pfr::io_fields` are symmetric, meaning that you get the original value by streaming it and
  135. /// reading back if each fields streaming operator is symmetric.
  136. ///
  137. /// \customio
  138. template <class T>
  139. auto io_fields(T&& value) noexcept {
  140. return detail::io_fields_impl<T>{std::forward<T>(value)};
  141. }
  142. BOOST_PFR_END_MODULE_EXPORT
  143. }} // namespace boost::pfr
  144. #endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
  145. #endif // BOOST_PFR_IO_FIELDS_HPP