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

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

# u32 -- 32-bit unsigned integer values
#
u32(val u32) : wrappingInteger u32, hasInterval u32, u32s is

  redef thiz => u32.this.val
  redef orderedThis => u32.this.val

  # overflow checking

  # would negation -thiz cause an overflow?
  redef wrappedOnNeg => !isZero

  # would addtion thiz + other cause an overflow or underflow?
  redef overflowOnAdd (other u32) => max -° thiz < other
  redef underflowOnAdd(other u32) => false

  # would subtraction thiz - other cause an overflow or underflow?
  redef overflowOnSub (other u32) => false
  redef underflowOnSub(other u32) => thiz < other

  # would multiplication thiz * other cause an overflow or underflow?
  redef overflowOnMul (other u32) => as_i64 *° other.as_i64 > max.as_i64
  redef underflowOnMul(other u32) => false

  # neg, add, sub, mul with wrap-around semantics
  redef prefix -° u32 is intrinsic
  redef infix +° (other u32) u32 is intrinsic
  redef infix -° (other u32) u32 is intrinsic
  redef infix *° (other u32) u32 is intrinsic

  # division and remainder with check for div-by-zero
  redef infix / (other u32)
    pre
      safety: other != 0
   => div(other)
  redef infix % (other u32)
    pre
      safety: other != 0
   => mod(other)

  # private division and remainder with crash in case of div-by-zero
  private div (other u32) u32 is intrinsic
  private mod (other u32) u32 is intrinsic

  # bitwise and, or and xor operations
  redef infix &  (other u32) u32 is intrinsic
  redef infix |  (other u32) u32 is intrinsic
  redef infix ^  (other u32) u32 is intrinsic

  # shift operations (unsigned)
  redef infix >> (other u32) u32 is intrinsic
  redef infix << (other u32) u32 is intrinsic

  # comparison
  redef infix == (other u32) bool is intrinsic
  redef infix != (other u32) bool is intrinsic
  redef infix <  (other u32) bool is intrinsic
  redef infix <= (other u32) bool is intrinsic
  redef infix >  (other u32) bool is intrinsic
  redef infix >= (other u32) bool is intrinsic

  as_i8 i8
    pre
      debug: thiz <= i8.max.as_u32
    is
      castTo_i32.as_i8
  as_i16 i16
    pre
      debug: thiz <= i16.max.as_u32
    is
      castTo_i32.as_i16
  as_i32 i32
    pre
      debug: thiz <= i32.max.as_u32
    is
      castTo_i32
  as_i64 i64 is intrinsic
# as_i128 i128 is as_i64.as_i128
  as_u8 u8
    pre
      debug: thiz <= u8.max.as_u32
    is
      castTo_i32.as_u8
  as_u16 u16
    pre
      debug: thiz <= u16.max.as_u32
    is
      castTo_i32.as_u16
  as_u64 u64
    is
      thiz.as_i64.as_u64
  as_u128 u128
    is
      u128 0 as_u64
  as_int  => int as_i64

  low8bits  u8  is intrinsic
  low16bits u16 is intrinsic
  castTo_i32 i32 is intrinsic
  castTo_f32 f32 is intrinsic

  # conversion to float
  as_f64 f64 is intrinsic
  as_f32 => as_f64.as_f32

  # NYI: max is redefined here only to solve repeated inheritance conflict. Since max inherited
  # from hasInterval is abstract, fz should not complain about this conflict.
  redef max => u32 0x_ffff_ffff


  # create hash code from this number
  hash u64 is
    as_u64.hash


  # find the highest 1 bit in this integer and return integer with
  # this single bit set or 0 if this is 0.
  #
  highestOneBit u32 is
    // NYI: should be possible to reuse v, s names
    (v0, s0) := (val, u32 0)
    (v1, s1) := if (v0 >= 0 && v0 < 0x10000) (v0, s0) else (v0 >> 16, s0 + 16)
    (v2, s2) := if (           v1 <   0x100) (v1, s1) else (v1 >>  8, s1 +  8)
    (v3, s3) := if (           v2 <    0x10) (v2, s2) else (v2 >>  4, s2 +  4)
    (v4, s4) := if (           v3 <       4) (v3, s3) else (v3 >>  2, s3 +  2)
    (v5, s5) := if (           v4 <       2) (v4, s4) else (v4 >>  1, s4 +  1)
    v5 << s5


  # the highest 1 bit in this integer
  #
  highest_bit u32 is
    if val = zero
      0
    else
      // NYI: should be possible to reuse v, s names
      (v0, s0) := (val, u32 0)
      (v1, s1) := if (v0 >= 0 && v0 < 0x10000) (v0, s0) else (v0 >> 16, s0 + 16)
      (v2, s2) := if (           v1 <   0x100) (v1, s1) else (v1 >>  8, s1 +  8)
      (v3, s3) := if (           v2 <    0x10) (v2, s2) else (v2 >>  4, s2 +  4)
      (v4, s4) := if (           v3 <       4) (v3, s3) else (v3 >>  2, s3 +  2)
      (v5, s5) := if (           v4 <       2) (v4, s4) else (v4 >>  1, s4 +  1)
      s5 + 1


  # count the number of trailing zeros in this integer.
  #
  trailingZeros i32 is
    // NYI: should be possible to reuse v, s names
    (v0, s0) := (val, 0)
    (v1, s1) := if (v0 &     0xffff)/=0 (v0, s0) else (v0 >> 16, s0 + 16)
    (v2, s2) := if (v1 &       0xff)/=0 (v1, s1) else (v1 >>  8, s1 +  8)
    (v3, s3) := if (v2 &        0xf)/=0 (v2, s2) else (v2 >>  4, s2 +  4)
    (v4, s4) := if (v3 &          3)/=0 (v3, s3) else (v3 >>  2, s3 +  2)
    (v5, s5) := if (v4 &          1)/=0 (v4, s4) else (v4 >>  1, s4 +  1)
    s6       := if (v5 &          1)/=0      s5  else                 32
    s6


  # count the number of 1 bits in the binary representation of this
  # integer.
  #
  onesCount i32 is
    v := val;
    m := v & 0xaaaaaaaa; v := v - m + (m >> 1)
    m := v & 0xcccccccc; v := v - m + (m >> 2)
    m := v & 0xf0f0f0f0; v := v - m + (m >> 4)
    (v *° 0x01010101 >> 24).as_i32


# u32s -- unit type defining features related to u32 but not requiring an
# instance
#
u32s : wrappingIntegers u32 is

  redef name => "u32"

  redef zero => u32 0
  redef one  => u32 1

  redef min => u32 0
  redef max => u32 0x_ffff_ffff


# u32 -- returns value of unit type u32s
#
# This is a convenience feature that allows using, e.g., 'u32.sum' to
# get the the monoid of (u32, infix +) instead of 'u32s.sum'.
#
# since this u32 with no arguments is a routine and not a constructor, it
# does not define a type (which would cause a name clash with u32 with one
# argument).
#
u32 => u32s