From 1514024f3441005732711fd0cab0b59b983bc71a Mon Sep 17 00:00:00 2001 From: arisnguyenit97 Date: Sun, 26 May 2024 00:27:16 +0700 Subject: [PATCH] :sparkles: feat: add unify functions for Collection4j, Byte4j and Array4j #4 --- .../groovy/org/unify4j/common/Array4j.java | 144 ++++++++++++++++++ .../groovy/org/unify4j/common/Byte4j.java | 10 +- .../org/unify4j/common/Collection4j.java | 48 ++++++ 3 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 plugin/src/main/groovy/org/unify4j/common/Array4j.java diff --git a/plugin/src/main/groovy/org/unify4j/common/Array4j.java b/plugin/src/main/groovy/org/unify4j/common/Array4j.java new file mode 100644 index 0000000..a4c0007 --- /dev/null +++ b/plugin/src/main/groovy/org/unify4j/common/Array4j.java @@ -0,0 +1,144 @@ +package org.unify4j.common; + +import java.lang.reflect.Array; +import java.util.Arrays; + +public class Array4j { + public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; + public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + public static final char[] EMPTY_CHAR_ARRAY = new char[0]; + public static final Character[] EMPTY_CHARACTER_ARRAY = new Character[0]; + public static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + + /** + * Checks if the specified array is empty or null. + *

