com.analog.lyric.benchmarking.utils.doublespace.JointIndexer.java Source code

Java tutorial

Introduction

Here is the source code for com.analog.lyric.benchmarking.utils.doublespace.JointIndexer.java

Source

/*******************************************************************************
 *   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();
        }

    }

}