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

hasInterval.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 hasInterval
#
#  Author: Fridtjof Siebert (siebert@tokiwa.software)
#
# -----------------------------------------------------------------------

# hasInterval -- feature for integers that can define an interval
#
hasInterval<T: hasInterval<T>> : integer<T> is
  max  T is abstract
/*
  zero T is abstract
  one  T is abstract
  infix +  (other T) T is abstract
  infix -  (other T) T is abstract
  infix <= (other T) bool is abstract
  infix >= (other T) bool is abstract
  infix <  (other T) bool is abstract
  infix >  (other T) bool is abstract
*/

  # 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
  infix .. (upper T) : Set<T> is

    lower T is thiz
    # lower => hasInterval.this  # NYI: This does not work yet since the result type when doing clazz layout is hasInterval and not the actual clazz (i32, etc)

    size T is if lower <= upper then upper - lower + one else zero

    # apply function f to all elements in this interval
    redef forAll(f T -> unit) unit is
      for
        x := lower, x + one
      while x <= upper
        f x

    # create a stream of all the elements of this interval, in order.
    redef asStream ref : stream<T> is
      x := numOption lower
      redef hasNext bool is x.exists && x.val <= upper
      redef next T is res := x.val; set x := x +? one; res


    # does this range contain the given value?
    #
    contains (e T) => lower <= e <= upper


    # Create a Sequence that is steping through this interval skipping values. For a
    # non-negative step parameter, the stream will return lower, lower+step,
    # lower+2*step, etc. as long as these values are <= upper.
    #
    # For a negative step parameter, the stream will return upper, upper+step,
    # upper+2*step, etc. as long as these values are >= lower.  Note that this means
    # that a negative step will produce a non-empty stream for an empty interval with
    # lower > upper!
    #
    infix : (step T) : Set<T> is

      # create a stream of all the elements of this interval, in order.
      redef asStream ref : stream<T> is
        x := numOption lower
        redef hasNext bool is
          (step > zero && x.exists && x.val <= upper ||
           step < zero && x.exists && x.val >= upper    )
        redef next T is res := x.val; set x := x +? step; res


      # list representation of values in this interval
      #
      redef asList list<T> is
        cons (head T) :  Cons<T, list<T>> is
          tail list<T> is
            (lower+?step ? nil    => nil
                         | next T => (next..upper:step).asList.asList)
        if (step > zero && lower <= upper ||
            step < zero && lower >= upper    )
          cons lower
        else
          nil


      # does this range contain the given value?
      #
      contains (e T) => lower <= e <= upper && ((e - lower) %% step)


      # use map implementation from Sequence:
      #
      map<B>(f T -> B)  => mapSequence f


    # create a list from this interval
    #
    redef asList list<T> is
      cons (head T) : Cons<T, list<T>> is
        tail list<T> is
          if (head >= upper) nil else cons head+head.one // NYI should be '+ one', but does not work yet since outer.outer.outer.clazz is hasInterval<i32>, it should be i32.
      if (lower > upper) nil else cons lower


    # use map implementation from Sequence:
    #
    map<B>(f T -> B)  => mapSequence f


    # string representation of this interval, e.g., "1..10"
    #
    redef asString => "$lower..$upper"


  # the open interval from this to the maximum T value
  postfix .. () infix .. is
    hasInterval.this..max

  # postfix .. : infix .. (max) is  # NYI: check: this should have the same effect using a sub-class