// Copyright 2010, 2011, 2012 The Apache Software Foundation // // 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 org.apache.tapestry5.func; import java.lang.reflect.Array; import java.util.*; /** * Abstract base class for implementations of {@link Flow}. Subclasses typically override some * methods for either efficiency, or for the concern they embrace. * * @since 5.2.0 */ abstract class AbstractFlow<T> implements Flow<T> { /** * Method limited to just AbstractFlow and its subclasses. Forces a resolve of the entire Flow, * and results in a mutable list of the values in the flow. */ protected List<T> toMutableList() { return toMutableList(this); } protected static <T> List<T> toMutableList(Flow<T> flow) { List<T> result = new ArrayList<T>(); for (T value : flow) { result.add(value); } return result; } @Override public Iterator<T> iterator() { return new Iterator<T>() { private Flow<T> current = AbstractFlow.this; @Override public boolean hasNext() { return !current.isEmpty(); } @Override public T next() { T next = current.first(); current = current.rest(); return next; } @Override public void remove() { throw new UnsupportedOperationException("Flows are immutable."); } }; } @Override public Flow<T> concat(Collection<? extends T> collection) { return concat(F.flow(collection)); } @Override public <V extends T> Flow<T> append(V... values) { return concat(F.flow(values)); } @Override public Flow<T> concat(Flow<? extends T> other) { return F.lazy(new LazyConcat<T>(this, other)); } /** Subclasses may override this for efficiency. */ @Override public Flow<T> each(Worker<? super T> worker) { assert worker != null; for (T value : this) { worker.work(value); } return this; } @Override public Flow<T> filter(Predicate<? super T> predicate) { assert predicate != null; return F.lazy(new LazyFilter<T>(predicate, this)); } @Override public <X> Flow<X> map(Mapper<T, X> mapper) { assert mapper != null; return F.lazy(new LazyMapper<T, X>(mapper, this)); } @Override public <X, Y> Flow<Y> map(Mapper2<T, X, Y> mapper, Flow<? extends X> flow) { assert mapper != null; assert flow != null; if (this.isEmpty() || flow.isEmpty()) return F.emptyFlow(); return F.lazy(new LazyMapper2<T, X, Y>(mapper, this, flow)); } @Override public <A> A reduce(Reducer<A, T> reducer, A initial) { assert reducer != null; A accumulator = initial; Flow<T> cursor = this; while (!cursor.isEmpty()) { accumulator = reducer.reduce(accumulator, cursor.first()); cursor = cursor.rest(); } return accumulator; } @Override public <X> Flow<X> mapcat(Mapper<T, Flow<X>> mapper) { Flow<Flow<X>> flows = map(mapper); if (flows.isEmpty()) return F.emptyFlow(); return flows.rest().reduce(new Reducer<Flow<X>, Flow<X>>() { @Override public Flow<X> reduce(Flow<X> accumulator, Flow<X> value) { return accumulator.concat(value); } }, flows.first()); } @Override public Flow<T> remove(Predicate<? super T> predicate) { assert predicate != null; return filter(F.not(predicate)); } @Override public Flow<T> reverse() { if (isEmpty()) return F.emptyFlow(); return new ArrayFlow<T>(this).reverse(); } @Override public Flow<T> sort() { if (isEmpty()) return F.emptyFlow(); return new ArrayFlow<T>(this).sort(); } @Override public Flow<T> sort(Comparator<T> comparator) { if (isEmpty()) return F.emptyFlow(); return new ArrayFlow<T>(this).sort(comparator); } @Override public List<T> toList() { if (isEmpty()) return Collections.emptyList(); return Collections.unmodifiableList(toMutableList()); } @Override @SuppressWarnings("unchecked") public T[] toArray(Class<T> type) { assert type != null; List<T> list = toMutableList(); Object array = Array.newInstance(type, list.size()); return list.toArray((T[]) array); } @Override public int count() { if (isEmpty()){ return 0; } int count = 0; for(Flow<T> flow = this; flow != null && !flow.isEmpty(); flow = flow.rest()){ count++; } return count; } @Override public Flow<T> take(int length) { return F.lazy(new LazyTake<T>(length, this)); } @Override public Flow<T> drop(int length) { assert length >= 0; if (length == 0) return this; return F.lazy(new LazyDrop<T>(length, this)); } @Override public Set<T> toSet() { Set<T> set = new HashSet<T>(); each(F.addToCollection(set)); return Collections.unmodifiableSet(set); } @Override public <X> ZippedFlow<T, X> zipWith(Flow<X> otherFlow) { assert otherFlow != null; Flow<Tuple<T, X>> tupleFlow = F.lazy(new LazyZip<T, X>(this, otherFlow)); return ZippedFlowImpl.create(tupleFlow); } @Override public Flow<T> removeNulls() { return remove(F.isNull()); } @Override public boolean isEmpty() { // TODO Auto-generated method stub return false; } @Override public T first() { // TODO Auto-generated method stub return null; } @Override public Flow<T> rest() { // TODO Auto-generated method stub return null; } @Override public Flow<T> interleave(Flow<T>... otherFlows) { List<Flow<T>> allFlows = new ArrayList<Flow<T>>(otherFlows.length + 1); allFlows.add(this); for (Flow<T> otherFlow : otherFlows) { allFlows.add(otherFlow); } return F.lazy(new Interleaver<T>(allFlows)); } }