![JAR search and dependency download from the Maven repository](/logo.png)
io.vavr.collection.JavaConverters Maven / Gradle / Ivy
Show all versions of vavr Show documentation
/* __ __ __ __ __ ___
* \ \ / / \ \ / / __/
* \ \/ / /\ \ \/ / /
* \____/__/ \__\____/__/
*
* Copyright 2014-2019 Vavr, http://vavr.io
*
* 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 io.vavr.collection;
import java.io.Serializable;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* THIS CLASS IS INTENDED TO BE USED INTERNALLY ONLY!
*
* This helper class provides methods that return views on Java collections.
* The view creation and back conversion take O(1).
*
* @author Daniel Dietrich
*/
class JavaConverters {
private JavaConverters() {
}
@GwtIncompatible
static > ListView asJava(C seq, ChangePolicy changePolicy) {
return new ListView<>(seq, changePolicy.isMutable());
}
enum ChangePolicy {
IMMUTABLE, MUTABLE;
boolean isMutable() {
return this == MUTABLE;
}
}
// -- private view implementations
/**
* Encapsulates the access to delegate and performs mutability checks.
*
* @param The Vavr collection type
*/
private static abstract class HasDelegate> implements Serializable {
private static final long serialVersionUID = 1L;
private C delegate;
private final boolean mutable;
HasDelegate(C delegate, boolean mutable) {
this.delegate = delegate;
this.mutable = mutable;
}
protected boolean isMutable() {
return mutable;
}
C getDelegate() {
return delegate;
}
protected boolean setDelegateAndCheckChanged(Supplier delegate) {
ensureMutable();
final C previousDelegate = this.delegate;
final C newDelegate = delegate.get();
final boolean changed = newDelegate.size() != previousDelegate.size();
if (changed) {
this.delegate = newDelegate;
}
return changed;
}
protected void setDelegate(Supplier newDelegate) {
ensureMutable();
this.delegate = newDelegate.get();
}
protected void ensureMutable() {
if (!mutable) {
throw new UnsupportedOperationException();
}
}
}
@GwtIncompatible("reflection is not supported")
static class ListView> extends HasDelegate implements java.util.List {
private static final long serialVersionUID = 1L;
ListView(C delegate, boolean mutable) {
super(delegate, mutable);
}
@SuppressWarnings("unchecked")
@Override
public boolean add(T element) {
setDelegate(() -> (C) getDelegate().append(element));
return true;
}
@SuppressWarnings("unchecked")
@Override
public void add(int index, T element) {
setDelegate(() -> (C) getDelegate().insert(index, element));
}
@SuppressWarnings("unchecked")
@Override
public boolean addAll(Collection extends T> collection) {
Objects.requireNonNull(collection, "collection is null");
return setDelegateAndCheckChanged(() -> (C) getDelegate().appendAll(collection));
}
@SuppressWarnings("unchecked")
@Override
public boolean addAll(int index, Collection extends T> collection) {
Objects.requireNonNull(collection, "collection is null");
return setDelegateAndCheckChanged(() -> (C) getDelegate().insertAll(index, collection));
}
@SuppressWarnings("unchecked")
@Override
public void clear() {
// DEV-NOTE: acts like Java: works for empty immutable collections
if (isEmpty()) {
return;
}
setDelegate(() -> (C) getDelegate().take(0));
}
@Override
public boolean contains(Object obj) {
@SuppressWarnings("unchecked") final T that = (T) obj;
return getDelegate().contains(that);
}
@Override
public boolean containsAll(Collection> collection) {
Objects.requireNonNull(collection, "collection is null");
@SuppressWarnings("unchecked") final Collection that = (Collection) collection;
return getDelegate().containsAll(that);
}
@Override
public T get(int index) {
return getDelegate().get(index);
}
@Override
public int indexOf(Object obj) {
@SuppressWarnings("unchecked") final T that = (T) obj;
return getDelegate().indexOf(that);
}
@Override
public boolean isEmpty() {
return getDelegate().isEmpty();
}
@Override
public java.util.Iterator iterator() {
return new Iterator<>(this);
}
@Override
public int lastIndexOf(Object obj) {
@SuppressWarnings("unchecked") final T that = (T) obj;
return getDelegate().lastIndexOf(that);
}
@Override
public java.util.ListIterator listIterator() {
return new ListIterator<>(this, 0);
}
@Override
public java.util.ListIterator listIterator(int index) {
return new ListIterator<>(this, index);
}
@SuppressWarnings("unchecked")
@Override
public T remove(int index) {
return setDelegateAndGetPreviousElement(index, () -> (C) getDelegate().removeAt(index));
}
@SuppressWarnings("unchecked")
@Override
public boolean remove(Object obj) {
final T that = (T) obj;
return setDelegateAndCheckChanged(() -> (C) getDelegate().remove(that));
}
@SuppressWarnings("unchecked")
@Override
public boolean removeAll(Collection> collection) {
Objects.requireNonNull(collection, "collection is null");
@SuppressWarnings("unchecked") final Collection that = (Collection) collection;
return setDelegateAndCheckChanged(() -> (C) getDelegate().removeAll(that));
}
@SuppressWarnings("unchecked")
@Override
public boolean retainAll(Collection> collection) {
Objects.requireNonNull(collection, "collection is null");
@SuppressWarnings("unchecked") final Collection that = (Collection) collection;
return setDelegateAndCheckChanged(() -> (C) getDelegate().retainAll(that));
}
@SuppressWarnings("unchecked")
@Override
public T set(int index, T element) {
return setDelegateAndGetPreviousElement(index, () -> (C) getDelegate().update(index, element));
}
@Override
public int size() {
return getDelegate().size();
}
@SuppressWarnings("unchecked")
@Override
public void sort(Comparator super T> comparator) {
Objects.requireNonNull(comparator, "comparator is null");
if (isEmpty()) {
return;
}
setDelegate(() -> (C) getDelegate().sorted(comparator));
}
@Override
public java.util.List subList(int fromIndex, int toIndex) {
return new ListView<>(getDelegate().subSequence(fromIndex, toIndex), isMutable());
}
@Override
public Object[] toArray() {
return getDelegate().toJavaArray();
}
@SuppressWarnings("unchecked")
@Override
public U[] toArray(U[] array) {
Objects.requireNonNull(array, "array is null");
final U[] target;
final C delegate = getDelegate();
final int length = delegate.length();
if (array.length < length) {
final Class extends Object[]> newType = array.getClass();
target = (newType == Object[].class)
? (U[]) new Object[length]
: (U[]) java.lang.reflect.Array.newInstance(newType.getComponentType(), length);
} else {
if (array.length > length) {
array[length] = null;
}
target = array;
}
final java.util.Iterator iter = delegate.iterator();
for (int i = 0; i < length; i++) {
target[i] = (U) iter.next();
}
return target;
}
// -- Object.*
@Override
public boolean equals(Object o) {
return o == this || o instanceof java.util.List && Collections.areEqual(getDelegate(), (java.util.List>) o);
}
@Override
public int hashCode() {
// DEV-NOTE: Ensures that hashCode calculation is stable, regardless of delegate.hashCode()
return Collections.hashOrdered(getDelegate());
}
@Override
public String toString() {
return getDelegate().mkString("[", ", ", "]");
}
// -- private helpers
private T setDelegateAndGetPreviousElement(int index, Supplier delegate) {
ensureMutable();
final T previousElement = getDelegate().get(index);
setDelegate(delegate);
return previousElement;
}
// DEV-NOTE: Iterator is intentionally not Serializable
private static class Iterator> implements java.util.Iterator {
ListView list;
int expectedSize;
int nextIndex = 0;
int lastIndex = -1;
Iterator(ListView list) {
this.list = list;
expectedSize = list.size();
}
@Override
public boolean hasNext() {
return nextIndex != list.size();
}
@Override
public T next() {
checkForComodification();
if (nextIndex >= list.size()) {
throw new NoSuchElementException();
}
try {
return list.get(lastIndex = nextIndex++);
} catch (IndexOutOfBoundsException x) {
throw new ConcurrentModificationException();
}
}
@Override
public void remove() {
list.ensureMutable();
if (lastIndex < 0) {
throw new IllegalStateException();
}
checkForComodification();
try {
list.remove(nextIndex = lastIndex);
lastIndex = -1;
expectedSize = list.size();
} catch (IndexOutOfBoundsException x) {
throw new ConcurrentModificationException();
}
}
@Override
public void forEachRemaining(Consumer super T> consumer) {
Objects.requireNonNull(consumer, "consumer is null");
checkForComodification();
if (nextIndex >= list.size()) {
return;
}
int index = nextIndex;
// DEV-NOTE: intentionally not using hasNext() and next() in order not to modify internal state
while (expectedSize == list.size() && index < expectedSize) {
consumer.accept(list.get(index++));
}
nextIndex = index;
lastIndex = index - 1;
checkForComodification();
}
final void checkForComodification() {
if (expectedSize != list.size()) {
throw new ConcurrentModificationException();
}
}
}
// DEV-NOTE: ListIterator is intentionally not Serializable
private static class ListIterator> extends ListView.Iterator implements java.util.ListIterator {
ListIterator(ListView list, int index) {
super(list);
if (index < 0 || index > list.size()) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + list.size());
}
this.nextIndex = index;
}
@Override
public boolean hasPrevious() {
return nextIndex != 0;
}
@Override
public int nextIndex() {
return nextIndex;
}
@Override
public int previousIndex() {
return nextIndex - 1;
}
@Override
public T previous() {
checkForComodification();
final int index = nextIndex - 1;
if (index < 0) {
throw new NoSuchElementException();
}
if (index >= list.size()) {
throw new ConcurrentModificationException();
}
try {
final T element = list.get(index);
// DEV-NOTE: intentionally updating indices _after_ reading the element. This makes a difference in case of a concurrent modification.
lastIndex = nextIndex = index;
return element;
} catch (IndexOutOfBoundsException x) {
throw new ConcurrentModificationException();
}
}
@Override
public void set(T element) {
list.ensureMutable();
if (lastIndex < 0) {
throw new IllegalStateException();
}
checkForComodification();
try {
list.set(lastIndex, element);
} catch (IndexOutOfBoundsException x) {
throw new ConcurrentModificationException();
}
}
@Override
public void add(T element) {
list.ensureMutable();
checkForComodification();
try {
final int index = nextIndex;
list.add(index, element);
// DEV-NOTE: intentionally increasing nextIndex _after_ adding the element. This makes a difference in case of a concurrent modification.
nextIndex = index + 1;
lastIndex = -1;
expectedSize = list.size();
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
}
}