Skip to content

Commit 0a88b72

Browse files
Michel CharpentierMichel Charpentier
authored andcommitted
Version 1.5.1.
- Update Scala to 3.3.5 - Some internals slightly rewritten; no change to API.
1 parent 8d62383 commit 0a88b72

File tree

107 files changed

+2914
-2224
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+2914
-2224
lines changed

S/src/main/scala/tinyscalautils/control/interruptibly.scala

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,49 +21,50 @@ private inline def check[A](inline code: A): A =
2121
@throws[InterruptedException]
2222
inline def interruptibly[A](inline code: A): A = check(code)
2323

24-
extension [I, O](f: I => O)
25-
/** @define text1
26-
* Makes a function responsive to interrupts: `f.interruptibly` has the same behavior as `f`
27-
* except that it checks for interrupts before each invocation. Additionally,
28-
* `f.interruptibly` checks for interrupts once, before the resulting function is used.
29-
*
30-
* @note
31-
* This is only implemented for functions of arity 1 and 2. For higher arities, one can use
32-
* `untupled(f.tupled.interruptibly)`.
33-
*
34-
* @since 1.5
35-
*
36-
* $text1
37-
*/
38-
@throws[InterruptedException]
39-
def interruptibly: I => O = check(x => check(f(x)))
24+
given InterruptiblyExtensions: AnyRef with
25+
extension [I, O](f: I => O)
26+
/** @define text1
27+
* Makes a function responsive to interrupts: `f.interruptibly` has the same behavior as
28+
* `f` except that it checks for interrupts before each invocation. Additionally,
29+
* `f.interruptibly` checks for interrupts once, before the resulting function is used.
30+
*
31+
* @note
32+
* This is only implemented for functions of arity 1 and 2. For higher arities, one can use
33+
* `untupled(f.tupled.interruptibly)`.
34+
*
35+
* @since 1.5
36+
*
37+
* $text1
38+
*/
39+
@throws[InterruptedException]
40+
def interruptibly: I => O = check(x => check(f(x)))
4041

41-
extension [I1, I2, O](f: (I1, I2) => O)
42-
/** $text1 */
43-
@throws[InterruptedException]
44-
def interruptibly: (I1, I2) => O = check((x, y) => check(f(x, y)))
42+
extension [I1, I2, O](f: (I1, I2) => O)
43+
/** $text1 */
44+
@throws[InterruptedException]
45+
def interruptibly: (I1, I2) => O = check((x, y) => check(f(x, y)))
4546

46-
extension [I, O1, O2](h: (I => O1) => O2)
47-
/** @define text2
48-
* Makes the function argument of a higher-order function `h` responsive to interrupts:
49-
* `h.interruptiby(f)` is equivalent to `h(f.interruptibly)` but is more convenient when `f`
50-
* is defined as a lambda expression, e.g.: `list.forall.interruptibly(x => x > 0)`.
51-
*
52-
* @note
53-
* This handling of higher-order functions only works with arguments `f` or arity 1 and
54-
* 2. If `f` is a 3-argument function, for instance, `h.interruptibly(f)` is equivalent to
55-
* `interruptibly(h(f))` instead. To achieved the desired behavior, one can use
56-
* `h(untupled(f.tupled.interruptibly))`.
57-
*
58-
* @since 1.5
59-
*
60-
* $text2
61-
*/
62-
@throws[InterruptedException]
63-
def interruptibly(using DummyImplicit): (I => O1) => O2 = f => h(f.interruptibly)
47+
extension [I, O1, O2](h: (I => O1) => O2)(using DummyImplicit)
48+
/** @define text2
49+
* Makes the function argument of a higher-order function `h` responsive to interrupts:
50+
* `h.interruptiby(f)` is equivalent to `h(f.interruptibly)` but is more convenient when
51+
* `f` is defined as a lambda expression, e.g.: `list.forall.interruptibly(x => x > 0)`.
52+
*
53+
* @note
54+
* This handling of higher-order functions only works with arguments `f` or arity 1 and
55+
* 2. If `f` is a 3-argument function, for instance, `h.interruptibly(f)` is equivalent to
56+
* `interruptibly(h(f))` instead. To achieved the desired behavior, one can use
57+
* `h(untupled(f.tupled.interruptibly))`.
58+
*
59+
* @since 1.5
60+
*
61+
* $text2
62+
*/
63+
@throws[InterruptedException]
64+
def interruptibly: (I => O1) => O2 = f => h(f.interruptibly)
6465

