1
0
Fork 0
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:
ocean 2005-12-29 02:29:26 +00:00
parent 056561c5dd
commit b29384860c
2 changed files with 45 additions and 45 deletions

View file

@ -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.

View file

@ -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