Skip to content

Instantly share code, notes, and snippets.

@tiqwab
Last active December 22, 2018 02:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tiqwab/40b6ddb9c49656a897fbacd9ad67e85b to your computer and use it in GitHub Desktop.
Save tiqwab/40b6ddb9c49656a897fbacd9ad67e85b to your computer and use it in GitHub Desktop.
Sample collection implementation to understand CanBuildFrom in Scala 2.12.7
package com.tiqwab.example.step6
import scala.collection.JavaConverters._
import scala.collection.immutable
trait MyBuilder[-Elem, +To] {
def +=(elem: Elem): this.type
def result(): To
}
trait CBF[-From, -Elem, +To] {
def apply(): MyBuilder[Elem, To]
}
// Can be Covariant for A by adding `protected[this]` modifier to newBuilder
trait MyTraversable[+A, +Repr] {
def foreach(f: A => Unit): Unit
protected[this] def newBuilder: MyBuilder[A, Repr]
def size: Int = {
var count = 0
foreach(_ => count = count + 1)
count
}
def map[B, That](f: A => B)(implicit cbf: CBF[Repr, B, That]): That = {
val b = cbf()
foreach(x => { b += f(x); () })
b.result()
}
def filter(p: A => Boolean): Repr = {
val b = newBuilder
foreach(x => if (p(x)) { b += x; () } else ())
b.result()
}
override def toString: String = s"MyTraversable(${mkString(",")})"
private def mkString(sep: String): String = {
var first = true
val sb = new StringBuilder()
foreach { x =>
if (first) {
sb.append(x)
first = false
} else {
sb.append(sep)
sb.append(x)
}
}
sb.toString
}
}
class MyList[+A](elems: List[A]) extends MyTraversable[A, MyList[A]] {
override def foreach(f: A => Unit): Unit = elems.foreach(f)
override protected[this] def newBuilder: MyBuilder[A, MyList[A]] = MyList.newBuilder[A]
override def toString: String = s"MyList(${elems.mkString(",")})"
}
object MyList {
def apply[A](elems: A*): MyList[A] = new MyList(elems.toList)
def newBuilder[B]: MyBuilder[B, MyList[B]] = new MyBuilder[B, MyList[B]] {
val l = new java.util.ArrayList[B]
override def +=(elem: B): this.type = { l.add(elem); this }
override def result(): MyList[B] = new MyList(l.asScala.toList)
}
implicit def cbf[From, Elem]: CBF[From, Elem, MyList[Elem]] = () => newBuilder[Elem]
}
class MySet[A](elems: Set[A]) extends MyTraversable[A, MySet[A]] {
override def foreach(f: A => Unit): Unit = elems.foreach(f)
override protected[this] def newBuilder: MyBuilder[A, MySet[A]] = MySet.newBuilder[A]
override def toString: String = s"MySet(${elems.mkString(",")})"
}
object MySet {
def apply[A](elems: A*): MySet[A] = new MySet(elems.toSet)
def newBuilder[B]: MyBuilder[B, MySet[B]] = new MyBuilder[B, MySet[B]] {
val l = new java.util.ArrayList[B]
override def +=(elem: B): this.type = { l.add(elem); this }
override def result(): MySet[B] = new MySet(l.asScala.toSet)
}
implicit def cbf[From, Elem]: CBF[From, Elem, MySet[Elem]] = () => newBuilder[Elem]
}
class MyMap[A, +B](elems: Map[A, B]) extends MyTraversable[(A, B), MyMap[A, B]] {
override def foreach(f: ((A, B)) => Unit): Unit = elems.foreach(f)
override protected[this] def newBuilder: MyBuilder[(A, B), MyMap[A, B]] = MyMap.newBuilder[A, B]
override def toString: String = s"MyMap(${elems.mkString(",")})"
}
object MyMap {
def apply[A, B](elems: (A, B)*): MyMap[A, B] = new MyMap(elems.toMap)
def newBuilder[A, B]: MyBuilder[(A, B), MyMap[A, B]] = new MyBuilder[(A, B), MyMap[A, B]] {
val l = new java.util.ArrayList[(A, B)]
override def +=(elem: (A, B)): this.type = { l.add(elem); this }
override def result(): MyMap[A, B] = new MyMap(l.asScala.toMap)
}
implicit def cbf[From, A, B]: CBF[From, (A, B), MyMap[A, B]] = () => newBuilder[A, B]
}
class MySortedSet[A: Ordering](elems: immutable.SortedSet[A]) extends MySet(elems) with MyTraversable[A, MySortedSet[A]] {
override def foreach(f: A => Unit): Unit = elems.foreach(f)
override def newBuilder: MyBuilder[A, MySortedSet[A]] = MySortedSet.newBuilder[A]
override def toString: String = s"MySortedSet(${elems.mkString(",")})"
}
object MySortedSet {
def apply[A: Ordering](elems: A*): MySortedSet[A] = new MySortedSet(immutable.SortedSet(elems: _*))
def newBuilder[A: Ordering]: MyBuilder[A, MySortedSet[A]] = new MyBuilder[A, MySortedSet[A]] {
val l = new java.util.ArrayList[A]
override def +=(elem: A): this.type = { l.add(elem); this }
override def result(): MySortedSet[A] = MySortedSet(l.asScala: _*)
}
implicit def cbf[From, Elem: Ordering]: CBF[From, Elem, MySortedSet[Elem]] = () => MySortedSet.newBuilder[Elem]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment