1 /// Arbitrary size integer implementation (must be 0<x<=64) 2 module tern.integer; 3 4 import tern.meta : isSame; 5 import std.conv; 6 import std.traits; 7 8 /// Represents the shorthand for an integer 9 public alias utri = UInt!24; 10 /// ditto 11 public alias tri = Int!24; 12 /// ditto 13 public alias upent = UInt!40; 14 /// ditto 15 public alias pent = Int!40; 16 /// ditto 17 public alias usex = UInt!48; 18 /// ditto 19 public alias sex = Int!48; 20 /// ditto 21 public alias uhept = UInt!56; 22 /// ditto 23 public alias hept = Int!56; 24 25 /// Represents the shorthand for a non-promoting integer 26 public alias npubyte = UInt!8; 27 /// ditto 28 public alias npbyte = Int!8; 29 /// ditto 30 public alias npushort = UInt!16; 31 /// ditto 32 public alias npshort = Int!16; 33 /// ditto 34 public alias nputri = UInt!24; 35 /// ditto 36 public alias nptri = Int!24; 37 /// ditto 38 public alias npuint = UInt!32; 39 /// ditto 40 public alias npint = Int!32; 41 /// ditto 42 public alias npupent = UInt!40; 43 /// ditto 44 public alias nppent = Int!40; 45 /// ditto 46 public alias npusex = UInt!48; 47 /// ditto 48 public alias npsex = Int!48; 49 /// ditto 50 public alias npuhept = UInt!56; 51 /// ditto 52 public alias nphept = Int!56; 53 /// ditto 54 public alias npulong = UInt!64; 55 /// ditto 56 public alias nplong = Int!64; 57 58 /// Represents an arbitrary unsigned integer of `SIZE`. 59 public struct UInt(size_t SIZE) 60 if (SIZE <= 64 && SIZE >= 8 && SIZE % 8 == 0) 61 { 62 private: 63 final: 64 enum size = SIZE / 8; 65 ubyte[size] data; 66 67 public: 68 enum max = 2 ^^ cast(ulong)SIZE - 1; 69 enum min = 0; 70 71 string toString() const 72 { 73 return (cast(ulong)this).to!string; 74 } 75 76 @nogc: 77 this(T)(T val) 78 if (isIntegral!T) 79 { 80 this = val; 81 } 82 83 T opCast(T)() const 84 { 85 ubyte[T.sizeof] data; 86 static if (T.sizeof < size) 87 data[0..T.sizeof] = this.data[0..T.sizeof]; 88 else 89 data[0..size] = this.data[0..size]; 90 return *cast(T*)&data; 91 } 92 93 auto opAssign(A)(A ahs) 94 { 95 ulong val = cast(ulong)ahs; 96 data[0..size] = (cast(ubyte*)&val)[0..size]; 97 return this; 98 } 99 100 auto opBinary(string op, R)(const R rhs) const 101 { 102 return mixin("UInt!SIZE(cast(ulong)this "~op~" cast(ulong)rhs)"); 103 } 104 105 auto opBinaryRight(string op, L)(const L lhs) const 106 { 107 return mixin("UInt!SIZE(cast(ulong)rhs "~op~" cast(ulong)this)"); 108 } 109 110 auto opUnary(string op)() 111 { 112 return mixin("UInt!SIZE("~op~"cast(ulong)this)"); 113 } 114 115 auto opOpAssign(string op, A)(A ahs) 116 { 117 this = mixin("cast(A)this "~op~" cast(ulong)ahs"); 118 return this; 119 } 120 121 bool opEquals(A)(const A ahs) const 122 { 123 static if (!isSame!(Unqual!A, Unqual!(typeof(this)))) 124 return cast(A)this == ahs; 125 else 126 { 127 static if (isSigned!A) 128 return cast(long)this == ahs; 129 else 130 return cast(ulong)this == ahs; 131 } 132 } 133 134 int opCmp(A)(const A ahs) const 135 { 136 return cast(int)(cast(A)this - ahs); 137 } 138 } 139 140 /// Represents an arbitrary signed integer of `SIZE`. 141 public struct Int(size_t SIZE) 142 if (SIZE <= 64 && SIZE >= 8 && SIZE % 8 == 0) 143 { 144 private: 145 final: 146 enum size = SIZE / 8; 147 ubyte[size] data; 148 149 public: 150 enum max = 2UL ^^ (cast(ulong)SIZE - 1) - 1; 151 enum min = -(2L ^^ (cast(long)SIZE - 1) - 1); 152 153 string toString() const 154 { 155 return (cast(long)this).to!string; 156 } 157 158 @nogc: 159 this(T)(T val) 160 if (isIntegral!T) 161 { 162 this = val; 163 } 164 165 T opCast(T)() const 166 { 167 ubyte[T.sizeof] data; 168 static if (T.sizeof < size) 169 data[0..T.sizeof] = this.data[0..T.sizeof]; 170 else 171 data[0..size] = this.data[0..size]; 172 173 static if (isSigned!T) 174 { 175 if (this.data[$-1] & 128) 176 return cast(T)(-(2L ^^ cast(long)SIZE - (*cast(T*)&data))); 177 } 178 static if (T.sizeof == size) 179 data[$-1] &= ~128; 180 return *cast(T*)&data; 181 } 182 183 auto opAssign(A)(A ahs) 184 { 185 long val = cast(long)ahs; 186 data[0..size] = (cast(ubyte*)&val)[0..size]; 187 data[$-1] >>= 1; 188 static if (isSigned!A) 189 if (val < 0) 190 data[$-1] |= 128; 191 return this; 192 } 193 194 auto opBinary(string op, R)(const R rhs) const 195 { 196 return mixin("Int!SIZE(cast(ulong)this "~op~" cast(ulong)rhs)"); 197 } 198 199 auto opBinaryRight(string op, L)(const L lhs) const 200 { 201 return mixin("Int!SIZE(cast(ulong)rhs "~op~" cast(ulong)this)"); 202 } 203 204 auto opUnary(string op)() 205 { 206 return mixin("Int!SIZE("~op~"cast(long)this)"); 207 } 208 209 auto opOpAssign(string op, A)(A ahs) 210 { 211 this = mixin("cast(A)this "~op~" ahs"); 212 return this; 213 } 214 215 bool opEquals(A)(const A ahs) const 216 { 217 static if (!isSame!(Unqual!A, Unqual!(typeof(this)))) 218 return cast(A)this == ahs; 219 else 220 { 221 static if (isSigned!A) 222 return cast(long)this == ahs; 223 else 224 return cast(ulong)this == ahs; 225 } 226 } 227 228 int opCmp(A)(const A ahs) const 229 { 230 return cast(int)(cast(A)this - ahs); 231 } 232 }