@@ -2979,7 +2979,9 @@ pub const Managed = struct {
29792979 ///
29802980 /// Returns an error if memory could not be allocated.
29812981 pub fn addScalar (r : * Managed , a : * const Managed , scalar : anytype ) Allocator.Error ! void {
2982- try r .ensureAddScalarCapacity (a .toConst (), scalar );
2982+ const needed = @max (a .len (), calcLimbLen (scalar )) + 1 ;
2983+ const aliased = limbsAliasDistinct (r , a );
2984+ try r .ensureAliasAwareCapacity (needed , aliased );
29832985 var m = r .toMutable ();
29842986 m .addScalar (a .toConst (), scalar );
29852987 r .setMetadata (m .positive , m .len );
@@ -2991,7 +2993,9 @@ pub const Managed = struct {
29912993 ///
29922994 /// Returns an error if memory could not be allocated.
29932995 pub fn add (r : * Managed , a : * const Managed , b : * const Managed ) Allocator.Error ! void {
2994- try r .ensureAddCapacity (a .toConst (), b .toConst ());
2996+ const needed = @max (a .len (), b .len ()) + 1 ;
2997+ const aliased = limbsAliasDistinct (r , a ) or limbsAliasDistinct (r , b );
2998+ try r .ensureAliasAwareCapacity (needed , aliased );
29952999 var m = r .toMutable ();
29963000 m .add (a .toConst (), b .toConst ());
29973001 r .setMetadata (m .positive , m .len );
@@ -3009,7 +3013,9 @@ pub const Managed = struct {
30093013 signedness : Signedness ,
30103014 bit_count : usize ,
30113015 ) Allocator.Error ! bool {
3012- try r .ensureTwosCompCapacity (bit_count );
3016+ const aliased = limbsAliasDistinct (r , a ) or limbsAliasDistinct (r , b );
3017+ const needed = calcTwosCompLimbCount (bit_count );
3018+ try r .ensureAliasAwareCapacity (needed , aliased );
30133019 var m = r .toMutable ();
30143020 const wrapped = m .addWrap (a .toConst (), b .toConst (), signedness , bit_count );
30153021 r .setMetadata (m .positive , m .len );
@@ -3022,7 +3028,9 @@ pub const Managed = struct {
30223028 ///
30233029 /// Returns an error if memory could not be allocated.
30243030 pub fn addSat (r : * Managed , a : * const Managed , b : * const Managed , signedness : Signedness , bit_count : usize ) Allocator.Error ! void {
3025- try r .ensureTwosCompCapacity (bit_count );
3031+ const aliased = limbsAliasDistinct (r , a ) or limbsAliasDistinct (r , b );
3032+ const needed = calcTwosCompLimbCount (bit_count );
3033+ try r .ensureAliasAwareCapacity (needed , aliased );
30263034 var m = r .toMutable ();
30273035 m .addSat (a .toConst (), b .toConst (), signedness , bit_count );
30283036 r .setMetadata (m .positive , m .len );
@@ -3034,7 +3042,9 @@ pub const Managed = struct {
30343042 ///
30353043 /// Returns an error if memory could not be allocated.
30363044 pub fn sub (r : * Managed , a : * const Managed , b : * const Managed ) ! void {
3037- try r .ensureCapacity (@max (a .len (), b .len ()) + 1 );
3045+ const aliased = limbsAliasDistinct (r , a ) or limbsAliasDistinct (r , b );
3046+ const needed = @max (a .len (), b .len ()) + 1 ;
3047+ try r .ensureAliasAwareCapacity (needed , aliased );
30383048 var m = r .toMutable ();
30393049 m .sub (a .toConst (), b .toConst ());
30403050 r .setMetadata (m .positive , m .len );
@@ -3052,7 +3062,9 @@ pub const Managed = struct {
30523062 signedness : Signedness ,
30533063 bit_count : usize ,
30543064 ) Allocator.Error ! bool {
3055- 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 );
30563068 var m = r .toMutable ();
30573069 const wrapped = m .subWrap (a .toConst (), b .toConst (), signedness , bit_count );
30583070 r .setMetadata (m .positive , m .len );
@@ -3071,7 +3083,9 @@ pub const Managed = struct {
30713083 signedness : Signedness ,
30723084 bit_count : usize ,
30733085 ) Allocator.Error ! void {
3074- try r .ensureTwosCompCapacity (bit_count );
3086+ const aliased = limbsAliasDistinct (r , a ) or limbsAliasDistinct (r , b );
3087+ const needed = calcTwosCompLimbCount (bit_count );
3088+ try r .ensureAliasAwareCapacity (needed , aliased );
30753089 var m = r .toMutable ();
30763090 m .subSat (a .toConst (), b .toConst (), signedness , bit_count );
30773091 r .setMetadata (m .positive , m .len );
@@ -3090,7 +3104,9 @@ pub const Managed = struct {
30903104 alias_count += 1 ;
30913105 if (rma .limbs .ptr == b .limbs .ptr )
30923106 alias_count += 1 ;
3093- try rma .ensureMulCapacity (a .toConst (), b .toConst ());
3107+ const needed = a .len () + b .len () + 1 ;
3108+ const capacity_alias = limbsAliasDistinct (rma , a ) or limbsAliasDistinct (rma , b );
3109+ try rma .ensureAliasAwareCapacity (needed , capacity_alias );
30943110 var m = rma .toMutable ();
30953111 if (alias_count == 0 ) {
30963112 m .mulNoAlias (a .toConst (), b .toConst (), rma .allocator );
@@ -3122,8 +3138,9 @@ pub const Managed = struct {
31223138 alias_count += 1 ;
31233139 if (rma .limbs .ptr == b .limbs .ptr )
31243140 alias_count += 1 ;
3125-
3126- try rma .ensureTwosCompCapacity (bit_count );
3141+ const needed = calcTwosCompLimbCount (bit_count );
3142+ const capacity_alias = limbsAliasDistinct (rma , a ) or limbsAliasDistinct (rma , b );
3143+ try rma .ensureAliasAwareCapacity (needed , capacity_alias );
31273144 var m = rma .toMutable ();
31283145 if (alias_count == 0 ) {
31293146 m .mulWrapNoAlias (a .toConst (), b .toConst (), signedness , bit_count , rma .allocator );
@@ -3140,26 +3157,54 @@ pub const Managed = struct {
31403157 try r .ensureCapacity (calcTwosCompLimbCount (bit_count ));
31413158 }
31423159
3160+ /// True if both `Managed` instances are distinct but share the same limbs buffer.
3161+ fn limbsAliasDistinct (a : * const Managed , b : * const Managed ) bool {
3162+ return @intFromPtr (a ) != @intFromPtr (b ) and a .limbs .ptr == b .limbs .ptr ;
3163+ }
3164+
3165+ /// Ensures capacity if not aliased. Requires enough capacity if aliased.
3166+ fn ensureAliasAwareCapacity (r : * Managed , needed : usize , aliased : bool ) ! void {
3167+ if (aliased ) {
3168+ assert (needed <= r .limbs .len );
3169+ } else {
3170+ try r .ensureCapacity (needed );
3171+ }
3172+ }
3173+
31433174 pub fn ensureAddScalarCapacity (r : * Managed , a : Const , scalar : anytype ) ! void {
31443175 try r .ensureCapacity (@max (a .limbs .len , calcLimbLen (scalar )) + 1 );
31453176 }
31463177
3178+ pub fn ensureAddScalarCapacityManaged (r : * Managed , a : * const Managed , scalar : anytype ) ! void {
3179+ try r .ensureCapacity (@max (a .len (), calcLimbLen (scalar )) + 1 );
3180+ }
3181+
31473182 pub fn ensureAddCapacity (r : * Managed , a : Const , b : Const ) ! void {
31483183 try r .ensureCapacity (@max (a .limbs .len , b .limbs .len ) + 1 );
31493184 }
31503185
3186+ pub fn ensureAddCapacityManaged (r : * Managed , a : * const Managed , b : * const Managed ) ! void {
3187+ try r .ensureCapacity (@max (a .len (), b .len ()) + 1 );
3188+ }
3189+
31513190 pub fn ensureMulCapacity (rma : * Managed , a : Const , b : Const ) ! void {
31523191 try rma .ensureCapacity (a .limbs .len + b .limbs .len + 1 );
31533192 }
31543193
3194+ pub fn ensureMulCapacityManaged (rma : * Managed , a : * const Managed , b : * const Managed ) ! void {
3195+ try rma .ensureCapacity (a .len () + b .len () + 1 );
3196+ }
3197+
31553198 /// q = a / b (rem r)
31563199 ///
31573200 /// a / b are floored (rounded towards 0).
31583201 ///
31593202 /// Returns an error if memory could not be allocated.
31603203 pub fn divFloor (q : * Managed , r : * Managed , a : * const Managed , b : * const Managed ) ! void {
3161- try q .ensureCapacity (a .len ());
3162- try r .ensureCapacity (b .len ());
3204+ const q_alias = limbsAliasDistinct (q , a ) or limbsAliasDistinct (q , b );
3205+ const r_alias = limbsAliasDistinct (r , a ) or limbsAliasDistinct (r , b );
3206+ try q .ensureAliasAwareCapacity (a .len (), q_alias );
3207+ try r .ensureAliasAwareCapacity (b .len (), r_alias );
31633208 var mq = q .toMutable ();
31643209 var mr = r .toMutable ();
31653210 const limbs_buffer = try q .allocator .alloc (Limb , calcDivLimbsBufferLen (a .len (), b .len ()));
@@ -3175,8 +3220,10 @@ pub const Managed = struct {
31753220 ///
31763221 /// Returns an error if memory could not be allocated.
31773222 pub fn divTrunc (q : * Managed , r : * Managed , a : * const Managed , b : * const Managed ) ! void {
3178- try q .ensureCapacity (a .len ());
3179- try r .ensureCapacity (b .len ());
3223+ const q_alias = limbsAliasDistinct (q , a ) or limbsAliasDistinct (q , b );
3224+ const r_alias = limbsAliasDistinct (r , a ) or limbsAliasDistinct (r , b );
3225+ try q .ensureAliasAwareCapacity (a .len (), q_alias );
3226+ try r .ensureAliasAwareCapacity (b .len (), r_alias );
31803227 var mq = q .toMutable ();
31813228 var mr = r .toMutable ();
31823229 const limbs_buffer = try q .allocator .alloc (Limb , calcDivLimbsBufferLen (a .len (), b .len ()));
@@ -3189,7 +3236,9 @@ pub const Managed = struct {
31893236 /// r = a << shift, in other words, r = a * 2^shift
31903237 /// r and a may alias.
31913238 pub fn shiftLeft (r : * Managed , a : * const Managed , shift : usize ) ! void {
3192- try r .ensureCapacity (a .len () + (shift / limb_bits ) + 1 );
3239+ const aliased = limbsAliasDistinct (r , a );
3240+ const needed = a .len () + (shift / limb_bits ) + 1 ;
3241+ try r .ensureAliasAwareCapacity (needed , aliased );
31933242 var m = r .toMutable ();
31943243 m .shiftLeft (a .toConst (), shift );
31953244 r .setMetadata (m .positive , m .len );
@@ -3198,7 +3247,9 @@ pub const Managed = struct {
31983247 /// r = a <<| shift with 2s-complement saturating semantics.
31993248 /// r and a may alias.
32003249 pub fn shiftLeftSat (r : * Managed , a : * const Managed , shift : usize , signedness : Signedness , bit_count : usize ) ! void {
3201- try r .ensureTwosCompCapacity (bit_count );
3250+ const aliased = limbsAliasDistinct (r , a );
3251+ const needed = calcTwosCompLimbCount (bit_count );
3252+ try r .ensureAliasAwareCapacity (needed , aliased );
32023253 var m = r .toMutable ();
32033254 m .shiftLeftSat (a .toConst (), shift , signedness , bit_count );
32043255 r .setMetadata (m .positive , m .len );
@@ -3220,7 +3271,9 @@ pub const Managed = struct {
32203271 return ;
32213272 }
32223273
3223- try r .ensureCapacity (a .len () - (shift / limb_bits ));
3274+ const aliased = limbsAliasDistinct (r , a );
3275+ const needed = a .len () - (shift / limb_bits );
3276+ try r .ensureAliasAwareCapacity (needed , aliased );
32243277 var m = r .toMutable ();
32253278 m .shiftRight (a .toConst (), shift );
32263279 r .setMetadata (m .positive , m .len );
@@ -3229,7 +3282,9 @@ pub const Managed = struct {
32293282 /// r = ~a under 2s-complement wrapping semantics.
32303283 /// r and a may alias.
32313284 pub fn bitNotWrap (r : * Managed , a : * const Managed , signedness : Signedness , bit_count : usize ) ! void {
3232- try r .ensureTwosCompCapacity (bit_count );
3285+ const aliased = limbsAliasDistinct (r , a );
3286+ const needed = calcTwosCompLimbCount (bit_count );
3287+ try r .ensureAliasAwareCapacity (needed , aliased );
32333288 var m = r .toMutable ();
32343289 m .bitNotWrap (a .toConst (), signedness , bit_count );
32353290 r .setMetadata (m .positive , m .len );
@@ -3239,7 +3294,9 @@ pub const Managed = struct {
32393294 ///
32403295 /// a and b are zero-extended to the longer of a or b.
32413296 pub fn bitOr (r : * Managed , a : * const Managed , b : * const Managed ) ! void {
3242- try r .ensureCapacity (@max (a .len (), b .len ()));
3297+ const aliased = limbsAliasDistinct (r , a ) or limbsAliasDistinct (r , b );
3298+ const needed = @max (a .len (), b .len ());
3299+ try r .ensureAliasAwareCapacity (needed , aliased );
32433300 var m = r .toMutable ();
32443301 m .bitOr (a .toConst (), b .toConst ());
32453302 r .setMetadata (m .positive , m .len );
@@ -3251,7 +3308,8 @@ pub const Managed = struct {
32513308 if (b .isPositive ()) b .len () else if (a .isPositive ()) a .len () else a .len () + 1
32523309 else if (a .isPositive ()) a .len () else if (b .isPositive ()) b .len () else b .len () + 1 ;
32533310
3254- try r .ensureCapacity (cap );
3311+ const aliased = limbsAliasDistinct (r , a ) or limbsAliasDistinct (r , b );
3312+ try r .ensureAliasAwareCapacity (cap , aliased );
32553313 var m = r .toMutable ();
32563314 m .bitAnd (a .toConst (), b .toConst ());
32573315 r .setMetadata (m .positive , m .len );
@@ -3260,7 +3318,8 @@ pub const Managed = struct {
32603318 /// r = a ^ b
32613319 pub fn bitXor (r : * Managed , a : * const Managed , b : * const Managed ) ! void {
32623320 const cap = @max (a .len (), b .len ()) + @intFromBool (a .isPositive () != b .isPositive ());
3263- try r .ensureCapacity (cap );
3321+ const aliased = limbsAliasDistinct (r , a ) or limbsAliasDistinct (r , b );
3322+ try r .ensureAliasAwareCapacity (cap , aliased );
32643323
32653324 var m = r .toMutable ();
32663325 m .bitXor (a .toConst (), b .toConst ());
@@ -3272,7 +3331,9 @@ pub const Managed = struct {
32723331 ///
32733332 /// rma's allocator is used for temporary storage to boost multiplication performance.
32743333 pub fn gcd (rma : * Managed , x : * const Managed , y : * const Managed ) ! void {
3275- try rma .ensureCapacity (@min (x .len (), y .len ()));
3334+ const aliased = limbsAliasDistinct (rma , x ) or limbsAliasDistinct (rma , y );
3335+ const needed = @min (x .len (), y .len ());
3336+ try rma .ensureAliasAwareCapacity (needed , aliased );
32763337 var m = rma .toMutable ();
32773338 var limbs_buffer = std .array_list .Managed (Limb ).init (rma .allocator );
32783339 defer limbs_buffer .deinit ();
@@ -3350,15 +3411,19 @@ pub const Managed = struct {
33503411
33513412 /// r = truncate(Int(signedness, bit_count), a)
33523413 pub fn truncate (r : * Managed , a : * const Managed , signedness : Signedness , bit_count : usize ) ! void {
3353- try r .ensureCapacity (calcTwosCompLimbCount (bit_count ));
3414+ const aliased = limbsAliasDistinct (r , a );
3415+ const needed = calcTwosCompLimbCount (bit_count );
3416+ try r .ensureAliasAwareCapacity (needed , aliased );
33543417 var m = r .toMutable ();
33553418 m .truncate (a .toConst (), signedness , bit_count );
33563419 r .setMetadata (m .positive , m .len );
33573420 }
33583421
33593422 /// r = saturate(Int(signedness, bit_count), a)
33603423 pub fn saturate (r : * Managed , a : * const Managed , signedness : Signedness , bit_count : usize ) ! void {
3361- try r .ensureCapacity (calcTwosCompLimbCount (bit_count ));
3424+ const aliased = limbsAliasDistinct (r , a );
3425+ const needed = calcTwosCompLimbCount (bit_count );
3426+ try r .ensureAliasAwareCapacity (needed , aliased );
33623427 var m = r .toMutable ();
33633428 m .saturate (a .toConst (), signedness , bit_count );
33643429 r .setMetadata (m .positive , m .len );
@@ -3367,7 +3432,9 @@ pub const Managed = struct {
33673432 /// r = @popCount(a) with 2s-complement semantics.
33683433 /// r and a may be aliases.
33693434 pub fn popCount (r : * Managed , a : * const Managed , bit_count : usize ) ! void {
3370- try r .ensureCapacity (calcTwosCompLimbCount (bit_count ));
3435+ const aliased = limbsAliasDistinct (r , a );
3436+ const needed = calcTwosCompLimbCount (bit_count );
3437+ try r .ensureAliasAwareCapacity (needed , aliased );
33713438 var m = r .toMutable ();
33723439 m .popCount (a .toConst (), bit_count );
33733440 r .setMetadata (m .positive , m .len );
0 commit comments