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

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

# u16 -- 16-bit unsigned integer values
#
public u16(public val u16) : num.wrap_around, has_interval is

  public thiz => u16.this.val

  # overflow checking

  # would negation -thiz cause an overflow?
  redef wrapped_on_neg => !is_zero

  # would addition thiz + other cause an overflow or underflow?
  public fixed overflow_on_add (other u16) => u16.type.max -° thiz < other
  public fixed underflow_on_add(other u16) => false

  # would subtraction thiz - other cause an overflow or underflow?
  public fixed overflow_on_sub (other u16) => false
  public fixed underflow_on_sub(other u16) => thiz < other

  # would multiplication thiz * other cause an overflow or underflow?
  public fixed overflow_on_mul (other u16) => as_i32 *° other.as_i32 > u16.type.max.as_i32
  public fixed underflow_on_mul(other u16) => false

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

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

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

  # bitwise and, or and xor operations
  public fixed infix &  (other u16) u16 is intrinsic
  public fixed infix |  (other u16) u16 is intrinsic
  public fixed infix ^  (other u16) u16 is intrinsic

  # shift operations (unsigned)
  public fixed infix >> (other u16) u16 is intrinsic
  public fixed infix << (other u16) u16 is intrinsic

  public as_i8 i8
    pre
      debug: thiz ≤ i8.type.max.as_u16
    is
      cast_to_i16.as_i8
  public as_i16 i16
    pre
      debug: thiz ≤ i16.type.max.as_u16
    is
      cast_to_i16
  public as_i32 i32 is intrinsic
  public as_i64  => thiz.as_i32.as_i64
# as_i128 => thiz.as_i32.as_i128
  public as_u8 u8
    pre
      thiz ≤ u8.type.max.as_u16
    is
      low8bits
  public as_u32  => thiz.as_i32.as_u32
  public as_u64  => thiz.as_i32.as_u64
  public as_u128 => thiz.as_i32.as_u128
  public as_int  => int as_i64

  public low8bits u8 is intrinsic
  public cast_to_i16 i16 is intrinsic

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


  # create hash code from this number
  public type.hash_code(a u16.this) u64 is
    hash a.as_u64


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


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


  # count the number of 1 bits in the binary representation of this
  # integer.
  #
  public ones_count i32 is
    v := val.as_i32
    m := v & 0xaaaa; v := v - m + (m >> 1)
    m := v & 0xcccc; v := v - m + (m >> 2)
    m := v & 0xf0f0; v := v - m + (m >> 4)
    (v + (v >> 8)) & 0x1f


  # -----------------------------------------------------------------------
  #
  # type features:


  # identity element for 'infix +'
  #
  fixed type.zero u16 is 0


  # identity element for 'infix *'
  #
  fixed type.one  u16 is 1


  # equality
  #
  fixed type.equality(a, b u16) bool is intrinsic_constructor


  # total order
  #
  fixed type.lteq(a, b u16) bool is intrinsic_constructor


  # returns the number in whose bit representation all bits are ones
  fixed redef type.all_bits_set => u16 0xffff


  # minimum
  #
  public fixed type.min => u16 0


  # maximum
  #
  public fixed type.max => u16 0xffff