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>
|
Wed Dec 28 14:10:05 2005 Tanaka Akira <akr@m17n.org>
|
||||||
|
|
||||||
* ia64.s: remove .pred.safe_across_calls directive.
|
* ia64.s: remove .pred.safe_across_calls directive.
|
||||||
|
|
|
@ -28,9 +28,6 @@
|
||||||
# Generator converts an internal iterator (i.e. an Enumerable object)
|
# Generator converts an internal iterator (i.e. an Enumerable object)
|
||||||
# to an external iterator.
|
# to an external iterator.
|
||||||
#
|
#
|
||||||
# Note that it is not very fast since it is implemented using
|
|
||||||
# continuations, which are currently slow.
|
|
||||||
#
|
|
||||||
# == Example
|
# == Example
|
||||||
#
|
#
|
||||||
# require 'generator'
|
# require 'generator'
|
||||||
|
@ -68,99 +65,97 @@ class Generator
|
||||||
# itself, and expected to call the +yield+ method for each element.
|
# itself, and expected to call the +yield+ method for each element.
|
||||||
def initialize(enum = nil, &block)
|
def initialize(enum = nil, &block)
|
||||||
if enum
|
if enum
|
||||||
@block = proc { |g|
|
@block = proc{|g| enum.each{|value| g.yield value}}
|
||||||
enum.each { |x| g.yield x }
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
@block = block
|
@block = block
|
||||||
end
|
end
|
||||||
|
|
||||||
@index = 0
|
@index = 0
|
||||||
@queue = []
|
@queue = []
|
||||||
@cont_next = @cont_yield = @cont_endp = nil
|
@loop_thread = Thread.new do
|
||||||
|
Thread.stop
|
||||||
if @cont_next = callcc { |c| c }
|
Thread.critical = true
|
||||||
@block.call(self)
|
begin
|
||||||
|
@block.call(self) # exception safe?
|
||||||
@cont_endp.call(nil) if @cont_endp
|
rescue
|
||||||
|
@main_thread.raise $!
|
||||||
|
ensure
|
||||||
|
@main_thread.wakeup
|
||||||
|
Thread.critical = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
# Yields an element to the generator.
|
# Yields an element to the generator.
|
||||||
def yield(value)
|
def yield(value)
|
||||||
if @cont_yield = callcc { |c| c }
|
if Thread.current != @loop_thread
|
||||||
@queue << value
|
raise RuntimeError.new("Generator#yield must be called in Generator.new{|g| ... }")
|
||||||
@cont_next.call(nil)
|
|
||||||
end
|
end
|
||||||
|
@queue << value
|
||||||
|
@main_thread.wakeup
|
||||||
|
Thread.stop
|
||||||
|
Thread.critical = true
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns true if the generator has reached the end.
|
# Returns true if the generator has reached the end.
|
||||||
def end?()
|
def end?
|
||||||
if @cont_endp = callcc { |c| c }
|
if @queue.empty?
|
||||||
@cont_yield.nil? && @queue.empty?
|
Thread.critical = true
|
||||||
else
|
@main_thread = Thread.current
|
||||||
@queue.empty?
|
begin
|
||||||
|
@loop_thread.wakeup
|
||||||
|
Thread.stop
|
||||||
|
rescue ThreadError
|
||||||
|
# ignore
|
||||||
|
ensure
|
||||||
|
@main_thread = nil
|
||||||
|
Thread.critical = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@queue.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns true if the generator has not reached the end yet.
|
# Returns true if the generator has not reached the end yet.
|
||||||
def next?()
|
def next?
|
||||||
!end?
|
!end?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the current index (position) counting from zero.
|
# Returns the current index (position) counting from zero.
|
||||||
def index()
|
def index
|
||||||
@index
|
@index
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the current index (position) counting from zero.
|
# Returns the current index (position) counting from zero.
|
||||||
def pos()
|
def pos
|
||||||
@index
|
@index
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the element at the current position and moves forward.
|
# Returns the element at the current position and moves forward.
|
||||||
def next()
|
def next
|
||||||
if end?
|
raise EOFError.new("no more elements available") if end?
|
||||||
raise EOFError, "no more elements available"
|
|
||||||
end
|
|
||||||
|
|
||||||
if @cont_next = callcc { |c| c }
|
|
||||||
@cont_yield.call(nil) if @cont_yield
|
|
||||||
end
|
|
||||||
|
|
||||||
@index += 1
|
@index += 1
|
||||||
|
|
||||||
@queue.shift
|
@queue.shift
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the element at the current position.
|
# Returns the element at the current position.
|
||||||
def current()
|
def current
|
||||||
if @queue.empty?
|
raise EOFError.new("no more elements available") if end?
|
||||||
raise EOFError, "no more elements available"
|
|
||||||
end
|
|
||||||
|
|
||||||
@queue.first
|
@queue.first
|
||||||
end
|
end
|
||||||
|
|
||||||
# Rewinds the generator.
|
# Rewinds the generator.
|
||||||
def rewind()
|
def rewind
|
||||||
initialize(nil, &@block) if @index.nonzero?
|
initialize(nil, &@block) if @index.nonzero?
|
||||||
|
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
# Rewinds the generator and enumerates the elements.
|
# Rewinds the generator and enumerates the elements.
|
||||||
def each
|
def each
|
||||||
rewind
|
rewind
|
||||||
|
|
||||||
until end?
|
until end?
|
||||||
yield self.next
|
yield self.next
|
||||||
end
|
end
|
||||||
|
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue