authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-16 01:50:59+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-16 11:32:05+02:00
log1e09157b53441d06cd1f49b9c3917a58ee244cb1
treebee7820a937e242eca9a014d51406b73f699de0f
parentf6bf24b2f3e1d65ce66625c4466aa2af9edff41c

big ints: Fix set(signed int minimum) panic


2 files changed, 20 insertions(+), 29 deletions(-)

lib/std/math/big/int.zig+13-29
......@@ -18,18 +18,12 @@ const debug_safety = false;
1818/// Returns the number of limbs needed to store `scalar`, which must be a
1919/// primitive integer value.
2020pub fn calcLimbLen(scalar: anytype) usize {
21 const T = @TypeOf(scalar);
22 switch (@typeInfo(T)) {
23 .Int => |info| {
24 const UT = if (info.signedness == .signed) std.meta.Int(.unsigned, info.bits - 1) else T;
25 return @sizeOf(UT) / @sizeOf(Limb);
26 },
27 .ComptimeInt => {
28 const w_value = if (scalar < 0) -scalar else scalar;
29 return @divFloor(math.log2(w_value), limb_bits) + 1;
30 },
31 else => @compileError("parameter must be a primitive integer type"),
21 if (scalar == 0) {
22 return 1;
3223 }
24
25 const w_value = std.math.absCast(scalar);
26 return @divFloor(@intCast(Limb, math.log2(w_value)), limb_bits) + 1;
3327}
3428
3529pub fn calcToStringLimbsBufferLen(a_len: usize, base: u8) usize {
......@@ -218,26 +212,22 @@ pub const Mutable = struct {
218212 /// needs to be to store a specific value.
219213 pub fn set(self: *Mutable, value: anytype) void {
220214 const T = @TypeOf(value);
215 const needed_limbs = calcLimbLen(value);
216 assert(needed_limbs <= self.limbs.len); // value too big
217
218 self.len = needed_limbs;
219 self.positive = value >= 0;
221220
222221 switch (@typeInfo(T)) {
223222 .Int => |info| {
224 const UT = if (info.signedness == .signed) std.meta.Int(.unsigned, info.bits - 1) else T;
225
226 const needed_limbs = @sizeOf(UT) / @sizeOf(Limb);
227 assert(needed_limbs <= self.limbs.len); // value too big
228 self.len = 0;
229 self.positive = value >= 0;
230
231 var w_value: UT = if (value < 0) @intCast(UT, -value) else @intCast(UT, value);
223 var w_value = std.math.absCast(value);
232224
233225 if (info.bits <= limb_bits) {
234 self.limbs[0] = @as(Limb, w_value);
235 self.len += 1;
226 self.limbs[0] = w_value;
236227 } else {
237228 var i: usize = 0;
238229 while (w_value != 0) : (i += 1) {
239230 self.limbs[i] = @truncate(Limb, w_value);
240 self.len += 1;
241231
242232 // TODO: shift == 64 at compile-time fails. Fails on u128 limbs.
243233 w_value >>= limb_bits / 2;
......@@ -246,13 +236,7 @@ pub const Mutable = struct {
246236 }
247237 },
248238 .ComptimeInt => {
249 comptime var w_value = if (value < 0) -value else value;
250
251 const req_limbs = @divFloor(math.log2(w_value), limb_bits) + 1;
252 assert(req_limbs <= self.limbs.len); // value too big
253
254 self.len = req_limbs;
255 self.positive = value >= 0;
239 comptime var w_value = std.math.absCast(value);
256240
257241 if (w_value <= maxInt(Limb)) {
258242 self.limbs[0] = w_value;
lib/std/math/big/int_test.zig+7
......@@ -61,6 +61,13 @@ test "big.int sub-limb to" {
6161 try testing.expect((try a.to(u8)) == 10);
6262}
6363
64test "big.int set negative minimum" {
65 var a = try Managed.initSet(testing.allocator, @as(i64, minInt(i64)));
66 defer a.deinit();
67
68 try testing.expect((try a.to(i64)) == minInt(i64));
69}
70
6471test "big.int to target too small error" {
6572 var a = try Managed.initSet(testing.allocator, 0xffffffff);
6673 defer a.deinit();