Skip to content

Commit aa000a1

Browse files
committed
Add remaining FlagSet impls
Replace Env#copy(File, CopyFlags...) with copy(File, CopyFlagSet). As there is only one flag this should not be a breaking change. Deprecate Env#txn(Txn, TxnFlags...) as there is now Env#txn(Txn) Env#txn(Txn, TxnFlags) Env#txn(Txn, TxnFlagSet)
1 parent 0f66aaf commit aa000a1

19 files changed

+1066
-115
lines changed

src/main/java/org/lmdbjava/AbstractFlagSet.java

Lines changed: 163 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@
22

33
import java.util.Collection;
44
import java.util.Collections;
5-
import java.util.Comparator;
65
import java.util.EnumSet;
76
import java.util.Iterator;
87
import java.util.Objects;
98
import java.util.Set;
109
import java.util.function.Function;
11-
import java.util.stream.Collectors;
10+
import java.util.function.Supplier;
1211

1312
/**
1413
* Encapsulates an immutable set of flags and the associated bit mask for the flags in the set.
1514
*
1615
* @param <T>
1716
*/
18-
public abstract class AbstractFlagSet<T extends Enum<T> & MaskedFlag> implements Iterable<T> {
17+
public abstract class AbstractFlagSet<T extends Enum<T> & MaskedFlag> implements FlagSet<T> {
1918

2019
private final Set<T> flags;
2120
private final int mask;
@@ -29,35 +28,42 @@ protected AbstractFlagSet(final EnumSet<T> flags) {
2928
/**
3029
* @return THe combined bit mask for all flags in the set.
3130
*/
32-
int getMask() {
31+
@Override
32+
public int getMask() {
3333
return mask;
3434
}
3535

3636
/**
3737
* @return All flags in the set.
3838
*/
39+
@Override
3940
public Set<T> getFlags() {
4041
return flags;
4142
}
4243

4344
/**
4445
* @return True if flag has been set, i.e. is contained in this set.
4546
*/
47+
@Override
4648
public boolean isSet(final T flag) {
49+
// Probably cheaper to compare the masks than to use EnumSet.contains()
4750
return flag != null
48-
&& flags.contains(flag);
51+
&& MaskedFlag.isSet(mask, flag);
52+
4953
}
5054

5155
/**
5256
* @return The number of flags in this set.
5357
*/
58+
@Override
5459
public int size() {
5560
return flags.size();
5661
}
5762

5863
/**
5964
* @return True if this set is empty.
6065
*/
66+
@Override
6167
public boolean isEmpty() {
6268
return flags.isEmpty();
6369
}
@@ -73,9 +79,8 @@ public Iterator<T> iterator() {
7379
@Override
7480
public boolean equals(Object object) {
7581
if (this == object) return true;
76-
if (object == null || getClass() != object.getClass()) return false;
77-
AbstractFlagSet<?> flagSet = (AbstractFlagSet<?>) object;
78-
return mask == flagSet.mask && Objects.equals(flags, flagSet.flags);
82+
// if (object == null || getClass() != object.getClass()) return false;
83+
return FlagSet.equals(this, (FlagSet<?>) object);
7984
}
8085

8186
@Override
@@ -85,14 +90,137 @@ public int hashCode() {
8590

8691
@Override
8792
public String toString() {
88-
final String flagsStr = flags.stream()
89-
.sorted(Comparator.comparing(MaskedFlag::getMask))
90-
.map(MaskedFlag::name)
91-
.collect(Collectors.joining(", "));
92-
return "FlagSet{" +
93-
"flags=[" + flagsStr +
94-
"], mask=" + mask +
95-
'}';
93+
return FlagSet.asString(this);
94+
}
95+
96+
97+
// --------------------------------------------------------------------------------
98+
99+
100+
static abstract class AbstractSingleFlagSet<T extends Enum<T> & MaskedFlag> implements FlagSet<T> {
101+
102+
private final T flag;
103+
// Only holding this for iterator() and getFlags() so make it lazy.
104+
private EnumSet<T> enumSet;
105+
106+
public AbstractSingleFlagSet(final T flag) {
107+
this.flag = Objects.requireNonNull(flag);
108+
}
109+
110+
@Override
111+
public int getMask() {
112+
return flag.getMask();
113+
}
114+
115+
@Override
116+
public Set<T> getFlags() {
117+
if (enumSet == null) {
118+
return initSet();
119+
} else {
120+
return this.enumSet;
121+
}
122+
}
123+
124+
@Override
125+
public boolean isSet(final T flag) {
126+
return this.flag == flag;
127+
}
128+
129+
@Override
130+
public int size() {
131+
return 1;
132+
}
133+
134+
@Override
135+
public boolean isEmpty() {
136+
return false;
137+
}
138+
139+
@Override
140+
public Iterator<T> iterator() {
141+
if (enumSet == null) {
142+
return initSet().iterator();
143+
} else {
144+
return this.enumSet.iterator();
145+
}
146+
}
147+
148+
@Override
149+
public String toString() {
150+
return FlagSet.asString(this);
151+
}
152+
153+
@Override
154+
public boolean equals(Object object) {
155+
if (this == object) return true;
156+
// if (object == null || getClass() != object.getClass()) return false;
157+
return FlagSet.equals(this, (FlagSet<?>) object);
158+
}
159+
160+
@Override
161+
public int hashCode() {
162+
return Objects.hash(flag, getFlags());
163+
}
164+
165+
private Set<T> initSet() {
166+
final EnumSet<T> set = EnumSet.of(this.flag);
167+
this.enumSet = set;
168+
return set;
169+
}
170+
}
171+
172+
173+
// --------------------------------------------------------------------------------
174+
175+
176+
static class AbstractEmptyFlagSet<T extends MaskedFlag> implements FlagSet<T> {
177+
178+
@Override
179+
public int getMask() {
180+
return MaskedFlag.EMPTY_MASK;
181+
}
182+
183+
@Override
184+
public Set<T> getFlags() {
185+
return Collections.emptySet();
186+
}
187+
188+
@Override
189+
public boolean isSet(final T flag) {
190+
return false;
191+
}
192+
193+
@Override
194+
public int size() {
195+
return 0;
196+
}
197+
198+
@Override
199+
public boolean isEmpty() {
200+
return true;
201+
}
202+
203+
@Override
204+
public Iterator<T> iterator() {
205+
return Collections.emptyIterator();
206+
}
207+
208+
@Override
209+
public String toString() {
210+
return FlagSet.asString(this);
211+
}
212+
213+
@Override
214+
public boolean equals(Object object) {
215+
if (this == object) return true;
216+
// if (object == null || getClass() != object.getClass()) return false;
217+
return FlagSet.equals(this, (FlagSet<?>) object);
218+
}
219+
220+
@Override
221+
public int hashCode() {
222+
return Objects.hash(getMask(), getFlags());
223+
}
96224
}
97225

98226

@@ -105,17 +233,23 @@ public String toString() {
105233
* @param <E> The type of flag to be held in the {@link AbstractFlagSet}
106234
* @param <S> The type of the {@link AbstractFlagSet} implementation.
107235
*/
108-
public static class Builder<E extends Enum<E> & MaskedFlag, S extends AbstractFlagSet<E>> {
236+
public static class Builder<E extends Enum<E> & MaskedFlag, S extends FlagSet<E>> {
109237

110238
final Class<E> type;
111239
final EnumSet<E> enumSet;
112240
final Function<EnumSet<E>, S> constructor;
241+
final Function<E, S> singletonSetConstructor;
242+
final Supplier<S> emptySetSupplier;
113243

114244
protected Builder(final Class<E> type,
115-
final Function<EnumSet<E>, S> constructor) {
245+
final Function<EnumSet<E>, S> constructor,
246+
final Function<E, S> singletonSetConstructor,
247+
final Supplier<S> emptySetSupplier) {
116248
this.type = type;
117249
this.enumSet = EnumSet.noneOf(type);
118-
this.constructor = constructor;
250+
this.constructor = Objects.requireNonNull(constructor);
251+
this.singletonSetConstructor = Objects.requireNonNull(singletonSetConstructor);
252+
this.emptySetSupplier = Objects.requireNonNull(emptySetSupplier);
119253
}
120254

121255
/**
@@ -125,7 +259,7 @@ protected Builder(final Class<E> type,
125259
* @return this builder instance.
126260
*/
127261
public Builder<E, S> withFlags(final Collection<E> flags) {
128-
enumSet.clear();
262+
clear();
129263
if (flags != null) {
130264
for (E flag : flags) {
131265
if (flag != null) {
@@ -142,7 +276,7 @@ public Builder<E, S> withFlags(final Collection<E> flags) {
142276
*/
143277
@SafeVarargs
144278
public final Builder<E, S> withFlags(final E... flags) {
145-
enumSet.clear();
279+
clear();
146280
if (flags != null) {
147281
for (E flag : flags) {
148282
if (flag != null) {
@@ -185,8 +319,14 @@ public Builder<E, S> clear() {
185319
* @return A
186320
*/
187321
public S build() {
188-
return constructor.apply(enumSet);
322+
final int size = enumSet.size();
323+
if (size == 0) {
324+
return emptySetSupplier.get();
325+
} else if (size == 1) {
326+
return singletonSetConstructor.apply(enumSet.stream().findFirst().get());
327+
} else {
328+
return constructor.apply(enumSet);
329+
}
189330
}
190331
}
191332
}
192-
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package org.lmdbjava;
2+
3+
import java.util.Collection;
4+
import java.util.EnumSet;
5+
import java.util.Objects;
6+
7+
public interface CopyFlagSet extends FlagSet<CopyFlags> {
8+
9+
static CopyFlagSet EMPTY = CopyFlagSetImpl.EMPTY;
10+
11+
static CopyFlagSet empty() {
12+
return CopyFlagSetImpl.EMPTY;
13+
}
14+
15+
static CopyFlagSet of(final CopyFlags dbiFlag) {
16+
Objects.requireNonNull(dbiFlag);
17+
return dbiFlag;
18+
}
19+
20+
static CopyFlagSet of(final CopyFlags... CopyFlags) {
21+
return builder()
22+
.withFlags(CopyFlags)
23+
.build();
24+
}
25+
26+
static CopyFlagSet of(final Collection<CopyFlags> CopyFlags) {
27+
return builder()
28+
.withFlags(CopyFlags)
29+
.build();
30+
}
31+
32+
static AbstractFlagSet.Builder<CopyFlags, CopyFlagSet> builder() {
33+
return new AbstractFlagSet.Builder<>(
34+
CopyFlags.class,
35+
CopyFlagSetImpl::new,
36+
copyFlag -> copyFlag,
37+
() -> CopyFlagSetImpl.EMPTY);
38+
}
39+
40+
41+
// --------------------------------------------------------------------------------
42+
43+
44+
class CopyFlagSetImpl extends AbstractFlagSet<CopyFlags> implements CopyFlagSet {
45+
46+
static final CopyFlagSet EMPTY = new EmptyCopyFlagSet();
47+
48+
private CopyFlagSetImpl(final EnumSet<CopyFlags> flags) {
49+
super(flags);
50+
}
51+
}
52+
53+
54+
// --------------------------------------------------------------------------------
55+
56+
57+
class EmptyCopyFlagSet extends AbstractFlagSet.AbstractEmptyFlagSet<CopyFlags> implements CopyFlagSet {
58+
}
59+
}

src/main/java/org/lmdbjava/CopyFlags.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515
*/
1616
package org.lmdbjava;
1717

18+
import java.util.EnumSet;
19+
import java.util.Set;
20+
1821
/** Flags for use when performing a {@link Env#copy(java.io.File, org.lmdbjava.CopyFlags...)}. */
19-
public enum CopyFlags implements MaskedFlag {
22+
public enum CopyFlags implements MaskedFlag, CopyFlagSet {
2023

2124
/** Compacting copy: Omit free space from copy, and renumber all pages sequentially. */
2225
MDB_CP_COMPACT(0x01);
@@ -31,4 +34,29 @@ public enum CopyFlags implements MaskedFlag {
3134
public int getMask() {
3235
return mask;
3336
}
37+
38+
@Override
39+
public Set<CopyFlags> getFlags() {
40+
return EnumSet.of(this);
41+
}
42+
43+
@Override
44+
public boolean isSet(final CopyFlags flag) {
45+
return flag != null && mask == flag.getMask();
46+
}
47+
48+
@Override
49+
public int size() {
50+
return 1;
51+
}
52+
53+
@Override
54+
public boolean isEmpty() {
55+
return false;
56+
}
57+
58+
@Override
59+
public String toString() {
60+
return FlagSet.asString(this);
61+
}
3462
}

0 commit comments

Comments
 (0)