xmasked_value.hpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. /***************************************************************************
  2. * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and *
  3. * Martin Renou *
  4. * Copyright (c) QuantStack *
  5. * *
  6. * Distributed under the terms of the BSD 3-Clause License. *
  7. * *
  8. * The full license is in the file LICENSE, distributed with this software. *
  9. ****************************************************************************/
  10. #ifndef XTL_XMASKED_VALUE_HPP
  11. #define XTL_XMASKED_VALUE_HPP
  12. #include "xmasked_value_meta.hpp"
  13. #include "xtype_traits.hpp"
  14. namespace xtl
  15. {
  16. template <class T>
  17. inline xmasked_value<T, bool> masked() noexcept
  18. {
  19. return xmasked_value<T, bool>(T(0), false);
  20. }
  21. /****************************
  22. * xmasked_value declaration *
  23. *****************************/
  24. template <class T, class B>
  25. class xmasked_value
  26. {
  27. public:
  28. using self_type = xmasked_value<T, B>;
  29. using value_type = T;
  30. using flag_type = B;
  31. template <class T1, class B1>
  32. constexpr xmasked_value(T1&& value, B1&& flag);
  33. template <class T1>
  34. constexpr xmasked_value(T1&& value);
  35. explicit constexpr xmasked_value();
  36. inline operator value_type() {
  37. return m_value;
  38. }
  39. std::add_lvalue_reference_t<T> value() & noexcept;
  40. std::add_lvalue_reference_t<std::add_const_t<T>> value() const & noexcept;
  41. std::conditional_t<std::is_reference<T>::value, apply_cv_t<T, std::decay_t<T>>&, std::decay_t<T>> value() && noexcept;
  42. std::conditional_t<std::is_reference<T>::value, const std::decay_t<T>&, std::decay_t<T>> value() const && noexcept;
  43. std::add_lvalue_reference_t<B> visible() & noexcept;
  44. std::add_lvalue_reference_t<std::add_const_t<B>> visible() const & noexcept;
  45. std::conditional_t<std::is_reference<B>::value, apply_cv_t<B, std::decay_t<B>>&, std::decay_t<B>> visible() && noexcept;
  46. std::conditional_t<std::is_reference<B>::value, const std::decay_t<B>&, std::decay_t<B>> visible() const && noexcept;
  47. template <class T1, class B1>
  48. bool equal(const xmasked_value<T1, B1>& rhs) const noexcept;
  49. template <class T1, XTL_DISALLOW(is_xmasked_value<T1>)>
  50. bool equal(const T1& rhs) const noexcept;
  51. template <class T1, class B1>
  52. void swap(xmasked_value<T1, B1>& other);
  53. #define DEFINE_ASSIGN_OPERATOR(OP) \
  54. template <class T1> \
  55. inline xmasked_value& operator OP(const T1& rhs) \
  56. { \
  57. if (m_visible) \
  58. { \
  59. m_value OP rhs; \
  60. } \
  61. return *this; \
  62. } \
  63. \
  64. template <class T1, class B1> \
  65. inline xmasked_value& operator OP(const xmasked_value<T1, B1>& rhs) \
  66. { \
  67. m_visible = m_visible && rhs.visible(); \
  68. if (m_visible) \
  69. { \
  70. m_value OP rhs.value(); \
  71. } \
  72. return *this; \
  73. }
  74. DEFINE_ASSIGN_OPERATOR(=);
  75. DEFINE_ASSIGN_OPERATOR(+=);
  76. DEFINE_ASSIGN_OPERATOR(-=);
  77. DEFINE_ASSIGN_OPERATOR(*=);
  78. DEFINE_ASSIGN_OPERATOR(/=);
  79. DEFINE_ASSIGN_OPERATOR(%=);
  80. DEFINE_ASSIGN_OPERATOR(&=);
  81. DEFINE_ASSIGN_OPERATOR(|=);
  82. DEFINE_ASSIGN_OPERATOR(^=);
  83. #undef DEFINE_ASSIGN_OPERATOR
  84. private:
  85. value_type m_value;
  86. flag_type m_visible;
  87. };
  88. /********************************
  89. * xmasked_value implementation *
  90. ********************************/
  91. template <class T, class B>
  92. template <class T1, class B1>
  93. inline constexpr xmasked_value<T, B>::xmasked_value(T1&& value, B1&& flag)
  94. : m_value(std::forward<T1>(value)), m_visible(std::forward<B1>(flag))
  95. {
  96. }
  97. template <class T, class B>
  98. template <class T1>
  99. inline constexpr xmasked_value<T, B>::xmasked_value(T1&& value)
  100. : m_value(std::forward<T1>(value)), m_visible(true)
  101. {
  102. }
  103. template <class T, class B>
  104. inline constexpr xmasked_value<T, B>::xmasked_value()
  105. : m_value(0), m_visible(true)
  106. {
  107. }
  108. template <class T>
  109. inline auto masked_value(T&& val)
  110. {
  111. return xmasked_value<T>(std::forward<T>(val));
  112. }
  113. template <class T, class B>
  114. inline auto masked_value(T&& val, B&& mask)
  115. {
  116. return xmasked_value<T, B>(std::forward<T>(val), std::forward<B>(mask));
  117. }
  118. template <class T, class B>
  119. inline auto xmasked_value<T, B>::value() & noexcept -> std::add_lvalue_reference_t<T>
  120. {
  121. return m_value;
  122. }
  123. template <class T, class B>
  124. inline auto xmasked_value<T, B>::value() const & noexcept -> std::add_lvalue_reference_t<std::add_const_t<T>>
  125. {
  126. return m_value;
  127. }
  128. template <class T, class B>
  129. inline auto xmasked_value<T, B>::value() && noexcept -> std::conditional_t<std::is_reference<T>::value, apply_cv_t<T, std::decay_t<T>>&, std::decay_t<T>>
  130. {
  131. return m_value;
  132. }
  133. template <class T, class B>
  134. inline auto xmasked_value<T, B>::value() const && noexcept -> std::conditional_t<std::is_reference<T>::value, const std::decay_t<T>&, std::decay_t<T>>
  135. {
  136. return m_value;
  137. }
  138. template <class T, class B>
  139. inline auto xmasked_value<T, B>::visible() & noexcept -> std::add_lvalue_reference_t<B>
  140. {
  141. return m_visible;
  142. }
  143. template <class T, class B>
  144. inline auto xmasked_value<T, B>::visible() const & noexcept -> std::add_lvalue_reference_t<std::add_const_t<B>>
  145. {
  146. return m_visible;
  147. }
  148. template <class T, class B>
  149. inline auto xmasked_value<T, B>::visible() && noexcept -> std::conditional_t<std::is_reference<B>::value, apply_cv_t<B, std::decay_t<B>>&, std::decay_t<B>>
  150. {
  151. return m_visible;
  152. }
  153. template <class T, class B>
  154. inline auto xmasked_value<T, B>::visible() const && noexcept -> std::conditional_t<std::is_reference<B>::value, const std::decay_t<B>&, std::decay_t<B>>
  155. {
  156. return m_visible;
  157. }
  158. template <class T, class B>
  159. template <class T1, class B1>
  160. inline bool xmasked_value<T, B>::equal(const xmasked_value<T1, B1>& rhs) const noexcept
  161. {
  162. return (!m_visible && !rhs.visible()) || (m_value == rhs.value() && (m_visible && rhs.visible()));
  163. }
  164. template <class T, class B>
  165. template <class T1, check_disallow<is_xmasked_value<T1>>>
  166. inline bool xmasked_value<T, B>::equal(const T1& rhs) const noexcept
  167. {
  168. return m_visible && m_value == rhs;
  169. }
  170. template <class T, class B>
  171. template <class T1, class B1>
  172. inline void xmasked_value<T, B>::swap(xmasked_value<T1, B1>& other)
  173. {
  174. using std::swap;
  175. swap(m_value, other.m_value);
  176. swap(m_visible, other.m_visible);
  177. }
  178. template <class T1, class B1, class T2, class B2>
  179. inline bool operator==(const xmasked_value<T1, B1>& lhs, const xmasked_value<T2, B2>& rhs) noexcept
  180. {
  181. return lhs.equal(rhs);
  182. }
  183. template <class T1, class T2, class B2, XTL_REQUIRES(negation<is_xmasked_value<T1>>)>
  184. inline bool operator==(const T1& lhs, const xmasked_value<T2, B2>& rhs) noexcept
  185. {
  186. return rhs.equal(lhs);
  187. }
  188. template <class T1, class B1, class T2, XTL_REQUIRES(negation<is_xmasked_value<T2>>)>
  189. inline bool operator==(const xmasked_value<T1, B1>& lhs, const T2& rhs) noexcept
  190. {
  191. return lhs.equal(rhs);
  192. }
  193. template <class T1, class B1, class T2, class B2>
  194. inline bool operator!=(const xmasked_value<T1, B1>& lhs, const xmasked_value<T2, B2>& rhs) noexcept
  195. {
  196. return !lhs.equal(rhs);
  197. }
  198. template <class T1, class T2, class B2, XTL_REQUIRES(negation<is_xmasked_value<T1>>)>
  199. inline bool operator!=(const T1& lhs, const xmasked_value<T2, B2>& rhs) noexcept
  200. {
  201. return !rhs.equal(lhs);
  202. }
  203. template <class T1, class B1, class T2, XTL_REQUIRES(negation<is_xmasked_value<T2>>)>
  204. inline bool operator!=(const xmasked_value<T1, B1>& lhs, const T2& rhs) noexcept
  205. {
  206. return !lhs.equal(rhs);
  207. }
  208. template <class T, class B>
  209. inline auto operator+(const xmasked_value<T, B>& e) noexcept
  210. -> xmasked_value<std::decay_t<T>, std::decay_t<B>>
  211. {
  212. return xmasked_value<std::decay_t<T>, std::decay_t<B>>(e.value(), e.visible());
  213. }
  214. template <class T, class B>
  215. inline auto operator-(const xmasked_value<T, B>& e) noexcept
  216. -> xmasked_value<std::decay_t<T>, std::decay_t<B>>
  217. {
  218. return xmasked_value<std::decay_t<T>, std::decay_t<B>>(-e.value(), e.visible());
  219. }
  220. template <class T, class B>
  221. inline auto operator~(const xmasked_value<T, B>& e) noexcept
  222. -> xmasked_value<std::decay_t<T>>
  223. {
  224. using value_type = std::decay_t<T>;
  225. return e.visible() ? masked_value(~e.value()) : masked<value_type>();
  226. }
  227. template <class T, class B>
  228. inline auto operator!(const xmasked_value<T, B>& e) noexcept -> xmasked_value<decltype(!e.value())>
  229. {
  230. using return_type = xmasked_value<decltype(!e.value())>;
  231. using value_type = typename return_type::value_type;
  232. return e.visible() ? return_type(!e.value()) : masked<value_type>();
  233. }
  234. template <class T, class B, class OC, class OT>
  235. inline std::basic_ostream<OC, OT>& operator<<(std::basic_ostream<OC, OT>& out, xmasked_value<T, B> v)
  236. {
  237. if (v.visible())
  238. {
  239. out << v.value();
  240. }
  241. else
  242. {
  243. out << "masked";
  244. }
  245. return out;
  246. }
  247. template <class T1, class B1, class T2, class B2>
  248. inline void swap(xmasked_value<T1, B1>& lhs, xmasked_value<T2, B2>& rhs)
  249. {
  250. lhs.swap(rhs);
  251. }
  252. #define DEFINE_OPERATOR(OP) \
  253. template <class T1, class B1, class T2, class B2> \
  254. inline auto operator OP(const xmasked_value<T1, B1>& e1, const xmasked_value<T2, B2>& e2) noexcept \
  255. -> xmasked_value<promote_type_t<std::decay_t<T1>, std::decay_t<T2>>> \
  256. { \
  257. using value_type = promote_type_t<std::decay_t<T1>, std::decay_t<T2>>; \
  258. return e1.visible() && e2.visible() ? masked_value(e1.value() OP e2.value()) : masked<value_type>(); \
  259. } \
  260. \
  261. template <class T1, class B1, class T2, XTL_REQUIRES(negation<is_xmasked_value<T2>>)> \
  262. inline auto operator OP(const xmasked_value<T1, B1>& e1, const T2& e2) noexcept \
  263. -> xmasked_value<promote_type_t<std::decay_t<T1>, std::decay_t<T2>>> \
  264. { \
  265. using value_type = promote_type_t<std::decay_t<T1>, std::decay_t<T2>>; \
  266. return e1.visible() ? masked_value(e1.value() OP e2) : masked<value_type>(); \
  267. } \
  268. \
  269. template <class T1, class T2, class B2, XTL_REQUIRES(negation<is_xmasked_value<T1>>)> \
  270. inline auto operator OP(const T1& e1, const xmasked_value<T2, B2>& e2) noexcept \
  271. -> xmasked_value<promote_type_t<std::decay_t<T1>, std::decay_t<T2>>> \
  272. { \
  273. using value_type = promote_type_t<std::decay_t<T1>, std::decay_t<T2>>; \
  274. return e2.visible() ? masked_value(e1 OP e2.value()) : masked<value_type>(); \
  275. }
  276. #define DEFINE_BOOL_OPERATOR(OP) \
  277. template <class T1, class B1, class T2, class B2> \
  278. inline auto operator OP(const xmasked_value<T1, B1>& e1, const xmasked_value<T2, B2>& e2) noexcept \
  279. -> xmasked_value<decltype(e1.value() OP e2.value())> \
  280. { \
  281. return e1.visible() && e2.visible() ? \
  282. masked_value(e1.value() OP e2.value()) : \
  283. masked<decltype(e1.value() OP e2.value())>(); \
  284. } \
  285. \
  286. template <class T1, class B1, class T2, XTL_REQUIRES(negation<is_xmasked_value<T2>>)> \
  287. inline auto operator OP(const xmasked_value<T1, B1>& e1, const T2& e2) noexcept \
  288. -> xmasked_value<decltype(e1.value() OP e2)> \
  289. { \
  290. return e1.visible() ? masked_value(e1.value() OP e2) : masked<decltype(e1.value() OP e2)>(); \
  291. } \
  292. \
  293. template <class T1, class T2, class B2, XTL_REQUIRES(negation<is_xmasked_value<T1>>)> \
  294. inline auto operator OP(const T1& e1, const xmasked_value<T2, B2>& e2) noexcept \
  295. -> xmasked_value<decltype(e1 OP e2.value())> \
  296. { \
  297. return e2.visible() ? masked_value(e1 OP e2.value()) : masked<decltype(e1 OP e2.value())>(); \
  298. }
  299. #define DEFINE_UNARY_OPERATOR(OP) \
  300. template <class T, class B> \
  301. inline xmasked_value<std::decay_t<T>> OP(const xmasked_value<T, B>& e) \
  302. { \
  303. using std::OP; \
  304. return e.visible() ? masked_value(OP(e.value())) : masked<std::decay_t<T>>(); \
  305. }
  306. #define DEFINE_UNARY_BOOL_OPERATOR(OP) \
  307. template <class T, class B> \
  308. inline auto OP(const xmasked_value<T, B>& e) \
  309. { \
  310. using std::OP; \
  311. return e.visible() ? masked_value(OP(e.value())) : masked<decltype(OP(e.value()))>(); \
  312. }
  313. #define DEFINE_BINARY_OPERATOR(OP) \
  314. template <class T1, class B1, class T2, class B2> \
  315. inline auto OP(const xmasked_value<T1, B1>& e1, const xmasked_value<T2, B2>& e2) \
  316. { \
  317. using std::OP; \
  318. return e1.visible() && e2.visible() ? \
  319. masked_value(OP(e1.value(), e2.value())) : \
  320. masked<decltype(OP(e1.value(), e2.value()))>(); \
  321. } \
  322. \
  323. template <class T1, class B1, class T2> \
  324. inline auto OP(const xmasked_value<T1, B1>& e1, const T2& e2) \
  325. { \
  326. using std::OP; \
  327. return e1.visible() ? masked_value(OP(e1.value(), e2)) : masked<decltype(OP(e1.value(), e2))>(); \
  328. } \
  329. \
  330. template <class T1, class T2, class B2> \
  331. inline auto OP(const T1& e1, const xmasked_value<T2, B2>& e2) \
  332. { \
  333. using std::OP; \
  334. return e2.visible() ? masked_value(OP(e1, e2.value())) : masked<decltype(OP(e1, e2.value()))>(); \
  335. }
  336. #define DEFINE_TERNARY_OPERATOR_MMM(OP) \
  337. template <class T1, class B1, class T2, class B2, class T3, class B3> \
  338. inline auto OP(const xmasked_value<T1, B1>& e1, const xmasked_value<T2, B2>& e2, const xmasked_value<T3, B3>& e3) \
  339. { \
  340. using std::OP; \
  341. return (e1.visible() && e2.visible() && e3.visible()) ? \
  342. masked_value(OP(e1.value(), e2.value(), e3.value())) : \
  343. masked<decltype(OP(e1.value(), e2.value(), e3.value()))>(); \
  344. }
  345. #define DEFINE_TERNARY_OPERATOR_MMT(OP) \
  346. template <class T1, class B1, class T2, class B2, class T3> \
  347. inline auto OP(const xmasked_value<T1, B1>& e1, const xmasked_value<T2, B2>& e2, const T3& e3) \
  348. { \
  349. using std::OP; \
  350. return (e1.visible() && e2.visible()) ? \
  351. masked_value(OP(e1.value(), e2.value(), e3)) : \
  352. masked<decltype(OP(e1.value(), e2.value(), e3))>(); \
  353. }
  354. #define DEFINE_TERNARY_OPERATOR_MTM(OP) \
  355. template <class T1, class B1, class T2, class T3, class B3> \
  356. inline auto OP(const xmasked_value<T1, B1>& e1, const T2& e2, const xmasked_value<T3, B3>& e3) \
  357. { \
  358. using std::OP; \
  359. return (e1.visible() && e3.visible()) ? \
  360. masked_value(OP(e1.value(), e2, e3.value())) : \
  361. masked<decltype(OP(e1.value(), e2, e3.value()))>(); \
  362. }
  363. #define DEFINE_TERNARY_OPERATOR_TMM(OP) \
  364. template <class T1, class T2, class B2, class T3, class B3> \
  365. inline auto OP(const T1& e1, const xmasked_value<T2, B2>& e2, const xmasked_value<T3, B3>& e3) \
  366. { \
  367. using std::OP; \
  368. return (e2.visible() && e3.visible()) ? \
  369. masked_value(OP(e1, e2.value(), e3.value())) : \
  370. masked<decltype(OP(e1, e2.value(), e3.value()))>(); \
  371. }
  372. #define DEFINE_TERNARY_OPERATOR_TTM(OP) \
  373. template <class T1, class T2, class T3, class B3> \
  374. inline auto OP(const T1& e1, const T2& e2, const xmasked_value<T3, B3>& e3) \
  375. { \
  376. using std::OP; \
  377. return e3.visible() ? \
  378. masked_value(OP(e1, e2, e3.value())) : \
  379. masked<decltype(OP(e1, e2, e3.value()))>(); \
  380. }
  381. #define DEFINE_TERNARY_OPERATOR_TMT(OP) \
  382. template <class T1, class T2, class B2, class T3> \
  383. inline auto OP(const T1& e1, const xmasked_value<T2, B2>& e2, const T3& e3) \
  384. { \
  385. using std::OP; \
  386. return e2.visible() ? \
  387. masked_value(OP(e1, e2.value(), e3)) : \
  388. masked<decltype(OP(e1, e2.value(), e3))>(); \
  389. }
  390. #define DEFINE_TERNARY_OPERATOR_MTT(OP) \
  391. template <class T1, class B1, class T2, class T3> \
  392. inline auto OP(const xmasked_value<T1, B1>& e1, const T2& e2, const T3& e3) \
  393. { \
  394. using std::OP; \
  395. return e1.visible() ? \
  396. masked_value(OP(e1.value(), e2, e3)) : \
  397. masked<decltype(OP(e1.value(), e2, e3))>(); \
  398. }
  399. #define DEFINE_TERNARY_OPERATOR(OP) \
  400. DEFINE_TERNARY_OPERATOR_MMM(OP) \
  401. \
  402. DEFINE_TERNARY_OPERATOR_MMT(OP) \
  403. DEFINE_TERNARY_OPERATOR_MTM(OP) \
  404. DEFINE_TERNARY_OPERATOR_TMM(OP) \
  405. DEFINE_TERNARY_OPERATOR_TTM(OP) \
  406. DEFINE_TERNARY_OPERATOR_TMT(OP) \
  407. DEFINE_TERNARY_OPERATOR_MTT(OP)
  408. DEFINE_OPERATOR(+);
  409. DEFINE_OPERATOR(-);
  410. DEFINE_OPERATOR(*);
  411. DEFINE_OPERATOR(/);
  412. DEFINE_OPERATOR(%);
  413. DEFINE_BOOL_OPERATOR(||);
  414. DEFINE_BOOL_OPERATOR(&&);
  415. DEFINE_OPERATOR(&);
  416. DEFINE_OPERATOR(|);
  417. DEFINE_OPERATOR(^);
  418. DEFINE_BOOL_OPERATOR(<);
  419. DEFINE_BOOL_OPERATOR(<=);
  420. DEFINE_BOOL_OPERATOR(>);
  421. DEFINE_BOOL_OPERATOR(>=);
  422. DEFINE_UNARY_OPERATOR(abs)
  423. DEFINE_UNARY_OPERATOR(fabs)
  424. DEFINE_UNARY_OPERATOR(exp)
  425. DEFINE_UNARY_OPERATOR(exp2)
  426. DEFINE_UNARY_OPERATOR(expm1)
  427. DEFINE_UNARY_OPERATOR(log)
  428. DEFINE_UNARY_OPERATOR(log10)
  429. DEFINE_UNARY_OPERATOR(log2)
  430. DEFINE_UNARY_OPERATOR(log1p)
  431. DEFINE_UNARY_OPERATOR(sqrt)
  432. DEFINE_UNARY_OPERATOR(cbrt)
  433. DEFINE_UNARY_OPERATOR(sin)
  434. DEFINE_UNARY_OPERATOR(cos)
  435. DEFINE_UNARY_OPERATOR(tan)
  436. DEFINE_UNARY_OPERATOR(acos)
  437. DEFINE_UNARY_OPERATOR(asin)
  438. DEFINE_UNARY_OPERATOR(atan)
  439. DEFINE_UNARY_OPERATOR(sinh)
  440. DEFINE_UNARY_OPERATOR(cosh)
  441. DEFINE_UNARY_OPERATOR(tanh)
  442. DEFINE_UNARY_OPERATOR(acosh)
  443. DEFINE_UNARY_OPERATOR(asinh)
  444. DEFINE_UNARY_OPERATOR(atanh)
  445. DEFINE_UNARY_OPERATOR(erf)
  446. DEFINE_UNARY_OPERATOR(erfc)
  447. DEFINE_UNARY_OPERATOR(tgamma)
  448. DEFINE_UNARY_OPERATOR(lgamma)
  449. DEFINE_UNARY_OPERATOR(ceil)
  450. DEFINE_UNARY_OPERATOR(floor)
  451. DEFINE_UNARY_OPERATOR(trunc)
  452. DEFINE_UNARY_OPERATOR(round)
  453. DEFINE_UNARY_OPERATOR(nearbyint)
  454. DEFINE_UNARY_OPERATOR(rint)
  455. DEFINE_UNARY_BOOL_OPERATOR(isfinite)
  456. DEFINE_UNARY_BOOL_OPERATOR(isinf)
  457. DEFINE_UNARY_BOOL_OPERATOR(isnan)
  458. DEFINE_BINARY_OPERATOR(fmod)
  459. DEFINE_BINARY_OPERATOR(remainder)
  460. DEFINE_BINARY_OPERATOR(fmax)
  461. DEFINE_BINARY_OPERATOR(fmin)
  462. DEFINE_BINARY_OPERATOR(fdim)
  463. DEFINE_BINARY_OPERATOR(pow)
  464. DEFINE_BINARY_OPERATOR(hypot)
  465. DEFINE_BINARY_OPERATOR(atan2)
  466. DEFINE_TERNARY_OPERATOR(fma)
  467. #undef DEFINE_TERNARY_OPERATOR
  468. #undef DEFINE_TERNARY_OPERATOR_MMM
  469. #undef DEFINE_TERNARY_OPERATOR_MMT
  470. #undef DEFINE_TERNARY_OPERATOR_MTM
  471. #undef DEFINE_TERNARY_OPERATOR_TMM
  472. #undef DEFINE_TERNARY_OPERATOR_TTM
  473. #undef DEFINE_TERNARY_OPERATOR_TMT
  474. #undef DEFINE_TERNARY_OPERATOR_MTT
  475. #undef DEFINE_BINARY_OPERATOR
  476. #undef DEFINE_UNARY_OPERATOR
  477. #undef DEFINE_UNARY_BOOL_OPERATOR
  478. #undef DEFINE_OPERATOR
  479. #undef DEFINE_BOOL_OPERATOR
  480. }
  481. #endif