Skip to content

Commit

Permalink
[RFC 58] Add partial arithmetic for integer types (#2865)
Browse files Browse the repository at this point in the history
* [RFC 58] Add partial arithmetic for integer types

* fix failing VerifyTest.PartialSugaredBinaryOperatorCall

as it mapped +? to partial add, not to add_partial
so in this respect, a class could not have both methods, but the integer typed need to have.

* remove division test

this one should be included in another PR fixing the underlying issue with
detecting overflow on division for I128 on platforms without native 128 bit int support

* remove empty lines [skip ci]
  • Loading branch information
mfelsche authored and jemc committed Aug 29, 2018
1 parent 38bb038 commit 85efc78
Show file tree
Hide file tree
Showing 10 changed files with 543 additions and 68 deletions.
65 changes: 65 additions & 0 deletions packages/builtin/_partial_arithmetic.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@

trait _PartialArithmetic
fun add_partial[T: (Integer[T] val & Int)](x: T, y: T): T? =>
(let r: T, let overflow: Bool) = x.addc(y)
if overflow then error else r end

fun sub_partial[T: (Integer[T] val & Int)](x: T, y: T): T? =>
(let r: T, let overflow: Bool) = x.subc(y)
if overflow then error else r end

fun mul_partial[T: (Integer[T] val & Int)](x: T, y: T): T? =>
(let r: T, let overflow: Bool) = x.mulc(y)
if overflow then error else r end

primitive _UnsignedPartialArithmetic is _PartialArithmetic
fun div_partial[T: _UnsignedInteger[T] val](x: T, y: T): T? =>
if (y == T.from[U8](0)) then
error
else
x /~ y
end

fun mod_partial[T: _UnsignedInteger[T] val](x: T, y: T): T? =>
if (y == T.from[U8](0)) then
error
else
x %~ y
end

fun divmod_partial[T: _UnsignedInteger[T] val](x: T, y: T): (T, T)? =>
if (y == T.from[U8](0)) then
error
else
(x /~ y, x %~ y)
end

primitive _SignedPartialArithmetic is _PartialArithmetic

fun div_partial[T: (_SignedInteger[T, U] val & Signed), U: _UnsignedInteger[U] val](x: T, y: T): T? =>
if (y == T.from[I8](0)) or ((y == T.from[I8](I8(-1))) and (x == T.min_value())) then
error
else
x /~ y
end

fun mod_partial[T: (_SignedInteger[T, U] val & Signed), U: _UnsignedInteger[U] val](x: T, y: T): T? =>
if (y == T.from[I8](0)) or ((y == T.from[I8](I8(-1))) and (x == T.min_value())) then
error
else
x %~ y
end

fun divmod_partial[T: (_SignedInteger[T, U] val & Signed), U: _UnsignedInteger[U] val](x: T, y: T): (T, T)? =>
if (y == T.from[I8](0)) or ((y == T.from[I8](I8(-1))) and (x == T.min_value())) then
error
else
(x/~y, x %~ y)
end

fun neg_partial[T: (_SignedInteger[T, U] val & Signed), U: _UnsignedInteger[U] val](x: T): T? =>
if x == T.min_value() then
error
else
-~x
end
46 changes: 46 additions & 0 deletions packages/builtin/real.pony
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,48 @@ trait val Integer[A: Integer[A] val] is Real[A]
"""
this %~ y

fun add_partial(y: A): A ?
"""
Add y to this number.
If the operation overflows this function errors.
"""

fun sub_partial(y: A): A ?
"""
Subtract y from this number.
If the operation overflows/underflows this function errors.
"""

fun mul_partial(y: A): A ?
"""
Multiply y with this number.
If the operation overflows this function errors.
"""

fun div_partial(y: A): A ?
"""
Divides this number by y.
If y is `0` this function errors.
"""

fun mod_partial(y: A): A ?
"""
Calculates the remainder of this number divided by y.
If y is `0` this function errors.
"""

fun divmod_partial(y: A): (A, A) ?
"""
Divides this number by y and calculates the remainder of the operation.
If y is `0` this function errors.
"""

fun neg_unsafe(): A =>
"""
Unsafe operation.
Expand Down Expand Up @@ -350,12 +392,16 @@ trait val _UnsignedInteger[A: _UnsignedInteger[A] val] is Integer[A]

fun clz_unsafe(): A
"""
Count leading zeroes.
Unsafe operation.
If this is 0, the result is undefined.
"""

fun ctz_unsafe(): A
"""
Count trailing zeroes.
Unsafe operation.
If this is 0, the result is undefined.
"""
Expand Down
126 changes: 126 additions & 0 deletions packages/builtin/signed.pony
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,24 @@ primitive I8 is _SignedInteger[I8, U8]
fun mulc(y: I8): (I8, Bool) =>
@"llvm.smul.with.overflow.i8"[(I8, Bool)](this, y)

fun add_partial(y: I8): I8 ? =>
_SignedPartialArithmetic.add_partial[I8](this, y)?

fun sub_partial(y: I8): I8 ? =>
_SignedPartialArithmetic.sub_partial[I8](this, y)?

fun mul_partial(y: I8): I8 ? =>
_SignedPartialArithmetic.mul_partial[I8](this, y)?

fun div_partial(y: I8): I8 ? =>
_SignedPartialArithmetic.div_partial[I8, U8](this, y)?

fun mod_partial(y: I8): I8 ? =>
_SignedPartialArithmetic.mod_partial[I8, U8](this, y)?

fun divmod_partial(y: I8): (I8, I8) ? =>
_SignedPartialArithmetic.divmod_partial[I8, U8](this, y)?

primitive I16 is _SignedInteger[I16, U16]
new create(value: I16) => value
new from[A: (Number & Real[A] val)](a: A) => a.i16()
Expand Down Expand Up @@ -82,6 +100,25 @@ primitive I16 is _SignedInteger[I16, U16]
fun mulc(y: I16): (I16, Bool) =>
@"llvm.smul.with.overflow.i16"[(I16, Bool)](this, y)

fun add_partial(y: I16): I16 ? =>
_SignedPartialArithmetic.add_partial[I16](this, y)?

fun sub_partial(y: I16): I16 ? =>
_SignedPartialArithmetic.sub_partial[I16](this, y)?

fun mul_partial(y: I16): I16 ? =>
_SignedPartialArithmetic.mul_partial[I16](this, y)?

fun div_partial(y: I16): I16 ? =>
_SignedPartialArithmetic.div_partial[I16, U16](this, y)?

fun mod_partial(y: I16): I16 ? =>
_SignedPartialArithmetic.mod_partial[I16, U16](this, y)?

fun divmod_partial(y: I16): (I16, I16) ? =>
_SignedPartialArithmetic.divmod_partial[I16, U16](this, y)?


primitive I32 is _SignedInteger[I32, U32]
new create(value: I32) => value
new from[A: (Number & Real[A] val)](a: A) => a.i32()
Expand Down Expand Up @@ -124,6 +161,24 @@ primitive I32 is _SignedInteger[I32, U32]
fun mulc(y: I32): (I32, Bool) =>
@"llvm.smul.with.overflow.i32"[(I32, Bool)](this, y)

fun add_partial(y: I32): I32 ? =>
_SignedPartialArithmetic.add_partial[I32](this, y)?

fun sub_partial(y: I32): I32 ? =>
_SignedPartialArithmetic.sub_partial[I32](this, y)?

fun mul_partial(y: I32): I32 ? =>
_SignedPartialArithmetic.mul_partial[I32](this, y)?

fun div_partial(y: I32): I32 ? =>
_SignedPartialArithmetic.div_partial[I32, U32](this, y)?

fun mod_partial(y: I32): I32 ? =>
_SignedPartialArithmetic.mod_partial[I32, U32](this, y)?

fun divmod_partial(y: I32): (I32, I32) ? =>
_SignedPartialArithmetic.divmod_partial[I32, U32](this, y)?

primitive I64 is _SignedInteger[I64, U64]
new create(value: I64) => value
new from[A: (Number & Real[A] val)](a: A) => a.i64()
Expand Down Expand Up @@ -167,6 +222,23 @@ primitive I64 is _SignedInteger[I64, U64]
fun mulc(y: I64): (I64, Bool) =>
_SignedCheckedArithmetic._mulc[U64, I64](this, y)

fun add_partial(y: I64): I64 ? =>
_SignedPartialArithmetic.add_partial[I64](this, y)?

fun sub_partial(y: I64): I64 ? =>
_SignedPartialArithmetic.sub_partial[I64](this, y)?

fun mul_partial(y: I64): I64 ? =>
_SignedPartialArithmetic.mul_partial[I64](this, y)?

fun div_partial(y: I64): I64 ? =>
_SignedPartialArithmetic.div_partial[I64, U64](this, y)?

fun mod_partial(y: I64): I64 ? =>
_SignedPartialArithmetic.mod_partial[I64, U64](this, y)?

fun divmod_partial(y: I64): (I64, I64) ? =>
_SignedPartialArithmetic.divmod_partial[I64, U64](this, y)?

primitive ILong is _SignedInteger[ILong, ULong]
new create(value: ILong) => value
Expand Down Expand Up @@ -263,6 +335,24 @@ primitive ILong is _SignedInteger[ILong, ULong]
_SignedCheckedArithmetic._mulc[ULong, ILong](this, y)
end

fun add_partial(y: ILong): ILong ? =>
_SignedPartialArithmetic.add_partial[ILong](this, y)?

fun sub_partial(y: ILong): ILong ? =>
_SignedPartialArithmetic.sub_partial[ILong](this, y)?

fun mul_partial(y: ILong): ILong ? =>
_SignedPartialArithmetic.mul_partial[ILong](this, y)?

fun div_partial(y: ILong): ILong ? =>
_SignedPartialArithmetic.div_partial[ILong, ULong](this, y)?

fun mod_partial(y: ILong): ILong ? =>
_SignedPartialArithmetic.mod_partial[ILong, ULong](this, y)?

fun divmod_partial(y: ILong): (ILong, ILong) ? =>
_SignedPartialArithmetic.divmod_partial[ILong, ULong](this, y)?

primitive ISize is _SignedInteger[ISize, USize]
new create(value: ISize) => value
new from[A: (Number & Real[A] val)](a: A) => a.isize()
Expand Down Expand Up @@ -357,6 +447,24 @@ primitive ISize is _SignedInteger[ISize, USize]
_SignedCheckedArithmetic._mulc[USize, ISize](this, y)
end

fun add_partial(y: ISize): ISize ? =>
_SignedPartialArithmetic.add_partial[ISize](this, y)?

fun sub_partial(y: ISize): ISize ? =>
_SignedPartialArithmetic.sub_partial[ISize](this, y)?

fun mul_partial(y: ISize): ISize ? =>
_SignedPartialArithmetic.mul_partial[ISize](this, y)?

fun div_partial(y: ISize): ISize ? =>
_SignedPartialArithmetic.div_partial[ISize, USize](this, y)?

fun mod_partial(y: ISize): ISize ? =>
_SignedPartialArithmetic.mod_partial[ISize, USize](this, y)?

fun divmod_partial(y: ISize): (ISize, ISize) ? =>
_SignedPartialArithmetic.divmod_partial[ISize, USize](this, y)?

primitive I128 is _SignedInteger[I128, U128]
new create(value: I128) => value
new from[A: (Number & Real[A] val)](a: A) => a.i128()
Expand Down Expand Up @@ -547,6 +655,24 @@ primitive I128 is _SignedInteger[I128, U128]
// doing
_SignedCheckedArithmetic._mulc[U128, I128](this, y)

fun add_partial(y: I128): I128 ? =>
_SignedPartialArithmetic.add_partial[I128](this, y)?

fun sub_partial(y: I128): I128 ? =>
_SignedPartialArithmetic.sub_partial[I128](this, y)?

fun mul_partial(y: I128): I128 ? =>
_SignedPartialArithmetic.mul_partial[I128](this, y)?

fun div_partial(y: I128): I128 ? =>
_SignedPartialArithmetic.div_partial[I128, U128](this, y)?

fun mod_partial(y: I128): I128 ? =>
_SignedPartialArithmetic.mod_partial[I128, U128](this, y)?

fun divmod_partial(y: I128): (I128, I128) ? =>
_SignedPartialArithmetic.divmod_partial[I128, U128](this, y)?

type Signed is (I8 | I16 | I32 | I64 | I128 | ILong | ISize)


Expand Down
Loading

0 comments on commit 85efc78

Please sign in to comment.