| /* |
| * Copyright 2017-present Open Networking Foundation |
| * |
| * 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. |
| */ |
| |
| package org.onosproject.pi.demo.app.tor; |
| |
| import com.google.common.collect.AbstractIterator; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.math.IntMath; |
| |
| import java.util.AbstractSet; |
| import java.util.BitSet; |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.Set; |
| |
| import static com.google.common.base.Preconditions.checkArgument; |
| |
| /** |
| * Combination algorithm implementation, taken from Guava 23. |
| */ |
| final class Combination { |
| |
| private Combination() { |
| // Hides constructor. |
| } |
| |
| /** |
| * Returns a map from the ith element of list to i. |
| */ |
| private static <E> ImmutableMap<E, Integer> indexMap(Collection<E> list) { |
| ImmutableMap.Builder<E, Integer> builder = ImmutableMap.builder(); |
| int i = 0; |
| for (E e : list) { |
| builder.put(e, i++); |
| } |
| return builder.build(); |
| } |
| |
| /** |
| * Returns the set of all subsets of {@code set} of size {@code size}. For example, {@code |
| * combinations(ImmutableSet.of(1, 2, 3), 2)} returns the set {@code {{1, 2}, {1, 3}, {2, 3}}}. |
| * <p> |
| * <p>Elements appear in these subsets in the same iteration order as they appeared in the input set. The order in |
| * which these subsets appear in the outer set is undefined. |
| * <p> |
| * <p>The returned set and its constituent sets use {@code equals} to decide whether two elements are identical, |
| * even if the input set uses a different concept of equivalence. |
| * <p> |
| * <p><i>Performance notes:</i> the memory usage of the returned set is only {@code O(n)}. When the result set is |
| * constructed, the input set is merely copied. Only as the result set is iterated are the individual subsets |
| * created. Each of these subsets occupies an additional O(n) memory but only for as long as the user retains a |
| * reference to it. That is, the set returned by {@code combinations} does not retain the individual subsets. |
| * |
| * @param set the set of elements to take combinations of |
| * @param size the number of elements per combination |
| * @return the set of all combinations of {@code size} elements from {@code set} |
| * @throws IllegalArgumentException if {@code size} is not between 0 and {@code set.size()} inclusive |
| * @throws NullPointerException if {@code set} is or contains {@code null} |
| * @since 23.0 |
| */ |
| static <E> Set<Set<E>> combinations(Set<E> set, final int size) { |
| final ImmutableMap<E, Integer> index = indexMap(set); |
| checkArgument(size > 0, "size"); |
| checkArgument(size <= index.size(), "size (%s) must be <= set.size() (%s)", size, index.size()); |
| if (size == 0) { |
| return ImmutableSet.of(ImmutableSet.<E>of()); |
| } else if (size == index.size()) { |
| return ImmutableSet.of(index.keySet()); |
| } |
| return new AbstractSet<Set<E>>() { |
| @Override |
| public boolean contains(Object o) { |
| if (o instanceof Set) { |
| Set<?> s = (Set<?>) o; |
| return s.size() == size && index.keySet().containsAll(s); |
| } |
| return false; |
| } |
| |
| @Override |
| public Iterator<Set<E>> iterator() { |
| return new AbstractIterator<Set<E>>() { |
| final BitSet bits = new BitSet(index.size()); |
| |
| @Override |
| protected Set<E> computeNext() { |
| if (bits.isEmpty()) { |
| bits.set(0, size); |
| } else { |
| int firstSetBit = bits.nextSetBit(0); |
| int bitToFlip = bits.nextClearBit(firstSetBit); |
| |
| if (bitToFlip == index.size()) { |
| return endOfData(); |
| } |
| |
| /* |
| * The current set in sorted order looks like |
| * {firstSetBit, firstSetBit + 1, ..., bitToFlip - 1, ...} |
| * where it does *not* contain bitToFlip. |
| * |
| * The next combination is |
| * |
| * {0, 1, ..., bitToFlip - firstSetBit - 2, bitToFlip, ...} |
| * |
| * This is lexicographically next if you look at the combinations in descending order |
| * e.g. {2, 1, 0}, {3, 1, 0}, {3, 2, 0}, {3, 2, 1}, {4, 1, 0}... |
| */ |
| |
| bits.set(0, bitToFlip - firstSetBit - 1); |
| bits.clear(bitToFlip - firstSetBit - 1, bitToFlip); |
| bits.set(bitToFlip); |
| } |
| final BitSet copy = (BitSet) bits.clone(); |
| return new AbstractSet<E>() { |
| @Override |
| public boolean contains(Object o) { |
| Integer i = index.get(o); |
| return i != null && copy.get(i); |
| } |
| |
| @Override |
| public Iterator<E> iterator() { |
| return new AbstractIterator<E>() { |
| int i = -1; |
| |
| @Override |
| protected E computeNext() { |
| i = copy.nextSetBit(i + 1); |
| if (i == -1) { |
| return endOfData(); |
| } |
| return index.keySet().asList().get(i); |
| } |
| }; |
| } |
| |
| @Override |
| public int size() { |
| return size; |
| } |
| }; |
| } |
| }; |
| } |
| |
| @Override |
| public int size() { |
| return IntMath.binomial(index.size(), size); |
| } |
| |
| @Override |
| public String toString() { |
| return "Sets.combinations(" + index.keySet() + ", " + size + ")"; |
| } |
| }; |
| } |
| |
| } |