diff --git a/src/main/java/org/apache/commons/collections4/set/PatriciaTrieSet.java b/src/main/java/org/apache/commons/collections4/set/PatriciaTrieSet.java
new file mode 100644
index 0000000000..7b70b0d42d
--- /dev/null
+++ b/src/main/java/org/apache/commons/collections4/set/PatriciaTrieSet.java
@@ -0,0 +1,248 @@
+/*
+ * 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.commons.collections4.set;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.AbstractSet;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.Spliterator;
+
+import org.apache.commons.collections4.trie.PatriciaTrie;
+
+/**
+ * Add {@code Set} to work with PatriciaTree with unique key ignore corresponding values
+ *
+ * This set exists to provide interface to work with Set + PatriciaTree
+ *
+ *
+ * One usage would be to ensure that no null entries are added to the set.
+ *
+ * PatriciaTrieSet = new PatriciaTrieSet();
+ *
+ * This class is Serializable and Cloneable.
+ *
+ */
+public class PatriciaTrieSet extends AbstractSet implements TrieSet, Serializable {
+
+ private static final long serialVersionUID = -2365733183789787136L;
+
+ // Stub for all values in PatriciaTrie
+ static final Object PRESENT = new Object();
+ transient PatriciaTrie trie;
+
+ /**
+ * Create new Patricia Set with PatriciaTrie under the hood using StringKeyAnalyzer
+ */
+ public PatriciaTrieSet() {
+ trie = new PatriciaTrie<>();
+ }
+
+ @Override
+ public Iterator iterator() {
+ return trie.keySet().iterator();
+ }
+
+ @Override
+ public int size() {
+ return trie.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return trie.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ if (o instanceof String) {
+ return trie.containsKey(o);
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean add(String e) {
+ return trie.put(e, PRESENT) == null;
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return trie.remove(o) == PRESENT;
+ }
+
+ @Override
+ public void clear() {
+ trie.clear();
+ }
+
+ /**
+ * Serializes this object to an ObjectOutputStream.
+ *
+ * @param out the target ObjectOutputStream.
+ * @throws IOException thrown when an I/O errors occur writing to the target stream.
+ */
+ private void writeObject(java.io.ObjectOutputStream out)
+ throws IOException {
+ out.defaultWriteObject();
+ out.writeInt(trie.size());
+
+ for (String entry : this.trie.keySet()) {
+ out.writeObject(entry);
+ }
+ }
+
+ /**
+ * Deserializes the set in using a custom routine.
+ *
+ * @param s the input stream
+ * @throws IOException if an error occurs while reading from the stream
+ * @throws ClassNotFoundException if an object read from the stream cannot be loaded
+ */
+ private void readObject(java.io.ObjectInputStream s)
+ throws IOException, ClassNotFoundException {
+ s.readFields();
+ final int size = s.readInt();
+ this.trie = new PatriciaTrie<>();
+
+ for (int i = 0; i < size; i++) {
+ this.add((String) s.readObject());
+ }
+ }
+
+ @Override
+ public SortedSet prefixSet(String key) {
+ return new RangePatriciaTrieSortedSet(trie.prefixMap(key));
+ }
+
+ @Override
+ public Comparator super String> comparator() {
+ return trie.comparator();
+ }
+
+ @Override
+ public SortedSet subSet(String fromElement, String toElement) {
+ return new RangePatriciaTrieSortedSet(trie.subMap(fromElement, toElement));
+ }
+
+ @Override
+ public SortedSet headSet(String toElement) {
+ return new RangePatriciaTrieSortedSet(trie.headMap(toElement));
+ }
+
+ @Override
+ public SortedSet tailSet(String fromElement) {
+ return new RangePatriciaTrieSortedSet(trie.tailMap(fromElement));
+ }
+
+ @Override
+ public String first() {
+ return trie.firstKey();
+ }
+
+ @Override
+ public String last() {
+ return trie.lastKey();
+ }
+
+ static class RangePatriciaTrieSortedSet extends AbstractSet implements SortedSet {
+
+ protected SortedMap delegate;
+
+ RangePatriciaTrieSortedSet(SortedMap del) {
+ delegate = del;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return delegate.keySet().iterator();
+ }
+
+ @Override
+ public Spliterator spliterator() {
+ return delegate.keySet().spliterator();
+ }
+
+ @Override
+ public int size() {
+ return delegate.size();
+ }
+
+ @Override
+ public boolean contains(Object key) {
+ if (key instanceof String) {
+ return delegate.containsKey(key);
+ }
+
+ return false;
+ }
+
+ @Override
+ public Comparator super String> comparator() {
+ return delegate.comparator();
+ }
+
+ @Override
+ public SortedSet subSet(String fromElement, String toElement) {
+ return new RangePatriciaTrieSortedSet(delegate.subMap(fromElement, toElement));
+ }
+
+ @Override
+ public SortedSet headSet(String toElement) {
+ return new RangePatriciaTrieSortedSet(delegate.headMap(toElement));
+ }
+
+ @Override
+ public SortedSet tailSet(String fromElement) {
+ return new RangePatriciaTrieSortedSet(delegate.tailMap(fromElement));
+ }
+
+ @Override
+ public String first() {
+ return delegate.firstKey();
+ }
+
+ @Override
+ public String last() {
+ return delegate.lastKey();
+ }
+
+ @Override
+ public boolean add(String value) {
+ return delegate.put(value, PRESENT) != null;
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return delegate.remove(o) == PRESENT;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return delegate.isEmpty();
+ }
+
+ @Override
+ public void clear() {
+ delegate.clear();
+ }
+ }
+}
diff --git a/src/main/java/org/apache/commons/collections4/set/TrieSet.java b/src/main/java/org/apache/commons/collections4/set/TrieSet.java
new file mode 100644
index 0000000000..6c27c709bb
--- /dev/null
+++ b/src/main/java/org/apache/commons/collections4/set/TrieSet.java
@@ -0,0 +1,42 @@
+/*
+ * 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.commons.collections4.set;
+
+import java.util.SortedSet;
+
+/**
+ * Defines the interface for a prefix set, an ordered tree data structure. For more information, see Tries .
+ *
+ * @param – the type of elements maintained by this set
+ */
+public interface TrieSet extends SortedSet {
+
+ /**
+ * Returns a view of this {@link TrieSet} of all elements that are prefixed by the given key without duplicates
+ *
+ * In a {@link TrieSet} with fixed size keys, this is essentially a {@link #contains(Object)} operation.
+ *
+ *
+ * For example, if the {@link TrieSet} contains 'Anna', 'Anael', 'Analu', 'Andreas', 'Andrea', 'Andres', and 'Anatole', then a lookup of 'And' would return
+ * 'Andreas', 'Andrea', and 'Andres'.
+ *
+ *
+ * @param key the key used in the search
+ * @return a {@link SortedSet} view of this {@link TrieSet} with all elements whose key is prefixed by the search key
+ */
+ SortedSet prefixSet(K key);
+}
diff --git a/src/test/java/org/apache/commons/collections4/set/PatriciaTrieSetTest.java b/src/test/java/org/apache/commons/collections4/set/PatriciaTrieSetTest.java
new file mode 100644
index 0000000000..7adacc6fd8
--- /dev/null
+++ b/src/test/java/org/apache/commons/collections4/set/PatriciaTrieSetTest.java
@@ -0,0 +1,662 @@
+/*
+ * 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.commons.collections4.set;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.HashSet;
+import java.util.NoSuchElementException;
+import java.util.SortedSet;
+import java.util.Spliterator;
+
+import org.apache.commons.collections4.trie.analyzer.StringKeyAnalyzer;
+import org.apache.commons.lang3.SerializationUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class PatriciaTrieSetTest {
+
+ PatriciaTrieSet patriciaTrieSet = new PatriciaTrieSet();
+
+ @BeforeEach
+ public void preInitTest() {
+ patriciaTrieSet.clear();
+ }
+
+ @Test
+ public void setShouldContainUniqueElements() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albe");
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albe");
+
+ Assertions.assertEquals(2, patriciaTrieSet.size());
+ Assertions.assertTrue(patriciaTrieSet.contains("Alberto"));
+ Assertions.assertTrue(patriciaTrieSet.contains("Albe"));
+ }
+
+ @Test
+ public void setShouldNotContainsNullKey() {
+ Assertions.assertThrows(NullPointerException.class, () -> patriciaTrieSet.add(null));
+ }
+
+ @Test
+ public void clearShouldClearAllElements() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albe");
+
+ patriciaTrieSet.clear();
+
+ Assertions.assertEquals(0, patriciaTrieSet.size());
+ Assertions.assertTrue(patriciaTrieSet.isEmpty());
+ }
+
+ @Test
+ public void isEmptyShouldReturnFalseIfElementsExist() {
+ Assertions.assertTrue(patriciaTrieSet.isEmpty());
+ patriciaTrieSet.add("Alberto");
+
+ Assertions.assertFalse(patriciaTrieSet.isEmpty());
+ }
+
+ @Test
+ public void iteratorShouldContainsAllElements() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albe");
+
+ final HashSet set = new HashSet<>(2);
+ set.add("Alberto");
+ set.add("Albe");
+
+ for (String value : patriciaTrieSet) {
+ Assertions.assertTrue(set.remove(value), "Value " + value + " not exists!");
+ }
+ }
+
+ @Test
+ public void containsShouldReturnCorrectValue() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albe");
+ patriciaTrieSet.add("Al");
+ patriciaTrieSet.add("A");
+
+ Assertions.assertTrue(patriciaTrieSet.contains("A"));
+ Assertions.assertTrue(patriciaTrieSet.contains("Al"));
+ Assertions.assertTrue(patriciaTrieSet.contains("Albe"));
+ Assertions.assertTrue(patriciaTrieSet.contains("Alberto"));
+ Assertions.assertFalse(patriciaTrieSet.contains("Albert"));
+ }
+
+ @Test
+ public void addShouldReturnFalseIfValueExists() {
+ patriciaTrieSet.add("Alberto");
+
+ Assertions.assertFalse(patriciaTrieSet.add("Alberto"));
+ }
+
+ @Test
+ public void addShouldReturnTrueIfValueNotExists() {
+ Assertions.assertTrue(patriciaTrieSet.add("Alberto"));
+ }
+
+ @Test
+ public void removeShouldReturnTrueIfValueExists() {
+ patriciaTrieSet.add("Alberto");
+
+ Assertions.assertTrue(patriciaTrieSet.remove("Alberto"));
+ }
+
+ @Test
+ public void removeShouldReturnFalseIfValueNotExist() {
+ Assertions.assertFalse(patriciaTrieSet.remove("Alberto"));
+ }
+
+ @Test
+ public void serializeShouldSerializeAndDeserializedCorrectly() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albe");
+ patriciaTrieSet.add("Al");
+ patriciaTrieSet.add("A");
+
+ final byte[] serializedBytes = SerializationUtils.serialize(patriciaTrieSet);
+ final PatriciaTrieSet expected = SerializationUtils.deserialize(serializedBytes);
+
+ Assertions.assertEquals(4, expected.size());
+ Assertions.assertTrue(patriciaTrieSet.contains("A"));
+ Assertions.assertTrue(patriciaTrieSet.contains("Al"));
+ Assertions.assertTrue(patriciaTrieSet.contains("Albe"));
+ Assertions.assertTrue(patriciaTrieSet.contains("Alberto"));
+ }
+
+ @Test
+ public void serializeShouldSerializeAndDeserializedCorrectlyEmptyObject() {
+ final byte[] serializedBytes = SerializationUtils.serialize(patriciaTrieSet);
+ final PatriciaTrieSet expected = SerializationUtils.deserialize(serializedBytes);
+
+ Assertions.assertEquals(0, expected.size());
+ }
+
+ @Test
+ public void prefixSetShouldReturnCorrectObject() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Bbe");
+ patriciaTrieSet.add("Bb");
+ patriciaTrieSet.add("Al");
+ patriciaTrieSet.add("A");
+
+ final SortedSet set = patriciaTrieSet.prefixSet("Bb");
+ Assertions.assertEquals(2, set.size());
+
+ Assertions.assertEquals("Bb", set.first());
+ Assertions.assertEquals("Bbe", set.last());
+ }
+
+ @Test
+ public void subSetShouldReturnCorrectObject() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Bbe");
+ patriciaTrieSet.add("Bb");
+ patriciaTrieSet.add("Al");
+ patriciaTrieSet.add("A");
+
+ final SortedSet set = patriciaTrieSet.subSet("Al", "Bbe");
+ Assertions.assertEquals(3, set.size());
+
+ final String[] array = new String[3];
+ set.toArray(array);
+
+ Assertions.assertEquals("Al", array[0]);
+ Assertions.assertEquals("Alberto", array[1]);
+ Assertions.assertEquals("Bb", array[2]);
+ }
+
+ @Test
+ public void headSetShouldReturnCorrectObject() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Bbe");
+ patriciaTrieSet.add("Bb");
+ patriciaTrieSet.add("Al");
+ patriciaTrieSet.add("A");
+
+ final SortedSet set = patriciaTrieSet.headSet("Bbe");
+ Assertions.assertEquals(4, set.size());
+
+ final String[] array = new String[4];
+ set.toArray(array);
+
+ Assertions.assertEquals("A", array[0]);
+ Assertions.assertEquals("Al", array[1]);
+ Assertions.assertEquals("Alberto", array[2]);
+ Assertions.assertEquals("Bb", array[3]);
+ }
+
+ @Test
+ public void tailSetShouldReturnCorrectObject() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Bbe");
+ patriciaTrieSet.add("Bb");
+ patriciaTrieSet.add("Al");
+ patriciaTrieSet.add("Z");
+
+ final SortedSet set = patriciaTrieSet.tailSet("Bbe");
+ Assertions.assertEquals(2, set.size());
+
+ final String[] array = new String[2];
+ set.toArray(array);
+
+ Assertions.assertEquals("Bbe", array[0]);
+ Assertions.assertEquals("Z", array[1]);
+ }
+
+ @Test
+ public void firstKeyShouldReturnCorrectObject() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Bbe");
+ patriciaTrieSet.add("Bb");
+ patriciaTrieSet.add("Al");
+ patriciaTrieSet.add("Z");
+
+ Assertions.assertEquals("Al", patriciaTrieSet.first());
+ }
+
+ @Test
+ public void lastKeyShouldReturnCorrectObject() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Bbe");
+ patriciaTrieSet.add("Bb");
+ patriciaTrieSet.add("Al");
+ patriciaTrieSet.add("Zz");
+
+ Assertions.assertEquals("Zz", patriciaTrieSet.last());
+ }
+
+ @Test
+ public void comparatorShouReturnSetComparator() {
+ Assertions.assertEquals(StringKeyAnalyzer.INSTANCE, patriciaTrieSet.comparator());
+ }
+
+ @Test
+ public void prefixMapShouldCorrectlyWorkWihChineseCharacter() {
+ // COLLECTIONS-525
+ patriciaTrieSet.add("点评");
+ patriciaTrieSet.add("书评");
+ assertTrue(patriciaTrieSet.prefixSet("点").contains("点评"));
+ assertEquals("点评", patriciaTrieSet.prefixSet("点").first());
+ assertFalse(patriciaTrieSet.prefixSet("点").isEmpty());
+ assertEquals(1, patriciaTrieSet.prefixSet("点").size());
+ assertEquals(1, patriciaTrieSet.prefixSet("点评").size());
+
+ patriciaTrieSet.clear();
+ patriciaTrieSet.add("点评");
+ patriciaTrieSet.add("点版");
+ assertEquals(2, patriciaTrieSet.prefixSet("点").size());
+ assertEquals(2, patriciaTrieSet.prefixSet("点").size());
+ }
+
+ @Test
+ public void setShouldCorrectlyWorkWithMixedCharacters() {
+ patriciaTrieSet.add("书评");
+ patriciaTrieSet.add("书点");
+ patriciaTrieSet.add("Al");
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Йод");
+ patriciaTrieSet.add("Йододефицит");
+
+
+ SortedSet subset = patriciaTrieSet.prefixSet("Al");
+ assertEquals(2, subset.size());
+ assertEquals("Al", subset.first());
+ assertEquals("Alberto", subset.last());
+
+ subset = patriciaTrieSet.prefixSet("Йод");
+ assertEquals(2, subset.size());
+ assertEquals("Йод", subset.first());
+ assertEquals("Йододефицит", subset.last());
+
+ subset = patriciaTrieSet.prefixSet("书");
+
+ assertEquals(2, subset.size());
+ assertEquals("书点", subset.first());
+ assertEquals("书评", subset.last());
+ }
+
+ @Test
+ public void containsShouldReturnFalse() {
+ patriciaTrieSet.add("Al");
+ patriciaTrieSet.add("Alberto");
+
+ assertFalse(patriciaTrieSet.contains("w"));
+ assertFalse(patriciaTrieSet.contains(new Object()));
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetIteratorShouldReturnCorrectOrder() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("Al");
+
+ final SortedSet subSet = patriciaTrieSet.headSet("Wirz");
+
+ Assertions.assertNotNull(subSet);
+
+ final String[] actual = new String[3];
+ int idx = 0;
+
+ for (String s : subSet) {
+ actual[idx] = s;
+ idx++;
+ }
+
+ Assertions.assertEquals("Al", actual[0]);
+ Assertions.assertEquals("Albert", actual[1]);
+ Assertions.assertEquals("Alberto", actual[2]);
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetSplitIteratorShouldReturnIteratorOverMap() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("Al");
+
+ final SortedSet subSet = patriciaTrieSet.headSet("Wirz");
+
+ final Spliterator spliterator = subSet.spliterator();
+ Assertions.assertEquals(Spliterator.DISTINCT | Spliterator.SIZED | Spliterator.SUBSIZED, spliterator.characteristics());
+ Assertions.assertEquals(3, spliterator.getExactSizeIfKnown());
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetSizeShouldReturnCorrectSize() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+
+ final SortedSet subSet = patriciaTrieSet.headSet("Wirz");
+ Assertions.assertEquals(3, subSet.size());
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetContainsShouldReturnTrue() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+
+ final SortedSet subSet = patriciaTrieSet.headSet("Wirz");
+ Assertions.assertTrue(subSet.contains("Albert"));
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetContainsShouldReturnFalse() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+
+ final SortedSet subSet = patriciaTrieSet.headSet("Wirz");
+ Assertions.assertFalse(subSet.contains("Wirz"));
+ Assertions.assertFalse(subSet.contains(new Object()));
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetComparatorShouldCorrectValue() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+
+ final SortedSet subSet = patriciaTrieSet.headSet("Wirz");
+ Assertions.assertEquals(StringKeyAnalyzer.INSTANCE, subSet.comparator());
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetSubSetShouldReturnCorrectSubSet() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+ patriciaTrieSet.add("Al");
+
+ final SortedSet subSet = patriciaTrieSet.subSet("Albert", "Wirz");
+
+ Assertions.assertNotNull(subSet);
+
+ final String[] actual = new String[3];
+ int idx = 0;
+
+ for (String s : subSet) {
+ actual[idx] = s;
+ idx++;
+ }
+
+ Assertions.assertEquals("Albert", actual[0]);
+ Assertions.assertEquals("Alberto", actual[1]);
+ Assertions.assertEquals("W", actual[2]);
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetSubSetShouldReturnCorrectSubSetTwice() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+ patriciaTrieSet.add("Al");
+
+ SortedSet subSet = patriciaTrieSet.subSet("Albert", "Wirz");
+ subSet = subSet.subSet("Albert", "W");
+ Assertions.assertNotNull(subSet);
+
+ Assertions.assertNotNull(subSet);
+
+ final String[] actual = new String[2];
+ int idx = 0;
+
+ for (String s : subSet) {
+ actual[idx] = s;
+ idx++;
+ }
+
+ Assertions.assertEquals("Albert", actual[0]);
+ Assertions.assertEquals("Alberto", actual[1]);
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetHeadSetShouldReturnCorrectHeadSet() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+ patriciaTrieSet.add("Wl");
+ patriciaTrieSet.add("Al");
+
+ final SortedSet subSet = patriciaTrieSet.headSet("Wl");
+ Assertions.assertNotNull(subSet);
+
+ final String[] actual = new String[5];
+ int idx = 0;
+
+ for (String s : subSet) {
+ actual[idx] = s;
+ idx++;
+ }
+
+ Assertions.assertEquals("Al", actual[0]);
+ Assertions.assertEquals("Albert", actual[1]);
+ Assertions.assertEquals("Alberto", actual[2]);
+ Assertions.assertEquals("W", actual[3]);
+ Assertions.assertEquals("Wirz", actual[4]);
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetHeadSetShouldReturnCorrectHeadSetTwice() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+ patriciaTrieSet.add("Wl");
+ patriciaTrieSet.add("Al");
+
+ SortedSet subSet = patriciaTrieSet.headSet("Wl");
+ Assertions.assertNotNull(subSet);
+ subSet = subSet.headSet("Alberto");
+ Assertions.assertNotNull(subSet);
+
+ final String[] actual = new String[2];
+ int idx = 0;
+
+ for (String s : subSet) {
+ actual[idx] = s;
+ idx++;
+ }
+
+ Assertions.assertEquals("Al", actual[0]);
+ Assertions.assertEquals("Albert", actual[1]);
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetTailSetShouldReturnCorrectTailSet() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+ patriciaTrieSet.add("Wl");
+ patriciaTrieSet.add("Al");
+
+ final SortedSet subSet = patriciaTrieSet.tailSet("Alberto");
+ Assertions.assertNotNull(subSet);
+
+ final String[] actual = new String[4];
+ int idx = 0;
+
+ for (String s : subSet) {
+ actual[idx] = s;
+ idx++;
+ }
+
+ Assertions.assertEquals("Alberto", actual[0]);
+ Assertions.assertEquals("W", actual[1]);
+ Assertions.assertEquals("Wirz", actual[2]);
+ Assertions.assertEquals("Wl", actual[3]);
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetTailSetShouldReturnCorrectTailSetTwice() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+ patriciaTrieSet.add("Wl");
+ patriciaTrieSet.add("Al");
+
+ SortedSet subSet = patriciaTrieSet.tailSet("Alberto");
+ Assertions.assertNotNull(subSet);
+ subSet = subSet.tailSet("Wirz");
+
+ final String[] actual = new String[2];
+ int idx = 0;
+
+ for (String s : subSet) {
+ actual[idx] = s;
+ idx++;
+ }
+
+ Assertions.assertEquals("Wirz", actual[0]);
+ Assertions.assertEquals("Wl", actual[1]);
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetFirstShouldReturnCorrectResult() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+ patriciaTrieSet.add("Wl");
+ patriciaTrieSet.add("Al");
+
+ SortedSet subSet = patriciaTrieSet.tailSet("Alberto");
+
+ Assertions.assertEquals("Alberto", subSet.first());
+
+ subSet = patriciaTrieSet.tailSet("Wir");
+
+ Assertions.assertEquals("Wirz", subSet.first());
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetLastShouldReturnCorrectResult() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+ patriciaTrieSet.add("Wl");
+ patriciaTrieSet.add("Al");
+
+ SortedSet subSet = patriciaTrieSet.headSet("Alberto");
+ Assertions.assertEquals("Albert", subSet.last());
+
+ subSet = patriciaTrieSet.headSet("Al");
+ Assertions.assertThrows(NoSuchElementException.class, subSet::last);
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetAddShouldReturnCorrectResult() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+ patriciaTrieSet.add("Wl");
+ patriciaTrieSet.add("Al");
+
+ final SortedSet subSet = patriciaTrieSet.headSet("Alberto");
+ subSet.add("Albert");
+
+ Assertions.assertEquals(2, subSet.size());
+ Assertions.assertEquals(6, patriciaTrieSet.size());
+
+ subSet.add("Alber");
+
+ Assertions.assertEquals(3, subSet.size());
+ Assertions.assertEquals(7, patriciaTrieSet.size());
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetRemoveShouldReturnCorrectResult() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+ patriciaTrieSet.add("Wl");
+ patriciaTrieSet.add("Al");
+
+ final SortedSet subSet = patriciaTrieSet.headSet("Alberto");
+ subSet.remove("Al");
+
+ Assertions.assertEquals(1, subSet.size());
+ Assertions.assertEquals(5, patriciaTrieSet.size());
+
+ subSet.remove("A");
+
+ Assertions.assertEquals(1, subSet.size());
+ Assertions.assertEquals(5, patriciaTrieSet.size());
+
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetIsEmptyShouldReturnCorrectResult() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+ patriciaTrieSet.add("Wl");
+ patriciaTrieSet.add("Al");
+
+ SortedSet subSet = patriciaTrieSet.headSet("Al");
+ assertTrue(subSet.isEmpty());
+
+ subSet = patriciaTrieSet.headSet("Albert");
+ assertFalse(subSet.isEmpty());
+ }
+
+ @Test
+ public void rangePatriciaTrieSortedSetClearShouldClearElements() {
+ patriciaTrieSet.add("Alberto");
+ patriciaTrieSet.add("Albert");
+ patriciaTrieSet.add("Wirz");
+ patriciaTrieSet.add("W");
+ patriciaTrieSet.add("Wl");
+ patriciaTrieSet.add("Al");
+
+ SortedSet subSet = patriciaTrieSet.headSet("Al");
+ subSet.clear();
+
+ Assertions.assertEquals(0, subSet.size());
+ Assertions.assertEquals(6, patriciaTrieSet.size());
+
+ subSet = patriciaTrieSet.headSet("Alberto");
+ subSet.clear();
+
+ Assertions.assertEquals(0, subSet.size());
+ Assertions.assertEquals(4, patriciaTrieSet.size());
+ }
+}