22
33import java .util .Collection ;
44import java .util .Collections ;
5- import java .util .Comparator ;
65import java .util .EnumSet ;
76import java .util .Iterator ;
87import java .util .Objects ;
98import java .util .Set ;
109import 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-
0 commit comments