profile
viewpoint
If you are wondering where the data of this site comes from, please visit https://api.github.com/users/JohannesMP/events. GitMemory does not store any data, but only uses NGINX to cache data for a period of time. The idea behind GitMemory is simply to give users a better reading experience.

JohannesMP/DarkBoard-Espresso-Theme 4

A theme that emulates TextMate's 'Blackboard' Theme for use with MacRabbit's Espresso 2.0

Azurelol/DCEngine 1

GAM 250

JohannesMP/com.johannesmp.compile 1

A small web-based multi-file compiler using the coliru.stacked-crooked.com API

JohannesMP/2019-10_MP01 0

A simple Multiplayer Test

JohannesMP/351ELEC 0

Handheld firmware optimized for the Anbernic RG351P/M/V devices.

push eventJohannesMP/351ELEC-pages

Johannes

commit sha 3403e498f230f560ce8d5a417ee2520dba2e6b03

Clarified ROM directory structure convention and partition mapping Mirrors changes made on Github Wiki, before I was made aware of this new wiki: https://github.com/351ELEC/351ELEC/wiki/Getting-to-Know-351ELEC/_compare/2109a1ee6c9b92d8d518c452dc9ea2b874090236...371505623d7cd5184374ed991c59189832f3d5a5

view details

push time in 7 days

push eventJohannesMP/351ELEC-pages

Johannes

commit sha 2089c451c5415462e4969144ea5c565a85f09e05

Clarifying how the GAMES partition relates to base ROM path Mirrors changes made on Github Wiki, before I was made aware of this new wiki: https://github.com/351ELEC/351ELEC/wiki/Supported-Emulators-and-Ports/_compare/4a2f58a7b0cac641e4f06b4fd444178cfc9fa50d...1dd1a62527bb461c075eecf4a6146c588c0dc94c

view details

push time in 7 days

GollumEvent
GollumEvent
GollumEvent
GollumEvent

fork JohannesMP/351ELEC

Handheld firmware optimized for the Anbernic RG351P/M/V devices.

fork in 8 days

started351ELEC/351ELEC

started time in 8 days

starteddziemborowicz/hourglass

started time in 2 months

startedBlueRaja/High-Speed-Priority-Queue-for-C-Sharp

started time in 2 months

Pull request review commentBlueRaja/High-Speed-Priority-Queue-for-C-Sharp

Add SimplePriorityQueue.Try...() overloads that expose priority as out parameter

 public bool TryRemove(TItem item)             }         } +        /// <summary>+        /// Attempts to remove an item from the queue. The item does not need to be the head of the queue.+        /// Useful for multi-threading, where the queue may become empty between calls to Contains(), GetPriority() and Remove()+        /// Returns true if the item was successfully removed, false if it wasn't in the queue.+        /// Assigns priority to priority of removed item if successfully removed.+        /// If multiple copies of the item are enqueued, only the first one is removed. +        /// O(log n)+        /// </summary>+        public bool TryRemove(TItem item, out TPriority priority)

For clarity/consistency the priority parameter here should probably be named itemPriority, but leaving this code review as is for now.

JohannesMP

comment created time in 2 months

PullRequestReviewEvent
GollumEvent
GollumEvent
GollumEvent

issue commentBlueRaja/High-Speed-Priority-Queue-for-C-Sharp

Proposal: SimplePriorityQueue.Dequeue/TryDequeue overloads that also expose priority

I've made a pull requests that adds a variation of the proposal: #55

In hindsight it would be impractical to have an out parameter on a function that isn't of the format bool Try...(), since there would be no way to know if the returned out parameter is valid or not, especially if it's a value type and so cannot be null-checked.

Instead I added the proposed functionality as overloads to TryFirst, TryRemove and TryDequeue. In each of these cases the caller would normally need to use GetPriority/TryGetPriority first, so this can now be done thread safely.

This is also now consistent with the intent (as per the region that contains them) that the Try*(...) functions are intended for multiththreading.

JohannesMP

comment created time in 2 months

PR opened BlueRaja/High-Speed-Priority-Queue-for-C-Sharp

Add SimplePriorityQueue.Try...() overloads that expose priority as out parameter
  • Add SimplePriorityQueue.TryDequeue() overload with out TPriority parameter and relevant unit tests
  • Add SimplePriorityQueue.TryRemove() overload with out TPriority parameter and relevant unit tests
  • Add SimplePriorityQueue.TryFirst overload with out TPriority parameter and relevant unit tests

See issue https://github.com/BlueRaja/High-Speed-Priority-Queue-for-C-Sharp/issues/54

+215 -3

0 comment

2 changed files

pr created time in 2 months

push eventJohannesMP/High-Speed-Priority-Queue-for-C-Sharp

JohannesMP

commit sha 99db0bfe4b8a06651f765ba825dae0d65d9bb200

Add missing summary xml comment tag

view details

JohannesMP

commit sha c39e2a9da9ecef9b9e187cd1ab4bf11c9f00d714

Add SimplePriorityQueue.TryDequeue TryRemove overloads that also output the priority of the removed node

view details

JohannesMP

commit sha 4eb72d54d5fd9708a833f4ebe7851198433b9a31

Add SimplePriorityQueue.TryFirst overload that also outputs the priority of the node

view details

JohannesMP

commit sha d358f5b7659ff4feb22980e77a309243a216a184

Add Tests for SimplePriorityQueue.TryDequeue with priority out parameter

view details

JohannesMP

