Skip to content

Commit

Permalink
Add Chain (#2371)
Browse files Browse the repository at this point in the history
* Add Catenable

* Add law tests and simple arbitrary and eq instances

* More tests

* Add benchmarks

* Add chain benchmarks

* Add Iterator

* More chain benchmarks

* Add Paul and Pavel to Authors and change COPYING to Cats Contributors

* More Tests

* Add reverse, groupBy and zipWith

* Add Collection Wrapping optimization

* Add traverse and foldRight implementations that don't convert to List

* Rename to Chain; add reverseIterator

* More efficient implementations

* Use Vector for reversing

* Remove redundant benchmarking methods

* Format scaladoc consistently

* Rename snoc and cons to append and prepend for consistency

* Add proper Eq, PartialOrder, Order and Coflatmap instances
  • Loading branch information
Luka Jacobowitz authored Aug 15, 2018
1 parent fc21141 commit 21aa369
Show file tree
Hide file tree
Showing 8 changed files with 889 additions and 2 deletions.
2 changes: 2 additions & 0 deletions AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,10 @@ possible:
* P. Oscar Boykin
* Paolo G. Giarrusso
* Pascal Voitot
* Paul Chiusano
* Paul Phillips
* Paulo "JCranky" Siqueira
* Pavel Chlupacek
* Pavkin Vladimir
* Pepe García
* Pere Villega
Expand Down
2 changes: 1 addition & 1 deletion COPYING
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Cats Copyright (c) 2015 Erik Osheim.
Cats Copyright (c) 2015 Cats Contributors.

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
Expand Down
79 changes: 79 additions & 0 deletions bench/src/main/scala/cats/bench/ChainBench.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package cats.bench

import cats.data.Chain
import fs2.Catenable
import chain.{Chain => OldChain}
import org.openjdk.jmh.annotations.{Benchmark, Scope, State}

@State(Scope.Thread)
class ChainBench {

private val smallChain = Chain(1, 2, 3, 4, 5)
private val smallCatenable = Catenable(1, 2, 3, 4, 5)
private val smallVector = Vector(1, 2, 3, 4, 5)
private val smallList = List(1, 2, 3, 4, 5)
private val smallOldChain = OldChain(smallList)

private val largeChain = (0 to 1000)
.foldLeft(Chain.empty[Int])((acc, _) => acc ++ Chain.fromSeq(0 to 1000))
private val largeCatenable = Catenable.fromSeq(0 to 1000000)
private val largeVector = (0 to 1000000).toVector
private val largeList = (0 to 1000000).toList
private val largeOldChain = (0 to 1000).foldLeft(OldChain.empty[Int])((acc, _) => acc ++ OldChain(0 to 1000))


@Benchmark def mapSmallChain: Chain[Int] = smallChain.map(_ + 1)
@Benchmark def mapSmallCatenable: Catenable[Int] = smallCatenable.map(_ + 1)
@Benchmark def mapSmallVector: Vector[Int] = smallVector.map(_ + 1)
@Benchmark def mapSmallList: List[Int] = smallList.map(_ + 1)
@Benchmark def mapSmallOldChain: OldChain[Int] = smallOldChain.map(_ + 1)


@Benchmark def mapLargeChain: Chain[Int] = largeChain.map(_ + 1)
@Benchmark def mapLargeCatenable: Catenable[Int] = largeCatenable.map(_ + 1)
@Benchmark def mapLargeVector: Vector[Int] = largeVector.map(_ + 1)
@Benchmark def mapLargeList: List[Int] = largeList.map(_ + 1)
@Benchmark def mapLargeOldChain: OldChain[Int] = largeOldChain.map(_ + 1)



@Benchmark def foldLeftSmallChain: Int = smallChain.foldLeft(0)(_ + _)
@Benchmark def foldLeftSmallCatenable: Int = smallCatenable.foldLeft(0)(_ + _)
@Benchmark def foldLeftSmallVector: Int = smallVector.foldLeft(0)(_ + _)
@Benchmark def foldLeftSmallList: Int = smallList.foldLeft(0)(_ + _)
@Benchmark def foldLeftSmallOldChain: Int = smallOldChain.foldLeft(0)(_ + _)


@Benchmark def foldLeftLargeChain: Int = largeChain.foldLeft(0)(_ + _)
@Benchmark def foldLeftLargeCatenable: Int = largeCatenable.foldLeft(0)(_ + _)
@Benchmark def foldLeftLargeVector: Int = largeVector.foldLeft(0)(_ + _)
@Benchmark def foldLeftLargeList: Int = largeList.foldLeft(0)(_ + _)
@Benchmark def foldLeftLargeOldChain: Int = largeOldChain.foldLeft(0)(_ + _)




@Benchmark def consSmallChain: Chain[Int] = 0 +: smallChain
@Benchmark def consSmallCatenable: Catenable[Int] = 0 +: smallCatenable
@Benchmark def consSmallVector: Vector[Int] = 0 +: smallVector
@Benchmark def consSmallList: List[Int] = 0 +: smallList
@Benchmark def consSmallOldChain: OldChain[Int] = 0 +: smallOldChain

@Benchmark def consLargeChain: Chain[Int] = 0 +: largeChain
@Benchmark def consLargeCatenable: Catenable[Int] = 0 +: largeCatenable
@Benchmark def consLargeVector: Vector[Int] = 0 +: largeVector
@Benchmark def consLargeList: List[Int] = 0 +: largeList
@Benchmark def consLargeOldChain: OldChain[Int] = 0 +: largeOldChain

@Benchmark def createTinyChain: Chain[Int] = Chain(1)
@Benchmark def createTinyCatenable: Catenable[Int] = Catenable(1)
@Benchmark def createTinyVector: Vector[Int] = Vector(1)
@Benchmark def createTinyList: List[Int] = List(1)
@Benchmark def createTinyOldChain: OldChain[Int] = OldChain.single(1)

@Benchmark def createSmallChain: Chain[Int] = Chain(1, 2, 3, 4, 5)
@Benchmark def createSmallCatenable: Catenable[Int] = Catenable(1, 2, 3, 4, 5)
@Benchmark def createSmallVector: Vector[Int] = Vector(1, 2, 3, 4, 5)
@Benchmark def createSmallList: List[Int] = List(1, 2, 3, 4, 5)
@Benchmark def createSmallOldChain: OldChain[Int] = OldChain(Seq(1, 2, 3, 4, 5))
}
24 changes: 24 additions & 0 deletions bench/src/main/scala/cats/bench/CollectionMonoidBench.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package cats.bench

import cats.Monoid
import cats.data.Chain
import cats.implicits._
import chain.{Chain => OldChain}
import org.openjdk.jmh.annotations.{Benchmark, Scope, State}

@State(Scope.Thread)
class CollectionMonoidBench {

private val largeList = (0 to 1000000).toList

implicit def monoidOldChain[A]: Monoid[OldChain[A]] = new Monoid[OldChain[A]] {
def empty: OldChain[A] = OldChain.empty[A]

def combine(x: OldChain[A], y: OldChain[A]): OldChain[A] = x ++ y
}

@Benchmark def accumulateChain: Chain[Int] = largeList.foldMap(Chain.one)
@Benchmark def accumulateVector: Vector[Int] = largeList.foldMap(Vector(_))
@Benchmark def accumulateList: List[Int] = largeList.foldMap(List(_))
@Benchmark def accumulateOldChain: OldChain[Int] = largeList.foldMap(OldChain.single)
}
5 changes: 4 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,10 @@ lazy val bench = project.dependsOn(macrosJVM, coreJVM, freeJVM, lawsJVM)
.settings(commonJvmSettings)
.settings(coverageEnabled := false)
.settings(libraryDependencies ++= Seq(
"org.scalaz" %% "scalaz-core" % "7.2.23"))
"org.scalaz" %% "scalaz-core" % "7.2.23",
"org.spire-math" %% "chain" % "0.3.0",
"co.fs2" %% "fs2-core" % "0.10.4"
))
.enablePlugins(JmhPlugin)

// cats-js is JS-only
Expand Down
Loading

0 comments on commit 21aa369

Please sign in to comment.