diff dwtx/core/internal/jobs/JobQueue.d @ 122:9d0585bcb7aa

Add core.jobs package
author Frank Benoit <benoit@tionex.de>
date Tue, 12 Aug 2008 02:34:21 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/core/internal/jobs/JobQueue.d	Tue Aug 12 02:34:21 2008 +0200
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM - Initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.core.internal.jobs.JobQueue;
+
+import dwt.dwthelper.utils;
+
+import dwtx.core.runtime.Assert;
+import dwtx.core.runtime.IProgressMonitor;
+import dwtx.core.runtime.IStatus;
+import dwtx.core.runtime.Status;
+
+import dwtx.core.internal.jobs.InternalJob;
+
+/**
+ * A linked list based priority queue. Either the elements in the queue must
+ * implement Comparable, or a Comparator must be provided.
+ */
+public class JobQueue {
+    /**
+     * The dummy entry sits between the head and the tail of the queue.
+     * dummy.previous() is the head, and dummy.next() is the tail.
+     */
+    private final InternalJob dummy;
+
+    /**
+     * If true, conflicting jobs will be allowed to overtake others in the
+     * queue that have lower priority. If false, higher priority jumps can only
+     * move up the queue by overtaking jobs that they don't conflict with.
+     */
+    private bool allowConflictOvertaking;
+
+    /**
+     * Create a new job queue.
+     */
+    public this(bool allowConflictOvertaking) {
+        //compareTo on dummy is never called
+        dummy = new class("Queue-Head") InternalJob {//$NON-NLS-1$
+            this( String name ){
+                super(name);
+            }
+            public IStatus run(IProgressMonitor m) {
+                return Status.OK_STATUS;
+            }
+        };
+        dummy.setNext(dummy);
+        dummy.setPrevious(dummy);
+        this.allowConflictOvertaking = allowConflictOvertaking;
+    }
+
+    /**
+     * remove all elements
+     */
+    public void clear() {
+        dummy.setNext(dummy);
+        dummy.setPrevious(dummy);
+    }
+
+    /**
+     * Return and remove the element with highest priority, or null if empty.
+     */
+    public InternalJob dequeue() {
+        InternalJob toRemove = dummy.previous();
+        if (toRemove is dummy)
+            return null;
+        return toRemove.remove();
+    }
+
+    /**
+     * Adds an item to the queue
+     */
+    public void enqueue(InternalJob newEntry) {
+        //assert new entry is does not already belong to some other data structure
+        Assert.isTrue(newEntry.next() is null);
+        Assert.isTrue(newEntry.previous() is null);
+        InternalJob tail = dummy.next();
+        //overtake lower priority jobs. Only overtake conflicting jobs if allowed to
+        while (canOvertake(newEntry, tail))
+            tail = tail.next();
+        //new entry is smaller than tail
+        final InternalJob tailPrevious = tail.previous();
+        newEntry.setNext(tail);
+        newEntry.setPrevious(tailPrevious);
+        tailPrevious.setNext(newEntry);
+        tail.setPrevious(newEntry);
+    }
+
+    /**
+     * Returns whether the new entry to overtake the existing queue entry.
+     * @param newEntry The entry to be added to the queue
+     * @param queueEntry The existing queue entry
+     */
+    private bool canOvertake(InternalJob newEntry, InternalJob queueEntry) {
+        //can never go past the end of the queue
+        if (queueEntry is dummy)
+            return false;
+        //if the new entry was already in the wait queue, ensure it is re-inserted in correct position (bug 211799)
+        if (newEntry.getWaitQueueStamp() > 0 && newEntry.getWaitQueueStamp() < queueEntry.getWaitQueueStamp())
+            return true;
+        //if the new entry has lower priority, there is no need to overtake the existing entry
+        if (queueEntry.compareTo(newEntry) >= 0)
+            return false;
+        //the new entry has higher priority, but only overtake the existing entry if the queue allows it
+        return allowConflictOvertaking || !newEntry.isConflicting(queueEntry);
+    }
+
+    /**
+     * Removes the given element from the queue.
+     */
+    public void remove(InternalJob toRemove) {
+        toRemove.remove();
+        //previous of toRemove might now bubble up
+    }
+
+    /**
+     * The given object has changed priority. Reshuffle the heap until it is
+     * valid.
+     */
+    public void resort(InternalJob entry) {
+        remove(entry);
+        enqueue(entry);
+    }
+
+    /**
+     * Returns true if the queue is empty, and false otherwise.
+     */
+    public bool isEmpty() {
+        return dummy.next() is dummy;
+    }
+
+    /**
+     * Return greatest element without removing it, or null if empty
+     */
+    public InternalJob peek() {
+        return dummy.previous() is dummy ? null : dummy.previous();
+    }
+}