1 // Written in the D programming language 2 /** 3 * Implements a signed 128 bit integer type. 4 * 5 Author: Walter Bright 6 Copyright: Copyright (c) 2022, D Language Foundation 7 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 Source: $(PHOBOSSRC std/int128.d) 9 */ 10 module std.int128; 11 12 private import core.int128; 13 14 15 /*********************************** 16 * 128 bit signed integer type. 17 */ 18 19 public struct Int128 20 { 21 @safe pure nothrow @nogc: 22 23 Cent data; /// core.int128.Cent 24 25 /**************** 26 * Construct an `Int128` from a `long` value. 27 * The upper 64 bits are formed by sign extension. 28 * Params: 29 * lo = signed lower 64 bits 30 */ 31 this(long lo) 32 { 33 data.lo = lo; 34 data.hi = lo < 0 ? ~0L : 0; 35 } 36 37 /**************** 38 * Construct an `Int128` from a `ulong` value. 39 * The upper 64 bits are set to zero. 40 * Params: 41 * lo = unsigned lower 64 bits 42 */ 43 this(ulong lo) 44 { 45 data.lo = lo; 46 data.hi = 0; 47 } 48 49 /**************** 50 * Construct an `Int128` from a `long` value. 51 * Params: 52 * hi = upper 64 bits 53 * lo = lower 64 bits 54 */ 55 this(long hi, long lo) 56 { 57 data.hi = hi; 58 data.lo = lo; 59 } 60 61 /******************** 62 * Construct an `Int128` from a `Cent`. 63 * Params: 64 * data = Cent data 65 */ 66 this(Cent data) 67 { 68 this.data = data; 69 } 70 71 /******************** 72 * Returns: hash value for Int128 73 */ 74 size_t toHash() const 75 { 76 return cast(size_t)((data.lo & 0xFFFF_FFFF) + (data.hi & 0xFFFF_FFFF) + (data.lo >> 32) + (data.hi >> 32)); 77 } 78 79 /************************ 80 * Compare for equality 81 * Params: lo = signed value to compare with 82 * Returns: true if Int128 equals value 83 */ 84 bool opEquals(long lo) const 85 { 86 return data.lo == lo && data.hi == (lo >> 63); 87 } 88 89 /************************ 90 * Compare for equality 91 * Params: lo = unsigned value to compare with 92 * Returns: true if Int128 equals value 93 */ 94 bool opEquals(ulong lo) const 95 { 96 return data.hi == 0 && data.lo == lo; 97 } 98 99 /************************ 100 * Compare for equality 101 * Params: op2 = value to compare with 102 * Returns: true if Int128 equals value 103 */ 104 bool opEquals(Int128 op2) const 105 { 106 return data.hi == op2.data.hi && data.lo == op2.data.lo; 107 } 108 109 /** Support unary arithmentic operator + 110 * Params: op = "+" 111 * Returns: lvalue of result 112 */ 113 Int128 opUnary(string op)() const 114 if (op == "+") 115 { 116 return this; 117 } 118 119 /** Support unary arithmentic operator - ~ 120 * Params: op = "-", "~" 121 * Returns: lvalue of result 122 */ 123 Int128 opUnary(string op)() const 124 if (op == "-" || op == "~") 125 { 126 static if (op == "-") 127 return Int128(neg(this.data)); 128 else static if (op == "~") 129 return Int128(com(this.data)); 130 } 131 132 /** Support unary arithmentic operator ++ -- 133 * Params: op = "++", "--" 134 * Returns: lvalue of result 135 */ 136 Int128 opUnary(string op)() 137 if (op == "++" || op == "--") 138 { 139 static if (op == "++") 140 this.data = inc(this.data); 141 else static if (op == "--") 142 this.data = dec(this.data); 143 else 144 static assert(0, op); 145 return this; 146 } 147 148 /** Support casting to a bool 149 * Params: T = bool 150 * Returns: boolean result 151 */ 152 bool opCast(T : bool)() const 153 { 154 return tst(this.data); 155 } 156 157 /** Support binary arithmetic operators + - * / % & | ^ << >> >>> 158 * Params: 159 * op = one of the arithmetic binary operators 160 * op2 = second operand 161 * Returns: value after the operation is applied 162 */ 163 Int128 opBinary(string op)(Int128 op2) const 164 if (op == "+" || op == "-" || 165 op == "*" || op == "/" || op == "%" || 166 op == "&" || op == "|" || op == "^") 167 { 168 static if (op == "+") 169 return Int128(add(this.data, op2.data)); 170 else static if (op == "-") 171 return Int128(sub(this.data, op2.data)); 172 else static if (op == "*") 173 return Int128(mul(this.data, op2.data)); 174 else static if (op == "/") 175 return Int128(div(this.data, op2.data)); 176 else static if (op == "%") 177 { 178 Cent modulus; 179 divmod(this.data, op2.data, modulus); 180 return Int128(modulus); 181 } 182 else static if (op == "&") 183 return Int128(and(this.data, op2.data)); 184 else static if (op == "|") 185 return Int128(or(this.data, op2.data)); 186 else static if (op == "^") 187 return Int128(xor(this.data, op2.data)); 188 else 189 static assert(0, "wrong op value"); 190 } 191 192 /// ditto 193 Int128 opBinary(string op)(long op2) const 194 if (op == "+" || op == "-" || 195 op == "*" || op == "/" || op == "%" || 196 op == "&" || op == "|" || op == "^") 197 { 198 return mixin("this " ~ op ~ " Int128(0, op2)"); 199 } 200 201 /// ditto 202 Int128 opBinaryRight(string op)(long op2) const 203 if (op == "+" || op == "-" || 204 op == "*" || op == "/" || op == "%" || 205 op == "&" || op == "|" || op == "^") 206 { 207 mixin("return Int128(0, op2) " ~ op ~ " this;"); 208 } 209 210 /// ditto 211 Int128 opBinary(string op)(long op2) const 212 if (op == "<<") 213 { 214 return Int128(shl(this.data, cast(uint) op2)); 215 } 216 217 /// ditto 218 Int128 opBinary(string op)(long op2) const 219 if (op == ">>") 220 { 221 return Int128(sar(this.data, cast(uint) op2)); 222 } 223 224 /// ditto 225 Int128 opBinary(string op)(long op2) const 226 if (op == ">>>") 227 { 228 return Int128(shr(this.data, cast(uint) op2)); 229 } 230 231 /** arithmetic assignment operators += -= *= /= %= &= |= ^= <<= >>= >>>= 232 * Params: op = one of +, -, etc. 233 * op2 = second operand 234 * Returns: lvalue of updated left operand 235 */ 236 ref Int128 opOpAssign(string op)(Int128 op2) 237 if (op == "+" || op == "-" || 238 op == "*" || op == "/" || op == "%" || 239 op == "&" || op == "|" || op == "^" || 240 op == "<<" || op == ">>" || op == ">>>") 241 { 242 mixin("this = this " ~ op ~ " op2;"); 243 return this; 244 } 245 246 /// ditto 247 ref Int128 opOpAssign(string op)(long op2) 248 if (op == "+" || op == "-" || 249 op == "*" || op == "/" || op == "%" || 250 op == "&" || op == "|" || op == "^" || 251 op == "<<" || op == ">>" || op == ">>>") 252 { 253 mixin("this = this " ~ op ~ " op2;"); 254 return this; 255 } 256 257 /** support signed arithmentic comparison operators < <= > >= 258 * Params: op2 = right hand operand 259 * Returns: -1 for less than, 0 for equals, 1 for greater than 260 */ 261 int opCmp(Int128 op2) const 262 { 263 return this == op2 ? 0 : gt(this.data, op2.data) * 2 - 1; 264 } 265 266 /** support signed arithmentic comparison operators < <= > >= 267 * Params: op2 = right hand operand 268 * Returns: -1 for less than, 0 for equals, 1 for greater than 269 */ 270 int opCmp(long op2) const 271 { 272 return opCmp(Int128(0, op2)); 273 } 274 275 enum min = Int128(long.min, 0); /// minimum value 276 enum max = Int128(long.max, ulong.max); /// maximum value 277 } 278 279 /********************************************* Tests ************************************/ 280 281 version (unittest) 282 { 283 import core.stdc.stdio; 284 285 @trusted void print(Int128 c) 286 { 287 printf("%lld, %lld\n", c.data.hi, c.data.lo); 288 } 289 290 @trusted void printx(Int128 c) 291 { 292 printf("%llx, %llx\n", c.data.hi, c.data.lo); 293 } 294 } 295 296 /// Int128 tests 297 @safe pure nothrow @nogc 298 unittest 299 { 300 Int128 c = Int128(5, 6); 301 assert(c == c); 302 assert(c == +c); 303 assert(c == - -c); 304 assert(~c == Int128(~5, ~6)); 305 ++c; 306 assert(c == Int128(5, 7)); 307 assert(--c == Int128(5, 6)); 308 assert(!!c); 309 assert(!Int128()); 310 311 assert(c + Int128(10, 20) == Int128(15, 26)); 312 assert(c - Int128(1, 2) == Int128(4, 4)); 313 assert(c * Int128(100, 2) == Int128(610, 12)); 314 assert(c / Int128(3, 2) == Int128(0, 1)); 315 assert(c % Int128(3, 2) == Int128(2, 4)); 316 assert((c & Int128(3, 2)) == Int128(1, 2)); 317 assert((c | Int128(3, 2)) == Int128(7, 6)); 318 assert((c ^ Int128(3, 2)) == Int128(6, 4)); 319 320 assert(c + 15 == Int128(5, 21)); 321 assert(c - 15 == Int128(4, -9)); 322 assert(c * 15 == Int128(75, 90)); 323 assert(c / 15 == Int128(0, 6148914691236517205)); 324 assert(c % 15 == Int128(0, 11)); 325 assert((c & 15) == Int128(0, 6)); 326 assert((c | 15) == Int128(5, 15)); 327 assert((c ^ 15) == Int128(5, 9)); 328 329 assert(15 + c == Int128(5, 21)); 330 assert(15 - c == Int128(-5, 9)); 331 assert(15 * c == Int128(75, 90)); 332 assert(15 / c == Int128(0, 0)); 333 assert(15 % c == Int128(0, 15)); 334 assert((15 & c) == Int128(0, 6)); 335 assert((15 | c) == Int128(5, 15)); 336 assert((15 ^ c) == Int128(5, 9)); 337 338 assert(c << 1 == Int128(10, 12)); 339 assert(-c >> 1 == Int128(-3, 9223372036854775805)); 340 assert(-c >>> 1 == Int128(9223372036854775805, 9223372036854775805)); 341 342 assert((c += 1) == Int128(5, 7)); 343 assert((c -= 1) == Int128(5, 6)); 344 assert((c += Int128(0, 1)) == Int128(5, 7)); 345 assert((c -= Int128(0, 1)) == Int128(5, 6)); 346 assert((c *= 2) == Int128(10, 12)); 347 assert((c /= 2) == Int128(5, 6)); 348 assert((c %= 2) == Int128()); 349 c += Int128(5, 6); 350 assert((c *= Int128(10, 20)) == Int128(160, 120)); 351 assert((c /= Int128(10, 20)) == Int128(0, 15)); 352 c += Int128(72, 0); 353 assert((c %= Int128(10, 20)) == Int128(1, -125)); 354 assert((c &= Int128(3, 20)) == Int128(1, 0)); 355 assert((c |= Int128(8, 2)) == Int128(9, 2)); 356 assert((c ^= Int128(8, 2)) == Int128(1, 0)); 357 c |= Int128(10, 5); 358 assert((c <<= 1) == Int128(11 * 2, 5 * 2)); 359 assert((c >>>= 1) == Int128(11, 5)); 360 c = Int128(long.min, long.min); 361 assert((c >>= 1) == Int128(long.min >> 1, cast(ulong) long.min >> 1)); 362 363 assert(-Int128.min == Int128.min); 364 assert(Int128.max + 1 == Int128.min); 365 366 c = Int128(5, 6); 367 assert(c < Int128(6, 5)); 368 assert(c > 10); 369 370 c = Int128(-1UL); 371 assert(c == -1UL); 372 c = Int128(-1L); 373 assert(c == -1L); 374 } 375