Skip to content

Commit

Permalink
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 2 deletions.
53 changes: 51 additions & 2 deletions core/src/main/scala/scalaz/ISet.scala
Expand Up @@ -5,8 +5,8 @@ import Ordering._
import std.option._

/**
* @see [[http://hackage.haskell.org/package/containers-0.5.0.0/docs/Data-Set.html]]
* @see [[https://github.com/haskell/containers/blob/v0.5.0.0/Data/Set/Base.hs]]
* @see [[http://hackage.haskell.org/package/containers-0.5.7.1/docs/Data-Set.html]]
* @see [[https://github.com/haskell/containers/blob/v0.5.7.1/Data/Set/Base.hs]]
*/
sealed abstract class ISet[A] {
import ISet._
Expand Down Expand Up @@ -329,6 +329,55 @@ sealed abstract class ISet[A] {
}
}

final def splitRoot: List[ISet[A]] =
this match {
case Tip() => List.empty[ISet[A]]
case Bin(x, l, r) => List(l, singleton(x), r)
}

// -- * Index
/** Alias for Foldable[ISet].index */
final def elemAt(i: Int): Option[A] =
Foldable[ISet].index(this, i)

final def lookupIndex(x: A)(implicit o: Order[A]): Option[Int] = {
@tailrec
def loop(s: ISet[A], i: Int): Option[Int] =
s match {
case Tip() =>
none
case Bin(y, l, r) =>
val sizeL = l.size
o.order(y, x) match {
case LT =>
loop(r, i + sizeL + 1)
case GT =>
loop(l, i)
case EQ =>
some(i + sizeL)
}
}

loop(this, 0)
}

final def deleteAt(i: Int): ISet[A] =
this match {
case Tip() =>
Tip()
case Bin(x, l, r) =>
import std.anyVal._
val sizeL = l.size
Order[Int].order(i, sizeL) match {
case LT =>
balanceR(x, l.deleteAt(i), r)
case GT =>
balanceL(x, l, r.deleteAt(i - sizeL - 1))
case EQ =>
glue(l, r)
}
}

/**
* For the `Functor` composition law to hold it is important that the `Order[B]` is substitutive for the `Order[A]` –
* that is, that the `Order[B]` should be __no stronger__, it should not distinguish two `B` instances that would
Expand Down
43 changes: 43 additions & 0 deletions tests/src/test/scala/scalaz/ISetTest.scala
Expand Up @@ -91,6 +91,49 @@ object ISetTest extends SpecLite {
}
}

"splitRoot" ! forAll { a: ISet[Int] =>
a match {
case Tip() =>
a.splitRoot must_=== List.empty[ISet[Int]]
case s@Bin(_, _, _) =>
val List(l, x, r) = s.splitRoot
structurallySound(l)
structurallySound(r)
l must_=== s.l
r must_=== s.r
x must_=== singleton(s.a)
l.union(r).union(x) must_=== s
}
}

"lookupIndex" ! forAll { a: ISet[Int] =>
val l = a.toList
(0 until a.size) foreach { i =>
a.lookupIndex(l(i)) must_=== Some(i)
}
(0 until 5) foreach { _ =>
val r = Random.nextInt()
if(a.member(r))
a.lookupIndex(r) must_=== Some(l.indexOf(r))
else
a.lookupIndex(r) must_=== None
}
}

"deleteAt" ! forAll { a: ISet[Int] =>
val l = a.toList
(0 until a.size) foreach { i =>
val e = l(i)
val b = a.deleteAt(i)
structurallySound(b)
b.notMember(e) must_=== true
b.size must_=== (a.size - 1)
b.insert(e) must_=== a
}
a.deleteAt(-1) must_=== a
a.deleteAt(a.size) must_=== a
}

"lookupLT" ! forAll { (a: ISet[Int], i: Int) =>
a.lookupLT(i) match {
case Some(b) =>
Expand Down

0 comments on commit 3ea1990

Please sign in to comment.