65-
extension [I1, I2, O1, O2](h: ((I1, I2) => O1) => O2)
66-
/** $text2 */
67-
@throws[InterruptedException]
68-
def interruptibly(using d1: DummyImplicit, d2: DummyImplicit): ((I1, I2) => O1) => O2 =
69-
f => h(f.interruptibly)
66+
extension [I1, I2, O1, O2](h: ((I1, I2) => O1) => O2)(using d1: DummyImplicit, d2: DummyImplicit)
67+
/** $text2 */
68+
@throws[InterruptedException]
69+
def interruptibly: ((I1, I2) => O1) => O2 =
70+
f => h(f.interruptibly)

S/src/main/scala/tinyscalautils/util/FastRandom.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ end FastRandom
3939
object FastRandom extends FastRandom(ThreadLocalRandomAdapter):
4040
assert(java.lang.Double.parseDouble("0x1.0p-24f").doubleValue == 5.9604644775390625E-8f)
4141

42+
/** Interruptible variant, same as the `interruptible` extension, but cached for performance. */
43+
lazy val interruptible: Random = InterruptibleRandom(this)
44+
end FastRandom
45+
4246
/* It'd be nice to merge the two adapter classes into one (their methods are identical),
4347
* but the type for `rand` would have to be `RandomGenerator`, which does not exist in Java 11.
4448
*/
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package tinyscalautils
2+
3+
import org.scalatest.funsuite.AnyFunSuite
4+
5+
// outside control package to test givens
6+
7+
class InterruptiblySuite extends AnyFunSuite:
8+
test("plain"):
9+
import tinyscalautils.control.interruptibly
10+
assert(interruptibly("X") == "X")
11+
Thread.currentThread.interrupt()
12+
assertThrows[InterruptedException](interruptibly("X"))
13+
assert(!Thread.currentThread.isInterrupted)
14+
15+
test("functions"):
16+
import tinyscalautils.control.InterruptiblyExtensions
17+
val list = List(1, 2, 3)
18+
assert(list.map.interruptibly(_ + 1) == List(2, 3, 4))
19+
Thread.currentThread.interrupt()
20+
assertThrows[InterruptedException](list.map.interruptibly(_ + 1))
21+
assert(!Thread.currentThread.isInterrupted)
22+
23+
test("ambiguous 1"):
24+
import tinyscalautils.control.interruptibly
25+
val set = Set(1, 2, 3)
26+
assert(interruptibly(set) == Set(1, 2, 3))
27+
28+
test("ambiguous 2"):
29+
import tinyscalautils.control.InterruptiblyExtensions
30+
val set = Set(1, 2, 3)
31+
assert(set.interruptibly(2))
32+
33+
test("ambiguous 3"):
34+
import tinyscalautils.control.{ InterruptiblyExtensions, interruptibly }
35+
val set = Set(1, 2, 3)
36+
assert(interruptibly(set) == Set(1, 2, 3))
37+
assert(set.interruptibly(2))

T/src/main/scala/tinyscalautils/test/grading/GradingSuites.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ open class GradingSuites private (
1010
override val nestedSuites: IndexedSeq[GradingSuite]
1111
) extends GradingSuite:
1212

13-
/** Creates a combined suite.Its weight is the sum of the weights of the nested suites. */
13+
/** Creates a combined suite. Its weight is given and must be positive. */
1414
def this(weight: Double)(suites: GradingSuite*) = this(weight, suites.toIndexedSeq)
1515

16-
/** Creates a combined suite. Its weight is given and must be positive. */
16+
/** Creates a combined suite.Its weight is the sum of the weights of the nested suites. */
1717
def this(suites: GradingSuite*) = this(0.0, suites.toIndexedSeq)
1818

1919
val grader: Grader = Graders()

build.sbt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
val ScalaTest = "org.scalatest" %% "scalatest-funsuite" % "3.2.19"
22
val JUnit = "org.junit.jupiter" % "junit-jupiter" % "5.11.4"
33

4-
ThisBuild / version := "1.5.0"
5-
ThisBuild / scalaVersion := "3.3.4"
4+
ThisBuild / version := "1.5.1"
5+
ThisBuild / scalaVersion := "3.3.5"
66
ThisBuild / versionScheme := Some("semver-spec")
77

88
ThisBuild / Test / fork := true

0 commit comments

Comments
 (0)