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

commonMain.org.antlr.v4.kotlinruntime.misc.IntervalSet.kt Maven / Gradle / Ivy

// Copyright 2017-present Strumenta and contributors, licensed under Apache 2.0.
// Copyright 2024-present Strumenta and contributors, licensed under BSD 3-Clause.
package org.antlr.v4.kotlinruntime.misc

import com.strumenta.antlrkotlin.runtime.ext.appendCodePoint
import org.antlr.v4.kotlinruntime.Lexer
import org.antlr.v4.kotlinruntime.Token
import org.antlr.v4.kotlinruntime.Vocabulary
import kotlin.jvm.JvmField

/**
 * This class implements the [IntSet] backed by a sorted array of
 * non-overlapping intervals. It is particularly efficient for representing
 * large collections of numbers, where the majority of elements appear as part
 * of a sequential range of numbers that are all part of the set. For example,
 * the set `{ 1, 2, 3, 4, 7, 8 }` may be represented as `{ [1, 4], [7, 8] }`.
 *
 * This class is able to represent sets containing any combination of values in
 * the range [Int.MIN_VALUE] to [Int.MAX_VALUE] (inclusive).
 */
@Suppress("LocalVariableName")
public class IntervalSet : IntSet {
  public companion object {
    @JvmField
    public val COMPLETE_CHAR_SET: IntervalSet = of(Lexer.MIN_CHAR_VALUE, Lexer.MAX_CHAR_VALUE).also {
      it.isReadonly = true
    }

    @JvmField
    public val EMPTY_SET: IntervalSet = IntervalSet().also {
      it.isReadonly = true
    }

    /**
     * Create a set with a single element, [a].
     */
    public fun of(a: Int): IntervalSet {
      val s = IntervalSet()
      s.add(a)
      return s
    }

    /**
     * Create a set with all int(s) within range `a..b` (inclusive).
     */
    public fun of(a: Int, b: Int): IntervalSet {
      val s = IntervalSet()
      s.add(a, b)
      return s
    }

    /**
     * Combine all sets in the array returned the or'd value.
     */
    public fun or(vararg sets: IntervalSet): IntervalSet {
      val r = IntervalSet()

      for (s in sets) {
        r.addAll(s)
      }

      return r
    }

    /**
     * Compute the set difference between two interval sets.
     *
     * The specific operation is `left - right`.
     * If either of the input sets is `null`, it is treated as though it was an empty set.
     */
    public fun subtract(left: IntervalSet, right: IntervalSet): IntervalSet {
      if (left.isNil) {
        return IntervalSet()
      }

      val result = IntervalSet(left)

      if (right.isNil) {
        // Right set has no elements; just return the copy of the current set
        return result
      }

      var resultI = 0
      var rightI = 0

      while (resultI < result._intervals.size && rightI < right._intervals.size) {
        val resultInterval = result._intervals[resultI]
        val rightInterval = right._intervals[rightI]

        // Operation: (resultInterval - rightInterval) and update indexes

        if (rightInterval.b < resultInterval.a) {
          rightI++
          continue
        }

        if (rightInterval.a > resultInterval.b) {
          resultI++
          continue
        }

        var beforeCurrent: Interval? = null
        var afterCurrent: Interval? = null

        if (rightInterval.a > resultInterval.a) {
          beforeCurrent = Interval(resultInterval.a, rightInterval.a - 1)
        }

        if (rightInterval.b < resultInterval.b) {
          afterCurrent = Interval(rightInterval.b + 1, resultInterval.b)
        }

        if (beforeCurrent != null) {
          if (afterCurrent != null) {
            // Split the current interval into two
            result._intervals[resultI] = beforeCurrent
            result._intervals.add(resultI + 1, afterCurrent)
            resultI++
            rightI++
            continue
          } else {
            // Replace the current interval
            result._intervals[resultI] = beforeCurrent
            resultI++
            continue
          }
        } else {
          if (afterCurrent != null) {
            // Replace the current interval
            result._intervals[resultI] = afterCurrent
            rightI++
            continue
          } else {
            // Remove the current interval (thus no need to increment resultI)
            result._intervals.removeAt(resultI)
            continue
          }
        }
      }

      // If rightI reached right.intervals.size(), no more intervals to subtract from result.
      // If resultI reached result.intervals.size(), we would be subtracting from an empty set.
      // Either way, we are done.
      return result
    }
  }

