Skip to content

Commit

Permalink
add shim for right-biased either
Browse files Browse the repository at this point in the history
  • Loading branch information
Martijn Hoekstra committed May 28, 2018
1 parent a4c5413 commit 386b318
Show file tree
Hide file tree
Showing 16 changed files with 450 additions and 1 deletion.
4 changes: 3 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ lazy val `scala-collection-compat` = crossProject(JSPlatform, JVMPlatform)
unmanagedSourceDirectories in Compile += {
val sharedSourceDir = baseDirectory.value.getParentFile / "src/main"
if (scalaVersion.value.startsWith("2.13.")) sharedSourceDir / "scala-2.13"
else sharedSourceDir / "scala-2.11_2.12"
else if (scalaVersion.value.startsWith("2.12.")) sharedSourceDir / "scala-2.12"
else if (scalaVersion.value.startsWith("2.11.")) sharedSourceDir / "scala-2.11"
else ???
}
)
.jvmSettings(
Expand Down
9 changes: 9 additions & 0 deletions src/main/scala-2.11/scala/util/compat/SwappableEither.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package scala.util.compat

private[compat] class SwappableEither[+A, +B](underlying: Either[A, B]) {
def swap: Either[B, A] = underlying match {
case Right(b) => Left(b)
case Left(a) => Right(a)
}

}
6 changes: 6 additions & 0 deletions src/main/scala-2.11/scala/util/compat/package.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package scala.util

package object compat {
implicit def bias[A, B](src: Either[A, B]) = src.right
implicit def swappable[A, B](src: Either[A, B]): SwappableEither[A, B] = new SwappableEither[A, B](src)
}
39 changes: 39 additions & 0 deletions src/main/scala-2.12/scala/collection/compat/BuildFrom.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package scala.collection.compat

import scala.collection.generic.CanBuildFrom
import scala.collection.{Iterable, mutable}

/** Builds a collection of type `C` from elements of type `A` when a source collection of type `From` is available.
* Implicit instances of `BuildFrom` are available for all collection types.
*
* @tparam From Type of source collection
* @tparam A Type of elements (e.g. `Int`, `Boolean`, etc.)
* @tparam C Type of collection (e.g. `List[Int]`, `TreeMap[Int, String]`, etc.)
*/
trait BuildFrom[-From, -A, +C] extends Any {

def fromSpecificIterable(from: From)(it: Iterable[A]): C

/** Get a Builder for the collection. For non-strict collection types this will use an intermediate buffer.
* Building collections with `fromSpecificIterable` is preferred because it can be lazy for lazy collections. */
def newBuilder(from: From): mutable.Builder[A, C]

@deprecated("Use newBuilder() instead of apply()", "2.13.0")
@`inline` def apply(from: From): mutable.Builder[A, C] = newBuilder(from)

}

object BuildFrom {

// Implicit instance derived from an implicit CanBuildFrom instance
implicit def fromCanBuildFrom[From, A, C](implicit cbf: CanBuildFrom[From, A, C]): BuildFrom[From, A, C] =
new BuildFrom[From, A, C] {
def fromSpecificIterable(from: From)(it: Iterable[A]): C = (cbf(from) ++= it).result()
def newBuilder(from: From): mutable.Builder[A, C] = cbf(from)
}

// Implicit conversion derived from an implicit conversion to CanBuildFrom
implicit def fromCanBuildFromConversion[X, From, A, C](x: X)(implicit toCanBuildFrom: X => CanBuildFrom[From, A, C]): BuildFrom[From, A, C] =
fromCanBuildFrom(toCanBuildFrom(x))

}
15 changes: 15 additions & 0 deletions src/main/scala-2.12/scala/collection/compat/CompatImpl.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package scala.collection.compat

import scala.collection.generic.CanBuildFrom
import scala.collection.mutable.Builder
import scala.collection.{immutable => i, mutable => m}

private[compat] object CompatImpl {
def simpleCBF[A, C](f: => Builder[A, C]): CanBuildFrom[Any, A, C] = new CanBuildFrom[Any, A, C] {
def apply(from: Any): Builder[A, C] = apply()
def apply(): Builder[A, C] = f
}

type ImmutableBitSetCC[X] = ({ type L[_] = i.BitSet })#L[X]
type MutableBitSetCC[X] = ({ type L[_] = m.BitSet })#L[X]
}
37 changes: 37 additions & 0 deletions src/main/scala-2.12/scala/collection/compat/Factory.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package scala.collection.compat

import scala.collection.generic.CanBuildFrom
import scala.collection.{TraversableOnce, mutable}

/**
* A factory that builds a collection of type `C` with elements of type `A`.
*
* @tparam A Type of elements (e.g. `Int`, `Boolean`, etc.)
* @tparam C Type of collection (e.g. `List[Int]`, `TreeMap[Int, String]`, etc.)
*/
trait Factory[-A, +C] extends Any {

/**
* @return A collection of type `C` containing the same elements
* as the source collection `it`.
* @param it Source collection
*/
def fromSpecific(it: TraversableOnce[A]): C

/** Get a Builder for the collection. For non-strict collection types this will use an intermediate buffer.
* Building collections with `fromSpecific` is preferred because it can be lazy for lazy collections. */
def newBuilder(): mutable.Builder[A, C]
}

object Factory {

implicit def fromCanBuildFrom[A, C](implicit cbf: CanBuildFrom[Nothing, A, C]): Factory[A, C] =
new Factory[A, C] {
def fromSpecific(it: TraversableOnce[A]): C = (cbf() ++= it).result()
def newBuilder(): mutable.Builder[A, C] = cbf()
}

implicit def fromCanBuildFromConversion[X, A, C](x: X)(implicit toCanBuildFrom: X => CanBuildFrom[Nothing, A, C]): Factory[A, C] =
fromCanBuildFrom(toCanBuildFrom(x))

}
226 changes: 226 additions & 0 deletions src/main/scala-2.12/scala/collection/compat/immutable/ArraySeq.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
package scala.collection.compat.immutable

import java.util.Arrays

import scala.annotation.unchecked.uncheckedVariance
import scala.collection.AbstractSeq
import scala.collection.generic._
import scala.collection.immutable.IndexedSeq
import scala.collection.mutable.{ArrayBuilder, Builder, WrappedArrayBuilder}
import scala.reflect.ClassTag
import scala.util.hashing.MurmurHash3

/**
* An immutable array.
*
* Supports efficient indexed access and has a small memory footprint.
*
* @define Coll `ArraySeq`
* @define coll wrapped array
* @define orderDependent
* @define orderDependentFold
* @define mayNotTerminateInf
* @define willNotTerminateInf
*/
abstract class ArraySeq[+T]
extends AbstractSeq[T]
with IndexedSeq[T]
{

override protected[this] def thisCollection: ArraySeq[T] = this

/** The tag of the element type */
protected[this] def elemTag: ClassTag[T]

/** The length of the array */
def length: Int

/** The element at given index */
def apply(index: Int): T

/** The underlying array */
def unsafeArray: Array[T @uncheckedVariance]

override def stringPrefix = "ArraySeq"

/** Clones this object, including the underlying Array. */
override def clone(): ArraySeq[T] = ArraySeq unsafeWrapArray unsafeArray.clone()

/** Creates new builder for this collection ==> move to subclasses
*/
override protected[this] def newBuilder: Builder[T, ArraySeq[T]] =
new WrappedArrayBuilder[T](elemTag).mapResult(w => ArraySeq.unsafeWrapArray(w.array))

}

/** A companion object used to create instances of `ArraySeq`.
*/
object ArraySeq {
// This is reused for all calls to empty.
private val EmptyArraySeq = new ofRef[AnyRef](new Array[AnyRef](0))
def empty[T <: AnyRef]: ArraySeq[T] = EmptyArraySeq.asInstanceOf[ArraySeq[T]]

/**
* Wrap an existing `Array` into an `ArraySeq` of the proper primitive specialization type
* without copying.
*
* Note that an array containing boxed primitives can be wrapped in an `ArraySeq` without
* copying. For example, `val a: Array[Any] = Array(1)` is an array of `Object` at runtime,
* containing `Integer`s. An `ArraySeq[Int]` can be obtained with a cast:
* `ArraySeq.unsafeWrapArray(a).asInstanceOf[ArraySeq[Int]]`. The values are still
* boxed, the resulting instance is an [[ArraySeq.ofRef]]. Writing
* `ArraySeq.unsafeWrapArray(a.asInstanceOf[Array[Int]])` does not work, it throws a
* `ClassCastException` at runtime.
*/
def unsafeWrapArray[T](x: Array[T]): ArraySeq[T] = (x.asInstanceOf[Array[_]] match {
case null => null
case x: Array[AnyRef] => new ofRef[AnyRef](x)
case x: Array[Int] => new ofInt(x)
case x: Array[Double] => new ofDouble(x)
case x: Array[Long] => new ofLong(x)
case x: Array[Float] => new ofFloat(x)
case x: Array[Char] => new ofChar(x)
case x: Array[Byte] => new ofByte(x)
case x: Array[Short] => new ofShort(x)
case x: Array[Boolean] => new ofBoolean(x)
case x: Array[Unit] => new ofUnit(x)
}).asInstanceOf[ArraySeq[T]]

implicit def canBuildFrom[T](implicit m: ClassTag[T]): CanBuildFrom[ArraySeq[_], T, ArraySeq[T]] =
new CanBuildFrom[ArraySeq[_], T, ArraySeq[T]] {
def apply(from: ArraySeq[_]): Builder[T, ArraySeq[T]] =
ArrayBuilder.make[T]()(m) mapResult ArraySeq.unsafeWrapArray[T]
def apply: Builder[T, ArraySeq[T]] =
ArrayBuilder.make[T]()(m) mapResult ArraySeq.unsafeWrapArray[T]
}

@SerialVersionUID(3L)
final class ofRef[T <: AnyRef](val unsafeArray: Array[T]) extends ArraySeq[T] with Serializable {
lazy val elemTag = ClassTag[T](unsafeArray.getClass.getComponentType)
def length: Int = unsafeArray.length
def apply(index: Int): T = unsafeArray(index)
def update(index: Int, elem: T) { unsafeArray(index) = elem }
override def hashCode = MurmurHash3.arrayHash(unsafeArray, MurmurHash3.seqSeed)
override def equals(that: Any) = that match {
case that: ofRef[_] => Arrays.equals(unsafeArray.asInstanceOf[Array[AnyRef]], that.unsafeArray.asInstanceOf[Array[AnyRef]])
case _ => super.equals(that)
}
}

@SerialVersionUID(3L)
final class ofByte(val unsafeArray: Array[Byte]) extends ArraySeq[Byte] with Serializable {
def elemTag = ClassTag.Byte
def length: Int = unsafeArray.length
def apply(index: Int): Byte = unsafeArray(index)
def update(index: Int, elem: Byte) { unsafeArray(index) = elem }
override def hashCode = MurmurHash3.bytesHash(unsafeArray, MurmurHash3.seqSeed)
override def equals(that: Any) = that match {
case that: ofByte => Arrays.equals(unsafeArray, that.unsafeArray)
case _ => super.equals(that)
}
}

@SerialVersionUID(3L)
final class ofShort(val unsafeArray: Array[Short]) extends ArraySeq[Short] with Serializable {
def elemTag = ClassTag.Short
def length: Int = unsafeArray.length
def apply(index: Int): Short = unsafeArray(index)
def update(index: Int, elem: Short) { unsafeArray(index) = elem }
override def hashCode = MurmurHash3.arrayHash(unsafeArray, MurmurHash3.seqSeed)
override def equals(that: Any) = that match {
case that: ofShort => Arrays.equals(unsafeArray, that.unsafeArray)
case _ => super.equals(that)
}
}

@SerialVersionUID(3L)
final class ofChar(val unsafeArray: Array[Char]) extends ArraySeq[Char] with Serializable {
def elemTag = ClassTag.Char
def length: Int = unsafeArray.length
def apply(index: Int): Char = unsafeArray(index)
def update(index: Int, elem: Char) { unsafeArray(index) = elem }
override def hashCode = MurmurHash3.arrayHash(unsafeArray, MurmurHash3.seqSeed)
override def equals(that: Any) = that match {
case that: ofChar => Arrays.equals(unsafeArray, that.unsafeArray)
case _ => super.equals(that)
}
}

@SerialVersionUID(3L)
final class ofInt(val unsafeArray: Array[Int]) extends ArraySeq[Int] with Serializable {
def elemTag = ClassTag.Int
def length: Int = unsafeArray.length
def apply(index: Int): Int = unsafeArray(index)
def update(index: Int, elem: Int) { unsafeArray(index) = elem }
override def hashCode = MurmurHash3.arrayHash(unsafeArray, MurmurHash3.seqSeed)
override def equals(that: Any) = that match {
case that: ofInt => Arrays.equals(unsafeArray, that.unsafeArray)
case _ => super.equals(that)
}
}

@SerialVersionUID(3L)
final class ofLong(val unsafeArray: Array[Long]) extends ArraySeq[Long] with Serializable {
def elemTag = ClassTag.Long
def length: Int = unsafeArray.length
def apply(index: Int): Long = unsafeArray(index)
def update(index: Int, elem: Long) { unsafeArray(index) = elem }
override def hashCode = MurmurHash3.arrayHash(unsafeArray, MurmurHash3.seqSeed)
override def equals(that: Any) = that match {
case that: ofLong => Arrays.equals(unsafeArray, that.unsafeArray)
case _ => super.equals(that)
}
}

@SerialVersionUID(3L)
final class ofFloat(val unsafeArray: Array[Float]) extends ArraySeq[Float] with Serializable {
def elemTag = ClassTag.Float
def length: Int = unsafeArray.length
def apply(index: Int): Float = unsafeArray(index)
def update(index: Int, elem: Float) { unsafeArray(index) = elem }
override def hashCode = MurmurHash3.arrayHash(unsafeArray, MurmurHash3.seqSeed)
override def equals(that: Any) = that match {
case that: ofFloat => Arrays.equals(unsafeArray, that.unsafeArray)
case _ => super.equals(that)
}
}

@SerialVersionUID(3L)
final class ofDouble(val unsafeArray: Array[Double]) extends ArraySeq[Double] with Serializable {
def elemTag = ClassTag.Double
def length: Int = unsafeArray.length
def apply(index: Int): Double = unsafeArray(index)
def update(index: Int, elem: Double) { unsafeArray(index) = elem }
override def hashCode = MurmurHash3.arrayHash(unsafeArray, MurmurHash3.seqSeed)
override def equals(that: Any) = that match {
case that: ofDouble => Arrays.equals(unsafeArray, that.unsafeArray)
case _ => super.equals(that)
}
}

@SerialVersionUID(3L)
final class ofBoolean(val unsafeArray: Array[Boolean]) extends ArraySeq[Boolean] with Serializable {
def elemTag = ClassTag.Boolean
def length: Int = unsafeArray.length
def apply(index: Int): Boolean = unsafeArray(index)
def update(index: Int, elem: Boolean) { unsafeArray(index) = elem }
override def hashCode = MurmurHash3.arrayHash(unsafeArray, MurmurHash3.seqSeed)
override def equals(that: Any) = that match {
case that: ofBoolean => Arrays.equals(unsafeArray, that.unsafeArray)
case _ => super.equals(that)
}
}

@SerialVersionUID(3L)
final class ofUnit(val unsafeArray: Array[Unit]) extends ArraySeq[Unit] with Serializable {
def elemTag = ClassTag.Unit
def length: Int = unsafeArray.length
def apply(index: Int): Unit = unsafeArray(index)
def update(index: Int, elem: Unit) { unsafeArray(index) = elem }
override def hashCode = MurmurHash3.arrayHash(unsafeArray, MurmurHash3.seqSeed)
override def equals(that: Any) = that match {
case that: ofUnit => unsafeArray.length == that.unsafeArray.length
case _ => super.equals(that)
}
}
}
Loading

0 comments on commit 386b318

Please sign in to comment.