authorgravatar for ashe@kivikakk.eeAsherah Connor <ashe@kivikakk.ee> 2021-03-24 16:39:46+11:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-06-11 16:18:10+03:00
loge56ba4cee1040eb0ca4d94e7e4dbfe88a12c171a
tree10cb092230b65cf8bbf13c7873b937fea361cd8d
parentb15e2054384ba683499138fcad0a9503f3aa9e0b

bigint: add ensureAdd(Scalar)Capacity, note aliasing requirements


2 files changed, 33 insertions(+), 8 deletions(-)

lib/std/math/big/int.zig+18-6
...@@ -335,10 +335,10 @@ pub const Mutable = struct {...@@ -335,10 +335,10 @@ pub const Mutable = struct {
335 }335 }
336 } else {336 } else {
337 if (a.limbs.len >= b.limbs.len) {337 if (a.limbs.len >= b.limbs.len) {
338 lladd(r.limbs[0..], a.limbs[0..a.limbs.len], b.limbs[0..b.limbs.len]);338 lladd(r.limbs[0..], a.limbs, b.limbs);
339 r.normalize(a.limbs.len + 1);339 r.normalize(a.limbs.len + 1);
340 } else {340 } else {
341 lladd(r.limbs[0..], b.limbs[0..b.limbs.len], a.limbs[0..a.limbs.len]);341 lladd(r.limbs[0..], b.limbs, a.limbs);
342 r.normalize(b.limbs.len + 1);342 r.normalize(b.limbs.len + 1);
343 }343 }
344344
...@@ -1685,12 +1685,14 @@ pub const Managed = struct {...@@ -1685,12 +1685,14 @@ pub const Managed = struct {
16851685
1686 /// r = a + scalar1686 /// r = a + scalar
1687 ///1687 ///
1688 /// r and a may be aliases.1688 /// r and a may be aliases. If r aliases a, then caller must call
1689 /// `r.ensureAddScalarCapacity` prior to calling `add`.
1689 /// scalar is a primitive integer type.1690 /// scalar is a primitive integer type.
1690 ///1691 ///
1691 /// Returns an error if memory could not be allocated.1692 /// Returns an error if memory could not be allocated.
1692 pub fn addScalar(r: *Managed, a: Const, scalar: anytype) Allocator.Error!void {1693 pub fn addScalar(r: *Managed, a: Const, scalar: anytype) Allocator.Error!void {
1693 try r.ensureCapacity(math.max(a.limbs.len, calcLimbLen(scalar)) + 1);1694 assert((r.limbs.ptr != a.limbs.ptr) or r.limbs.len >= math.max(a.limbs.len, calcLimbLen(scalar)) + 1);
1695 try r.ensureAddScalarCapacity(a, scalar);
1694 var m = r.toMutable();1696 var m = r.toMutable();
1695 m.addScalar(a, scalar);1697 m.addScalar(a, scalar);
1696 r.setMetadata(m.positive, m.len);1698 r.setMetadata(m.positive, m.len);
...@@ -1698,11 +1700,13 @@ pub const Managed = struct {...@@ -1698,11 +1700,13 @@ pub const Managed = struct {
16981700
1699 /// r = a + b1701 /// r = a + b
1700 ///1702 ///
1701 /// r, a and b may be aliases.1703 /// r, a and b may be aliases. If r aliases a or b, then caller must call
1704 /// `r.ensureAddCapacity` prior to calling `add`.
1702 ///1705 ///
1703 /// Returns an error if memory could not be allocated.1706 /// Returns an error if memory could not be allocated.
1704 pub fn add(r: *Managed, a: Const, b: Const) Allocator.Error!void {1707 pub fn add(r: *Managed, a: Const, b: Const) Allocator.Error!void {
1705 try r.ensureCapacity(math.max(a.limbs.len, b.limbs.len) + 1);1708 assert((r.limbs.ptr != a.limbs.ptr and r.limbs.ptr != b.limbs.ptr) or r.limbs.len >= math.max(a.limbs.len, b.limbs.len) + 1);
1709 try r.ensureAddCapacity(a, b);
1706 var m = r.toMutable();1710 var m = r.toMutable();
1707 m.add(a, b);1711 m.add(a, b);
1708 r.setMetadata(m.positive, m.len);1712 r.setMetadata(m.positive, m.len);
...@@ -1748,6 +1752,14 @@ pub const Managed = struct {...@@ -1748,6 +1752,14 @@ pub const Managed = struct {
1748 rma.setMetadata(m.positive, m.len);1752 rma.setMetadata(m.positive, m.len);
1749 }1753 }
17501754
1755 pub fn ensureAddScalarCapacity(r: *Managed, a: Const, scalar: anytype) !void {
1756 try r.ensureCapacity(math.max(a.limbs.len, calcLimbLen(scalar)) + 1);
1757 }
1758
1759 pub fn ensureAddCapacity(r: *Managed, a: Const, b: Const) !void {
1760 try r.ensureCapacity(math.max(a.limbs.len, b.limbs.len) + 1);
1761 }
1762
1751 pub fn ensureMulCapacity(rma: *Managed, a: Const, b: Const) !void {1763 pub fn ensureMulCapacity(rma: *Managed, a: Const, b: Const) !void {
1752 try rma.ensureCapacity(a.limbs.len + b.limbs.len + 1);1764 try rma.ensureCapacity(a.limbs.len + b.limbs.len + 1);
1753 }1765 }
lib/std/math/big/int_test.zig+15-2
...@@ -538,6 +538,17 @@ test "big.int add sign" {...@@ -538,6 +538,17 @@ test "big.int add sign" {
538 try testing.expect((try a.to(i32)) == -3);538 try testing.expect((try a.to(i32)) == -3);
539}539}
540540
541test "big.int add scalar" {
542 var a = try Managed.initSet(testing.allocator, 50);
543 defer a.deinit();
544
545 var b = try Managed.init(testing.allocator);
546 defer b.deinit();
547 try b.addScalar(a.toConst(), 5);
548
549 try testing.expect((try b.to(u32)) == 55);
550}
551
541test "big.int sub single-single" {552test "big.int sub single-single" {
542 var a = try Managed.initSet(testing.allocator, 50);553 var a = try Managed.initSet(testing.allocator, 50);
543 defer a.deinit();554 defer a.deinit();
...@@ -1563,7 +1574,7 @@ test "big.int pow" {...@@ -1563,7 +1574,7 @@ test "big.int pow" {
1563 }1574 }
1564}1575}
15651576
1566test "bigint regression test for 1 limb overflow with alias" {1577test "big.int regression test for 1 limb overflow with alias" {
1567 // Note these happen to be two consecutive Fibonacci sequence numbers, the1578 // Note these happen to be two consecutive Fibonacci sequence numbers, the
1568 // first two whose sum exceeds 2**64.1579 // first two whose sum exceeds 2**64.
1569 var a = try Managed.initSet(testing.allocator, 7540113804746346429);1580 var a = try Managed.initSet(testing.allocator, 7540113804746346429);
...@@ -1571,12 +1582,13 @@ test "bigint regression test for 1 limb overflow with alias" {...@@ -1571,12 +1582,13 @@ test "bigint regression test for 1 limb overflow with alias" {
1571 var b = try Managed.initSet(testing.allocator, 12200160415121876738);1582 var b = try Managed.initSet(testing.allocator, 12200160415121876738);
1572 defer b.deinit();1583 defer b.deinit();
15731584
1585 try a.ensureAddCapacity(a.toConst(), b.toConst());
1574 try a.add(a.toConst(), b.toConst());1586 try a.add(a.toConst(), b.toConst());
15751587
1576 try testing.expect(a.toConst().orderAgainstScalar(19740274219868223167) == .eq);1588 try testing.expect(a.toConst().orderAgainstScalar(19740274219868223167) == .eq);
1577}1589}
15781590
1579test "bigint regression test for something else with alias" {1591test "big.int regression test for realloc with alias" {
1580 // Note these happen to be two consecutive Fibonacci sequence numbers, the1592 // Note these happen to be two consecutive Fibonacci sequence numbers, the
1581 // second of which is the first such number to exceed 2**192.1593 // second of which is the first such number to exceed 2**192.
1582 var a = try Managed.initSet(testing.allocator, 5611500259351924431073312796924978741056961814867751431689);1594 var a = try Managed.initSet(testing.allocator, 5611500259351924431073312796924978741056961814867751431689);
...@@ -1584,6 +1596,7 @@ test "bigint regression test for something else with alias" {...@@ -1584,6 +1596,7 @@ test "bigint regression test for something else with alias" {
1584 var b = try Managed.initSet(testing.allocator, 9079598147510263717870894449029933369491131786514446266146);1596 var b = try Managed.initSet(testing.allocator, 9079598147510263717870894449029933369491131786514446266146);
1585 defer b.deinit();1597 defer b.deinit();
15861598
1599 try a.ensureAddCapacity(a.toConst(), b.toConst());
1587 try a.add(a.toConst(), b.toConst());1600 try a.add(a.toConst(), b.toConst());
15881601
1589 try testing.expect(a.toConst().orderAgainstScalar(14691098406862188148944207245954912110548093601382197697835) == .eq);1602 try testing.expect(a.toConst().orderAgainstScalar(14691098406862188148944207245954912110548093601382197697835) == .eq);