This commit is contained in:
+171
@@ -0,0 +1,171 @@
|
||||
module Concurrent
|
||||
module Synchronization
|
||||
|
||||
# @!visibility private
|
||||
# @!macro internal_implementation_note
|
||||
module AbstractStruct
|
||||
|
||||
# @!visibility private
|
||||
def initialize(*values)
|
||||
super()
|
||||
ns_initialize(*values)
|
||||
end
|
||||
|
||||
# @!macro struct_length
|
||||
#
|
||||
# Returns the number of struct members.
|
||||
#
|
||||
# @return [Fixnum] the number of struct members
|
||||
def length
|
||||
self.class::MEMBERS.length
|
||||
end
|
||||
alias_method :size, :length
|
||||
|
||||
# @!macro struct_members
|
||||
#
|
||||
# Returns the struct members as an array of symbols.
|
||||
#
|
||||
# @return [Array] the struct members as an array of symbols
|
||||
def members
|
||||
self.class::MEMBERS.dup
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# @!macro struct_values
|
||||
#
|
||||
# @!visibility private
|
||||
def ns_values
|
||||
@values.dup
|
||||
end
|
||||
|
||||
# @!macro struct_values_at
|
||||
#
|
||||
# @!visibility private
|
||||
def ns_values_at(indexes)
|
||||
@values.values_at(*indexes)
|
||||
end
|
||||
|
||||
# @!macro struct_to_h
|
||||
#
|
||||
# @!visibility private
|
||||
def ns_to_h
|
||||
length.times.reduce({}){|memo, i| memo[self.class::MEMBERS[i]] = @values[i]; memo}
|
||||
end
|
||||
|
||||
# @!macro struct_get
|
||||
#
|
||||
# @!visibility private
|
||||
def ns_get(member)
|
||||
if member.is_a? Integer
|
||||
if member >= @values.length
|
||||
raise IndexError.new("offset #{member} too large for struct(size:#{@values.length})")
|
||||
end
|
||||
@values[member]
|
||||
else
|
||||
send(member)
|
||||
end
|
||||
rescue NoMethodError
|
||||
raise NameError.new("no member '#{member}' in struct")
|
||||
end
|
||||
|
||||
# @!macro struct_equality
|
||||
#
|
||||
# @!visibility private
|
||||
def ns_equality(other)
|
||||
self.class == other.class && self.values == other.values
|
||||
end
|
||||
|
||||
# @!macro struct_each
|
||||
#
|
||||
# @!visibility private
|
||||
def ns_each
|
||||
values.each{|value| yield value }
|
||||
end
|
||||
|
||||
# @!macro struct_each_pair
|
||||
#
|
||||
# @!visibility private
|
||||
def ns_each_pair
|
||||
@values.length.times do |index|
|
||||
yield self.class::MEMBERS[index], @values[index]
|
||||
end
|
||||
end
|
||||
|
||||
# @!macro struct_select
|
||||
#
|
||||
# @!visibility private
|
||||
def ns_select
|
||||
values.select{|value| yield value }
|
||||
end
|
||||
|
||||
# @!macro struct_inspect
|
||||
#
|
||||
# @!visibility private
|
||||
def ns_inspect
|
||||
struct = pr_underscore(self.class.ancestors[1])
|
||||
clazz = ((self.class.to_s =~ /^#<Class:/) == 0) ? '' : " #{self.class}"
|
||||
"#<#{struct}#{clazz} #{ns_to_h}>"
|
||||
end
|
||||
|
||||
# @!macro struct_merge
|
||||
#
|
||||
# @!visibility private
|
||||
def ns_merge(other, &block)
|
||||
self.class.new(*self.to_h.merge(other, &block).values)
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
def ns_initialize_copy
|
||||
@values = @values.map do |val|
|
||||
begin
|
||||
val.clone
|
||||
rescue TypeError
|
||||
val
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
def pr_underscore(clazz)
|
||||
word = clazz.to_s.dup # dup string to workaround JRuby 9.2.0.0 bug https://github.com/jruby/jruby/issues/5229
|
||||
word.gsub!(/::/, '/')
|
||||
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
||||
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
||||
word.tr!("-", "_")
|
||||
word.downcase!
|
||||
word
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
def self.define_struct_class(parent, base, name, members, &block)
|
||||
clazz = Class.new(base || Object) do
|
||||
include parent
|
||||
self.const_set(:MEMBERS, members.collect{|member| member.to_s.to_sym}.freeze)
|
||||
def ns_initialize(*values)
|
||||
raise ArgumentError.new('struct size differs') if values.length > length
|
||||
@values = values.fill(nil, values.length..length-1)
|
||||
end
|
||||
end
|
||||
unless name.nil?
|
||||
begin
|
||||
parent.send :remove_const, name if parent.const_defined?(name, false)
|
||||
parent.const_set(name, clazz)
|
||||
clazz
|
||||
rescue NameError
|
||||
raise NameError.new("identifier #{name} needs to be constant")
|
||||
end
|
||||
end
|
||||
members.each_with_index do |member, index|
|
||||
clazz.send :remove_method, member if clazz.instance_methods(false).include? member
|
||||
clazz.send(:define_method, member) do
|
||||
@values[index]
|
||||
end
|
||||
end
|
||||
clazz.class_exec(&block) unless block.nil?
|
||||
clazz.singleton_class.send :alias_method, :[], :new
|
||||
clazz
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user