Robert Klemme
5/2/2005 4:02:00 PM
"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