Promote SingletonSet to a SequencedSet
[yangtools.git] / common / util / src / main / java / org / opendaylight / yangtools / util / SingletonSet.java
index 51f65dfac6abd060a8e3ae4fdb188b8acddfe389..2189d54a9188b7d4183067a1fa15b16e0d8ec2ea 100644 (file)
@@ -9,11 +9,12 @@ package org.opendaylight.yangtools.util;
 
 import static java.util.Objects.requireNonNull;
 
-import com.google.common.annotations.Beta;
 import com.google.common.collect.Iterators;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.io.Serializable;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.SequencedSet;
 import java.util.Set;
 import java.util.Spliterator;
 import org.eclipse.jdt.annotation.NonNull;
@@ -22,59 +23,41 @@ import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.concepts.Immutable;
 
 /**
- * A {@link Set} containing a single value. For some reason neither Java nor Guava provide direct access to the retained
- * element -- which is desirable in some situations, as is the case in {@link SharedSingletonMap#entrySet()}.
+ * A {@link SequencedSet} containing a single value. For some reason neither Java nor Guava provide direct access to the
+ * retained element -- which is desirable in some situations, as is the case in {@link SharedSingletonMap#entrySet()}.
  */
-@Beta
-public abstract class SingletonSet<E> implements Set<E>, Immutable, Serializable {
+public abstract sealed class SingletonSet<E> implements SequencedSet<E>, Immutable, Serializable {
+    @java.io.Serial
     private static final long serialVersionUID = 1L;
 
-    private static final SingletonSet<?> NULL_SINGLETON = new SingletonSet<>() {
-        private static final long serialVersionUID = 1L;
-
-        @Override
-        @SuppressWarnings("checkstyle:parameterName")
-        public boolean contains(final Object o) {
-            return o == null;
-        }
-
-        @Override
-        @SuppressWarnings("checkstyle:equalsHashCode")
-        public int hashCode() {
-            return 0;
-        }
-
-        @Override
-        public @Nullable Object getElement() {
-            return null;
-        }
-
-        @Override
-        public @NonNull Spliterator<Object> spliterator() {
-            return SingletonSpliterators.immutableOfNull();
-        }
-
-        @Override
-        public @NonNull String toString() {
-            return "[null]";
-        }
-
-        private Object readResolve() {
-            return NULL_SINGLETON;
-        }
-    };
-
     @SuppressWarnings("unchecked")
     public static <E> @NonNull SingletonSet<E> of(final @Nullable E element) {
-        return element == null ? (SingletonSet<E>) NULL_SINGLETON : new RegularSingletonSet<>(element);
+        return element == null ? (SingletonSet<E>) NullElement.INSTANCE : new Regular<>(element);
     }
 
     /**
      * Return the single element contained in this set.
      *
      * @return This set's element.
+     * @deprecated Use {@link #getFirst()} instead.
      */
-    public abstract E getElement();
+    @Deprecated(since = "14.0.0", forRemoval = true)
+    public final E getElement() {
+        return getFirst();
+    }
+
+    @Override
+    public abstract E getFirst();
+
+    @Override
+    public final E getLast() {
+        return getFirst();
+    }
+
+    @Override
+    public final SingletonSet<E> reversed() {
+        return this;
+    }
 
     @Override
     public final int size() {
@@ -88,7 +71,7 @@ public abstract class SingletonSet<E> implements Set<E>, Immutable, Serializable
 
     @Override
     public final @NonNull Iterator<E> iterator() {
-        return Iterators.singletonIterator(getElement());
+        return Iterators.singletonIterator(getFirst());
     }
 
     @Override
@@ -96,18 +79,18 @@ public abstract class SingletonSet<E> implements Set<E>, Immutable, Serializable
 
     @Override
     public final @NonNull Object[] toArray() {
-        return new Object[] { getElement() };
+        return new Object[] { getFirst() };
     }
 
     @SuppressWarnings({ "unchecked", "checkstyle:parameterName" })
     @Override
     public final <T> @NonNull T[] toArray(final T[] a) {
         if (a.length > 0) {
-            a[0] = (T)getElement();
+            a[0] = (T)getFirst();
             return a;
         }
 
-        return (T[]) new Object[] {getElement()};
+        return (T[]) new Object[] { getFirst() };
     }
 
     @Override
@@ -146,6 +129,16 @@ public abstract class SingletonSet<E> implements Set<E>, Immutable, Serializable
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public final E removeFirst() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public final E removeLast() {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public final void clear() {
         throw new UnsupportedOperationException();
@@ -157,32 +150,65 @@ public abstract class SingletonSet<E> implements Set<E>, Immutable, Serializable
     @Override
     @SuppressWarnings("checkstyle:equalsHashCode")
     public final boolean equals(final Object obj) {
-        if (obj == this) {
-            return true;
-        }
-        if (!(obj instanceof Set)) {
-            return false;
-        }
+        return obj == this || obj instanceof Set<?> other && other.size() == 1 && otherContains(other);
+    }
 
-        final Set<?> s = (Set<?>)obj;
-        return s.size() == 1 && otherContains(s);
+    @java.io.Serial
+    final Object writeReplace() {
+        return new SSv1(getFirst());
     }
 
+    @SuppressFBWarnings(value = "DCN_NULLPOINTER_EXCEPTION",
+        justification = "https://github.com/spotbugs/spotbugs/issues/1954")
     private boolean otherContains(final @NonNull Collection<?> other) {
         try {
-            return other.contains(getElement());
+            return other.contains(getFirst());
         } catch (ClassCastException | NullPointerException e) {
             return false;
         }
     }
 
+    private static final class NullElement<E> extends SingletonSet<E> {
+        @java.io.Serial
+        private static final long serialVersionUID = 1L;
+        static final @NonNull NullElement<?> INSTANCE = new NullElement<>();
+
+        @Override
+        @SuppressWarnings("checkstyle:parameterName")
+        public boolean contains(final Object o) {
+            return o == null;
+        }
+
+        @Override
+        @SuppressWarnings("checkstyle:equalsHashCode")
+        public int hashCode() {
+            return 0;
+        }
+
+        @Override
+        public E getFirst() {
+            return null;
+        }
+
+        @Override
+        public Spliterator<E> spliterator() {
+            return SingletonSpliterators.immutableOfNull();
+        }
+
+        @Override
+        public String toString() {
+            return "[null]";
+        }
+    }
+
     @NonNullByDefault
-    private static final class RegularSingletonSet<E> extends SingletonSet<E> {
+    private static final class Regular<E> extends SingletonSet<E> {
+        @java.io.Serial
         private static final long serialVersionUID = 1L;
 
-        private final E element;
+        private final @NonNull E element;
 
-        RegularSingletonSet(final E element) {
+        Regular(final E element) {
             this.element = requireNonNull(element);
         }
 
@@ -193,14 +219,14 @@ public abstract class SingletonSet<E> implements Set<E>, Immutable, Serializable
         }
 
         @Override
-        public E getElement() {
+        public @NonNull E getFirst() {
             return element;
         }
 
         @Override
         @SuppressWarnings("checkstyle:equalsHashCode")
         public int hashCode() {
-            return getElement().hashCode();
+            return element.hashCode();
         }
 
         @Override