class TestCase::Operator::Ref {
  use TestCase::Point_3b;
  use TestCase::Point_3s;
  use TestCase::Point_3i;
  use TestCase::Point_3l;
  use TestCase::Point_3f;
  use TestCase::Point_3d;
  use Complex_2d;
  use Fn;
  use Array;

  static method numeric_ref_deref_byte : int () {
    my $num1 = Fn->INT8_MIN;
    
    my $num1_ref = \$num1;
    
    my $num2 = $$num1_ref;
    
    $$num1_ref = (byte)(Fn->INT8_MIN + 1);
    
    if ($num2 == Fn->INT8_MIN && $num1 == Fn->INT8_MIN + 1) {
      return 1;
    }
    
    return 0;
  }

  static method numeric_ref_deref_short : int () {
    my $num1 = Fn->INT16_MIN;
    
    my $num1_ref = \$num1;
    
    my $num2 = $$num1_ref;
    
    $$num1_ref = (short)(Fn->INT16_MIN + 1);
    
    if ($num2 == Fn->INT16_MIN && $num1 == Fn->INT16_MIN + 1) {
      return 1;
    }
    
    return 0;
  }

  static method numeric_ref_deref_int : int () {
    my $num1 = 4;
    
    my $num1_ref = \$num1;
    
    my $num2 = $$num1_ref;
    
    $$num1_ref = 5;
    
    if ($num2 == 4 && $num1 == 5) {
      return 1;
    }
    
    return 0;
  }

  static method numeric_ref_deref_long : int () {
    my $num1 = (long)Fn->INT64_MIN;
    
    my $num1_ref = \$num1;
    
    my $num2 = $$num1_ref;
    
    $$num1_ref = (long)(Fn->INT64_MIN + 1);
    
    if ($num2 == Fn->INT64_MIN && $num1 == Fn->INT64_MIN + 1) {
      return 1;
    }
    
    return 0;
  }

  static method numeric_ref_deref_float : int () {
    my $num1 = (float)Fn->FLT_MIN;
    
    my $num1_ref = \$num1;
    
    my $num2 = $$num1_ref;
    
    $$num1_ref = (float)(Fn->FLT_MIN + 1);
    
    if ($num2 == Fn->FLT_MIN && $num1 == Fn->FLT_MIN + 1) {
      return 1;
    }
    
    return 0;
  }

  static method numeric_ref_deref_double : int () {
    my $num1 = (double)Fn->DBL_MIN;
    
    my $num1_ref = \$num1;
    
    my $num2 = $$num1_ref;
    
    $$num1_ref = (double)(Fn->DBL_MIN + 1);
    
    if ($num2 == Fn->DBL_MIN && $num1 == Fn->DBL_MIN + 1) {
      return 1;
    }
    
    return 0;
  }
  
  static method mulnum_ref_deref_byte : int () {
    my $point1 : TestCase::Point_3b;
    
    $point1->{x} = Fn->INT8_MIN;
    $point1->{y} = 1;
    $point1->{z} = 2;
    
    my $point1_ref = \$point1;
    
    my $point2 = $$point1_ref;
    
    if ($point2->{x} == Fn->INT8_MIN && $point2->{y} == 1 && $point2->{z} == 2) {
      return 1;
    }
    return 0;
  }

  static method mulnum_ref_deref_get_field_byte : int () {
    my $point : TestCase::Point_3b;
    
    $point->{x} = Fn->INT8_MIN;
    $point->{y} = 1;
    $point->{z} = 2;
    
    my $point_ref = \$point;
    
    my $point_x = $point_ref->{x};
    my $point_y = $point_ref->{y};
    my $point_z = $point_ref->{z};
    
    if ($point_x == Fn->INT8_MIN && $point_y == 1 && $point_z == 2) {
      return 1;
    }
    return 0;
  }
  
  static method mulnum_ref_deref_set_field_byte : int () {
    my $point : TestCase::Point_3b;

    my $point_ref = \$point;
    
    $point->{x} = Fn->INT8_MIN;
    $point->{y} = 1;
    $point->{z} = 2;
    
    if ($point->{x} == Fn->INT8_MIN && $point->{y} == 1 && $point->{z} == 2) {
      return 1;
    }
    return 0;
  }
  
