/* * Created on May 9, 2007 Copyright (C) 2001-6, Anthony Harrison anh23@pitt.edu * (jactr.org) This library 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 2.1 of the License, * or (at your option) any later version. This library 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 this * library; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jactr.core.queue.collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Crazy prioritized queue (bad name.. whatever) that had to be implemented for * one reason: java.util.PriorityQueue does not maintain insertion order of * items when they have the same priority. jACT-R needs to maintain the order so * that timed events added by instantiations are fired in the order they are * queued.<br> * <br> * This has three pieces, IPrioritizer<T> which takes a T and returns a double * value. When you add an item, its priority is used to determine which * collection, in a sorted map of collections, it will be stored in.<br> * <br> * You call Collection<T> remove(double) to remove all items from the queue * that have priorities less than or equal to the value.<br> * <b>Note</b>: this is not thread safe * * @author developer */ public class PrioritizedQueue<T> { /** * logger definition */ static private final Log LOGGER = LogFactory .getLog(PrioritizedQueue.class); private IPrioritizer<T> _prioritizer; private SortedMap<Double, Collection<T>> _backingMap; private int _size; public PrioritizedQueue(IPrioritizer<T> prioritizer) { _prioritizer = prioritizer; _backingMap = new TreeMap<Double, Collection<T>>(); } synchronized public void clear() { _backingMap.clear(); } synchronized public void add(T item) { double priority = _prioritizer.getPriority(item); if (Double.isNaN(priority)) throw new IllegalArgumentException("Invalid priority of " + item + ", must not be NaN"); Collection<T> itemsOfSamePriority = _backingMap.get(priority); if (itemsOfSamePriority == null) { itemsOfSamePriority = new ArrayList<T>(); _backingMap.put(priority, itemsOfSamePriority); } itemsOfSamePriority.add(item); _size++; } synchronized public boolean remove(T item) { double priority = _prioritizer.getPriority(item); if (Double.isNaN(priority)) throw new IllegalArgumentException("Invalid priority of " + item + ", must not be NaN"); Collection<T> itemsOfSamePriority = _backingMap.get(priority); if (itemsOfSamePriority == null) return false; itemsOfSamePriority.remove(item); _size--; return true; } /** * return all the items of less than or equal to upThrough * * @param upThrough * @return */ synchronized public void remove(double upThrough, Collection<T> removedEvents) { if (_backingMap.isEmpty()) return; double firstKey = _backingMap.firstKey(); if (firstKey > upThrough) return; int originalSize = removedEvents.size(); if (firstKey != upThrough) { /* * snag collections from lowest to upToPriority(exclusive) */ Iterator<Map.Entry<Double, Collection<T>>> itr = _backingMap.subMap( firstKey, upThrough).entrySet().iterator(); while (itr.hasNext()) { removedEvents.addAll(itr.next().getValue()); itr.remove(); } } /* * that took care of everyone from low to priority(exclusive) - now we need * priority */ Collection<T> atPriority = _backingMap.remove(upThrough); if (atPriority != null) removedEvents.addAll(atPriority); _size -= (removedEvents.size()-originalSize); } /** * return all the elements in order of priority (and insertion if priorities * are the same) * * @return */ synchronized public Collection<T> get() { ArrayList<T> rtn = new ArrayList<T>(); if (_backingMap.isEmpty()) return rtn; for (Map.Entry<Double, Collection<T>> entry : _backingMap.entrySet()) rtn.addAll(entry.getValue()); return rtn; } /** * first key, or NaN if empty * * @return */ synchronized public double getFirstPriority() { if (!_backingMap.isEmpty()) return _backingMap.firstKey(); return Double.NaN; } /** * first key after afterPriority, or NaN * * @param afterPriority * @return */ synchronized public double getFirstPriorityAfter(double afterPriority) { SortedMap<Double, Collection<T>> submap = _backingMap.subMap(_backingMap .firstKey(), afterPriority); if (!submap.isEmpty()) return submap.firstKey(); return Double.NaN; } synchronized public boolean isEmpty() { return _backingMap.isEmpty(); } public int getSize() { return _size; } }