/** * PermissionsEx * Copyright (C) zml and PermissionsEx contributors * * 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 ninja.leaping.permissionsex.util; import com.google.common.collect.AbstractIterator; import com.google.common.collect.ImmutableSet; import com.google.common.collect.PeekingIterator; import java.util.Iterator; import java.util.Set; /** * An iterable class that provides all combinations of any of a given set of values * The algorithm used is a version of Algorithm T in section 7.2.1.3 of Knuth's The Art of Computer Programming, * modified to function as an Iterator. This implementation also begins with the original set, * and accepts the empty set as an input (unlike the original algorithm, only defined for n>0 where n is the length of the set). */ public class Combinations<T> implements Iterable<Set<T>> { private final T[] items; @SuppressWarnings("unchecked") private Combinations(Set<T> items) { this.items = (T[]) items.toArray(); } public static <T> Combinations<T> of(Set<T> items) { return new Combinations<>(ImmutableSet.copyOf(items)); } private class CombinationIterator extends AbstractIterator<Set<T>> implements PeekingIterator<Set<T>> { private int j; private int currentLength = items.length; private int[] c; // Reuse the same array -- it isn't getting any bigger private void init() { for (j = 0; j < currentLength; ++j) { c[j] = j; } c[currentLength] = items.length; c[currentLength + 1] = 0; j = currentLength - 1; } @Override protected Set<T> computeNext() { if (currentLength < 0) { return endOfData(); } if (c == null) { c = new int[currentLength + 2]; init(); } else { if (c[0] + 1 < c[1]) { c[0] = c[0] + 1; } else { int x; j = 1; do { ++j; c[j - 2] = j - 2; x = c[j - 1] + 1; } while (x == c[j]); if (j > currentLength) { currentLength--; init(); } else { c[j - 1] = x; j--; } } } if (currentLength == 0) { --currentLength; return ImmutableSet.of(); } else { ImmutableSet.Builder<T> build = ImmutableSet.builder(); for (int i = 0; i < currentLength; ++i) { build.add(items[c[i]]); } return build.build(); } } } @Override public Iterator<Set<T>> iterator() { return new CombinationIterator(); } }