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