  static method test_pass_mulnum_ref_byte : int () {
    my $point_out : TestCase::Point_3b;
    
    my $point1 : TestCase::Point_3b;
    $point1->{x} = Fn->INT8_MIN;
    $point1->{y} = 1;
    $point1->{z} = 2;

    my $point2 : TestCase::Point_3b;
    $point2->{x} = 3;
    $point2->{y} = 4;
    $point2->{z} = 5;
    
    TestCase::Operator::Ref->pass_mulnum_ref_byte($point1, $point2, \$point_out);
    
    if ($point_out->{x} == Fn->INT8_MIN + 3 && $point_out->{y} == 5 && $point_out->{z} == 7) {
      return 1;
    }
    return 0;
  }
  
  static method pass_mulnum_ref_byte : void ($x_in1 : TestCase::Point_3b, $x_in2 : TestCase::Point_3b, $x_out : TestCase::Point_3b*) {
    $x_out->{x} = (byte)($x_in1->{x} + $x_in2->{x});
    $x_out->{y} = (byte)($x_in1->{y} + $x_in2->{y});
    $x_out->{z} = (byte)($x_in1->{z} + $x_in2->{z});
  }

  static method mulnum_ref_deref_short : int () {
    my $point1 : TestCase::Point_3s;
    
    $point1->{x} = Fn->INT16_MIN;
    $point1->{y} = 1;
    $point1->{z} = 2;
    
    my $point1_ref = \$point1;
    
    my $point2 = $$point1_ref;
    
    if ($point2->{x} == Fn->INT16_MIN && $point2->{y} == 1 && $point2->{z} == 2) {
      return 1;
    }
    return 0;
  }

  static method mulnum_ref_deref_get_field_short : int () {
    my $point : TestCase::Point_3s;
    
    $point->{x} = Fn->INT16_MIN;
    $point->{y} = 1;
    $point->{z} = 2;
    
    my $point_ref = \$point;
    
    my $point_x = $point_ref->{x};
    my $point_y = $point_ref->{y};
    my $point_z = $point_ref->{z};
    
    if ($point_x == Fn->INT16_MIN && $point_y == 1 && $point_z == 2) {
      return 1;
    }
    return 0;
  }
  
  static method mulnum_ref_deref_set_field_short : int () {
    my $point : TestCase::Point_3s;

    my $point_ref = \$point;
    
    $point->{x} = Fn->INT16_MIN;
    $point->{y} = 1;
    $point->{z} = 2;
    
    if ($point->{x} == Fn->INT16_MIN && $point->{y} == 1 && $point->{z} == 2) {
      return 1;
    }
    return 0;
  }
  
  static method test_pass_mulnum_ref_short : int () {
    my $point_out : TestCase::Point_3s;
    
    my $point1 : TestCase::Point_3s;
    $point1->{x} = Fn->INT16_MIN;
    $point1->{y} = 1;
    $point1->{z} = 2;

    my $point2 : TestCase::Point_3s;
    $point2->{x} = 3;
    $point2->{y} = 4;
    $point2->{z} = 5;
    
    TestCase::Operator::Ref->pass_mulnum_ref_short($point1, $point2, \$point_out);
    
    if ($point_out->{x} == Fn->INT16_MIN + 3 && $point_out->{y} == 5 && $point_out->{z} == 7) {
      return 1;
    }
    return 0;
  }
  
  static method pass_mulnum_ref_short : void ($x_in1 : TestCase::Point_3s, $x_in2 : TestCase::Point_3s, $x_out : TestCase::Point_3s*) {
    $x_out->{x} = (short)($x_in1->{x} + $x_in2->{x});
    $x_out->{y} = (short)($x_in1->{y} + $x_in2->{y});
    $x_out->{z} = (short)($x_in1->{z} + $x_in2->{z});
  }

