| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.flink.api.common.operators.util; |
| |
| import org.apache.flink.annotation.Internal; |
| |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| |
| /** Immutable unordered collection of fields IDs. */ |
| @Internal |
| public class FieldSet implements Iterable<Integer> { |
| |
| public static final FieldSet EMPTY_SET = new FieldSet(); |
| |
| protected final Collection<Integer> collection; |
| |
| // -------------------------------------------------------------------------------------------- |
| |
| /** Creates a new empty set of fields. */ |
| public FieldSet() { |
| this.collection = Collections.emptySet(); |
| } |
| |
| /** |
| * Creates a set with one field. |
| * |
| * @param fieldID The id of the field. |
| */ |
| public FieldSet(Integer fieldID) { |
| if (fieldID == null) { |
| throw new IllegalArgumentException("Field ID must not be null."); |
| } |
| |
| this.collection = Collections.singleton(fieldID); |
| } |
| |
| /** |
| * Creates a set with the given fields. |
| * |
| * @param fieldIDs The IDs of the fields. |
| */ |
| public FieldSet(int... fieldIDs) { |
| if (fieldIDs == null || fieldIDs.length == 0) { |
| this.collection = Collections.emptySet(); |
| } else { |
| HashSet<Integer> set = new HashSet<Integer>(2 * fieldIDs.length); |
| for (int i = 0; i < fieldIDs.length; i++) { |
| set.add(fieldIDs[i]); |
| } |
| |
| this.collection = Collections.unmodifiableSet(set); |
| } |
| } |
| |
| /** |
| * Creates a set with the given fields. |
| * |
| * @param fieldIDs The IDs of the fields. |
| */ |
| public FieldSet(int[] fieldIDs, boolean marker) { |
| if (fieldIDs == null || fieldIDs.length == 0) { |
| this.collection = Collections.emptySet(); |
| } else { |
| HashSet<Integer> set = new HashSet<Integer>(2 * fieldIDs.length); |
| for (int i = 0; i < fieldIDs.length; i++) { |
| set.add(fieldIDs[i]); |
| } |
| |
| this.collection = Collections.unmodifiableSet(set); |
| } |
| } |
| |
| protected FieldSet(Collection<Integer> fields) { |
| this.collection = fields; |
| } |
| |
| /** |
| * @param fieldSet The first part of the new set, NOT NULL! |
| * @param fieldID The ID to be added, NOT NULL! |
| */ |
| private FieldSet(FieldSet fieldSet, Integer fieldID) { |
| if (fieldSet.size() == 0) { |
| this.collection = Collections.singleton(fieldID); |
| } else { |
| HashSet<Integer> set = new HashSet<Integer>(2 * (fieldSet.collection.size() + 1)); |
| set.addAll(fieldSet.collection); |
| set.add(fieldID); |
| this.collection = Collections.unmodifiableSet(set); |
| } |
| } |
| |
| private FieldSet(FieldSet fieldSet, int... fieldIDs) { |
| if (fieldIDs == null || fieldIDs.length == 0) { |
| this.collection = fieldSet.collection; |
| } else { |
| HashSet<Integer> set = |
| new HashSet<Integer>(2 * (fieldSet.collection.size() + fieldIDs.length)); |
| set.addAll(fieldSet.collection); |
| |
| for (int i = 0; i < fieldIDs.length; i++) { |
| set.add(fieldIDs[i]); |
| } |
| |
| this.collection = Collections.unmodifiableSet(set); |
| } |
| } |
| |
| private FieldSet(FieldSet fieldSet1, FieldSet fieldSet2) { |
| if (fieldSet2.size() == 0) { |
| this.collection = fieldSet1.collection; |
| } else if (fieldSet1.size() == 0) { |
| this.collection = fieldSet2.collection; |
| } else { |
| HashSet<Integer> set = new HashSet<Integer>(2 * (fieldSet1.size() + fieldSet2.size())); |
| set.addAll(fieldSet1.collection); |
| set.addAll(fieldSet2.collection); |
| this.collection = Collections.unmodifiableSet(set); |
| } |
| } |
| |
| // -------------------------------------------------------------------------------------------- |
| |
| public FieldSet addField(Integer fieldID) { |
| if (fieldID == null) { |
| throw new IllegalArgumentException("Field ID must not be null."); |
| } |
| return new FieldSet(this, fieldID); |
| } |
| |
| public FieldSet addFields(int... fieldIDs) { |
| return new FieldSet(this, fieldIDs); |
| } |
| |
| public FieldSet addFields(FieldSet set) { |
| if (set == null) { |
| throw new IllegalArgumentException("FieldSet to add must not be null."); |
| } |
| |
| if (set.size() == 0) { |
| return this; |
| } else if (this.size() == 0) { |
| return set; |
| } else { |
| return new FieldSet(this, set); |
| } |
| } |
| |
| public boolean contains(Integer columnIndex) { |
| return this.collection.contains(columnIndex); |
| } |
| |
| public int size() { |
| return this.collection.size(); |
| } |
| |
| @Override |
| public Iterator<Integer> iterator() { |
| return this.collection.iterator(); |
| } |
| |
| /** |
| * Turns the FieldSet into an ordered FieldList. |
| * |
| * @return An ordered FieldList. |
| */ |
| public FieldList toFieldList() { |
| int[] pos = toArray(); |
| Arrays.sort(pos); |
| return new FieldList(pos); |
| } |
| |
| /** |
| * Transforms the field set into an array of field IDs. Whether the IDs are ordered or unordered |
| * depends on the specific subclass of the field set. |
| * |
| * @return An array of all contained field IDs. |
| */ |
| public int[] toArray() { |
| int[] a = new int[this.collection.size()]; |
| int i = 0; |
| for (int col : this.collection) { |
| a[i++] = col; |
| } |
| return a; |
| } |
| |
| // -------------------------------------------------------------------------------------------- |
| |
| /** |
| * Checks if the given set of fields is a valid subset of this set of fields. For unordered |
| * sets, this is the case if all of the given set's fields are also part of this field. |
| * |
| * <p>Subclasses that describe field sets where the field order matters must override this |
| * method to implement a field ordering sensitive check. |
| * |
| * @param set The set that is a candidate subset. |
| * @return True, if the given set is a subset of this set, false otherwise. |
| */ |
| public boolean isValidSubset(FieldSet set) { |
| if (set.size() > size()) { |
| return false; |
| } |
| for (Integer i : set) { |
| if (!contains(i)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| // -------------------------------------------------------------------------------------------- |
| |
| @Override |
| public int hashCode() { |
| return this.collection.hashCode(); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj == null) { |
| return false; |
| } |
| if (obj instanceof FieldSet) { |
| return this.collection.equals(((FieldSet) obj).collection); |
| } else { |
| return false; |
| } |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder bld = new StringBuilder(); |
| bld.append(getDescriptionPrefix()); |
| for (Integer i : this.collection) { |
| bld.append(i); |
| bld.append(','); |
| bld.append(' '); |
| } |
| if (this.collection.size() > 0) { |
| bld.setLength(bld.length() - 2); |
| } |
| bld.append(getDescriptionSuffix()); |
| return bld.toString(); |
| } |
| |
| /** |
| * Since instances of FieldSet are strictly immutable, this method does not actually clone, but |
| * it only returns the original instance. |
| * |
| * @return This objects reference, unmodified. |
| */ |
| public FieldSet clone() { |
| return this; |
| } |
| |
| // -------------------------------------------------------------------------------------------- |
| |
| protected String getDescriptionPrefix() { |
| return "("; |
| } |
| |
| protected String getDescriptionSuffix() { |
| return ")"; |
| } |
| } |