Home | History | Annotate | Download | only in util
      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 
     17 package java.util;
     18 
     19 
     20 /**
     21  * A concrete EnumSet for enums with 64 or fewer elements.
     22  */
     23 @SuppressWarnings("serial")
     24 final 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