Separate SeqImpl out of Sequence, hiding it away in our impl package tree. Make

Sequence an interface.

We're going to change all of the places in Depot where we take a Collection as
an argument and take an Iterable instead. We invariably just turn the
Collection to an array, and we can just as well do that with an Iterable and be
more flexible about what we accept. Iterables.toArray has a fast path for
Iterable instances that also implement Collection, so we make SeqImpl implement
Collection under the hood even though we don't advertise that in the Sequence
interface because we don't want people using these as collections.

What we really want is something in between Iterable and Collection that knows
its size but otherwise does not allow mutation or containment checks.
This commit is contained in:
Michael Bayne
2010-02-25 06:30:12 +00:00
parent 503f3893cb
commit 950653960b
3 changed files with 117 additions and 63 deletions
@@ -60,6 +60,7 @@ import com.samskivert.depot.impl.SQLBuilder;
import com.samskivert.depot.impl.clause.DeleteClause;
import com.samskivert.depot.impl.clause.UpdateClause;
import com.samskivert.depot.impl.expression.ValueExp;
import com.samskivert.depot.impl.util.SeqImpl;
import static com.samskivert.depot.Log.log;
@@ -197,7 +198,7 @@ public abstract class DepotRepository
public <T extends PersistentRecord> List<T> loadAll (Collection<Key<T>> keys)
throws DatabaseException
{
return keys.isEmpty() ? Collections.emptyList() :
return keys.isEmpty() ? Collections.<T>emptyList() :
_ctx.invoke(new FindAllQuery.WithKeys<T>(_ctx, keys));
}
@@ -909,7 +910,7 @@ public abstract class DepotRepository
*/
protected <F, T> Sequence<T> map (Collection<F> source, Function<? super F, ? extends T> func)
{
return Sequence.map(source, func);
return new SeqImpl<F, T>(source, func);
}
protected PersistenceContext _ctx;
@@ -0,0 +1,105 @@
//
// $Id$
//
// Depot library - a Java relational persistence library
// Copyright (C) 2006-2009 Michael Bayne and Pär Winzell
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.depot.impl.util;
import java.lang.reflect.Array;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterators;
import com.samskivert.depot.util.Sequence;
/**
* An implementation of {@link Sequence} which secretly implements {@link Collection} so that
* {@link Iterables#toArray} can efficiently turn it into an array. We use {@link
* Iterables#toArray} in various places in Depot, so we prefer to enable such efficience.
*/
public class SeqImpl<F, T> extends AbstractCollection<T> implements Sequence<T>
{
public SeqImpl (Collection<F> source, Function<? super F, ? extends T> func)
{
Preconditions.checkNotNull(source);
Preconditions.checkNotNull(func);
_source = source;
_func = func;
}
// from interface Sequence<T> and Collection<T>
public Iterator<T> iterator ()
{
return Iterators.transform(_source.iterator(), _func);
}
// from interface Sequence<T> and Collection<T>
public int size ()
{
return _source.size();
}
// from interface Sequence<T> and Collection<T>
public boolean isEmpty ()
{
return _source.isEmpty();
}
// from interface Sequence<T>
public ArrayList<T> toList ()
{
return copyInto(new ArrayList<T>(_source.size()));
}
// from interface Sequence<T>
public HashSet<T> toSet ()
{
return copyInto(new HashSet<T>(_source.size()));
}
// from interface Sequence<T>
public T[] toArray (Class<T> clazz)
// In a perfect world this would be <S super T> S[] toArray (Class<S> clazz)
{
@SuppressWarnings("unchecked")
T[] array = (T[]) Array.newInstance(clazz, _source.size());
int index = 0;
for (F elem : _source) {
array[index++] = _func.apply(elem);
}
return array;
}
protected <C extends Collection<T>> C copyInto (C coll)
{
for (F elem : _source) {
coll.add(_func.apply(elem));
}
return coll;
}
protected final Collection<F> _source;
protected final Function<? super F, ? extends T> _func;
}
@@ -20,16 +20,11 @@
package com.samskivert.depot.util;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterators;
/**
* Provides read-only access to a sequence of elements. Note that these elements will generally be
@@ -38,78 +33,31 @@ import com.google.common.collect.Iterators;
* #toList} to convert the sequence to concrete list to avoid repeated application of the
* conversion function on elements of the sequence.
*/
public abstract class Sequence<T> implements Iterable<T>
public interface Sequence<T> extends Iterable<T>
{
/**
* Applies the supplied mapping function to the elements in the supplied collection, returning
* a lazily created read-only view of the mapped elements.
*/
public static <F, T> Sequence<T> map (final Collection<F> source,
final Function<? super F, ? extends T> func)
{
Preconditions.checkNotNull(source);
Preconditions.checkNotNull(func);
return new Sequence<T>() {
public Iterator<T> iterator () {
return Iterators.transform(source.iterator(), func);
}
public int size () {
return source.size();
}
public boolean isEmpty () {
return source.isEmpty();
}
public ArrayList<T> toList () {
return copyInto(new ArrayList<T>(source.size()));
}
public HashSet<T> toSet () {
return copyInto(new HashSet<T>(source.size()));
}
// In a perfect world this would be <S super T> S[] toArray (Class<S> clazz)
public T[] toArray (Class<T> clazz) {
@SuppressWarnings("unchecked")
T[] array = (T[]) Array.newInstance(clazz, source.size());
int index = 0;
for (F elem : source) {
array[index++] = func.apply(elem);
}
return array;
}
protected <C extends Collection<T>> C copyInto (C coll) {
for (F elem : source) {
coll.add(func.apply(elem));
}
return coll;
}
};
}
// from interface Iterable
public abstract Iterator<T> iterator ();
/**
* Returns the number of elements in this sequence.
*/
public abstract int size ();
int size ();
/**
* Returns true if this sequence is empty, false if it contains at least one element.
*/
public abstract boolean isEmpty ();
boolean isEmpty ();
/**
* Converts this sequence into an ArrayList.
* Converts this sequence into an {@link ArrayList}.
*/
public abstract ArrayList<T> toList ();
ArrayList<T> toList ();
/**
* Converts this sequence into a HashSet.
* Converts this sequence into a {@link HashSet}.
*/
public abstract HashSet<T> toSet ();
HashSet<T> toSet ();
/**
* Converts this sequence into an array.
* I wish this were <S super T> S[] toArray (Class<S> clazz);
*/
public abstract T[] toArray (Class<T> clazz);
T[] toArray (Class<T> clazz);
// Ray wishes this were <S super T> S[] toArray (Class<S> clazz);
}