net.sf.jasperreports.engine.util.LinkedMap Maven / Gradle / Ivy
/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JasperReports is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JasperReports. If not, see .
*/
package net.sf.jasperreports.engine.util;
import java.util.HashMap;
import java.util.Map;
/**
* A doubly linked list that can also map entries on keys.
*
* The list can be iterated in FIFO order and implements the following operations
* in constant time:
*
* - adding an element at the start
* - adding an element at the end
* - finding and removing an element based on a key
*
*
* @author Lucian Chirita ([email protected])
*/
public class LinkedMap
{
protected static class LinkedValue implements Map.Entry
{
private LinkedValue prev;
private LinkedValue next;
private K key;
private V value;
protected LinkedValue(K key, V value)
{
this.key = key;
this.value = value;
}
@Override
public K getKey()
{
return key;
}
@Override
public V getValue()
{
return value;
}
@Override
public V setValue(V value)
{
throw new UnsupportedOperationException();
}
}
private final LinkedValue header;
private final HashMap> map;
/**
* Creates a list.
*/
public LinkedMap()
{
map = new HashMap>();
header = new LinkedValue(null, null);
header.prev = header;
header.next = header;
}
/**
* Adds a value at the end of the list.
*
* @param key the not-null key to which the value is mapped
* @param value the value
*/
public void add(K key, V value)
{
if (key != null && map.containsKey(key))
{
//NOP
return;
}
// add last
LinkedValue entry = new LinkedValue(key, value);
entry.prev = header.prev;
entry.next = header;
header.prev.next = entry;
header.prev = entry;
if (key != null)
{
map.put(key, entry);
}
}
/**
* Adds a value at the start of the list
*
* @param key the not-null key to which the value is mapped
* @param value the value
*/
public void addFirst(K key, V value)
{
if (key != null && map.containsKey(key))
{
//NOP
return;
}
// add first
LinkedValue entry = new LinkedValue(key, value);
entry.next = header.next;
entry.prev = header;
header.next.prev = entry;
header.next = entry;
if (key != null)
{
map.put(key, entry);
}
}
/**
* Determines whether the list is empty.
*
* @return whether the list is empty
*/
public boolean isEmpty()
{
return header.next == header;
}
/**
* Removes and returns the first element in the list.
*
* @return the first element in the list
*/
public V pop()
{
LinkedValue entry = removeFirst();
return entry.value;
}
/**
* Removes and returns the first element in the list.
*
* @return the first element in the list
*/
public Map.Entry popEntry()
{
return removeFirst();
}
protected LinkedValue removeFirst()
{
if (header.next == header)
{
throw new IllegalStateException("Empty map");
}
LinkedValue entry = header.next;
entry.prev.next = entry.next;
entry.next.prev = entry.prev;
if (entry.key != null)
{
map.remove(entry.key);
}
return entry;
}
/**
* Removes and returns an element mapped to a key.
*
* @param key
* @return the element mapped to the key, null
if the key is not mapped
*/
public V remove(K key)
{
if (key == null)
{
throw new NullPointerException("Key cannot be null");
}
LinkedValue entry = map.remove(key);
if (entry == null)
{
return null;
}
entry.prev.next = entry.next;
entry.next.prev = entry.prev;
return entry.value;
}
/**
* Adds all entries from the map to this map, preserving the order.
*
* @param map
*/
public void addAll(LinkedMap map)
{
for (LinkedValue entry = map.header.next; entry != map.header; entry = entry.next)
{
add(entry.key, entry.value);
}
}
}