diff --git a/lib/concurrent.rb b/lib/concurrent.rb index d6a9061e8..f2a8ce645 100644 --- a/lib/concurrent.rb +++ b/lib/concurrent.rb @@ -9,7 +9,6 @@ require 'concurrent/errors' require 'concurrent/executors' require 'concurrent/utilities' -require 'concurrent/struct' require 'concurrent/atomic/atomic_reference' require 'concurrent/atom' @@ -17,11 +16,14 @@ require 'concurrent/dataflow' require 'concurrent/delay' require 'concurrent/future' +require 'concurrent/immutable_struct' require 'concurrent/ivar' require 'concurrent/maybe' +require 'concurrent/mutable_struct' require 'concurrent/mvar' require 'concurrent/promise' require 'concurrent/scheduled_task' +require 'concurrent/settable_struct' require 'concurrent/timer_task' require 'concurrent/tvar' diff --git a/lib/concurrent/struct/immutable_struct.rb b/lib/concurrent/immutable_struct.rb similarity index 88% rename from lib/concurrent/struct/immutable_struct.rb rename to lib/concurrent/immutable_struct.rb index 9eaf308b4..ee0591a45 100644 --- a/lib/concurrent/struct/immutable_struct.rb +++ b/lib/concurrent/immutable_struct.rb @@ -1,4 +1,4 @@ -require 'concurrent/struct/abstract_struct' +require 'concurrent/synchronization/abstract_struct' require 'concurrent/synchronization' module Concurrent @@ -7,7 +7,7 @@ module Concurrent # # @see http://ruby-doc.org/core-2.2.0/Struct.html Ruby standard library `Struct` module ImmutableStruct - include AbstractStruct + include Synchronization::AbstractStruct # @!macro struct_values def values @@ -80,7 +80,7 @@ def self.new(*args, &block) FACTORY = Class.new(Synchronization::Object) do def define_struct(name, members, &block) synchronize do - AbstractStruct.define_struct_class(ImmutableStruct, Synchronization::Object, name, members, &block) + Synchronization::AbstractStruct.define_struct_class(ImmutableStruct, Synchronization::Object, name, members, &block) end end end.new diff --git a/lib/concurrent/struct/mutable_struct.rb b/lib/concurrent/mutable_struct.rb similarity index 96% rename from lib/concurrent/struct/mutable_struct.rb rename to lib/concurrent/mutable_struct.rb index 9c3efa6bb..68b0040d4 100644 --- a/lib/concurrent/struct/mutable_struct.rb +++ b/lib/concurrent/mutable_struct.rb @@ -1,4 +1,4 @@ -require 'concurrent/struct/abstract_struct' +require 'concurrent/synchronization/abstract_struct' require 'concurrent/synchronization' module Concurrent @@ -8,7 +8,7 @@ module Concurrent # # @see http://ruby-doc.org/core-2.2.0/Struct.html Ruby standard library `Struct` module MutableStruct - include AbstractStruct + include Synchronization::AbstractStruct # @!macro [new] struct_new # @@ -88,7 +88,7 @@ def inspect # @yieldparam [Object] selfvalue the value of the member in `self` # @yieldparam [Object] othervalue the value of the member in `other` # - # @return [AbstractStruct] a new struct with the new values + # @return [Synchronization::AbstractStruct] a new struct with the new values # # @raise [ArgumentError] of given a member that is not defined in the struct def merge(other, &block) @@ -209,7 +209,7 @@ def self.new(*args, &block) FACTORY = Class.new(Synchronization::Object) do def define_struct(name, members, &block) synchronize do - clazz = AbstractStruct.define_struct_class(MutableStruct, Synchronization::Object, name, members, &block) + clazz = Synchronization::AbstractStruct.define_struct_class(MutableStruct, Synchronization::Object, name, members, &block) members.each_with_index do |member, index| clazz.send(:define_method, member) do synchronize { @values[index] } diff --git a/lib/concurrent/struct/settable_struct.rb b/lib/concurrent/settable_struct.rb similarity index 93% rename from lib/concurrent/struct/settable_struct.rb rename to lib/concurrent/settable_struct.rb index 09fe705b8..f0b397a72 100644 --- a/lib/concurrent/struct/settable_struct.rb +++ b/lib/concurrent/settable_struct.rb @@ -1,4 +1,4 @@ -require 'concurrent/struct/abstract_struct' +require 'concurrent/synchronization/abstract_struct' require 'concurrent/errors' require 'concurrent/synchronization' @@ -12,7 +12,7 @@ module Concurrent # @see http://ruby-doc.org/core-2.2.0/Struct.html Ruby standard library `Struct` # @see http://en.wikipedia.org/wiki/Final_(Java) Java `final` keyword module SettableStruct - include AbstractStruct + include Synchronization::AbstractStruct # @!macro struct_values def values @@ -104,7 +104,7 @@ def self.new(*args, &block) FACTORY = Class.new(Synchronization::Object) do def define_struct(name, members, &block) synchronize do - clazz = AbstractStruct.define_struct_class(SettableStruct, Synchronization::Object, name, members, &block) + clazz = Synchronization::AbstractStruct.define_struct_class(SettableStruct, Synchronization::Object, name, members, &block) members.each_with_index do |member, index| clazz.send(:define_method, member) do synchronize { @values[index] } diff --git a/lib/concurrent/struct.rb b/lib/concurrent/struct.rb deleted file mode 100644 index 6aacba684..000000000 --- a/lib/concurrent/struct.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'concurrent/struct/immutable_struct' -require 'concurrent/struct/mutable_struct' -require 'concurrent/struct/settable_struct' diff --git a/lib/concurrent/struct/abstract_struct.rb b/lib/concurrent/struct/abstract_struct.rb deleted file mode 100644 index 755940feb..000000000 --- a/lib/concurrent/struct/abstract_struct.rb +++ /dev/null @@ -1,155 +0,0 @@ -module Concurrent - - # @!visibility private - module AbstractStruct - - # @!visibility private - def initialize(*values) - super() - ns_initialize(*values) - ensure_ivar_visibility! - end - - # @!macro [attach] 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 [attach] 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 =~ /^#" - 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 pr_underscore(clazz) - word = clazz.to_s - 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.const_set(name, clazz) - parent.const_get(name) - rescue NameError - raise NameError.new("identifier #{name} needs to be constant") - end - end - members.each_with_index do |member, index| - clazz.send(:define_method, member) do - @values[index] - end - end - clazz.class_exec(&block) unless block.nil? - clazz - end - end -end diff --git a/lib/concurrent/synchronization/abstract_struct.rb b/lib/concurrent/synchronization/abstract_struct.rb new file mode 100644 index 000000000..480383f93 --- /dev/null +++ b/lib/concurrent/synchronization/abstract_struct.rb @@ -0,0 +1,157 @@ +module Concurrent + module Synchronization + + # @!visibility private + module AbstractStruct + + # @!visibility private + def initialize(*values) + super() + ns_initialize(*values) + ensure_ivar_visibility! + end + + # @!macro [attach] 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 [attach] 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 =~ /^#" + 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 pr_underscore(clazz) + word = clazz.to_s + 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.const_set(name, clazz) + parent.const_get(name) + rescue NameError + raise NameError.new("identifier #{name} needs to be constant") + end + end + members.each_with_index do |member, index| + clazz.send(:define_method, member) do + @values[index] + end + end + clazz.class_exec(&block) unless block.nil? + clazz + end + end + end +end diff --git a/spec/concurrent/struct/immutable_struct_spec.rb b/spec/concurrent/immutable_struct_spec.rb similarity index 100% rename from spec/concurrent/struct/immutable_struct_spec.rb rename to spec/concurrent/immutable_struct_spec.rb diff --git a/spec/concurrent/struct/mutable_struct_spec.rb b/spec/concurrent/mutable_struct_spec.rb similarity index 100% rename from spec/concurrent/struct/mutable_struct_spec.rb rename to spec/concurrent/mutable_struct_spec.rb diff --git a/spec/concurrent/struct/settable_struct_spec.rb b/spec/concurrent/settable_struct_spec.rb similarity index 100% rename from spec/concurrent/struct/settable_struct_spec.rb rename to spec/concurrent/settable_struct_spec.rb diff --git a/spec/concurrent/struct/struct_shared.rb b/spec/concurrent/struct_shared.rb similarity index 100% rename from spec/concurrent/struct/struct_shared.rb rename to spec/concurrent/struct_shared.rb