Skip to content

Commit

Permalink
Merge pull request scala#73 from scala/hierarchy
Browse files Browse the repository at this point in the history
Flesh out the mutable type hierarchy
  • Loading branch information
julienrf committed May 15, 2017
2 parents 3fa69e3 + 18ac934 commit cbfc5a8
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 66 deletions.
9 changes: 5 additions & 4 deletions src/main/scala/strawman/collection/mutable/Growable.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package strawman.collection.mutable
package strawman
package collection.mutable

import strawman.collection.IterableOnce
import scala.{`inline`, Unit}
Expand Down Expand Up @@ -28,22 +29,22 @@ trait Growable[-A] {
* @param elems the remaining elements to $add.
* @return the $coll itself
*/
@`inline` final def +=(elem1: A, elem2: A, elems: A*): this.type = this += elem1 += elem2 ++= (elems.toStrawman: IterableOnce[A])
@`inline` final def += (elem1: A, elem2: A, elems: A*): this.type = this += elem1 += elem2 ++= (elems.toStrawman: IterableOnce[A])

/** ${Add}s all elements produced by a TraversableOnce to this $coll.
*
* @param xs the TraversableOnce producing the elements to $add.
* @return the $coll itself.
*/
def addAll(xs: IterableOnce[A]): this.type = {
@tailrec def loop(xs: scala.collection.LinearSeq[A]): Unit = {
@tailrec def loop(xs: collection.LinearSeq[A]): Unit = {
if (xs.nonEmpty) {
this += xs.head
loop(xs.tail)
}
}
xs match {
case xs: scala.collection.LinearSeq[_] => loop(xs.asInstanceOf[scala.collection.LinearSeq[A]])
case xs: collection.LinearSeq[A] => loop(xs)
case xs => xs.iterator() foreach += // Deviation: IterableOnce does not define `foreach`.
}
// @ichoran writes: Right now, this actually isn't any faster than using an iterator
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/strawman/collection/mutable/HashMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ final class HashMap[K, V] private[collection] (contents: HashTable.Contents[K, D

def clear(): Unit = table.clearTable()

def remove(key: K): this.type = { table.removeEntry(key); this }
def subtract(key: K): this.type = { table.removeEntry(key); this }

override def size: Int = table.size

Expand Down
26 changes: 23 additions & 3 deletions src/main/scala/strawman/collection/mutable/Iterable.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
package strawman.collection.mutable

import strawman.collection
import strawman.collection.IterableFactory
import strawman.collection.{IterableFactory, IterableOnce}

trait Iterable[A] extends collection.Iterable[A]
with collection.IterableOps[A, Iterable, Iterable[A]]
import scala.Boolean

trait Iterable[A]
extends collection.Iterable[A]
with IterableOps[A, Iterable, Iterable[A]] {

def mapInPlace(f: A => A): this.type

}

trait IterableOps[A, +CC[X], +C]
extends collection.IterableOps[A, CC, C]

object Iterable
extends IterableFactory.Delegate[Iterable](ArrayBuffer)

trait GrowableIterable[A]
extends Iterable[A]
with Growable[A] {

def flatMapInPlace(f: A => IterableOnce[A]): this.type

def filterInPlace(p: A => Boolean): this.type

}
66 changes: 50 additions & 16 deletions src/main/scala/strawman/collection/mutable/Map.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,25 @@ package strawman
package collection
package mutable

import scala.{Option, `inline`, Unit}
import strawman.collection.{IterableOnce, MapFactory}

import scala.{Boolean, Option, Unit, `inline`}

/** Base type of mutable Maps */
trait Map[K, V] extends Iterable[(K, V)]
with collection.Map[K, V]
with MapOps[K, V, Map, Map[K, V]]
trait Map[K, V]
extends GrowableIterable[(K, V)]
with collection.Map[K, V]
with MapOps[K, V, Map, Map[K, V]]
with Shrinkable[K]

/** Base trait of mutable Maps implementations */
trait MapOps[K, V, +CC[X, Y] <: Map[X, Y], +C <: Map[K, V]]
extends IterableOps[(K, V), Iterable, C]
with collection.MapOps[K, V, CC, C]
with Growable[(K, V)] {
with collection.MapOps[K, V, CC, C] {

def fromIterable[B](coll: collection.Iterable[B]): Iterable[B] = Iterable.fromIterable(coll)
protected def coll: Map[K, V]

/** Removes a single element from this $coll.
*
* @param key the key of the element to remove.
* @return the $coll itself
*/
def remove(key: K): this.type
/** Alias for `remove` */
@`inline` final def -= (key: K): this.type = remove(key)
def fromIterable[B](coll: collection.Iterable[B]): Iterable[B] = Iterable.fromIterable(coll)

/** Adds a new key/value pair to this map and optionally returns previously bound value.
* If the map already contains a
Expand All @@ -49,10 +45,48 @@ trait MapOps[K, V, +CC[X, Y] <: Map[X, Y], +C <: Map[K, V]]
* @param key The key to update
* @param value The new value
*/
def update(key: K, value: V): Unit = { this += ((key, value)) }
def update(key: K, value: V): Unit = { coll += ((key, value)) }

override def clone(): C = empty ++= coll

def mapInPlace(f: ((K, V)) => (K, V)): this.type = {
val toAdd = Map[K, V]()
val toRemove = Set[K]()
for (elem <- this) {
val mapped = f(elem)
if (!contains(mapped._1)) {
toAdd += mapped
toRemove -= elem._1
}
}
for (elem <- toRemove) coll -= elem
for (elem <- toAdd) coll += elem
this
}

def flatMapInPlace(f: ((K, V)) => IterableOnce[(K, V)]): this.type = {
val toAdd = Map[K, V]()
val toRemove = Set[K]()
for (elem <- this)
for (mapped <- f(elem).iterator())
if (!contains(mapped._1)) {
toAdd += mapped
toRemove -= elem._1
}
for (elem <- toRemove) coll -= elem
for (elem <- toAdd) coll += elem
this
}

def filterInPlace(p: ((K, V)) => Boolean): this.type = {
val toRemove = Set[K]()
for (elem <- this)
if (!p(elem)) toRemove += elem._1
for (elem <- toRemove)
coll -= elem
this
}

}

object Map extends MapFactory.Delegate[Map](HashMap)
17 changes: 10 additions & 7 deletions src/main/scala/strawman/collection/mutable/Seq.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,25 @@ import strawman.collection
import strawman.collection.{IterableOnce, toNewSeq, toOldSeq}
import scala.Predef.intWrapper

trait Seq[A] extends Iterable[A]
with collection.Seq[A]
with SeqOps[A, Seq, Seq[A]]
trait Seq[A]
extends Iterable[A]
with collection.Seq[A]
with SeqOps[A, Seq, Seq[A]]

trait SeqOps[A, +CC[A] <: Seq[A], +C] extends collection.SeqOps[A, CC, C] {

def update(idx: Int, elem: A): Unit
def mapInPlace(f: A => A): this.type

}

trait GrowableSeq[A] extends Seq[A] with Growable[A] {
trait GrowableSeq[A]
extends GrowableIterable[A]
with Seq[A] {

def insert(idx: Int, elem: A): Unit
def insertAll(idx: Int, elems: IterableOnce[A]): Unit
def remove(idx: Int): A
def remove(from: Int, n: Int): Unit
def flatMapInPlace(f: A => IterableOnce[A]): this.type
def filterInPlace(p: A => Boolean): this.type
def patchInPlace(from: Int, patch: collection.Seq[A], replaced: Int): this.type

// +=, ++=, clear inherited from Growable
Expand Down
69 changes: 35 additions & 34 deletions src/main/scala/strawman/collection/mutable/Set.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,17 @@ import strawman.collection.{IterableFactory, IterableOnce}
import scala.{Boolean, Int, None, Option, Some, Unit, `inline`}

/** Base trait for mutable sets */
trait Set[A] extends Iterable[A]
with collection.Set[A]
with SetOps[A, Set, Set[A]]
trait Set[A]
extends GrowableIterable[A]
with collection.Set[A]
with SetOps[A, Set, Set[A]]
with Shrinkable[A]

trait SetOps[A, +CC[X], +C <: Set[A]]
extends collection.SetOps[A, CC, C]
with Growable[A] {
extends IterableOps[A, CC, C]
with collection.SetOps[A, CC, C] {

/** Removes a single element from this $coll.
*
* @param elem the element to remove.
* @return the $coll itself
*/
def subtract(elem: A): this.type
/** Alias for `subtract` */
@`inline` final def -= (elem: A): this.type = subtract(elem)

def contains(elem: A): Boolean
def get(elem: A): Option[A]

def insert(elem: A): Boolean =
!contains(elem) && { +=(elem); true }

def remove(elem: A): Option[A] = {
val res = get(elem)
-=(elem)
res
}

def mapInPlace(f: A => A): Unit = {
def mapInPlace(f: A => A): this.type = {
val toAdd = Set[A]()
val toRemove = Set[A]()
for (elem <- this) {
Expand All @@ -45,11 +26,29 @@ trait SetOps[A, +CC[X], +C <: Set[A]]
toRemove -= elem
}
}
for (elem <- toRemove) +=(elem)
for (elem <- toAdd) -=(elem)
for (elem <- toRemove) coll -= elem
for (elem <- toAdd) coll += elem
this
}

/**
* @return The reference of the contained element that is equal to `elem`, if found, otherwise `None`
* @param elem The element to get.
*/
def get(elem: A): Option[A]

def insert(elem: A): Boolean =
!contains(elem) && {
coll += elem; true
}

def remove(elem: A): Option[A] = {
val res = get(elem)
coll -= elem
res
}

def flatMapInPlace(f: A => IterableOnce[A]): Unit = {
def flatMapInPlace(f: A => IterableOnce[A]): this.type = {
val toAdd = Set[A]()
val toRemove = Set[A]()
for (elem <- this)
Expand All @@ -58,16 +57,18 @@ trait SetOps[A, +CC[X], +C <: Set[A]]
toAdd += mapped
toRemove -= elem
}
for (elem <- toRemove) -=(elem)
for (elem <- toAdd) +=(elem)
for (elem <- toRemove) coll -= elem
for (elem <- toAdd) coll += elem
this
}

def filterInPlace(p: A => Boolean): Unit = {
def filterInPlace(p: A => Boolean): this.type = {
val toRemove = Set[A]()
for (elem <- this)
if (!p(elem)) toRemove += elem
for (elem <- toRemove)
-=(elem)
coll -= elem
this
}

override def clone(): C = empty ++= coll
Expand Down
68 changes: 68 additions & 0 deletions src/main/scala/strawman/collection/mutable/Shrinkable.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package strawman
package collection.mutable

import scala.annotation.tailrec

import collection.toNewSeq
import scala.{`inline`, Unit}

/** This trait forms part of collections that can be reduced
* using a `-=` operator.
*
* @author Martin Odersky
* @version 2.8
* @since 2.8
* @define coll shrinkable collection
* @define Coll `Shrinkable`
*/
trait Shrinkable[-A] {

/** Removes a single element from this $coll.
*
* @param elem the element to remove.
* @return the $coll itself
*/
def subtract(elem: A): this.type

/** Alias for `subtract` */
@`inline` final def -= (elem: A): this.type = subtract(elem)

/** Removes two or more elements from this $coll.
*
* @param elem1 the first element to remove.
* @param elem2 the second element to remove.
* @param elems the remaining elements to remove.
* @return the $coll itself
*/
def subtract(elem1: A, elem2: A, elems: A*): this.type = {
this -= elem1
this -= elem2
this --= elems.toStrawman
}

/** Alias for `subtract` */
@`inline` final def -= (elem1: A, elem2: A, elems: A*): this.type = subtract(elem1, elem2, elems: _*)

/** Removes all elements produced by an iterator from this $coll.
*
* @param xs the iterator producing the elements to remove.
* @return the $coll itself
*/
def subtractAll(xs: collection.IterableOnce[A]): this.type = {
@tailrec def loop(xs: collection.LinearSeq[A]): Unit = {
if (xs.nonEmpty) {
subtract(xs.head)
loop(xs.tail)
}
}
xs match {
case xs: collection.LinearSeq[A] => loop(xs)
case xs => xs.iterator().foreach(subtract)
}
this
}

/** Alias for `subtractAll` */
@`inline` final def --= (xs: collection.IterableOnce[A]): this.type = subtractAll(xs)

}
2 changes: 1 addition & 1 deletion src/main/scala/strawman/collection/mutable/TreeMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ sealed class TreeMap[K, V] private (tree: RB.Tree[K, V])(implicit val ordering:

def add(elem: (K, V)): this.type = { RB.insert(tree, elem._1, elem._2); this }

def remove(elem: K): this.type = { RB.delete(tree, elem); this }
def subtract(elem: K): this.type = { RB.delete(tree, elem); this }

def clear(): Unit = RB.clear(tree)

Expand Down

0 comments on commit cbfc5a8

Please sign in to comment.