diff --git a/demos/CancelQ.rb b/demos/CancelQ.rb new file mode 100644 index 0000000000000000000000000000000000000000..d9022f766bb7e70cfa07f2d76658f7ad9d1710b4 --- /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 0826328d8ad988147a44b8bc6d017431ea5776b7..cd63429ed20a65ea53d9102134bb623a7c0a9a58 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?