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(H (hasInterval H).type) : integer H is
  max  H 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 H) : Set H is

    lower H 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 H is if lower <= upper then upper - lower + one else zero

    # apply function f to all elements in this interval
    redef forAll(f H -> 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 H is
      x := numOption lower
      redef hasNext bool is x.exists && x.val <= upper
      redef next H is res := x.val; set x := x +? one; res


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


    # Create a Sequence that is stepping 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 H) : Set H is

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


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


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


      # use map implementation from Sequence:
      #
      map(B type, f H -> B)  => mapSequence f


    # create a list from this interval
    #
    redef asList list H is
      cons (head H) : Cons H (list H) is
        tail list H 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 type, f H -> B)  => mapSequence f


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


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

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