Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iterant, version 2 #683

Merged
merged 102 commits into from
Jul 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
cdc6533
WIP: introduce Scope to Iterant encoding
oleg-py May 21, 2018
77a13e9
Encode resource using Ref; fix Scope concat.
oleg-py May 22, 2018
041605b
Merge branch 'iterant-scope' of https://github.com/oleg-py/monix into…
alexandru May 24, 2018
e32a0a7
Change encoding
alexandru Jun 2, 2018
d9a62c5
Update to Cats-Effect 1.0.0-RC2
alexandru Jun 3, 2018
142d9c7
Broken merge
alexandru Jun 3, 2018
88ffdb7
Fix onErrorHandle and attempt
alexandru Jun 4, 2018
1502d7a
18/19 MapBatch
Avasil Jun 4, 2018
f310926
Fixed attempt/onErrorHandleWith
alexandru Jun 5, 2018
d574c04
IterantFoldLeft progress
Avasil Jun 5, 2018
3bd1fa8
Restore `Iterant#map` tests
oleg-py Jun 5, 2018
e39c1c9
Fix Iterant#zipWithIndex
oleg-py Jun 5, 2018
b5a5437
Restore `Iterant#collect` tests
oleg-py Jun 5, 2018
a8f9a4b
Fix Iterant#drop
oleg-py Jun 5, 2018
065eeb0
Fix Iterant#bufferSliding and batched
oleg-py Jun 6, 2018
c2eb380
fix IterantDropWhile
Avasil Jun 6, 2018
601b2be
Fix Iterant#filter
oleg-py Jun 6, 2018
1272fd7
Fix Iterant#liftMap
oleg-py Jun 6, 2018
ece6e1a
Restore tests for Iterant#mapEval
oleg-py Jun 6, 2018
a7e0cec
Fix Iterant#skipSuspendL
oleg-py Jun 6, 2018
00c0ca9
Fix Iterant#headOptionL
oleg-py Jun 6, 2018
fec29ba
Fix Iterant#take and Iterant#scan
oleg-py Jun 6, 2018
98b6152
Restore fromIndexedSeq, fromIterable, fromList
Avasil Jun 7, 2018
c055f04
Remove Iterant#skipSuspendL
oleg-py Jun 8, 2018
95e1b4e
Fix `guarantee` with `Iterant#take`
oleg-py Jun 8, 2018
bbac0dd
Fix Iterant#distinctUntilChanged{ByKey}
oleg-py Jun 8, 2018
e0cf9b6
Fix IterantDropWhile
Avasil Jun 8, 2018
977ad27
Merge remote-tracking branch 'upstream/iterant2' into iterant2
Avasil Jun 8, 2018
969bace
Fix Iterant#dropLast
oleg-py Jun 8, 2018
e54489a
Fix Iterant#foldWhileLeft{Eval}L
oleg-py Jun 8, 2018
98c8a6e
Fix Iterant#intersperse
oleg-py Jun 9, 2018
38b841b
Fix Iterant#reduce
oleg-py Jun 9, 2018
961ba60
Fix IterantTakeWhile
Avasil Jun 9, 2018
b28e42e
Fix IterantTakeWhileWithIndex
Avasil Jun 9, 2018
c0b5cdd
Fix IterantDropWhileWithIndex
Avasil Jun 9, 2018
5bc9476
Remove Iterant's DoOnEarlyStop / DoOnFinish tests
Avasil Jun 9, 2018
a3c9e40
Fix IterantDump
Avasil Jun 9, 2018
bf920af
Restore Iterant FromSeq, FromStateAction, Ranges suites
Avasil Jun 9, 2018
11c737d
IterantDump handle concat/scope like suspend
Avasil Jun 12, 2018
d7af44f
Introduce the visitor pattern
alexandru Jun 13, 2018
2677980
Merge branch 'iterant2' of github.com:monix/monix into iterant2
alexandru Jun 13, 2018
da8606b
Fix IterantTakeLast
Avasil Jun 13, 2018
a97d953
Refactor Iterant.foldLeft to use Visitor
alexandru Jun 13, 2018
fbd40f2
Restore Iterant#scanMap suite
oleg-py Jun 13, 2018
6756c0c
Refactor Iterant.map, add benchmark
alexandru Jun 13, 2018
158a4dc
Merge branch 'iterant2' of github.com:monix/monix into iterant2
alexandru Jun 13, 2018
544da99
Restore Iterant#scanEval
oleg-py Jun 13, 2018
d067aac
Optimize Concat
alexandru Jun 14, 2018
81bcc31
Merge branch 'iterant2' of github.com:monix/monix into iterant2
alexandru Jun 14, 2018
7adcb14
Cleanup junk from Iterant.concat
alexandru Jun 14, 2018
e7ab64c
Fix IterantRepeat
alexandru Jun 14, 2018
50a7dbb
Refactor Iterant#collect
alexandru Jun 15, 2018
a1f7a05
Refactor Iterant.completeL
alexandru Jun 15, 2018
f40ca1f
Refactor Iterant#distinctUntilChanged
alexandru Jun 15, 2018
0c2134e
Fixed Iterant#drop, refactored Iterant#distinctUntilChanged
alexandru Jun 15, 2018
9006243
Remove stack from Iterant.drop implementation
alexandru Jun 15, 2018
c6f59c0
Remove stack from Iterant.distinctUntilChanged implementation
alexandru Jun 15, 2018
fb5488a
Refactor Iterant.dropLast
alexandru Jun 15, 2018
2029f93
Refactor Iterant.dropWhile, Iterant.filter
alexandru Jun 15, 2018
669209f
Refactor Iterant.dropWhileWithIndex + dump
alexandru Jun 15, 2018
faf7096
Fix Iterant.foldRightL
alexandru Jun 15, 2018
821d6df
Refactor Iterant.foldWhileLeft
alexandru Jun 15, 2018
63b2168
Refactor Iterant.mapBatch
alexandru Jun 15, 2018
eec607e
Refactor Iterant.mapEval
alexandru Jun 15, 2018
76c2875
Refactor Iterant.liftMap
alexandru Jun 16, 2018
c3507f6
Add AndThen tests
alexandru Jun 16, 2018
5964927
Remove AndThen for now
alexandru Jun 16, 2018
104edce
Merge branch 'master' into iterant2
alexandru Jun 16, 2018
28fd866
Merge branch 'master' into iterant2
alexandru Jun 16, 2018
37870b5
Refactor Iterant.attempt and onErrorHandleWith
alexandru Jun 16, 2018
a0cd317
Iterant.reduce refactoring
alexandru Jun 16, 2018
5135050
Refactor IterantScanEval
alexandru Jun 16, 2018
39d9020
Refactor Iterant.headOptionL
alexandru Jun 16, 2018
2e58c76
Iterant.switchIfEmpty fix
alexandru Jun 16, 2018
ff24496
Refactor Iterant.tail
alexandru Jun 16, 2018
a3aabe6
Refactor Iterant.take
alexandru Jun 16, 2018
78f183b
Refactor Iterant.takeLast
alexandru Jun 16, 2018
e5012d0
Refactor Iterant.takeEveryNth
alexandru Jun 16, 2018
6c0e1fe
Refactor Iterant.takeWhile
alexandru Jun 16, 2018
d86a6b6
Refactor Iterant.takeWhileWithIndex
alexandru Jun 16, 2018
3844db6
Change Iterant.Scope to Iterant.Resource w/ new encoding
alexandru Jun 16, 2018
b670348
Fix Iterant.attempt + onErrorHandleWith
alexandru Jun 16, 2018
43b3e9e
Fix Iterant.foldWhileLeftL
alexandru Jun 16, 2018
ee851e7
Fix Iterant folds
alexandru Jun 16, 2018
439588b
Fix Iterant.dump test
alexandru Jun 16, 2018
100b998
Rename Resource back to Scope
alexandru Jun 17, 2018
151da34
Reintroduce stack usage in Iterant.foldLeftL
alexandru Jun 17, 2018
1e8d37a
Fix Iterant.completeL + foldLeftL + foldWhileLeftL
alexandru Jun 17, 2018
fb25761
Refactor Iterant.headOptionL
alexandru Jun 17, 2018
a3aa5a8
Refactor Iterant.foldRight
alexandru Jun 18, 2018
ef1d3dc
Fix Iterant.zip, zipMap and parZipMap, parZip
alexandru Jun 20, 2018
d197923
Remove junk
alexandru Jun 20, 2018
bb77e8b
Fix Iterant.interleave
alexandru Jun 21, 2018
e5c94ef
Fix Iterant.interleave
alexandru Jun 21, 2018
f5f0082
Fix Iterant.toReactivePublisher
alexandru Jun 22, 2018
bdeb492
Fix Iterant.toReactivePublisher
alexandru Jun 24, 2018
e596a75
Partial fromReactiveStream implementation
alexandru Jun 27, 2018
6e0db51
Change Iterant.fromReactivePublisher
alexandru Jun 29, 2018
d9a31db
Fix tests
alexandru Jul 3, 2018
547762e
Fix tests, builders
alexandru Jul 3, 2018
957cebc
Fix Mima issues
alexandru Jul 3, 2018
31bec94
Fix Scala 2.12.6 warning
alexandru Jul 3, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2014-2018 by The Monix Project Developers.
* See the project homepage at: https://monix.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package monix.benchmarks

