Skip to content

Commit 2ff44ef

Browse files
committed
Add ImmutableSet types
Change-Id: Id4beb72f4744fdf9605faadd2343e9b256bc06dc
1 parent 9361932 commit 2ff44ef

13 files changed

+810
-1
lines changed

drv/ImmutableSet.drv

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Copyright (C) 2002-2023 Sebastiano Vigna
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
18+
package PACKAGE;
19+
20+
21+
import java.util.ArrayList;
22+
import java.util.Collection;
23+
import java.util.stream.Collector;
24+
25+
import static java.util.stream.Collectors.collectingAndThen;
26+
import static java.util.stream.Collectors.toCollection;
27+
import static java.util.stream.Collectors.toList;
28+
29+
/**
30+
* Make an unmodifiable set feel like a Guava immutable set.
31+
*
32+
* <p>Mostly this means copy-on-construction and exposing an explicit immutable type.
33+
* Note that unlike the Guava versions, we don't guarantee anything about the iteration order.
34+
*/
35+
@SuppressWarnings({"unused", "unchecked"})
36+
public class IMMUTABLE_SET KEY_GENERIC extends SETS.UnmodifiableSet KEY_GENERIC {
37+
38+
private static final long serialVersionUID = 0L;
39+
40+
@SuppressWarnings("rawtypes")
41+
private static final IMMUTABLE_SET EMPTY =
42+
new IMMUTABLE_SET(SETS.emptySet());
43+
44+
private IMMUTABLE_SET(SET KEY_GENERIC set) {
45+
super(set);
46+
}
47+
48+
public static KEY_GENERIC IMMUTABLE_SET KEY_GENERIC of() {
49+
return EMPTY;
50+
}
51+
52+
public static KEY_GENERIC IMMUTABLE_SET KEY_GENERIC of(KEY_GENERIC_TYPE key) {
53+
return new IMMUTABLE_SET KEY_GENERIC(SETS.singleton(key));
54+
}
55+
56+
public static KEY_GENERIC IMMUTABLE_SET KEY_GENERIC of(KEY_GENERIC_TYPE... keys) {
57+
SET KEY_GENERIC set = new OPEN_HASH_SET KEY_GENERIC (keys.length);
58+
for (KEY_GENERIC_TYPE key : keys) {
59+
set.add(key);
60+
}
61+
return new IMMUTABLE_SET KEY_GENERIC(set);
62+
}
63+
64+
@SuppressWarnings("deprecation")
65+
public static KEY_GENERIC IMMUTABLE_SET KEY_GENERIC copyOf(Iterable<? extends KEY_GENERIC_CLASS> iter) {
66+
if ((iter instanceof IMMUTABLE_SET)) {
67+
return (IMMUTABLE_SET KEY_GENERIC) iter;
68+
}
69+
Collection<KEY_GENERIC_CLASS> col;
70+
if (iter instanceof Collection) {
71+
col = (Collection<KEY_GENERIC_CLASS>) iter;
72+
} else {
73+
col = new ArrayList<KEY_GENERIC_CLASS>();
74+
iter.forEach(col::add);
75+
}
76+
if (col.isEmpty()) {
77+
return of();
78+
}
79+
if (col.size() == 1) {
80+
return of(col.iterator().next());
81+
}
82+
if ((col instanceof SETS.UnmodifiableSet)) {
83+
return new IMMUTABLE_SET KEY_GENERIC((SET) col);
84+
}
85+
if (col instanceof COLLECTION) {
86+
return new IMMUTABLE_SET KEY_GENERIC(new OPEN_HASH_SET KEY_GENERIC((COLLECTION KEY_GENERIC) col));
87+
}
88+
return new IMMUTABLE_SET KEY_GENERIC (new OPEN_HASH_SET KEY_GENERIC(col));
89+
}
90+
91+
public static KEY_GENERIC IMMUTABLE_SET KEY_GENERIC copyOf(KEY_GENERIC_TYPE[] arr) {
92+
return arr.length == 0
93+
? of()
94+
: arr.length == 1
95+
? of(arr[0])
96+
: new IMMUTABLE_SET KEY_GENERIC(new OPEN_HASH_SET KEY_GENERIC(arr));
97+
}
98+
99+
public static KEY_GENERIC Collector<KEY_GENERIC_CLASS, ?, IMMUTABLE_SET KEY_GENERIC> TO_IMMUTABLE_SET() {
100+
return collectingAndThen(
101+
toCollection(OPEN_HASH_SET::new), IMMUTABLE_SET::new);
102+
}
103+
104+
public static class Builder KEY_GENERIC {
105+
106+
private OPEN_HASH_SET KEY_GENERIC temp;
107+
108+
public Builder() {
109+
temp = new OPEN_HASH_SET KEY_GENERIC();
110+
}
111+
112+
public Builder(int initialCapacity) {
113+
temp = new OPEN_HASH_SET KEY_GENERIC(initialCapacity);
114+
}
115+
116+
public Builder KEY_GENERIC add(KEY_GENERIC_TYPE... keys) {
117+
for (KEY_GENERIC_TYPE key : keys) {
118+
temp.add(key);
119+
}
120+
return this;
121+
}
122+
123+
@SuppressWarnings("deprecation")
124+
public Builder KEY_GENERIC addAll(Iterable<? extends KEY_GENERIC_CLASS> iter) {
125+
#if KEYS_PRIMITIVE
126+
if (iter instanceof COLLECTION) {
127+
return add(((COLLECTION KEY_GENERIC) iter).TO_KEY_ARRAY());
128+
}
129+
#endif
130+
if (iter instanceof Collection) {
131+
temp.addAll((Collection<? extends KEY_GENERIC_CLASS>) iter);
132+
} else {
133+
iter.forEach(temp::add);
134+
}
135+
return this;
136+
}
137+
138+
public Builder KEY_GENERIC combine(Builder KEY_GENERIC other) {
139+
return addAll(other.temp);
140+
}
141+
142+
public IMMUTABLE_SET KEY_GENERIC build() {
143+
OPEN_HASH_SET KEY_GENERIC built = temp;
144+
temp = null;
145+
built.trim();
146+
return new IMMUTABLE_SET KEY_GENERIC(built);
147+
}
148+
}
149+
}

