From: bwv549 Date: 2008-04-03T13:25:04+09:00 Subject: Re: revisiting memory/speed of an Array based class # this is array_class.rb module ArrayClass def self.new(fields) nclass = Class.new(Array) nclass.class_eval('def self.add_member(name) i = @@arr_size self.class_eval("def #{name}() self[#{i}] end") self.class_eval("def #{name}=(val) self[#{i}]=val end") self.class_eval("@@ind[:#{name}] = #{i}") self.class_eval("@@ind[\"#{name}\"] = #{i}") self.class_eval("@@attributes << :#{name}") self.class_eval("@@arr_size = @@attributes.size") end') # This list is derived from ImageList in ImageMagick (and I've added some # applicable to this guy) (I've left zip here as it is applicable and a # great method) %w(flatten flatten! assoc join rassoc push pop <<).each do |att| nclass.class_eval("undef_method :#{att}") end nclass.class_eval("undef_method :transpose if Array.instance_methods(false).include?('transpose')") nclass.class_eval("@@ind = {}") # array to preserve order nclass.class_eval("@@attributes = []") nclass.class_eval("@@arr_size = 0") fields.each_with_index do |field,i| nclass.add_member(field.to_s) end #nclass.class_eval('@@ind.each do |k,v| @@ind["#{k}"] = v end ') nclass.class_eval " def initialize(args=nil) if args.is_a? Array super(args) elsif args.is_a? Hash super(@@arr_size) args.each do |k,v| self[@@ind[k]] = v end else super(@@arr_size) end end" # list of nclass.class_eval('def self.members() @@attributes end') nclass.class_eval('def members() @@attributes end') nclass.class_eval("def is_a?(klass) if klass == Array ; false else ; super(klass) end end alias_method :kind_of?, :is_a?") nclass.class_eval('def inspect bits = @@attributes.map do |v| val = self.send(v) val = "nil" if val.nil? "#{v}=#{val.inspect}" end string = bits.join(", ") "<(ArrayClass based) #{string}>" end ') #nclass.class_eval('def self.indices() @@ind end') #nclass.class_eval('def indices() @@ind end') # NOTE that two separate objects will hash differently (even if their # content is the same!) nclass.class_eval('def hash() object_id end') nclass end end # this is the weakest link in this guy: # we need some way for the array_class objects not to be flattened on Array#flatten calls # we basically redefine array_class's is_a? method to say it is NOT an array # and redefine flatten to work only for things that say they are arrays. # this is my best solution so far... any better ideas? class Array undef_method :flatten undef_method :flatten! #tmp_verb = $VERBOSE #$VERBOSE = nil # WARNING! Array#flatten is redefined so that it calls the is_a? method # (instead of doing it internally as defined in the C code). This allows # ArrayClass derived objects to resist flattening by declaring that they are # not Arrays. This may be _slightly_ slower than the original, but in all # other respects should be the same (i.e., will flatten array derived # classes). def flatten new_array = [] self.each do |v| if v.is_a?(Array) new_array.push( *(v.flatten) ) else new_array << v end end new_array end # WARNING! Array#flatten! is redefined flatten method discussed above. def flatten! self.replace(flatten) end #$VERBOSE = tmp_verb end