[ruby-core:70692] Queue enhancement - promote! and promote_all!

From: Jonathan Cruz <JCruz@...>
Date: 2015-09-08 18:08:41 UTC
List: ruby-core #70692
I'm submitting a patch to enhance the Queue class by adding the methods Que=
ue#promote! and Queue#promote_all!. These methods require a block that acce=
pts queue elements. Elements for which the block returns a truthy value are=
 moved to the 'front' of the queue.  Queue#promote! only applies to the fir=
st such element and Queue#promote_all! applies to all matching elements (pr=
eserving their relative order).

Motivation for this enhancement: Our project has several worker threads wor=
king on long-running work units in a queue, trying to find a 'match'.  The =
queue is pre-sorted with the most likely matches at the front and least lik=
ely at the back. However, there are cases where as we work on some elements=
, we gain new data that certain elements are more likely to match than we o=
riginally thought. We need a way to promote these elements to the front of =
the queue.

-Jonathan Cruz

________________________________

This transmission may contain information that is privileged, confidential,=
 and/or exempt from disclosure under applicable law. If you are not the int=
ended recipient, you are hereby notified that any disclosure, copying, dist=
ribution, or use of the information contained herein (including any relianc=
e thereon) is strictly prohibited. If you received this transmission in err=
or, please immediately contact the sender and destroy the material in its e=
ntirety, whether in electronic or hard copy format.

Attachments (1)

ruby_queue_promote.patch (2.82 KB, text/x-diff)
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 51752)
+++ ChangeLog	(working copy)
@@ -1,3 +1,11 @@
+Tue Sep  9 02:43:13 2015  Jonathan Cruz  <jcruz@trustwave.com>
+
+	* thread_sync.c: Add Queue#promote! and Queue#promote_all!
+	  Promotes elements to the front of the queue for which the provided
+	  block returns a truthy value. #promote! only applies to the first
+	  such element. #promote_all! applies to all matching elements,
+	  maintaining their relative order.
+
 Thu Sep  3 21:12:12 2015  Nobuyoshi Nakada  <nobu@ruby-lang.org>
 
 	* lib/cgi/session.rb (create_new_id): use SHA512 instead of MD5.
Index: thread_sync.c
===================================================================
--- thread_sync.c	(revision 51752)
+++ thread_sync.c	(working copy)
@@ -905,6 +905,64 @@
 }
 
 /*
+ * Document-method: Queue#promote!
+ * call-seq: promote!
+ *
+ * Promotes first object to the front of the queue for which the given +block+
+ * returns a true value.
+ */
+
+static VALUE
+rb_queue_promote(VALUE self)
+{
+    if (!rb_block_given_p()) {
+        rb_raise(rb_eThreadError, "must be called with a block");
+    }
+    return queue_do_promote(self, FALSE);
+}
+
+/*
+ * Document-method: Queue#promote_all!
+ * call-seq: promote_all!
+ *
+ *
+ * Promotes all objects to the front of the queue for which the given +block+
+ * returns a true value, preserving their relative order.
+ */
+
+static VALUE
+rb_queue_promote_all(VALUE self)
+{
+    if (!rb_block_given_p()) {
+        rb_raise(rb_eThreadError, "must be called with a block");
+    }
+    return queue_do_promote(self, TRUE);
+}
+
+static VALUE
+queue_do_promote(VALUE self, int promote_all)
+{
+    VALUE que = GET_QUEUE_QUE(self);
+    VALUE promote = rb_ary_new2(RARRAY_LEN(que));
+    long i;
+    for (i = 0; i < RARRAY_LEN(que); i++) {
+        VALUE obj = RARRAY_AREF(que, i);
+        if (RTEST(rb_yield(obj))) {
+            rb_ary_unshift(promote, obj);
+            if (!promote_all) break;
+        }
+    }
+
+    for (i = 0; i < RARRAY_LEN(promote); i++) {
+        VALUE obj = RARRAY_AREF(promote, i);
+        rb_ary_delete(que, obj);
+        rb_ary_unshift(que, obj);
+    }
+    return self;
+}
+
+
+/*
  *  Document-class: SizedQueue
  *
  * This class represents queues of specified size capacity.  The push operation
@@ -1281,6 +1339,8 @@
     rb_define_method(rb_cQueue, "clear", rb_queue_clear, 0);
     rb_define_method(rb_cQueue, "length", rb_queue_length, 0);
     rb_define_method(rb_cQueue, "num_waiting", rb_queue_num_waiting, 0);
+    rb_define_method(rb_cQueue, "promote!", rb_queue_promote, 0);
+    rb_define_method(rb_cQueue, "promote_all!", rb_queue_promote_all, 0);
 
     rb_define_alias(rb_cQueue, "enq", "push");    /* Alias for #push. */
     rb_define_alias(rb_cQueue, "<<", "push");     /* Alias for #push. */

In This Thread

Prev Next