diff --git a/core/formula/doc/index.rst b/core/formula/doc/index.rst index f4ffd3f03d..811412cf51 100644 --- a/core/formula/doc/index.rst +++ b/core/formula/doc/index.rst @@ -148,6 +148,9 @@ and toIndex. The indexes must be valid, e.g. fromIndex > 0, fromIndex < toIndex **arrayRangeOf(VNumberArray array)** - Returns a Display Range of the given array This includes the display min, max +**arrayReversal(VNumberArray array)** - Returns a VNumberArray with the elements in reverse order +(the first element becomes the last, the last becomes the first). + **arrayStats(VNumberArray array)** - Returns a VStatistic with the statistical information of the given array This includes the average, min, max, and element count @@ -163,8 +166,6 @@ The down-sampling is performed using the Largest-Triangle-Three-Buckets (LTTB) a **arrayCumSum(VNumberArray array)** - Returns a VNumberArray where each element is defined as the cumulative sum of the input array. -String ------- **concat(String s...)** - Concatenate a list of strings of a string array. **strEqual(String s1, String s2)** - Compare value of 2 strings. Return true if s1 equals s2, else false. diff --git a/core/formula/src/main/java/org/csstudio/apputil/formula/array/ArrayReversalFunction.java b/core/formula/src/main/java/org/csstudio/apputil/formula/array/ArrayReversalFunction.java new file mode 100644 index 0000000000..4fb0dc7d15 --- /dev/null +++ b/core/formula/src/main/java/org/csstudio/apputil/formula/array/ArrayReversalFunction.java @@ -0,0 +1,98 @@ +package org.csstudio.apputil.formula.array; + +import org.csstudio.apputil.formula.Formula; +import org.epics.util.array.ListDouble; +import org.epics.util.array.ListNumber; +import org.epics.vtype.Alarm; +import org.epics.vtype.Display; +import org.epics.vtype.VNumberArray; +import org.epics.vtype.VType; +import org.phoebus.core.vtypes.VTypeHelper; + +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; + +/** + * A formula function for reversing the given array. + *

+ * The function allows for reversing the order of elements in an array, such that the first element + * becomes the last, the second element becomes the second to last, and so on. + *

+ * + * Arguments: + * + * + * Example: + *

+ * If given an array [1, 2, 3, 4, 5], the result will be [5, 4, 3, 2, 1]. + *

+ * + * @author Kunal Shroff + */ +public class ArrayReversalFunction extends BaseArrayFunction { + + @Override + public String getName() { + return "arrayReverse"; + } + + @Override + public String getDescription() { + return "Reverses the given numeric array so that the first element becomes the last and vice versa."; + } + + @Override + public List getArguments() { + return List.of("array"); + } + + /** + * Reverses the elements of a numeric array. + * + * @param array The input numeric array (VNumberArray) to reverse. + * @return A {@link VNumberArray} containing the reversed elements. + */ + protected VType getArrayData(final VNumberArray array) { + return VNumberArray.of(reverse(array.getData()), Alarm.none(), array.getTime(), Display.none()); + } + + private static ListDouble reverse(final ListNumber data) { + return new ListDouble() { + @Override + public double getDouble(int index) { + return data.getDouble(data.size() - 1 - index); + } + + @Override + public int size() { + return data.size(); + } + }; + } + + /** + * Computes the function's result by reversing the provided array. + * + * @param args The arguments to the function: + * - args[0]: The input array to reverse. + * @return A {@link VType} containing the reversed array. + * @throws Exception If an invalid number of arguments or incorrect argument types are provided. + */ + @Override + public VType compute(final VType... args) throws Exception { + if (args.length != 1) { + throw new Exception("Function " + getName() + + " requires 1 argument but received " + Arrays.toString(args)); + } + if (!VTypeHelper.isNumericArray(args[0])) { + Formula.logger.log(Level.WARNING, "Function " + getName() + + " takes array but received " + Arrays.toString(args)); + return DEFAULT_NAN_DOUBLE_ARRAY; + } else { + return getArrayData((VNumberArray) args[0]); + } + } +} diff --git a/core/formula/src/main/resources/META-INF/services/org.csstudio.apputil.formula.spi.FormulaFunction b/core/formula/src/main/resources/META-INF/services/org.csstudio.apputil.formula.spi.FormulaFunction index 8380212c2e..1da8cbd7a3 100644 --- a/core/formula/src/main/resources/META-INF/services/org.csstudio.apputil.formula.spi.FormulaFunction +++ b/core/formula/src/main/resources/META-INF/services/org.csstudio.apputil.formula.spi.FormulaFunction @@ -59,6 +59,7 @@ org.csstudio.apputil.formula.array.ArrayScalarDivisionFunction org.csstudio.apputil.formula.array.ArrayInverseScalarDivisionFunction org.csstudio.apputil.formula.array.ArrayOfFunction org.csstudio.apputil.formula.array.ArrayRangeOfFunction +org.csstudio.apputil.formula.array.ArrayReversalFunction org.csstudio.apputil.formula.array.ArraySampleWithLTTBFunction org.csstudio.apputil.formula.array.ArraySampleWithStrideFunction org.csstudio.apputil.formula.array.ArrayStatsFunction diff --git a/core/formula/src/test/java/org/csstudio/apputil/formula/array/ArrayReversalFunctionTest.java b/core/formula/src/test/java/org/csstudio/apputil/formula/array/ArrayReversalFunctionTest.java new file mode 100644 index 0000000000..6ca04aa43f --- /dev/null +++ b/core/formula/src/test/java/org/csstudio/apputil/formula/array/ArrayReversalFunctionTest.java @@ -0,0 +1,54 @@ +package org.csstudio.apputil.formula.array; + +import org.epics.util.array.ArrayDouble; +import org.epics.util.array.ListDouble; +import org.epics.vtype.Alarm; +import org.epics.vtype.Display; +import org.epics.vtype.Time; +import org.epics.vtype.VNumberArray; +import org.epics.vtype.VType; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + +class ArrayReversalFunctionTest { + private final ArrayReversalFunction function = new ArrayReversalFunction(); + + @Test + void testReverseTypicalArray() throws Exception { + VNumberArray input = VNumberArray.of(ArrayDouble.of(1, 2, 3, 4, 5), Alarm.none(), Time.now(), Display.none()); + VType result = function.compute(input); + assertTrue(result instanceof VNumberArray); + double[] reversed = ((VNumberArray) result).getData().toArray(new double[input.getData().size()]); + assertArrayEquals(new double[]{5, 4, 3, 2, 1}, reversed, 1e-9); + } + + @Test + void testReverseEmptyArray() throws Exception { + VNumberArray input = VNumberArray.of(ArrayDouble.of(), Alarm.none(), Time.now(), Display.none()); + VType result = function.compute(input); + assertTrue(result instanceof VNumberArray); + double[] reversed = ((VNumberArray) result).getData().toArray(new double[input.getData().size()]); + assertArrayEquals(new double[]{}, reversed, 1e-9); + } + + @Test + void testReverseSingleElementArray() throws Exception { + VNumberArray input = VNumberArray.of(ArrayDouble.of(42), Alarm.none(), Time.now(), Display.none()); + VType result = function.compute(input); + assertTrue(result instanceof VNumberArray); + double[] reversed = ((VNumberArray) result).getData().toArray(new double[input.getData().size()]); + assertArrayEquals(new double[]{42}, reversed, 1e-9); + } + + @Test + void testReverseNegativeNumbers() throws Exception { + VNumberArray input = VNumberArray.of(ArrayDouble.of(-1, -2, -3), Alarm.none(), Time.now(), Display.none()); + VType result = function.compute(input); + assertTrue(result instanceof VNumberArray); + double[] reversed = ((VNumberArray) result).getData().toArray(new double[input.getData().size()]); + assertArrayEquals(new double[]{-3, -2, -1}, reversed, 1e-9); + } +}