  static method mulnum_ref_deref_double : int () {
    my $point1 : TestCase::Point_3d;
    
    $point1->{x} = Fn->DBL_MIN;
    $point1->{y} = 0.5;
    $point1->{z} = 0.125;
    
    my $point1_ref = \$point1;
    
    my $point2 = $$point1_ref;
    
    if ($point2->{x} == Fn->DBL_MIN && $point2->{y} == 0.5 && $point2->{z} == 0.125) {
      return 1;
    }
    return 0;
  }

  static method mulnum_ref_deref_int : int () {
    my $point1 : TestCase::Point_3i;
    
    $point1->{x} = Fn->INT32_MIN;
    $point1->{y} = 1;
    $point1->{z} = 2;
    
    my $point1_ref = \$point1;
    
    my $point2 = $$point1_ref;
    
    if ($point2->{x} == Fn->INT32_MIN && $point2->{y} == 1 && $point2->{z} == 2) {
      return 1;
    }
    return 0;
  }

  static method mulnum_ref_deref_get_field_int : int () {
    my $point : TestCase::Point_3i;
    
    $point->{x} = Fn->INT32_MIN;
    $point->{y} = 1;
    $point->{z} = 2;
    
    my $point_ref = \$point;
    
    my $point_x = $point_ref->{x};
    my $point_y = $point_ref->{y};
    my $point_z = $point_ref->{z};
    
    if ($point_x == Fn->INT32_MIN && $point_y == 1 && $point_z == 2) {
      return 1;
    }
    return 0;
  }
  
  static method mulnum_ref_deref_set_field_int : int () {
    my $point : TestCase::Point_3i;

    my $point_ref = \$point;
    
    $point->{x} = Fn->INT32_MIN;
    $point->{y} = 1;
    $point->{z} = 2;
    
    if ($point->{x} == Fn->INT32_MIN && $point->{y} == 1 && $point->{z} == 2) {
      return 1;
    }
    return 0;
  }
  
  static method test_pass_mulnum_ref_int : int () {
    my $point_out : TestCase::Point_3i;
    
    my $point1 : TestCase::Point_3i;
    $point1->{x} = Fn->INT32_MIN;
    $point1->{y} = 1;
    $point1->{z} = 2;

    my $point2 : TestCase::Point_3i;
    $point2->{x} = 3;
    $point2->{y} = 4;
    $point2->{z} = 5;
    
    TestCase::Operator::Ref->pass_mulnum_ref_int($point1, $point2, \$point_out);
    
    if ($point_out->{x} == Fn->INT32_MIN + 3 && $point_out->{y} == 5 && $point_out->{z} == 7) {
      return 1;
    }
    return 0;
  }
  
  static method pass_mulnum_ref_int : void ($x_in1 : TestCase::Point_3i, $x_in2 : TestCase::Point_3i, $x_out : TestCase::Point_3i*) {
    $x_out->{x} = (int)($x_in1->{x} + $x_in2->{x});
    $x_out->{y} = (int)($x_in1->{y} + $x_in2->{y});
    $x_out->{z} = (int)($x_in1->{z} + $x_in2->{z});
  }

  static method mulnum_ref_deref_long : int () {
    my $point1 : TestCase::Point_3l;
    
    $point1->{x} = Fn->INT64_MIN;
    $point1->{y} = 1;
    $point1->{z} = 2;
    
    my $point1_ref = \$point1;
    
    my $point2 = $$point1_ref;
    
    if ($point2->{x} == Fn->INT64_MIN && $point2->{y} == 1 && $point2->{z} == 2) {
      return 1;
    }
    return 0;
  }

  static method mulnum_ref_deref_get_field_long : int () {
    my $point : TestCase::Point_3l;
    
    $point->{x} = Fn->INT64_MIN;
    $point->{y} = 1;
    $point->{z} = 2;
    
    my $point_ref = \$point;
    
    my $point_x = $point_ref->{x};
    my $point_y = $point_ref->{y};
    my $point_z = $point_ref->{z};
    
    if ($point_x == Fn->INT64_MIN && $point_y == 1 && $point_z == 2) {
      return 1;
    }
    return 0;
  }
  
