All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scalaz.ISet.scala Maven / Gradle / Ivy

The newest version!
package scalaz

import annotation.tailrec
import Ordering._
import std.option._

/**
 * @see [[https://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._

  val size: Int

  // -- * Query
  final def isEmpty: Boolean =
    this match {
      case Tip() => true
      case Bin(_, _, _) => false
    }

  @tailrec
  final def member(x: A)(implicit o: Order[A]): Boolean =
    this match {
      case Tip() => false
      case Bin(y, l, r) =>
        o.order(x, y) match {
          case LT => l.member(x)
          case GT => r.member(x)
          case EQ => true
        }
    }

  /** Alias for member */
  final def contains(x: A)(implicit o: Order[A]): Boolean =
    member(x)

  final def notMember(x: A)(implicit o: Order[A]): Boolean =
    !member(x)

  @tailrec
  final def lookupLT(x: A)(implicit o: Order[A]): Option[A] = {
    @tailrec
    def withBest(x: A, best: A, t: ISet[A]): Option[A] =
      t match {
        case Tip() =>
          some(best)
        case Bin(y, l, r) =>
          if (o.lessThanOrEqual(x, y)) withBest(x, best, l) else withBest(x, y, r)
      }

    this match {
      case Tip() =>
        none
      case Bin(y, l, r) =>
        if (o.lessThanOrEqual(x, y)) l.lookupLT(x) else withBest(x, y, r)
    }
  }

  @tailrec
  final def lookupGT(x: A)(implicit o: Order[A]): Option[A] = {
    @tailrec
    def withBest(x: A, best: A, t: ISet[A]): Option[A] =
      t match {
        case Tip() =>
          some(best)
        case Bin(y, l, r) =>
          if (o.lessThan(x, y)) withBest(x, y, l) else withBest(x, best, r)
      }

    this match {
      case Tip() =>
        none
      case Bin(y, l, r) =>
        if (o.lessThan(x, y)) withBest(x, y, l) else r.lookupGT(x)
    }
  }

  @tailrec
  final def lookupLE(x: A)(implicit o: Order[A]): Option[A] = {
    @tailrec
    def withBest(x: A, best: A, t: ISet[A]): Option[A] =
      t match {
        case Tip() =>
          some(best)
        case Bin(y, l, r) =>
          o.order(x, y) match {
            case LT =>
              withBest(x, best, l)
            case EQ =>
              some(y)
            case GT =>
              withBest(x, y, r)
          }
      }

    this match {
      case Tip() =>
        none
      case Bin(y, l, r) =>
        o.order(x, y) match {
          case LT =>
            l.lookupLE(x)
          case EQ =>
            some(y)
          case GT =>
            withBest(x, y, r)
        }
    }
  }

  @tailrec
  final def lookupGE(x: A)(implicit o: Order[A]): Option[A] = {
    @tailrec
    def withBest(x: A, best: A, t: ISet[A]): Option[A] =
      t match {
        case Tip() =>
          some(best)
        case Bin(y, l, r) =>
          o.order(x, y) match {
            case LT =>
              withBest(x, y, l)
            case EQ =>
              some(y)
            case GT =>
              withBest(x, best, r)
          }
      }

    this match {
      case Tip() =>
        none
      case Bin(y, l, r) =>
        o.order(x, y) match {
          case LT =>
            withBest(x, y, l)
          case EQ =>
            some(y)
          case GT =>
            r.lookupGE(x)
        }
    }
  }

  final def isSubsetOf(other: ISet[A])(implicit o: Order[A]): Boolean =
    (this.size <= other.size) && this.isSubsetOfX(other)

  private def isSubsetOfX(other: ISet[A])(implicit o: Order[A]): Boolean =
    (this, other) match {
      case (Tip(), _) =>
        true
      case (_, Tip()) =>
        false
      case (Bin(x, l, r), t) =>
        val (lt,found,gt) = t.splitMember(x)
        found && l.isSubsetOfX(lt) && r.isSubsetOfX(gt)
    }

  final def isProperSubsetOf(other: ISet[A])(implicit o: Order[A]): Boolean =
    (this.size < other.size) && this.isSubsetOf(other)

  // -- * Construction
  final def insert(x: A)(implicit o: Order[A]): ISet[A] =
    this match {
      case Tip() => singleton(x)
      case self @ Bin(y, l, r) =>
        o.order(x, y) match {
          case LT =>
            val left = l.insert(x)
            if (left eq l) {
              self
            } else {
              balanceL(y, left, r)
            }
          case GT =>
            val right = r.insert(x)
            if (right eq r) {
              self
            } else {
              balanceR(y, l, right)
            }
          case EQ =>
            self
        }
    }

  final def delete(x: A)(implicit o: Order[A]): ISet[A] =
    this match {
      case Tip() =>
        this
      case self @ Bin(y, l, r) =>
        o.order(x, y) match {
          case LT =>
            val left = l.delete(x)
            if (left eq l) {
              self
            } else {
              balanceR(y, left, r)
            }
          case GT =>
            val right = r.delete(x)
            if (right eq r) {
              self
            } else {
              balanceL(y, l, right)
            }
          case EQ =>
            glue(l, r)
        }
    }

  // -- * Combine
  final def union(other: ISet[A])(implicit o: Order[A]): ISet[A] = {
    def hedgeUnion(blo: Option[A], bhi: Option[A], t1: ISet[A], t2: ISet[A])(implicit o: Order[A]): ISet[A] =
      (t1, t2) match {
        case (t1, Tip()) =>
          t1
        case (Tip(), Bin(x, l, r)) =>
          join(x, l.filterGt(blo), r.filterLt(bhi))
        case (_, Bin(x, Tip(), Tip())) =>
          t1.insertR(x)
        case (Bin(x, l, r), _) =>
          val bmi = some(x)
          join(x, hedgeUnion(blo, bmi, l, t2.trim(blo, bmi)), hedgeUnion(bmi, bhi, r, t2.trim(bmi, bhi)))
      }

    (this, other) match {
      case (Tip(), t2) =>
        t2
      case (t1, Tip()) =>
        t1
      case (t1, t2) =>
        hedgeUnion(none, none, t1, t2)
    }
  }

  private def insertR(x: A)(implicit o: Order[A]): ISet[A] =
    this match {
      case Tip() =>
        singleton(x)
      case Bin(y, l, r) =>
        o.order(x, y) match {
          case LT =>
            balanceL(y, l.insertR(x), r)
          case GT =>
            balanceR(y, l, r.insertR(x))
          case EQ =>
            this
        }
    }

  final def difference(other: ISet[A])(implicit o: Order[A]): ISet[A] = {
    def hedgeDiff(blo: Option[A], bhi: Option[A], t1: ISet[A], t2: ISet[A]): ISet[A] =
      (t1, t2) match {
        case (Tip(), _) =>
          Tip()
        case (Bin(x, l, r), Tip()) =>
          join(x, l.filterGt(blo), r.filterLt(bhi))
        case (t, Bin(x, l, r)) =>
          val bmi = some(x)
          hedgeDiff(blo, bmi, t.trim(blo, bmi), l) merge hedgeDiff(bmi, bhi, t.trim(bmi, bhi), r)
      }

    (this, other) match {
      case (Tip(), _) =>
        Tip()
      case (t1, Tip()) =>
        t1
      case (t1, t2) =>
        hedgeDiff(none, none, t1, t2)
    }
  }

  // -- * Operators
  final def \\ (other: ISet[A])(implicit o: Order[A]): ISet[A] =
    difference(other)

  final def intersection(other: ISet[A])(implicit o: Order[A]): ISet[A] = {
    def hedgeInt(blo: Option[A], bhi: Option[A], t1: ISet[A], t2: ISet[A]): ISet[A] =
      (t1, t2) match {
        case (_, Tip()) =>
          t2
        case (Tip(), _) =>
          t1
        case (Bin(x, l, r), t2) =>
          val bmi = some(x)
          val l2 = hedgeInt(blo, bmi, l, t2.trim(blo, bmi))
          val r2 = hedgeInt(bmi, bhi, r, t2.trim(bmi, bhi))
          if (t2.member(x)) join(x, l2, r2) else l2 merge r2
      }

    (this, other) match {
      case (Tip(), _) =>
        this
      case (_, Tip()) =>
        other
      case (t1, t2) =>
        hedgeInt(None, None, t1, t2)
    }
  }

  // -- * Filter
  final def filter(p: A => Boolean): ISet[A] =
    this match {
      case Tip() => this
      case Bin(x, l, r) =>
        if (p(x)) {
          val left = l.filter(p)
          val right = r.filter(p)
          if ((left eq l) && (right eq r)) {
            this
          } else {
            join(x, left, right)
          }
        } else {
          l.filter(p) merge r.filter(p)
        }
    }

  final def partition(p: A => Boolean): (ISet[A], ISet[A]) =
    this match {
      case Tip() =>
        (this, this)
      case Bin(x, l, r) =>
        val (l1, l2) = l.partition(p)
        val (r1, r2) = r.partition(p)
        if (p(x)) (join(x, l1, r1), l2 merge r2) else (l1 merge r1, join(x, l2, r2))
    }

  final def split(x: A)(implicit o: Order[A]): (ISet[A], ISet[A]) =
    this match {
      case Tip() =>
        (this, this)
      case Bin(y, l, r) =>
        o.order(x, y) match {
          case LT =>
            val (lt, gt) = l.split(x)
            (lt, join(y, gt, r))
          case GT =>
            val (lt, gt) = r.split(x)
            (join(y, l, lt), gt)
          case EQ =>
            (l, r)
        }
    }

  final def splitMember(x: A)(implicit o: Order[A]): (ISet[A], Boolean, ISet[A]) =
    this match {
      case Tip() =>
        (this, false, this)
      case Bin(y, l, r) =>
        o.order(x, y) match {
          case LT =>
            val (lt, found, gt) = l.splitMember(x)
            (lt, found, join(y, gt, r))
          case GT =>
            val (lt, found, gt) = r.splitMember(x)
            (join(y, l, lt), found, gt)
          case EQ =>
            (l, true, r)
        }
    }

  final def splitRoot: IList[ISet[A]] =
    this match {
      case Tip()        => IList.empty[ISet[A]]
      case Bin(x, l, r) => IList(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)
        }
    }

  /**
    * The `Functor` composition law only holds for functions that preserve
    * equivalence, i.e. for functions `f` such that
    *
    *  -  ∀ a1, a2 ∈ A
    *    -  `Order[A].equal(a1, a2)` ⇒ `Order[B].equal(f(a1), f(a2))`
    *
    * In the case when the equivalence implied by `Order[A]` is in fact
    * _equality_, i.e. the finest equivalence, i.e. satisfying the
    * _substitution property_ (which is the above property quantified over
    * all `f`, see [[https://en.wikipedia.org/wiki/Equality_(mathematics)#Some_basic_logical_properties_of_equality Wikipedia page on Equality]]),
    * the requirement holds for all `f` by definition.
    *
    * When `Order` instances are viewed as "mere" equivalences (as opposed
    * to equalities), we can loosely say that `ISet` is an (endo-)functor
    * in the category _Equiv_ of sets with an equivalence relation (where
    * the morphishms are equivalence-preserving functions, i.e. exactly the
    * functions satisfying the above requirement). By contrast, [[Functor]]
    * instances are functors in the _Scala_ category, whose morphisms are
    * arbitrary functions, including the ones that don't preserve equivalence.
    *
    * '''Note:''' this is not able to implement `Functor` due to the `Order` constraint on the destination type,
    * however it still is a functor in the mathematical sense.
    *
    * Documentation as copied from the Haskell source:
    *  {{{
    -- | /O(n*log n)/.
    -- @'map' f s@ is the set obtained by applying @f@ to each element of @s@.
    --
    -- It's worth noting that the size of the result may be smaller if,
    -- for some @(x,y)@, @x \/= y && f x == f y@
    }}}
    */
  def map[B: Order](f: A => B): ISet[B] =
    fromList(toList.map(f))

  // -- * Folds
  final def foldRight[B](z: B)(f: (A, B) => B): B =
    this match {
      case Tip() => z
      case Bin(x, l ,r) => l.foldRight(f(x, r.foldRight(z)(f)))(f)
    }

  final def foldr[B](z: B)(f: (A, B) => B): B =
    foldRight(z)(f)

  final def foldLeft[B](z: B)(f: (B, A) => B): B =
    this match {
      case Tip() => z
      case Bin(x, l, r) =>
        r.foldLeft(f(l.foldLeft(z)(f), x))(f)
    }

  final def foldl[B](z: B)(f: (B, A) => B): B =
    foldLeft(z)(f)

  // -- * Min\/Max
  @tailrec
  final def findMin: Option[A] =
    this match {
      case Tip() => none
      case Bin(x, Tip(), _) => some(x)
      case Bin(_, l, _) => l.findMin
    }

  @tailrec
  final def findMax: Option[A] =
    this match {
      case Tip() => none
      case Bin(x, _, Tip()) => some(x)
      case Bin(_, _, r) => r.findMax
    }

  final def deleteMin: ISet[A] =
    this match {
      case Bin(_, Tip(), r) => r
      case Bin(x, l, r) => balanceR(x, l.deleteMin, r)
      case Tip() => Tip()
    }

  final def deleteMax: ISet[A] =
    this match {
      case Bin(_, l, Tip()) => l
      case Bin(x, l, r) => balanceL(x, l, r.deleteMax)
      case Tip() => Tip()
    }

  // TODO: Can we make this total? or should this remain unsafe, preferring minView instead?
  final def deleteFindMin: (A, ISet[A]) =
    this match {
      case Bin(x, Tip(), r) => (x, r)
      case Bin(x, l, r) =>
        val (xm, l2) = l.deleteFindMin
        (xm, balanceR(x, l2, r))
      case Tip() => sys.error("deleteFindMin on empty ISet")
    }

  // TODO: Can we make this total? or should this remain unsafe, preferring maxView instead?
  final def deleteFindMax: (A, ISet[A]) =
    this match {
      case Bin(x, l, Tip()) => (x, l)
      case Bin(x, l, r) =>
        val (xm, r2) = r.deleteFindMax
        (xm, balanceL(x, l, r2))
      case Tip() => sys.error("deleteFindMax on empty ISet")
    }

  final def minView: Option[(A, ISet[A])] =
    this match {
      case Tip() => none
      case x => some(x.deleteFindMin)
    }

  final def maxView: Option[(A, ISet[A])] =
    this match {
      case Tip() => none
      case x => some(x.deleteFindMax)
    }

  // -- ** List
  final def elems: IList[A] =
    toAscIList

  final def toList: List[A] =
    toAscList

  final def toIList: IList[A] =
    toAscIList

  // -- ** Ordered list
  final def toAscList: List[A] =
    foldRight(List.empty[A])(_ :: _)

  final def toAscIList: IList[A] =
    foldRight(IList.empty[A])(_ :: _)

  final def toDescList: List[A] =
    foldLeft(List.empty[A])((a, b) => b :: a)

  final def toDescIList: IList[A] =
    foldLeft(IList.empty[A])((a, b) => b :: a)

  private def glue[A](l: ISet[A], r: ISet[A]): ISet[A] =
    (l, r) match {
      case (Tip(), r) => r
      case (l, Tip()) => l
      case (_, _) =>
        if (l.size > r.size) {
          val (m, l2) = l.deleteFindMax
          balanceR(m, l2, r)
        } else {
          val (m, r2) = r.deleteFindMin
          balanceL(m, l, r2)
        }
    }

  private def join[A](x: A, l: ISet[A], r: ISet[A]): ISet[A] =
    (l, r) match {
      case (Tip(), r) => r.insertMin(x)
      case (l, Tip()) => l.insertMax(x)
      case (Bin(y, ly, ry), Bin(z, lz, rz)) =>
        if (delta*l.size < r.size) balanceL(z, join(x, l, lz), rz)
        else if (delta*r.size < l.size) balanceR(y, ly, join(x, ry, r))
        else Bin(x, l, r)
    }

  private def insertMax(x: A): ISet[A] =
    this match {
      case Tip() =>
        singleton(x)
      case Bin(y, l, r) =>
        balanceR(y, l, r.insertMax(x))
    }

  private def insertMin(x: A): ISet[A] =
    this match {
      case Tip() =>
        singleton(x)
      case Bin(y, l, r) =>
        balanceL(y, l.insertMin(x), r)
    }

  protected def merge(other: ISet[A]): ISet[A] =
    (this, other) match {
      case (Tip(), r) => r
      case (l, Tip()) => l
      case (l@Bin(x, lx, rx), r@Bin(y, ly, ry)) =>
        if (delta*l.size < r.size) balanceL(y, l merge ly, ry)
        else if (delta*r.size < l.size) balanceR(x, lx, rx merge r)
        else glue(l, r)
    }

  final def trim(a: Option[A], b: Option[A])(implicit o: Order[A]): ISet[A] =
    (a, b) match {
      case (None, None) =>
        this
      case (Some(lx), None) =>
        @tailrec
        def greater(lo: A, t: ISet[A]): ISet[A] =
          t match {
            case Bin(x, _, r) => if (o.lessThanOrEqual(x, lo)) greater(lo, r) else t
            case _ => t
          }
        greater(lx, this)
      case (None, Some(hx)) =>
        @tailrec
        def lesser(hi: A, t: ISet[A]): ISet[A] =
          t match {
            case Bin(x, l, _) => if (o.greaterThanOrEqual(x, hi)) lesser(hi, l) else t
            case _ => t
          }
        lesser(hx, this)
      case (Some(lx), Some(rx)) =>
        @tailrec
        def middle(lo: A, hi: A, t: ISet[A]): ISet[A] =
          t match {
            case Bin(x, l, r) =>
              if (o.lessThanOrEqual(x, lo)) middle(lo, hi, r)
              else if (o.greaterThanOrEqual(x, hi)) middle(lo, hi, l)
              else t
            case _ => t
          }
        middle(lx, rx, this)
    }

  final def filterGt(a: Option[A])(implicit o: Order[A]): ISet[A] =
    cata(a)(s => this match {
      case Tip() => ISet.empty
      case Bin(x, l, r) =>
        o.order(s, x) match {
          case LT => join(x, l.filterGt(a), r)
          case EQ => r
          case GT => r.filterGt(a)
        }
    }, this)

  final def filterLt(a: Option[A])(implicit o: Order[A]): ISet[A] =
    cata(a)(s => this match {
      case Tip() => ISet.empty
      case Bin(x, l, r) =>
        o.order(x, s) match {
          case LT => join(x, l, r.filterLt(a))
          case EQ => l
          case GT => l.filterLt(a)
        }
    }, this)

  override final def equals(other: Any): Boolean =
    other match {
      case that: ISet[A] =>
        ISet.setEqual[A](using Equal.equalA).equal(this, that)
      case _ =>
        false
    }

  override final def hashCode: Int =
    toAscList.hashCode
}

