/* * Copyright 2011 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.gwt.user.server.rpc.impl; import java.util.ArrayDeque; import java.util.Deque; import java.util.HashMap; /** * MultiMap with stack semantics for the values. * * Initial insertion of a given key results in a new stack containing the value. * Subsequent puts for the same key add the value to the stack. Removing a key * removes its value from the stack. * * @param <K> The key to use in the map * @param <V> The value to put in the deque */ public class DequeMap<K, V> { /** * The default initial capacity for the Deque objects. */ static final int DEFAULT_INITIAL_DEQUE_CAPACITY = 3; /** * The default initial capacity for the Deque objects. */ static final int DEFAULT_INITIAL_MAP_CAPACITY = 3; /** * The initial capacity for the Deque objects. */ int dequeCapacity = DEFAULT_INITIAL_DEQUE_CAPACITY; /** * The map used to hold data. * * Note that we do not extend map because we require control over the * addition and removal of elements from the map. */ HashMap<K, Deque<V>> map = null; /** * Constructs an empty <tt>DequeMap</tt> with the default initial capacities * (3 and 3) and the default map load factor (0.75). */ public DequeMap() { this(DEFAULT_INITIAL_MAP_CAPACITY, DEFAULT_INITIAL_DEQUE_CAPACITY); } /** * Constructs an empty <tt>DequeMap</tt> with the specified initial capacities * and the default map load factor (0.75). * * @param initialMapCapacity the initial map capacity. * @param initialDequeCapacity the initial deque capacity. * @throws IllegalArgumentException if the initial capacity is negative. */ public DequeMap(int initialMapCapacity, int initialDequeCapacity) { map = new HashMap<K, Deque<V>>(initialMapCapacity); dequeCapacity = initialDequeCapacity; } /** * Add a value for a key to the map. * * If the key already exists, the value is added to the head of the queue at * that key. Otherwise, a new queue containing the value is created and * inserted into the map at the key. * * @param key key with which the specified value is to be associated * @param value the value to push for the key */ public void add(K key, V value) { Deque<V> deque = map.get(key); if (deque == null) { deque = new ArrayDeque<V>(dequeCapacity); deque.addFirst(value); map.put(key, deque); } else { deque.addFirst(value); } } /** * Get the most recent value for a key. * * @param key key to get * @return the value at the head of the stack for the key, or null if the key * is unknown. */ public V get(K key) { Deque<V> deque = map.get(key); if (deque == null) { return null; } return deque.peekFirst(); } /** * Remove the most recent value for a key. * * @param key key to get * @return the value at the head of the stack for the key, or null if the key * is unknown. */ public V remove(K key) { Deque<V> deque = map.get(key); if (deque == null) { return null; } return deque.pollFirst(); } }