operators.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #ifndef BOOST_DESCRIBE_OPERATORS_HPP_INCLUDED
  2. #define BOOST_DESCRIBE_OPERATORS_HPP_INCLUDED
  3. // Copyright 2020, 2021 Peter Dimov
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // https://www.boost.org/LICENSE_1_0.txt
  6. #include <boost/describe/detail/config.hpp>
  7. #if defined(BOOST_DESCRIBE_CXX14)
  8. #include <boost/describe/bases.hpp>
  9. #include <boost/describe/members.hpp>
  10. #include <boost/describe/modifiers.hpp>
  11. #include <boost/mp11/algorithm.hpp>
  12. #include <type_traits>
  13. #include <iosfwd>
  14. #if defined(_MSC_VER) && _MSC_VER == 1900
  15. # pragma warning(push)
  16. # pragma warning(disable: 4100) // unreferenced formal parameter
  17. #endif
  18. namespace boost
  19. {
  20. namespace describe
  21. {
  22. namespace detail
  23. {
  24. template<class T,
  25. class Bd = describe::describe_bases<T, mod_any_access>,
  26. class Md = describe::describe_members<T, mod_any_access>>
  27. bool eq( T const& t1, T const& t2 )
  28. {
  29. bool r = true;
  30. mp11::mp_for_each<Bd>([&](auto D){
  31. using B = typename decltype(D)::type;
  32. r = r && (B const&)t1 == (B const&)t2;
  33. });
  34. mp11::mp_for_each<Md>([&](auto D){
  35. r = r && t1.*D.pointer == t2.*D.pointer;
  36. });
  37. return r;
  38. }
  39. template<class T,
  40. class Bd = describe::describe_bases<T, mod_any_access>,
  41. class Md = describe::describe_members<T, mod_any_access>>
  42. bool lt( T const& t1, T const& t2 )
  43. {
  44. int r = 0;
  45. mp11::mp_for_each<Bd>([&](auto D){
  46. using B = typename decltype(D)::type;
  47. if( r == 0 && (B const&)t1 < (B const&)t2 ) r = -1;
  48. if( r == 0 && (B const&)t2 < (B const&)t1 ) r = +1;
  49. });
  50. mp11::mp_for_each<Md>([&](auto D){
  51. if( r == 0 && t1.*D.pointer < t2.*D.pointer ) r = -1;
  52. if( r == 0 && t2.*D.pointer < t1.*D.pointer ) r = +1;
  53. });
  54. return r < 0;
  55. }
  56. template<class Os, class T,
  57. class Bd = describe::describe_bases<T, mod_any_access>,
  58. class Md = describe::describe_members<T, mod_any_access>>
  59. void print( Os& os, T const& t )
  60. {
  61. os << "{";
  62. bool first = true;
  63. mp11::mp_for_each<Bd>([&](auto D){
  64. if( !first ) { os << ", "; }
  65. first = false;
  66. using B = typename decltype(D)::type;
  67. os << (B const&)t;
  68. });
  69. mp11::mp_for_each<Md>([&](auto D){
  70. if( !first ) { os << ", "; }
  71. first = false;
  72. os << "." << D.name << " = " << t.*D.pointer;
  73. });
  74. os << "}";
  75. }
  76. } // namespace detail
  77. namespace operators
  78. {
  79. template<class T> std::enable_if_t<
  80. has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value, bool>
  81. operator==( T const& t1, T const& t2 )
  82. {
  83. return detail::eq( t1, t2 );
  84. }
  85. template<class T> std::enable_if_t<
  86. has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value, bool>
  87. operator!=( T const& t1, T const& t2 )
  88. {
  89. return !detail::eq( t1, t2 );
  90. }
  91. template<class T> std::enable_if_t<
  92. has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value, bool>
  93. operator<( T const& t1, T const& t2 )
  94. {
  95. return detail::lt( t1, t2 );
  96. }
  97. template<class T> std::enable_if_t<
  98. has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value, bool>
  99. operator>=( T const& t1, T const& t2 )
  100. {
  101. return !detail::lt( t1, t2 );
  102. }
  103. template<class T> std::enable_if_t<
  104. has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value, bool>
  105. operator>( T const& t1, T const& t2 )
  106. {
  107. return detail::lt( t2, t1 );
  108. }
  109. template<class T> std::enable_if_t<
  110. has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value, bool>
  111. operator<=( T const& t1, T const& t2 )
  112. {
  113. return !detail::lt( t2, t1 );
  114. }
  115. template<class T, class Ch, class Tr> std::enable_if_t<
  116. has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value,
  117. std::basic_ostream<Ch, Tr>&>
  118. operator<<( std::basic_ostream<Ch, Tr>& os, T const& t )
  119. {
  120. os.width( 0 );
  121. detail::print( os, t );
  122. return os;
  123. }
  124. } // namespace operators
  125. } // namespace describe
  126. } // namespace boost
  127. #if defined(_MSC_VER) && _MSC_VER == 1900
  128. # pragma warning(pop)
  129. #endif
  130. #endif // defined(BOOST_DESCRIBE_CXX14)
  131. #endif // #ifndef BOOST_DESCRIBE_OPERATORS_HPP_INCLUDED