gencsource.sh

+8
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,14 @@ $(if [[ "${CLASS[$k]}" != "" && "${CLASS[$v]}" != "" ]]; then\
607607
"#define UNMODIFIABLE_KEY_BIDI_ITERATOR Unmodifiable${TYPE_CAP[$k]}BidirectionalIterator\n"\
608608
"#define UNMODIFIABLE_KEY_LIST_ITERATOR Unmodifiable${TYPE_CAP[$k]}ListIterator\n"\
609609
\
610+
"/* Immutable wrappers */\n"\
611+
\
612+
\
613+
"#define IMMUTABLE_SET ${TYPE_CAP[$k]}ImmutableSet\n"\
614+
"#define IMMUTABLE_MAP ${TYPE_CAP[$k]}2${TYPE_CAP[$v]}ImmutableMap\n"\
615+
"#define TO_IMMUTABLE_SET to${TYPE_CAP[$k]}ImmutableSet\n"\
616+
"#define TO_IMMUTABLE_MAP to${TYPE_CAP[$k]}2${TYPE_CAP[$v]}ImmutableMap\n"\
617+
\
610618
\
611619
"/* Other wrappers */\n"\
612620
\

makefile

+11
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,17 @@ $(COMPARATORS_STATIC): drv/Comparators.drv; ./gencsource.sh $< $@ >$@
629629

630630
CSOURCES += $(COMPARATORS_STATIC)
631631

632+
633+
#
634+
# Immutable wrappers
635+
#
636+
637+
IMMUTABLE_SETS := $(foreach k,$(TYPE_NOREF), $(GEN_SRCDIR)/$(PKG_PATH)/$(PACKAGE_$(k))/$(k)ImmutableSet.c)
638+
$(IMMUTABLE_SETS): drv/ImmutableSet.drv; ./gencsource.sh $< $@ >$@
639+
640+
CSOURCES += $(IMMUTABLE_SETS)
641+
642+
632643
#
633644
# Fragmented stuff
634645
#

test.sh

+9-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,15 @@ for ((t=1; t<10000; t*=10)); do
3737
java -ea -server $CLASSNAME test $t $lf
3838
done
3939

40-
MAP=(OpenHashMap LinkedOpenHashMap RBTreeMap AVLTreeMap)
40+
l=${#TYPE[*]}
41+
for ((k=1; k<l; k++)); do
42+
CLASSNAME=it.unimi.dsi.fastutil.${PACKAGE[$k]}.${TYPE_CAP[$k]}ImmutableSet
43+
echo "Testing $CLASSNAME ($t elements)..."
44+
java -ea -server $CLASSNAME test $t
45+
done
46+
47+
48+
MAP=(OpenHashMap LinkedOpenHashMap RBTreeMap AVLTreeMap)
4149

4250
for ((f=0; f<${#MAP[*]}; f++)); do
4351
l=${#TYPE[*]}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package it.unimi.dsi.fastutil.booleans;
2+
3+
import java.util.Arrays;
4+
5+
import org.junit.Test;
6+
7+
import static org.junit.Assert.assertEquals;
8+
import static org.junit.Assert.assertThrows;
9+
import static org.junit.Assert.assertTrue;
10+
11+
public class BooleanImmutableSetTest {
12+
13+
@Test
14+
public void testEmpty() {
15+
BooleanImmutableSet set = BooleanImmutableSet.of();
16+
assertTrue(set.isEmpty());
17+
assertThrows(UnsupportedOperationException.class, () -> set.add(false));
18+
}
19+
20+
@Test
21+
public void test1() {
22+
BooleanImmutableSet set = BooleanImmutableSet.of(true);
23+
assertEquals(1, set.size());
24+
assertTrue(set.contains(true));
25+
assertThrows(UnsupportedOperationException.class, () -> set.add(false));
26+
}
27+
28+
@Test
29+
@SuppressWarnings("UnnecessaryBoxing")
30+
public void testBuilder() {
31+
BooleanImmutableSet.Builder builder = new BooleanImmutableSet.Builder();
32+
builder.add(true);
33+
builder.addAll(BooleanArraySet.of(false));
34+
BooleanImmutableSet set = builder.build();
35+
assertEquals(2, set.size());
36+
assertTrue(set.contains(true));
37+
assertTrue(set.contains(false));
38+
}
39+
40+
@Test
41+
public void testCollector() {
42+
BooleanImmutableSet c =
43+
Arrays.asList(true, false).stream().collect(BooleanImmutableSet.toBooleanImmutableSet());
44+
assertEquals(2, c.size());
45+
assertTrue(c.contains(true));
46+
assertTrue(c.contains(false));
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package it.unimi.dsi.fastutil.bytes;
2+
3+
import java.util.Arrays;
4+
import java.util.HashSet;
5+
6+
import org.junit.Test;
7+
8+
import static org.junit.Assert.assertEquals;
9+
import static org.junit.Assert.assertThrows;
10+
import static org.junit.Assert.assertTrue;
11+
12+
public class ByteImmutableSetTest {
13+
14+
@Test
15+
public void testEmpty() {
16+
ByteImmutableSet set = ByteImmutableSet.of();
17+
assertTrue(set.isEmpty());
18+
assertThrows(UnsupportedOperationException.class, () -> set.add((byte) 10));
19+
}
20+
21+
@Test
22+
public void test1() {
23+
ByteImmutableSet set = ByteImmutableSet.of((byte) 1);
24+
assertEquals(1, set.size());
25+
assertTrue(set.contains((byte) 1));
26+
assertThrows(UnsupportedOperationException.class, () -> set.add((byte) 10));
27+
}
28+
29+
@Test
30+
public void test5() {
31+
ByteImmutableSet set = ByteImmutableSet.of((byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5);
32+
assertEquals(5, set.size());
33+
assertTrue(set.contains((byte) 1));
34+
assertTrue(set.contains((byte) 2));
35+
assertTrue(set.contains((byte) 3));
36+
assertTrue(set.contains((byte) 4));
37+
assertTrue(set.contains((byte) 5));
38+
assertThrows(UnsupportedOperationException.class, () -> set.add((byte) 10));
39+
}
40+
41+
@Test
42+
@SuppressWarnings("UnnecessaryBoxing")
43+
public void testBuilder() {
44+
ByteImmutableSet.Builder builder = new ByteImmutableSet.Builder();
45+
builder.add((byte) 0);
46+
builder.add((byte) 1, (byte) 2, (byte) 3);
47+
builder.add(Byte.valueOf((byte) 4));
48+
builder.addAll(ByteArraySet.of((byte) 5, (byte) 6, (byte) 7));
49+
builder.addAll(new HashSet<>(Arrays.asList((byte) 8, (byte) 9)));
50+
ByteImmutableSet set = builder.build();
51+
assertEquals(10, set.size());
52+
assertTrue(set.contains((byte) 0));
53+
assertTrue(set.contains((byte) 1));
54+
assertTrue(set.contains((byte) 2));
55+
assertTrue(set.contains((byte) 3));
56+
assertTrue(set.contains((byte) 4));
57+
assertTrue(set.contains((byte) 5));
58+
assertTrue(set.contains((byte) 6));
59+
assertTrue(set.contains((byte) 7));
60+
assertTrue(set.contains((byte) 8));
61+
assertTrue(set.contains((byte) 9));
62+
}
63+
64+
@Test
65+
public void testCollector() {
66+
ByteImmutableSet c =
67+
Arrays.asList((byte) 1, (byte) 2).stream().collect(ByteImmutableSet.toByteImmutableSet());
68+
assertEquals(2, c.size());
69+
assertTrue(c.contains((byte) 1));
70+
assertTrue(c.contains((byte) 2));
71+
}
72+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package it.unimi.dsi.fastutil.chars;
2+
3+
import java.util.Arrays;
4+
import java.util.HashSet;
5+
6+
import org.junit.Test;
7+
8+
import static org.junit.Assert.assertEquals;
9+
import static org.junit.Assert.assertThrows;
10+
import static org.junit.Assert.assertTrue;
11+
12+
public class CharImmutableSetTest {
13+
14+
@Test
15+
public void testEmpty() {
16+
CharImmutableSet set = CharImmutableSet.of();
17+
assertTrue(set.isEmpty());
18+
assertThrows(UnsupportedOperationException.class, () -> set.add((char) 10));
19+
}
20+
21+
@Test
22+
public void test1() {
23+
CharImmutableSet set = CharImmutableSet.of((char) 1);
24+
assertEquals(1, set.size());
25+
assertTrue(set.contains((char) 1));
26+
assertThrows(UnsupportedOperationException.class, () -> set.add((char) 10));
27+
}
28+
29+
@Test
30+
public void test5() {
31+
CharImmutableSet set = CharImmutableSet.of((char) 1, (char) 2, (char) 3, (char) 4, (char) 5);
32+
assertEquals(5, set.size());
33+
assertTrue(set.contains((char) 1));
34+
assertTrue(set.contains((char) 2));
35+
assertTrue(set.contains((char) 3));
36+
assertTrue(set.contains((char) 4));
37+
assertTrue(set.contains((char) 5));
38+
assertThrows(UnsupportedOperationException.class, () -> set.add((char) 10));
39+
}
40+
41+
@Test
42+
@SuppressWarnings("UnnecessaryBoxing")
43+
public void testBuilder() {
44+
CharImmutableSet.Builder builder = new CharImmutableSet.Builder();
45+
builder.add((char) 0);
46+
builder.add((char) 1, (char) 2, (char) 3);
47+
builder.add(Character.valueOf((char) 4));
48+
builder.addAll(CharArraySet.of((char) 5, (char) 6, (char) 7));
49+
builder.addAll(new HashSet<>(Arrays.asList((char) 8, (char) 9)));
50+
CharImmutableSet set = builder.build();
51+
assertEquals(10, set.size());
52+
assertTrue(set.contains((char) 0));
53+
assertTrue(set.contains((char) 1));
54+
assertTrue(set.contains((char) 2));
55+
assertTrue(set.contains((char) 3));
56+
assertTrue(set.contains((char) 4));
57+
assertTrue(set.contains((char) 5));
58+
assertTrue(set.contains((char) 6));
59+
assertTrue(set.contains((char) 7));
60+
assertTrue(set.contains((char) 8));
61+
assertTrue(set.contains((char) 9));
62+
}
63+
64+
@Test
65+
public void testCollector() {
66+
CharImmutableSet c =
67+
Arrays.asList((char) 1, (char) 2).stream().collect(CharImmutableSet.toCharImmutableSet());
68+
assertEquals(2, c.size());
69+
assertTrue(c.contains((char) 1));
70+
assertTrue(c.contains((char) 2));
71+
}
72+
}

0 commit comments

Comments
 (0)