Use a mutex to make SortedSet.setup thread-safe

This should fix [Bug #13735].

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60304 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
knu 2017-10-21 15:57:32 +00:00
Родитель 76e3825376
Коммит 8daa6985dc
1 изменённых файлов: 79 добавлений и 77 удалений

Просмотреть файл

@ -634,6 +634,7 @@ end
# #
class SortedSet < Set class SortedSet < Set
@@setup = false @@setup = false
@@mutex = Mutex.new
class << self class << self
def [](*ary) # :nodoc: def [](*ary) # :nodoc:
@ -643,97 +644,98 @@ class SortedSet < Set
def setup # :nodoc: def setup # :nodoc:
@@setup and return @@setup and return
# a hack to shut up warning @@mutex.synchronize do
alias_method :old_init, :initialize # a hack to shut up warning
alias_method :old_init, :initialize
begin begin
require 'rbtree' require 'rbtree'
module_eval <<-END, __FILE__, __LINE__+1 module_eval <<-END, __FILE__, __LINE__+1
def initialize(*args) def initialize(*args)
@hash = RBTree.new @hash = RBTree.new
super super
end end
def add(o) def add(o)
o.respond_to?(:<=>) or raise ArgumentError, "value must respond to <=>" o.respond_to?(:<=>) or raise ArgumentError, "value must respond to <=>"
super super
end end
alias << add alias << add
END END
rescue LoadError rescue LoadError
module_eval <<-END, __FILE__, __LINE__+1 module_eval <<-END, __FILE__, __LINE__+1
def initialize(*args) def initialize(*args)
@keys = nil @keys = nil
super super
end end
def clear def clear
@keys = nil @keys = nil
super super
end end
def replace(enum) def replace(enum)
@keys = nil @keys = nil
super super
end end
def add(o) def add(o)
o.respond_to?(:<=>) or raise ArgumentError, "value must respond to <=>" o.respond_to?(:<=>) or raise ArgumentError, "value must respond to <=>"
@keys = nil @keys = nil
super super
end end
alias << add alias << add
def delete(o) def delete(o)
@keys = nil @keys = nil
@hash.delete(o) @hash.delete(o)
self self
end end
def delete_if def delete_if
block_given? or return enum_for(__method__) { size } block_given? or return enum_for(__method__) { size }
n = @hash.size n = @hash.size
super super
@keys = nil if @hash.size != n @keys = nil if @hash.size != n
self self
end end
def keep_if def keep_if
block_given? or return enum_for(__method__) { size } block_given? or return enum_for(__method__) { size }
n = @hash.size n = @hash.size
super super
@keys = nil if @hash.size != n @keys = nil if @hash.size != n
self self
end end
def merge(enum) def merge(enum)
@keys = nil @keys = nil
super super
end end
def each(&block) def each(&block)
block or return enum_for(__method__) { size } block or return enum_for(__method__) { size }
to_a.each(&block) to_a.each(&block)
self self
end end
def to_a def to_a
(@keys = @hash.keys).sort! unless @keys (@keys = @hash.keys).sort! unless @keys
@keys @keys
end end
def freeze def freeze
to_a to_a
super super
end end
END END
end
# a hack to shut up warning
remove_method :old_init
@@setup = true
end end
# a hack to shut up warning
remove_method :old_init
@@setup = true
end end
end end