CORSIKA  @c8_version@
The framework to simulate particle cascades for astroparticle physics
uint128.hpp
1 /*
2  * (c) Copyright 2021 CORSIKA Project, corsika-project@lists.kit.edu
3  *
4  * This software is distributed under the terms of the GNU General Public
5  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
6  * the license.
7  */
8 
9 /*
10  * uint128_t.hpp
11  *
12  * Created on: 13/03/2021
13  * Author: Antonio Augusto Alves Junior
14  */
15 
16 #pragma once
17 
18 #include <cstdint>
19 #include <ostream>
20 #include <stdexcept>
21 #include <string>
22 #include <type_traits>
23 #include <utility>
24 #include <vector>
25 
26 #include "Macros.h"
27 
28 namespace random_iterator {
29 
30  class uint128_t;
31 }
32 
33 namespace std { // This is probably not a good idea
34  template <>
35  struct is_arithmetic<random_iterator::uint128_t> : std::true_type {};
36  template <>
37  struct is_integral<random_iterator::uint128_t> : std::true_type {};
38  template <>
39  struct is_unsigned<random_iterator::uint128_t> : std::true_type {};
40 } // namespace std
41 
42 namespace random_iterator {
43 
44  // Give uint128_t type traits
45 
46  class uint128_t {
47 
48  public:
49  // Constructors
50  uint128_t() = default;
51 
52  uint128_t(uint128_t const& rhs) = default;
53 
54  uint128_t(uint128_t&& rhs) = default;
55 
56  uint128_t(std::string& s);
57 
58  uint128_t(const char* s);
59 
60  template <typename T,
61  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
62  uint128_t(const T& rhs)
63 #ifdef __BIG_ENDIAN__
64  : UPPER(0)
65  , LOWER(rhs)
66 #endif
67 #ifdef __LITTLE_ENDIAN__
68  : LOWER(rhs)
69  , UPPER(0)
70 #endif
71  {
72  if (std::is_signed<T>::value) {
73  if (rhs < T(0)) { UPPER = -1; }
74  }
75  }
76 
77  template <typename S, typename T,
78  typename = typename std::enable_if<
79  std::is_integral<S>::value && std::is_integral<T>::value, void>::type>
80  uint128_t(const S& upper_rhs, const T& lower_rhs)
81 #ifdef __BIG_ENDIAN__
82  : UPPER(upper_rhs)
83  , LOWER(lower_rhs)
84 #endif
85 #ifdef __LITTLE_ENDIAN__
86  : LOWER(lower_rhs)
87  , UPPER(upper_rhs)
88 #endif
89  {
90  }
91 
92  // RHS input args only
93 
94  // Assignment Operator
95  inline uint128_t& operator=(const uint128_t& rhs) = default;
96 
97  inline uint128_t& operator=(uint128_t&& rhs) = default;
98 
99  template <typename T,
100  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
101  inline uint128_t& operator=(const T& rhs) {
102  UPPER = 0;
103 
104  if (std::is_signed<T>::value) {
105  if (rhs < T(0)) { UPPER = -1; }
106  }
107 
108  LOWER = rhs;
109  return *this;
110  }
111 
112  // Typecast Operators
113  inline operator bool() const;
114  inline operator uint8_t() const;
115  inline operator uint16_t() const;
116  inline operator uint32_t() const;
117  inline operator uint64_t() const;
118 
119  // Bitwise Operators
120  inline uint128_t operator&(const uint128_t& rhs) const;
121 
122  // inline void export_bits(std::vector<uint8_t> & ret) const;
123 
124  template <typename T,
125  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
126  inline uint128_t operator&(const T& rhs) const {
127  return uint128_t(0, LOWER & (uint64_t)rhs);
128  }
129 
130  inline uint128_t& operator&=(const uint128_t& rhs);
131 
132  template <typename T,
133  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
134  inline uint128_t& operator&=(const T& rhs) {
135  UPPER = 0;
136  LOWER &= rhs;
137  return *this;
138  }
139 
140  inline uint128_t operator|(const uint128_t& rhs) const;
141 
142  template <typename T,
143  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
144  inline uint128_t operator|(const T& rhs) const {
145  return uint128_t(UPPER, LOWER | (uint64_t)rhs);
146  }
147 
148  inline uint128_t& operator|=(const uint128_t& rhs);
149 
150  template <typename T,
151  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
152  inline uint128_t& operator|=(const T& rhs) {
153  LOWER |= (uint64_t)rhs;
154  return *this;
155  }
156 
157  inline uint128_t operator^(const uint128_t& rhs) const;
158 
159  template <typename T,
160  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
161  inline uint128_t operator^(const T& rhs) const {
162  return uint128_t(UPPER, LOWER ^ (uint64_t)rhs);
163  }
164 
165  inline uint128_t& operator^=(const uint128_t& rhs);
166 
167  template <typename T,
168  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
169  inline uint128_t& operator^=(const T& rhs) {
170  LOWER ^= (uint64_t)rhs;
171  return *this;
172  }
173 
174  inline uint128_t operator~() const;
175 
176  // Bit Shift Operators
177  inline uint128_t operator<<(const uint128_t& rhs) const;
178 
179  template <typename T,
180  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
181  inline uint128_t operator<<(const T& rhs) const {
182  return *this << uint128_t(rhs);
183  }
184 
185  inline uint128_t& operator<<=(const uint128_t& rhs);
186 
187  template <typename T,
188  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
189  inline uint128_t& operator<<=(const T& rhs) {
190  *this = *this << uint128_t(rhs);
191  return *this;
192  }
193 
194  inline uint128_t operator>>(const uint128_t& rhs) const;
195 
196  template <typename T,
197  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
198  inline uint128_t operator>>(const T& rhs) const {
199  return *this >> uint128_t(rhs);
200  }
201 
202  inline uint128_t& operator>>=(const uint128_t& rhs);
203 
204  template <typename T,
205  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
206  inline uint128_t& operator>>=(const T& rhs) {
207  *this = *this >> uint128_t(rhs);
208  return *this;
209  }
210 
211  // Logical Operators
212  inline bool operator!() const;
213  inline bool operator&&(const uint128_t& rhs) const;
214  inline bool operator||(const uint128_t& rhs) const;
215 
216  template <typename T,
217  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
218  inline bool operator&&(const T& rhs) const {
219  return static_cast<bool>(*this && rhs);
220  }
221 
222  template <typename T,
223  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
224  inline bool operator||(const T& rhs) const {
225  return static_cast<bool>(*this || rhs);
226  }
227 
228  // Comparison Operators
229  inline bool operator==(const uint128_t& rhs) const;
230 
231  template <typename T,
232  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
233  inline bool operator==(const T& rhs) const {
234  return (!UPPER && (LOWER == (uint64_t)rhs));
235  }
236 
237  inline bool operator!=(const uint128_t& rhs) const;
238 
239  template <typename T,
240  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
241  inline bool operator!=(const T& rhs) const {
242  return (UPPER | (LOWER != (uint64_t)rhs));
243  }
244 
245  inline bool operator>(const uint128_t& rhs) const;
246 
247  template <typename T,
248  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
249  inline bool operator>(const T& rhs) const {
250  return (UPPER || (LOWER > (uint64_t)rhs));
251  }
252 
253  inline bool operator<(const uint128_t& rhs) const;
254 
255  template <typename T,
256  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
257  inline bool operator<(const T& rhs) const {
258  return (!UPPER) ? (LOWER < (uint64_t)rhs) : false;
259  }
260 
261  inline bool operator>=(const uint128_t& rhs) const;
262 
263  template <typename T,
264  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
265  inline bool operator>=(const T& rhs) const {
266  return ((*this > rhs) | (*this == rhs));
267  }
268 
269  inline bool operator<=(const uint128_t& rhs) const;
270 
271  template <typename T,
272  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
273  inline bool operator<=(const T& rhs) const {
274  return ((*this < rhs) | (*this == rhs));
275  }
276 
277  // Arithmetic Operators
278  inline uint128_t operator+(const uint128_t& rhs) const;
279 
280  template <typename T,
281  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
282  inline uint128_t operator+(const T& rhs) const {
283  return uint128_t(UPPER + ((LOWER + (uint64_t)rhs) < LOWER), LOWER + (uint64_t)rhs);
284  }
285 
286  inline uint128_t& operator+=(const uint128_t& rhs);
287 
288  template <typename T,
289  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
290  inline uint128_t& operator+=(const T& rhs) {
291  return *this += uint128_t(rhs);
292  }
293 
294  inline uint128_t operator-(const uint128_t& rhs) const;
295 
296  template <typename T,
297  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
298  inline uint128_t operator-(const T& rhs) const {
299  return uint128_t((uint64_t)(UPPER - ((LOWER - rhs) > LOWER)),
300  (uint64_t)(LOWER - rhs));
301  }
302 
303  inline uint128_t& operator-=(const uint128_t& rhs);
304 
305  template <typename T,
306  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
307  inline uint128_t& operator-=(const T& rhs) {
308  return *this = *this - uint128_t(rhs);
309  }
310 
311  inline uint128_t operator*(const uint128_t& rhs) const;
312 
313  template <typename T,
314  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
315  inline uint128_t operator*(const T& rhs) const {
316  return *this * uint128_t(rhs);
317  }
318 
319  inline uint128_t& operator*=(const uint128_t& rhs);
320 
321  template <typename T,
322  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
323  inline uint128_t& operator*=(const T& rhs) {
324  return *this = *this * uint128_t(rhs);
325  }
326 
327  inline uint128_t operator/(const uint128_t& rhs) const;
328 
329  template <typename T,
330  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
331  inline uint128_t operator/(const T& rhs) const {
332  return *this / uint128_t(rhs);
333  }
334 
335  inline uint128_t& operator/=(const uint128_t& rhs);
336 
337  template <typename T,
338  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
339  inline uint128_t& operator/=(const T& rhs) {
340  return *this = *this / uint128_t(rhs);
341  }
342 
343  inline uint128_t operator%(const uint128_t& rhs) const;
344 
345  template <typename T,
346  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
347  inline uint128_t operator%(const T& rhs) const {
348  return *this % uint128_t(rhs);
349  }
350 
351  inline uint128_t& operator%=(const uint128_t& rhs);
352 
353  template <typename T,
354  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
355  inline uint128_t& operator%=(const T& rhs) {
356  return *this = *this % uint128_t(rhs);
357  }
358 
359  // Increment Operator
360  inline uint128_t& operator++();
361  inline uint128_t operator++(int);
362 
363  // Decrement Operator
364  inline uint128_t& operator--();
365  inline uint128_t operator--(int);
366 
367  // Nothing done since promotion doesn't work here
368  inline uint128_t operator+() const;
369 
370  // two's complement
371  inline uint128_t operator-() const;
372 
373  // Get private values
374  inline uint64_t upper() const;
375  inline uint64_t lower() const;
376 
377  // Get bitsize of value
378  inline uint8_t bits() const;
379 
380  // rotate right 64
381  inline uint128_t rotate_right() const;
382 
383  // Get string representation of value
384  inline std::string str(uint8_t base = 10, const unsigned int& len = 0) const;
385 
386  private:
387  std::pair<uint128_t, uint128_t> divmod(const uint128_t& lhs,
388  const uint128_t& rhs) const;
389  void init(const char* s);
390  void _init_hex(const char* s);
391  void _init_dec(const char* s);
392  void _init_oct(const char* s);
393 
394 #if defined(__powerpc64__) || defined(__x86_64__)
395  static inline uint128_t mul128(uint128_t const x, uint128_t const y) {
396  uint128_t z;
397 #ifdef __powerpc64__
398  asm("mulhdu %3\n\t" : "=a"(z.LOWER), "=d"(z.UPPER) : "%0"(x.LOWER), "rm"(y.LOWER));
399 #else
400  asm("mulq %3\n\t" : "=a"(z.LOWER), "=d"(z.UPPER) : "%0"(x.LOWER), "rm"(y.LOWER));
401 #endif
402  z.UPPER += (x.UPPER * y.LOWER) + (x.LOWER * y.UPPER);
403  return z;
404  }
405 #endif
406 
407 #ifdef __BIG_ENDIAN__
408  uint64_t UPPER, LOWER;
409 #endif
410 #ifdef __LITTLE_ENDIAN__
411  uint64_t LOWER, UPPER;
412 #endif
413  };
414 
415  // lhs type T as first arguemnt
416  // If the output is not a bool, casts to type T
417 
418  // Bitwise Operators
419  template <typename T,
420  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
421  inline uint128_t operator&(const T& lhs, const uint128_t& rhs) {
422  return rhs & lhs;
423  }
424 
425  template <typename T,
426  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
427  inline T& operator&=(T& lhs, const uint128_t& rhs) {
428  return lhs = static_cast<T>(rhs & lhs);
429  }
430 
431  template <typename T,
432  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
433  inline uint128_t operator|(const T& lhs, const uint128_t& rhs) {
434  return rhs | lhs;
435  }
436 
437  template <typename T,
438  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
439  inline T& operator|=(T& lhs, const uint128_t& rhs) {
440  return lhs = static_cast<T>(rhs | lhs);
441  }
442 
443  template <typename T,
444  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
445  inline uint128_t operator^(const T& lhs, const uint128_t& rhs) {
446  return rhs ^ lhs;
447  }
448 
449  template <typename T,
450  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
451  inline T& operator^=(T& lhs, const uint128_t& rhs) {
452  return lhs = static_cast<T>(rhs ^ lhs);
453  }
454 
455  // Bitshift operators
456  inline uint128_t operator<<(const bool& lhs, const uint128_t& rhs);
457  inline uint128_t operator<<(const uint8_t& lhs, const uint128_t& rhs);
458  inline uint128_t operator<<(const uint16_t& lhs, const uint128_t& rhs);
459  inline uint128_t operator<<(const uint32_t& lhs, const uint128_t& rhs);
460  inline uint128_t operator<<(const uint64_t& lhs, const uint128_t& rhs);
461  inline uint128_t operator<<(const int8_t& lhs, const uint128_t& rhs);
462  inline uint128_t operator<<(const int16_t& lhs, const uint128_t& rhs);
463  inline uint128_t operator<<(const int32_t& lhs, const uint128_t& rhs);
464  inline uint128_t operator<<(const int64_t& lhs, const uint128_t& rhs);
465 
466  template <typename T,
467  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
468  inline T& operator<<=(T& lhs, const uint128_t& rhs) {
469  return lhs = static_cast<T>(uint128_t(lhs) << rhs);
470  }
471 
472  inline uint128_t operator>>(const bool& lhs, const uint128_t& rhs);
473  inline uint128_t operator>>(const uint8_t& lhs, const uint128_t& rhs);
474  inline uint128_t operator>>(const uint16_t& lhs, const uint128_t& rhs);
475  inline uint128_t operator>>(const uint32_t& lhs, const uint128_t& rhs);
476  inline uint128_t operator>>(const uint64_t& lhs, const uint128_t& rhs);
477  inline uint128_t operator>>(const int8_t& lhs, const uint128_t& rhs);
478  inline uint128_t operator>>(const int16_t& lhs, const uint128_t& rhs);
479  inline uint128_t operator>>(const int32_t& lhs, const uint128_t& rhs);
480  inline uint128_t operator>>(const int64_t& lhs, const uint128_t& rhs);
481 
482  template <typename T,
483  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
484  inline T& operator>>=(T& lhs, const uint128_t& rhs) {
485  return lhs = static_cast<T>(uint128_t(lhs) >> rhs);
486  }
487 
488  // Comparison Operators
489  template <typename T,
490  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
491  inline bool operator==(const T& lhs, const uint128_t& rhs) {
492  return (!rhs.upper() && ((uint64_t)lhs == rhs.lower()));
493  }
494 
495  template <typename T,
496  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
497  inline bool operator!=(const T& lhs, const uint128_t& rhs) {
498  return (rhs.upper() | ((uint64_t)lhs != rhs.lower()));
499  }
500 
501  template <typename T,
502  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
503  inline bool operator>(const T& lhs, const uint128_t& rhs) {
504  return (!rhs.upper()) && ((uint64_t)lhs > rhs.lower());
505  }
506 
507  template <typename T,
508  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
509  inline bool operator<(const T& lhs, const uint128_t& rhs) {
510  if (rhs.upper()) { return true; }
511  return ((uint64_t)lhs < rhs.lower());
512  }
513 
514  template <typename T,
515  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
516  inline bool operator>=(const T& lhs, const uint128_t& rhs) {
517  if (rhs.upper()) { return false; }
518  return ((uint64_t)lhs >= rhs.lower());
519  }
520 
521  template <typename T,
522  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
523  inline bool operator<=(const T& lhs, const uint128_t& rhs) {
524  if (rhs.upper()) { return true; }
525  return ((uint64_t)lhs <= rhs.lower());
526  }
527 
528  // Arithmetic Operators
529  template <typename T,
530  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
531  inline uint128_t operator+(const T& lhs, const uint128_t& rhs) {
532  return rhs + lhs;
533  }
534 
535  template <typename T,
536  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
537  inline T& operator+=(T& lhs, const uint128_t& rhs) {
538  return lhs = static_cast<T>(rhs + lhs);
539  }
540 
541  template <typename T,
542  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
543  inline uint128_t operator-(const T& lhs, const uint128_t& rhs) {
544  return -(rhs - lhs);
545  }
546 
547  template <typename T,
548  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
549  inline T& operator-=(T& lhs, const uint128_t& rhs) {
550  return lhs = static_cast<T>(-(rhs - lhs));
551  }
552 
553  template <typename T,
554  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
555  inline uint128_t operator*(const T& lhs, const uint128_t& rhs) {
556  return rhs * lhs;
557  }
558 
559  template <typename T,
560  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
561  inline T& operator*=(T& lhs, const uint128_t& rhs) {
562  return lhs = static_cast<T>(rhs * lhs);
563  }
564 
565  template <typename T,
566  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
567  inline uint128_t operator/(const T& lhs, const uint128_t& rhs) {
568  return uint128_t(lhs) / rhs;
569  }
570 
571  template <typename T,
572  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
573  inline T& operator/=(T& lhs, const uint128_t& rhs) {
574  return lhs = static_cast<T>(uint128_t(lhs) / rhs);
575  }
576 
577  template <typename T,
578  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
579  inline uint128_t operator%(const T& lhs, const uint128_t& rhs) {
580  return uint128_t(lhs) % rhs;
581  }
582 
583  template <typename T,
584  typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
585  inline T& operator%=(T& lhs, const uint128_t& rhs) {
586  return lhs = static_cast<T>(uint128_t(lhs) % rhs);
587  }
588 
589  // IO Operator
590  inline std::ostream& operator<<(std::ostream& stream, const uint128_t& rhs);
591 
592 } // namespace random_iterator
593 
594 #include "uint128.inl"
constexpr bool operator<(quantity< D, X > const &x, quantity< D, Y > const &y)
less-than.
Definition: quantity.hpp:714
constexpr quantity< D, X > operator-(quantity< D, X > const &x)
Definition: quantity.hpp:552
constexpr quantity< D, detail::PromoteMul< X, Y > > operator*(quantity< D, X > const &x, const Y &y)
quan * num
Definition: quantity.hpp:576
constexpr quantity< D, detail::PromoteMul< X, Y > > operator/(quantity< D, X > const &x, const Y &y)
quan / num
Definition: quantity.hpp:609
constexpr bool operator>=(quantity< D, X > const &x, quantity< D, Y > const &y)
greater-equal.
Definition: quantity.hpp:735
STL namespace.
constexpr bool operator<=(quantity< D, X > const &x, quantity< D, Y > const &y)
less-equal.
Definition: quantity.hpp:721
constexpr quantity< D, X > operator+(quantity< D, X > const &x)
Definition: quantity.hpp:528
std::ostream & operator<<(std::ostream &, corsika::Code)
Code output operator.
constexpr bool operator!=(quantity< D, X > const &x, quantity< D, Y > const &y)
inequality.
Definition: quantity.hpp:707
constexpr quantity< D, X > & operator-=(quantity< D, X > &x, quantity< D, Y > const &y)
quan -= quan
Definition: quantity.hpp:545
constexpr quantity< D, X > & operator*=(quantity< D, X > &x, const Y &y)
quan *= num
Definition: quantity.hpp:569
constexpr quantity< D, X > & operator+=(quantity< D, X > &x, quantity< D, Y > const &y)
quan += quan
Definition: quantity.hpp:521
constexpr bool operator>(quantity< D, X > const &x, quantity< D, Y > const &y)
greater-than.
Definition: quantity.hpp:728
constexpr quantity< D, X > & operator/=(quantity< D, X > &x, const Y &y)
quan /= num
Definition: quantity.hpp:602