+ * An array is considered empty if it is either null or has a length of zero. + * + * @param array The array to check for emptiness. + * @return {@code true} if the array is empty or null, {@code false} otherwise. + */ + public static boolean isEmpty(final Object array) { + return array == null || Array.getLength(array) == 0; + } + + /** + * Retrieves the size of the specified array. + *

+ * If the array is null, the size returned is 0. + * + * @param array The array to determine the size of. + * @return The size of the array. Returns 0 if the array is null. + */ + public static int size(final Object array) { + return array == null ? 0 : Array.getLength(array); + } + + /** + *

Shallow copies an array of Objects + *

+ *

The objects in the array are not cloned, thus there is no special + * handling for multi-dimensional arrays. + *

+ *

This method returns null if null array input.

+ * + * @param array the array to shallow clone, may be null + * @param the array type + * @return the cloned array, null if null input + */ + public static T[] shallowCopy(final T[] array) { + if (isEmpty(array)) { + return null; + } + return array.clone(); + } + + /** + * Adds all the elements of the given arrays into a new array. + *

+ * The new array contains all of the elements of the first array followed + * by all of the elements of the second array. When an array is returned, + * it is always a new array. + *

+ *
+     * ArrayUtilities.addAll(null, null)     = null
+     * ArrayUtilities.addAll(array1, null)   = cloned copy of array1
+     * ArrayUtilities.addAll(null, array2)   = cloned copy of array2
+     * ArrayUtilities.addAll([], [])         = []
+     * ArrayUtilities.addAll([null], [null]) = [null, null]
+     * ArrayUtilities.addAll(["a", "b", "c"], ["1", "2", "3"]) = ["a", "b", "c", "1", "2", "3"]
+     * 
+ * + * @param array1 the first array whose elements are added to the new array, may be null + * @param array2 the second array whose elements are added to the new array, may be null + * @param the array type + * @return The new array, null if null array inputs. + * The type of the new array is the type of the first array. + */ + @SuppressWarnings("unchecked") + public static T[] addAll(final T[] array1, final T[] array2) { + if (isEmpty(array1)) { + return shallowCopy(array2); + } else if (isEmpty(array2)) { + return shallowCopy(array1); + } + // Create a new array with a length equal to the sum of the lengths of array1 and array2. + final T[] newArray = (T[]) Array.newInstance(array1.getClass().getComponentType(), array1.length + array2.length); + // Copy the elements of array1 and array2 into the new array. + System.arraycopy(array1, 0, newArray, 0, array1.length); + System.arraycopy(array2, 0, newArray, array1.length, array2.length); + return newArray; + } + + /** + * Removes an item from the given array at the specified position. + *

+ * This method creates a new array with one fewer element than the original array + * by removing the element at the specified position. If the input array is empty + * or null, it returns the input array as is. + *

+ * + * @param array the array from which the item is to be removed, may be null + * @param position the position of the item to remove + * @param the type of the array elements + * @return A new array with the specified item removed, or the original array if it's empty or null. + * If the specified position is out of bounds, returns a shallow copy of the original array. + */ + @SuppressWarnings("unchecked") + public static T[] removeItem(T[] array, int position) { + if (isEmpty(array)) { + return array; + } + final int len = Array.getLength(array); + // Create a new array with one fewer element. + T[] newArray = (T[]) Array.newInstance(array.getClass().getComponentType(), len - 1); + // Copy elements before the specified position. + System.arraycopy(array, 0, newArray, 0, position); + // Copy elements after the specified position. + System.arraycopy(array, position + 1, newArray, position, len - position - 1); + return newArray; + } + + /** + * Returns a subset of the given array between the specified start (inclusive) and end (exclusive) indices. + *

+ * This method creates a new array containing elements from the input array, starting from the + * specified start index up to, but not including, the specified end index. + * If the input array is empty or null, it returns the input array as is. + *

+ * + * @param array the array from which the subset is to be extracted, may be null + * @param start the start index (inclusive) of the subset + * @param end the end index (exclusive) of the subset + * @param the type of the array elements + * @return A new array containing elements from the input array within the specified range. + * Returns the original array if it's empty or null. + * If the specified indices are out of bounds, returns a shallow copy of the original array. + */ + public static T[] getArraySubset(T[] array, int start, int end) { + if (isEmpty(array)) { + return array; + } + return Arrays.copyOfRange(array, start, end); + } +} diff --git a/plugin/src/main/groovy/org/unify4j/common/Byte4j.java b/plugin/src/main/groovy/org/unify4j/common/Byte4j.java index 5a4b59c..2cdb882 100644 --- a/plugin/src/main/groovy/org/unify4j/common/Byte4j.java +++ b/plugin/src/main/groovy/org/unify4j/common/Byte4j.java @@ -38,19 +38,19 @@ public static String encode(final byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length << 1); // Loop through each byte and convert it to two hexadecimal characters for (byte aByte : bytes) { - sb.append(convertDigit(aByte >> 4)); - sb.append(convertDigit(aByte & 0x0f)); + sb.append(toDigit(aByte >> 4)); + sb.append(toDigit(aByte & 0x0f)); } return sb.toString(); } /** - * Converts a value (0 .. 15) to the corresponding hexadecimal digit. + * Converts a value (0 ... 15) to the corresponding hexadecimal digit. * * @param value the value to convert - * @return the corresponding hexadecimal character ('0'..'F') + * @return the corresponding hexadecimal character ('0'...'F') */ - private static char convertDigit(final int value) { + private static char toDigit(final int value) { return hexes[value & 0x0f]; } diff --git a/plugin/src/main/groovy/org/unify4j/common/Collection4j.java b/plugin/src/main/groovy/org/unify4j/common/Collection4j.java index 86de4e0..d80f6c3 100644 --- a/plugin/src/main/groovy/org/unify4j/common/Collection4j.java +++ b/plugin/src/main/groovy/org/unify4j/common/Collection4j.java @@ -11,6 +11,8 @@ public class Collection4j { protected static final Logger logger = LoggerFactory.getLogger(Collection4j.class); + private static final Set unmodifiableEmptySet = Collections.unmodifiableSet(new HashSet<>()); + private static final List unmodifiableEmptyList = Collections.unmodifiableList(new ArrayList<>()); /** * Checks if the provided collection is null or empty. @@ -580,6 +582,52 @@ public static boolean isConsistOf(E[] array, int index) { return !Object4j.isEmpty(array) && index >= 0 && index < array.length; } + /** + * Creates an immutable list containing the specified elements. + * This method is preferable when creating immutable lists in Java versions + * where Set.of() is not available (e.g., JDK versions before 11). + * It returns an empty immutable list if no elements are provided or if the input array is null. + * + * @param items The elements to be included in the immutable list. + * @param The type of elements in the list. + * @return An immutable list containing the specified elements. + * Returns an empty immutable list if no elements are provided or if the input array is null. + */ + @SuppressWarnings({"unchecked"}) + @SafeVarargs + public static List listOf(T... items) { + if (items == null || items.length == 0) { + return (List) unmodifiableEmptyList; + } + List list = new ArrayList<>(); + Collections.addAll(list, items); + return Collections.unmodifiableList(list); + } + + /** + * Creates an immutable set containing the specified elements. + * This method is preferable when creating immutable sets in Java versions + * where Set.of() is not available (e.g., JDK versions before 11). + * It returns an empty immutable set if no elements are provided or if the input array is null. + *

+ * Note: For JDK 11 and above, consider using Set.of() instead. + * + * @param items The elements to be included in the immutable set. + * @param The type of elements in the set. + * @return An immutable set containing the specified elements. + * Returns an empty immutable set if no elements are provided or if the input array is null. + */ + @SuppressWarnings({"unchecked"}) + @SafeVarargs + public static Set setOf(T... items) { + if (items == null || items.length == 0) { + return (Set) unmodifiableEmptySet; + } + Set set = new LinkedHashSet<>(); + Collections.addAll(set, items); + return Collections.unmodifiableSet(set); + } + /** * Throws UnsupportedOperationException if the list is not of type ArrayList. *