blob: a1a1168dd8702540cedbd31ac23d4ac264cad6d6 [file] [log] [blame]
/*
* Copyright 2000-2010 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.openapi.editor.impl.softwrap.mapping;
import gnu.trove.TIntHashSet;
import gnu.trove.TIntObjectHashMap;
import gnu.trove.TIntObjectProcedure;
import gnu.trove.TIntProcedure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Stands for key-value storage with <code>int</code> keys that allows to mark particular range for deletion and
* remove it later.
*
* @author Denis Zhdanov
* @since 11/15/10 10:56 AM
* @param <T> value type
*/
class DelayedRemovalMap<T> {
//TODO den add simple array that tracks stored key in assumption that they are adjacent
private final TIntObjectHashMap<T> myMap = new TIntObjectHashMap<T>();
private final TIntHashSet myKeysToRemove = new TIntHashSet();
private final TIntProcedure myRemoveEntriesProcedure = new TIntProcedure() {
@Override
public boolean execute(int value) {
myMap.remove(value);
return true;
}
};
/**
* Asks for the value stored for the given key if any.
*
* @param key target key
* @return value mapped for the given key if any; <code>null</code> otherwise
*/
@Nullable
public T get(int key) {
return myMap.get(key);
}
/**
* Stores mapping between the given key and value.
*
* @param key target key
* @param value target value
*/
public void put(int key, @NotNull T value) {
myMap.put(key, value);
myKeysToRemove.remove(key);
}
/**
* Marks all entries of the given map that belongs to the <code>[start; end]</code> interval for further removal (triggered by
* call to {@link #deleteMarked()}).
*
* @param start target key's interval start (inclusive)
* @param end target key's interval end (inclusive)
*/
public void markForDeletion(int start, int end) {
for (int i = start; i <= end; i++) {
if (myMap.containsKey(i)) {
myKeysToRemove.add(i);
}
}
}
/**
* Asks current map to remove all keys that were marked during {@link #markForDeletion(int, int)}.
* <p/>
* <b>Note:</b> following actions sequence is possible:
* <pre>
* <ol>
* <li>
* {@link #put(int, Object)} is called for entries with keys, say, <code>'1'</code>, <code>'2'</code> and <code>'3'</code>;
* </li>
* <li>
* {@link #markForDeletion(int, int)} is called with range <code>[2; 3]</code>;
* </li>
* <li>
* {@link #put(int, Object)} is called for key <code>'2'</code>;
* </li>
* <li>
* {@link #deleteMarked()} is called;
* </li>
* </ol>
* </pre>
* Entry with key <code>'2'</code> is not removed on {@link #deleteMarked()} processing then because it was updated <b>after</b>
* {@link #markForDeletion(int, int)}.
*/
public void deleteMarked() {
myKeysToRemove.forEach(myRemoveEntriesProcedure);
}
/**
* Asks current map to drop all entries which keys are greater or equal to the given one.
*
* @param key target start key
*/
public void deleteFrom(final int key) {
myMap.retainEntries(new TIntObjectProcedure<T>() {
@Override
public boolean execute(int a, T b) {
if (a >= key) {
myKeysToRemove.remove(a);
return false;
}
return true;
}
});
}
/**
* Asks current map to clear its state.
*/
public void clear() {
myMap.clear();
myKeysToRemove.clear();
}
public int size() {
return myMap.size();
}
}