/* * Copyright 2000-2014 JetBrains s.r.o. * * 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.intellij.vcs.log.graph.utils.impl; import com.intellij.vcs.log.graph.utils.Flags; import com.intellij.vcs.log.graph.utils.IntToIntMap; import org.jetbrains.annotations.NotNull; public class PermanentListIntToIntMap extends AbstractIntToIntMap implements IntToIntMap { public static final int DEFAULT_BLOCK_SIZE = 30; @NotNull public static IntToIntMap newInstance(@NotNull Flags visibleIndexes, int shortSize) { return newInstance(visibleIndexes, shortSize, DEFAULT_BLOCK_SIZE); } @NotNull public static IntToIntMap newInstance(@NotNull final Flags visibleIndexes, int shortSize, int blockSize) { if (shortSize < 0) throw new NegativeArraySizeException("shortSize < 0: " + shortSize); if (shortSize == 0) return createEmptyIntToIntMap(visibleIndexes); int[] strongShortIndexes = new int[(shortSize - 1) / blockSize + 1]; int currentShortIndex = -1; for (int longIndex = 0; longIndex < visibleIndexes.size(); longIndex++) { if (visibleIndexes.get(longIndex)) { currentShortIndex++; if (currentShortIndex % blockSize == 0) strongShortIndexes[currentShortIndex / blockSize] = longIndex; } } return new PermanentListIntToIntMap(visibleIndexes, shortSize, blockSize, strongShortIndexes); } @NotNull private static IntToIntMap createEmptyIntToIntMap(@NotNull final Flags visibleIndexes) { return new IntToIntMap() { @Override public int shortSize() { return 0; } @Override public int longSize() { return visibleIndexes.size(); } @Override public int getLongIndex(int shortIndex) { return 0; } @Override public int getShortIndex(int longIndex) { return 0; } }; } @NotNull private final Flags myVisibleIndexes; private final int myLongSize; private final int myShortSize; private final int myBlockSize; @NotNull private final int[] myStrongShortIndexes; private PermanentListIntToIntMap(@NotNull Flags visibleIndexes, int shortSize, int blockSize, @NotNull int[] strongShortIndexes) { myVisibleIndexes = visibleIndexes; myLongSize = visibleIndexes.size(); myShortSize = shortSize; myBlockSize = blockSize; myStrongShortIndexes = strongShortIndexes; } @Override public int shortSize() { return myShortSize; } @Override public int longSize() { return myLongSize; } @Override public int getLongIndex(int shortIndex) { checkShortIndex(shortIndex); int strongIndex = shortIndex / myBlockSize; int sub = shortIndex - strongIndex * myBlockSize; for (int longIndex = myStrongShortIndexes[strongIndex]; longIndex < myLongSize; longIndex++) { if (myVisibleIndexes.get(longIndex)) sub--; if (sub == -1) return longIndex; } throw new IllegalStateException( "Not found long index for short index: " + shortIndex + ". Long & short size is: " + myLongSize + ", " + myShortSize + "."); } }