"Eric Mahurin" <eric_mahurin / yahoo.com> schrieb im Newsbeitrag
news:20050502150819.69075.qmail / web41102.mail.yahoo.com...
> > > I still think a more general extension would be nice.  And
> > > Robert, I guess you might say I'm guessing.  I'm new to
> > ruby,
> > > but from my perl usage, I know of many times I've dealt
> > with
> > > large amounts of data and would have wanted more C-like
> > > efficiency.
> >
> > ;-)
> >
> > As Mark has demonstrated, you can stuff anything into a
> > String with pack and
> > unpack.
> >
> > Btw, Mark, if you factor out conversion to string and from
> > string (hint
> > traits), you have a generic implementation for any fixed size
> > type.  Maybe
> > this should go somewhere into the std lib...
>
> That would be great.  What do you mean by "fixed size type"?
> Does that mean you couldn't use this class to make a
> homogeneous array of strings, arrays, or hashes?

Exactly.  Because for that to work you need info about each instance
stored there.  And then you have Array.

>  The way I was
> thinking you'd handle the complex object case would be to give
> "new" an initial object instead of a simply a class.  From
> this, you could tell how much flattening to do in the array.
>
> Now that I'm looking at Array.new, you could even use the same
> interface:
>
> HomogeneousArray.new(size=0,defaultObject=nil)
>
> Now, defaultObject is not only the default but its class is
> used to make the array homogeneous (if not nil)
>
> Here are a few examples:
>
> # like Array.new - objects can be anything (treat nil as Object
> instead of NilClass) and initialized to nil (when array
> expands)
> HomogeneousArray.new(0,nil)

This doesn't make sense as that would a) not work in the general case and
b) if it would, it would create unnecessary overhead.

> # array of Floats initialized to 0.0
> HomogeneousArray.new(0,0.0)
>
> # array of FixNums initialized to 0
> HomogeneousArray.new(0,0)
>
> # array of Strings initialized to ""
> HomogeneousArray.new(0,"")
>
> # array of name/address/zip structs where fields can be
> anything and are initialized to nil
> Customer = Struct.new(:name,:address,:zip)
> HomogeneousArray.new(0,Customer.new)
>
> # now name/address/zip must be String/String/Fixnum and are
> initialized to empty strings and 0.  There is one more level of
> flattening in the array storage compared to above
> Customer = Struct.new(:name,:address,:zip)
> HomogeneousArray.new(0,Customer.new("","",0))
>
> I think having something similar for a Hash would also be
> useful.  The "new" method with this homogenous hash class just
> needs one more optional argument:
>
> HomogeneousHash.new(defaultValue=nil, defaultKey=nil)
>
> Here would be a few examples:
>
> HomogeneousHash.new(nil,nil) # same as Hash.new
> HomogeneousHash.new(nil,"") # keys must be Strings
>
> # keys are Strings and values are String,Fixnum Structs
> CustomerData = Struct.new(:address,:zip)
> HomogeneousHash.new(CustomerData.new("",0),"")
>
> # values must be true.  No value storage should be necessary
> since only one value is possible.  Only key storage should be
> needed.  This acts like an unordered set.
> HomogeneousHash.new(true,nil)
>
>
> In addition to all this, some way to designate fixed-length
> Arrays, Strings, and Bignums (down to 1-bit) in the collection
> values would allow one more level of flattening in the storage.
>  You could have special classes or just designate a non-zero
> length to mean the objects should have a fixed length.  For
> Bignums/Fixnums, you'd just strip off the most significant 1 to
> allow easy specifying of bits and allow any default.  Here
> would be some more examples using this method for designating
> fixed-length Arrays, String, and Bignums:
>
> # array of 64-bit integers with initial value of 0
> HomogeneousArray.new(0,2**64)
>
> # array of 16-bit integers with initial value of 1
> HomogeneousArray.new(0,2**16+1)
>
> # array of 1-bit integers with initial value of 0
> HomogeneousArray.new(0,2**1)
>
> # array of array of 4 8-bit integers initialized to 0
> HomogeneousArray.new(0,[2**8]*4)
>
> # array of 2 character string initialized to \0\0
> HomogeneousArray.new(0,"\0\0")
>
> # array of array of 4 Objects initialized to nil
> HomogeneousArray.new(0,[nil]*4)
>
>
> Well, I think this summarizes my proposal.  Maybe an RCR is in
> order.

Personally I don't like the sample instance stuff.  This puts too much
knowlege into HomogeneousArray while restricting extensibility at the same
time.  I prefer the traits approach:

# disclaimer: this is just a quick demo
class HomogeneousArray
  class FloatTraits
    def size() 4 end
    def to_native(str) str.unpack("f*") end
    def to_string(*values) values.pack("f*") end
  end

  FLOAT = FloatTraits.new

  class IntTraits
    def size() 4 end
    def to_native(str) str.unpack("i*") end
    def to_string(*values) values.pack("i*") end
  end

  INT = IntTraits.new

  include Enumerable

  def initialize(traits)
    @traits = traits
    @storage = ""
  end

  def <<(o) @storage << @traits.to_string(o); self end
  def size() @storage.length / @traits.size end
  def empty?() @storage.empty? end

  def each
    size.times {|i| yield self[i]}
    self
  end

  def [](idx,len=nil)
    if len
      @traits.to_native( @storage[idx * @traits.size, len *
@traits.size] )
    elsif Range === idx
      @traits.to_native( @storage[idx.first * @traits.size, (idx.last -
idx.first) * @traits.size] )
    else
      @traits.to_native( @storage[idx * @traits.size, @traits.size] )[0]
    end
  end

  def to_s() @traits.to_native( @storage ).join end
  def inspect() @traits.to_native( @storage ).inspect end
end

hf = HomogeneousArray.new HomogeneousArray::FLOAT
hf << 1.2 << 3.4 << 1.2
hi = HomogeneousArray.new HomogeneousArray::INT
hi << 1 << 2 << 3

Kind regards

    robert