<commit_before>package scala.collection.immutable

import scala.collection.{AbstractIterator, Iterator}

import java.lang.String

/** `NumericRange` is a more generic version of the
  *  `Range` class which works with arbitrary types.
  *  It must be supplied with an `Integral` implementation of the
  *  range type.
  *
  *  Factories for likely types include `Range.BigInt`, `Range.Long`,
  *  and `Range.BigDecimal`.  `Range.Int` exists for completeness, but
  *  the `Int`-based `scala.Range` should be more performant.
  *
  *  {{{
  *     val r1 = Range(0, 100, 1)
  *     val veryBig = Int.MaxValue.toLong + 1
  *     val r2 = Range.Long(veryBig, veryBig + 100, 1)
  *     assert(r1 sameElements r2.map(_ - veryBig))
  *  }}}
  *
  *  @define Coll `NumericRange`
  *  @define coll numeric range
  *  @define mayNotTerminateInf
  *  @define willNotTerminateInf
  */
@SerialVersionUID(3L)
sealed class NumericRange[T](
  val start: T,
  val end: T,
  val step: T,
  val isInclusive: Boolean
)(implicit
  num: Integral[T]
)
  extends AbstractSeq[T]
    with IndexedSeq[T]
    with IndexedSeqOps[T, IndexedSeq, IndexedSeq[T]]
    with StrictOptimizedSeqOps[T, IndexedSeq, IndexedSeq[T]] { self =>

  override def iterator: Iterator[T] = new NumericRange.NumericRangeIterator(this, num)

  /** Note that NumericRange must be invariant so that constructs
    *  such as "1L to 10 by 5" do not infer the range type as AnyVal.
    */
  import num._

  // See comment in Range for why this must be lazy.
  override lazy val length: Int = NumericRange.count(start, end, step, isInclusive)
  override def isEmpty = length == 0
  override def last: T =
    if (length == 0) Nil.head
    else locationAfterN(length - 1)
  override def init: NumericRange[T] =
    if (isEmpty) Nil.init
    else new NumericRange(start, end - step, step, isInclusive)

  override def head: T = if (isEmpty) Nil.head else start
  override def tail: NumericRange[T] =
    if (isEmpty) Nil.tail
    else if(isInclusive) new NumericRange.Inclusive(start + step, end, step)
    else new NumericRange.Exclusive(start + step, end, step)

  /** Create a new range with the start and end values of this range and
    *  a new `step`.
    */
  def by(newStep: T): NumericRange[T] = copy(start, end, newStep)


  /** Create a copy of this range.
    */
  def copy(start: T, end: T, step: T): NumericRange[T] =
    new NumericRange(start, end, step, isInclusive)

  @throws[IndexOutOfBoundsException]
  def apply(idx: Int): T = {
    if (idx < 0 || idx >= length) throw new IndexOutOfBoundsException(idx.toString)
    else locationAfterN(idx)
  }

  override def foreach[@specialized(Unit) U](f: T => U): Unit = {
    var count = 0
    var current = start
    while (count < length) {
      f(current)
      current += step
      count += 1
    }
  }

  // TODO: these private methods are straight copies from Range, duplicated
  // to guard against any (most likely illusory) performance drop.  They should
  // be eliminated one way or another.

  // Tests whether a number is within the endpoints, without testing
  // whether it is a member of the sequence (i.e. when step > 1.)
  private def isWithinBoundaries(elem: T) = !isEmpty && (
    (step > zero && start <= elem && elem <= last ) ||
      (step < zero &&  last <= elem && elem <= start)
    )
  // Methods like apply throw exceptions on invalid n, but methods like take/drop
  // are forgiving: therefore the checks are with the methods.
  private def locationAfterN(n: Int): T = start + (step * fromInt(n))

  // When one drops everything.  Can't ever have unchecked operations
  // like "end + 1" or "end - 1" because ranges involving Int.{ MinValue, MaxValue }
  // will overflow.  This creates an exclusive range where start == end
  // based on the given value.
  private def newEmptyRange(value: T) = NumericRange(value, value, step)

  override def take(n: Int): NumericRange[T] = {
    if (n <= 0 || length == 0) newEmptyRange(start)
    else if (n >= length) this
    else new NumericRange.Inclusive(start, locationAfterN(n - 1), step)
  }

  override def drop(n: Int): NumericRange[T] = {
    if (n <= 0 || length == 0) this
    else if (n >= length) newEmptyRange(end)
    else copy(locationAfterN(n), end, step)
  }

  override def splitAt(n: Int): (NumericRange[T], NumericRange[T]) = (take(n), drop(n))

  override def reverse: NumericRange[T] =
    if (isEmpty) this else new NumericRange.Inclusive(last, start, -step)

  import NumericRange.defaultOrdering

  override def min[T1 >: T](implicit ord: Ordering[T1]): T =
  // We can take the fast path:
  // - If the Integral of this NumericRange is also the requested Ordering
  //   (Integral <: Ordering). This can happen for custom Integral types.
  // - The Ordering is the default Ordering of a well-known Integral type.
    if ((ord eq num) || defaultOrdering.get(num).exists(ord eq _)) {
      if (num.signum(step) > 0) head
      else last
    } else super.min(ord)

  override def max[T1 >: T](implicit ord: Ordering[T1]): T =
  // See comment for fast path in min().
    if ((ord eq num) || defaultOrdering.get(num).exists(ord eq _)) {
      if (num.signum(step) > 0) last
      else head
    } else super.max(ord)

  // Motivated by the desire for Double ranges with BigDecimal precision,
  // we need some way to map a Range and get another Range.  This can't be
  // done in any fully general way because Ranges are not arbitrary
  // sequences but step-valued, so we have a custom method only we can call
  // which we promise to use responsibly.
  //
  // The point of it all is that
  //
  //   0.0 to 1.0 by 0.1
  //
  // should result in
  //
  //   NumericRange[Double](0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0)
  //
  // and not
  //
  //   NumericRange[Double](0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9)
  //
  // or perhaps more importantly,
  //
  //   (0.1 to 0.3 by 0.1 contains 0.3) == true
  //
  private[immutable] def mapRange[A](fm: T => A)(implicit unum: Integral[A]): NumericRange[A] = {
    val self = this

    // XXX This may be incomplete.
    new NumericRange[A](fm(start), fm(end), fm(step), isInclusive) {

      private[this] lazy val underlyingRange: NumericRange[T] = self
      override def foreach[@specialized(Unit) U](f: A => U): Unit = { underlyingRange foreach (x => f(fm(x))) }
      override def isEmpty = underlyingRange.isEmpty
      override def apply(idx: Int): A = fm(underlyingRange(idx))
      override def containsTyped(el: A) = underlyingRange exists (x => fm(x) == el)

      override def toString = {
        def simpleOf(x: Any): String = x.getClass.getName.split("\\.").last
        val stepped = simpleOf(underlyingRange.step)
        s"${super.toString} (using $underlyingRange of $stepped)"
      }
    }
  }

  // a well-typed contains method.
  def containsTyped(x: T): Boolean =
    isWithinBoundaries(x) && (((x - start) % step) == zero)

  override def contains[A1 >: T](x: A1): Boolean =
    try containsTyped(x.asInstanceOf[T])
    catch { case _: ClassCastException => false }

  override def sum[B >: T](implicit num: Numeric[B]): B = {
    if (isEmpty) num.zero
    else if (size == 1) head
    else {
      // If there is no overflow, use arithmetic series formula
      //   a + ... (n terms total) ... + b = n*(a+b)/2
      if ((num eq scala.math.Numeric.IntIsIntegral)||
        (num eq scala.math.Numeric.ShortIsIntegral)||
        (num eq scala.math.Numeric.ByteIsIntegral)||
        (num eq scala.math.Numeric.CharIsIntegral)) {<commit_msg>remove NumericRange#mapRange<commit_after>package scala.collection.immutable

import scala.collection.{AbstractIterator, Iterator}

import java.lang.String

/** `NumericRange` is a more generic version of the
  *  `Range` class which works with arbitrary types.
  *  It must be supplied with an `Integral` implementation of the
  *  range type.
  *
  *  Factories for likely types include `Range.BigInt`, `Range.Long`,
  *  and `Range.BigDecimal`.  `Range.Int` exists for completeness, but
  *  the `Int`-based `scala.Range` should be more performant.
  *
  *  {{{
  *     val r1 = Range(0, 100, 1)
  *     val veryBig = Int.MaxValue.toLong + 1
  *     val r2 = Range.Long(veryBig, veryBig + 100, 1)
  *     assert(r1 sameElements r2.map(_ - veryBig))
  *  }}}
  *
  *  @define Coll `NumericRange`
  *  @define coll numeric range
  *  @define mayNotTerminateInf
  *  @define willNotTerminateInf
  */
@SerialVersionUID(3L)
sealed class NumericRange[T](
  val start: T,
  val end: T,
  val step: T,
  val isInclusive: Boolean
)(implicit
  num: Integral[T]
)
  extends AbstractSeq[T]
    with IndexedSeq[T]
    with IndexedSeqOps[T, IndexedSeq, IndexedSeq[T]]
    with StrictOptimizedSeqOps[T, IndexedSeq, IndexedSeq[T]] { self =>

  override def iterator: Iterator[T] = new NumericRange.NumericRangeIterator(this, num)

  /** Note that NumericRange must be invariant so that constructs
    *  such as "1L to 10 by 5" do not infer the range type as AnyVal.
    */
  import num._

  // See comment in Range for why this must be lazy.
  override lazy val length: Int = NumericRange.count(start, end, step, isInclusive)
  override def isEmpty = length == 0
  override def last: T =
    if (length == 0) Nil.head
    else locationAfterN(length - 1)
  override def init: NumericRange[T] =
    if (isEmpty) Nil.init
    else new NumericRange(start, end - step, step, isInclusive)

  override def head: T = if (isEmpty) Nil.head else start
  override def tail: NumericRange[T] =
    if (isEmpty) Nil.tail
    else if(isInclusive) new NumericRange.Inclusive(start + step, end, step)
    else new NumericRange.Exclusive(start + step, end, step)

  /** Create a new range with the start and end values of this range and
    *  a new `step`.
    */
  def by(newStep: T): NumericRange[T] = copy(start, end, newStep)


  /** Create a copy of this range.
    */
  def copy(start: T, end: T, step: T): NumericRange[T] =
    new NumericRange(start, end, step, isInclusive)

  @throws[IndexOutOfBoundsException]
  def apply(idx: Int): T = {
    if (idx < 0 || idx >= length) throw new IndexOutOfBoundsException(idx.toString)
    else locationAfterN(idx)
  }

  override def foreach[@specialized(Unit) U](f: T => U): Unit = {
    var count = 0
    var current = start
    while (count < length) {
      f(current)
      current += step
      count += 1
    }
  }

  // TODO: these private methods are straight copies from Range, duplicated
  // to guard against any (most likely illusory) performance drop.  They should
  // be eliminated one way or another.

  // Tests whether a number is within the endpoints, without testing
  // whether it is a member of the sequence (i.e. when step > 1.)
  private def isWithinBoundaries(elem: T) = !isEmpty && (
    (step > zero && start <= elem && elem <= last ) ||
      (step < zero &&  last <= elem && elem <= start)
    )
  // Methods like apply throw exceptions on invalid n, but methods like take/drop
  // are forgiving: therefore the checks are with the methods.
  private def locationAfterN(n: Int): T = start + (step * fromInt(n))

  // When one drops everything.  Can't ever have unchecked operations
  // like "end + 1" or "end - 1" because ranges involving Int.{ MinValue, MaxValue }
  // will overflow.  This creates an exclusive range where start == end
  // based on the given value.
  private def newEmptyRange(value: T) = NumericRange(value, value, step)

  override def take(n: Int): NumericRange[T] = {
    if (n <= 0 || length == 0) newEmptyRange(start)
    else if (n >= length) this
    else new NumericRange.Inclusive(start, locationAfterN(n - 1), step)
  }

  override def drop(n: Int): NumericRange[T] = {
    if (n <= 0 || length == 0) this
    else if (n >= length) newEmptyRange(end)
    else copy(locationAfterN(n), end, step)
  }

  override def splitAt(n: Int): (NumericRange[T], NumericRange[T]) = (take(n), drop(n))

  override def reverse: NumericRange[T] =
    if (isEmpty) this else new NumericRange.Inclusive(last, start, -step)

  import NumericRange.defaultOrdering

  override def min[T1 >: T](implicit ord: Ordering[T1]): T =
  // We can take the fast path:
  // - If the Integral of this NumericRange is also the requested Ordering
  //   (Integral <: Ordering). This can happen for custom Integral types.
  // - The Ordering is the default Ordering of a well-known Integral type.
    if ((ord eq num) || defaultOrdering.get(num).exists(ord eq _)) {
      if (num.signum(step) > 0) head
      else last
    } else super.min(ord)

  override def max[T1 >: T](implicit ord: Ordering[T1]): T =
  // See comment for fast path in min().
    if ((ord eq num) || defaultOrdering.get(num).exists(ord eq _)) {
      if (num.signum(step) > 0) last
      else head
    } else super.max(ord)

  // a well-typed contains method.
  def containsTyped(x: T): Boolean =
    isWithinBoundaries(x) && (((x - start) % step) == zero)

  override def contains[A1 >: T](x: A1): Boolean =
    try containsTyped(x.asInstanceOf[T])
    catch { case _: ClassCastException => false }

  override def sum[B >: T](implicit num: Numeric[B]): B = {
    if (isEmpty) num.zero
    else if (size == 1) head
    else {
      // If there is no overflow, use arithmetic series formula
      //   a + ... (n terms total) ... + b = n*(a+b)/2
      if ((num eq scala.math.Numeric.IntIsIntegral)||
        (num eq scala.math.Numeric.ShortIsIntegral)||
        (num eq scala.math.Numeric.ByteIsIntegral)||
        (num eq scala.math.Numeric.CharIsIntegral)) {
{'fraction_non_alphanumeric': 0.12255733352997566, 'fraction_numerical': 0.013863284418553204, 'mean_word_length': 3.041120381406436, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 3, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3224539', 'n_tokens_mistral': 4602, 'n_tokens_neox': 4394, 'n_words': 1507}