commit sha 6d00bccb93df65f7a85a89d2b0ddd9afce34a3e6

Add Tests for SimplePriorityQueue.TryRemove with priority out parameter

view details

JohannesMP

commit sha e0f3b9683585b60abc2fc7ba18df013f9bf4f846

Add Tests for SimplePriorityQueue.TryFirst with priority out parameter

view details

push time in 2 months

issue openedBlueRaja/High-Speed-Priority-Queue-for-C-Sharp

Proposal: SimplePriorityQueue.Dequeue/TryDequeue overloads that also expose priority

Overview

With Priority Queues it's often useful to be able to access the priority of the head node as you dequeue it. This is especially common in Pathfinding and graph traversal.

When using GenericPriorityQueue or FastPriorityQueue you manipulate the nodes directly and so have access to their respective Priority properties.

When using SimplePriorityQueue the nodes are not publicly exposed and so it is currently necessary to get the priority of the First element, and then dequeue it.

A basic user implementation might look like this:

public static class SimplePriorityQueueExtensions
{
    public static TItem Dequeue<TItem, TPriority>(
        this SimplePriorityQueue<TItem, TPriority> queue,
        out TPriority priority)
    {
        priority = queue.GetPriority(queue.First);
        return queue.Dequeue();
    }
    
    public static bool TryDequeue<TItem, TPriority>(
        this SimplePriorityQueue<TItem, TPriority> queue,
        out TItem first, 
        out TPriority priority)
    {
        if (!queue.TryFirst(out first))
        {
            priority = default;
            return false;
        }
        
        priority = queue.GetPriority(first);
        queue.Dequeue();
        return true;
    }
}

That achieves the desired result, but it is suboptimal.

The Problem

In its implementation SimplePriorityQueue.Dequeue() retrieves its internal SimpleNode , which contains both the data as well as the priority value, but only uses the data:

public TItem Dequeue()
{
  lock (this._queue)
  {
    SimplePriorityQueue<TItem, TPriority>.SimpleNode node = this._queue.Count > 0 
      ? this._queue.Dequeue() 
      : throw new InvalidOperationException("Cannot call Dequeue() on an empty queue");
    this.RemoveFromNodeCache(node);
    return node.Data;
  }
}

So by performing Dequeue/TryDequeue we actually already have access the Priority value of the head node that we want! It's just not exposed to the caller. They instead have to use GetPriority, which in the worst case requires an additional _itemToNodesCache.TryGetValue call that could be avoided, since it's designed to work for any node and not just the head.

The Proposal

It would be trivial to add a Dequeue and TryDequeue overload to SimplePriorityQueue that has a out TPriority parameter, since we get that value for free in both of existing implementations.

For example, these overloads could look like this:

/// <summary>
/// Removes the head of the queue (node with minimum priority; ties are broken by order of insertion), 
/// and returns it along with its priority.
/// If queue is empty, throws an exception
/// O(log n)
/// </summary>
public TItem Dequeue(out TPriority priority)
{
  lock (this._queue)
  {
    SimplePriorityQueue<TItem, TPriority>.SimpleNode node = this._queue.Count > 0 
      ? this._queue.Dequeue() 
      : throw new InvalidOperationException("Cannot call Dequeue() on an empty queue");
    priority = node.Priority;
    this.RemoveFromNodeCache(node);
    return node.Data;
  }
}

/// <summary>
/// Removes the head of the queue (node with minimum priority; ties are broken by order of insertion), 
/// and sets it to first along with its priority.
/// Useful for multi-threading, where the queue may become empty between calls to Contains() and Dequeue()
/// Returns true if successful; false if queue was empty
/// O(log n)
/// </summary>
public bool TryDequeue(out TItem first, out TPriority priority)
{
  if (this._queue.Count > 0)
  {
    lock (this._queue)
    {
      if (this._queue.Count > 0)
      {
        SimplePriorityQueue<TItem, TPriority>.SimpleNode node = this._queue.Dequeue();
        first = node.Data;
        priority = node.Priority;
        this.RemoveFromNodeCache(node);
        return true;
      }
    }
  }
  first = default (TItem);
  priority = default (TPriority);
  return false;
}

They are identical to the existing implementations, except for assigning the priority out parameter.

Alternatively if it was deemed necessary to keep the function names unique and not overload them they could be named DequeueWithPriority and TryDequeueWithPriority respectively.

Keeping things 'Simple'

The argument could be made that if you care enough about optimizing Dequeue with priority you should just use GenericPriorityQueue or FastPriorityQueue, and that the public signature of SimplePriorityQueue should be kept, well, 'simple'.

That is valid, but given how trivial this implementation would be to add it seems like a missed opportunity, especially for saving an additional hash for an operation that as I understand it is very common in some of the main applications of Priority Queues.

It just seems like the equivalent of

if(Dictionary.Contains(key))
{
    Value val = Dictionary[key];
    // Use val
}

vs.

if(Dictionary.TryGetValue(key, out Value val))
{
    // Use val
}

The primary purpose of this library is performance (it's in the name after all), so I'd like to make the argument that even its 'simple' queue implementation would benefit from this addition, while (especially if we use unique names) remaining as backwards compatible.

Relevant issues

  • https://github.com/BlueRaja/High-Speed-Priority-Queue-for-C-Sharp/issues/27 (Added SimplePriorityQueue.GetPriority, which as discussed here is sub-optimal in this specific case where we already have the node and so don't need to hash to retrieve it.)

created time in 2 months