mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* lib/generator.rb: reimplemented Generator class with Thread instead of
callcc, in order to fix memory leak. [ruby-dev:28142] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9752 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
056561c5dd
commit
b29384860c
2 changed files with 45 additions and 45 deletions
|
@ -1,3 +1,8 @@
|
|||
Thu Dec 29 11:22:34 2005 Hirokazu Yamamoto <ocean@m2.ccsnet.ne.jp>
|
||||
|
||||
* lib/generator.rb: reimplemented Generator class with Thread instead of
|
||||
callcc, in order to fix memory leak. [ruby-dev:28142]
|
||||
|
||||
Wed Dec 28 14:10:05 2005 Tanaka Akira <akr@m17n.org>
|
||||
|
||||
* ia64.s: remove .pred.safe_across_calls directive.
|
||||
|
|
|
@ -28,9 +28,6 @@
|
|||
# Generator converts an internal iterator (i.e. an Enumerable object)
|
||||
# to an external iterator.
|
||||
#
|
||||
# Note that it is not very fast since it is implemented using
|
||||
# continuations, which are currently slow.
|
||||
#
|
||||
# == Example
|
||||
#
|
||||
# require 'generator'
|
||||
|
@ -68,99 +65,97 @@ class Generator
|
|||
# itself, and expected to call the +yield+ method for each element.
|
||||
def initialize(enum = nil, &block)
|
||||
if enum
|
||||
@block = proc { |g|
|
||||
enum.each { |x| g.yield x }
|
||||
}
|
||||
@block = proc{|g| enum.each{|value| g.yield value}}
|
||||
else
|
||||
@block = block
|
||||
end
|
||||
|
||||
@index = 0
|
||||
@queue = []
|
||||
@cont_next = @cont_yield = @cont_endp = nil
|
||||
|
||||
if @cont_next = callcc { |c| c }
|
||||
@block.call(self)
|
||||
|
||||
@cont_endp.call(nil) if @cont_endp
|
||||
@loop_thread = Thread.new do
|
||||
Thread.stop
|
||||
Thread.critical = true
|
||||
begin
|
||||
@block.call(self) # exception safe?
|
||||
rescue
|
||||
@main_thread.raise $!
|
||||
ensure
|
||||
@main_thread.wakeup
|
||||
Thread.critical = false
|
||||
end
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Yields an element to the generator.
|
||||
def yield(value)
|
||||
if @cont_yield = callcc { |c| c }
|
||||
@queue << value
|
||||
@cont_next.call(nil)
|
||||
if Thread.current != @loop_thread
|
||||
raise RuntimeError.new("Generator#yield must be called in Generator.new{|g| ... }")
|
||||
end
|
||||
|
||||
@queue << value
|
||||
@main_thread.wakeup
|
||||
Thread.stop
|
||||
Thread.critical = true
|
||||
self
|
||||
end
|
||||
|
||||
# Returns true if the generator has reached the end.
|
||||
def end?()
|
||||
if @cont_endp = callcc { |c| c }
|
||||
@cont_yield.nil? && @queue.empty?
|
||||
else
|
||||
@queue.empty?
|
||||
def end?
|
||||
if @queue.empty?
|
||||
Thread.critical = true
|
||||
@main_thread = Thread.current
|
||||
begin
|
||||
@loop_thread.wakeup
|
||||
Thread.stop
|
||||
rescue ThreadError
|
||||
# ignore
|
||||
ensure
|
||||
@main_thread = nil
|
||||
Thread.critical = false
|
||||
end
|
||||
end
|
||||
@queue.empty?
|
||||
end
|
||||
|
||||
# Returns true if the generator has not reached the end yet.
|
||||
def next?()
|
||||
def next?
|
||||
!end?
|
||||
end
|
||||
|
||||
# Returns the current index (position) counting from zero.
|
||||
def index()
|
||||
def index
|
||||
@index
|
||||
end
|
||||
|
||||
# Returns the current index (position) counting from zero.
|
||||
def pos()
|
||||
def pos
|
||||
@index
|
||||
end
|
||||
|
||||
# Returns the element at the current position and moves forward.
|
||||
def next()
|
||||
if end?
|
||||
raise EOFError, "no more elements available"
|
||||
end
|
||||
|
||||
if @cont_next = callcc { |c| c }
|
||||
@cont_yield.call(nil) if @cont_yield
|
||||
end
|
||||
|
||||
def next
|
||||
raise EOFError.new("no more elements available") if end?
|
||||
@index += 1
|
||||
|
||||
@queue.shift
|
||||
end
|
||||
|
||||
# Returns the element at the current position.
|
||||
def current()
|
||||
if @queue.empty?
|
||||
raise EOFError, "no more elements available"
|
||||
end
|
||||
|
||||
def current
|
||||
raise EOFError.new("no more elements available") if end?
|
||||
@queue.first
|
||||
end
|
||||
|
||||
# Rewinds the generator.
|
||||
def rewind()
|
||||
def rewind
|
||||
initialize(nil, &@block) if @index.nonzero?
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Rewinds the generator and enumerates the elements.
|
||||
def each
|
||||
rewind
|
||||
|
||||
until end?
|
||||
yield self.next
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue