001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.commons.svl.functions;
018
019import org.apache.juneau.commons.svl.*;
020
021/**
022 * Arithmetic functions for the {@code #{...}} script catalog.
023 *
024 * <p>
025 * All operations work on {@code double} so integer and decimal inputs compose naturally; the
026 * result renders as a String. Integer-perfect results omit the decimal point (e.g.
027 * {@code add(2, 3)} returns {@code "5"}, not {@code "5.0"}).
028 */
029public final class ArithmeticFunctions {
030
031   private ArithmeticFunctions() {}
032
033   /** All function classes in this category. */
034   @SuppressWarnings({
035      "java:S2386", // ALL is an immutable compile-time registry; exposed as an array for the cross-package/varargs functions(...) API, so visibility cannot be reduced.
036      "unchecked" // Cast is safe: type verified by caller context.
037   })
038   public static final Class<? extends VarFunction>[] ALL = new Class[] {
039      Add.class, Subtract.class, Multiply.class, Divide.class, Modulo.class,
040      Min.class, Max.class, Abs.class
041   };
042
043   /** Render a double as a String, dropping the decimal portion when it's an exact integer. */
044   static String render(double v) {
045      if (Double.isNaN(v) || Double.isInfinite(v)) return String.valueOf(v);
046      if (v == Math.floor(v) && Math.abs(v) < 1e18)
047         return String.valueOf((long) v);
048      return String.valueOf(v);
049   }
050
051   /** {@code #{add(a, b)}} — returns {@code a + b}. */
052   public static class Add extends TypedFunction {
053      @Override public String name() { return "add"; }
054      public String invoke(double a, double b) { return render(a + b); }
055   }
056
057   /** {@code #{subtract(a, b)}} — returns {@code a - b}. */
058   public static class Subtract extends TypedFunction {
059      @Override public String name() { return "subtract"; }
060      public String invoke(double a, double b) { return render(a - b); }
061   }
062
063   /** {@code #{multiply(a, b)}} — returns {@code a * b}. */
064   public static class Multiply extends TypedFunction {
065      @Override public String name() { return "multiply"; }
066      public String invoke(double a, double b) { return render(a * b); }
067   }
068
069   /** {@code #{divide(a, b)}} — returns {@code a / b}. {@code b = 0} returns {@code Infinity} or {@code NaN} per IEEE 754. */
070   public static class Divide extends TypedFunction {
071      @Override public String name() { return "divide"; }
072      public String invoke(double a, double b) { return render(a / b); }
073   }
074
075   /** {@code #{modulo(a, b)}} — returns {@code a % b}. */
076   public static class Modulo extends TypedFunction {
077      @Override public String name() { return "modulo"; }
078      public String invoke(double a, double b) { return render(a % b); }
079   }
080
081   /** {@code #{min(a, b)}} — returns the smaller of two numbers. */
082   public static class Min extends TypedFunction {
083      @Override public String name() { return "min"; }
084      public String invoke(double a, double b) { return render(Math.min(a, b)); }
085   }
086
087   /** {@code #{max(a, b)}} — returns the larger of two numbers. */
088   public static class Max extends TypedFunction {
089      @Override public String name() { return "max"; }
090      public String invoke(double a, double b) { return render(Math.max(a, b)); }
091   }
092
093   /** {@code #{abs(a)}} — returns the absolute value of {@code a}. */
094   public static class Abs extends TypedFunction {
095      @Override public String name() { return "abs"; }
096      public String invoke(double a) { return render(Math.abs(a)); }
097   }
098}