1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  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
17package java.util;
18
19
20/**
21 * A concrete EnumSet for enums with 64 or fewer elements.
22 */
23@SuppressWarnings("serial")
24final class MiniEnumSet<E extends Enum<E>> extends EnumSet<E> {
25    private static final int MAX_ELEMENTS = 64;
26
27    private int size;
28
29    private final E[] enums;
30
31    private long bits;
32
33    /**
34     * Constructs an instance.
35     *
36     * @param elementType non-null; type of the elements
37     * @param enums non-null; pre-populated array of constants in ordinal
38     * order
39     */
40    MiniEnumSet(Class<E> elementType, E[] enums) {
41        super(elementType);
42        this.enums = enums;
43    }
44
45    private class MiniEnumSetIterator implements Iterator<E> {
46
47        /**
48         * The bits yet to be returned for bits. As values from the current index are returned,
49         * their bits are zeroed out.
50         */
51        private long currentBits = bits;
52
53        /**
54         * The single bit of the next value to return.
55         */
56        private long mask = currentBits & -currentBits; // the lowest 1 bit in currentBits
57
58        /**
59         * The candidate for removal. If null, no value may be removed.
60         */
61        private E last;
62
63        public boolean hasNext() {
64            return mask != 0;
65        }
66
67        public E next() {
68            if (mask == 0) {
69                throw new NoSuchElementException();
70            }
71
72            int ordinal = Long.numberOfTrailingZeros(mask);
73            last = enums[ordinal];
74
75            currentBits &= ~mask;
76            mask = currentBits & -currentBits; // the lowest 1 bit in currentBits
77
78            return last;
79        }
80
81        public void remove() {
82            if (last == null) {
83                throw new IllegalStateException();
84            }
85
86            MiniEnumSet.this.remove(last);
87            last = null;
88        }
89    }
90
91    @Override
92    public Iterator<E> iterator() {
93        return new MiniEnumSetIterator();
94    }
95
96    @Override
97    public int size() {
98        return size;
99    }
100
101    @Override
102    public void clear() {
103        bits = 0;
104        size = 0;
105    }
106
107    @Override
108    public boolean add(E element) {
109        elementClass.cast(element); // Called to throw ClassCastException.
110        long oldBits = bits;
111        long newBits = oldBits | (1L << element.ordinal());
112        if (oldBits != newBits) {
113            bits = newBits;
114            size++;
115            return true;
116        }
117        return false;
118    }
119
120    @Override
121    public boolean addAll(Collection<? extends E> collection) {
122        if (collection.isEmpty()) {
123            return false;
124        }
125        if (collection instanceof EnumSet) {
126            EnumSet<?> set = (EnumSet) collection; // raw type due to javac bug 6548436
127            set.elementClass.asSubclass(elementClass); // Called to throw ClassCastException.
128
129            MiniEnumSet<?> miniSet = (MiniEnumSet<?>) set;
130            long oldBits = bits;
131            long newBits = oldBits | miniSet.bits;
132            bits = newBits;
133            size = Long.bitCount(newBits);
134            return (oldBits != newBits);
135        }
136        return super.addAll(collection);
137    }
138
139    @Override
140    public boolean contains(Object object) {
141        if (object == null || !isValidType(object.getClass())) {
142            return false;
143        }
144
145        @SuppressWarnings("unchecked") // guarded by isValidType()
146        Enum<E> element = (Enum<E>) object;
147        int ordinal = element.ordinal();
148        return (bits & (1L << ordinal)) != 0;
149    }
150
151    @Override
152    public boolean containsAll(Collection<?> collection) {
153        if (collection.isEmpty()) {
154            return true;
155        }
156        if (collection instanceof MiniEnumSet) {
157            MiniEnumSet<?> set = (MiniEnumSet<?>) collection;
158            long setBits = set.bits;
159            return isValidType(set.elementClass) && ((bits & setBits) == setBits);
160        }
161        return !(collection instanceof EnumSet) && super.containsAll(collection);
162    }
163
164    @Override
165    public boolean removeAll(Collection<?> collection) {
166        if (collection.isEmpty()) {
167            return false;
168        }
169        if (collection instanceof EnumSet) {
170            EnumSet<?> set = (EnumSet<?>) collection;
171            if (!isValidType(set.elementClass)) {
172                return false;
173            }
174
175            MiniEnumSet<E> miniSet = (MiniEnumSet<E>) set;
176            long oldBits = bits;
177            long newBits = oldBits & ~miniSet.bits;
178            if (oldBits != newBits) {
179                bits = newBits;
180                size = Long.bitCount(newBits);
181                return true;
182            }
183            return false;
184        }
185        return super.removeAll(collection);
186    }
187
188    @Override
189    public boolean retainAll(Collection<?> collection) {
190        if (collection instanceof EnumSet) {
191            EnumSet<?> set = (EnumSet<?>) collection;
192            if (!isValidType(set.elementClass)) {
193                if (size > 0) {
194                    clear();
195                    return true;
196                } else {
197                    return false;
198                }
199            }
200
201            MiniEnumSet<E> miniSet = (MiniEnumSet<E>) set;
202            long oldBits = bits;
203            long newBits = oldBits & miniSet.bits;
204            if (oldBits != newBits) {
205                bits = newBits;
206                size = Long.bitCount(newBits);
207                return true;
208            }
209            return false;
210        }
211        return super.retainAll(collection);
212    }
213
214    @Override
215    public boolean remove(Object object) {
216        if (object == null || !isValidType(object.getClass())) {
217            return false;
218        }
219
220        @SuppressWarnings("unchecked") // guarded by isValidType()
221        Enum<E> element = (Enum<E>) object;
222        int ordinal = element.ordinal();
223        long oldBits = bits;
224        long newBits = oldBits & ~(1L << ordinal);
225        if (oldBits != newBits) {
226            bits = newBits;
227            size--;
228            return true;
229        }
230        return false;
231    }
232
233    @Override
234    public boolean equals(Object object) {
235        if (!(object instanceof EnumSet)) {
236            return super.equals(object);
237        }
238        EnumSet<?> set =(EnumSet<?>) object;
239        if (!isValidType(set.elementClass)) {
240            return size == 0 && set.isEmpty();
241        }
242        return bits == ((MiniEnumSet<?>) set).bits;
243    }
244
245    @Override
246    void complement() {
247        if (enums.length != 0) {
248            bits = ~bits;
249            bits &= (-1L >>> (MAX_ELEMENTS - enums.length));
250            size = enums.length - size;
251        }
252    }
253
254    @Override
255    void setRange(E start, E end) {
256        int length = end.ordinal() - start.ordinal() + 1;
257        long range = (-1L >>> (MAX_ELEMENTS - length)) << start.ordinal();
258        bits |= range;
259        size = Long.bitCount(bits);
260    }
261}
262