/*
* ARX: Powerful Data Anonymization
* Copyright 2012 - 2017 Fabian Prasser, Florian Kohlmayer and contributors
*
* 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 org.deidentifier.arx.framework.check.history;
import java.util.HashMap;
import java.util.Iterator;
/**
* The Class MRUCache.
*
* @author Fabian Prasser
* @author Florian Kohlmayer
* @param <T> the generic type
*/
public class MRUCache<T> {
/**
* The Class MRULinkedListIterator.
*
* @author Fabian Prasser
* @author Florian Kohlmayer
*/
public class MRULinkedListIterator implements Iterator<T> {
/** The currposition. */
private MRUCacheEntry<T> currposition;
/** The list. */
private final MRUCache<T> list;
/** The prevposition. */
private MRUCacheEntry<T> prevposition;
/**
* Instantiates a new mRU linked list iterator.
*
* @param l
* the l
*/
public MRULinkedListIterator(final MRUCache<T> l) {
this.currposition = l.first;
this.prevposition = l.first;
this.list = l;
}
/*
* (non-Javadoc)
*
* @see java.util.Iterator#hasNext()
*/
@Override
public boolean hasNext() {
return this.currposition != null;
}
/*
* (non-Javadoc)
*
* @see java.util.Iterator#next()
*/
@Override
public T next() {
final T obj = this.currposition.data;
this.prevposition = this.currposition;
this.currposition = this.currposition.next;
return obj;
}
/*
* (non-Javadoc)
*
* @see java.util.Iterator#remove()
*/
@Override
public void remove() {
this.list.remove(this.prevposition);
this.list.elementToEntry.remove(this.prevposition.data);
}
}
/** The element to entry. */
private HashMap<T, MRUCacheEntry<T>> elementToEntry = null;
/** The first. */
private MRUCacheEntry<T> first = null;
/** The last. */
private MRUCacheEntry<T> last = null;
/**
* Instantiates a new mRU cache.
*
* @param size
* the size
*/
public MRUCache(final int size) {
this.elementToEntry = new HashMap<T, MRUCacheEntry<T>>(size);
}
/**
* Append.
*
* @param node
* the node
*/
public void append(final T node) {
if (this.elementToEntry.containsKey(node)) {
this.touch(node);
return;
}
final MRUCacheEntry<T> entry = new MRUCacheEntry<T>(node);
this.append(entry);
this.elementToEntry.put(node, entry);
}
/**
* Clear.
*/
public void clear() {
elementToEntry.clear();
first = null;
last = null;
}
/**
* Gets the first.
*
* @return the first
*/
public MRUCacheEntry<T> getHead() {
return first;
}
/**
* Iterator.
*
* @return the iterator
*/
public Iterator<T> iterator() {
return new MRULinkedListIterator(this);
}
/**
* Removes the head.
*
* @return the t
*/
public T removeHead() {
final T obj = this.first.data;
this.remove(this.first);
this.elementToEntry.remove(obj);
return obj;
}
/**
* Size.
*
* @return the int
*/
public int size() {
return this.elementToEntry.size();
}
/**
* Touch.
*
* @param node
* the node
*/
public void touch(final T node) {
final MRUCacheEntry<T> entry = this.elementToEntry.get(node);
if (entry == this.last) { return; }
this.remove(entry);
this.append(entry);
}
/**
* Append.
*
* @param entry
* the entry
*/
private void append(final MRUCacheEntry<T> entry) {
if (this.first == null) {
this.first = entry;
this.last = entry;
entry.prev = null;
entry.next = null;
} else {
this.last.next = entry;
entry.prev = this.last;
entry.next = null;
this.last = entry;
}
}
/**
* Removes the.
*
* @param entry
* the entry
*/
private void remove(final MRUCacheEntry<T> entry) {
if (entry == this.first) {
this.first = entry.next;
if (this.first != null) {
this.first.prev = null;
}
} else if (entry == this.last) {
this.last = entry.prev;
this.last.next = null;
} else {
if (entry.prev != null) {
entry.prev.next = entry.next;
}
if (entry.next != null) {
entry.next.prev = entry.prev;
}
}
}
}