/******************************************************************************* * Copyright 2014 Analog Devices, Inc. * * 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.analog.lyric.benchmarking.utils.doublespace; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.jdt.annotation.Nullable; import com.google.common.collect.Iterables; /** * Combines indexers to produce multidimensional indexes. */ public class JointIndexer { private static int computeCardinality(List<Indexer> indexers) { int result = 1; for (final Indexer indexer : indexers) { result *= indexer.getCardinality(); } return result; } private final int _cardinality; private final Set<int[]> _coordinatesSet = Collections.unmodifiableSet(new AbstractSet<int[]>() { @Override public Iterator<int[]> iterator() { return new CoordinatesIterator(); } @Override public int size() { return getCardinality(); } }); private final int[] _dimensions; private final List<Indexer> _indexers; /** * Constructs a joint indexer given an array of indexers. * * @param indexers * The individual indexers, one for each dimension to index. */ public JointIndexer(Indexer... indexers) { this(Arrays.asList(indexers)); } /** * Constructs a joint indexer given an Iterable of indexers. * * @param indexers * The individual indexers, one for each dimension to index. */ public JointIndexer(Iterable<Indexer> indexers) { _indexers = new ArrayList<Indexer>(); Iterables.addAll(_indexers, indexers); _cardinality = computeCardinality(_indexers); _dimensions = new int[_indexers.size()]; for (int i = 0; i < _dimensions.length; i++) { _dimensions[i] = _indexers.get(i).getCardinality(); } } /** * Gets a set of all joint indexes, representing the cross product of the * individual indexers. */ public Set<int[]> coordinatesSet() { return _coordinatesSet; } /** * Gets the quantity of joint indexes. */ public int getCardinality() { return _cardinality; } /** * Gets an array containing the cardinality of each of the dimensions. */ public int[] getDimensions() { return _dimensions.clone(); } /** * Gets the quantity of dimensions. */ public int getDimensionsCount() { return _dimensions.length; } /** * Gets the nth represented index. * * @param n * The zero-based position of the desired index. */ public Indexer getIndexer(int n) { return _indexers.get(n); } private class CoordinatesIterator implements Iterator<int[]> { private @Nullable int[] _current; private final List<Iterator<Integer>> _iterators; public CoordinatesIterator() { final int dimensions = getDimensionsCount(); _iterators = new ArrayList<Iterator<Integer>>(dimensions); for (int i = 0; i < dimensions; i++) { _iterators.add(_indexers.get(i).iterator()); } } @Override public boolean hasNext() { final int dimensions = getDimensionsCount(); for (int i = dimensions - 1; i >= 0; i--) { if (_iterators.get(i).hasNext()) { return true; } } return false; } @Override public int[] next() { final int dimensions = getDimensionsCount(); int[] current = _current; if (current == null) { current = _current = new int[dimensions]; for (int i = dimensions - 1; i >= 0; i--) { final Iterator<Integer> it = _iterators.get(i); if (it.hasNext()) { current[i] = it.next(); } } } else { for (int i = dimensions - 1; i >= 0; i--) { final Iterator<Integer> it = _iterators.get(i); if (it.hasNext()) { current[i] = it.next(); for (int j = i + 1; j < dimensions; j++) { final Iterator<Integer> it_j = _indexers.get(j).iterator(); _iterators.set(j, it_j); if (it_j.hasNext()) { current[j] = it_j.next(); } else { throw new InternalError(); } } break; } } } return current.clone(); } @Override public void remove() { throw new UnsupportedOperationException(); } } }