/* * #%L * gitools-core * %% * Copyright (C) 2013 Universitat Pompeu Fabra - Biomedical Genomics group * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ package org.gitools.matrix.model.iterable; import org.gitools.api.matrix.IMatrix; import org.gitools.api.matrix.IMatrixDimension; import org.gitools.api.matrix.IMatrixPosition; import org.gitools.api.matrix.MatrixDimensionKey; import org.gitools.matrix.model.MatrixPosition; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; public abstract class AbstractSourceIterable<T> extends AbstractIterable<T> { private long size = 1; private MatrixPosition mainPosition; // Thread safe position private ThreadLocal<MatrixPosition> position = new ThreadLocal<MatrixPosition>() { @Override protected MatrixPosition initialValue() { return new MatrixPosition(mainPosition); } }; private IMatrixDimension[] iterateDimensions; protected AbstractSourceIterable(MatrixPosition position, IMatrixDimension... iterateDimensions) { // Iterate all dimensions if any dimension is set if (iterateDimensions.length == 0) { IMatrix matrix = position.getMatrix(); MatrixDimensionKey[] keys = matrix.getDimensionKeys(); iterateDimensions = new IMatrixDimension[keys.length]; for (int d=0; d < keys.length; d++) { iterateDimensions[d] = matrix.getDimension(keys[d]); } } this.mainPosition = position; this.iterateDimensions = iterateDimensions; for (IMatrixDimension dimension : iterateDimensions) { size *= dimension.size(); } } public IMatrix getMatrix() { return mainPosition.getMatrix(); } @Override public IMatrixPosition getPosition() { return position.get(); } @Override public long size() { return size; } @Override public Iterator<T> iterator() { return new ValueIterator(); } protected abstract T getValue(IMatrixPosition position); private class ValueIterator implements Iterator<T> { // Current position private String[] identifiers; // Iteration status private int activeDimension; private List<Iterator<String>> iterators; private boolean hasNext; private ValueIterator() { int length = iterateDimensions.length; this.identifiers = new String[length]; this.iterators = new ArrayList<>(length); try { // Iterate to the first position for (int d = 0; d < iterateDimensions.length; d++) { Iterator<String> iterator = iterateDimensions[d].iterator(); this.iterators.add(iterator); this.identifiers[d] = iterator.next(); this.activeDimension = d; } hasNext = true; } catch (NoSuchElementException e) { // If there is an empty iterate dimension it's impossible to iterate. hasNext = false; } } @Override public synchronized boolean hasNext() { return this.hasNext; } @Override public synchronized T next() { return getValue(nextPosition()); } private synchronized IMatrixPosition nextPosition() { // Return current position IMatrixPosition position = getPosition(); for (int d=0; d < iterateDimensions.length; d++) { position.set(iterateDimensions[d], identifiers[d]); } // Iterate to next position while(activeDimension >= 0) { Iterator<String> activeIterator = iterators.get(activeDimension); if (activeIterator.hasNext()) { identifiers[activeDimension] = activeIterator.next(); if (activeDimension == iterateDimensions.length - 1) { return position; } activeDimension++; } else { iterators.set(activeDimension, iterateDimensions[activeDimension].iterator()); activeDimension--; } } hasNext = false; return position; } @Override public void remove() { throw new UnsupportedOperationException("Read only iterator"); } } }