sealed abstract class ISetInstances {
  import ISet._

  implicit def setEqual[A: Equal]: Equal[ISet[A]] = new ISetEqual[A] {
    def A = implicitly
  }

  implicit def setOrder[A: Order]: Order[ISet[A]] = new Order[ISet[A]] with ISetEqual[A] {
    def A = implicitly

    def order(x: ISet[A], y: ISet[A]) =
      Order[IList[A]].order(x.toAscIList, y.toAscIList)
  }

  implicit def setShow[A](implicit A: Show[A]): Show[ISet[A]] = Show.show { as =>
    import scalaz.syntax.show._
    val content = IList.instances.intercalate(
      as.toIList.map(A.show),
      Cord(",")
    )
    cord"ISet($content)"
  }

  implicit def setMonoid[A: Order]: Monoid[ISet[A]] & SemiLattice[ISet[A]] =
    new Monoid[ISet[A]] with SemiLattice[ISet[A]] {
      def zero: ISet[A] =
        empty[A]

      def append(a: ISet[A], b: => ISet[A]): ISet[A] =
        a union b
    }

  implicit val setFoldable: Foldable[ISet] = new Foldable[ISet] {
    override def findLeft[A](fa: ISet[A])(f: A => Boolean) =
      fa match {
        case Bin(x, l, r) =>
          findLeft(l)(f) match {
            case a @ Some(_) =>
              a
            case None =>
              if(f(x))
                Some(x)
              else
                findLeft(r)(f)
          }
        case Tip() =>
          None
      }

    override def findRight[A](fa: ISet[A])(f: A => Boolean) =
      fa match {
        case Bin(x, l, r) =>
          findRight(r)(f) match {
            case a @ Some(_) =>
              a
            case None =>
              if(f(x))
                Some(x)
              else
                findRight(l)(f)
          }
        case Tip() =>
          None
      }

    def foldMap[A, B](fa: ISet[A])(f: A => B)(implicit F: Monoid[B]): B =
      fa match {
        case Tip() =>
          F.zero
        case Bin(x, l, r) =>
          F.append(F.append(foldMap(l)(f), f(x)), foldMap(r)(f))
      }

    def foldRight[A, B](fa: ISet[A], z: => B)(f: (A, => B) => B): B =
      fa.foldRight(z)((a, b) => f(a, b))

    override def foldLeft[A, B](fa: ISet[A], z: B)(f: (B, A) => B) =
      fa.foldLeft(z)(f)

    override def index[A](fa: ISet[A], i: Int): Option[A] = {
      import std.anyVal._
      @tailrec def loop(a: ISet[A], b: Int): Option[A] =
        a match {
          case Bin(x, l, r) =>
            Order[Int].order(b, l.size) match {
              case Ordering.LT =>
                loop(l, b)
              case Ordering.GT =>
                loop(r, b - l.size - 1)
              case Ordering.EQ =>
                Some(x)
            }
          case Tip() =>
            None
        }

      if (i < 0 || fa.size <= i)
        None
      else
        loop(fa, i)
    }

    override def toIList[A](fa: ISet[A]) =
      fa.foldRight(IList.empty[A])(_ :: _)

    override def toList[A](fa: ISet[A]) =
      fa.toList

    override def length[A](fa: ISet[A]) =
      fa.size

    override def maximum[A: Order](fa: ISet[A]) =
      fa.findMax

    override def minimum[A: Order](fa: ISet[A]) =
      fa.findMin

    override def empty[A](fa: ISet[A]) =
      fa.isEmpty

    override def any[A](fa: ISet[A])(f: A => Boolean) =
      fa match {
        case Tip() => false
        case Bin(x, l, r) =>
          any(l)(f) || f(x) || any(r)(f)
      }

    override def all[A](fa: ISet[A])(f: A => Boolean) =
      fa match {
        case Tip() => true
        case Bin(x, l, r) =>
          all(l)(f) && f(x) && all(r)(f)
      }
  }
}

