Example #1
0
  public static RubyNumeric intervalStepSize(
      ThreadContext context,
      IRubyObject from,
      IRubyObject to,
      IRubyObject step,
      boolean excludeLast) {
    Ruby runtime = context.runtime;

    if (from instanceof RubyFixnum && to instanceof RubyFixnum && step instanceof RubyFixnum) {
      long diff = ((RubyFixnum) step).getLongValue();
      if (diff == 0) {
        return RubyFloat.newFloat(runtime, Double.POSITIVE_INFINITY);
      }

      long delta = ((RubyFixnum) to).getLongValue() - ((RubyFixnum) from).getLongValue();
      if (diff < 0) {
        diff = -diff;
        delta = -delta;
      }
      if (excludeLast) {
        delta--;
      }
      if (delta < 0) {
        return runtime.newFixnum(0);
      }

      long result = delta / diff;
      return new RubyFixnum(runtime, result >= 0 ? result + 1 : 0);
    } else if (from instanceof RubyFloat || to instanceof RubyFloat || step instanceof RubyFloat) {
      double n =
          floatStepSize(
              from.convertToFloat().getDoubleValue(),
              to.convertToFloat().getDoubleValue(),
              step.convertToFloat().getDoubleValue(),
              excludeLast);

      if (Double.isInfinite(n)) {
        return runtime.newFloat(n);
      } else {
        return runtime.newFloat(n).convertToInteger();
      }
    } else {
      String cmpString = ">";
      RubyFixnum zero = RubyFixnum.zero(runtime);
      IRubyObject comparison = zero.coerceCmp(context, "<=>", step);

      switch (RubyComparable.cmpint(context, comparison, step, zero)) {
        case 0:
          return RubyFloat.newFloat(runtime, Float.POSITIVE_INFINITY);
        case 1:
          cmpString = "<";
          break;
      }

      if (from.callMethod(context, cmpString, to).isTrue()) {
        return RubyFixnum.zero(runtime);
      }

      IRubyObject diff = to.callMethod(context, "-", from);
      IRubyObject result = diff.callMethod(context, "div", step);
      if (!excludeLast
          || from.callMethod(context, "+", result.callMethod(context, "*", step))
              .callMethod(context, cmpString, to)
              .isTrue()) {
        result = result.callMethod(context, "+", RubyFixnum.newFixnum(runtime, 1));
      }
      return (RubyNumeric) result;
    }
  }