import java.util.concurrent.TimeUnit
import monix.eval.Coeval
import monix.tail.Iterant
import org.openjdk.jmh.annotations._

/** To do comparative benchmarks between versions:
*
* benchmarks/run-benchmark IterantMapFoldBenchmark
*
* This will generate results in `benchmarks/results`.
*
* Or to run the benchmark from within SBT:
*
* jmh:run -i 10 -wi 10 -f 2 -t 1 monix.benchmarks.IterantMapFoldBenchmark
*
* Which means "10 iterations", "10 warm-up iterations", "2 forks", "1 thread".
* Please note that benchmarks should be usually executed at least in
* 10 iterations (as a rule of thumb), but more is better.
*/
@State(Scope.Thread)
@BenchmarkMode(Array(Mode.Throughput))
@OutputTimeUnit(TimeUnit.SECONDS)
class IterantMapFoldBenchmark {
import IterantMapFoldBenchmark._

@Benchmark
def granular(): Long =
granularRef.map(_ + 1).foldLeftL(0L)(_ + _).value

@Benchmark
def batched(): Long =
batchedRef.map(_ + 1).foldLeftL(0L)(_ + _).value
}

object IterantMapFoldBenchmark {
val size = 1000

val granularRef: Iterant[Coeval, Int] = {
var stream = Iterant[Coeval].empty[Int]
var idx = 0
while (idx < size) {
stream = idx +: stream
idx += 1
}
stream
}

val batchedRef: Iterant[Coeval, Int] = {
var stream = Iterant[Coeval].empty[Int]
var idx = 0
while (idx < size) {
val rest = stream
stream = rest ++ Iterant[Coeval].range(0, 10)
idx += 1
}
stream
}
}
22 changes: 15 additions & 7 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ addCommandAlias("ci-js", ";clean ;coreJS/test:compile ;coreJS/test")
addCommandAlias("release", ";project monix ;+clean ;+package ;+publishSigned ;sonatypeReleaseAll")

