File indexing completed on 2025-01-30 10:02:38
0001
0002
0003
0004
0005
0006 #ifndef BOOST_YAP_PRINT_HPP_INCLUDED
0007 #define BOOST_YAP_PRINT_HPP_INCLUDED
0008
0009 #include <boost/yap/algorithm_fwd.hpp>
0010
0011 #include <boost/hana/for_each.hpp>
0012 #include <boost/type_index.hpp>
0013 #include <iostream>
0014
0015
0016 namespace boost { namespace yap {
0017
0018
0019
0020
0021
0022
0023 inline constexpr char const * op_string(expr_kind kind)
0024 {
0025 switch (kind) {
0026 case expr_kind::expr_ref: return "ref";
0027
0028 case expr_kind::terminal: return "term";
0029
0030 case expr_kind::unary_plus: return "+";
0031 case expr_kind::negate: return "-";
0032 case expr_kind::dereference: return "*";
0033 case expr_kind::complement: return "~";
0034 case expr_kind::address_of: return "&";
0035 case expr_kind::logical_not: return "!";
0036 case expr_kind::pre_inc: return "++";
0037 case expr_kind::pre_dec: return "--";
0038 case expr_kind::post_inc: return "++(int)";
0039 case expr_kind::post_dec: return "--(int)";
0040
0041 case expr_kind::shift_left: return "<<";
0042 case expr_kind::shift_right: return ">>";
0043 case expr_kind::multiplies: return "*";
0044 case expr_kind::divides: return "/";
0045 case expr_kind::modulus: return "%";
0046 case expr_kind::plus: return "+";
0047 case expr_kind::minus: return "-";
0048 case expr_kind::less: return "<";
0049 case expr_kind::greater: return ">";
0050 case expr_kind::less_equal: return "<=";
0051 case expr_kind::greater_equal: return ">=";
0052 case expr_kind::equal_to: return "==";
0053 case expr_kind::not_equal_to: return "!=";
0054 case expr_kind::logical_or: return "||";
0055 case expr_kind::logical_and: return "&&";
0056 case expr_kind::bitwise_and: return "&";
0057 case expr_kind::bitwise_or: return "|";
0058 case expr_kind::bitwise_xor: return "^";
0059 case expr_kind::comma: return ",";
0060 case expr_kind::mem_ptr: return "->*";
0061 case expr_kind::assign: return "=";
0062 case expr_kind::shift_left_assign: return "<<=";
0063 case expr_kind::shift_right_assign: return ">>=";
0064 case expr_kind::multiplies_assign: return "*=";
0065 case expr_kind::divides_assign: return "/=";
0066 case expr_kind::modulus_assign: return "%=";
0067 case expr_kind::plus_assign: return "+=";
0068 case expr_kind::minus_assign: return "-=";
0069 case expr_kind::bitwise_and_assign: return "&=";
0070 case expr_kind::bitwise_or_assign: return "|=";
0071 case expr_kind::bitwise_xor_assign: return "^=";
0072 case expr_kind::subscript: return "[]";
0073
0074 case expr_kind::if_else: return "?:";
0075
0076 case expr_kind::call: return "()";
0077
0078 default: return "** ERROR: UNKNOWN OPERATOR! **";
0079 }
0080 }
0081
0082 namespace detail {
0083
0084 inline std::ostream & print_kind(std::ostream & os, expr_kind kind)
0085 {
0086 return os << op_string(kind);
0087 }
0088
0089 template<typename T, typename = void_t<>>
0090 struct printer
0091 {
0092 std::ostream & operator()(std::ostream & os, T const &)
0093 {
0094 return os << "<<unprintable-value>>";
0095 }
0096 };
0097
0098 template<typename T>
0099 struct printer<
0100 T,
0101 void_t<decltype(
0102 std::declval<std::ostream &>() << std::declval<T const &>())>>
0103 {
0104 std::ostream & operator()(std::ostream & os, T const & x)
0105 {
0106 return os << x;
0107 }
0108 };
0109
0110 template<typename T>
0111 inline std::ostream & print_value(std::ostream & os, T const & x)
0112 {
0113 return printer<T>{}(os, x);
0114 }
0115
0116 template<long long I>
0117 inline std::ostream & print_value(std::ostream & os, hana::llong<I>)
0118 {
0119 return os << I << "_p";
0120 }
0121
0122 template<typename T>
0123 std::ostream & print_type(std::ostream & os, hana::tuple<T> const &)
0124 {
0125 os << typeindex::type_id<T>().pretty_name();
0126 if (std::is_const<std::remove_reference_t<T>>::value)
0127 os << " const";
0128 if (std::is_volatile<std::remove_reference_t<T>>::value)
0129 os << " volatile";
0130 if (std::is_lvalue_reference<T>::value)
0131 os << " &";
0132 if (std::is_rvalue_reference<T>::value)
0133 os << " &&";
0134 return os;
0135 }
0136
0137 template<typename T>
0138 bool is_const_expr_ref(T const &)
0139 {
0140 return false;
0141 }
0142 template<typename T, template<expr_kind, class> class expr_template>
0143 bool is_const_expr_ref(
0144 expr_template<expr_kind::expr_ref, hana::tuple<T const *>> const &)
0145 {
0146 return true;
0147 }
0148
0149 #ifdef BOOST_NO_CONSTEXPR_IF
0150
0151 template<expr_kind Kind>
0152 struct print_impl
0153 {
0154 template<typename Expr>
0155 std::ostream & operator()(
0156 std::ostream & os,
0157 Expr const & expr,
0158 int indent,
0159 char const * indent_str,
0160 bool is_ref = false,
0161 bool is_const_ref = false)
0162 {
0163 for (int i = 0; i < indent; ++i) {
0164 os << indent_str;
0165 }
0166
0167 os << "expr<";
0168 ::boost::yap::detail::print_kind(os, Expr::kind);
0169 os << ">";
0170 if (is_const_ref)
0171 os << " const &";
0172 else if (is_ref)
0173 os << " &";
0174 os << "\n";
0175 hana::for_each(
0176 expr.elements,
0177 [&os, indent, indent_str](auto const & element) {
0178 using element_type = decltype(element);
0179 constexpr expr_kind kind =
0180 detail::remove_cv_ref_t<element_type>::kind;
0181 print_impl<kind>{}(os, element, indent + 1, indent_str);
0182 });
0183
0184 return os;
0185 }
0186 };
0187
0188 template<>
0189 struct print_impl<expr_kind::expr_ref>
0190 {
0191 template<typename Expr>
0192 std::ostream & operator()(
0193 std::ostream & os,
0194 Expr const & expr,
0195 int indent,
0196 char const * indent_str,
0197 bool is_ref = false,
0198 bool is_const_ref = false)
0199 {
0200 using ref_type = decltype(::boost::yap::deref(expr));
0201 constexpr expr_kind ref_kind =
0202 detail::remove_cv_ref_t<ref_type>::kind;
0203 print_impl<ref_kind>{}(
0204 os,
0205 ::boost::yap::deref(expr),
0206 indent,
0207 indent_str,
0208 true,
0209 ::boost::yap::detail::is_const_expr_ref(expr));
0210 return os;
0211 }
0212 };
0213
0214 template<>
0215 struct print_impl<expr_kind::terminal>
0216 {
0217 template<typename Expr>
0218 std::ostream & operator()(
0219 std::ostream & os,
0220 Expr const & expr,
0221 int indent,
0222 char const * indent_str,
0223 bool is_ref = false,
0224 bool is_const_ref = false)
0225 {
0226 for (int i = 0; i < indent; ++i) {
0227 os << indent_str;
0228 }
0229
0230 os << "term<";
0231 ::boost::yap::detail::print_type(os, expr.elements);
0232 os << ">[=";
0233 ::boost::yap::detail::print_value(
0234 os, ::boost::yap::value(expr));
0235 os << "]";
0236 if (is_const_ref)
0237 os << " const &";
0238 else if (is_ref)
0239 os << " &";
0240 os << "\n";
0241
0242 return os;
0243 }
0244 };
0245
0246 #else
0247
0248 template<typename Expr>
0249 std::ostream & print_impl(
0250 std::ostream & os,
0251 Expr const & expr,
0252 int indent,
0253 char const * indent_str,
0254 bool is_ref = false,
0255 bool is_const_ref = false)
0256 {
0257 if constexpr (Expr::kind == expr_kind::expr_ref) {
0258 print_impl(
0259 os,
0260 ::boost::yap::deref(expr),
0261 indent,
0262 indent_str,
0263 true,
0264 ::boost::yap::detail::is_const_expr_ref(expr));
0265 } else {
0266 for (int i = 0; i < indent; ++i) {
0267 os << indent_str;
0268 }
0269
0270 if constexpr (Expr::kind == expr_kind::terminal) {
0271 os << "term<";
0272 ::boost::yap::detail::print_type(os, expr.elements);
0273 os << ">[=";
0274 ::boost::yap::detail::print_value(
0275 os, ::boost::yap::value(expr));
0276 os << "]";
0277 if (is_const_ref)
0278 os << " const &";
0279 else if (is_ref)
0280 os << " &";
0281 os << "\n";
0282 } else {
0283 os << "expr<";
0284 ::boost::yap::detail::print_kind(os, Expr::kind);
0285 os << ">";
0286 if (is_const_ref)
0287 os << " const &";
0288 else if (is_ref)
0289 os << " &";
0290 os << "\n";
0291 hana::for_each(
0292 expr.elements,
0293 [&os, indent, indent_str](auto const & element) {
0294 ::boost::yap::detail::print_impl(
0295 os, element, indent + 1, indent_str);
0296 });
0297 }
0298 }
0299
0300 return os;
0301 }
0302
0303 #endif
0304 }
0305
0306
0307 template<typename Expr>
0308 std::ostream & print(std::ostream & os, Expr const & expr)
0309 {
0310 #ifdef BOOST_NO_CONSTEXPR_IF
0311 return detail::print_impl<detail::remove_cv_ref_t<Expr>::kind>{}(
0312 os, expr, 0, " ");
0313 #else
0314 return detail::print_impl(os, expr, 0, " ");
0315 #endif
0316 }
0317
0318 }}
0319
0320 #endif