001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.internal;
018
019import java.util.*;
020
021import org.apache.juneau.common.utils.*;
022
023/**
024 * Encapsulates multiple collections so they can be iterated over as if they were all part of the same collection.
025 *
026 * <h5 class='section'>See Also:</h5><ul>
027
028 * </ul>
029 *
030 * @param <E> The object type of this set.
031 */
032public class MultiSet<E> extends AbstractSet<E> {
033
034   /** Inner collections. */
035   final Collection<E>[] l;
036
037   /**
038    * Create a new Set that consists as a coalesced set of the specified collections.
039    *
040    * @param c Zero or more collections to add to this set.
041    */
042   @SafeVarargs
043   public MultiSet(Collection<E>...c) {
044      Utils.assertArgNotNull("c", c);
045      for (Collection<E> cc : c)
046         Utils.assertArgNotNull("c", cc);
047      l = c;
048   }
049
050   /**
051    * Iterates over all entries in all collections.
052    */
053   @Override /* Set */
054   public Iterator<E> iterator() {
055      return new Iterator<>() {
056         int i = 0;
057         Iterator<E> i2 = (l.length > 0 ? l[i++].iterator() : null);
058
059         @Override /* Iterator */
060         public boolean hasNext() {
061            if (i2 == null)
062               return false;
063            if (i2.hasNext())
064               return true;
065            for (int j = i; j < l.length; j++)
066               if (l[j].size() > 0)
067                  return true;
068            return false;
069         }
070
071         @Override /* Iterator */
072         public E next() {
073            if (i2 == null)
074               throw new NoSuchElementException();
075            while (! i2.hasNext()) {
076               if (i >= l.length)
077                  throw new NoSuchElementException();
078               i2 = l[i++].iterator();
079            }
080            return i2.next();
081         }
082
083         @Override /* Iterator */
084         public void remove() {
085            if (i2 == null)
086               throw new NoSuchElementException();
087            i2.remove();
088         }
089      };
090   }
091
092   /**
093    * Enumerates over all entries in all collections.
094    *
095    * @return An enumeration wrapper around this set.
096    */
097   public Enumeration<E> enumerator() {
098      return Collections.enumeration(this);
099   }
100
101   @Override /* Set */
102   public int size() {
103      int i = 0;
104      for (Collection<E> c : l)
105         i += c.size();
106      return i;
107   }
108}