object ISet extends ISetInstances {
  final def empty[A]: ISet[A] =
    Tip()

  final def singleton[A](x: A): ISet[A] =
    Bin(x, Tip(), Tip())

  final def fromList[A](xs: List[A])(implicit o: Order[A]): ISet[A] =
    xs.foldLeft(empty[A])((a, b) => a insert b)

  final def fromIList[A](xs: IList[A])(implicit o: Order[A]): ISet[A] =
    xs.foldLeft(empty[A])((a, b) => a insert b)

  final def fromFoldable[F[_], A](xs: F[A])(implicit F: Foldable[F], o: Order[A]): ISet[A] =
    F.foldLeft(xs, empty[A])((a, b) => a insert b)

  final def unions[A](xs: List[ISet[A]])(implicit o: Order[A]): ISet[A] =
    xs.foldLeft(ISet.empty[A])(_ union _)

  final def unions[A](xs: IList[ISet[A]])(implicit o: Order[A]): ISet[A] =
    xs.foldLeft(ISet.empty[A])(_ union _)

  private[scalaz] final val delta = 3
  private[scalaz] final val ratio = 2

  private[scalaz] def balanceL[A](x: A, l: ISet[A], r: ISet[A]): ISet[A] =
    r match {
      case Tip() =>
        l match {
          case Tip() =>
            singleton(x)
          case Bin(_, Tip(), Tip()) =>
            Bin(x, l, Tip())
          case Bin(lx, Tip(), Bin(lrx, _, _)) =>
            Bin(lrx, singleton(lx), singleton(x))
          case Bin(lx, ll@Bin(_, _, _), Tip()) =>
            Bin(lx, ll, singleton(x))
          case Bin(lx, ll@Bin(_, _, _), lr@Bin(lrx, lrl, lrr)) =>
            if (lr.size < ratio*ll.size) Bin(lx, ll, Bin(x, lr, Tip()))
            else Bin(lrx, Bin(lx, ll, lrl), Bin(x, lrr, Tip()))
        }
      case Bin(_, _, _) =>
        l match {
          case Tip() =>
            Bin(x, Tip(), r)
          case Bin(lx, ll, lr) =>
            if (l.size > delta*r.size) {
              (ll, lr) match {
                case (Bin(_, _, _), Bin(lrx, lrl, lrr)) =>
                  if (lr.size < ratio*ll.size) Bin(lx, ll, Bin(x, lr, r))
                  else Bin(lrx, Bin(lx, ll, lrl), Bin(x, lrr, r))
                case _ => sys.error("Failure in ISet.balanceL")
              }
            } else Bin(x, l, r)
        }
    }