  private val _intervals: MutableList

  /**
   * The list of sorted, disjoint intervals.
   */
  public val intervals: List
    get() = _intervals

  override val isNil: Boolean
    get() = _intervals.size == 0

  /**
   * Returns the maximum value contained in the set if not [isNil].
   *
   * @return The maximum value contained in the set
   * @throws RuntimeException If set is empty
   */
  public val maxElement: Int
    get() {
      if (isNil) {
        throw RuntimeException("set is empty")
      }

      val last = _intervals[_intervals.size - 1]
      return last.b
    }

  /**
   * Returns the minimum value contained in the set if not [isNil].
   *
   * @return The minimum value contained in the set
   * @throws RuntimeException If set is empty
   */
  public val minElement: Int
    get() {
      if (isNil) {
        throw RuntimeException("set is empty")
      }

      return _intervals[0].a
    }

  public var isReadonly: Boolean = false
    set(value) {
      if (field && !value) {
        throw IllegalStateException("can't alter readonly IntervalSet")
      }

      field = value
    }

  // This is the most used constructor.
  // Before, the vararg one was getting used, allocating an IntArray for no reason
  public constructor() {
    // The initial size of 16 is a best guess by evaluating
    // the size when executed under multiple grammars
    _intervals = ArrayList(16)
  }

  public constructor(intervals: MutableList) {
    _intervals = intervals
  }

  public constructor(set: IntervalSet) {
    _intervals = ArrayList(set._intervals.size)
    addAll(set)
  }

  public fun clear() {
    if (isReadonly) {
      throw IllegalStateException("can't alter readonly IntervalSet")
    }

    _intervals.clear()
  }

  /**
   * Add a single element to the set.
   *
   * An isolated element is stored as a range `el..el`.
   */
  override fun add(el: Int): Unit =
    add(el, el)

  /**
   * Add interval; i.e., add all integers from a to b to set.
   *
   * If `b < a`, do nothing.
   * Keep list in sorted order (by left range value).
   * If there is overlap, combine ranges. For example,
   * if this is `{1..5, 10..20}`, adding `6..7` yields
   * `{1..5, 6..7, 10..20}`. Adding `4..8` yields `{1..8, 10..20}`.
   */
  public fun add(a: Int, b: Int): Unit =
    add(Interval.of(a, b))

  // Copy on write, so we can cache a..a intervals and sets of that
  private fun add(addition: Interval) {
    if (isReadonly) {
      throw IllegalStateException("can't alter readonly IntervalSet")
    }

    if (addition.b < addition.a) {
      return
    }

    // Find position in list.
    // Use iterators as we modify list in place
    val iter = _intervals.listIterator()

    while (iter.hasNext()) {
      val r = iter.next()

      if (addition == r) {
        return
      }

      if (addition.adjacent(r) || !addition.disjoint(r)) {
        // Next to each other, make a single larger interval
        val bigger = addition.union(r)
        iter.set(bigger)

        // Make sure we didn't just create an interval that
        // should be merged with next interval in list
        while (iter.hasNext()) {
          val next = iter.next()

          if (!bigger.adjacent(next) && bigger.disjoint(next)) {
            break
          }

          // If we bump up against or overlap next, merge
          iter.remove()                 // Remove this one
          iter.previous()               // Move backwards to what we just set
          iter.set(bigger.union(next))  // Set to 3 merged ones
          iter.next()                   // First call to next after previous duplicates the result
        }

        return
      }

      if (addition.startsBeforeDisjoint(r)) {
        // Insert before r
        iter.previous()
        iter.add(addition)
        return
      }

      // If disjoint and after r, a future iteration will handle it
    }

    // Ok, must be after last interval (and disjoint from last interval), just add it
    _intervals.add(addition)
  }

