From 5d4aa1ac1fc3e6ad3e86bfa0fd9c61f96bc69f98 Mon Sep 17 00:00:00 2001 From: pjs <pjs@alum.mit.edu> Date: Wed, 11 Jul 2018 07:41:17 -0700 Subject: [PATCH] Cancellation functioning w/ test cases --- demos/CancelQ.rb | 23 +++++++++++++++++++++++ lib/simplekit.rb | 24 ++++++++++++++++++++---- 2 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 demos/CancelQ.rb diff --git a/demos/CancelQ.rb b/demos/CancelQ.rb new file mode 100644 index 0000000..d9022f7 --- /dev/null +++ b/demos/CancelQ.rb @@ -0,0 +1,23 @@ +#!/usr/bin/env ruby + +require_relative '../lib/simplekit' + +class MyModel + include SimpleKit + + def init + @x = 1 + schedule(:increment, rand(2), n: 1, char: 'z'.ord) + cancel(:increment, char: 'q'.ord) + end + + def increment(n:, char:) + @x += n + schedule(:increment, 2.0 * rand(2), n: @x, char: char - 1, priority: 3) + printf "%f, %f, %c\n", model_time, @x, char + cancel_all :increment if model_time > 10 + end +end + +srand(42) +MyModel.new.run diff --git a/lib/simplekit.rb b/lib/simplekit.rb index 0826328..cd63429 100644 --- a/lib/simplekit.rb +++ b/lib/simplekit.rb @@ -1,3 +1,4 @@ +require 'set' require_relative 'priority_queue' # The +SimpleKit+ module provides basic event scheduling capabilities. @@ -50,7 +51,7 @@ module SimpleKit # - +event+ -> the event to be scheduled. # - +delay+ -> the amount of time which should elapse before # the event executes. - # - +args+ -> an optional list of arguments to pass to the event + # - +args+ -> zero or more named arguments to pass to the event # at invocation time. def schedule(event, delay, **args) raise 'Model scheduled event with negative delay.' if delay < 0 @@ -58,7 +59,8 @@ module SimpleKit end def cancel(event, **args) - @cancel_set[event] = args + @cancel_set[event] ||= Set.new + @cancel_set[event].add(args.empty? ? nil : args) end def cancel_all(event) @@ -83,8 +85,22 @@ module SimpleKit while (current_event = @event_list.pop) e = current_event.event if @cancel_set.key? e - @cancel_set.delete e # if @cancel_set[e].empty? - next + if @cancel_set[e] === nil + @cancel_set[e].delete nil + @cancel_set.delete e if @cancel_set[e].empty? + next + else + arg_match = false + for h in @cancel_set[e] do + if current_event.args >= h + arg_match = true + @cancel_set[e].delete h + @cancel_set.delete e if @cancel_set[e].empty? + break + end + end + next if arg_match + end end @model_time = current_event.time if current_event.args.empty? -- GitLab