/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ignite.internal.util; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Set; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.A; import org.apache.ignite.internal.util.typedef.internal.S; import org.jetbrains.annotations.Nullable; /** * Implementation of {@link Set} based on internal list rather than hash table. * The order of the internal list is either insertion order or defined by * optionally provided {@link Comparator}. * <p> * Note that if {@code 'strict'} flag is false, then this set allows inconsistencies * between {@link Object#equals(Object)} and {@link Comparator#compare(Object, Object)} * methods. The {@code equals(Object)} method will always be used to determine * final equality. This allows to have multiple elements for which {@code compare(Object)} * method returns {@code 0}, but {@code equals(Object)} method returns {@code false}. The * reverse is also true, where {@code equals(Object)} may return true, but * {@code compare(Object)} method may return non-zero values. * <p> * In {@code strict} mode, which is default, {@link Object#equals(Object)} and * {@link Comparator#compare(Object, Object)} methods must be absolutely consistent with each other. * <p> * This set does not allow {@code null} values. */ public class GridListSet<V> extends GridSerializableSet<V> implements Cloneable { /** */ private static final long serialVersionUID = 0L; /** Internal list. */ @GridToStringInclude private LinkedList<V> vals = new LinkedList<>(); /** Comparator. */ @GridToStringInclude private Comparator<V> comp; /** Strict flag. */ private boolean strict; /** * Creates unsorted list set. Values will be ordered in insertion order. */ public GridListSet() { comp = null; strict = true; } /** * If comparator is not {@code null}, then sorted list set will be created. * Values will be sorted according to provided comparator. * * @param comp Optional comparator to sort values. */ public GridListSet(@Nullable Comparator<V> comp) { this.comp = comp; strict = true; } /** * If comparator is not {@code null}, then sorted list set will be created. * Values will be sorted according to provided comparator. * * @param comp Optional comparator to sort values. * @param strict Strict flag. */ public GridListSet(@Nullable Comparator<V> comp, boolean strict) { this.comp = comp; this.strict = strict; } /** * Copy constructor. * * @param copy Set to copy from. */ public GridListSet(GridListSet<V> copy) { assert copy != null; comp = copy.comp; strict = copy.strict; addAll(copy); } /** * Gets value of {@code strict} flag for this set. * * @return Value of {@code strict} flag for this set. */ public boolean strict() { return strict; } /** * Gets optional comparator for this set. * * @return Optional comparator for this set. */ @Nullable public Comparator<V> comparator() { return comp; } /** {@inheritDoc} */ @Override public boolean add(V val) { return addx(val) == null; } /** * Either adds a value to set or does nothing if value is already present. * * @param val Value to add. * @return The instance of value from this set or {@code null} if value was added. */ @Nullable public V addx(V val) { A.notNull(val, "val"); if (comp == null) { for (V v : vals) if (v.equals(val)) return v; vals.add(val); return null; } if (strict) { for (ListIterator<V> it = vals.listIterator(); it.hasNext();) { V v = it.next(); // Prefer equals to comparator. if (v.equals(val)) return v; int c = comp.compare(v, val); if (c == 0) throw new IllegalStateException("Inconsistent equals and compare methods."); if (c > 0) { // Back up. it.previous(); it.add(val); return null; } } vals.add(val); return null; } // Full scan first. for (V v : vals) if (v.equals(val)) return v; for (ListIterator<V> it = vals.listIterator(); it.hasNext();) { V v = it.next(); if (comp.compare(v, val) > 0) { do { // Back up. v = it.previous(); } while (comp.compare(v, val) == 0); it.add(val); return null; } } vals.add(val); return null; } /** * Removes the first element of this list. * * @return Removed element or {@code null} if list is empty. */ @Nullable public V removeFirst() { return vals.isEmpty() ? null : vals.removeFirst(); } /** * Removes the last element of this list. * * @return Removed element or {@code null} if list is empty. */ @Nullable public V removeLast() { return vals.isEmpty() ? null : vals.removeLast(); } /** * Gets first element of this list. * * @return First element or {@code null} if list is empty. */ @Nullable public V first() { return vals.isEmpty() ? null : vals.getFirst(); } /** * Gets last element of this list. * * @return Last element or {@code null} if list is empty. */ @Nullable public V last() { return vals.isEmpty() ? null : vals.getLast(); } /** {@inheritDoc} */ @SuppressWarnings( {"unchecked"}) @Override public boolean remove(Object val) { A.notNull(val, "val"); return removex((V)val) != null; } /** * Removes given value from the set and returns the instance stored in the set * or {@code null} if value was not found. * * @param val Value to remove. * @return The instance that was stored in the set or {@code null}. */ @Nullable public V removex(V val) { A.notNull(val, "val"); if (comp == null || !strict) { for (Iterator<V> it = vals.iterator(); it.hasNext();) { V v = it.next(); if (v.equals(val)) { it.remove(); return v; } } return null; } assert comp != null && strict; for (Iterator<V> it = vals.iterator(); it.hasNext();) { V v = it.next(); // Prefer equals to comparator. if (v.equals(val)) { it.remove(); return v; } if (comp.compare(v, val) > 0) break; } return null; } /** * Gets instance {@code e} stored in this set for which {@code e.equals(val)} * returns {@code true}. * * @param val Value to check for equality. * @return Instance stored in this set for which {@code e.equals(val)} * returns {@code true}. */ @Nullable public V get(V val) { A.notNull(val, "val"); if (comp == null || !strict) { for (V v : vals) if (v.equals(val)) return v; return null; } assert comp != null && strict; for (V v : vals) { // Prefer equals to comparator. if (v.equals(val)) return v; if (comp.compare(v, val) > 0) break; } return null; } /** * Gets value at given index within internal list. Note that this method will iterate through * the list to get a value at the specified index. * * @param idx Index to get value at (must be non-negative and less than {@link #size()}). * @return Value at give index. */ public V get(int idx) { A.ensure(idx >= 0 && idx < size(), "idx >= 0 && idx < size()"); return vals.get(idx); } /** {@inheritDoc} */ @SuppressWarnings( {"unchecked"}) @Override public boolean contains(Object val) { A.notNull(val, "val"); if (comp != null && strict) { for (V v : vals) { // Prefer equals to comparator. if (v.equals(val)) return true; if (comp.compare(v, (V)val) > 0) break; } return false; } return vals.contains(val); } /** * Creates a copy of this set. * * @return Copy of this set. */ public GridListSet<V> copy() { return new GridListSet<>(this); } /** {@inheritDoc} */ @Override public Iterator<V> iterator() { return vals.iterator(); } /** {@inheritDoc} */ @Override public int size() { return vals.size(); } /** * Gets a copy of the internal list. * * @return Copy of the internal list. */ public List<V> values() { return new ArrayList<>(vals); } /** * Clones this set. * * @return Clone of this set. * @throws CloneNotSupportedException */ @SuppressWarnings( {"unchecked", "OverriddenMethodCallDuringObjectConstruction"}) @Override protected Object clone() throws CloneNotSupportedException { GridListSet<V> clone = (GridListSet<V>)super.clone(); clone.vals = (LinkedList<V>)vals.clone(); clone.comp = comp; clone.strict = strict; return clone; } /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridListSet.class, this); } /** * Creates a synchronized instance of this set. * * @return Synchronized instance of this set. */ public GridListSet<V> toSynchronized() { final GridListSet<V> set = this; return new GridListSet<V>() { @Override public synchronized boolean add(V val) { return set.add(val); } @Override public synchronized V addx(V val) { return set.addx(val); } @SuppressWarnings( {"CloneDoesntCallSuperClone"}) @Override public synchronized Object clone() throws CloneNotSupportedException { return set.clone(); } @Override public synchronized boolean contains(Object val) { return set.contains(val); } @Override public synchronized GridListSet<V> copy() { return set.copy(); } @Override public synchronized V get(int idx) { return set.get(idx); } @Override public synchronized V get(V val) { return set.get(val); } @Override public synchronized Iterator<V> iterator() { return set.iterator(); } @Override public synchronized boolean remove(Object val) { return set.remove(val); } @Override public synchronized V removex(V val) { return set.removex(val); } @Override public synchronized int size() { return set.size(); } @Override public synchronized String toString() { return set.toString(); } @Override public synchronized GridListSet<V> toSynchronized() { return set.toSynchronized(); } @Override public synchronized boolean equals(Object o) { return set.equals(o); } @Override public synchronized int hashCode() { return set.hashCode(); } @Override public synchronized boolean removeAll(Collection<?> c) { return set.removeAll(c); } @Override public synchronized boolean addAll(Collection<? extends V> c) { return set.addAll(c); } @Override public synchronized void clear() { set.clear(); } @Override public synchronized boolean containsAll(Collection<?> c) { return set.containsAll(c); } @Override public synchronized boolean isEmpty() { return set.isEmpty(); } @Override public synchronized boolean retainAll(Collection<?> c) { return set.retainAll(c); } @Override public synchronized Object[] toArray() { return set.toArray(); } @SuppressWarnings( {"SuspiciousToArrayCall"}) @Override public synchronized <T> T[] toArray(T[] a) { return set.toArray(a); } @Override public synchronized V first() { return set.first(); } @Override public synchronized V removeFirst() { return set.removeFirst(); } @Override public synchronized List<V> values() { return set.values(); } @Override public V last() { return set.last(); } @Override public V removeLast() { return set.removeLast(); } }; } }