/* * Copyright 2008-2016 the original author or authors. * * 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 com.nominanuda.zen.seq; import static com.nominanuda.zen.seq.Seq.SEQ; import java.util.Collection; import java.util.Iterator; import com.nominanuda.zen.stereotype.Value; /** * an {@link Iterable} with {@link Collection#size()} * to create an instance just {@link ReadOnlyCollection#size()} and {@link ReadOnlyCollection#iterator()} * need to be implemented. That is, the rest of the collection interface is implemented by default methods. * Also static factory methods are provided for wrapping {@link Iterable}s and {@link Iterator}s that miss the size. * @param <E> */ public interface ReadOnlyCollection<E> extends Collection<E> { @Override int size(); @Override Iterator<E> iterator(); @Override default boolean isEmpty() { return ! iterator().hasNext(); } @Override default boolean containsAll(Collection<?> c) { for(Object o : c) { if(contains(o)) { return true; } } return false; } @Override default boolean contains(Object o) { Iterator<E> i = iterator(); while(i.hasNext()) { if(Value.nullSafeEquals(o, i.next())) { return true; } } return false; } @Override default Object[] toArray() { Object[] result = new Object[size()]; SEQ.writeToArray(this, result); return result; } default <X> X[] toTypedArray(Class<X> elementType) { return SEQ.toTypedArray(this, elementType); } @Override @SuppressWarnings("unchecked") default <X> X[] toArray(X[] a) { int len = size(); if(a.length < len) { return (X[])toTypedArray(a.getClass().getComponentType()); } else { SEQ.writeToArray(this, a); return a; } } @Override default boolean add(E e) { throw new UnsupportedOperationException("read-only collection"); } @Override default boolean remove(Object o) { throw new UnsupportedOperationException("read-only collection"); } @Override default boolean addAll(Collection<? extends E> c) { throw new UnsupportedOperationException("read-only collection"); } @Override default boolean removeAll(Collection<?> c) { throw new UnsupportedOperationException("read-only collection"); } @Override default boolean retainAll(Collection<?> c) { throw new UnsupportedOperationException("read-only collection"); } @Override default void clear() { throw new UnsupportedOperationException("read-only collection"); } public static <T> ReadOnlyCollection<T> wrap(int len, Iterable<T> iter) { return new BoundIterableImpl<T>(len, iter); } public static <T> ReadOnlyCollection<T> wrap(Collection<T> coll) { return new BoundIterableImpl<T>(coll.size(), coll); } public static <T> ReadOnlyCollection<T> wrap(Iterable<T> iter) { return wrap(iter.iterator()); } public static <T> ReadOnlyCollection<T> wrap(Iterator<T> itr) { final LazyCopyIterator<T> i = new LazyCopyIterator<>(itr); boolean first = true; return new ReadOnlyCollection<T>() { private int len = -1; @Override public LazyCopyIterator<T> iterator() { return first ? i : i.copy(); } @Override public int size() { if(len < 0) { len = i.toList().size(); } return len; } @Override public boolean isEmpty() { return i.isEmpty(); } }; } public static class BoundIterableImpl<T> implements ReadOnlyCollection<T> { private final int len; private final Iterable<T> iter; public BoundIterableImpl(int len, Iterable<T> iter) { this.len = len; this.iter = iter; } @Override public Iterator<T> iterator() { return iter.iterator(); } @Override public int size() { return len; } @Override public boolean isEmpty() { return len == 0; } } }