You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

462 lines
17KB

  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2019-present
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. #ifndef RANGES_V3_ITERATOR_DIFFMAX_T_HPP
  14. #define RANGES_V3_ITERATOR_DIFFMAX_T_HPP
  15. #include <cstdint>
  16. #include <iosfwd>
  17. #include <limits>
  18. #include <concepts/concepts.hpp>
  19. #include <range/v3/range_fwd.hpp>
  20. #include <range/v3/iterator/concepts.hpp>
  21. RANGES_DIAGNOSTIC_PUSH
  22. RANGES_DIAGNOSTIC_IGNORE_UNSIGNED_MATH
  23. namespace ranges
  24. {
  25. /// \cond
  26. namespace detail
  27. {
  28. struct diffmax_t
  29. {
  30. private:
  31. bool neg_;
  32. std::uintmax_t val_;
  33. struct tag
  34. {};
  35. constexpr diffmax_t(tag, bool neg, std::uintmax_t val)
  36. : neg_(val && neg)
  37. , val_(val)
  38. {}
  39. /// \cond
  40. constexpr void _check()
  41. {
  42. RANGES_ENSURE(!neg_ || val_);
  43. }
  44. static constexpr diffmax_t _normalize(bool neg, std::uintmax_t val)
  45. {
  46. return diffmax_t{tag{}, val && neg, val};
  47. }
  48. /// \endcond
  49. public:
  50. diffmax_t() = default;
  51. template<typename T>
  52. constexpr CPP_ctor(diffmax_t)(T val)(noexcept(true) //
  53. requires integral<T>)
  54. : neg_(0 > val)
  55. , val_(0 > val ? static_cast<std::uintmax_t>(-val)
  56. : static_cast<std::uintmax_t>(val))
  57. {}
  58. constexpr friend bool operator<(diffmax_t a, diffmax_t b) noexcept
  59. {
  60. a._check();
  61. b._check();
  62. return a.neg_ ? (b.neg_ ? a.val_ > b.val_ : true)
  63. : (b.neg_ ? false : a.val_ < b.val_);
  64. }
  65. constexpr friend bool operator>(diffmax_t a, diffmax_t b) noexcept
  66. {
  67. return b < a;
  68. }
  69. constexpr friend bool operator<=(diffmax_t a, diffmax_t b) noexcept
  70. {
  71. return !(b < a);
  72. }
  73. constexpr friend bool operator>=(diffmax_t a, diffmax_t b) noexcept
  74. {
  75. return !(a < b);
  76. }
  77. constexpr friend bool operator==(diffmax_t a, diffmax_t b) noexcept
  78. {
  79. a._check();
  80. b._check();
  81. return a.val_ == b.val_ && a.neg_ == b.neg_;
  82. }
  83. constexpr friend bool operator!=(diffmax_t a, diffmax_t b) noexcept
  84. {
  85. return !(a == b);
  86. }
  87. constexpr friend diffmax_t operator+(diffmax_t a) noexcept
  88. {
  89. return a;
  90. }
  91. constexpr friend diffmax_t operator-(diffmax_t a) noexcept
  92. {
  93. return _normalize(!a.neg_, a.val_);
  94. }
  95. constexpr friend diffmax_t operator+(diffmax_t a, diffmax_t b) noexcept
  96. {
  97. return a.neg_ == b.neg_
  98. ? diffmax_t{tag{}, a.neg_, a.val_ + b.val_}
  99. : (a.neg_ ? (a.val_ > b.val_
  100. ? diffmax_t{tag{}, true, a.val_ - b.val_}
  101. : diffmax_t{tag{}, false, b.val_ - a.val_})
  102. : (b.val_ > a.val_
  103. ? diffmax_t{tag{}, true, b.val_ - a.val_}
  104. : diffmax_t{tag{}, false, a.val_ - b.val_}));
  105. }
  106. constexpr friend diffmax_t operator-(diffmax_t a, diffmax_t b) noexcept
  107. {
  108. return a + -b;
  109. }
  110. constexpr friend diffmax_t operator*(diffmax_t a, diffmax_t b) noexcept
  111. {
  112. return _normalize(a.neg_ ^ b.neg_, a.val_ * b.val_);
  113. }
  114. constexpr friend diffmax_t operator/(diffmax_t a, diffmax_t b) noexcept
  115. {
  116. return _normalize(a.neg_ ^ b.neg_, a.val_ / b.val_);
  117. }
  118. constexpr friend diffmax_t operator%(diffmax_t a, diffmax_t b) noexcept
  119. {
  120. return _normalize(a.neg_, a.val_ % b.val_);
  121. }
  122. static constexpr std::uintmax_t compl_if(bool neg,
  123. std::uintmax_t val) noexcept
  124. {
  125. return neg ? ~val + 1 : val;
  126. }
  127. constexpr friend diffmax_t operator&(diffmax_t a, diffmax_t b) noexcept
  128. {
  129. return _normalize(
  130. a.neg_ && b.neg_,
  131. compl_if(a.neg_ && b.neg_,
  132. compl_if(a.neg_, a.val_) & compl_if(b.neg_, b.val_)));
  133. }
  134. constexpr friend diffmax_t operator|(diffmax_t a, diffmax_t b) noexcept
  135. {
  136. return _normalize(
  137. a.neg_ || b.neg_,
  138. compl_if(a.neg_ || b.neg_,
  139. compl_if(a.neg_, a.val_) | compl_if(b.neg_, b.val_)));
  140. }
  141. constexpr friend diffmax_t operator^(diffmax_t a, diffmax_t b) noexcept
  142. {
  143. return _normalize(
  144. bool(a.neg_ ^ b.neg_),
  145. compl_if(bool(a.neg_ ^ b.neg_),
  146. compl_if(a.neg_, a.val_) ^ compl_if(b.neg_, b.val_)));
  147. }
  148. constexpr friend diffmax_t operator<<(diffmax_t a, diffmax_t b) noexcept
  149. {
  150. RANGES_ENSURE(!a.neg_);
  151. return b.neg_ ? diffmax_t{tag{}, false, a.val_ >> b.val_}
  152. : diffmax_t{tag{}, false, a.val_ << b.val_};
  153. }
  154. constexpr friend diffmax_t operator>>(diffmax_t a, diffmax_t b) noexcept
  155. {
  156. return b.neg_ ? diffmax_t{tag{}, a.neg_, a.val_ << b.val_}
  157. : diffmax_t{tag{}, a.neg_, a.val_ >> b.val_};
  158. }
  159. constexpr friend diffmax_t & operator+=(diffmax_t & a, diffmax_t b) noexcept
  160. {
  161. return (a = a + b);
  162. }
  163. constexpr friend diffmax_t & operator-=(diffmax_t & a, diffmax_t b) noexcept
  164. {
  165. return (a = a - b);
  166. }
  167. constexpr friend diffmax_t & operator*=(diffmax_t & a, diffmax_t b) noexcept
  168. {
  169. return (a = a * b);
  170. }
  171. constexpr friend diffmax_t & operator/=(diffmax_t & a, diffmax_t b) noexcept
  172. {
  173. return (a = a / b);
  174. }
  175. constexpr friend diffmax_t & operator%=(diffmax_t & a, diffmax_t b) noexcept
  176. {
  177. return (a = a % b);
  178. }
  179. constexpr friend diffmax_t & operator&=(diffmax_t & a, diffmax_t b) noexcept
  180. {
  181. return (a = a & b);
  182. }
  183. constexpr friend diffmax_t & operator|=(diffmax_t & a, diffmax_t b) noexcept
  184. {
  185. return (a = a | b);
  186. }
  187. constexpr friend diffmax_t & operator^=(diffmax_t & a, diffmax_t b) noexcept
  188. {
  189. return (a = a ^ b);
  190. }
  191. constexpr friend diffmax_t & operator<<=(diffmax_t & a, diffmax_t b) noexcept
  192. {
  193. a = (a << b);
  194. return a;
  195. }
  196. constexpr friend diffmax_t & operator>>=(diffmax_t & a, diffmax_t b) noexcept
  197. {
  198. a = (a >> b);
  199. return a;
  200. }
  201. template<typename T>
  202. constexpr friend auto operator+=(T & a, diffmax_t b) noexcept
  203. -> CPP_broken_friend_ret(T &)( //
  204. requires integral<T>)
  205. {
  206. return (a = static_cast<T>(diffmax_t{a} + b));
  207. }
  208. template<typename T>
  209. constexpr friend auto operator-=(T & a, diffmax_t b) noexcept
  210. -> CPP_broken_friend_ret(T &)( //
  211. requires integral<T>)
  212. {
  213. return (a = static_cast<T>(diffmax_t{a} - b));
  214. }
  215. template<typename T>
  216. constexpr friend auto operator*=(T & a, diffmax_t b) noexcept
  217. -> CPP_broken_friend_ret(T &)( //
  218. requires integral<T>)
  219. {
  220. return (a = static_cast<T>(diffmax_t{a} * b));
  221. }
  222. template<typename T>
  223. constexpr friend auto operator/=(T & a, diffmax_t b) noexcept
  224. -> CPP_broken_friend_ret(T &)( //
  225. requires integral<T>)
  226. {
  227. return (a = static_cast<T>(diffmax_t{a} / b));
  228. }
  229. template<typename T>
  230. constexpr friend auto operator%=(T & a, diffmax_t b) noexcept
  231. -> CPP_broken_friend_ret(T &)( //
  232. requires integral<T>)
  233. {
  234. return (a = static_cast<T>(diffmax_t{a} % b));
  235. }
  236. template<typename T>
  237. constexpr friend auto operator&=(T & a, diffmax_t b) noexcept
  238. -> CPP_broken_friend_ret(T &)( //
  239. requires integral<T>)
  240. {
  241. return (a = static_cast<T>(diffmax_t{a} & b));
  242. }
  243. template<typename T>
  244. constexpr friend auto operator|=(T & a, diffmax_t b) noexcept
  245. -> CPP_broken_friend_ret(T &)( //
  246. requires integral<T>)
  247. {
  248. return (a = static_cast<T>(diffmax_t{a} | b));
  249. }
  250. template<typename T>
  251. constexpr friend auto operator^=(T & a, diffmax_t b) noexcept
  252. -> CPP_broken_friend_ret(T &)( //
  253. requires integral<T>)
  254. {
  255. return (a = static_cast<T>(diffmax_t{a} ^ b));
  256. }
  257. template<typename T>
  258. constexpr friend auto operator<<=(T & a, diffmax_t b) noexcept
  259. -> CPP_broken_friend_ret(T &)( //
  260. requires integral<T>)
  261. {
  262. a = static_cast<T>(diffmax_t{a} << b);
  263. return a;
  264. }
  265. template<typename T>
  266. constexpr friend auto operator>>=(T & a, diffmax_t b) noexcept
  267. -> CPP_broken_friend_ret(T &)( //
  268. requires integral<T>)
  269. {
  270. a = static_cast<T>(diffmax_t{a} >> b);
  271. return a;
  272. }
  273. constexpr friend diffmax_t & operator++(diffmax_t & a) noexcept
  274. {
  275. a.neg_ = (a.neg_ ? --a.val_ : ++a.val_) && a.neg_;
  276. return a;
  277. }
  278. constexpr friend diffmax_t & operator--(diffmax_t & a) noexcept
  279. {
  280. a.neg_ = (a.neg_ ? ++a.val_ : --a.val_) && a.neg_;
  281. return a;
  282. }
  283. constexpr friend diffmax_t operator++(diffmax_t & a, int) noexcept
  284. {
  285. auto tmp = a;
  286. ++a;
  287. return tmp;
  288. }
  289. constexpr friend diffmax_t operator--(diffmax_t & a, int) noexcept
  290. {
  291. auto tmp = a;
  292. --a;
  293. return tmp;
  294. }
  295. CPP_template(typename T)( //
  296. requires integral<T>) //
  297. explicit constexpr
  298. operator T() const noexcept
  299. {
  300. return neg_ ? -static_cast<T>(val_) : static_cast<T>(val_);
  301. }
  302. explicit constexpr operator bool() const noexcept
  303. {
  304. return val_ != 0;
  305. }
  306. constexpr bool operator!() const noexcept
  307. {
  308. return val_ == 0;
  309. }
  310. template<typename Ostream>
  311. friend auto operator<<(Ostream & sout, diffmax_t a)
  312. -> CPP_broken_friend_ret(std::ostream &)( //
  313. requires derived_from<
  314. Ostream, std::basic_ostream<typename Ostream::char_type,
  315. typename Ostream::traits_type>>)
  316. {
  317. return sout << (&"-"[!a.neg_]) << a.val_;
  318. }
  319. };
  320. template<>
  321. RANGES_INLINE_VAR constexpr bool _is_integer_like_<diffmax_t> = true;
  322. } // namespace detail
  323. /// \endcond
  324. } // namespace ranges
  325. /// \cond
  326. RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
  327. namespace std
  328. {
  329. template<>
  330. struct numeric_limits<::ranges::detail::diffmax_t>
  331. {
  332. static constexpr bool is_specialized = true;
  333. static constexpr bool is_signed = true;
  334. static constexpr bool is_integer = true;
  335. static constexpr bool is_exact = true;
  336. static constexpr bool has_infinity = false;
  337. static constexpr bool has_quiet_NaN = false;
  338. static constexpr bool has_signaling_NaN = false;
  339. static constexpr bool has_denorm = false;
  340. static constexpr bool has_denorm_loss = false;
  341. static constexpr std::float_round_style round_style = std::round_toward_zero;
  342. static constexpr bool is_iec559 = false;
  343. static constexpr bool is_bounded = true;
  344. static constexpr bool is_modulo = false;
  345. static constexpr int digits = CHAR_BIT * sizeof(std::uintmax_t) + 1;
  346. static constexpr int digits10 =
  347. static_cast<int>(digits * 0.301029996); // digits * std::log10(2)
  348. static constexpr int max_digits10 = 0;
  349. static constexpr int radix = 2;
  350. static constexpr int min_exponent = 0;
  351. static constexpr int min_exponent10 = 0;
  352. static constexpr int max_exponent = 0;
  353. static constexpr int max_exponent10 = 0;
  354. static constexpr bool traps = true;
  355. static constexpr bool tinyness_before = false;
  356. static constexpr ::ranges::detail::diffmax_t max() noexcept
  357. {
  358. return std::uintmax_t(-1);
  359. }
  360. static constexpr ::ranges::detail::diffmax_t min() noexcept
  361. {
  362. return -max();
  363. }
  364. static constexpr ::ranges::detail::diffmax_t lowest() noexcept
  365. {
  366. return min();
  367. }
  368. static constexpr ::ranges::detail::diffmax_t epsilon() noexcept
  369. {
  370. return 0;
  371. }
  372. static constexpr ::ranges::detail::diffmax_t round_error() noexcept
  373. {
  374. return 0;
  375. }
  376. static constexpr ::ranges::detail::diffmax_t infinity() noexcept
  377. {
  378. return 0;
  379. }
  380. static constexpr ::ranges::detail::diffmax_t quiet_NaN() noexcept
  381. {
  382. return 0;
  383. }
  384. static constexpr ::ranges::detail::diffmax_t signaling_NaN() noexcept
  385. {
  386. return 0;
  387. }
  388. static constexpr ::ranges::detail::diffmax_t denorm_min() noexcept
  389. {
  390. return 0;
  391. }
  392. };
  393. template<>
  394. struct numeric_limits<::ranges::detail::diffmax_t const>
  395. : numeric_limits<::ranges::detail::diffmax_t>
  396. {};
  397. template<>
  398. struct numeric_limits<::ranges::detail::diffmax_t volatile>
  399. : numeric_limits<::ranges::detail::diffmax_t>
  400. {};
  401. template<>
  402. struct numeric_limits<::ranges::detail::diffmax_t const volatile>
  403. : numeric_limits<::ranges::detail::diffmax_t>
  404. {};
  405. #if RANGES_CXX_INLINE_VARIABLES >= RANGES_CXX_INLINE_VARIABLES_17
  406. inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_specialized;
  407. inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_signed;
  408. inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_integer;
  409. inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_exact;
  410. inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::has_infinity;
  411. inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::has_quiet_NaN;
  412. inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::has_signaling_NaN;
  413. inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::has_denorm;
  414. inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::has_denorm_loss;
  415. inline constexpr std::float_round_style
  416. numeric_limits<::ranges::detail::diffmax_t>::round_style;
  417. inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_iec559;
  418. inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_bounded;
  419. inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_modulo;
  420. inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::digits;
  421. inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::digits10;
  422. inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::max_digits10;
  423. inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::radix;
  424. inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::min_exponent;
  425. inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::min_exponent10;
  426. inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::max_exponent;
  427. inline constexpr int numeric_limits<::ranges::detail::diffmax_t>::max_exponent10;
  428. inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::traps;
  429. inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::tinyness_before;
  430. #endif
  431. } // namespace std
  432. RANGES_DIAGNOSTIC_POP
  433. /// \endcond
  434. #endif