8266571: Sequenced Collections

Reviewed-by: alanb
This commit is contained in:
Stuart Marks 2023-04-25 15:19:08 +00:00
parent bad6aa68e4
commit 17ce0976e4
42 changed files with 7060 additions and 150 deletions

View file

@ -369,9 +369,15 @@ public class Collections {
*
* This method runs in linear time.
*
* @apiNote
* This method mutates the specified list in-place. To obtain a
* reverse-ordered view of a list without mutating it, use the
* {@link List#reversed List.reversed} method.
*
* @param list the list whose elements are to be reversed.
* @throws UnsupportedOperationException if the specified list or
* its list-iterator does not support the {@code set} operation.
* @see List#reversed List.reversed
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static void reverse(List<?> list) {
@ -1130,6 +1136,87 @@ public class Collections {
}
}
/**
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
* specified {@code SequencedCollection}. Query operations on the returned collection
* "read through" to the specified collection, and attempts to modify the returned
* collection, whether direct or via its iterator, result in an
* {@code UnsupportedOperationException}.<p>
*
* The returned collection does <i>not</i> pass the {@code hashCode} and
* {@code equals} operations through to the backing collection, but relies on
* {@code Object}'s {@code equals} and {@code hashCode} methods. This
* is necessary to preserve the contracts of these operations in the case
* that the backing collection is a set or a list.<p>
*
* The returned collection will be serializable if the specified collection
* is serializable.
*
* @implNote This method may return its argument if the argument is already unmodifiable.
* @param <T> the class of the objects in the collection
* @param c the collection for which an unmodifiable view is to be
* returned.
* @return an unmodifiable view of the specified collection.
* @since 21
*/
@SuppressWarnings("unchecked")
public static <T> SequencedCollection<T> unmodifiableSequencedCollection(SequencedCollection<? extends T> c) {
if (c.getClass() == UnmodifiableSequencedCollection.class) {
return (SequencedCollection<T>) c;
}
return new UnmodifiableSequencedCollection<>(c);
}
/**
* @serial include
*/
static class UnmodifiableSequencedCollection<E> extends UnmodifiableCollection<E>
implements SequencedCollection<E>, Serializable {
@java.io.Serial
private static final long serialVersionUID = -6060065079711684830L;
UnmodifiableSequencedCollection(SequencedCollection<? extends E> c) {
super(c);
}
@SuppressWarnings("unchecked")
private SequencedCollection<E> sc() {
return (SequencedCollection<E>) c;
}
// Even though this wrapper class is serializable, the reversed view is effectively
// not serializable because it points to the reversed collection view, which usually isn't
// serializable.
public SequencedCollection<E> reversed() {
return new UnmodifiableSequencedCollection<>(sc().reversed());
}
public void addFirst(E e) {
throw new UnsupportedOperationException();
}
public void addLast(E e) {
throw new UnsupportedOperationException();
}
public E getFirst() {
return sc().getFirst();
}
public E getLast() {
return sc().getLast();
}
public E removeFirst() {
throw new UnsupportedOperationException();
}
public E removeLast() {
throw new UnsupportedOperationException();
}
}
/**
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
* specified set. Query operations on the returned set "read through" to the specified
@ -1166,6 +1253,56 @@ public class Collections {
public int hashCode() {return c.hashCode();}
}
/**
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
* specified {@code SequencedSet}. Query operations on the returned set
* "read through" to the specified set, and attempts to modify the returned
* set, whether direct or via its iterator, result in an
* {@code UnsupportedOperationException}.<p>
*
* The returned set will be serializable if the specified set
* is serializable.
*
* @implNote This method may return its argument if the argument is already unmodifiable.
* @param <T> the class of the objects in the set
* @param s the set for which an unmodifiable view is to be returned.
* @return an unmodifiable view of the specified sequenced set.
* @since 21
*/
@SuppressWarnings("unchecked")
public static <T> SequencedSet<T> unmodifiableSequencedSet(SequencedSet<? extends T> s) {
// Not checking for subclasses because of heap pollution and information leakage.
if (s.getClass() == UnmodifiableSequencedSet.class) {
return (SequencedSet<T>) s;
}
return new UnmodifiableSequencedSet<>(s);
}
/**
* @serial include
*/
static class UnmodifiableSequencedSet<E> extends UnmodifiableSequencedCollection<E>
implements SequencedSet<E>, Serializable {
@java.io.Serial
private static final long serialVersionUID = -2153469532349793522L;
UnmodifiableSequencedSet(SequencedSet<? extends E> s) {super(s);}
public boolean equals(Object o) {return o == this || c.equals(o);}
public int hashCode() {return c.hashCode();}
@SuppressWarnings("unchecked")
private SequencedSet<E> ss() {
return (SequencedSet<E>) c;
}
// Even though this wrapper class is serializable, the reversed view is effectively
// not serializable because it points to the reversed set view, which usually isn't
// serializable.
public SequencedSet<E> reversed() {
return new UnmodifiableSequencedSet<>(ss().reversed());
}
}
/**
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
* specified sorted set. Query operations on the returned sorted set "read
@ -1504,7 +1641,7 @@ public class Collections {
private static final long serialVersionUID = -1034234728574286014L;
@SuppressWarnings("serial") // Conditionally serializable
private final Map<? extends K, ? extends V> m;
final Map<? extends K, ? extends V> m;
UnmodifiableMap(Map<? extends K, ? extends V> m) {
if (m==null)
@ -1828,6 +1965,72 @@ public class Collections {
}
}
/**
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
* specified {@code SequencedMap}. Query operations on the returned map
* "read through" to the specified map, and attempts to modify the returned
* map, whether direct or via its collection views, result in an
* {@code UnsupportedOperationException}.<p>
*
* The returned map will be serializable if the specified map
* is serializable.
*
* @implNote This method may return its argument if the argument is already unmodifiable.
* @param <K> the class of the map keys
* @param <V> the class of the map values
* @param m the map for which an unmodifiable view is to be returned.
* @return an unmodifiable view of the specified map.
* @since 21
*/
@SuppressWarnings("unchecked")
public static <K,V> SequencedMap<K,V> unmodifiableSequencedMap(SequencedMap<? extends K, ? extends V> m) {
// Not checking for subclasses because of heap pollution and information leakage.
if (m.getClass() == UnmodifiableSequencedMap.class) {
return (SequencedMap<K,V>) m;
}
return new UnmodifiableSequencedMap<>(m);
}
/**
* @serial include
*/
private static class UnmodifiableSequencedMap<K,V> extends UnmodifiableMap<K,V> implements SequencedMap<K,V>, Serializable {
@java.io.Serial
private static final long serialVersionUID = -8171676257373950636L;
UnmodifiableSequencedMap(Map<? extends K, ? extends V> m) {
super(m);
}
@SuppressWarnings("unchecked")
private SequencedMap<K, V> sm() {
return (SequencedMap<K, V>) m;
}
// Even though this wrapper class is serializable, the reversed view is effectively
// not serializable because it points to the reversed map view, which usually isn't
// serializable.
public SequencedMap<K, V> reversed() {
return new UnmodifiableSequencedMap<>(sm().reversed());
}
public Entry<K, V> pollFirstEntry() {
throw new UnsupportedOperationException();
}
public Entry<K, V> pollLastEntry() {
throw new UnsupportedOperationException();
}
public V putFirst(K k, V v) {
throw new UnsupportedOperationException();
}
public V putLast(K k, V v) {
throw new UnsupportedOperationException();
}
}
/**
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
* specified sorted map. Query operations on the returned sorted map "read through"
@ -5326,6 +5529,14 @@ public class Collections {
*
* The returned comparator is serializable.
*
* @apiNote
* This method returns a {@code Comparator} that is suitable for sorting
* elements in reverse order. To obtain a reverse-ordered <i>view</i> of a
* sequenced collection, use the {@link SequencedCollection#reversed
* SequencedCollection.reversed} method. Or, to obtain a reverse-ordered
* <i>view</i> of a sequenced map, use the {@link SequencedMap#reversed
* SequencedMap.reversed} method.
*
* @param <T> the class of the objects compared by the comparator
* @return A comparator that imposes the reverse of the <i>natural
* ordering</i> on a collection of objects that implement
@ -5372,6 +5583,14 @@ public class Collections {
* <p>The returned comparator is serializable (assuming the specified
* comparator is also serializable or {@code null}).
*
* @apiNote
* This method returns a {@code Comparator} that is suitable for sorting
* elements in reverse order. To obtain a reverse-ordered <i>view</i> of a
* sequenced collection, use the {@link SequencedCollection#reversed
* SequencedCollection.reversed} method. Or, to obtain a reverse-ordered
* <i>view</i> of a sequenced map, use the {@link SequencedMap#reversed
* SequencedMap.reversed} method.
*
* @param <T> the class of the objects compared by the comparator
* @param cmp a comparator who's ordering is to be reversed by the returned
* comparator or {@code null}
@ -5682,6 +5901,8 @@ public class Collections {
* @since 1.6
*/
public static <E> Set<E> newSetFromMap(Map<E, Boolean> map) {
if (! map.isEmpty()) // implicit null check
throw new IllegalArgumentException("Map is non-empty");
return new SetFromMap<>(map);
}
@ -5692,12 +5913,10 @@ public class Collections {
implements Set<E>, Serializable
{
@SuppressWarnings("serial") // Conditionally serializable
private final Map<E, Boolean> m; // The backing map
final Map<E, Boolean> m; // The backing map
private transient Set<E> s; // Its keySet
SetFromMap(Map<E, Boolean> map) {
if (!map.isEmpty())
throw new IllegalArgumentException("Map is non-empty");
m = map;
s = map.keySet();
}
@ -5746,6 +5965,91 @@ public class Collections {
stream.defaultReadObject();
s = m.keySet();
}
@java.io.Serial
private void readObjectNoData() throws java.io.ObjectStreamException {
throw new java.io.InvalidObjectException("missing SetFromMap data");
}
}
/**
* Returns a sequenced set backed by the specified map. The resulting set displays
* the same ordering, concurrency, and performance characteristics as the
* backing map. In essence, this factory method provides a {@link SequencedSet}
* implementation corresponding to any {@link SequencedMap} implementation.
*
* <p>Each method invocation on the set returned by this method results in
* exactly one method invocation on the backing map or its {@code keySet}
* view, with one exception. The {@code addAll} method is implemented
* as a sequence of {@code put} invocations on the backing map.
*
* <p>The specified map must be empty at the time this method is invoked,
* and should not be accessed directly after this method returns. These
* conditions are ensured if the map is created empty, passed directly
* to this method, and no reference to the map is retained.
*
* @apiNote
* The following example code creates a {@code SequencedSet} from a
* {@code LinkedHashMap}. This differs from a {@code LinkedHashSet}
* in that the map's {@code removeEldestEntry} is overridden to provide
* an eviction policy, which is not possible with a {@code LinkedHashSet}.
*
* {@snippet :
* SequencedSet<String> set = Collections.newSequencedSetFromMap(
* new LinkedHashMap<String, Boolean>() {
* protected boolean removeEldestEntry(Map.Entry<String, Boolean> e) {
* return this.size() > 5;
* }
* });
* }
*
* @param <E> the class of the map keys and of the objects in the
* returned set
* @param map the backing map
* @return the set backed by the map
* @throws IllegalArgumentException if {@code map} is not empty
* @since 21
*/
public static <E> SequencedSet<E> newSequencedSetFromMap(SequencedMap<E, Boolean> map) {
if (! map.isEmpty()) // implicit null check
throw new IllegalArgumentException("Map is non-empty");
return new SequencedSetFromMap<>(map);
}
/**
* @serial include
*/
private static class SequencedSetFromMap<E> extends SetFromMap<E> implements SequencedSet<E> {
private E nsee(Map.Entry<E, Boolean> e) {
if (e == null) {
throw new NoSuchElementException();
} else {
return e.getKey();
}
}
private SequencedMap<E, Boolean> map() {
return (SequencedMap<E, Boolean>) super.m;
}
SequencedSetFromMap(SequencedMap<E, Boolean> map) {
super(map);
}
// Even though this wrapper class is serializable, the reversed view is effectively
// not serializable because it points to the reversed map view, which usually isn't
// serializable.
public SequencedSet<E> reversed() { return new SequencedSetFromMap<>(map().reversed()); }
public void addFirst(E e) { map().putFirst(e, Boolean.TRUE); }
public void addLast(E e) { map().putLast(e, Boolean.TRUE); }
public E getFirst() { return nsee(map().firstEntry()); }
public E getLast() { return nsee(map().lastEntry()); }
public E removeFirst() { return nsee(map().pollFirstEntry()); }
public E removeLast() { return nsee(map().pollLastEntry()); }
@java.io.Serial
private static final long serialVersionUID = -3943479744841433802L;
}
/**
@ -5761,6 +6065,11 @@ public class Collections {
* implemented as a sequence of {@link Deque#addFirst addFirst}
* invocations on the backing deque.
*
* @apiNote
* This method provides a view that inverts the sense of certain operations,
* but it doesn't reverse the encounter order. To obtain a reverse-ordered
* view, use the {@link Deque#reversed Deque.reversed} method.
*
* @param <T> the class of the objects in the deque
* @param deque the deque
* @return the queue