1 ///////////////////////////////////////////////////////////////
2 // Copyright 2012 John Maddock. Distributed under the Boost
3 // Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
6 #ifndef BOOST_MATH_LOGGED_ADAPTER_HPP
7 #define BOOST_MATH_LOGGED_ADAPTER_HPP
9 #include <boost/multiprecision/traits/extract_exponent_type.hpp>
10 #include <boost/multiprecision/detail/integer_ops.hpp>
13 namespace multiprecision {
15 template <class Backend>
16 inline void log_postfix_event(const Backend&, const char* /*event_description*/)
19 template <class Backend, class T>
20 inline void log_postfix_event(const Backend&, const T&, const char* /*event_description*/)
23 template <class Backend>
24 inline void log_prefix_event(const Backend&, const char* /*event_description*/)
27 template <class Backend, class T>
28 inline void log_prefix_event(const Backend&, const T&, const char* /*event_description*/)
31 template <class Backend, class T, class U>
32 inline void log_prefix_event(const Backend&, const T&, const U&, const char* /*event_description*/)
35 template <class Backend, class T, class U, class V>
36 inline void log_prefix_event(const Backend&, const T&, const U&, const V&, const char* /*event_description*/)
42 template <class Backend>
45 typedef typename Backend::signed_types signed_types;
46 typedef typename Backend::unsigned_types unsigned_types;
47 typedef typename Backend::float_types float_types;
48 typedef typename extract_exponent_type<
49 Backend, number_category<Backend>::value>::type exponent_type;
57 log_postfix_event(m_value, "Default construct");
59 logged_adaptor(const logged_adaptor& o)
61 log_prefix_event(m_value, o.value(), "Copy construct");
63 log_postfix_event(m_value, "Copy construct");
65 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
66 logged_adaptor(logged_adaptor&& o)
68 log_prefix_event(m_value, o.value(), "Move construct");
69 m_value = static_cast<Backend&&>(o.m_value);
70 log_postfix_event(m_value, "Move construct");
72 logged_adaptor& operator=(logged_adaptor&& o)
74 log_prefix_event(m_value, o.value(), "Move Assignment");
75 m_value = static_cast<Backend&&>(o.m_value);
76 log_postfix_event(m_value, "Move construct");
80 logged_adaptor& operator=(const logged_adaptor& o)
82 log_prefix_event(m_value, o.value(), "Assignment");
84 log_postfix_event(m_value, "Copy construct");
88 logged_adaptor(const T& i, const typename enable_if_c<is_convertible<T, Backend>::value>::type* = 0)
91 log_postfix_event(m_value, "construct from arithmetic type");
94 logged_adaptor(const logged_adaptor<T>& i, const typename enable_if_c<is_convertible<T, Backend>::value>::type* = 0)
97 log_postfix_event(m_value, "construct from arithmetic type");
100 typename enable_if_c<is_arithmetic<T>::value || is_convertible<T, Backend>::value, logged_adaptor&>::type operator=(const T& i)
102 log_prefix_event(m_value, i, "Assignment from arithmetic type");
104 log_postfix_event(m_value, "Assignment from arithmetic type");
107 logged_adaptor& operator=(const char* s)
109 log_prefix_event(m_value, s, "Assignment from string type");
111 log_postfix_event(m_value, "Assignment from string type");
114 void swap(logged_adaptor& o)
116 log_prefix_event(m_value, o.value(), "swap");
117 std::swap(m_value, o.value());
118 log_postfix_event(m_value, "swap");
120 std::string str(std::streamsize digits, std::ios_base::fmtflags f) const
122 log_prefix_event(m_value, "Conversion to string");
123 std::string s = m_value.str(digits, f);
124 log_postfix_event(m_value, s, "Conversion to string");
129 log_prefix_event(m_value, "negate");
131 log_postfix_event(m_value, "negate");
133 int compare(const logged_adaptor& o) const
135 log_prefix_event(m_value, o.value(), "compare");
136 int r = m_value.compare(o.value());
137 log_postfix_event(m_value, r, "compare");
141 int compare(const T& i) const
143 log_prefix_event(m_value, i, "compare");
144 int r = m_value.compare(i);
145 log_postfix_event(m_value, r, "compare");
152 const Backend& value() const
156 template <class Archive>
157 void serialize(Archive& ar, const unsigned int /*version*/)
159 log_prefix_event(m_value, "serialize");
160 ar& boost::make_nvp("value", m_value);
161 log_postfix_event(m_value, "serialize");
163 static unsigned default_precision() BOOST_NOEXCEPT
165 return Backend::default_precision();
167 static void default_precision(unsigned v) BOOST_NOEXCEPT
169 Backend::default_precision(v);
171 unsigned precision() const BOOST_NOEXCEPT
173 return value().precision();
175 void precision(unsigned digits10) BOOST_NOEXCEPT
177 value().precision(digits10);
182 inline const T& unwrap_logged_type(const T& a) { return a; }
183 template <class Backend>
184 inline const Backend& unwrap_logged_type(const logged_adaptor<Backend>& a) { return a.value(); }
186 #define NON_MEMBER_OP1(name, str) \
187 template <class Backend> \
188 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend> & result) \
190 using default_ops::BOOST_JOIN(eval_, name); \
191 log_prefix_event(result.value(), str); \
192 BOOST_JOIN(eval_, name) \
194 log_postfix_event(result.value(), str); \
197 #define NON_MEMBER_OP2(name, str) \
198 template <class Backend, class T> \
199 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend> & result, const T& a) \
201 using default_ops::BOOST_JOIN(eval_, name); \
202 log_prefix_event(result.value(), unwrap_logged_type(a), str); \
203 BOOST_JOIN(eval_, name) \
204 (result.value(), unwrap_logged_type(a)); \
205 log_postfix_event(result.value(), str); \
207 template <class Backend> \
208 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend> & result, const logged_adaptor<Backend>& a) \
210 using default_ops::BOOST_JOIN(eval_, name); \
211 log_prefix_event(result.value(), unwrap_logged_type(a), str); \
212 BOOST_JOIN(eval_, name) \
213 (result.value(), unwrap_logged_type(a)); \
214 log_postfix_event(result.value(), str); \
217 #define NON_MEMBER_OP3(name, str) \
218 template <class Backend, class T, class U> \
219 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend> & result, const T& a, const U& b) \
221 using default_ops::BOOST_JOIN(eval_, name); \
222 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str); \
223 BOOST_JOIN(eval_, name) \
224 (result.value(), unwrap_logged_type(a), unwrap_logged_type(b)); \
225 log_postfix_event(result.value(), str); \
227 template <class Backend, class T> \
228 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend> & result, const logged_adaptor<Backend>& a, const T& b) \
230 using default_ops::BOOST_JOIN(eval_, name); \
231 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str); \
232 BOOST_JOIN(eval_, name) \
233 (result.value(), unwrap_logged_type(a), unwrap_logged_type(b)); \
234 log_postfix_event(result.value(), str); \
236 template <class Backend, class T> \
237 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend> & result, const T& a, const logged_adaptor<Backend>& b) \
239 using default_ops::BOOST_JOIN(eval_, name); \
240 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str); \
241 BOOST_JOIN(eval_, name) \
242 (result.value(), unwrap_logged_type(a), unwrap_logged_type(b)); \
243 log_postfix_event(result.value(), str); \
245 template <class Backend> \
246 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend> & result, const logged_adaptor<Backend>& a, const logged_adaptor<Backend>& b) \
248 using default_ops::BOOST_JOIN(eval_, name); \
249 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str); \
250 BOOST_JOIN(eval_, name) \
251 (result.value(), unwrap_logged_type(a), unwrap_logged_type(b)); \
252 log_postfix_event(result.value(), str); \
255 #define NON_MEMBER_OP4(name, str) \
256 template <class Backend, class T, class U, class V> \
257 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend> & result, const T& a, const U& b, const V& c) \
259 using default_ops::BOOST_JOIN(eval_, name); \
260 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str); \
261 BOOST_JOIN(eval_, name) \
262 (result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c)); \
263 log_postfix_event(result.value(), str); \
265 template <class Backend, class T> \
266 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend> & result, const logged_adaptor<Backend>& a, const logged_adaptor<Backend>& b, const T& c) \
268 using default_ops::BOOST_JOIN(eval_, name); \
269 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str); \
270 BOOST_JOIN(eval_, name) \
271 (result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c)); \
272 log_postfix_event(result.value(), str); \
274 template <class Backend, class T> \
275 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend> & result, const logged_adaptor<Backend>& a, const T& b, const logged_adaptor<Backend>& c) \
277 using default_ops::BOOST_JOIN(eval_, name); \
278 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str); \
279 BOOST_JOIN(eval_, name) \
280 (result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c)); \
281 log_postfix_event(result.value(), str); \
283 template <class Backend, class T> \
284 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend> & result, const T& a, const logged_adaptor<Backend>& b, const logged_adaptor<Backend>& c) \
286 using default_ops::BOOST_JOIN(eval_, name); \
287 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str); \
288 BOOST_JOIN(eval_, name) \
289 (result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c)); \
290 log_postfix_event(result.value(), str); \
292 template <class Backend> \
293 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend> & result, const logged_adaptor<Backend>& a, const logged_adaptor<Backend>& b, const logged_adaptor<Backend>& c) \
295 using default_ops::BOOST_JOIN(eval_, name); \
296 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str); \
297 BOOST_JOIN(eval_, name) \
298 (result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c)); \
299 log_postfix_event(result.value(), str); \
301 template <class Backend, class T, class U> \
302 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend> & result, const logged_adaptor<Backend>& a, const T& b, const U& c) \
304 using default_ops::BOOST_JOIN(eval_, name); \
305 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str); \
306 BOOST_JOIN(eval_, name) \
307 (result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c)); \
308 log_postfix_event(result.value(), str); \
311 NON_MEMBER_OP2(add, "+=")
312 NON_MEMBER_OP2(subtract, "-=")
313 NON_MEMBER_OP2(multiply, "*=")
314 NON_MEMBER_OP2(divide, "/=")
316 template <class Backend, class R>
317 inline void eval_convert_to(R* result, const logged_adaptor<Backend>& val)
319 using default_ops::eval_convert_to;
320 log_prefix_event(val.value(), "convert_to");
321 eval_convert_to(result, val.value());
322 log_postfix_event(val.value(), *result, "convert_to");
325 template <class Backend, class Exp>
326 inline void eval_frexp(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& arg, Exp* exp)
328 log_prefix_event(arg.value(), "frexp");
329 eval_frexp(result.value(), arg.value(), exp);
330 log_postfix_event(result.value(), *exp, "frexp");
333 template <class Backend, class Exp>
334 inline void eval_ldexp(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& arg, Exp exp)
336 log_prefix_event(arg.value(), "ldexp");
337 eval_ldexp(result.value(), arg.value(), exp);
338 log_postfix_event(result.value(), exp, "ldexp");
341 template <class Backend, class Exp>
342 inline void eval_scalbn(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& arg, Exp exp)
344 log_prefix_event(arg.value(), "scalbn");
345 eval_scalbn(result.value(), arg.value(), exp);
346 log_postfix_event(result.value(), exp, "scalbn");
349 template <class Backend>
350 inline typename Backend::exponent_type eval_ilogb(const logged_adaptor<Backend>& arg)
352 log_prefix_event(arg.value(), "ilogb");
353 typename Backend::exponent_type r = eval_ilogb(arg.value());
354 log_postfix_event(arg.value(), "ilogb");
358 NON_MEMBER_OP2(floor, "floor")
359 NON_MEMBER_OP2(ceil, "ceil")
360 NON_MEMBER_OP2(sqrt, "sqrt")
362 template <class Backend>
363 inline int eval_fpclassify(const logged_adaptor<Backend>& arg)
365 using default_ops::eval_fpclassify;
366 log_prefix_event(arg.value(), "fpclassify");
367 int r = eval_fpclassify(arg.value());
368 log_postfix_event(arg.value(), r, "fpclassify");
372 /*********************************************************************
374 * Optional arithmetic operations come next:
376 *********************************************************************/
378 NON_MEMBER_OP3(add, "+")
379 NON_MEMBER_OP3(subtract, "-")
380 NON_MEMBER_OP3(multiply, "*")
381 NON_MEMBER_OP3(divide, "/")
382 NON_MEMBER_OP3(multiply_add, "fused-multiply-add")
383 NON_MEMBER_OP3(multiply_subtract, "fused-multiply-subtract")
384 NON_MEMBER_OP4(multiply_add, "fused-multiply-add")
385 NON_MEMBER_OP4(multiply_subtract, "fused-multiply-subtract")
387 NON_MEMBER_OP1(increment, "increment")
388 NON_MEMBER_OP1(decrement, "decrement")
390 /*********************************************************************
392 * Optional integer operations come next:
394 *********************************************************************/
396 NON_MEMBER_OP2(modulus, "%=")
397 NON_MEMBER_OP3(modulus, "%")
398 NON_MEMBER_OP2(bitwise_or, "|=")
399 NON_MEMBER_OP3(bitwise_or, "|")
400 NON_MEMBER_OP2(bitwise_and, "&=")
401 NON_MEMBER_OP3(bitwise_and, "&")
402 NON_MEMBER_OP2(bitwise_xor, "^=")
403 NON_MEMBER_OP3(bitwise_xor, "^")
404 NON_MEMBER_OP4(qr, "quotient-and-remainder")
405 NON_MEMBER_OP2(complement, "~")
407 template <class Backend>
408 inline void eval_left_shift(logged_adaptor<Backend>& arg, std::size_t a)
410 using default_ops::eval_left_shift;
411 log_prefix_event(arg.value(), a, "<<=");
412 eval_left_shift(arg.value(), a);
413 log_postfix_event(arg.value(), "<<=");
415 template <class Backend>
416 inline void eval_left_shift(logged_adaptor<Backend>& arg, const logged_adaptor<Backend>& a, std::size_t b)
418 using default_ops::eval_left_shift;
419 log_prefix_event(arg.value(), a, b, "<<");
420 eval_left_shift(arg.value(), a.value(), b);
421 log_postfix_event(arg.value(), "<<");
423 template <class Backend>
424 inline void eval_right_shift(logged_adaptor<Backend>& arg, std::size_t a)
426 using default_ops::eval_right_shift;
427 log_prefix_event(arg.value(), a, ">>=");
428 eval_right_shift(arg.value(), a);
429 log_postfix_event(arg.value(), ">>=");
431 template <class Backend>
432 inline void eval_right_shift(logged_adaptor<Backend>& arg, const logged_adaptor<Backend>& a, std::size_t b)
434 using default_ops::eval_right_shift;
435 log_prefix_event(arg.value(), a, b, ">>");
436 eval_right_shift(arg.value(), a.value(), b);
437 log_postfix_event(arg.value(), ">>");
440 template <class Backend, class T>
441 inline unsigned eval_integer_modulus(const logged_adaptor<Backend>& arg, const T& a)
443 using default_ops::eval_integer_modulus;
444 log_prefix_event(arg.value(), a, "integer-modulus");
445 unsigned r = eval_integer_modulus(arg.value(), a);
446 log_postfix_event(arg.value(), r, "integer-modulus");
450 template <class Backend>
451 inline unsigned eval_lsb(const logged_adaptor<Backend>& arg)
453 using default_ops::eval_lsb;
454 log_prefix_event(arg.value(), "least-significant-bit");
455 unsigned r = eval_lsb(arg.value());
456 log_postfix_event(arg.value(), r, "least-significant-bit");
460 template <class Backend>
461 inline unsigned eval_msb(const logged_adaptor<Backend>& arg)
463 using default_ops::eval_msb;
464 log_prefix_event(arg.value(), "most-significant-bit");
465 unsigned r = eval_msb(arg.value());
466 log_postfix_event(arg.value(), r, "most-significant-bit");
470 template <class Backend>
471 inline bool eval_bit_test(const logged_adaptor<Backend>& arg, unsigned a)
473 using default_ops::eval_bit_test;
474 log_prefix_event(arg.value(), a, "bit-test");
475 bool r = eval_bit_test(arg.value(), a);
476 log_postfix_event(arg.value(), r, "bit-test");
480 template <class Backend>
481 inline void eval_bit_set(const logged_adaptor<Backend>& arg, unsigned a)
483 using default_ops::eval_bit_set;
484 log_prefix_event(arg.value(), a, "bit-set");
485 eval_bit_set(arg.value(), a);
486 log_postfix_event(arg.value(), arg, "bit-set");
488 template <class Backend>
489 inline void eval_bit_unset(const logged_adaptor<Backend>& arg, unsigned a)
491 using default_ops::eval_bit_unset;
492 log_prefix_event(arg.value(), a, "bit-unset");
493 eval_bit_unset(arg.value(), a);
494 log_postfix_event(arg.value(), arg, "bit-unset");
496 template <class Backend>
497 inline void eval_bit_flip(const logged_adaptor<Backend>& arg, unsigned a)
499 using default_ops::eval_bit_flip;
500 log_prefix_event(arg.value(), a, "bit-flip");
501 eval_bit_flip(arg.value(), a);
502 log_postfix_event(arg.value(), arg, "bit-flip");
505 NON_MEMBER_OP3(gcd, "gcd")
506 NON_MEMBER_OP3(lcm, "lcm")
507 NON_MEMBER_OP4(powm, "powm")
509 /*********************************************************************
513 *********************************************************************/
515 NON_MEMBER_OP2(abs, "abs")
516 NON_MEMBER_OP2(fabs, "fabs")
518 /*********************************************************************
520 * Floating point functions:
522 *********************************************************************/
524 NON_MEMBER_OP2(trunc, "trunc")
525 NON_MEMBER_OP2(round, "round")
526 NON_MEMBER_OP2(exp, "exp")
527 NON_MEMBER_OP2(log, "log")
528 NON_MEMBER_OP2(log10, "log10")
529 NON_MEMBER_OP2(sin, "sin")
530 NON_MEMBER_OP2(cos, "cos")
531 NON_MEMBER_OP2(tan, "tan")
532 NON_MEMBER_OP2(asin, "asin")
533 NON_MEMBER_OP2(acos, "acos")
534 NON_MEMBER_OP2(atan, "atan")
535 NON_MEMBER_OP2(sinh, "sinh")
536 NON_MEMBER_OP2(cosh, "cosh")
537 NON_MEMBER_OP2(tanh, "tanh")
538 NON_MEMBER_OP2(logb, "logb")
539 NON_MEMBER_OP3(fmod, "fmod")
540 NON_MEMBER_OP3(pow, "pow")
541 NON_MEMBER_OP3(atan2, "atan2")
543 template <class Backend>
544 int eval_signbit(const logged_adaptor<Backend>& val)
546 using default_ops::eval_signbit;
547 return eval_signbit(val.value());
550 template <class Backend>
551 std::size_t hash_value(const logged_adaptor<Backend>& val)
553 return hash_value(val.value());
556 #define NON_MEMBER_COMPLEX_TO_REAL(name, str) \
557 template <class B1, class B2> \
558 inline void BOOST_JOIN(eval_, name)(logged_adaptor<B1> & result, const logged_adaptor<B2>& a) \
560 using default_ops::BOOST_JOIN(eval_, name); \
561 log_prefix_event(a.value(), a.value(), str); \
562 BOOST_JOIN(eval_, name) \
563 (result.value(), a.value()); \
564 log_postfix_event(result.value(), str); \
566 template <class B1, class B2> \
567 inline void BOOST_JOIN(eval_, name)(B1 & result, const logged_adaptor<B2>& a) \
569 using default_ops::BOOST_JOIN(eval_, name); \
570 log_prefix_event(a.value(), a.value(), str); \
571 BOOST_JOIN(eval_, name) \
572 (result, a.value()); \
573 log_postfix_event(result, str); \
576 NON_MEMBER_COMPLEX_TO_REAL(real, "real")
577 NON_MEMBER_COMPLEX_TO_REAL(imag, "imag")
579 template <class T, class V, class U>
580 inline void assign_components(logged_adaptor<T>& result, const V& v1, const U& v2)
582 assign_components(result.value(), v1, v2);
585 } // namespace backends
587 using backends::logged_adaptor;
589 template <class Backend>
590 struct number_category<backends::logged_adaptor<Backend> > : public number_category<Backend>
593 }} // namespace boost::multiprecision
597 template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
598 class numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::logged_adaptor<Backend>, ExpressionTemplates> >
599 : public std::numeric_limits<boost::multiprecision::number<Backend, ExpressionTemplates> >
601 typedef std::numeric_limits<boost::multiprecision::number<Backend, ExpressionTemplates> > base_type;
602 typedef boost::multiprecision::number<boost::multiprecision::backends::logged_adaptor<Backend>, ExpressionTemplates> number_type;
605 static number_type(min)() BOOST_NOEXCEPT { return (base_type::min)(); }
606 static number_type(max)() BOOST_NOEXCEPT { return (base_type::max)(); }
607 static number_type lowest() BOOST_NOEXCEPT { return -(max)(); }
608 static number_type epsilon() BOOST_NOEXCEPT { return base_type::epsilon(); }
609 static number_type round_error() BOOST_NOEXCEPT { return epsilon() / 2; }
610 static number_type infinity() BOOST_NOEXCEPT { return base_type::infinity(); }
611 static number_type quiet_NaN() BOOST_NOEXCEPT { return base_type::quiet_NaN(); }
612 static number_type signaling_NaN() BOOST_NOEXCEPT { return base_type::signaling_NaN(); }
613 static number_type denorm_min() BOOST_NOEXCEPT { return base_type::denorm_min(); }
623 template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy>
624 struct precision<boost::multiprecision::number<boost::multiprecision::logged_adaptor<Backend>, ExpressionTemplates>, Policy>
625 : public precision<boost::multiprecision::number<Backend, ExpressionTemplates>, Policy>
630 }} // namespace boost::math::policies
632 #undef NON_MEMBER_OP1
633 #undef NON_MEMBER_OP2
634 #undef NON_MEMBER_OP3
635 #undef NON_MEMBER_OP4