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

scala.coursier.core.MinimizedExclusions.scala Maven / Gradle / Ivy

The newest version!
package coursier.core

import coursier.core.Exclusions.{allOrganizations, allNames}
import dataclass.data

/** This file defines a special-purpose structure for exclusions that has the following
  * properties/goals:
  *   - The exclusion data is always minimized (minimized meaning overlapping rules are removed)
  *   - The data structure is split into various cases, optimizing common cases for join/meet
  *   - The hashcode is cached, such that recalculating the hashcode for these exclusions is cached.
  */
object MinimizedExclusions {

  val zero = MinimizedExclusions(ExcludeNone)
  val one  = MinimizedExclusions(ExcludeAll)

  sealed abstract class ExclusionData extends Product with Serializable {
    def apply(org: Organization, module: ModuleName): Boolean

    def join(other: ExclusionData): ExclusionData
    def meet(other: ExclusionData): ExclusionData

    def partitioned()
      : (Boolean, Set[Organization], Set[ModuleName], Set[(Organization, ModuleName)])
    def map(f: String => String): ExclusionData

    def size(): Int

    def subsetOf(other: ExclusionData): Boolean

    def toSet(): Set[(Organization, ModuleName)]
  }

  case object ExcludeNone extends ExclusionData {
    override def apply(org: Organization, module: ModuleName): Boolean = true

    override def join(other: ExclusionData): ExclusionData = other
    override def meet(other: ExclusionData): ExclusionData = ExcludeNone
    override def partitioned()
      : (Boolean, Set[Organization], Set[ModuleName], Set[(Organization, ModuleName)]) =
      (false, Set.empty, Set.empty, Set.empty)
    override def map(f: String => String): ExclusionData = ExcludeNone

    override def size(): Int                              = 0
    override def subsetOf(other: ExclusionData): Boolean  = true
    override def toSet(): Set[(Organization, ModuleName)] = Set.empty
  }

  case object ExcludeAll extends ExclusionData {
    override def apply(org: Organization, module: ModuleName): Boolean = false

    override def join(other: ExclusionData): ExclusionData = ExcludeAll
    override def meet(other: ExclusionData): ExclusionData = other

    override def partitioned()
      : (Boolean, Set[Organization], Set[ModuleName], Set[(Organization, ModuleName)]) =
      (true, Set.empty, Set.empty, Set.empty)
    override def map(f: String => String): ExclusionData = ExcludeAll

    override def size(): Int                              = 1
    override def subsetOf(other: ExclusionData): Boolean  = other == ExcludeAll
    override def toSet(): Set[(Organization, ModuleName)] = Set((allOrganizations, allNames))
  }

  @data class ExcludeSpecific(
    byOrg: Set[Organization],
    byModule: Set[ModuleName],
    specific: Set[(Organization, ModuleName)]
  ) extends ExclusionData {
    override def apply(org: Organization, module: ModuleName): Boolean =
      !byModule(module) &&
      !byOrg(org) &&
      !specific((org, module))

    override def join(other: ExclusionData): ExclusionData =
      other match {
        case ExcludeNone => this
        case ExcludeAll  => ExcludeAll
        case other: ExcludeSpecific =>
          val joinedByOrg    = byOrg ++ other.byOrg
          val joinedByModule = byModule ++ other.byModule

          val joinedSpecific =
            specific.filter { case e @ (org, module) =>
              !other.byOrg(org) && !other.byModule(module)
            } ++
              other.specific.filter { case e @ (org, module) =>
                !byOrg(org) && !byModule(module)
              }

          ExcludeSpecific(joinedByOrg, joinedByModule, joinedSpecific)
      }

    override def meet(other: ExclusionData): ExclusionData =
      other match {
        case ExcludeNone => this
        case ExcludeAll  => ExcludeAll
        case other: ExcludeSpecific =>
          val metByOrg    = byOrg intersect other.byOrg
          val metByModule = byModule intersect other.byModule

          val metSpecific =
            specific.filter { case e @ (org, module) =>
              other.byOrg(org) || other.byModule(module) || other.specific(e)
            } ++
              other.specific.filter { case e @ (org, module) =>
                byOrg(org) || byModule(module) || specific(e)
              }

          if (metByOrg.isEmpty && metByModule.isEmpty && metSpecific.isEmpty)
            ExcludeNone
          else
            ExcludeSpecific(metByOrg, metByModule, metSpecific)
      }

    override def partitioned()
      : (Boolean, Set[Organization], Set[ModuleName], Set[(Organization, ModuleName)]) =
      (false, byOrg, byModule, specific)

    override def map(f: String => String): ExclusionData =
      ExcludeSpecific(
        byOrg.map(_.map(f)),
        byModule.map(_.map(f)),
        specific.map { case (org, module) =>
          org.map(f) -> module.map(f)
        }
      )

    override def size(): Int = byOrg.size + byModule.size + specific.size

    override def subsetOf(other: ExclusionData): Boolean =
      other match {
        case ExcludeNone => false
        case ExcludeAll  => false
        case other: ExcludeSpecific =>
          byOrg.subsetOf(other.byOrg) &&
          byModule.subsetOf(other.byModule) &&
          specific.subsetOf(other.specific)
      }

    override def toSet(): Set[(Organization, ModuleName)] =
      byOrg.map(_ -> allNames) ++ byModule.map(allOrganizations -> _) ++ specific
  }

