raise "OMG" if RUBY_VERSION < "1.9.0"
class Go
@@waiting = []
@@current = nil
@@creation = []
class Channel
Msg = Struct.new :value, :p, :blocker
def initialize(bufsize=1)
@bufsize = bufsize
@msgbuf = []
@send = []
@recv = []
end
def << value
_send_msg Msg.new(value)
end
def send(&p)
_send_msg Msg.new(nil, p)
end
def ~
unless @msgbuf.empty?
msg = @msgbuf.shift
Go.schedule(msg.blocker, nil) if msg.blocker
return _value_of msg
end
@recv << Go.current_fiber
Fiber.yield
end
def _send_msg(msg)
@msgbuf << msg
if !@recv.empty?
# ASSERT @msgbuf.first.blocker.nil?
Go.schedule(@recv.shift, _value_of(@msgbuf.shift))
else @msgbuf.size + 1 >= @bufsize
msg.blocker = Go.current_fiber
Fiber.yield
end
end
def _value_of msg
msg.p ? msg.p[] : msg.value
end
end
def self.go(&p)
@@creation << p
end
def self.chan
Channel.new
end
def self.schedule(fiber, arg)
@@waiting << [fiber, arg]
end
def self.current_fiber
@@current_fiber
end
def self.proceed(&p)
go &p if p
loop {
unless @@creation.empty?
@@creation.each {|p|
@@waiting << [Fiber.new(&p), nil]
}
@@creation = []
end
break if @@waiting.empty?
a = @@waiting
@@waiting = []
a.each {|pair|
@@current_fiber = pair.first
pair.first.resume(pair.last)
}
}
end
end
## MAIN ##
def fibs
ch = Go::chan
Go::go {
ch << 1
ch << 1
ch0 = fibs
ch1 = fibs
~ch1
loop { ch.send { ~ch0 + ~ch1 } }
}
ch
end
Go.proceed {
ch = fibs
10.times { p [~ch] }
}