Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API: Align CharSequenceSet impl with Data/DeleteFileSet #11322

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 24 additions & 154 deletions api/src/main/java/org/apache/iceberg/util/CharSequenceSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,183 +18,53 @@
*/
package org.apache.iceberg.util;

import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
import org.apache.iceberg.relocated.com.google.common.collect.Iterables;
import org.apache.iceberg.relocated.com.google.common.collect.Iterators;
import org.apache.iceberg.relocated.com.google.common.collect.Sets;
import org.apache.iceberg.relocated.com.google.common.collect.Streams;

public class CharSequenceSet implements Set<CharSequence>, Serializable {
public class CharSequenceSet extends WrapperSet<CharSequence> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be easier to just look at the resulting file instead of the diff

private static final ThreadLocal<CharSequenceWrapper> WRAPPERS =
ThreadLocal.withInitial(() -> CharSequenceWrapper.wrap(null));

public static CharSequenceSet of(Iterable<CharSequence> charSequences) {
return new CharSequenceSet(charSequences);
}

public static CharSequenceSet empty() {
return new CharSequenceSet(ImmutableList.of());
}

private final Set<CharSequenceWrapper> wrapperSet;

private CharSequenceSet(Iterable<CharSequence> charSequences) {
this.wrapperSet =
Sets.newHashSet(Iterables.transform(charSequences, CharSequenceWrapper::wrap));
private CharSequenceSet() {
// needed for serialization
}

@Override
public int size() {
return wrapperSet.size();
private CharSequenceSet(Iterable<? extends CharSequence> charSequences) {
super(
Iterables.transform(
charSequences,
obj -> {
Preconditions.checkNotNull(obj, "Invalid object: null");
return CharSequenceWrapper.wrap(obj);
}));
}

@Override
public boolean isEmpty() {
return wrapperSet.isEmpty();
public static CharSequenceSet of(Iterable<? extends CharSequence> charSequences) {
return new CharSequenceSet(charSequences);
}

@Override
public boolean contains(Object obj) {
if (obj instanceof CharSequence) {
CharSequenceWrapper wrapper = WRAPPERS.get();
boolean result = wrapperSet.contains(wrapper.set((CharSequence) obj));
wrapper.set(null); // don't hold a reference to the value
return result;
}
return false;
public static CharSequenceSet empty() {
return new CharSequenceSet();
}

@Override
public Iterator<CharSequence> iterator() {
return Iterators.transform(wrapperSet.iterator(), CharSequenceWrapper::get);
protected Wrapper<CharSequence> wrapper() {
return WRAPPERS.get();
}

@Override
public Object[] toArray() {
return Iterators.toArray(iterator(), CharSequence.class);
protected Wrapper<CharSequence> wrap(CharSequence file) {
return CharSequenceWrapper.wrap(file);
}

@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] destArray) {
int size = wrapperSet.size();
if (destArray.length < size) {
return (T[]) toArray();
}

Iterator<CharSequence> iter = iterator();
int ind = 0;
while (iter.hasNext()) {
destArray[ind] = (T) iter.next();
ind += 1;
}

if (destArray.length > size) {
destArray[size] = null;
}

return destArray;
protected Class<CharSequence> elementClass() {
return CharSequence.class;
}

@Override
public boolean add(CharSequence charSequence) {
return wrapperSet.add(CharSequenceWrapper.wrap(charSequence));
}

@Override
public boolean remove(Object obj) {
if (obj instanceof CharSequence) {
CharSequenceWrapper wrapper = WRAPPERS.get();
boolean result = wrapperSet.remove(wrapper.set((CharSequence) obj));
wrapper.set(null); // don't hold a reference to the value
return result;
}
return false;
}

@Override
@SuppressWarnings("CollectionUndefinedEquality")
public boolean containsAll(Collection<?> objects) {
if (objects != null) {
return Iterables.all(objects, this::contains);
}
return false;
}

@Override
public boolean addAll(Collection<? extends CharSequence> charSequences) {
if (charSequences != null) {
return Iterables.addAll(
wrapperSet, Iterables.transform(charSequences, CharSequenceWrapper::wrap));
}
return false;
}

@Override
public boolean retainAll(Collection<?> objects) {
if (objects != null) {
Set<CharSequenceWrapper> toRetain =
objects.stream()
.filter(CharSequence.class::isInstance)
.map(CharSequence.class::cast)
.map(CharSequenceWrapper::wrap)
.collect(Collectors.toSet());

return Iterables.retainAll(wrapperSet, toRetain);
}

return false;
}

@Override
@SuppressWarnings("CollectionUndefinedEquality")
public boolean removeAll(Collection<?> objects) {
if (objects != null) {
return objects.stream().filter(this::remove).count() != 0;
}

return false;
}

@Override
public void clear() {
wrapperSet.clear();
}

@SuppressWarnings("CollectionUndefinedEquality")
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (!(other instanceof Set)) {
return false;
}

Set<?> that = (Set<?>) other;

if (size() != that.size()) {
return false;
}

try {
return containsAll(that);
} catch (ClassCastException | NullPointerException unused) {
return false;
}
}

@Override
public int hashCode() {
return wrapperSet.stream().mapToInt(CharSequenceWrapper::hashCode).sum();
}

@Override
public String toString() {
return Streams.stream(iterator()).collect(Collectors.joining("CharSequenceSet({", ", ", "})"));
// method is needed to not break API compatibility
return super.add(charSequence);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@
*/
package org.apache.iceberg.util;

import java.io.Serializable;
import org.apache.iceberg.types.Comparators;
import org.apache.iceberg.types.JavaHashes;

/** Wrapper class to adapt CharSequence for use in maps and sets. */
public class CharSequenceWrapper implements CharSequence, Serializable {
public class CharSequenceWrapper implements CharSequence, WrapperSet.Wrapper<CharSequence> {
public static CharSequenceWrapper wrap(CharSequence seq) {
return new CharSequenceWrapper(seq);
}
Expand All @@ -39,13 +38,15 @@ private CharSequenceWrapper(CharSequence wrapped) {
this.wrapped = wrapped;
}

@Override
public CharSequenceWrapper set(CharSequence newWrapped) {
this.wrapped = newWrapped;
this.hashCode = 0;
this.hashIsZero = false;
return this;
}

@Override
public CharSequence get() {
return wrapped;
}
Expand Down
Loading