Skip to content

Commit 2113507

Browse files
Create two new versions of InlineNumeric
Create version of InlineNumeric that extends Numeric. This requires: - dropping the inline keyword for parameters (cannot override non-inline parameter with inline parameter) - dropping abs, sign, zero and one from InlineNumeric (see code for the errors). Instead, override them in the given instances Create version of InlineNumeric with extension methods defined in the traits instead of in the companion objects. This allows the usage of said methods without having to import them. The inconvenient is that the overriding must be done with extension methods, but since an extension method object A: extension (x: T) def foo: U = ??? can be called both like x.foo and A.foo(x), this allows for both forms when performing operations such as toInt.
1 parent 563f2c5 commit 2113507

File tree

2 files changed

+505
-0
lines changed

2 files changed

+505
-0
lines changed

InlineNumeric-extendsNumeric.scala

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
import scala.util.Try
2+
3+
trait InlineNumeric[T] extends Numeric[T]:
4+
transparent inline def plus(x: T, y: T): T
5+
transparent inline def minus(x: T, y: T): T
6+
transparent inline def times(x: T, y: T): T
7+
transparent inline def negate(x: T): T
8+
transparent inline def fromInt(x: Int): T
9+
transparent inline def parseString(str: String): Option[T]
10+
transparent inline def toInt(x: T): Int
11+
transparent inline def toLong(x: T): Long
12+
transparent inline def toFloat(x: T): Float
13+
transparent inline def toDouble(x: T): Double
14+
15+
// error overriding method abs in trait InlineNumeric of type (x: T): T;
16+
// method abs in trait Numeric of type (x: T): T is not inline, cannot implement an inline method
17+
//transparent inline def abs(x: T): T
18+
//transparent inline def sign(x: T): T
19+
20+
// Deferred inline method fromInt in trait InlineNumeric cannot be invoked
21+
//transparent inline def zero = fromInt(0)
22+
//transparent inline def one = fromInt(1)
23+
24+
object InlineNumeric:
25+
extension [T](x: T)(using num: InlineNumeric[T])
26+
transparent inline def +(y: T): T = num.plus(x, y)
27+
transparent inline def -(y: T) = num.minus(x, y)
28+
transparent inline def *(y: T): T = num.times(x, y)
29+
transparent inline def unary_- = num.negate(x)
30+
transparent inline def toInt: Int = num.toInt(x)
31+
transparent inline def toLong: Long = num.toLong(x)
32+
transparent inline def toFloat: Float = num.toFloat(x)
33+
transparent inline def toDouble: Double = num.toDouble(x)
34+
transparent inline def abs: T = num.abs(x)
35+
transparent inline def sign: T = num.sign(x)
36+
37+
trait InlineIntegral[T] extends InlineNumeric[T]:
38+
transparent inline def quot(x: T, y: T): T
39+
transparent inline def rem(x: T, y: T): T
40+
41+
object InlineIntegral:
42+
extension [T](lhs: T)(using int: InlineIntegral[T])
43+
transparent inline def /(rhs: T) = int.quot(lhs, rhs)
44+
transparent inline def %(rhs: T) = int.rem(lhs, rhs)
45+
transparent inline def /%(rhs: T) = (int.quot(lhs, rhs), int.rem(lhs, rhs))
46+
47+
trait InlineFractional[T] extends InlineNumeric[T]:
48+
transparent inline def div(x: T, y: T): T
49+
50+
object InlineFractional:
51+
extension [T](lhs: T)(using frac: InlineFractional[T])
52+
transparent inline def /(rhs: T) = frac.div(lhs, rhs)
53+
54+
given IntIsInlineIntegral: InlineIntegral[Int] with Ordering.IntOrdering with
55+
transparent inline def plus(x: Int, y: Int): Int = x + y
56+
transparent inline def minus(x: Int, y: Int): Int = x - y
57+
transparent inline def times(x: Int, y: Int): Int = x * y
58+
transparent inline def negate(x: Int): Int = -x
59+
transparent inline def fromInt(x: Int): Int = x
60+
transparent inline def parseString(str: String): Option[Int] = str.toIntOption
61+
transparent inline def toInt(x: Int): Int = x
62+
transparent inline def toLong(x: Int): Long = x.toLong
63+
transparent inline def toFloat(x: Int): Float = x.toFloat
64+
transparent inline def toDouble(x: Int): Double = x.toDouble
65+
transparent override inline def abs(x: Int): Int = math.abs(x)
66+
transparent override inline def sign(x: Int): Int = math.signum(x)
67+
68+
transparent inline def quot(x: Int, y: Int): Int = x / y
69+
transparent inline def rem(x: Int, y: Int): Int = x % y
70+
71+
given BigIntIsInlineIntegral: InlineIntegral[BigInt] with Ordering.BigIntOrdering with
72+
transparent inline def plus(x: BigInt, y: BigInt): BigInt = x + y
73+
transparent inline def minus(x: BigInt, y: BigInt): BigInt = x - y
74+
transparent inline def times(x: BigInt, y: BigInt): BigInt = x * y
75+
transparent inline def negate(x: BigInt): BigInt = -x
76+
transparent inline def fromInt(x: Int): BigInt = BigInt(x)
77+
transparent inline def parseString(str: String): Option[BigInt] = Try(BigInt(str)).toOption
78+
transparent inline def toInt(x: BigInt): Int = x.intValue
79+
transparent inline def toLong(x: BigInt): Long = x.longValue
80+
transparent inline def toFloat(x: BigInt): Float = x.floatValue
81+
transparent inline def toDouble(x: BigInt): Double = x.doubleValue
82+
transparent override inline def abs(x: BigInt): BigInt = x.abs
83+
transparent override inline def sign(x: BigInt): BigInt = x.sign
84+
85+
transparent inline def quot(x: BigInt, y: BigInt): BigInt = x / y
86+
transparent inline def rem(x: BigInt, y: BigInt): BigInt = x % y
87+
88+
given ShortIsInlineIntegral: InlineIntegral[Short] with Ordering.ShortOrdering with
89+
transparent inline def plus(x: Short, y: Short): Short = (x + y).toShort
90+
transparent inline def minus(x: Short, y: Short): Short = (x - y).toShort
91+
transparent inline def times(x: Short, y: Short): Short = (x * y).toShort
92+
transparent inline def negate(x: Short): Short = (-x).toShort
93+
transparent inline def fromInt(x: Int): Short = x.toShort
94+
transparent inline def parseString(str: String): Option[Short] = str.toShortOption
95+
transparent inline def toInt(x: Short): Int = x.toInt
96+
transparent inline def toLong(x: Short): Long = x.toLong
97+
transparent inline def toFloat(x: Short): Float = x.toFloat
98+
transparent inline def toDouble(x: Short): Double = x.toDouble
99+
transparent override inline def abs(x: Short): Short = math.abs(x).toShort
100+
transparent override inline def sign(x: Short): Short = math.signum(x).toShort
101+
102+
transparent inline def quot(x: Short, y: Short): Short = (x / y).toShort
103+
transparent inline def rem(x: Short, y: Short): Short = (x % y).toShort
104+
105+
given ByteIsInlineIntegral: InlineIntegral[Byte] with Ordering.ByteOrdering with
106+
transparent inline def plus(x: Byte, y: Byte): Byte = (x + y).toByte
107+
transparent inline def minus(x: Byte, y: Byte): Byte = (x - y).toByte
108+
transparent inline def times(x: Byte, y: Byte): Byte = (x * y).toByte
109+
transparent inline def negate(x: Byte): Byte = (-x).toByte
110+
transparent inline def fromInt(x: Int): Byte = x.toByte
111+
transparent inline def parseString(str: String): Option[Byte] = str.toByteOption
112+
transparent inline def toInt(x: Byte): Int = x.toInt
113+
transparent inline def toLong(x: Byte): Long = x.toLong
114+
transparent inline def toFloat(x: Byte): Float = x.toFloat
115+
transparent inline def toDouble(x: Byte): Double = x.toDouble
116+
transparent override inline def abs(x: Byte): Byte = math.abs(x).toByte
117+
transparent override inline def sign(x: Byte): Byte = math.signum(x).toByte
118+
119+
transparent inline def quot(x: Byte, y: Byte): Byte = (x / y).toByte
120+
transparent inline def rem(x: Byte, y: Byte): Byte = (x % y).toByte
121+
122+
given CharIsInlineIntegral: InlineIntegral[Char] with Ordering.CharOrdering with
123+
transparent inline def plus(x: Char, y: Char): Char = (x + y).toChar
124+
transparent inline def minus(x: Char, y: Char): Char = (x - y).toChar
125+
transparent inline def times(x: Char, y: Char): Char = (x * y).toChar
126+
transparent inline def negate(x: Char): Char = (-x).toChar
127+
transparent inline def fromInt(x: Int): Char = x.toChar
128+
transparent inline def parseString(str: String): Option[Char] = Try(str.toInt.toChar).toOption
129+
transparent inline def toInt(x: Char): Int = x.toInt
130+
transparent inline def toLong(x: Char): Long = x.toLong
131+
transparent inline def toFloat(x: Char): Float = x.toFloat
132+
transparent inline def toDouble(x: Char): Double = x.toDouble
133+
transparent override inline def abs(x: Char): Char = math.abs(x).toChar
134+
transparent override inline def sign(x: Char): Char = math.signum(x).toChar
135+
136+
transparent inline def quot(x: Char, y: Char): Char = (x / y).toChar
137+
transparent inline def rem(x: Char, y: Char): Char = (x % y).toChar
138+
139+
given LongIsInlineIntegral: InlineIntegral[Long] with Ordering.LongOrdering with
140+
transparent inline def plus(x: Long, y: Long): Long = x + y
141+
transparent inline def minus(x: Long, y: Long): Long = x - y
142+
transparent inline def times(x: Long, y: Long): Long = x * y
143+
transparent inline def negate(x: Long): Long = -x
144+
transparent inline def fromInt(x: Int): Long = x.toLong
145+
transparent inline def parseString(str: String): Option[Long] = str.toLongOption
146+
transparent inline def toInt(x: Long): Int = x.toInt
147+
transparent inline def toLong(x: Long): Long = x
148+
transparent inline def toFloat(x: Long): Float = x.toFloat
149+
transparent inline def toDouble(x: Long): Double = x.toDouble
150+
transparent override inline def abs(x: Long): Long = math.abs(x)
151+
transparent override inline def sign(x: Long): Long = math.signum(x)
152+
153+
transparent inline def quot(x: Long, y: Long): Long = (x / y).toLong
154+
transparent inline def rem(x: Long, y: Long): Long = (x % y).toLong
155+
156+
given FloatIsInlineFractional: InlineFractional[Float] with Ordering.Float.IeeeOrdering with
157+
transparent inline def plus(x: Float, y: Float): Float = x + y
158+
transparent inline def minus(x: Float, y: Float): Float = x - y
159+
transparent inline def times(x: Float, y: Float): Float = x * y
160+
transparent inline def negate(x: Float): Float = -x
161+
transparent inline def fromInt(x: Int): Float = x.toFloat
162+
transparent inline def parseString(str: String): Option[Float] = str.toFloatOption
163+
transparent inline def toInt(x: Float): Int = x.toInt
164+
transparent inline def toLong(x: Float): Long = x.toLong
165+
transparent inline def toFloat(x: Float): Float = x
166+
transparent inline def toDouble(x: Float): Double = x.toDouble
167+
transparent override inline def abs(x: Float): Float = math.abs(x)
168+
transparent override inline def sign(x: Float): Float = math.signum(x)
169+
170+
transparent inline def div(x: Float, y: Float): Float = x / y
171+
172+
given DoubleIsInlineFractional: InlineFractional[Double] with Ordering.Double.IeeeOrdering with
173+
transparent inline def plus(x: Double, y: Double): Double = x + y
174+
transparent inline def minus(x: Double, y: Double): Double = x - y
175+
transparent inline def times(x: Double, y: Double): Double = x * y
176+
transparent inline def negate(x: Double): Double = -x
177+
transparent inline def fromInt(x: Int): Double = x.toDouble
178+
transparent inline def parseString(str: String): Option[Double] = str.toDoubleOption
179+
transparent inline def toInt(x: Double): Int = x.toInt
180+
transparent inline def toLong(x: Double): Long = x.toLong
181+
transparent inline def toFloat(x: Double): Float = x.toFloat
182+
transparent inline def toDouble(x: Double): Double = x
183+
transparent override inline def abs(x: Double): Double = math.abs(x)
184+
transparent override inline def sign(x: Double): Double = math.signum(x)
185+
186+
transparent inline def div(x: Double, y: Double): Double = x / y
187+
188+
trait BigDecimalIsConflicted extends InlineNumeric[BigDecimal] with Ordering.BigDecimalOrdering:
189+
transparent inline def plus(x: BigDecimal, y: BigDecimal): BigDecimal = x + y
190+
transparent inline def minus(x: BigDecimal, y: BigDecimal): BigDecimal = x - y
191+
transparent inline def times(x: BigDecimal, y: BigDecimal): BigDecimal = x * y
192+
transparent inline def negate(x: BigDecimal): BigDecimal = -x
193+
transparent inline def fromInt(x: Int): BigDecimal = BigDecimal(x)
194+
transparent inline def parseString(str: String): Option[BigDecimal] = Try(BigDecimal(str)).toOption
195+
transparent inline def toInt(x: BigDecimal): Int = x.intValue
196+
transparent inline def toLong(x: BigDecimal): Long = x.longValue
197+
transparent inline def toFloat(x: BigDecimal): Float = x.floatValue
198+
transparent inline def toDouble(x: BigDecimal): Double = x.doubleValue
199+
transparent override inline def abs(x: BigDecimal): BigDecimal = x.abs
200+
transparent override inline def sign(x: BigDecimal): BigDecimal = x.sign
201+
202+
given BigDecimalIsInlineFractional: BigDecimalIsConflicted with InlineFractional[BigDecimal] with
203+
transparent inline def div(x: BigDecimal, y: BigDecimal): BigDecimal = x / y
204+
205+
given BigDecimalAsIfInlineIntegral: BigDecimalIsConflicted with InlineIntegral[BigDecimal] with
206+
transparent inline def quot(x: BigDecimal, y: BigDecimal): BigDecimal = x quot y
207+
transparent inline def rem(x: BigDecimal, y: BigDecimal): BigDecimal = x remainder y
208+
209+
object tests:
210+
import InlineNumeric.*
211+
import InlineIntegral.{/ => ¦, %}
212+
import InlineFractional./
213+
214+
inline def foo[T: InlineNumeric](a: T, b: T) =
215+
a + b * b
216+
217+
inline def div[T: InlineIntegral](a: T, b: T) =
218+
a ¦ b % b
219+
220+
inline def div[T: InlineFractional](a: T, b: T) =
221+
a / b + a
222+
223+
inline def bar[T: InlineNumeric](a: T) = a.toInt
224+
225+
inline def sign[T: InlineNumeric](a: T) = a.sign
226+
227+
def test(a: Int, b: Int) =
228+
val v1 = foo(a, b) // should be a + b * b // can check with -Xprint:inlining
229+
val v2 = foo(a.toShort, b.toShort) // should be a + b * b
230+
231+
val v3 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalAsIfInlineIntegral) // should be BigDecimal(a) quot BigDecimal(b) remainder BigDecimal(b)
232+
val v4 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalIsInlineFractional) // should be BigDecimal(a) / BigDecimal(b) + BigDecimal(a)
233+
234+
val v5 = bar(a.toFloat) // should be a.toFloat.toInt
235+
val v6 = bar(a) // should be a
236+
237+
val v7 = sign(a)
238+
val v8 = sign(a.toChar)
239+
val v9 = sign(-7F)
240+
241+
val v10 = sign(BigDecimal(a))(using BigDecimalAsIfInlineIntegral)
242+
val v11 = sign(BigDecimal(a))(using BigDecimalIsInlineFractional) // the condition with isNan() should be removed, i.e. it should be equivalent to v10

0 commit comments

Comments
 (0)