authorgravatar for 67321817+aaron-ang@users.noreply.github.comAaron Ang <67321817+aaron-ang@users.noreply.github.com> 2025-12-24 16:39:56-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-27 20:38:33+01:00
log9db3e23e8081e7598e35a2da53a2b29c064d8404
tree98483662eebe5803949e6068f14ddee9f9cee02f
parente55e6b5528bb2f01de242fcf32b172e244e98e74

std.math.big: require sufficient capacity for aliased params


2 files changed, 133 insertions(+), 57 deletions(-)

lib/std/math/big/int.zig+124-53
...@@ -3013,7 +3013,9 @@ pub const Managed = struct {...@@ -3013,7 +3013,9 @@ pub const Managed = struct {
3013 ///3013 ///
3014 /// Returns an error if memory could not be allocated.3014 /// Returns an error if memory could not be allocated.
3015 pub fn addScalar(r: *Managed, a: *const Managed, scalar: anytype) Allocator.Error!void {3015 pub fn addScalar(r: *Managed, a: *const Managed, scalar: anytype) Allocator.Error!void {
3016 try r.ensureAddScalarCapacity(a.toConst(), scalar);3016 const needed = @max(a.len(), calcLimbLen(scalar)) + 1;
3017 const aliased = limbsAliasDistinct(r, a);
3018 try r.ensureAliasAwareCapacity(needed, aliased);
3017 var m = r.toMutable();3019 var m = r.toMutable();
3018 m.addScalar(a.toConst(), scalar);3020 m.addScalar(a.toConst(), scalar);
3019 r.setMetadata(m.positive, m.len);3021 r.setMetadata(m.positive, m.len);
...@@ -3025,7 +3027,9 @@ pub const Managed = struct {...@@ -3025,7 +3027,9 @@ pub const Managed = struct {
3025 ///3027 ///
3026 /// Returns an error if memory could not be allocated.3028 /// Returns an error if memory could not be allocated.
3027 pub fn add(r: *Managed, a: *const Managed, b: *const Managed) Allocator.Error!void {3029 pub fn add(r: *Managed, a: *const Managed, b: *const Managed) Allocator.Error!void {
3028 try r.ensureAddCapacity(a.toConst(), b.toConst());3030 const needed = @max(a.len(), b.len()) + 1;
3031 const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b);
3032 try r.ensureAliasAwareCapacity(needed, aliased);
3029 var m = r.toMutable();3033 var m = r.toMutable();
3030 m.add(a.toConst(), b.toConst());3034 m.add(a.toConst(), b.toConst());
3031 r.setMetadata(m.positive, m.len);3035 r.setMetadata(m.positive, m.len);
...@@ -3043,7 +3047,9 @@ pub const Managed = struct {...@@ -3043,7 +3047,9 @@ pub const Managed = struct {
3043 signedness: Signedness,3047 signedness: Signedness,
3044 bit_count: usize,3048 bit_count: usize,
3045 ) Allocator.Error!bool {3049 ) Allocator.Error!bool {
3046 try r.ensureTwosCompCapacity(bit_count);3050 const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b);
3051 const needed = calcTwosCompLimbCount(bit_count);
3052 try r.ensureAliasAwareCapacity(needed, aliased);
3047 var m = r.toMutable();3053 var m = r.toMutable();
3048 const wrapped = m.addWrap(a.toConst(), b.toConst(), signedness, bit_count);3054 const wrapped = m.addWrap(a.toConst(), b.toConst(), signedness, bit_count);
3049 r.setMetadata(m.positive, m.len);3055 r.setMetadata(m.positive, m.len);
...@@ -3056,7 +3062,9 @@ pub const Managed = struct {...@@ -3056,7 +3062,9 @@ pub const Managed = struct {
3056 ///3062 ///
3057 /// Returns an error if memory could not be allocated.3063 /// Returns an error if memory could not be allocated.
3058 pub fn addSat(r: *Managed, a: *const Managed, b: *const Managed, signedness: Signedness, bit_count: usize) Allocator.Error!void {3064 pub fn addSat(r: *Managed, a: *const Managed, b: *const Managed, signedness: Signedness, bit_count: usize) Allocator.Error!void {
3059 try r.ensureTwosCompCapacity(bit_count);3065 const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b);
3066 const needed = calcTwosCompLimbCount(bit_count);
3067 try r.ensureAliasAwareCapacity(needed, aliased);
3060 var m = r.toMutable();3068 var m = r.toMutable();
3061 m.addSat(a.toConst(), b.toConst(), signedness, bit_count);3069 m.addSat(a.toConst(), b.toConst(), signedness, bit_count);
3062 r.setMetadata(m.positive, m.len);3070 r.setMetadata(m.positive, m.len);
...@@ -3068,7 +3076,9 @@ pub const Managed = struct {...@@ -3068,7 +3076,9 @@ pub const Managed = struct {
3068 ///3076 ///
3069 /// Returns an error if memory could not be allocated.3077 /// Returns an error if memory could not be allocated.
3070 pub fn sub(r: *Managed, a: *const Managed, b: *const Managed) !void {3078 pub fn sub(r: *Managed, a: *const Managed, b: *const Managed) !void {
3071 try r.ensureCapacity(@max(a.len(), b.len()) + 1);3079 const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b);
3080 const needed = @max(a.len(), b.len()) + 1;
3081 try r.ensureAliasAwareCapacity(needed, aliased);
3072 var m = r.toMutable();3082 var m = r.toMutable();
3073 m.sub(a.toConst(), b.toConst());3083 m.sub(a.toConst(), b.toConst());
3074 r.setMetadata(m.positive, m.len);3084 r.setMetadata(m.positive, m.len);
...@@ -3086,7 +3096,9 @@ pub const Managed = struct {...@@ -3086,7 +3096,9 @@ pub const Managed = struct {
3086 signedness: Signedness,3096 signedness: Signedness,
3087 bit_count: usize,3097 bit_count: usize,
3088 ) Allocator.Error!bool {3098 ) Allocator.Error!bool {
3089 try r.ensureTwosCompCapacity(bit_count);3099 const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b);
3100 const needed = calcTwosCompLimbCount(bit_count);
3101 try r.ensureAliasAwareCapacity(needed, aliased);
3090 var m = r.toMutable();3102 var m = r.toMutable();
3091 const wrapped = m.subWrap(a.toConst(), b.toConst(), signedness, bit_count);3103 const wrapped = m.subWrap(a.toConst(), b.toConst(), signedness, bit_count);
3092 r.setMetadata(m.positive, m.len);3104 r.setMetadata(m.positive, m.len);
...@@ -3105,7 +3117,9 @@ pub const Managed = struct {...@@ -3105,7 +3117,9 @@ pub const Managed = struct {
3105 signedness: Signedness,3117 signedness: Signedness,
3106 bit_count: usize,3118 bit_count: usize,
3107 ) Allocator.Error!void {3119 ) Allocator.Error!void {
3108 try r.ensureTwosCompCapacity(bit_count);3120 const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b);
3121 const needed = calcTwosCompLimbCount(bit_count);
3122 try r.ensureAliasAwareCapacity(needed, aliased);
3109 var m = r.toMutable();3123 var m = r.toMutable();
3110 m.subSat(a.toConst(), b.toConst(), signedness, bit_count);3124 m.subSat(a.toConst(), b.toConst(), signedness, bit_count);
3111 r.setMetadata(m.positive, m.len);3125 r.setMetadata(m.positive, m.len);
...@@ -3124,7 +3138,9 @@ pub const Managed = struct {...@@ -3124,7 +3138,9 @@ pub const Managed = struct {
3124 alias_count += 1;3138 alias_count += 1;
3125 if (rma.limbs.ptr == b.limbs.ptr)3139 if (rma.limbs.ptr == b.limbs.ptr)
3126 alias_count += 1;3140 alias_count += 1;
3127 try rma.ensureMulCapacity(a.toConst(), b.toConst());3141 const needed = a.len() + b.len() + 1;
3142 const capacity_alias = limbsAliasDistinct(rma, a) or limbsAliasDistinct(rma, b);
3143 try rma.ensureAliasAwareCapacity(needed, capacity_alias);
3128 var m = rma.toMutable();3144 var m = rma.toMutable();
3129 if (alias_count == 0) {3145 if (alias_count == 0) {
3130 m.mulNoAlias(a.toConst(), b.toConst(), rma.allocator);3146 m.mulNoAlias(a.toConst(), b.toConst(), rma.allocator);
...@@ -3156,8 +3172,9 @@ pub const Managed = struct {...@@ -3156,8 +3172,9 @@ pub const Managed = struct {
3156 alias_count += 1;3172 alias_count += 1;
3157 if (rma.limbs.ptr == b.limbs.ptr)3173 if (rma.limbs.ptr == b.limbs.ptr)
3158 alias_count += 1;3174 alias_count += 1;
31593175 const needed = calcTwosCompLimbCount(bit_count);
3160 try rma.ensureTwosCompCapacity(bit_count);3176 const capacity_alias = limbsAliasDistinct(rma, a) or limbsAliasDistinct(rma, b);
3177 try rma.ensureAliasAwareCapacity(needed, capacity_alias);
3161 var m = rma.toMutable();3178 var m = rma.toMutable();
3162 if (alias_count == 0) {3179 if (alias_count == 0) {
3163 m.mulWrapNoAlias(a.toConst(), b.toConst(), signedness, bit_count, rma.allocator);3180 m.mulWrapNoAlias(a.toConst(), b.toConst(), signedness, bit_count, rma.allocator);
...@@ -3174,16 +3191,40 @@ pub const Managed = struct {...@@ -3174,16 +3191,40 @@ pub const Managed = struct {
3174 try r.ensureCapacity(calcTwosCompLimbCount(bit_count));3191 try r.ensureCapacity(calcTwosCompLimbCount(bit_count));
3175 }3192 }
31763193
3177 pub fn ensureAddScalarCapacity(r: *Managed, a: Const, scalar: anytype) !void {3194 /// True if two distinct `Managed` parameters share the same limbs buffer.
3178 try r.ensureCapacity(@max(a.limbs.len, calcLimbLen(scalar)) + 1);3195 ///
3196 /// We specifically exclude the case where `@intFromPtr(a) == @intFromPtr(b)` (same object).
3197 /// When both pointers refer to the same `Managed` instance, `ensureCapacity` can reallocate
3198 /// the buffer (if needed) without creating dangling pointers for that object.
3199 fn limbsAliasDistinct(a: *const Managed, b: *const Managed) bool {
3200 return @intFromPtr(a) != @intFromPtr(b) and a.limbs.ptr == b.limbs.ptr;
3201 }
3202
3203 /// When `aliased` is false (including when both pointers refer to the same object),
3204 /// `ensureCapacity` may reallocate; callers who rely on distinct `Managed` instances
3205 /// aliasing must ensure capacity before aliasing.
3206 /// See https://github.com/ziglang/zig/issues/6167
3207 fn ensureAliasAwareCapacity(r: *Managed, needed: usize, aliased: bool) !void {
3208 if (aliased) {
3209 assert(needed <= r.limbs.len);
3210 } else {
3211 try r.ensureCapacity(needed);
3212 }
3179 }3213 }
31803214
3181 pub fn ensureAddCapacity(r: *Managed, a: Const, b: Const) !void {3215 /// Use this function before doing `addScalar` if some of your parameters alias each other
3182 try r.ensureCapacity(@max(a.limbs.len, b.limbs.len) + 1);3216 pub fn ensureAddScalarCapacity(r: *Managed, a: *const Managed, scalar: anytype) !void {
3217 try r.ensureCapacity(@max(a.len(), calcLimbLen(scalar)) + 1);
3183 }3218 }
31843219
3185 pub fn ensureMulCapacity(rma: *Managed, a: Const, b: Const) !void {3220 /// Use this function before doing `add` if some of your parameters alias each other
3186 try rma.ensureCapacity(a.limbs.len + b.limbs.len + 1);3221 pub fn ensureAddCapacity(r: *Managed, a: *const Managed, b: *const Managed) !void {
3222 try r.ensureCapacity(@max(a.len(), b.len()) + 1);
3223 }
3224
3225 /// Use this function before doing `mul` if some of your parameters alias each other
3226 pub fn ensureMulCapacity(rma: *Managed, a: *const Managed, b: *const Managed) !void {
3227 try rma.ensureCapacity(a.len() + b.len() + 1);
3187 }3228 }
31883229
3189 /// q = a / b (rem r)3230 /// q = a / b (rem r)
...@@ -3192,8 +3233,10 @@ pub const Managed = struct {...@@ -3192,8 +3233,10 @@ pub const Managed = struct {
3192 ///3233 ///
3193 /// Returns an error if memory could not be allocated.3234 /// Returns an error if memory could not be allocated.
3194 pub fn divFloor(q: *Managed, r: *Managed, a: *const Managed, b: *const Managed) !void {3235 pub fn divFloor(q: *Managed, r: *Managed, a: *const Managed, b: *const Managed) !void {
3195 try q.ensureCapacity(a.len());3236 const q_alias = limbsAliasDistinct(q, a) or limbsAliasDistinct(q, b);
3196 try r.ensureCapacity(b.len());3237 const r_alias = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b);
3238 try q.ensureAliasAwareCapacity(a.len(), q_alias);
3239 try r.ensureAliasAwareCapacity(b.len(), r_alias);
3197 var mq = q.toMutable();3240 var mq = q.toMutable();
3198 var mr = r.toMutable();3241 var mr = r.toMutable();
3199 const limbs_buffer = try q.allocator.alloc(Limb, calcDivLimbsBufferLen(a.len(), b.len()));3242 const limbs_buffer = try q.allocator.alloc(Limb, calcDivLimbsBufferLen(a.len(), b.len()));
...@@ -3209,8 +3252,10 @@ pub const Managed = struct {...@@ -3209,8 +3252,10 @@ pub const Managed = struct {
3209 ///3252 ///
3210 /// Returns an error if memory could not be allocated.3253 /// Returns an error if memory could not be allocated.
3211 pub fn divTrunc(q: *Managed, r: *Managed, a: *const Managed, b: *const Managed) !void {3254 pub fn divTrunc(q: *Managed, r: *Managed, a: *const Managed, b: *const Managed) !void {
3212 try q.ensureCapacity(a.len());3255 const q_alias = limbsAliasDistinct(q, a) or limbsAliasDistinct(q, b);
3213 try r.ensureCapacity(b.len());3256 const r_alias = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b);
3257 try q.ensureAliasAwareCapacity(a.len(), q_alias);
3258 try r.ensureAliasAwareCapacity(b.len(), r_alias);
3214 var mq = q.toMutable();3259 var mq = q.toMutable();
3215 var mr = r.toMutable();3260 var mr = r.toMutable();
3216 const limbs_buffer = try q.allocator.alloc(Limb, calcDivLimbsBufferLen(a.len(), b.len()));3261 const limbs_buffer = try q.allocator.alloc(Limb, calcDivLimbsBufferLen(a.len(), b.len()));
...@@ -3223,7 +3268,9 @@ pub const Managed = struct {...@@ -3223,7 +3268,9 @@ pub const Managed = struct {
3223 /// r = a << shift, in other words, r = a * 2^shift3268 /// r = a << shift, in other words, r = a * 2^shift
3224 /// r and a may alias.3269 /// r and a may alias.
3225 pub fn shiftLeft(r: *Managed, a: *const Managed, shift: usize) !void {3270 pub fn shiftLeft(r: *Managed, a: *const Managed, shift: usize) !void {
3226 try r.ensureCapacity(a.len() + (shift / limb_bits) + 1);3271 const aliased = limbsAliasDistinct(r, a);
3272 const needed = a.len() + (shift / limb_bits) + 1;
3273 try r.ensureAliasAwareCapacity(needed, aliased);
3227 var m = r.toMutable();3274 var m = r.toMutable();
3228 m.shiftLeft(a.toConst(), shift);3275 m.shiftLeft(a.toConst(), shift);
3229 r.setMetadata(m.positive, m.len);3276 r.setMetadata(m.positive, m.len);
...@@ -3232,7 +3279,9 @@ pub const Managed = struct {...@@ -3232,7 +3279,9 @@ pub const Managed = struct {
3232 /// r = a <<| shift with 2s-complement saturating semantics.3279 /// r = a <<| shift with 2s-complement saturating semantics.
3233 /// r and a may alias.3280 /// r and a may alias.
3234 pub fn shiftLeftSat(r: *Managed, a: *const Managed, shift: usize, signedness: Signedness, bit_count: usize) !void {3281 pub fn shiftLeftSat(r: *Managed, a: *const Managed, shift: usize, signedness: Signedness, bit_count: usize) !void {
3235 try r.ensureTwosCompCapacity(bit_count);3282 const aliased = limbsAliasDistinct(r, a);
3283 const needed = calcTwosCompLimbCount(bit_count);
3284 try r.ensureAliasAwareCapacity(needed, aliased);
3236 var m = r.toMutable();3285 var m = r.toMutable();
3237 m.shiftLeftSat(a.toConst(), shift, signedness, bit_count);3286 m.shiftLeftSat(a.toConst(), shift, signedness, bit_count);
3238 r.setMetadata(m.positive, m.len);3287 r.setMetadata(m.positive, m.len);
...@@ -3254,7 +3303,9 @@ pub const Managed = struct {...@@ -3254,7 +3303,9 @@ pub const Managed = struct {
3254 return;3303 return;
3255 }3304 }
32563305
3257 try r.ensureCapacity(a.len() - (shift / limb_bits));3306 const aliased = limbsAliasDistinct(r, a);
3307 const needed = a.len() - (shift / limb_bits);
3308 try r.ensureAliasAwareCapacity(needed, aliased);
3258 var m = r.toMutable();3309 var m = r.toMutable();
3259 m.shiftRight(a.toConst(), shift);3310 m.shiftRight(a.toConst(), shift);
3260 r.setMetadata(m.positive, m.len);3311 r.setMetadata(m.positive, m.len);
...@@ -3263,7 +3314,9 @@ pub const Managed = struct {...@@ -3263,7 +3314,9 @@ pub const Managed = struct {
3263 /// r = ~a under 2s-complement wrapping semantics.3314 /// r = ~a under 2s-complement wrapping semantics.
3264 /// r and a may alias.3315 /// r and a may alias.
3265 pub fn bitNotWrap(r: *Managed, a: *const Managed, signedness: Signedness, bit_count: usize) !void {3316 pub fn bitNotWrap(r: *Managed, a: *const Managed, signedness: Signedness, bit_count: usize) !void {
3266 try r.ensureTwosCompCapacity(bit_count);3317 const aliased = limbsAliasDistinct(r, a);
3318 const needed = calcTwosCompLimbCount(bit_count);
3319 try r.ensureAliasAwareCapacity(needed, aliased);
3267 var m = r.toMutable();3320 var m = r.toMutable();
3268 m.bitNotWrap(a.toConst(), signedness, bit_count);3321 m.bitNotWrap(a.toConst(), signedness, bit_count);
3269 r.setMetadata(m.positive, m.len);3322 r.setMetadata(m.positive, m.len);
...@@ -3273,7 +3326,9 @@ pub const Managed = struct {...@@ -3273,7 +3326,9 @@ pub const Managed = struct {
3273 ///3326 ///
3274 /// a and b are zero-extended to the longer of a or b.3327 /// a and b are zero-extended to the longer of a or b.
3275 pub fn bitOr(r: *Managed, a: *const Managed, b: *const Managed) !void {3328 pub fn bitOr(r: *Managed, a: *const Managed, b: *const Managed) !void {
3276 try r.ensureCapacity(@max(a.len(), b.len()));3329 const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b);
3330 const needed = @max(a.len(), b.len());
3331 try r.ensureAliasAwareCapacity(needed, aliased);
3277 var m = r.toMutable();3332 var m = r.toMutable();
3278 m.bitOr(a.toConst(), b.toConst());3333 m.bitOr(a.toConst(), b.toConst());
3279 r.setMetadata(m.positive, m.len);3334 r.setMetadata(m.positive, m.len);
...@@ -3285,7 +3340,8 @@ pub const Managed = struct {...@@ -3285,7 +3340,8 @@ pub const Managed = struct {
3285 if (b.isPositive()) b.len() else if (a.isPositive()) a.len() else a.len() + 13340 if (b.isPositive()) b.len() else if (a.isPositive()) a.len() else a.len() + 1
3286 else if (a.isPositive()) a.len() else if (b.isPositive()) b.len() else b.len() + 1;3341 else if (a.isPositive()) a.len() else if (b.isPositive()) b.len() else b.len() + 1;
32873342
3288 try r.ensureCapacity(cap);3343 const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b);
3344 try r.ensureAliasAwareCapacity(cap, aliased);
3289 var m = r.toMutable();3345 var m = r.toMutable();
3290 m.bitAnd(a.toConst(), b.toConst());3346 m.bitAnd(a.toConst(), b.toConst());
3291 r.setMetadata(m.positive, m.len);3347 r.setMetadata(m.positive, m.len);
...@@ -3294,7 +3350,8 @@ pub const Managed = struct {...@@ -3294,7 +3350,8 @@ pub const Managed = struct {
3294 /// r = a ^ b3350 /// r = a ^ b
3295 pub fn bitXor(r: *Managed, a: *const Managed, b: *const Managed) !void {3351 pub fn bitXor(r: *Managed, a: *const Managed, b: *const Managed) !void {
3296 const cap = @max(a.len(), b.len()) + @intFromBool(a.isPositive() != b.isPositive());3352 const cap = @max(a.len(), b.len()) + @intFromBool(a.isPositive() != b.isPositive());
3297 try r.ensureCapacity(cap);3353 const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b);
3354 try r.ensureAliasAwareCapacity(cap, aliased);
32983355
3299 var m = r.toMutable();3356 var m = r.toMutable();
3300 m.bitXor(a.toConst(), b.toConst());3357 m.bitXor(a.toConst(), b.toConst());
...@@ -3306,7 +3363,9 @@ pub const Managed = struct {...@@ -3306,7 +3363,9 @@ pub const Managed = struct {
3306 ///3363 ///
3307 /// rma's allocator is used for temporary storage to boost multiplication performance.3364 /// rma's allocator is used for temporary storage to boost multiplication performance.
3308 pub fn gcd(rma: *Managed, x: *const Managed, y: *const Managed) !void {3365 pub fn gcd(rma: *Managed, x: *const Managed, y: *const Managed) !void {
3309 try rma.ensureCapacity(@min(x.len(), y.len()));3366 const aliased = limbsAliasDistinct(rma, x) or limbsAliasDistinct(rma, y);
3367 const needed = @min(x.len(), y.len());
3368 try rma.ensureAliasAwareCapacity(needed, aliased);
3310 var m = rma.toMutable();3369 var m = rma.toMutable();
3311 var limbs_buffer = std.array_list.Managed(Limb).init(rma.allocator);3370 var limbs_buffer = std.array_list.Managed(Limb).init(rma.allocator);
3312 defer limbs_buffer.deinit();3371 defer limbs_buffer.deinit();
...@@ -3317,18 +3376,20 @@ pub const Managed = struct {...@@ -3317,18 +3376,20 @@ pub const Managed = struct {
3317 /// r = a * a3376 /// r = a * a
3318 pub fn sqr(rma: *Managed, a: *const Managed) !void {3377 pub fn sqr(rma: *Managed, a: *const Managed) !void {
3319 const needed_limbs = 2 * a.len() + 1;3378 const needed_limbs = 2 * a.len() + 1;
33203379 const capacity_alias = limbsAliasDistinct(rma, a);
3321 if (rma.limbs.ptr == a.limbs.ptr) {3380 const same_buffer = rma.limbs.ptr == a.limbs.ptr;
3322 var m = try Managed.initCapacity(rma.allocator, needed_limbs);3381 try rma.ensureAliasAwareCapacity(needed_limbs, capacity_alias);
3323 errdefer m.deinit();3382
3324 var m_mut = m.toMutable();3383 if (same_buffer) {
3325 m_mut.sqrNoAlias(a.toConst(), rma.allocator);3384 const a_len = a.len();
3326 m.setMetadata(m_mut.positive, m_mut.len);3385 const tmp = try rma.allocator.alloc(Limb, a_len);
33273386 defer rma.allocator.free(tmp);
3328 rma.deinit();3387 @memcpy(tmp[0..a_len], a.limbs[0..a_len]);
3329 rma.swap(&m);3388 const a_const = Const{ .limbs = tmp[0..a_len], .positive = a.isPositive() };
3389 var rma_mut = rma.toMutable();
3390 rma_mut.sqrNoAlias(a_const, rma.allocator);
3391 rma.setMetadata(rma_mut.positive, rma_mut.len);
3330 } else {3392 } else {
3331 try rma.ensureCapacity(needed_limbs);
3332 var rma_mut = rma.toMutable();3393 var rma_mut = rma.toMutable();
3333 rma_mut.sqrNoAlias(a.toConst(), rma.allocator);3394 rma_mut.sqrNoAlias(a.toConst(), rma.allocator);
3334 rma.setMetadata(rma_mut.positive, rma_mut.len);3395 rma.setMetadata(rma_mut.positive, rma_mut.len);
...@@ -3337,21 +3398,23 @@ pub const Managed = struct {...@@ -3337,21 +3398,23 @@ pub const Managed = struct {
33373398
3338 pub fn pow(rma: *Managed, a: *const Managed, b: u32) !void {3399 pub fn pow(rma: *Managed, a: *const Managed, b: u32) !void {
3339 const needed_limbs = calcPowLimbsBufferLen(a.bitCountAbs(), b);3400 const needed_limbs = calcPowLimbsBufferLen(a.bitCountAbs(), b);
3401 const capacity_alias = limbsAliasDistinct(rma, a);
3402 const same_buffer = rma.limbs.ptr == a.limbs.ptr;
33403403
3404 try rma.ensureAliasAwareCapacity(needed_limbs, capacity_alias);
3341 const limbs_buffer = try rma.allocator.alloc(Limb, needed_limbs);3405 const limbs_buffer = try rma.allocator.alloc(Limb, needed_limbs);
3342 defer rma.allocator.free(limbs_buffer);3406 defer rma.allocator.free(limbs_buffer);
33433407
3344 if (rma.limbs.ptr == a.limbs.ptr) {3408 if (same_buffer) {
3345 var m = try Managed.initCapacity(rma.allocator, needed_limbs);3409 const a_len = a.len();
3346 errdefer m.deinit();3410 const tmp = try rma.allocator.alloc(Limb, a_len);
3347 var m_mut = m.toMutable();3411 defer rma.allocator.free(tmp);
3348 m_mut.pow(a.toConst(), b, limbs_buffer);3412 @memcpy(tmp[0..a_len], a.limbs[0..a_len]);
3349 m.setMetadata(m_mut.positive, m_mut.len);3413 const a_const = Const{ .limbs = tmp[0..a_len], .positive = a.isPositive() };
33503414 var rma_mut = rma.toMutable();
3351 rma.deinit();3415 rma_mut.pow(a_const, b, limbs_buffer);
3352 rma.swap(&m);3416 rma.setMetadata(rma_mut.positive, rma_mut.len);
3353 } else {3417 } else {
3354 try rma.ensureCapacity(needed_limbs);
3355 var rma_mut = rma.toMutable();3418 var rma_mut = rma.toMutable();
3356 rma_mut.pow(a.toConst(), b, limbs_buffer);3419 rma_mut.pow(a.toConst(), b, limbs_buffer);
3357 rma.setMetadata(rma_mut.positive, rma_mut.len);3420 rma.setMetadata(rma_mut.positive, rma_mut.len);
...@@ -3361,6 +3424,7 @@ pub const Managed = struct {...@@ -3361,6 +3424,7 @@ pub const Managed = struct {
3361 /// r = ⌊√a⌋3424 /// r = ⌊√a⌋
3362 pub fn sqrt(rma: *Managed, a: *const Managed) !void {3425 pub fn sqrt(rma: *Managed, a: *const Managed) !void {
3363 const bit_count = a.bitCountAbs();3426 const bit_count = a.bitCountAbs();
3427 const aliased = limbsAliasDistinct(rma, a);
33643428
3365 if (bit_count == 0) {3429 if (bit_count == 0) {
3366 try rma.set(0);3430 try rma.set(0);
...@@ -3376,7 +3440,8 @@ pub const Managed = struct {...@@ -3376,7 +3440,8 @@ pub const Managed = struct {
3376 const limbs_buffer = try rma.allocator.alloc(Limb, needed_limbs);3440 const limbs_buffer = try rma.allocator.alloc(Limb, needed_limbs);
3377 defer rma.allocator.free(limbs_buffer);3441 defer rma.allocator.free(limbs_buffer);
33783442
3379 try rma.ensureCapacity((a.len() - 1) / 2 + 1);3443 const needed = (a.len() - 1) / 2 + 1;
3444 try rma.ensureAliasAwareCapacity(needed, aliased);
3380 var m = rma.toMutable();3445 var m = rma.toMutable();
3381 m.sqrt(a.toConst(), limbs_buffer);3446 m.sqrt(a.toConst(), limbs_buffer);
3382 rma.setMetadata(m.positive, m.len);3447 rma.setMetadata(m.positive, m.len);
...@@ -3384,7 +3449,9 @@ pub const Managed = struct {...@@ -3384,7 +3449,9 @@ pub const Managed = struct {
33843449
3385 /// r = truncate(Int(signedness, bit_count), a)3450 /// r = truncate(Int(signedness, bit_count), a)
3386 pub fn truncate(r: *Managed, a: *const Managed, signedness: Signedness, bit_count: usize) !void {3451 pub fn truncate(r: *Managed, a: *const Managed, signedness: Signedness, bit_count: usize) !void {
3387 try r.ensureCapacity(calcTwosCompLimbCount(bit_count));3452 const aliased = limbsAliasDistinct(r, a);
3453 const needed = calcTwosCompLimbCount(bit_count);
3454 try r.ensureAliasAwareCapacity(needed, aliased);
3388 var m = r.toMutable();3455 var m = r.toMutable();
3389 m.truncate(a.toConst(), signedness, bit_count);3456 m.truncate(a.toConst(), signedness, bit_count);
3390 r.setMetadata(m.positive, m.len);3457 r.setMetadata(m.positive, m.len);
...@@ -3392,7 +3459,9 @@ pub const Managed = struct {...@@ -3392,7 +3459,9 @@ pub const Managed = struct {
33923459
3393 /// r = saturate(Int(signedness, bit_count), a)3460 /// r = saturate(Int(signedness, bit_count), a)
3394 pub fn saturate(r: *Managed, a: *const Managed, signedness: Signedness, bit_count: usize) !void {3461 pub fn saturate(r: *Managed, a: *const Managed, signedness: Signedness, bit_count: usize) !void {
3395 try r.ensureCapacity(calcTwosCompLimbCount(bit_count));3462 const aliased = limbsAliasDistinct(r, a);
3463 const needed = calcTwosCompLimbCount(bit_count);
3464 try r.ensureAliasAwareCapacity(needed, aliased);
3396 var m = r.toMutable();3465 var m = r.toMutable();
3397 m.saturate(a.toConst(), signedness, bit_count);3466 m.saturate(a.toConst(), signedness, bit_count);
3398 r.setMetadata(m.positive, m.len);3467 r.setMetadata(m.positive, m.len);
...@@ -3401,7 +3470,9 @@ pub const Managed = struct {...@@ -3401,7 +3470,9 @@ pub const Managed = struct {
3401 /// r = @popCount(a) with 2s-complement semantics.3470 /// r = @popCount(a) with 2s-complement semantics.
3402 /// r and a may be aliases.3471 /// r and a may be aliases.
3403 pub fn popCount(r: *Managed, a: *const Managed, bit_count: usize) !void {3472 pub fn popCount(r: *Managed, a: *const Managed, bit_count: usize) !void {
3404 try r.ensureCapacity(calcTwosCompLimbCount(bit_count));3473 const aliased = limbsAliasDistinct(r, a);
3474 const needed = calcTwosCompLimbCount(bit_count);
3475 try r.ensureAliasAwareCapacity(needed, aliased);
3405 var m = r.toMutable();3476 var m = r.toMutable();
3406 m.popCount(a.toConst(), bit_count);3477 m.popCount(a.toConst(), bit_count);
3407 r.setMetadata(m.positive, m.len);3478 r.setMetadata(m.positive, m.len);
lib/std/math/big/int_test.zig+9-4
...@@ -583,7 +583,9 @@ test "bitcount + sizeInBaseUpperBound" {...@@ -583,7 +583,9 @@ test "bitcount + sizeInBaseUpperBound" {
583 try testing.expect(a.sizeInBaseUpperBound(2) >= 32);583 try testing.expect(a.sizeInBaseUpperBound(2) >= 32);
584 try testing.expect(a.sizeInBaseUpperBound(10) >= 10);584 try testing.expect(a.sizeInBaseUpperBound(10) >= 10);
585585
586 try a.shiftLeft(&a, 5000);586 const shift = 5000;
587 try a.ensureCapacity(a.len() + (shift / @bitSizeOf(Limb)) + 1);
588 try a.shiftLeft(&a, shift);
587 try testing.expectEqual(5032, a.bitCountAbs());589 try testing.expectEqual(5032, a.bitCountAbs());
588 try testing.expect(a.sizeInBaseUpperBound(2) >= 5032);590 try testing.expect(a.sizeInBaseUpperBound(2) >= 5032);
589 a.setSign(false);591 a.setSign(false);
...@@ -2380,7 +2382,9 @@ test "truncate negative multi to single" {...@@ -2380,7 +2382,9 @@ test "truncate negative multi to single" {
2380test "truncate multi unsigned many" {2382test "truncate multi unsigned many" {
2381 var a = try Managed.initSet(testing.allocator, 1);2383 var a = try Managed.initSet(testing.allocator, 1);
2382 defer a.deinit();2384 defer a.deinit();
2383 try a.shiftLeft(&a, 1023);2385 const shift = 1023;
2386 try a.ensureCapacity(a.len() + (shift / @bitSizeOf(Limb)) + 1);
2387 try a.shiftLeft(&a, shift);
23842388
2385 var b = try Managed.init(testing.allocator);2389 var b = try Managed.init(testing.allocator);
2386 defer b.deinit();2390 defer b.deinit();
...@@ -3263,7 +3267,7 @@ test "regression test for 1 limb overflow with alias" {...@@ -3263,7 +3267,7 @@ test "regression test for 1 limb overflow with alias" {
3263 var b = try Managed.initSet(testing.allocator, 12200160415121876738);3267 var b = try Managed.initSet(testing.allocator, 12200160415121876738);
3264 defer b.deinit();3268 defer b.deinit();
32653269
3266 try a.ensureAddCapacity(a.toConst(), b.toConst());3270 try a.ensureAddCapacity(&a, &b);
3267 try a.add(&a, &b);3271 try a.add(&a, &b);
32683272
3269 try testing.expectEqual(.eq, a.toConst().orderAgainstScalar(19740274219868223167));3273 try testing.expectEqual(.eq, a.toConst().orderAgainstScalar(19740274219868223167));
...@@ -3277,7 +3281,7 @@ test "regression test for realloc with alias" {...@@ -3277,7 +3281,7 @@ test "regression test for realloc with alias" {
3277 var b = try Managed.initSet(testing.allocator, 9079598147510263717870894449029933369491131786514446266146);3281 var b = try Managed.initSet(testing.allocator, 9079598147510263717870894449029933369491131786514446266146);
3278 defer b.deinit();3282 defer b.deinit();
32793283
3280 try a.ensureAddCapacity(a.toConst(), b.toConst());3284 try a.ensureAddCapacity(&a, &b);
3281 try a.add(&a, &b);3285 try a.add(&a, &b);
32823286
3283 try testing.expectEqual(.eq, a.toConst().orderAgainstScalar(14691098406862188148944207245954912110548093601382197697835));3287 try testing.expectEqual(.eq, a.toConst().orderAgainstScalar(14691098406862188148944207245954912110548093601382197697835));
...@@ -3692,6 +3696,7 @@ test "mul multi-multi alias r with a and b" {...@@ -3692,6 +3696,7 @@ test "mul multi-multi alias r with a and b" {
3692 var a = try Managed.initSet(testing.allocator, 2 * maxInt(Limb));3696 var a = try Managed.initSet(testing.allocator, 2 * maxInt(Limb));
3693 defer a.deinit();3697 defer a.deinit();
36943698
3699 try a.ensureMulCapacity(&a, &a);
3695 try a.mul(&a, &a);3700 try a.mul(&a, &a);
36963701
3697 var want = try Managed.initSet(testing.allocator, 4 * maxInt(Limb) * maxInt(Limb));3702 var want = try Managed.initSet(testing.allocator, 4 * maxInt(Limb) * maxInt(Limb));