val catsVersion = "1.1.0"
val catsEffectVersion = "1.0.0-RC2"
// Hash version is safe, containing a laws fix over 1.0.0-RC2:
// https://github.com/typelevel/cats-effect/pull/277
val catsEffectVersion = "1.0.0-RC2-93ac33d"
val jcToolsVersion = "2.1.1"
val reactiveStreamsVersion = "1.0.2"
val scalaTestVersion = "3.0.4"
Expand Down Expand Up @@ -44,8 +46,8 @@ lazy val warnUnusedImport = Seq(

lazy val sharedSettings = warnUnusedImport ++ Seq(
organization := "io.monix",
scalaVersion := "2.12.4",
crossScalaVersions := Seq("2.11.12", "2.12.4"),
scalaVersion := "2.12.6",
crossScalaVersions := Seq("2.11.12", "2.12.6"),

scalacOptions ++= Seq(
// warnings
Expand All @@ -57,7 +59,9 @@ lazy val sharedSettings = warnUnusedImport ++ Seq(
"-language:implicitConversions",
"-language:experimental.macros",
// possibly deprecated options
"-Ywarn-inaccessible"
"-Ywarn-inaccessible",
// absolutely necessary for Iterant
"-Ypartial-unification"
),

// Force building with Java 8
Expand Down Expand Up @@ -297,6 +301,8 @@ def mimaSettings(projectName: String) = Seq(
exclude[IncompatibleResultTypeProblem]("monix.eval.Task.foreach"),
// Breakage - changed type
exclude[IncompatibleResultTypeProblem]("monix.execution.Cancelable.empty"),
// Breackage — made CompositeException final
exclude[FinalClassProblem]("monix.execution.exceptions.CompositeException"),
// Breakage — extra implicit param
exclude[DirectMissingMethodProblem]("monix.eval.TaskInstancesLevel0.catsEffect"),
exclude[DirectMissingMethodProblem]("monix.eval.instances.CatsConcurrentEffectForTask.this"),
Expand Down Expand Up @@ -359,7 +365,9 @@ def mimaSettings(projectName: String) = Seq(
exclude[IncompatibleResultTypeProblem]("monix.execution.internal.collection.ArrayStack.clone"),
exclude[MissingTypesProblem]("monix.execution.internal.collection.ArrayStack"),
exclude[DirectMissingMethodProblem]("monix.eval.internal.TaskCancellation#RaiseCancelable.this"),
exclude[MissingClassProblem]("monix.eval.internal.TaskBracket$ReleaseRecover")
exclude[MissingClassProblem]("monix.eval.internal.TaskBracket$ReleaseRecover"),
exclude[MissingClassProblem]("monix.eval.instances.ParallelApplicative$"),
exclude[MissingClassProblem]("monix.eval.instances.ParallelApplicative")
)
)

Expand Down Expand Up @@ -442,14 +450,14 @@ lazy val tailCommon =

lazy val tailJVM = project.in(file("monix-tail/jvm"))
.configure(profile)
.dependsOn(evalJVM % "compile->compile; test->test")
.dependsOn(evalJVM % "test->test")
.dependsOn(executionJVM)
.settings(tailCommon)

lazy val tailJS = project.in(file("monix-tail/js"))
.enablePlugins(ScalaJSPlugin)
.configure(profile)
.dependsOn(evalJS % "compile->compile; test->test")
.dependsOn(evalJS % "test->test")
.dependsOn(executionJS)
.settings(scalaJSSettings)
.settings(tailCommon)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

package monix.eval.internal

import monix.eval.Task.{Async, Context, FlatMap, Map}
import monix.eval.Task.{Async, Context, ContextSwitch, FlatMap, Map}
import monix.eval.{Callback, Task}

import scala.annotation.tailrec
Expand Down Expand Up @@ -48,6 +48,7 @@ private[eval] object ForkedRegister {
case Async(_: ForkedRegister[_], _, _, _) => true
case FlatMap(other, _) => detect(other, limit - 1)
case Map(other, _, _) => detect(other, limit - 1)
case ContextSwitch(other, _, _) => detect(other, limit - 1)
case _ => false
} else {
false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ trait ArbitraryInstancesBase extends monix.execution.ArbitraryInstances {
implicit def arbitraryPfExToA[A](implicit A: Arbitrary[A]): Arbitrary[PartialFunction[Throwable, A]] =
Arbitrary {
val fun = implicitly[Arbitrary[Int => A]]
for (f <- fun.arbitrary) yield PartialFunction((t: Throwable) => f(t.hashCode()))
for (f <- fun.arbitrary) yield { case (t: Throwable) => f(t.hashCode()) }
}

implicit def arbitraryCoevalToLong[A, B](implicit A: Arbitrary[A], B: Arbitrary[B]): Arbitrary[Coeval[A] => B] =
Expand All @@ -216,7 +216,9 @@ trait ArbitraryInstancesBase extends monix.execution.ArbitraryInstances {
implicit def equalityCoeval[A](implicit A: Eq[A]): Eq[Coeval[A]] =
new Eq[Coeval[A]] {
def eqv(lh: Coeval[A], rh: Coeval[A]): Boolean = {
Eq[Try[A]].eqv(lh.runTry(), rh.runTry())
val lht = lh.runTry()
val rht = rh.runTry()
Eq[Try[A]].eqv(lht, rht)
}
}

Expand Down
69 changes: 69 additions & 0 deletions monix-eval/shared/src/test/scala/monix/eval/TestUtils.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2014-2018 by The Monix Project Developers.
* See the project homepage at: https://monix.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package monix.eval

import java.io.{ByteArrayOutputStream, PrintStream}
import scala.util.control.NonFatal

/**
* INTERNAL API — test utilities.
*/
trait TestUtils {

/**
* Silences `System.err`, only printing the output in case exceptions are
* thrown by the executed `thunk`.
*/
def silenceSystemErr[A](thunk: => A): A = synchronized {
// Silencing System.err
val oldErr = System.err
val outStream = new ByteArrayOutputStream()
val fakeErr = new PrintStream(outStream)
System.setErr(fakeErr)
try {
val result = thunk
System.setErr(oldErr)
result
} catch {
case NonFatal(e) =>
System.setErr(oldErr)
// In case of errors, print whatever was caught
fakeErr.close()
val out = outStream.toString("utf-8")
if (out.nonEmpty) oldErr.println(out)
throw e
}
}

/**
* Catches `System.err` output, for testing purposes.
*/
def catchSystemErr(thunk: => Unit): String = synchronized {
val oldErr = System.err
val outStream = new ByteArrayOutputStream()
val fakeErr = new PrintStream(outStream)
System.setErr(fakeErr)
try {
thunk
} finally {
System.setErr(oldErr)
fakeErr.close()
}
outStream.toString("utf-8")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ package monix.eval

import cats.Applicative
import cats.laws.discipline.ApplicativeTests
import monix.eval.instances.{CatsParallelForTask, ParallelApplicative}
import monix.eval.instances.CatsParallelForTask
import monix.execution.internal.ParallelApplicative

object TypeClassLawsForParallelApplicativeSuite extends BaseLawsSuite {
implicit val ap: Applicative[Task] =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2014-2018 by The Monix Project Developers.
* See the project homepage at: https://monix.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package monix.execution
package internal

import scala.concurrent.ExecutionContext

/**
* INTERNAL API — implements [[UncaughtExceptionReporter.default]].
*/
private[execution] object DefaultUncaughtExceptionReporter
extends UncaughtExceptionReporter {

def reportFailure(e: Throwable): Unit =
logger(e)

private[this] lazy val logger =
ExecutionContext.defaultReporter
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package monix.execution.internal

import monix.execution.exceptions.CompositeException
import monix.execution.schedulers.CanBlock

import scala.concurrent.Awaitable
import scala.concurrent.duration.Duration

Expand Down Expand Up @@ -96,17 +95,22 @@ private[monix] object Platform {
rest.filter(_ ne first).toList match {
case Nil => first
case nonEmpty =>
CompositeException(first :: nonEmpty)
first match {
case CompositeException(errors) =>
val list = errors.toList
CompositeException(list ::: nonEmpty)
case _ =>
CompositeException(first :: nonEmpty)
}
}

/** Useful utility that combines an `Either` result, which is what
/**
* Useful utility that combines an `Either` result, which is what
* `MonadError#attempt` returns.
*/
def composeErrors(first: Throwable, second: Either[Throwable, _]): Throwable =
second match {
case Left(e2) if e2 ne first =>
CompositeException(List(first, e2))
case _ =>
first
case Left(e2) => composeErrors(first, e2)
case _ => first
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@ private[execution] class StandardContext(reporter: UncaughtExceptionReporter)
}

private[execution] object StandardContext
extends StandardContext(UncaughtExceptionReporter.LogExceptionsToStandardErr)
extends StandardContext(UncaughtExceptionReporter.default)
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2014-2018 by The Monix Project Developers.
* See the project homepage at: https://monix.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package monix.execution
package internal

/**
* INTERNAL API — implements [[UncaughtExceptionReporter.default]].
*/
private[execution] object DefaultUncaughtExceptionReporter
extends UncaughtExceptionReporter {

def reportFailure(e: Throwable): Unit =
Thread.getDefaultUncaughtExceptionHandler match {
case null => e.printStackTrace()
case h => h.uncaughtException(Thread.currentThread(), e)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@
package monix.execution.schedulers

import java.util.concurrent.{Executors, ScheduledExecutorService}
import monix.execution.UncaughtExceptionReporter.LogExceptionsToStandardErr
import monix.execution.UncaughtExceptionReporter

private[schedulers] object Defaults {
/** Internal. Provides the `Scheduler.DefaultScheduledExecutor` instance. */
/**
* Internal. Provides the `Scheduler.DefaultScheduledExecutor` instance.
*/
lazy val scheduledExecutor: ScheduledExecutorService =
Executors.newSingleThreadScheduledExecutor(
ThreadFactoryBuilder("monix-scheduler", LogExceptionsToStandardErr, daemonic = true)
ThreadFactoryBuilder("monix-scheduler", UncaughtExceptionReporter.default, daemonic = true)
)
}
Loading