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