mirror of
https://github.com/mistergibson/gxg-web-client.git
synced 2026-08-15 03:26:00 -07:00
355 lines
7.3 KiB
Ruby
355 lines
7.3 KiB
Ruby
module Rubinius
|
|
class Tuple
|
|
include Enumerable
|
|
|
|
def self.new(cnt)
|
|
Rubinius.primitive :tuple_allocate
|
|
raise PrimitiveFailure, "Tuple.new primitive failed"
|
|
end
|
|
|
|
def self.pattern(size, obj)
|
|
Rubinius.primitive :tuple_pattern
|
|
raise PrimitiveFailure, "Tuple.pattern primitive failed"
|
|
end
|
|
|
|
def [](idx)
|
|
Rubinius.primitive :tuple_at
|
|
|
|
unless idx.kind_of? Fixnum
|
|
raise TypeError, "Only Fixnums valid for Tuple indices"
|
|
end
|
|
|
|
raise PrimitiveFailure, "Tuple#[] primitive failed"
|
|
end
|
|
|
|
alias_method :at, :[]
|
|
|
|
def []=(idx, val)
|
|
Rubinius.primitive :tuple_put
|
|
|
|
unless idx.kind_of? Fixnum
|
|
raise TypeError, "Only Fixnums valid for Tuple indices"
|
|
end
|
|
raise PrimitiveFailure, "Tuple#[]= primitive failed"
|
|
end
|
|
|
|
alias_method :put, :[]=
|
|
|
|
def fields
|
|
Rubinius.primitive :tuple_fields
|
|
raise PrimitiveFailure, "Tuple#fields primitive failed"
|
|
end
|
|
|
|
def copy_from(other, start, length, dest)
|
|
Rubinius.primitive :tuple_copy_from
|
|
|
|
unless other.kind_of? Rubinius::Tuple
|
|
raise TypeError, "Tuple#copy_from was expecting a Tuple, not a #{other.class}"
|
|
end
|
|
start = Rubinius::Type.coerce_to start, Fixnum, :to_i
|
|
length = Rubinius::Type.coerce_to length, Fixnum, :to_i
|
|
dest = Rubinius::Type.coerce_to dest, Fixnum, :to_i
|
|
|
|
if start < 0 || start > other.fields
|
|
raise IndexError, "Start %d is out of bounds %d" % [start, other.fields]
|
|
end
|
|
|
|
if dest < 0 || dest > self.fields
|
|
raise IndexError, "Destination %d is out of bounds %d" % [dest, self.fields]
|
|
end
|
|
|
|
if length < 0
|
|
raise IndexError, "length %d must be positive" % [length]
|
|
end
|
|
|
|
if (start + length) > other.fields
|
|
raise IndexError, "end index %d can not exceed size of source %d" % [start+length, other.fields]
|
|
end
|
|
|
|
if length > (self.fields - dest)
|
|
raise IndexError, "length %d can not exceed space %d in destination" % [length, self.fields - dest]
|
|
end
|
|
|
|
src = start
|
|
dst = dest
|
|
while src < (start + length)
|
|
put dst, other.at(src)
|
|
src += 1
|
|
dst += 1
|
|
end
|
|
|
|
self
|
|
end
|
|
|
|
def dup
|
|
Rubinius.primitive :tuple_dup
|
|
|
|
obj = Rubinius::Type.object_class(self).new(self.size)
|
|
|
|
Rubinius.invoke_primitive :object_copy_object, obj, self
|
|
|
|
Rubinius.privately do
|
|
obj.initialize_copy self
|
|
end
|
|
|
|
obj
|
|
end
|
|
|
|
def delete(start, length, object)
|
|
Rubinius.primitive :tuple_delete_inplace
|
|
|
|
start = Rubinius::Type.coerce_to start, Fixnum, :to_i
|
|
length = Rubinius::Type.coerce_to length, Fixnum, :to_i
|
|
|
|
lend = start
|
|
rend = lend + length
|
|
|
|
return 0 if self.fields == 0
|
|
if lend < 0 || lend >= self.fields
|
|
raise IndexError, "Index %d is not within Tuple of length %d" % [lend, self.fields]
|
|
end
|
|
|
|
if rend < 0 || rend > self.fields
|
|
raise IndexError, "Index %d is not within Tuple of length %d" % [rend, self.fields]
|
|
end
|
|
|
|
i = lend
|
|
while i < rend
|
|
if at(i) == object
|
|
j = i
|
|
i += 1
|
|
while i < rend
|
|
val = at(i)
|
|
if val != object
|
|
put j, val
|
|
j += 1
|
|
end
|
|
i += 1
|
|
end
|
|
|
|
# cleanup all the remaining bins in the tuple
|
|
i = j
|
|
while i < rend
|
|
put i, nil
|
|
i += 1
|
|
end
|
|
|
|
return rend - j
|
|
end
|
|
i += 1
|
|
end
|
|
|
|
return 0
|
|
end
|
|
|
|
def reverse!(start, total)
|
|
Rubinius.primitive :tuple_reverse
|
|
|
|
reverse(
|
|
Rubinius::Type.coerce_to(start, Fixnum, :to_i),
|
|
Rubinius::Type.coerce_to(total, Fixnum, :to_i))
|
|
end
|
|
|
|
def delete_at_index(index)
|
|
return if size == 1
|
|
|
|
s = size - 1
|
|
t = self.class.new s
|
|
|
|
if index != 0
|
|
t.copy_from self, 0, index, 0
|
|
end
|
|
|
|
if index < s
|
|
t.copy_from self, index+1, s-index, index
|
|
end
|
|
|
|
t
|
|
end
|
|
|
|
def insert_at_index(index, value)
|
|
t = self.class.new size + 1
|
|
|
|
if index != 0
|
|
t.copy_from self, 0, index, 0
|
|
end
|
|
|
|
if index < size
|
|
t.copy_from self, index, size-index, index+1
|
|
end
|
|
|
|
t[index] = value
|
|
|
|
t
|
|
end
|
|
|
|
def self.[](*args)
|
|
args.to_tuple
|
|
end
|
|
|
|
def to_s
|
|
"#<#{self.class}:0x#{object_id.to_s(16)} #{fields} elements>"
|
|
end
|
|
|
|
def each
|
|
i = 0
|
|
t = fields
|
|
while i < t
|
|
yield at(i)
|
|
i += 1
|
|
end
|
|
self
|
|
end
|
|
|
|
def ==(tup)
|
|
return super unless tup.kind_of?(Tuple)
|
|
|
|
t = fields()
|
|
|
|
return false unless t == tup.size
|
|
|
|
i = 0
|
|
while i < t
|
|
return false unless at(i) == tup.at(i)
|
|
i += 1
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
def +(o)
|
|
t = Tuple.new(size + o.size)
|
|
t.copy_from(self, 0, size, 0)
|
|
t.copy_from(o, 0, o.size, size)
|
|
t
|
|
end
|
|
|
|
def inspect
|
|
str = "#<#{self.class}"
|
|
if fields == 0
|
|
str << " empty>"
|
|
else
|
|
str << ": #{join(", ", :inspect)}>"
|
|
end
|
|
return str
|
|
end
|
|
|
|
def join(sep, meth=:to_s)
|
|
join_upto(sep, fields, meth)
|
|
end
|
|
|
|
def join_upto(sep, count, meth=:to_s)
|
|
str = ""
|
|
return str if count == 0 or empty?
|
|
|
|
count = fields if count >= fields
|
|
count -= 1
|
|
i = 0
|
|
while i < count
|
|
str.append at(i).__send__(meth)
|
|
str.append sep.dup
|
|
i += 1
|
|
end
|
|
|
|
str.append at(count).__send__(meth)
|
|
return str
|
|
end
|
|
|
|
def ===(other)
|
|
return false unless Tuple === other and fields == other.fields
|
|
i = 0
|
|
while i < fields
|
|
return false unless at(i) === other.at(i)
|
|
i += 1
|
|
end
|
|
true
|
|
end
|
|
|
|
def to_a
|
|
array = Array.allocate
|
|
|
|
m = Rubinius::Mirror.reflect array
|
|
m.tuple = dup
|
|
m.total = fields
|
|
|
|
array
|
|
end
|
|
|
|
alias_method :to_ary, :to_a
|
|
|
|
def shift
|
|
return self unless fields > 0
|
|
t = Tuple.new(fields-1)
|
|
t.copy_from self, 1, fields-1, 0
|
|
return t
|
|
end
|
|
|
|
# Swap elements of the two indexes.
|
|
def swap(a, b)
|
|
temp = at(a)
|
|
put a, at(b)
|
|
put b, temp
|
|
end
|
|
|
|
alias_method :size, :fields
|
|
alias_method :length, :fields
|
|
|
|
def empty?
|
|
size == 0
|
|
end
|
|
|
|
def first
|
|
at(0)
|
|
end
|
|
|
|
def last
|
|
at(fields - 1)
|
|
end
|
|
|
|
# Marshal support - _dump / _load are deprecated so eventually we should figure
|
|
# out a better way.
|
|
def _dump(depth)
|
|
# TODO use depth
|
|
Marshal.dump to_a
|
|
end
|
|
|
|
def self._load(str)
|
|
ary = Marshal.load(str)
|
|
t = new(ary.size)
|
|
ary.each_with_index { |obj, idx| t[idx] = obj }
|
|
return t
|
|
end
|
|
end
|
|
|
|
class RTuple < Tuple
|
|
include Enumerable
|
|
|
|
def self.new(cnt)
|
|
Rubinius.primitive :rtuple_allocate
|
|
raise PrimitiveFailure, "RTuple.new primitive failed"
|
|
end
|
|
|
|
def [](idx)
|
|
Rubinius.primitive :rtuple_at
|
|
|
|
unless idx.kind_of? Fixnum
|
|
raise TypeError, "Only Fixnums valid for RTuple indices"
|
|
end
|
|
|
|
raise PrimitiveFailure, "RTuple#[] primitive failed"
|
|
end
|
|
|
|
alias_method :at, :[]
|
|
|
|
def []=(idx, val)
|
|
Rubinius.primitive :rtuple_put
|
|
|
|
unless idx.kind_of? Fixnum
|
|
raise TypeError, "Only Fixnums valid for RTuple indices"
|
|
end
|
|
raise PrimitiveFailure, "RTuple#[]= primitive failed"
|
|
end
|
|
|
|
alias_method :put, :[]=
|
|
end
|
|
end
|