org.jactr.core.queue.collection.PrioritizedQueue.java Source code

Java tutorial

Introduction

Here is the source code for org.jactr.core.queue.collection.PrioritizedQueue.java

Source

/*
 * 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;
    }
}