content: /*
   * Copyright 1999-2012 Alibaba Group.
   *  
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *  
   *      http://www.apache.org/licenses/LICENSE-2.0
   *  
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  /**
   * (created at 2011-8-23)
   */
  package com.alibaba.cobar.util;
  
  import java.io.Serializable;
  import java.util.AbstractSet;
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.NoSuchElementException;
  import java.util.Set;
  
  /**
   * usually one element
   * 
   * @author <a href="mailto:shuo.qius@alibaba-inc.com">QIU Shuo</a>
   */
  public final class SmallSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable {
  
      private static final long serialVersionUID = 2037649294658559180L;
  
      private final int initSize;
      private ArrayList<E> list;
      private E single;
      private int size;
  
      public SmallSet() {
          this(2);
      }
  
      public SmallSet(int initSize) {
          this.initSize = initSize;
      }
  
      @Override
      public boolean add(E e) {
          switch (size) {
          case 0:
              ++size;
              single = e;
              return true;
          case 1:
              if (isEquals(e, single))
                  return false;
              list = new ArrayList<E>(initSize);
              list.add(single);
              list.add(e);
              ++size;
              return true;
          default:
              for (int i = 0; i < list.size(); ++i) {
                  E e1 = list.get(i);
                  if (isEquals(e1, e))
                      return false;
              }
              list.add(e);
              ++size;
              return true;
          }
      }
  
      private boolean isEquals(E e1, E e2) {
          if (e1 == null)
              return e2 == null;
          return e1.equals(e2);
      }
  
      @Override
      protected Object clone() throws CloneNotSupportedException {
          return super.clone();
      }
  
      @Override
      public Iterator<E> iterator() {
          return new Iterator<E>() {
              private int i;
              private boolean next;
  
              @Override
              public boolean hasNext() {
                  return i < size;
              }
  
              @Override
              public E next() {
                  next = true;
                  switch (size) {
                  case 0:
                      throw new NoSuchElementException();
                  case 1:
                      switch (i) {
                      case 0:
                          ++i;
                          return single;
                      default:
                          throw new NoSuchElementException();
                      }
                  default:
                      try {
                          E e = list.get(i);
                          ++i;
                          return e;
                      } catch (IndexOutOfBoundsException e) {
                          throw new NoSuchElementException(e.getMessage());
                      }
                  }
              }
  
              @Override
              public void remove() {
                  if (!next)
                      throw new IllegalStateException();
                  switch (size) {
                  case 0:
                      throw new IllegalStateException();
                  case 1:
                      size = i = 0;
                      single = null;
                      if (list != null && !list.isEmpty())
                          list.remove(0);
                      break;
                  default:
                      list.remove(--i);
                      if (--size == 1)
                          single = list.get(0);
                      break;
                  }
                  next = false;
              }
          };
      }
  
      @Override
      public int size() {
          return size;
      }
  
  }
  