  static method mulnum_ref_deref_set_field_long : int () {
    my $point : TestCase::Point_3l;

    my $point_ref = \$point;
    
    $point->{x} = Fn->INT64_MIN;
    $point->{y} = 1;
    $point->{z} = 2;
    
    if ($point->{x} == Fn->INT64_MIN && $point->{y} == 1 && $point->{z} == 2) {
      return 1;
    }
    return 0;
  }
  
  static method test_pass_mulnum_ref_long : int () {
    my $point_out : TestCase::Point_3l;
    
    my $point1 : TestCase::Point_3l;
    $point1->{x} = Fn->INT64_MIN;
    $point1->{y} = 1;
    $point1->{z} = 2;

    my $point2 : TestCase::Point_3l;
    $point2->{x} = 3;
    $point2->{y} = 4;
    $point2->{z} = 5;
    
    TestCase::Operator::Ref->pass_mulnum_ref_long($point1, $point2, \$point_out);
    
    if ($point_out->{x} == Fn->INT64_MIN + 3 && $point_out->{y} == 5 && $point_out->{z} == 7) {
      return 1;
    }
    return 0;
  }
  
  static method pass_mulnum_ref_long : void ($x_in1 : TestCase::Point_3l, $x_in2 : TestCase::Point_3l, $x_out : TestCase::Point_3l*) {
    $x_out->{x} = (long)($x_in1->{x} + $x_in2->{x});
    $x_out->{y} = (long)($x_in1->{y} + $x_in2->{y});
    $x_out->{z} = (long)($x_in1->{z} + $x_in2->{z});
  }

  static method mulnum_ref_deref_float : int () {
    my $point1 : TestCase::Point_3f;
    
    $point1->{x} = Fn->FLT_MIN;
    $point1->{y} = 0.5f;
    $point1->{z} = 0.125f;
    
    my $point1_ref = \$point1;
    
    my $point2 = $$point1_ref;
    
    if ($point2->{x} == Fn->FLT_MIN && $point2->{y} == 0.5 && $point2->{z} == 0.125) {
      return 1;
    }
    return 0;
  }

  static method mulnum_ref_deref_get_field_float : int () {
    my $point : TestCase::Point_3f;
    
    $point->{x} = Fn->FLT_MIN;
    $point->{y} = 0.5f;
    $point->{z} = 0.125f;
    
    my $point_ref = \$point;
    
    my $point_x = $point_ref->{x};
    my $point_y = $point_ref->{y};
    my $point_z = $point_ref->{z};
    
    if ($point_x == Fn->FLT_MIN && $point_y == 0.5 && $point_z == 0.125) {
      return 1;
    }
    return 0;
  }
  
  static method mulnum_ref_deref_set_field_float : int () {
    my $point : TestCase::Point_3f;

    my $point_ref = \$point;
    
    $point_ref->{x} = Fn->FLT_MIN;
    $point_ref->{y} = 0.5f;
    $point_ref->{z} = 0.125f;
    
    if ($point->{x} == Fn->FLT_MIN && $point->{y} == 0.5 && $point->{z} == 0.125) {
      return 1;
    }
    return 0;
  }
  
  static method test_pass_mulnum_ref_float : int () {
    my $point_out : TestCase::Point_3f;
    
    my $point1 : TestCase::Point_3f;
    $point1->{x} = 0.25f;
    $point1->{y} = 0.5f;
    $point1->{z} = 0.125f;

    my $point2 : TestCase::Point_3f;
    $point2->{x} = 0.25f;
    $point2->{y} = 0.5f;
    $point2->{z} = 0.125f;
    
    TestCase::Operator::Ref->pass_mulnum_ref_float($point1, $point2, \$point_out);
    
    if ($point_out->{x} == 0.5 && $point_out->{y} == 1 && $point_out->{z} == 0.25) {
      return 1;
    }
    return 0;
  }
  
