| ... | @@ -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; |
| 3159 | | 3175 | 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 | } |
| 3176 | | 3193 | |
| 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 | } |
| 3180 | | 3214 | |
| 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 | } |
| 3184 | | 3219 | |
| 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 | } |
| 3188 | | 3229 | |
| 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^shift | 3268 | /// 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 | } |
| 3256 | | 3305 | |
| 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() + 1 | 3340 | 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; |
| 3287 | | 3342 | |
| 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 ^ b | 3350 | /// 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); |
| 3298 | | 3355 | |
| 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 * a | 3376 | /// 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; |
| 3320 | | 3379 | 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); |
| 3327 | | 3386 | 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 { |
| 3337 | | 3398 | |
| 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; |
| 3340 | | 3403 | |
| | 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); |
| 3343 | | 3407 | |
| 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() }; |
| 3350 | | 3414 | 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); |
| 3364 | | 3428 | |
| 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); |
| 3378 | | 3442 | |
| 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 { |
| 3384 | | 3449 | |
| 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 { |
| 3392 | | 3459 | |
| 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); |