Fuzion Logo
fuzion-lang.dev — The Fuzion Language Portal
JavaScript seems to be disabled. Functionality is limited.

interval.fz


# This file is part of the Fuzion language implementation.
#
# The Fuzion language implementation is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, version 3 of the License.
#
# The Fuzion language implementation is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License along with The
# Fuzion language implementation.  If not, see <https://www.gnu.org/licenses/>.


# -----------------------------------------------------------------------
#
#  Tokiwa Software GmbH, Germany
#
#  Source code of Fuzion standard library feature interval
#
#  Author: Fridtjof Siebert (siebert@tokiwa.software)
#
# -----------------------------------------------------------------------


# An interval `from..through` that includes `from`, `from+step`, `from+step+step`,
# etc. up to and including `through`.
#
# In case step is positive (negative), the first value larger (smaller) than
# through will not be included.
#
# In case `step.sign = (from ⋄ through).sign`, this `Set` is empty, e.g.,
# `interval 1 2 -1` and `interval 2 1 1` are both empty.
#
public interval(T type : integer,

                # the first element of this Set when used as a Sequence
                public from T,

                # upper/lower bound for elements in this Set
                #
                # in case this is nil, there is no bound except for the
                # range of legal values for T.
                public through option T,

                # the distance between to elements
                public step T)

  : container.Set T

pre
  debug: ((step.sign = 0): through.as_equatable=from)  # step cannot be zero unless from=through
is


  # Create an new interval with `step` multiplied by `step_factor`.
  #
  # This is typically applied to an interval with implicit `step` of one,
  # e.g., in `2..10:2` will create "{2,4,6,8,10}".
  #
  public infix : (step_factor T) interval T
  pre
    debug: ((step_factor.sign = 0): through.as_equatable=from)  # step cannot be zero unless from=through
    safety: (step *? step_factor).exists
  =>
    interval from through step*step_factor


  # list representation of values in this interval
  #
  public redef as_list list T =>
    if (through ? nil => false
                | thru T => step.sign = (from ⋄ thru).sign) then
      nil
    else
      tail => (from+?step ? next T => (interval next through step).as_list
                          | nil    => nil)
      from : tail


  # get the number of elements in this interval
  #
  # Performance O(1) in case  through.exists, otherwise O(result)
  #
  public size T
  =>
    match through
      thru T =>
        if from = thru then
          T.one
        else if step.sign = (from ⋄ thru).sign then
          T.zero
        else
          (thru - from) / step + T.one
      nil =>
        T.from_u32 as_list.count.as_u32


  # does this interval contain the given value?
  #
  public redef contains(e T) bool =>
    if      step.sign > 0 then from <= e <= through.or_else e && (e %  step = from %  step)
    else if step.sign < 0 then from >= e >= through.or_else e && (e % -step = from % -step)
    else                       from =  e


  # string representation of this interval, e.g., "1..10:2"
  #
  public redef as_string String =>
    thru := through.bind ($)
                   .or_else ()->if step.sign < 0 then "-∞" else "∞"
    "$from..$thru{if step = T.one then "" else ":$step"}"


  # create a new interval from a sequence of elements
  #
  public fixed redef type.new (s Sequence T) container.Set T =>
    container.set_of_ordered s


  # is this sequence known to be finite?  For infinite sequences, features like
  # count diverge.
  #
  public redef finite trit =>
    if through.exists then trit.yes else trit.no



# has_interval -- feature for integers that can define an interval
#
public has_interval : integer is


  # defining an integer interval from this to other, both inclusive
  #
  # special cases of interval a..b:
  #
  #     a <  b: the interval from a to b, both inclusive
  #     a == b: the interval containing only one element, a
  #     a >  b: an empty interval
  public infix .. (through has_interval.this) interval has_interval.this =>
    interval has_interval.this through has_interval.this.one


  # an infinite integer Sequence starting from this up to the maximum value
  # has_interval.this.max
  #
  public postfix .. interval has_interval.this =>
    interval has_interval.this nil has_interval.this.one


  # an infinite integer Sequence starting from this up to the maximum value
  # has_interval.this.max
  #
  # NYI: CLEANUP: Eventually remove `postfix ..` or `postfix ..∞` in favor of the
  # other one, for now this is here to show that `∞` is a legal symbol in an operator.
  #
  public postfix ..∞ interval has_interval.this =>
    postfix ..
last changed: 2025-07-10