  static method pass_mulnum_ref_float : void ($x_in1 : TestCase::Point_3f, $x_in2 : TestCase::Point_3f, $x_out : TestCase::Point_3f*) {
    $x_out->{x} = $x_in1->{x} + $x_in2->{x};
    $x_out->{y} = $x_in1->{y} + $x_in2->{y};
    $x_out->{z} = $x_in1->{z} + $x_in2->{z};
  }

  static method mulnum_ref_deref_get_field_double : int () {
    my $point : TestCase::Point_3d;
    
    $point->{x} = Fn->DBL_MIN;
    $point->{y} = 0.5;
    $point->{z} = 0.125;
    
    my $point_ref = \$point;
    
    my $point_x = $point_ref->{x};
    my $point_y = $point_ref->{y};
    my $point_z = $point_ref->{z};
    
    if ($point_x == Fn->DBL_MIN && $point_y == 0.5 && $point_z == 0.125) {
      return 1;
    }
    return 0;
  }
  
  static method mulnum_ref_deref_set_field_double : int () {
    my $point : TestCase::Point_3d;

    my $point_ref = \$point;
    
    $point_ref->{x} = Fn->DBL_MIN;
    $point_ref->{y} = 0.5;
    $point_ref->{z} = 0.125;
    
    if ($point->{x} == Fn->DBL_MIN && $point->{y} == 0.5 && $point->{z} == 0.125) {
      return 1;
    }
    return 0;
  }
  
  static method test_pass_mulnum_ref_double : int () {
    my $point_out : TestCase::Point_3d;
    
    my $point1 : TestCase::Point_3d;
    $point1->{x} = 0.25;
    $point1->{y} = 0.5;
    $point1->{z} = 0.125;

    my $point2 : TestCase::Point_3d;
    $point2->{x} = 0.25;
    $point2->{y} = 0.5;
    $point2->{z} = 0.125;
    
    TestCase::Operator::Ref->pass_mulnum_ref_double($point1, $point2, \$point_out);
    
    if ($point_out->{x} == 0.5 && $point_out->{y} == 1 && $point_out->{z} == 0.25) {
      return 1;
    }
    return 0;
  }
  
  static method pass_mulnum_ref_double : void ($x_in1 : TestCase::Point_3d, $x_in2 : TestCase::Point_3d, $x_out : TestCase::Point_3d*) {
    $x_out->{x} = $x_in1->{x} + $x_in2->{x};
    $x_out->{y} = $x_in1->{y} + $x_in2->{y};
    $x_out->{z} = $x_in1->{z} + $x_in2->{z};
  }
  
  static method deep_call_simple : int () {
    
    my $count = 5;
    
    my $count_ref = \$count;
    
    &method_for_deep_call_only_count($count_ref);
    
    unless ($count == 0) {
      warn $count;
      return 0;
    }
    
    return 1;
  }
  
  static method method_for_deep_call_only_count : void ($count_ref : int*) {
    
    $$count_ref--;
    
    if ($$count_ref > 0) {
      &method_for_deep_call_only_count($count_ref);
    }
    
  }
  
  static method deep_call : int () {
    
    my $tmp = Complex_2d->new;
    
    my $count = 500;
    
    my $arg_int = 0;
    my $arg_double_complex = Complex_2d->new;
    
    &method_for_deep_call (\$count, $tmp, \$arg_int, \$arg_double_complex);
    
    unless ($arg_int == 5) {
      return 0;
    }
    
    unless ($arg_double_complex->{re} == 1) {
      return 0;
    }
    
    unless ($arg_double_complex->{im} == 2) {
      return 0;
    }
    
    return 1;
  }
  
  static method method_for_deep_call : void ($count_ref : int*, $tmp : Complex_2d, $arg_int_ref : int*, $arg_double_complex_ref : Complex_2d*) {
    $$arg_int_ref = 5;
    $arg_double_complex_ref->{re} = 1;
    $arg_double_complex_ref->{im} = 2;
    
    $$count_ref--;
    
    if ($$count_ref > 0) {
      &method_for_deep_call($count_ref, $tmp, $arg_int_ref, $arg_double_complex_ref);
    }
    
  }
}