  def apply(exclusions: Set[(Organization, ModuleName)]): MinimizedExclusions =
    if (exclusions.isEmpty)
      zero
    else {

      val excludeByOrg0  = Set.newBuilder[Organization]
      val excludeByName0 = Set.newBuilder[ModuleName]
      val remaining0     = Set.newBuilder[(Organization, ModuleName)]

      val it    = exclusions.iterator
      var isOne = false
      while (it.hasNext && !isOne) {
        val excl = it.next()
        if (excl._1 == allOrganizations)
          if (excl._2 == allNames)
            isOne = true
          else
            excludeByName0 += excl._2
        else if (excl._2 == allNames)
          excludeByOrg0 += excl._1
        else
          remaining0 += excl
      }

      if (isOne)
        one
      else
        MinimizedExclusions(ExcludeSpecific(
          excludeByOrg0.result(),
          excludeByName0.result(),
          remaining0.result()
        ))
    }
}

@data class MinimizedExclusions(data: MinimizedExclusions.ExclusionData) {
  def apply(org: Organization, module: ModuleName): Boolean = data(org, module)

  def join(other: MinimizedExclusions): MinimizedExclusions = {
    val newData = data.join(other.data)
    // If no data was changed, no need to construct a new instance and create a new hashcode
    if (newData eq this.data)
      this
    else if (newData eq other.data)
      other
    else
      MinimizedExclusions(newData)
  }

  def meet(other: MinimizedExclusions): MinimizedExclusions = {
    val newData = data.meet(other.data)
    // If no data was changed, no need to construct a new instance and create a new hashcode
    if (newData eq this.data)
      this
    else if (newData eq other.data)
      other
    else
      MinimizedExclusions(newData)
  }

  def map(f: String => String): MinimizedExclusions = {
    val newData = data.map(f)
    // If no data was changed, no need to construct a new instance and create a new hashcode
    if (newData eq this.data)
      this
    else
      MinimizedExclusions(newData)
  }

  def partitioned()
    : (Boolean, Set[Organization], Set[ModuleName], Set[(Organization, ModuleName)]) =
    data.partitioned()

  def isEmpty: Boolean = data == MinimizedExclusions.ExcludeNone

  def nonEmpty: Boolean = data != MinimizedExclusions.ExcludeNone

  def size(): Int = data.size()

  def subsetOf(other: MinimizedExclusions): Boolean = data.subsetOf(other.data)

  def toSet(): Set[(Organization, ModuleName)] = data.toSet()

  def toVector(): Vector[(Organization, ModuleName)] = data.toSet().toVector

  def toSeq(): Seq[(Organization, ModuleName)] = data.toSet().toSeq

  final override lazy val hashCode = data.hashCode()
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy