1 /*  This file is part of Jellyfish.
2 
3     Jellyfish is free software: you can redistribute it and/or modify
4     it under the terms of the GNU General Public License as published by
5     the Free Software Foundation, either version 3 of the License, or
6     (at your option) any later version.
7 
8     Jellyfish is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12 
13     You should have received a copy of the GNU General Public License
14     along with Jellyfish.  If not, see <http://www.gnu.org/licenses/>.
15 */
16 
17 #ifndef _INT128_H_
18 #define _INT128_H_
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #ifndef HAVE_INT128
23 #error "The type __int128 is not supported"
24 #endif
25 #endif
26 
27 #include <unistd.h>
28 #include <stdint.h>
29 #include <iostream>
30 #include <sstream>
31 #include <limits>
32 #include <cstring>
33 
34 // Output of __int128: this might be slow
35 namespace __int128_ns {
36 template<int base>
__print_digits(std::ostream & os,unsigned __int128 x,bool lower=true)37 void __print_digits(std::ostream& os, unsigned __int128 x,
38                     bool lower = true) {
39   char buf[50];
40   char* ptr = buf + sizeof(buf);
41   do {
42     int o  = x % base;
43     if(o < 10) {
44       *--ptr = '0' + o;
45     } else {
46       *--ptr = (lower ? 'a' : 'A') + o - 10;
47     }
48     x     /= base;
49   } while (x > 0);
50   os.write(ptr, buf + sizeof(buf) - ptr);
51 }
52 
is_negative(unsigned __int128 x)53 inline bool is_negative(unsigned __int128 x) { return false; }
is_negative(__int128 x)54 inline bool is_negative(__int128 x) { return x < 0; }
55 
56 template<typename T>
__print_decimal(std::ostream & prefix,std::ostream & os,T x,const std::ios::fmtflags & ff)57 void __print_decimal(std::ostream& prefix, std::ostream& os, T x,
58                      const std::ios::fmtflags& ff) {
59   if((ff & std::ios::showpos) && x > 0)
60     prefix << "+";
61   if(x == 0) {
62     os << "0";
63     return;
64   }
65   if(is_negative(x)) {
66     prefix << "-";
67     x = -x;
68   }
69   __print_digits<10>(os, x);
70 }
71 
72 void __print_bases(std::ostream& prefix, std::ostream& os,
73                    unsigned __int128 x,
74                    const std::ios::fmtflags& ff);
75 
76 template<typename T>
__print_buf(std::ostream & prefix,std::ostream & os,T x,const std::ios::fmtflags & ff)77 void __print_buf(std::ostream& prefix, std::ostream& os, T x,
78                  const std::ios::fmtflags& ff) {
79   if(ff & std::ios::dec)
80     __print_decimal(prefix, os, x, ff);
81   else
82     __print_bases(prefix, os, (unsigned __int128)x, ff);
83 }
84 
85 template<typename T>
__print(std::ostream & os,T x)86 void __print(std::ostream&os, T x) {
87   const std::ios_base::fmtflags ff = os.flags();
88 
89   if(!(ff & std::ios::adjustfield))
90     return __print_buf(os, os, x, ff);
91 
92   std::ostringstream prefix;
93   std::ostringstream buf;
94   __print_buf(prefix, buf, x, ff);
95   ssize_t nb_padding = os.width() - (prefix.str().size() + buf.str().size());
96   if(nb_padding <= 0) {
97     os.write(prefix.str().c_str(), prefix.tellp());
98     os.write(buf.str().c_str(), buf.tellp());
99     return;
100   }
101 
102   char padding[nb_padding];
103   memset(padding, os.fill(), nb_padding);
104   if(ff & std::ios::right)
105     os.write(padding, nb_padding);
106   os.write(prefix.str().c_str(), prefix.tellp());
107   if(ff & std::ios::internal)
108     os.write(padding, nb_padding);
109   os.write(buf.str().c_str(), buf.tellp());
110   if(ff & std::ios::left)
111     os.write(padding, nb_padding);
112 }
113 }
114 
115 inline
operator <<(std::ostream & os,__int128 x)116 std::ostream& operator<<(std::ostream& os, __int128 x) {
117   __int128_ns::__print(os, x);
118   return os;
119 }
120 
121 inline
operator <<(std::ostream & os,unsigned __int128 x)122 std::ostream& operator<<(std::ostream& os, unsigned __int128 x) {
123   __int128_ns::__print(os, x);
124   return os;
125 }
126 
127 #ifndef HAVE_NUMERIC_LIMITS128
128 namespace std {
129 template<>
130 class numeric_limits<__int128> {
131 public:
132   static const bool is_specialized = true;
max()133   static __int128 max() { return (unsigned __int128)-1 >> 1; }
min()134   static __int128 min() { return  max() + 1; }
135   static const int  digits     = 127;
136   static const int  digits10   = 38;
137 #define NLS64 numeric_limits<int64_t>
138   static const bool is_signed  = NLS64::is_signed;
139   static const bool is_integer = NLS64::is_integer;
140   static const bool is_exact   = NLS64::is_exact;
141   static const int  radix      = NLS64::radix;
epsilon()142   static __int128 epsilon() { return NLS64::epsilon(); }
round_error()143   static __int128 round_error() { return NLS64::round_error(); }
144   static const int                min_exponent      = NLS64::min_exponent;
145   static const int                min_exponent10    = NLS64::min_exponent10;
146   static const int                max_exponent      = NLS64::max_exponent;
147   static const int                max_exponent10    = NLS64::max_exponent10;
148   static const bool               has_infinity      = NLS64::has_infinity;
149   static const bool               has_quiet_NaN     = NLS64::has_quiet_NaN;
150   static const bool               has_signaling_NaN = NLS64::has_signaling_NaN;
151   static const float_denorm_style has_denorm        = NLS64::has_denorm;
152   static const bool               has_denorm_loss   = NLS64::has_denorm_loss;
infinity()153   static __int128 infinity() { return NLS64::infinity(); }
quiet_NaN()154   static __int128 quiet_NaN() { return NLS64::quiet_NaN(); }
signaling_NaN()155   static __int128 signaling_NaN() { return NLS64::signaling_NaN(); }
denorm_min()156   static __int128 denorm_min() { return NLS64::denorm_min(); }
157   static const bool              is_iec559       = NLS64::is_iec559;
158   static const bool              is_bounded      = NLS64::is_bounded;
159   static const bool              is_modulo       = NLS64::is_modulo;
160   static const bool              traps           = NLS64::traps;
161   static const bool              tinyness_before = NLS64::tinyness_before;
162   static const float_round_style round_style     = NLS64::round_style;
163 };
164 
165 template<>
166 class numeric_limits<unsigned __int128> {
167 public:
168   static const bool is_specialized = true;
max()169   static __int128 max() { return (unsigned __int128)-1; }
min()170   static __int128 min() { return  0; }
171   static const int  digits     = 128;
172   static const int  digits10   = 39;
173 #define NLU64 numeric_limits<uint64_t>
174   static const bool is_signed  = NLU64::is_signed;
175   static const bool is_integer = NLU64::is_integer;
176   static const bool is_exact   = NLU64::is_exact;
177   static const int  radix      = NLU64::radix;
epsilon()178   static __int128 epsilon() { return NLU64::epsilon(); }
round_error()179   static __int128 round_error() { return NLU64::round_error(); }
180   static const int                min_exponent      = NLU64::min_exponent;
181   static const int                min_exponent10    = NLU64::min_exponent10;
182   static const int                max_exponent      = NLU64::max_exponent;
183   static const int                max_exponent10    = NLU64::max_exponent10;
184   static const bool               has_infinity      = NLU64::has_infinity;
185   static const bool               has_quiet_NaN     = NLU64::has_quiet_NaN;
186   static const bool               has_signaling_NaN = NLU64::has_signaling_NaN;
187   static const float_denorm_style has_denorm        = NLU64::has_denorm;
188   static const bool               has_denorm_loss   = NLU64::has_denorm_loss;
infinity()189   static __int128 infinity() { return NLU64::infinity(); }
quiet_NaN()190   static __int128 quiet_NaN() { return NLU64::quiet_NaN(); }
signaling_NaN()191   static __int128 signaling_NaN() { return NLU64::signaling_NaN(); }
denorm_min()192   static __int128 denorm_min() { return NLU64::denorm_min(); }
193   static const bool              is_iec559       = NLU64::is_iec559;
194   static const bool              is_bounded      = NLU64::is_bounded;
195   static const bool              is_modulo       = NLU64::is_modulo;
196   static const bool              traps           = NLU64::traps;
197   static const bool              tinyness_before = NLU64::tinyness_before;
198   static const float_round_style round_style     = NLU64::round_style;
199 };
200 } // namespace std
201 #endif /* HAVE_NUMERIC_LIMITS128 */
202 
203 #endif /* _INT128_H_ */
204