001/* 002 * Copyright (C) 2012 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.collect; 018 019import static com.google.common.base.Preconditions.checkArgument; 020import static com.google.common.base.Preconditions.checkNotNull; 021 022import com.google.common.annotations.Beta; 023import com.google.common.annotations.GwtIncompatible; 024 025import java.util.ArrayDeque; 026import java.util.Collection; 027import java.util.Queue; 028 029/** 030 * A non-blocking queue which automatically evicts elements from the head of the queue when 031 * attempting to add new elements onto the queue and it is full. 032 * 033 * <p>An evicting queue must be configured with a maximum size. Each time an element is added 034 * to a full queue, the queue automatically removes its head element. This is different from 035 * conventional bounded queues, which either block or reject new elements when full. 036 * 037 * <p>This class is not thread-safe, and does not accept null elements. 038 * 039 * @author Kurt Alfred Kluever 040 * @since 15.0 041 */ 042@Beta 043@GwtIncompatible("java.util.ArrayDeque") 044public final class EvictingQueue<E> extends ForwardingQueue<E> { 045 046 private final Queue<E> delegate; 047 private final int maxSize; 048 049 private EvictingQueue(int maxSize) { 050 checkArgument(maxSize >= 0, "maxSize (%s) must >= 0", maxSize); 051 this.delegate = new ArrayDeque<E>(maxSize); 052 this.maxSize = maxSize; 053 } 054 055 /** 056 * Creates and returns a new evicting queue that will hold up to {@code maxSize} elements. 057 * 058 * <p>When {@code maxSize} is zero, elements will be evicted immediately after being added to the 059 * queue. 060 */ 061 public static <E> EvictingQueue<E> create(int maxSize) { 062 return new EvictingQueue<E>(maxSize); 063 } 064 065 @Override protected Queue<E> delegate() { 066 return delegate; 067 } 068 069 /** 070 * Adds the given element to this queue. If the queue is currently full, the element at the head 071 * of the queue is evicted to make room. 072 * 073 * @return {@code true} always 074 */ 075 @Override public boolean offer(E e) { 076 return add(e); 077 } 078 079 /** 080 * Adds the given element to this queue. If the queue is currently full, the element at the head 081 * of the queue is evicted to make room. 082 * 083 * @return {@code true} always 084 */ 085 @Override public boolean add(E e) { 086 checkNotNull(e); // check before removing 087 if (maxSize == 0) { 088 return true; 089 } 090 if (size() == maxSize) { 091 delegate.remove(); 092 } 093 delegate.add(e); 094 return true; 095 } 096 097 @Override public boolean addAll(Collection<? extends E> collection) { 098 return standardAddAll(collection); 099 } 100 101 @Override 102 public boolean contains(Object object) { 103 return delegate().contains(checkNotNull(object)); 104 } 105 106 @Override 107 public boolean remove(Object object) { 108 return delegate().remove(checkNotNull(object)); 109 } 110 111 // TODO(user): Do we want to checkNotNull each element in containsAll, removeAll, and retainAll? 112 113 // TODO(user): Do we want to add EvictingQueue#isFull()? 114}