From 2bf7d5ddeab646ed8e0da06498617bff330f9c60 Mon Sep 17 00:00:00 2001 From: zzz <zzz@i2pmail.org> Date: Fri, 17 Jun 2022 13:07:22 -0400 Subject: [PATCH] Util: New UnmodifiableSortedSet based on ArraySet use in OrderedProperties --- .../src/net/i2p/util/OrderedProperties.java | 8 +- .../net/i2p/util/UnmodifiableSortedSet.java | 171 ++++++++++++++++++ 2 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 core/java/src/net/i2p/util/UnmodifiableSortedSet.java diff --git a/core/java/src/net/i2p/util/OrderedProperties.java b/core/java/src/net/i2p/util/OrderedProperties.java index 630372179d..c9b7cccd87 100644 --- a/core/java/src/net/i2p/util/OrderedProperties.java +++ b/core/java/src/net/i2p/util/OrderedProperties.java @@ -10,12 +10,10 @@ package net.i2p.util; */ import java.io.Serializable; -import java.util.Collections; import java.util.Comparator; import java.util.Map; import java.util.Properties; import java.util.Set; -import java.util.TreeSet; /** * Properties map that has its keySet ordered consistently (via the key's lexicographical ordering). @@ -41,16 +39,14 @@ public class OrderedProperties extends Properties { public Set<Object> keySet() { if (size() <= 1) return super.keySet(); - return Collections.unmodifiableSortedSet(new TreeSet<Object>(super.keySet())); + return new UnmodifiableSortedSet(super.keySet()); } @Override public Set<Map.Entry<Object, Object>> entrySet() { if (size() <= 1) return super.entrySet(); - TreeSet<Map.Entry<Object, Object>> rv = new TreeSet<Map.Entry<Object, Object>>(ECOMP); - rv.addAll(super.entrySet()); - return Collections.unmodifiableSortedSet(rv); + return new UnmodifiableSortedSet(super.entrySet(), ECOMP); } private static class EntryComparator implements Comparator<Map.Entry<Object, Object>>, Serializable { diff --git a/core/java/src/net/i2p/util/UnmodifiableSortedSet.java b/core/java/src/net/i2p/util/UnmodifiableSortedSet.java new file mode 100644 index 0000000000..ecf623cc08 --- /dev/null +++ b/core/java/src/net/i2p/util/UnmodifiableSortedSet.java @@ -0,0 +1,171 @@ +package net.i2p.util; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.SortedSet; + +/** + * Efficient implementation of a SortedSet stored in a fixed-size array. + * Much more space-efficient than TreeSet. + * Doesn't do copying like CopyOnWriteArraySet. + * Unmodifiable, thread-safe. + * Null elements are not permitted. + * + * The Collection constructors are not recommended for large sets + * as the duplicate check is O(n**2). + * + * @since 0.9.55 + */ +public class UnmodifiableSortedSet<E> extends ArraySet<E> implements SortedSet<E> { + + private final Comparator<? super E> comp; + private final boolean initialized; + + public UnmodifiableSortedSet(SortedSet<? extends E> c) { + this(c, null); + } + + public UnmodifiableSortedSet(SortedSet<? extends E> c, Comparator<? super E> comparator) { + super(c, c.size()); + comp = comparator; + // no sort required + initialized = true; + } + + public UnmodifiableSortedSet(Set<? extends E> c) { + this(c, null); + } + + public UnmodifiableSortedSet(Set<? extends E> c, Comparator<? super E> comparator) { + super(c, c.size()); + comp = comparator; + int sz = size(); + if (sz > 1) + Arrays.sort((E[]) _entries, 0, sz, comp); + initialized = true; + } + + /** + * Warning: O(n**2) + */ + public UnmodifiableSortedSet(Collection<? extends E> c) { + this(c, null); + } + + /** + * Warning: O(n**2) + */ + public UnmodifiableSortedSet(Collection<? extends E> c, Comparator<? super E> comparator) { + super(c, c.size()); + comp = comparator; + int sz = size(); + if (sz > 1) + Arrays.sort((E[]) _entries, 0, sz, comp); + initialized = true; + } + + public Comparator<? super E> comparator() { return comp; } + + public E first() { + if (isEmpty()) + throw new NoSuchElementException(); + return (E) _entries[0]; + } + + public E last() { + int sz = size(); + if (sz <= 0) + throw new NoSuchElementException(); + return (E) _entries[sz - 1]; + } + + /** + * @throws UnsupportedOperationException + */ + public SortedSet<E> headSet(E toElement) { + throw new UnsupportedOperationException(); + } + + /** + * @throws UnsupportedOperationException + */ + public SortedSet<E> subSet(E fromElement, E toElement) { + throw new UnsupportedOperationException(); + } + + /** + * @throws UnsupportedOperationException + */ + public SortedSet<E> tailSet(E fromElement) { + throw new UnsupportedOperationException(); + } + + /** + * @throws UnsupportedOperationException + */ + @Override + public boolean add(E o) { + if (initialized) + throw new UnsupportedOperationException(); + // for Collection constructor via addAll() + return super.add(o); + } + + /** + * @throws UnsupportedOperationException + */ + @Override + public void addUnique(E o) { + if (initialized) + throw new UnsupportedOperationException(); + // for Collection constructor via addAll() + super.addUnique(o); + } + + /** + * @throws UnsupportedOperationException + */ + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + /** + * @throws UnsupportedOperationException + */ + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + + /** + * Overridden to do binary search + */ + @Override + protected int indexOf(Object o) { + // don't do this if comp is not initialized and array is not sorted + if (! initialized) + return super.indexOf(o); + if (o != null) { + int rv = Arrays.binarySearch((E[]) _entries, 0, size(), (E) o, comp); + if (rv >= 0) + return rv; + } + return -1; + } + +/* + public static void main(String[] args) { + String[] test = new String[] {"foo", "bar", "baz", "bar", "baf", "bar", "boo", "foo", "a" }; + java.util.List<String> list = Arrays.asList(test); + Set<String> set = new UnmodifiableSortedSet(list); + System.out.println(set.toString()); + Set<String> set2 = new java.util.HashSet<String>(list); + set = new UnmodifiableSortedSet(set2); + System.out.println(set.toString()); + } +*/ +} -- GitLab