  override fun addAll(set: IntSet): IntervalSet {
    if (set is IntervalSet) {
      // Walk set and add each interval
      val setIntervals = set._intervals

      for (i in 0.. el) {
        r = m - 1
      } else { // el >= a && el <= b
        return true
      }
    }

    return false
  }

  override fun hashCode(): Int {
    var hash = MurmurHash.initialize()

    for (I in _intervals) {
      hash = MurmurHash.update(hash, I.a)
      hash = MurmurHash.update(hash, I.b)
    }

    hash = MurmurHash.finish(hash, _intervals.size * 2)
    return hash
  }

  /**
   * Are two `IntervalSets` equal? Because all intervals are sorted
   * and disjoint, equals is a simple linear walk over both lists
   * to make sure they are the same.
   *
   * [Interval.equals] is used by the [List.equals] method to check the ranges.
   */
  override fun equals(other: Any?): Boolean =
    other is IntervalSet && _intervals == other._intervals

  override fun toString(): String =
    toString(false)

  public fun toString(elemAreChar: Boolean): String {
    if (_intervals.isEmpty()) {
      return "{}"
    }

    val buf = StringBuilder(64)

    if (size() > 1) {
      buf.append("{")
    }

    val n = _intervals.size
    var index = 0

    while (index < n) {
      val I = _intervals[index++]
      val a = I.a
      val b = I.b

      if (a == b) {
        if (a == Token.EOF) {
          buf.append("")
        } else if (elemAreChar) {
          buf.append("'")
          buf.appendCodePoint(a)
          buf.append("'")
        } else {
          buf.append(a)
        }
      } else {
        if (elemAreChar) {
          buf.append("'")
          buf.appendCodePoint(a)
          buf.append("'..'")
          buf.appendCodePoint(b)
          buf.append("'")
        } else {
          buf.append(a)
          buf.append("..")
          buf.append(b)
        }
      }

      if (index < n) {
        buf.append(", ")
      }
    }

    if (size() > 1) {
      buf.append("}")
    }

    return buf.toString()
  }

  public fun toString(vocabulary: Vocabulary): String {
    if (_intervals.isEmpty()) {
      return "{}"
    }

    val buf = StringBuilder(64)

    if (size() > 1) {
      buf.append("{")
    }

    val n = _intervals.size
    var index = 0

    while (index < n) {
      val I = _intervals[index++]
      val a = I.a
      val b = I.b

      if (a == b) {
        buf.append(elementName(vocabulary, a))
      } else {
        for (p in a..b) {
          if (p > a) {
            buf.append(", ")
          }

          buf.append(elementName(vocabulary, p))
        }
      }

      if (index < n) {
        buf.append(", ")
      }
    }

    if (size() > 1) {
      buf.append("}")
    }

    return buf.toString()
  }

  private fun elementName(vocabulary: Vocabulary, a: Int): String =
    when (a) {
      Token.EOF -> ""
      Token.EPSILON -> ""
      else -> vocabulary.getDisplayName(a)
    }

  override fun size(): Int {
    val numIntervals = _intervals.size

    if (numIntervals == 1) {
      val firstInterval = _intervals[0]
      return firstInterval.b - firstInterval.a + 1
    }

    var n = 0

    for (i in 0.. {
    val values = ArrayList(32)
    val n = _intervals.size

    for (i in 0.. {
    val s = HashSet(32)

    for (I in _intervals) {
      val a = I.a
      val b = I.b

      for (v in a..b) {
        s.add(v)
      }
    }

    return s
  }

  /**
   * Get the ith element of ordered set.
   *
   * Used only by `RandomPhrase` so don't bother to implement
   * if you're not doing that for a new ANTLR code gen target.
   */
  public operator fun get(i: Int): Int {
    val n = _intervals.size
    var index = 0

    for (j in 0..




© 2015 - 2024 Weber Informatics LLC | Privacy Policy