com.google.uzaygezen.core.Pow2LengthBitSetRangeFactory.java Source code

Java tutorial

Introduction

Here is the source code for com.google.uzaygezen.core.Pow2LengthBitSetRangeFactory.java

Source

/*
 * Copyright (C) 2008 Google 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.google.uzaygezen.core;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.primitives.Ints;

/**
 * Transforms a {@link MapNode} tree into a {@link java.util.Map} which contains
 * as keys all paths from the root node to all nodes. The path from root to root
 * is empty and is present in the produced map iff the tree is not empty(i.e.,
 * its root is not null). The values in the map are pairs of the original tree
 * node's value and a flag indicating if the node is a leaf node.
 * 
 * @author Daniel Aioanei
 * 
 * @param <V> value type
 */
public class Pow2LengthBitSetRangeFactory<V>
        implements Function<MapNode<BitVector, V>, Map<Pow2LengthBitSetRange, NodeValue<V>>> {

    private final int[] elementLengths;
    private final int[] elementLengthSums;

    /**
     * @param cardinality must have the bit cardinality for each iteration. The
     * size of the list must be {@code mMax}.
     */
    private Pow2LengthBitSetRangeFactory(List<Integer> cardinality) {
        this.elementLengths = Ints.toArray(cardinality);
        elementLengthSums = new int[elementLengths.length];
        for (int i = 0; i < elementLengths.length; ++i) {
            elementLengthSums[i] = (i == 0 ? 0 : elementLengthSums[i - 1]) + elementLengths[i];
        }
    }

    public static <V> Pow2LengthBitSetRangeFactory<V> create(List<Integer> elementLengths) {
        return new Pow2LengthBitSetRangeFactory<V>(elementLengths);
    }

    @Override
    public Map<Pow2LengthBitSetRange, NodeValue<V>> apply(MapNode<BitVector, V> from) {
        if (from == null) {
            return ImmutableMap.of();
        }
        Deque<MapNode<BitVector, V>> inputStack = new ArrayDeque<MapNode<BitVector, V>>();
        Deque<BitVectorWithIterationLevelAndValue> outputStack = new ArrayDeque<BitVectorWithIterationLevelAndValue>();
        inputStack.push(from);
        int n = elementLengthSums.length;
        int bitCount = n == 0 ? 0 : elementLengthSums[n - 1];
        outputStack.push(new BitVectorWithIterationLevelAndValue(BitVectorFactories.OPTIMAL.apply(bitCount), n,
                from.getValue()));
        MapNode<BitVector, V> inputNode;
        Map<Pow2LengthBitSetRange, NodeValue<V>> map = Maps.newHashMap();
        while ((inputNode = inputStack.poll()) != null) {
            BitVectorWithIterationLevelAndValue outputElement = outputStack.poll();
            map.put(new Pow2LengthBitSetRange(outputElement.bitVector,
                    outputElement.level == 0 ? 0 : elementLengthSums[outputElement.level - 1]),
                    NodeValue.of(outputElement.value, inputNode.getChildren().isEmpty()));
            Preconditions.checkArgument(
                    outputElement.level > 0 || (inputNode.getChildren().isEmpty() && outputElement.level >= 0));
            for (Entry<BitVector, MapNode<BitVector, V>> entry : inputNode.getChildren().entrySet()) {
                inputStack.push(entry.getValue());
                BitVector childBitSet = outputElement.bitVector.clone();
                BitVector key = entry.getKey();
                for (int i = key.size() == 0 ? -1 : key.nextSetBit(0); i != -1; i = i == key.size() - 1 ? -1
                        : key.nextSetBit(i + 1)) {
                    int bitIndex = (outputElement.level == 1 ? 0 : elementLengthSums[outputElement.level - 2]) + i;
                    Preconditions.checkState(bitIndex < bitCount, "bitIndex is too high");
                    Preconditions.checkState(!childBitSet.get(bitIndex));
                    childBitSet.set(bitIndex);
                }
                outputStack.push(new BitVectorWithIterationLevelAndValue(childBitSet, outputElement.level - 1,
                        entry.getValue().getValue()));
            }
        }
        Preconditions.checkState(outputStack.isEmpty() & !map.isEmpty());
        return map;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }

    private class BitVectorWithIterationLevelAndValue {

        private final BitVector bitVector;
        private final int level;
        private final V value;

        public BitVectorWithIterationLevelAndValue(BitVector bitSet, int level, V value) {
            this.bitVector = bitSet;
            this.level = level;
            this.value = value;
        }

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
        }
    }
}