  private[scalaz] def balanceR[A](x: A, l: ISet[A], r: ISet[A]): ISet[A] =
    l match {
      case Tip() =>
        r match {
          case Tip() =>
            singleton(x)
          case Bin(_, Tip(), Tip()) =>
            Bin(x, Tip(), r)
          case Bin(rx, Tip(), rr@Bin(_, _, _)) =>
            Bin(rx, singleton(x), rr)
          case Bin(rx, Bin(rlx, _, _), Tip()) =>
            Bin(rlx, singleton(x), singleton(rx))
          case Bin(rx, rl@Bin(rlx, rll, rlr), rr@Bin(_, _, _)) =>
            if (rl.size < ratio*rr.size) Bin(rx, Bin(x, Tip(), rl), rr)
            else Bin(rlx, Bin(x, Tip(), rll), Bin(rx, rlr, rr))
        }
      case Bin(_, _, _) =>
        r match {
          case Tip() =>
            Bin(x, l, Tip())
          case Bin(rx, rl, rr) =>
            if (r.size > delta*l.size) {
              (rl, rr) match {
                case (Bin(rlx, rll, rlr), Bin(_, _, _)) =>
                  if (rl.size < ratio*rr.size) Bin(rx, Bin(x, l, rl), rr)
                  else Bin(rlx, Bin(x, l, rll), Bin(rx, rlr, rr))
                case _ => sys.error("Failure in ISet.balanceR")
              }
            } else Bin(x, l, r)
        }
    }

  private[scalaz] final case class Tip[A] private() extends ISet[A] {
    val size = 0
  }
  private[scalaz] object Tip {
    private[this] val value: Tip[Nothing] = new Tip[Nothing]
    def apply[A](): ISet[A] = value.asInstanceOf[ISet[A]]
  }

  private[scalaz] final case class Bin[A](a: A, l: ISet[A], r: ISet[A]) extends ISet[A] {
    val size = l.size + r.size + 1
  }
}

private sealed trait ISetEqual[A] extends Equal[ISet[A]] {
  import std.list._
  implicit def A: Equal[A]

  override final def equal(a1: ISet[A], a2: ISet[A]) =
    (a1.size == a2.size) && Equal[List[A]].equal(a1.toAscList, a2.toAscList)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy