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

au.id.tmm.collections.DupelessSeq.scala Maven / Gradle / Ivy

The newest version!
package au.id.tmm.collections

import scala.annotation.unchecked.uncheckedVariance
import scala.collection.immutable.{AbstractSeq, ArraySeq, IndexedSeq, IndexedSeqOps, StrictOptimizedSeqOps}
import scala.collection.{IterableFactoryDefaults, SeqFactory, mutable}

/**
  * A sequence without duplicates, and a constant-time `contains` lookup.
  */
class DupelessSeq[+A] private (private val iterationOrder: ArraySeq[A], private val elements: Set[A @uncheckedVariance])
    extends AbstractSeq[A]
    with IndexedSeq[A]
    with IndexedSeqOps[A, DupelessSeq, DupelessSeq[A]]
    with StrictOptimizedSeqOps[A, DupelessSeq, DupelessSeq[A]]
    with IterableFactoryDefaults[A, DupelessSeq] {

  def toNonEmptyDupelessSeq: Option[NonEmptyDupelessSeq[A]] =
    if (nonEmpty) Some(NonEmptyDupelessSeq.fromDupelessSeqUnsafe(this)) else None

  override def iterableFactory: SeqFactory[DupelessSeq] = DupelessSeq

  override def length: Int = iterationOrder.length

  override def apply(idx: Int): A = iterationOrder(idx)

  override def reverse: DupelessSeq[A] =
    new DupelessSeq(
      iterationOrder = this.iterationOrder.reverse,
      elements = this.elements,
    )

  override def reverseIterator: Iterator[A] = this.iterationOrder.reverseIterator

  override def iterator: Iterator[A] = iterationOrder.iterator

  /**
    * Always returns a reference to this collection, since it will never contain duplicates
    */
  override def distinct: DupelessSeq[A] = this

  /**
    * Tests if some element is contained in this collection. This is a constant time operation.
    */
  @inline
  override def contains[A1 >: A](elem: A1): Boolean = elements.asInstanceOf[Set[Any]].contains(elem)

  /**
    * Appends the given element to this sequence if it is not already in the sequence. Otherwise, returns this sequence.
    */
  override def appended[B >: A](elem: B): DupelessSeq[B] = {
    if (this.contains(elem)) {
      return this
    }

    new DupelessSeq(
      iterationOrder = this.iterationOrder.appended(elem),
      elements = this.elements.asInstanceOf[Set[B]] + elem,
    )
  }

  /**
    * Appends the given element to this sequence if it is not already in the sequence. Otherwise, returns this sequence.
    */
  override def prepended[B >: A](elem: B): DupelessSeq[B] = {
    if (this.contains(elem)) {
      return this
    }

    new DupelessSeq(
      iterationOrder = this.iterationOrder.prepended(elem),
      elements = this.elements.asInstanceOf[Set[B]] + elem,
    )
  }

  override def splitAt(n: Int): (DupelessSeq[A], DupelessSeq[A]) = {
    val splitVectors = iterationOrder.splitAt(n)

    val leftSplit = new DupelessSeq[A](
      iterationOrder = splitVectors._1,
      elements = splitVectors._1.toSet,
    )

    val rightSplit = new DupelessSeq[A](
      iterationOrder = splitVectors._2,
      elements = splitVectors._2.toSet,
    )

    (leftSplit, rightSplit)
  }

  override def padTo[B >: A](len: Int, elem: B): DupelessSeq[B] =
    if (this.contains(elem)) {
      this
    } else {
      this appended elem
    }

  override def sorted[B >: A](implicit ord: Ordering[B]): DupelessSeq[A] =
    new DupelessSeq(
      iterationOrder = this.iterationOrder.sorted(ord),
      elements = this.elements,
    )

  def -[A1 >: A](elem: A1): DupelessSeq[A] =
    if (this.contains(elem)) {
      new DupelessSeq(
        iterationOrder = this.iterationOrder.filterNot(_ == elem),
        elements = this.elements - elem.asInstanceOf[A],
      )
    } else {
      this
    }

  override def toList: List[A] = this.iterationOrder.toList

  override def toSet[B >: A]: Set[B] = this.elements.asInstanceOf[Set[B]]

  def toArraySeq: ArraySeq[A] = this.iterationOrder

  override protected[this] def className: String = "DupelessSeq"

  override def canEqual(other: Any): Boolean = other.isInstanceOf[DupelessSeq[_]]

  override def equals(other: Any): Boolean =
    other match {
      case that: DupelessSeq[_] =>
        super.equals(that) &&
          (that canEqual this) &&
          iterationOrder == that.iterationOrder &&
          elements == that.elements
      case _ => false
    }

  override def hashCode(): Int = (iterationOrder, elements).hashCode()
}

object DupelessSeq extends SeqFactory[DupelessSeq] {
  private val EMPTY: DupelessSeq[Any] = new DupelessSeq(ArraySeq.untagged.empty, Set.empty)

  override def empty[A]: DupelessSeq[A] = EMPTY.asInstanceOf[DupelessSeq[A]]

  def apply[A](): DupelessSeq[A] = empty

  override def apply[A](elems: A*): DupelessSeq[A] =
    new DupelessSeq(elems.distinct.to(ArraySeq.untagged), elems.toSet)

  override def newBuilder[A]: DupelessSeqBuilder[A] = new DupelessSeqBuilder()

  class DupelessSeqBuilder[A] extends mutable.ReusableBuilder[A, DupelessSeq[A]] {
    private val set: mutable.Set[A]                    = mutable.Set()
    private val iterationOrder: mutable.ArrayBuffer[A] = mutable.ArrayBuffer()

    override def addOne(elem: A): DupelessSeqBuilder.this.type = {
      if (!set.contains(elem)) {
        set += elem
        iterationOrder += elem
      }

      this
    }

    override def clear(): Unit = {
      set.clear()
      iterationOrder.clear()
    }

    override def result(): DupelessSeq[A] =
      if (set.isEmpty) {
        DupelessSeq.empty
      } else {
        new DupelessSeq[A](iterationOrder.to(ArraySeq.untagged), set.toSet)
      }

    override def sizeHint(size: Int): Unit = {
      set.sizeHint(size)
      iterationOrder.sizeHint(size)
    }
  }

  override def from[A](source: IterableOnce[A]): DupelessSeq[A] =
    if (source.getClass eq Set.getClass) {
      val set = source.asInstanceOf[Set[A]]
      new DupelessSeq[A](set.to(ArraySeq.untagged), set)
    } else {
      newBuilder.addAll(source).result()
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy